理解linux0.11加载过程

阅读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的好处是对于其中的代码,线形地址和物理地址是一样的,写程序、理解更方便。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值