x86架构内核引导流程
Bootstrap
The PC hardware is designed to make sure BIOS always gets control of the machine first after the computer is powered on. The BIOS will be performing some test and initialization, e.g., checking memory available and activating video card.
After this initialization, the BIOS will try to find a bootable device from some appropriate location such as a floppy disk, hard disk, CD-ROM, or the network.
Then the BIOS will pass control of the machine to the bootloader who will load the operating system.
from pintos guide book
BIOS
BIOS(Basic Input/Output System), 是一种为操作系统和用户程序提供初始化运行时环境的程序
QEMU在i386 下,采用SeaBIOS开源项目作为默认引导程序
所以我们采用qmeu0-system-i386中提供的gdbserver实际感受BIOS的行为
debug hint
(gdb) target remote :1234
(gdb) set architecture i8086 # 设置架构为16位
(gdb) set disassembly-flavor intel # intel style asm
Getting Real (Debug)
在BIOS中,CPU刚启动时处于16位实模式,硬件电路对段寄存器做了一个非常特殊的初始化
代码段选择子
CS:0xF000代码段基址
CS Base:被硬件强制设为0xFFFF0000(高位全 1)指令指针
IP:0xFFF0
所以在第一步调试就会遇到问题

显然这是一个无效反汇编
CS Register在Real Mode中是定位代码段的寄存器,CS存储段基地址,IP则是该代码段的offset ,这样共同定位代码指令
但是gdb软件层面的默认寻址机制并不知道 CPU 内部这些由硬件隐式维护的段基址
所以直接读取$ip的时候,会直接去找0xfff0地址上的指令,而不是0xffff0上的指令

这样可以直观展示出来
BIOS 中断向量表(IVT)的建立
Interrupt Vector Table, IVT是 x86 架构 CPU 在实模式 (Real Mode) 下用于处理中断和系统调用的内存数据结构
本质上是一个包含 256 个内存地址指针的数组,存放于系统物理内存的最底部,0x00000 到 0x003FF

我们走到0x7c00地址处,此时BIOS已经根据标准初始化硬件结束,查看IVT
在 16 位实模式下,IVT 占据内存物理地址的最前端 0x00000 到 0x003FF(共 256 个中断,每个中断占 4 字节,总计 1024 字节/1KB)
每个中断向量占用 4 字节
格式为:
[16位 Offset][16位 Segment]
这些中断处理函数逻辑是在出厂时写入到ROM中的,IVT的构建是运行时构建的
中断的函数接口调用规范有严格的标准,IBM PC 兼容性规范
(gdb) printf "INT 10h -> CS=%04X, IP=%04X\n", *(unsigned short*)0x42, *(unsigned short*)0x40
使用这个macro可以直观观察对应中断向量的映射
POST
IVT的构建不是一成不变的,它是通过BIOS动态分析
在初始化IVT后会扫描 Option ROM
例如: 发现了VGA显卡ROM,调用显卡 ROM 初始化代码(显卡自检等)
随后主版将显卡 ROM 的代码映射到了内存物理地址 0xC0000 处
主板 BIOS 通过一条 远跳转/远调用指令(Far Call 0xC000:0x0003),让 CPU 指针 跳转到显卡 ROM 映射区去执行代码
CPU 开始逐行执行显卡 ROM 里的指令。当执行到 mov [0x0040], 0x560E 和 mov [0x0042], 0xC000 这类写入指令时,CPU 会将显卡 ROM 自己的入口地址(C000:560E)强行写进内存最底部的 IVT(0x00000)中
这就是硬件的动态挂载
所以主版和这些Optional设备是相互协作的
优点:
解耦与即插即用:主板 BIOS 不需要懂任何显卡细节,只需要找到
0xC0000处的 Option ROM 并调用它,显卡就会自动把自己的驱动挂载进系统。统一的系统接口:对你的 MBR 引导代码或 DOS 来说,你根本不需要关心当前插的是什么显卡。你只需要触发
int 0x10,CPU 就会自动顺着 IVT 跳转到C000:560E去执行该显卡专属的渲染代码。
Optional ROM
x86早期显卡和扩展硬件设计中一个非常经典的概念就是Optional ROM
在 16 位实模式下,整个 1MB(0x00000 ~ 0xFFFFF)内存空间被 IBM 严格划分成了不同用途的区块
在刚刚上面的指令执行时发现,CS寄存器为0xC00,这是因为IBM对内存空间有严格划分
0x00000 ~ 0x9FFFF(0 ~ 640KB):常规 RAM,供 OS、中断表(IVT)、BDA 和 MBR 使用。
0xA0000 ~ 0xBFFFF(640KB ~ 768KB):保留给显存(Video RAM),比如文本模式的0xB8000。
0xC0000 ~ 0xC7FFF(768KB ~ 800KB):专门预留给 VGA 显卡 BIOS (Video BIOS)
0xF0000 ~ 0xFFFFF: BIOS ROM (主板 BIOS 代码)
VGA就属于扩展设备,所以中断向量表中的指针指向了对应的区域
qemu-system-i386 -device isa-debug-exit -drive format=raw,media=disk,index=0,file=/tmp/Et5FLbl28G.dsk -m 4 -net none -nS
回顾刚刚的qemu启动脚本,发现他也是默认开启模拟的VGA
