您的位置:首页 > 运维架构 > Linux

理解linux0.11加载过程

2014-09-28 17:32 288 查看
阅读linux0.11源码Boot部分很多次了,每次看着看着就晕了,主要是因为对X86芯片和汇编不熟悉;虽然赵炯博士的<<Linux内核完全注释>>讲的非常详细,网上资料也很多,但毕竟不是自己的东西,只有用自己的思维理解了才会记忆深刻。我就试着用自己的思路,也小结一下。

0. 加载步骤: Bois->bootsect.s->setup.s->(head.s->main.c)。(head.s->main.c合为system模块)

1. PC加电,80x86CPU处于实模式,从CS:IP=FFFF:0000处开始执行指令(CPU在上电或者复位时总是执行物理地址0xFFFF0处的代码)。

0xFFFF0地址是Bois的默认地址。Bios进入硬件自检(内存、硬盘、显卡...)

Bios最后将磁盘的第一个扇区(512字节的bootsect.s)读入内存绝对地址0x7C00处,并跳到这个地方去执行。

2. bootsect.s执行过程:

1).将自己移动到内存绝对地址0x90000开始处并继续执行;

2).将磁盘第2个扇区开始的4个扇区的setup.s模块(setup.s编译成)加载到内存0x90200(bootsect.s后面);

3).然后利用BIOS中断0x13取磁盘参数表中当前启动引导盘的参数,屏幕上显示“Loading system…”字符串;

4).将system模块加载到内存0x10000。(0x10000~0x8ffff);

5).确定根文件系统的设备号; 并保存其设备号于root_dev(引导块的508地址处);

6).跳转到setup.s程序的开始处(0x90200)执行setup.s程序。



3. setup.s是一个操作系统加载程序,它的主要过程是:

1).使用BIOS中断来获得相关系统信息:内存大小,硬盘分区信息,显示卡信息(这些信息都保存在bios,把这些信息读出来放到内存),并将这些数据保存到0x90000开始的位置(覆盖掉了bootsect.s程序所在的地方);

2).将head.s代码拷贝到内存地址为0X0000的地方;

3).加载idt表和gdt表地址;

4).开启A20地址线,只有开启它了才能访问高于1M地址的内存;

5).重新设定中断控制器。这之后以前的BIOS中断号就没用了;

6).置位CR0寄存器的最后一位进入保护模式, 然后跳转到地址0x0000处开始执行,也就是head.s的起始代码处。



4. head.s过程

1:将堆栈设定在static_stack处,堆栈大小为1KB;

2:重新设定设定IDT(此时全部IDT的都设置为ignore_int,即仍然忽略中断)和GDT;

GDT中为内核代码、数据段,所有进程的LDT和任务状态段(TSS);

3:设定分页(目录项和页表);

页目录最大为0x0000~0xffff,目录项为页表描述符(每个页表描述符占4个字节),所以最多有4096/4个页表

页表有4个,每个页表有1024项,每项占4个页地址,可对应物理地址4*1024*4 = 16M

(这里的设置GDT和分页是内存分配的基础,将在后续的学习中进行详细总结)



5. 开始执行init/main.c中的main函数。

......

系统加载起来后,物理内存布局(从0到16M)

页目录

4K

页表1

4K

页表2

4K

页表3

4K

页表4

4K

软盘缓冲区

1K

head.s后半部分代码

IDT表

2K

GDT表

2K

main.o代码部分

内核其余部分

大约512K

setup保存的系统参数

(90000H~900200)

BIOS

(640K-1M)

主内存区

(1M-16M)

这里借用<<Linux内核完全注释>>书中的图描述boot内部启动搬迁过程:



有一些疑问,先自我圆了答案吧,等后续理解深入后如有问题再更正。

1.为什么bios将bootsect.s读到0x7c00,而不是从0x0000依次加载开始呢?

在加载bootsect.s之前,bios从0地址开始加载了中断向量表,为了不覆盖中断向量表,从0x7c00开始。



2.为什么bootsect.s将自己移动到内存绝对地址0x90000开始处并继续执行?

为存放system模块预留空间(0x10000~0x8ffff)?



3.为什么bootsect.s将system模块加载到内存0x10000后,setup.s又将将head.s代码从0x10000拷贝到内存地址为0X0000的地方。

bootsect.s将system模块加载到内存0x10000时,位于0x7c00的bootsect.s还有用(没执行完);

setup.s又将将head.s代码从0x10000拷贝到内存地址为0X0000的地方,此时此刻,位于0x7c00的bootsect.s已经执行完毕,0x7c00以下的bios中断向量表也不再需要(后面的代码都不再调用bios中断),可以覆盖掉。

至于加载到0x0000的好处是对于其中的代码,线形地址和物理地址是一样的,写程序、理解更方便。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: