2. 计算机体系结构基础回顾:CPU、内存、I/O设备的基本概念;x86与ARM架构的启动流程;实模式与保护模式
好,咱们正式开始动手之前,得先把地基打牢。很多同学一上来就急着写代码,结果连CPU怎么取指令、内存怎么编址都没搞明白,后面调试起来那叫一个痛苦。我个人习惯是,先花点时间把体系结构的关键脉络理清楚,后面写内核时心里才有底。
2.1 三大核心部件:CPU、内存、I/O
计算机系统说白了就三样东西:CPU、内存、I/O设备。你想想看,不管多复杂的系统,最终都逃不出这个框架。
CPU(中央处理器)
CPU是大脑,负责执行指令。它内部有几个关键部件:
- 寄存器:CPU内部的高速存储单元,访问速度比内存快几个数量级。x86里有EAX、EBX、ECX等通用寄存器,还有EIP(指令指针)、EFLAGS(标志寄存器)等特殊寄存器。
- 算术逻辑单元(ALU):负责加减乘除、与或非等运算。
- 控制单元:负责取指令、译码、调度执行。
内存
内存就是存放指令和数据的地方。CPU通过地址总线访问内存,每个地址对应一个字节。这里有个关键概念——内存映射。在x86的实模式下,内存地址是20位的,最大寻址1MB。到了保护模式,地址变成32位,能访问4GB空间。
I/O设备
键盘、鼠标、硬盘、显示器……这些都是I/O设备。CPU怎么跟它们通信?两种方式:
- 端口映射I/O:x86用IN/OUT指令,通过专门的I/O端口地址访问设备。比如键盘控制器通常挂在0x60端口。
- 内存映射I/O:把设备寄存器映射到内存地址空间,直接用内存读写指令操作。ARM架构几乎全用这种方式。
我在项目中遇到过一个问题:某块网卡用内存映射I/O,但它的寄存器地址恰好和内存条的区域冲突了。折腾了两天才发现是BIOS里没正确配置MMIO区域。嗯,这种坑踩过一次就记住了。
2.2 x86与ARM的启动流程
启动流程,说白了就是CPU上电后,从哪开始执行第一行代码。x86和ARM的思路完全不同,咱们分别看看。
x86启动流程
- 上电复位:CPU的CS寄存器被初始化为0xF000,IP寄存器为0xFFF0。所以第一条指令的物理地址是0xFFFF0(即0xF000 << 4 + 0xFFF0)。
- 跳转到BIOS:这个地址通常是一条跳转指令,直接跳到BIOS的入口。BIOS开始执行POST(上电自检)。
- BIOS加载引导扇区:BIOS扫描启动设备(硬盘、U盘等),读取第一个扇区(512字节)到内存0x7C00处,然后跳过去执行。
- 引导程序接力:这个512字节的引导代码(比如GRUB的stage1)再加载更复杂的引导程序,最终加载内核。
ARM启动流程
ARM的启动方式灵活得多,但主流SoC(比如树莓派的BCM2837)通常是这样:
- 上电复位:CPU从固定的复位向量地址取指令。这个地址通常映射到ROM或片上SRAM。
- 一级引导(BootROM):芯片内部的BootROM代码开始执行,它初始化时钟、内存控制器等基础硬件。
- 二级引导:BootROM从SD卡、eMMC或SPI Flash中读取二级引导程序(比如树莓派的bootcode.bin),加载到片上SRAM。
- 加载内核:二级引导程序再加载真正的操作系统内核(比如Linux的kernel.img)到DRAM,然后跳转执行。
你可能会问:为什么ARM搞这么复杂?因为ARM芯片的启动介质太多了,SD卡、NAND Flash、USB……BootROM得先判断从哪启动,再一步步把代码“搬”到内存里。
2.3 实模式与保护模式
这两个模式是x86体系结构的精髓。我刚开始学的时候也觉得绕,但搞明白后,你会发现它其实很优雅。
实模式(Real Mode)
这是x86 CPU的“出厂设置”。特点如下:
- 地址空间:20位地址线,最大1MB。
- 寻址方式:段地址 << 4 + 偏移地址。比如段地址0x1000,偏移0x1234,物理地址就是0x1000 << 4 + 0x1234 = 0x11234。
- 无保护:任何程序都能访问任何内存地址,包括硬件中断向量表。写错了直接死机。
- 中断向量表:固定在内存0x00000处,每个中断向量占4字节(段地址+偏移地址)。
保护模式(Protected Mode)
从80386开始,x86引入了保护模式。它带来了三个核心能力:
- 32位地址空间:直接寻址4GB,不再需要段寄存器左移4位。
- 内存保护:通过段描述符和页表,实现权限控制(内核态/用户态)、地址隔离。
- 分页机制:虚拟地址到物理地址的映射,每个进程可以拥有独立的地址空间。
从实模式切换到保护模式,需要做这几步:
- 关闭中断(CLI指令)。
- 加载全局描述符表(GDT),定义代码段、数据段等描述符。
- 设置CR0寄存器的PE位(保护模式使能位)为1。
- 执行远跳转(JMP指令),刷新CPU流水线。
下面是一个简化的切换代码示例(NASM语法):
; 切换到保护模式
cli ; 关闭中断
lgdt [gdt_ptr] ; 加载GDT
mov eax, cr0
or eax, 0x1 ; 设置PE位
mov cr0, eax
jmp 0x08:protected_mode ; 远跳转刷新流水线
[bits 32]
protected_mode:
; 现在已经在保护模式下了
mov ax, 0x10 ; 数据段选择子
mov ds, ax
mov es, ax
mov ss, ax
; ... 继续初始化
2.4 知识体系总览
为了让你更直观地理解本章的知识结构,我画了一张图。它把CPU、内存、I/O的关系,以及x86/ARM的启动路径、实模式与保护模式的切换,都串在了一起。
这张图把本章的核心内容都囊括了。你可以把它当作一个“导航图”,后面写内核代码时,随时回来对照,看看当前代码运行在哪个阶段、操作了哪些硬件。
公众号:蓝海资料掘金营,微信deep3321