CPU初始化
-
CPU加电, RESET重重寄存器数据 CS:0xffff IP:0
-
进入实地址模式(0-0xfffff) seg(16bit)+offset(16bit): seg<<4 + offset (0~1MB)
-
执行第一条指令(线性地址 0xffff0 EPROM映射)进入初始引导程序(可用空间0x0C0000-0xfffff)
初始引导程序: 从磁盘读入引导扇区的程序. 由于EPROM的空间发展, 后逐渐增加硬件检测, 设备驱动(Linux未采用)等一起组成BIOS.
-
有的机器会在读入引导扇区中间引入中间步骤, 成为引导装入程序, 例如LILO.作用就是可以让用户有选择的引导对应的
操作系统映像. -
从主引导记录块(MBR, 硬盘的第一个扇区)读取引导位置(其他逻辑扇区的引导扇区)-- 每个扇区512B (目前有4KB)
-
Linux的引导扇区由bootSec.s定义. 汇编后需要压缩, 大小不超过512B.借助其他辅助程序(setup, compressed)可以将
内核vmlinux解压装载进内存.
bootsec被bios装载到0x7c00处之后自己会移动至0x90000, 然后jump到该处执行. (此时是16位实地址模式) -
然后, setup程序被装载到0x90200处, 系统映像于0x10000.(利用的是BIOS的中断处理INT 0x13)
实际上内核映像是压缩而成, 将引导扇区和引导辅助程序的映像拼接到一起. 大小超过(508KB=512KB-4KB)的称为大内核(后缀bzImage), 小者称为小映像(zImage). 内核会解压后都会装载在0x100000(1MB). -
setup执行过程中将由16位实地址转化为32位保护模式的段寻址方式, setup解压缩 装载 内核映像至0x100000.
-
开启PE, 装载GDT IDT
-
跳转到0x100000, 开始内核初始化.
内核初始化
系统初始化-1
-
SMP结构系统中主CPU开始执行
start_up
, 位于物理地址0x100000处, 这部分地址是位于线性映射区, 那么虚拟地址为(0xC0000000+0x100000 = 0xC0100000).但是段描述表中的
__KERNEL_DS
的值为0, CS被设置成0, IP被ljmp 0x10000 设置成0x10000,所以CPU在进入startup_32
之后ahis使用物理地址取指令.(实际上不跳转的话是可以继续执行的) -
首先, CPU将除CS外所有段寄存器(
%ds
,%es
,%fs
和%gs
)设置成__KERNEL_DS
(0x18 表示GDT中下表为3的描述项目, RPL为0, 段基址为0) -
填入2个用户页目录项和766个空白页目录项(
BOOT_USR_PGD_PTRS
= 768) , 2个内核页目录项目254个页目录项(BOOT_KERNEL_PGD_PTRS
=256)总数为1024
所以总空间为1K1K4KB = 4GB虚拟存储.注意到: 用户空间和内核空间都映射了开头的两个页目录项目而且值相同, 表示指向了相同的页面映射表.
用户区放同样目录项目的原因是为了平稳过度, CPU进入start_up()到开启页式映射前都是使用的物理地址, 在
这种情况下, 如果映射目录只包含虚存高区映射,那么一旦开启页式映射, 因为此时CPU的取指令IP仍然指向低区, 仍然会以物理地址取指令(书中的描述我认为有问题, 实际上分页后这里IP是没有变化(没有加_PAGE_OFFSET)的所以访问的虚拟地址是指向低区, 那么如果该地址没有映射则无法确认物理页, 这里巧妙的设置了双份目录项就是为了访问低区地址仍然映射到相同的物理区不影响执行). 直至发生绝对地址跳转.解决方案:
- 先开启页式映射, 但是在虚存空间的低区暂时提供与高区相同的映射, CPU继续可执行.
- 开启了页式映射后, 以一个符号地址(有偏移了)为目标执行一条绝对转移指令.强制转换到高地址区.
-
在
pg0
到empty_zero_page
之间的8K设置成页面映射表.(主CPU负责初始化, 次CPU跳过该