OS-Lab2
一.TLB访存机制
当一个虚拟地址被送到MMU中进行翻译的时候,硬件首先在TLB中寻找包含这个地址的页面,如果它的虚页号在TLB中,并且没有违反保护位,那么就可以直接从TLB中得到相应的物理页号,而不去访问页表;如果发现虚页号在TLB中不存在,那么MMU将进行常规的页表查找,同时通过一定的策略来将这一页的页表项替换到TLB中,之后再次访问这一页的时候就可以直接在TLB中找到。
拿到了物理地址后,可以直接访问内存拿数据,不过会慢,所以,Cache就是部分物理地址到数据的映射。是内存的一部分copy。
二.二级页表
首先,c语言可以操作任何空间的地址,这个就是虚拟地址。
我们要做的就是模拟二级页表机制,往虚拟地址里面填写物理地址,再通过f(va)−>pa和f(pa)→va转换取到地址里面的东西。
简单来说,把放着很多很多页的虚拟地址,按照虚拟地址的索引,把它对应的物理地址放到另一个虚拟地址pgidr里。
这样就“假装”建立起了二级页表,物理地址从未使用过,要访问时永远要加上ULIM。
Page
结构体其实是物理地址的一个“象征”。因为它减去pages拿到ppn以后,shift12位再加上ULIM,就是虚拟地址,减去ULM又变回物理地址。建立起来虚拟页和物理页之间的桥梁。尽管自己不是真正的4KB页,但是是桥梁。
三.Page存储结构
四.自映射机制图示
五.页面与地址的转化
在本次实验中涉及到许多的页面与地址的转化,其中用到许多已经定义的函数,现整理如下:
page2pa:得到某个page结构体的物理地址
1 |
|
pa2page:得到某个物理地址所对应的Page结构体
1 |
|
page2kva:得到某个Page结构体的内核虚拟地址
1 |
|
PPN:得到某个虚拟地址的页号
1 |
|
PADDR:将某个内核虚拟地址转化为物理地址
1 |
|
KADDR:将某个物理地址转化为内核虚拟地址
1 |
|
本次实验的前半部分涉及了许多对这类函数的应用,熟练掌握这类函数实现各类地址查询是本次实验的一大难点。
六.部分实验代码详解
部分代码含义解释如下:
1 |
|
其余的一些定义(异常码的解释略去):
1 |
|
最后是一些函数与函数宏:
void bcopy(const void *, void *, size_t)
:内存拷贝void bzero(void *, size_t)
:内存清空assert(x)
:支持断言机制。TRUP(_p)
:相当于min(_p, ULIM)
,似乎是为了防止用户读写内核段内存。
在进行内存初始化时,mips_detect_memory()
、mips_vm_init()
与page_init()
被依次调用。mips_detect_memory()
用来初始化一些全局变量(此处将物理内存大小设置为64MB,在实际中,内存大小是由硬件得到的,这里只是模拟了检测物理内存大小这个过程)。其余的函数的功能为:
static void *alloc(u_int n, u_int align, int clear)
:申请一块内存,返回首地址。static Pte *boot_pgdir_walk(Pde *pgdir, u_long va, int create)
:从页目录项中找出虚拟地址va
对应的页表项,若create
置位,则不存在时创建。void boot_map_segment(Pde *pgdir, u_long va, u_long size, u_long pa, int perm)
:将虚拟地址va
映射到物理地址pa
。void mips_vm_init()
:创建一个二级页表。void page_init(void)
:将内存分页并初始化空闲页表。int page_alloc(struct Page **pp)
:分配一页内存并把值赋给pp。void page_free(struct Page *pp)
:释放一页内存。int pgdir_walk(Pde *pgdir, u_long va, int create, Pte **ppte)
:建立起二级页表结构后从页目录中找到va对应页表项的函数。int page_insert(Pde *pgdir, struct Page *pp, u_long va, u_int perm)
:将物理页pp映射到va。struct Page * page_lookup(Pde *pgdir, u_long va, Pte **ppte)
:找到虚拟地址va对应的物理页面。void page_decref(struct Page *pp)
:降低物理页面的引用次数,降到0后释放页面。void page_remove(Pde *pgdir, u_long va)
:释放虚拟地址va对应的页面。void tlb_invalidate(Pde *pgdir, u_long va)
:更新TLB。