《操作系统实战 45 讲》笔记 1——引导部分
05 | CPU 工作模式:执行程序的三种模式
实模式 --> 保护模式 --> 长模式
三个模式就是 Intel CPU 的发展史,发展的主线是支持更大的内存,以及提供必要的保护机制。
虽然现在都是 64 位了,但是还得了解实模式和保护模式,这是由于兼容性的原因,在引导流程中会经历这三个模式:BIOS 工作在实模式,引导程序工作在实模式,最后 kernel 切到长模式运行,这些内容在第 10、11 讲。
保护模式中保护的含义
段选择子(CS、SS)最低 2 位是 RPL(Request Privilege Level)
段描述符的 45、46 位是 DPL(Descriptor Privilege Level)保护模式就是根据这两个字段实现访问权限控制。
切换到保护模式的步骤
1、准备全局段描述符表
第一行必须为 0。引导程序都是平坦模型,关键的几个位:
55 位 G 为 1,表示段长粒度 4KB
54 位 D/B 为 1,表示操作数是 32 位
43 位 T,代码段 1,数据段 0
43 位 C,是否可执行
2、加载 GDTR 寄存器
3、设置 cr0 寄存器
4、长跳转,加载 CS 段寄存器
0x8 换成二进制 1000,段选择子低 3 位为 TI 和 RPL,TI 为 0 表示从 GDT 中查询,偏移 1 为 kcode_dsc,再在段基的基础上偏移 _32bits_mode。
切换到长模式的步骤
1、准备全局段描述符表
53 位 L 为 1,表示段是 64 位模式
43 位 T,同上
2、准备页表
长模式下内存地址空间的保护交给了 MMU,段描述中的段基和段长已无效。
cr4 的第 5 位开启 PAE
cr3 指向页表物理地址
3、加载 GDTR 寄存器
基于上面那个段描述符表,输入和输出是一样的,真正的转换落到了 MMU。
4、开启长模式
IA32_EFER 寄存器的地址为 0xC0000080,有两个专门的指令进行读写。
5、加载 CS 段寄存器
06 | 虚幻与真实:程序中的地址如何转换?
长模式 4KB 页,每个项表 512 个条目,5125125125124KB=256TB,实际上只能寻址 48 位,这是由于 x86 CPU 只实现了 48 位的地址总线。页表本身占用空间 45128B = 16KB。
07 | Cache 与内存:程序放在哪儿?
开启 Cache
内存视图
所有硬件都有物理地址,例如 BIOS ROM 的地址是 0xffff0,CPU 加电后 CS:IP 寄存器就会设置为该地址,以运行 BIOS 程序,而物理内存 RAM 每没有固定的地址,而该信息对于 kernel 运行至关重要,可以从 BIOS 提供的实模型下的中断服务获取内存视图。
在第 12 讲二级引导程序中使用了该函数。
10 | 设置工作模式与环境(上):建立计算机
创建虚拟硬件个几个小问题:
1、 loop0 无法正常使用如下命令查看空闲的,换一个即可
2、 grub-install 失败
指定一下 --target=i386-pc
11 | 设置工作模式与环境(中):建造二级引导器
GRUB 头 imginithead.asm 中切换 32bits_mode,并没有设置 CR0.PE,而在第 15 讲引导 linux 时却在 go_to_protected_mode 函数中设置了 CR0.PE,一开始我以为是笔误,后来发现引导器也有很多规范:
Cosmos 遵守的是 GRUB Multiboot Specification,所以在执行 imginithead.asm 时已经是 32 位保护模式;
而 linux 采用的是自己的规范,引导的时候是 16 位实模式。
详见:https://stackoverflow.com/questions/4821911/does-grub-switch-to-protected-mode
12 | 设置工作模式与环境(下):探查和收集信息整个引导流程:
BIOS(0xffff0) ,将硬盘第一扇区加载到 0x7c00,也就是主引导器 GRUB
GRUB 主引导(0x7c00) ,initldrimh.bin 按照 Multiboot Specification 被执行
将 initldrsve.bin 加载到 0x1000
将 initldrkrl.bin 加载到 0x200000
二级引导器 initldrkrl.bin(0x200000)
通过 initldrsve.bin 调 BIOS 中断获取机器信息,由于 BIOS 中断是实模式,而引导程序是保护模式,所以封装了 initldrsve.bin 处理模式的切换
将 Cosmos.bin 加载到 0x2000000
建立 MMU 页表
内核 Cosmos.bin(0x2000000),
13 | 第一个 C 函数:如何实现板级初始化?
版权声明: 本文为 InfoQ 作者【袁世超】的原创文章。
原文链接:【http://xie.infoq.cn/article/8976dd2bdcb8c65c085f2ec3f】。文章转载请联系作者。
评论