Lab2:物理内存管理
物理内存布局的探测和管理
在Lab1当中,我们仅仅是把操作系统内核从硬盘上搬到了内存里,而没有对内存进行管理。
其实bootloader在加载ELF文件之前,首先会检测所有的物理内存块,把这些内存块的信息存储在内存当中的内存块信息表e820map当中,其中包括:块的起始地址addr、块的大小size、块的类型type(例如是不是可用的)。
当ucore内核开始运行时,将会利用这个信息表去建立一个Page结构表,它按物理地址的顺序,保存了每一个物理页(4KB)的信息,包括:物理页被虚拟页引用的次数、页是否被保留、空闲页链表指针、连续空闲页的页数。
随后,操作系统将会建立一个空闲页链表,它将所有连续空闲内存的起始页的Page结构链接起来。
这样,当用户对内存进行请求alloc_page(int n)
和释放free_page(int n)
的时候,直接遍历空闲页链表,并修改其中的Page结构即可。
分页机制的建立
在bootloader阶段,不仅初始化了全局描述符表,建立了段机制,同时也建立了临时的二级页表。而操作系统内核在后续过程中完善了二级页表,将操作系统所用的逻辑地址与物理地址对应起来。其中页目录的首地址保存在CR3
寄存器当中。此时逻辑地址、线性地址和物理地址的关系如下:
v
i
r
t
a
d
d
r
=
l
i
n
e
a
r
a
d
d
r
=
p
h
y
a
d
d
r
+
0
x
C
0000000
virt\ addr = linear\ addr = phy\ addr + 0xC0000000
virt addr=linear addr=phy addr+0xC0000000
也就是操作系统在物理内存实际是从0x0000000
开始,但是它看到的虚拟地址是0xC0000000
。
当分页机制建立之后,虚拟地址到物理地址的映射过程如下:
-
将虚拟地址分为段选择子和偏移,按照分段机制转化为线性地址
-
将线性地址分为3部分:页目录索引Dir、页表索引Table、偏移Offset
-
根据
CR3
寄存器找到页目录表,并根据Dir找到对应的页目录项 -
查询页目录项的标志位,若页表是否存在,若不存在则调用我们的
alloc_page
函数新建一个页表 -
根据页表索引找到页表项,里面存储了物理页的地址。如果物理页不存在,则需要继续分配内存。
可以看到,空闲内存的管理为分页机制提供了保障,至此操作系统完成了段页式机制的处理。程序的虚拟地址可以转化为物理地址了。