PC架构
PC组成
- x86 CPU,其中包含一组寄存器,执行单元,内存管理硬件.
- CPU芯片管脚,其中包含地址和数据信号.
- 内存
- 硬盘
- 键盘
- 显示器
- 其他资源: 只读BIOS, 时钟等.
启动
我们将从1978年推出的16位的8086 CPU开始.
CPU指令执行
只要不出现改变EIP寄存器的指令,EIP将永远递增,不断执行下一条指令.
工作空间: 数据寄存器
- 4个16位数据寄存器: AX, BX, CX, DX
- 每个都可以分为高低两个,比如: AH和AL.
- 寄存器速度非常快,也非常少.
更大的工作空间: 内存
- CPU通过地址线来控制访问地址.
- 数据则由数据线传递.
地址寄存器: 指向内存
- SP: 栈顶寄存器
- BP: 栈底寄存器
- SI: Source index,源变址寄存器
- DI: Destination index,目的变址寄存器
指令位置
- 指令保存在内存中
- IP: instruction pointer, 程序计数器
- 通常自增
- 可以被如下指令修改: CALL, RET, JMP, 条件跳转.
条件跳转
FLAGS标志位
- 算术操作溢出
- 正负
- 零/非零
- 加减的借位
- 中断
- 直接数据拷贝
相关指令
- JP, JN, J[N]Z, J[N]C, J[N]O.
I/O
原始PC架构: 专用IO空间
- 和内存操作相似,但使用IO信号.
- 只有1024个IO地址
- 使用特定指令操作(IN, OUT)
示例,写一个字节到line printer:
#define DATA_PORT 0x378 #define STATUS_PORT 0x379 #define BUSY 0x80 #define CONTROL_PORT 0x37A #define STROBE 0x01 void lpt_putc(int c) { /* wait for printer to consume previous byte */ while((inb(STATUS_PORT) & BUSY) == 0) ; /* put the byte on the parallel lines */ outb(DATA_PORT, c); /* tell the printer to look at the data */ outb(CONTROL_PORT, STROBE); outb(CONTROL_PORT, 0); }
现代PC架构: 内存映射IO
使用正常的物理内存地址
1.1 突破了IO地址空间的限制 1.2 不需要特殊的操作指令 1.3 系统控制器将在对应的设备间充当路由功能.
操作设备如同操作一块神奇的内存
2.1 寻址,访问等操作和操作内存一样 2.2 操作结果和内存不同 2.3 读写设备映射内存均会导致不同的反应 2.4 外部事件变化可能会导致读取的结果发生变化
内存限制突破
如何突破2^16的内存地址限制?
- 8086芯片的物理寻址能力是20bit,因此可以访问的内存空间是1MB.
- 那额外的4位来自16位的段寄存器
- CS: 指令段寄存器,和IP寄存器搭配使用
- SS: 栈段寄存器,和SP,BP寄存器搭配使用
- DS: 数据段寄存器
- ES: 另一个数据段寄存器,字符串操作目的寄存器
- 寻址公式: 物理地址 = 虚拟地址 + 16*段寄存器
- 注意: 仅使用16位地址并不能作为指针使用
- 完整的指针包括: 段:偏移,是(16+16)bit
- 注意: 指针运算和数组偏移越过段边界的情况
突破8086的内存使用限制
8086使用的是16位地址和数据寄存器,其内存寻址能力太小了,最大可用内存仅有1MB.
- 1985年推出的80386芯片使用32位地址和数据寄存器.
- 为了保证前向兼容,在启动时为16位模式.在BootLoader的前半段boot.S中,将会切换为32位模式.
- 寄存器由16位扩展为32位,因此寄存器名称也由AX改为EAX,其中E就是Extend的缩写.
- 操作和寻址的位宽也由16位改为32位
- 前缀0x66/0x67将会被添加到32位操作符之前,比如在32位模式,MOVW被解释为0x66 MOVW.
- 在boot.S中的.code32将告诉汇编器添加0x66前缀到指令之前.
- 除了上述改动,80386也改变了段寄存器,同时增加了分页支持.
示例
b8 cd ab 16-bit CPU, AX <- 0xabcd
b8 34 12 cd ab 32-bit CPU, EAX <- 0xabcd1234
66 b8 cd ab 32-bit CPU, AX <- 0xabcd