首先了解如何发现系统中的物理内存; 然后了解如何建立对物理内存的初步管理,即了解连续物理内存管理; 最后了解页表相关的操作,
即如何建立页表来实现虚拟内存到物理内存之间的映射,对段页式内存管
理机制有一个比较全面的了解。

系统内存的探测

分配内存空间前,必须获取物理内存空间的信息

e820map:
  memory: 0009fc00, [00000000, 0009fbff], type = 1.
  memory: 00000400, [0009fc00, 0009ffff], type = 2.
  memory: 00010000, [000f0000, 000fffff], type = 2.
  memory: 07ee0000, [00100000, 07fdffff], type = 1.
  memory: 00020000, [07fe0000, 07ffffff], type = 2.
  memory: 00040000, [fffc0000, ffffffff], type = 2.

1是可以使用的物理内存空间,

2是不能使用的物理内存空间。

注意, 2中的"不能使用"指的是这些地址不能映射到物理内存上, 但它们可以映射到ROM或者映射到其他设备,比如各种外设等。

实模式下进行探测,也就是在 bootloader 中添加了物理内存空间探测的功能。

一个内存映射地址描述符占 20字节

struct e820map {      // 该数据结构保存于物理地址0x8000
    int nr_map;       // map中的元素个数
    struct {
        uint64_t addr;    // 某块内存的起始地址
        uint64_t size;    // 某块内存的大小
        uint32_t type;    // 某块内存的属性。1标识可被使用内存块;2表示保留的内存块,不可映射。
    } __attribute__((packed)) map[E820MAX];
};

00h    8字节   base address            #系统内存块基地址
08h    8字节   length in bytes         #系统内存大小
10h    4字节   type of address range   #内存类型

INT 15h 进行物理内存空间探测

probe_memory:
    movl $0, 0x8000     # 初始化,向内存地址0x8000,即uCore结构e820map中的成员nr_map中写入0
    xorl %ebx, %ebx   
    movw $0x8004, %di   # e820map的成员变量nr_map清零
start_probe:
    movl $0xE820, %eax  # BIOS 0x15中断的子功能编号 %eax == 0xE820
    movl $20, %ecx      # 存放地址范围描述符的内存大小,至少20
    movl $SMAP, %edx    # 签名, %edx == 0x534D4150h("SMAP"字符串的ASCII码)
    int $0x15           # 调用0x15中断
    jnc cont            # 如果该中断执行失败,则CF标志位会置1,此时要通知UCore出错
    movw $12345, 0x8000 # 向结构e820map中的成员nr_map中写入特殊信息,报告当前错误
    jmp finish_probe    
cont:
    addw $20, %di       # 下一个位置 对应 e820map 的20 字节
    incl 0x8000         # e820::nr_map++
    cmpl $0, %ebx       # 如果%ebx为0,则说明当前内存探测完成
    jnz start_probe
finish_probe:
  1. 设置一个存放内存映射地址描述符的物理地址(这里是0x8000)
  2. 将e820作为参数传递给INT 15h中断
  3. 通过检测eflags的CF位来判断探测是否结束。如果没有结束, 设置存放下一个内存映射地址描述符的物理地址,然后跳到步骤2;如果结束,则程序结束