bootsect.s
我们实验环境中,Image 就是一个软盘镜像,bootsect.s就在软盘的第一个扇区中(引导扇区,0磁道,0磁头,第一个扇区)
硬盘有一个单独的镜像文件
BIOS ROM如果设置成软盘启动,就把引导扇区的代码加载到0x7C00开始处执行。因为前面的内存保存有有用的信息。
如果是从硬盘启动系统,就不执行bootsect.s。LILO, Grub等多操作系统引导程序来完成bootsect.s的任务。
setup.s
利用BIOS ROM中断读取硬件的系统数据,并将保存在0x90000的内存,覆盖掉bootsect.s 并将system模块(不超过512K)移动到0x00000处,加载中断描述表寄存器,和全局描述符表寄存器,开始A20地址线,设置两个中断控制芯片8259A,将硬件中断号重新设置,最后设置CPU控制寄存器CR0,进入32位保护模式运行。
- 32位保护运行模式,与实地址模式区别:支持多任务,4G物理内存,虚拟内存,段页式管理,特权。
- 内存管理寄存器:GDTR,LDTR,IDTR,TR(任务寄存器)
- 控制寄存器: CR0,CR1,CR2,CR3
head.s
在保护模式下运行,与前面的语法不通,采用AT&T汇编语言格式,赋值的方向是从左到右。 head.s 执行后,内存布局如下图,GDT都设置好了,页式管理相关的寄存器内存都设置好了。利用返回指令将预先放置在堆中的/init/main.c程序的入口地址弹出。
system.s
main.c
真正的初始化工作在这里,对硬件逐个初始化。其中会调用:outb_p 等直接和硬件打交道的汇编调用。
手工设置第一个任务task 0,完成初始化后,内核把自己执行权限切换到用户模式,fork init进程1。
进程0在创建首个新进程1之前,不能使用其用户态栈。就是要求0不要调用任何函数,用inline解决这个问题。中断调用还是会用到栈,但是用的是内核态的栈,所以没事。
创建进程1后,进程0和1使用相同的栈,用的是copy on writing。
初始化进程的内存使用
Linux 所以任务运行在用户态,内核源代码lib/目录下的库文件(除了string.c),就是为这些新创建的用户态进程提供函数的。内核代码本身不使用这些。
环境初始化,Session概念。