x86_physical_layout

总结关于x86物理内存布局和real mode/protect mode相关的基本知识

1 x86 physical address layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

+------------------+ <- 0xFFFFFFFF (4GB)
| 32-bit |
| memory mapped |
| devices |
| |
/\/\/\/\/\/\/\/\/\/\

/\/\/\/\/\/\/\/\/\/\
| |
| Unused |
| |
+------------------+ <- depends on amount of RAM
| |
| |
| Extended Memory |
| |
| |
+------------------+ <- 0x00100000 (1MB)
| BIOS ROM |
+------------------+ <- 0x000F0000 (960KB)
| 16-bit devices, |
| expansion ROMs |
+------------------+ <- 0x000C0000 (768KB)
| VGA Display |
+------------------+ <- 0x000A0000 (640KB)
| |
| Low Memory |
| |
+------------------+ <- 0x00000000

8086的16位架构,操作系统只能利用2^20的地址,也就是1MB,也就是上图中0x0000000到0x00100000的区域。其中0x0到0xA0000的640KB是RAM使用,0xA0000到0xF0000的320KB是设备使用比如VGA,0xF0000到0x100000的64KB是BIOS使用。

在扩展到80386的32位架构后,系统可以收用2^32的4GB的地址。为了兼容16位系统,0xA0000到0x100000的区域(原先BIOS和设备区域)不再使用而空出。把原来0x0到0xA0000的RAM区域称为Low memory区域,1MB之后的RAM区域称为Extended Memory区域。BIOS和设备内存区域移动到32位区域的顶部。

可想而知当扩展到64位架构之后,为了系统向后兼容,又会产生第二个空闲区域。

2 real mode和protect mode

2.1 real mode

real mode wiki
real mode是x86系统都兼容的一个运行模式,出现在早期的8086/8088架构时期。

  • real mode支持20位寻址,也就是1MB的内存空间。
    • 使用段寄存器(16位)和偏移寄存器(16位)计算地址: segment * 16 + offset
  • 运行程序可以直接访问物理内存,I/O地址和外部设备
  • 因此不提供内存保护(memory protection)/多任务(multitasking)和权限(code privilege levels)

2.2 protect mode

protect mode wiki
80286引进protect mode, 80386加强

1
2
3
4
5
6
7
8
           Selector  +--------------+         +-----------+
---------->| | | |
| Segmentation | | Paging |
Software | |-------->| |----------> RAM
Offset | Mechanism | | Mechanism |
---------->| | | |
+--------------+ +-----------+
Virtual Linear Physical

2.2.1 提供

  • 虚拟内存(virtual memory)
  • 页表(page)(386引进)
  • 安全的多任务(multi-tasking)处理(286引进)
  • 无需重置CPU切换回real mode(386引入)

2.2.2 段寻址(80286开始)

  • real mode中段部分替换为16位的选择器(selector), 高13位代表GDT的条目索引, 最低2位确定了请求的权限等级(0代表最高等级/3代表最低等级)
  • GDT介绍
    • GDT条目(segment descriptor)有8字节长,定义了段的基地址(base address 32位),段的大小(limit 20位)以及权限(access rights)
      注意base的32bits是分成8bits, 8bits和16bits的, limit的20bits是分成16bits和4bits的
    • GDT的位置存在GDTR寄存器中,可以使用LGDT指令写,只有一个GDT
  • 如果开启paging,则将计算出的linear address输入page table,否则直接映射到物理地址

2.2.3 paging(80386开始)

  • page管理使用page directories和page tables。
    • page directory是1个page的大小(4K)包含1024 page directories entries(PDE), PDE指向page table
    • page table同样是4K大小,包含1024个page tables entries(PTE),PTE指向实际的物理地址
  • page directories的地址存在控制寄存器CR3的高20位之中(参考控制寄存器)
  • 开启paging需要设置CR0的PG位
  • 一个时间内只会有1个page directory在使用中

2.2.4 flat mode

没有必要使用segment translation, 但是没有直接可以关闭segment translation的方式。

C 指针就是虚拟地址(virtual address)的偏移部分。 在boot/boot.S, 我们可以设置一个Global Descriptor Table (GDT)来通过使得所有segment base address为0而limit为0xffffffff来有效关闭segment translation。 因此selector部分就没有作用了,linear address总是等于虚拟地址(virtual address)的offset。

2.2.5 兼容real mode

为了提供向后兼容,286以real mode开始运行, 当系统程序设置了descriptor table(至少设置null descriptor/code segment descriptot和data segment descriptor)且开启控制寄存器CR0中的Protection Enable(PE)位之后,才可以进入protect mode。

1
2
3
4
5
6
7
8
9
10
; set PE bit
mov eax, cr0
or eax, 1
mov cr0, eax

; far jump (cs = selector of code segment)
jmp cs:@pm

@pm:
; Now we are in PM.

2.3 关于在real mode下的寻址能力

8086/8088/80186的地址总线是20位,用段寄存器和偏移寄存器寻址方式能产生21位,如果超过$2^{20}$则取模$2^{20}$,即偏移地址 - 0x10(A20line关闭)

80286的地址总线是24位也就是16MB的寻址能力,可以容纳21位,用段寄存器和偏移寄存器的方式寻址,最大寻址能力为0xFFFF0 + 0xFFFF = 0x10FFEF = 1MB + 64KB - 16(A20line打开)

2.4 80286下从protect mode切回real mode

直接重置CPU,由于RAM没有重置,CPU可以重新以real mode开始运行。