阅读更多
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
),加载在内存地址0x7C00
MBR
经过一系列操作,最终把控制权交给操作系统
二级引导器的作用:
- 收集机器信息
- 对
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 Memory
linu
:Linux
z
:压缩
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