操作系统的加载
CPU被设计成只能对内存寻址,不能对磁盘寻址,所以磁盘上的信息都需要加载到内存才能运行。
但是上电后,内存中什么都没有,所以需要通过纯硬件方式将BIOS内存映射到内存的 0xFFFF0 处,并且将CS的值置为0xF000、IP的值置为0xFFF0,这样CS:IP就指向了BIOS的入口地址 0xFFFF0。
BIOS程序在内存最开始的位置(0x00000)用1KB的内存空间(0x00000~0x003FF)构建中断向量表。
通过0x19中断,将磁盘的第一扇区(512B)加载到内存0x07C00处,这个扇区就是启动扇区,其程序叫做引导程序bootsect。
bootsect使用0x13中断,将第二扇区开始的4个扇区,即setup.s对应的程序加载至内存的SETUPSEG(0x90200)处,获取机器信息和硬件参数。
bootsect使用0x13中断,将其余内核代码加载到内存。
由bootsect转为执行setup。
关中断,并将内核代码移到内存起始处(0x00000),此时硬件中断表被覆盖,然后会建立软件中断表。
打开A20,寻址模式由16位变为32位,将CR0寄存器的PE位设置为1,由实模式进入保护模式,至此setup执行完毕。
程序跳转到head,bootsect和setup都是汇编,但是head是.o文件,会在main之前执行。
head会做一些main执行前的准备,以及建立分页框架,即在0x000000的位置创建了页目录表、页表、缓冲区、GDT、IDT。
head会废除setup创建的IDT,并重新构建一套IDT,以适应16位到32位的转变。
之后head给main函数准入入参,通过手工压栈,最后程序跳转到main。
main函数
设置系统盘为根目录,内存分页,初始化输入输出设备。
init进程
手工用汇编创建进程0,开启时钟中断和系统调用。
开中断。
进程0由特权级转变为用户级。
进程1和进程2
进程0 fork 出进程1。
进程1设置硬盘信息、格式化虚拟盘、加载根文件系统等工作。
进程1 fork 出进程2。
进程2会打开中断和加载Shell,最后进程进入怠速状态。