阅读更多
1 重点
linux_kernel_map

取指、访问内存数据
- 代码段是由
CS和IP确定的 - 栈段是由
SS和SP段确定的

2 夺权:启动初始化
2.1 设置环境
2.1.1 Ubuntu-18.04.6
1 | base_dir=/root/os |
2.1.2 CentOS-7.9-2009
1 | base_dir=/root/os |
第四步报错:
1 | Kernel driver not installed (rc=-1908) |
2.2 二级引导器
计算机如何启动:
- 通电
- 读取
ROM里面的BIOS,用来检查硬件(工作在实模式) - 硬件检查通过
BIOS根据指定的顺序,检查引导设备的第一个扇区(即MBR,在Linux中的MBR就是grub2,严格来说,是grub2中的boot.img),加载在内存地址0x7C00MBR经过一系列操作,最终把控制权交给操作系统
二级引导器的作用:
- 收集机器信息
- 对
CPU、内存、显卡进行一些初级配置 - 放置好内核相关的文件
Layout of Multiboot header:
| Offset | Type | Field Name | Note |
|---|---|---|---|
| 0 | u32 | magic | required |
| 4 | u32 | flags | required |
| 8 | u32 | checksum | required |
| 12 | u32 | header_addr | if flags[16] is set |
| 16 | u32 | load_addr | if flags[16] is set |
| 20 | u32 | load_end_addr | if flags[16] is set |
| 24 | u32 | bss_end_addr | if flags[16] is set |
| 28 | u32 | entry_addr | if flags[16] is set |
| 32 | u32 | mode_type | if flags[2] is set |
| 36 | u32 | width | if flags[2] is set |
| 40 | u32 | height | if flags[2] is set |
| 44 | u32 | depth | if flags[2] is set |
细节知识点:
jmp dword far [cpmty_mode]:长跳转这里表示把cpmty_mode处的第一个4字节装入eip,把其后的2字节装入cs
整个引导过程:
2.3 GRUB与vmlinuz的结构
这里提到的GRUB都是指GRUB2
2.3.1 从BIOS到GRUB
硬件工程师设计CPU时,硬性地规定在加电的瞬间,强制将CS寄存器的值设置为0XF000,IP寄存器的值设置为0XFFF0
- 由于开始的时候处于实模式,在实模式下的段地址要乘以
16,也就是左移4位,于是0xF000:0xFFF0的等效地址将是0xFFFF0。此地址就是BIOS的入口地址 - 在这个物理地址上连接了主板上的一块小的
ROM芯片。这种芯片的访问机制和寻址方式和内存一样,只是它在断电时不会丢失数据,在常规下也不能往这里写入数据,它是一种只读内存,BIOS程序就被固化在该ROM芯片里
当设备初始化和检查步骤完成之后,BIOS会在内存中建立中断表和中断服务程序,这是启动Linux至关重要的工作,因为Linux会用到它们
BIOS会从内存地址(0x00000)开始用1KB的内存空间(0x00000~0x003FF)构建中断表,在紧接着中断表的位置,用256KB的内存空间构建BIOS数据区(0x00400~0x004FF),并在0x0E05B的地址加载了8KB大小的与中断表对应的中断服务程序- 中断表中有
256个条目,每个条目占用4个字节,其中两个字节是CS寄存器的值,两个字节是IP寄存器的值。每个条目都指向一个具体的中断服务程序
Linux 通常是从硬盘中启动的。硬盘上的第1个扇区(每个扇区512字节空间),被称为MBR(主启动记录),其中包含有基本的GRUB启动程序和分区表,安装GRUB时会自动写入到这个扇区,当MBR被BIOS装载到0x7C00地址开始的内存空间中后,BIOS就会将控制权转交给了MBR。在当前的情况下,其实是交给了GRUB
2.3.2 GRUB是如何启动的
BIOS只会加载硬盘上的第1个扇区。不过这个扇区仅有512字节,这512字节中还有64字节的分区表加2字节的启动标志,很显然,剩下446字节的空间,是装不下GRUB这种大型通用引导器的
于是,GRUB的加载分成了多个步骤,同时GRUB也分成了多个文件,其中有两个重要的文件boot.img和core.img
- 其中,
boot.img被GRUB的安装程序写入到硬盘的MBR中,同时在boot.img文件中的一个位置写入core.img文件占用的第一个扇区的扇区号 - 而
core.img文件是由GRUB安装程序根据安装时环境信息,用其它GRUB的模块文件动态生成。如下图所示 
- 如果是从硬盘启动的话,
core.img中的第一个扇区的内容就是diskboot.img文件。diskboot.img文件的作用是,读取core.img中剩余的部分到内存中 - 由于这时
diskboot.img文件还不识别文件系统,所以我们将core.img文件的全部位置,都用文件块列表的方式保存到diskboot.img文件中。这样就能确保diskboot.img文件找到core.img文件的剩余内容,最后将控制权交给kernel.img文件 - 因为这时
core.img文件中嵌入了足够多的功能模块,所以可以保证GRUB识别出硬盘分区上文件系统,能够访问/boot/grub目录,并且可以加载相关的配置文件和功能模块,来实现相关的功能,例如加载启动菜单、加载目标操作系统等
正因为GRUB大量使用了动态加载功能模块,这使得core.img文件的体积变得足够小。而GRUB的core.img文件一旦开始工作,就可以加载Linux系统的vmlinuz内核文件了
2.3.3 详解vmlinuz文件结构
vmlinuz名字:
vm:Virtual Memorylinu:Linuxz:压缩
vmlinuz由bzImage复制而来
bzImage由setup.bin、vmlinux.bin、tools/build这三者构建而成(详见arch/x86/boot/Makefile)
- 其中
tools/build只是一个构件工具,用于将setup.bin、vmlinux.bin拼接成bzImage文件 setup.bin由objcopy工具根据setup.elf生成setup.elf由arch/x86/boot/目录下的源码编译链接而来
vmlinux.bin由objcopy工具根据vmlinux生成objcopy工具在处理过程中只是删除了vmlinux文件中.comment段,以及符号表和重定位表(通过参数-S指定),而vmlinux文件的格式是ELF格式的,所以vmlinux.bin仍然是ELF格式的vmlinux文件就是编译整个Linux内核源代码文件生成的vmlinux.bin文件它依然是ELF格式的文件
3 土地革命:内存
真实的物理内存地址空间不是连续的,这中间可能有空洞,可能是显存,也可能是外设的寄存器

- 硬件区:它占用物理内存低端区域,地址区间为
0~32MB。从名字就能看出来,这个内存区域是给硬件使用的,我们不是使用虚拟地址吗?虚拟地址不是和物理地址无关吗,一个虚拟可以映射到任一合法的物理地址。但凡事总有例外,虚拟地址主要依赖于CPU中的MMU,但有很多外部硬件能直接和内存交换数据,常见的有DMA,并且它只能访问低于24MB的物理内存。这就导致了我们很多内存页不能随便分配给这些设备,但是我们只要规定硬件区分配内存页就好,这就是硬件区的作用 - 内核区:内核也要使用内存,但是内核同样也是运行在虚拟地址空间,就需要有一段物理内存空间和内核的虚拟地址空间是线性映射关系。很多时候,内核使用内存需要大的、且连续的物理内存空间,比如一个进程的内核栈要
16KB连续的物理内存、显卡驱动可能需要更大的连续物理内存来存放图形图像数据。这时,我们就需要在这个内核区中分配内存了 - 应用区:这个区域主是给应用用户态程序使用。应用程序使用虚拟地址空间,一开始并不会为应用一次性分配完所需的所有物理内存,而是按需分配,即应用用到一页就分配一个页。如果访问到一个没有与物理内存页建立映射关系的虚拟内存页,这时候
CPU就会产生缺页异常。最终这个缺页异常由操作系统处理,操作系统会分配一个物理内存页,并建好映射关系
4 缩写表
| 缩写 | 全称 |
|---|---|
HAL |
Hardware Abstraction Layer |
5 源码命名
关于源码中的命名,个人感觉是该课程的不足之处,大量缩写,缺少解释说明,没有相关经验的话,基本全靠猜,对新人特别不友好
| 缩写 | 全称 |
|---|---|
adr |
Address |
chk |
Check |
krl |
Kernel |
mem |
Memory |
phy |
Physical |
sz |
Size |
vrm |
Video RAM |
6 参考
- 《极客时间-操作系统实战-彭东》
- 计算机是如何启动的?
- 为什么主引导记录的内存地址是0x7C00?
- Booting