BUAA-OS-Lab2
Lab2:内存管理
[toc]
访存流程概览
内核态
内核态是操作系统运行的一种状态,与用户态相对,在这种状态下,计算机系统赋予了操作系统内核最高的权限。包括但不限于:
- 拥有最高权限:CPU可执行指令集中的所有指令,包括特权指令,进而直接访问和控制关键资源和硬件。
- 访问所有内存空间。
- 处理中断和异常。
- 系统资源管理:如CPU时间片分配,进程的创建与销毁等。
内存布局
在我们设计的MOS操作系统中,内存的布局以及虚实映射关系如下:
- 虚拟地址:
0x00000000~0x7fffffff(kuseg),这2GB空间用于存放用户程序代码与数据。需要通过TLB转化为物理地址,再通过cache访存。 - 虚拟地址:
0x80000000~0x9fffffff(kseg0),这512MB空间用于存放内核代码与数据。将虚拟地址的最高位置零得到物理地址,通过cache访存。 - 虚拟地址:
0xa0000000~0xbfffffff(kseg1),这512MB空间可以用于访问外存,将虚拟地址的最高三位置零得到物理地址,不通过cache访存 - 虚拟地址:
0xc0000000~0xffffffff(kseg2),这1GB空间只能在内核态下使用,并且需要通过TLB转化为物理地址,通过cache访存
在4Kc(实验所用CPU)中,通过硬件MMU来完成上述地址映射,MMU中集成了TLB。对所有第2GB空间的访存都需要经过TLB。


内核程序启动
mips_init函数是在基于MIPS架构的操作系统内核代码里出现的一个初始化函数。它的主要作用是对 MIPS 架构相关的硬件和软件环境进行初始化操作。它需要调用调用如下函数
mips_detect_memory(u_int _memsize)
该函数作用是探测硬件可用内存,并对一些和内存管理相关的变量进行初始化。
mips_vm_init()
该函数作用是建立一些用于管理的数据结构。
为了建立起内存管理机制,还需要用到alloc函数来分配内存空间。
1 | staticvoid *alloc(u_intn,u_intalign, intclear) { |
extern char end[]:外部变量 end,它表示内核代码和全局变量所占用内存的结束地址。在MOS系统中,end对应虚拟地址0x80400000,根据对应规则,转化为物理地址就是0x00400000。我们从该地址开始进行内存分配。ROUND(freemem, align):作用是将freemem按照align向上对齐,例如freemem为101,align为4,则对齐后为104。if (clear) {...}:当clear为真,该函数会将这一部分内存清零。
实现完分配函数后,我们要完成对内存管理数据结构的空间分配。
1 | void mips_vm_init() { |
这里使用alloc函数为物理内存管理所用到的Page结构体按页分配物理内存。
物理内存管理
MOS中的内存管理使用页式内存管理,采用链表法管理空闲物理页框。
页控制块
MOS中维护了npage个页控制块,也就是Page结构体。每一个页控制块对应一页的物理内存,MOS用这个结构体来按页管理物理内存的分配。
将空闲物理页对应的Page结构体全部插入一个链表中,该链表被称为空闲链表,即page_free_list。 当一个进程需要分配内存时,就需要将空闲链表头部的页控制块对应的那一页物理内存分配出去,同时将该页控制块从空闲链表中删去。 当一页物理内存被使用完毕(准确来说,引用次数为0)时,将其对应的页控制块重新插入到空闲链表的头部。
虚拟内存管理
前面已经提到,MOS中用PADDR(x)宏可以将位于kseg0的虚拟地址x转化为对应的物理地址。KADDR(x)宏可以返回物理地址x位于kseg0的虚拟地址。
两级页表结构
第一级页表称为页目录(Page Directory),第二级页表称为页表(Page Table)。
对于一个32位的虚存地址,其31-22位,共10位表示的是一级页表项的偏移量。21-12位,共10位表示的是二级页表项的偏移量。11-0位,共12位表示的是页内偏移量。
include/mmu.h中提供了两个宏以快速获取偏移量,PDX(va)可以获取虚拟地址va的31-22 位,PTX(va) 可以获取虚拟地址va的21-12 位。
一级页表与二级页表的结构相同:1024个页表项 + 每个页表项32位(20位物理页号 + 高6位硬件标志位 + 低6位软件标志位)。每个页表4KB,刚好是一个物理页面的大小。
访问内存与TLB重填
TLB组成
TLB是页表的高速缓存,是一种硬件,用于缓存最近使用过的虚拟页号(VPN)和对应的物理页框号(PPN)的映射关系,以加快虚拟地址到物理地址的转化速度。
每个TLB表项都有两个组成部分,包括一组Key和两组Data。EntryLo0存储Key对应的偶页而EntryLo1存储 Key对应的奇页。
当TLB缺失时, EntryHi中的VPN自动(由硬件)填充为对应虚拟地址的虚页号。
4Kc处理器架构
4Kc中与内存管理相关的CP0寄存器如下:


4Kc中的TLB采用奇偶页的设计,即使用VPN中的高19位与ASID作为Key,一次查找到两个Data(一对相邻页面的两个页表项),并用VPN中的最低1位在两个Data中选择命中的结果。因此在对TLB进行维护(无效化、重填)时,除了维护目标页面,同时还需要维护目标页面的邻居页面。


TLB事实上构建了一个映射TLB→ <PFN,C,D,V,G >。(Physical Frame Number)
TLB相关指令
tlbr:以Index寄存器中的值为索引,读出TLB中对应的表项到EntryHi与EntryLo0、EntryLo1。tlbwi:以Index寄存器中的值为索引,将此时EntryHi与EntryLo0、EntryLo1的值写到索引指定的TLB表项中。tlbwr:将EntryHi与EntryLo0、EntryLo1的数据随机写到一个TLB表项中(此处使用Random寄存器来“随机”指定表项,Random寄存器本质上是一个不停运行的循环计数器)tlbp:根据EntryHi中的Key(包含VPN与ASID),查找TLB中与之对应的表项,并将表项的索引存入Index寄存器(若未找到匹配项,则Index最高位被置1)
tlbp中,p代表probe,搜索与指定虚拟地址(此时虚拟地址体现于EntryHi)相匹配的条目。
软件必须经过CP0与TLB交互,因此软件操作TLB的流程总是分为两步:
- 填写
CP0寄存器。 - 使用
TLB相关指令。
TLB的维护
更新页表中虚拟地址
va对应的页表项时,将TLB中对应的旧表项无效化。在下次访问该虚拟地址时,硬件会触发
TLB重填异常,此时操作系统对TLB进行重填。tlb_invalidate函数实现删除特定虚拟地址在TLB中的旧表项(无效化)。
_do_tlb_refill(Pte *pte, u_intva, u_intasid)重填。








