标签:开启 poi res 删除节点 好处 转换 MIP 不用 形式
请思考cache用虚拟地址来查询的可能性,并且给出这种方式对访存带来的好处和坏处。另外,你能否能根据前一个问题的解答来得出用物理地址来查询的优势?
cache用虚拟地址查询时可能的,只要CPU(程序)可以用虚拟地址取到正确物理地址中的数据,其中间经过的cache使用的地址并无大碍。
使用虚拟地址的cache时,优点在于查询cache前不用访问页表进行地址转换,缺点在于一旦cache中数据缺失,更新cache时需要访问页表,时间开销更大;同时多个程序的虚拟地址可能相同,安全性以及数据正确性比较难以保障,异或每个程序单独cache会对数据共享造成影响。
运用物理地址查询的优势便在于数据的安全性和方便共享。
请查阅相关资料,针对我们提出的疑问,给出一个上述流程的优化版本,新的版本需要有更快的访存效率。(提示:考虑并行执行某些步骤)
访问TLB出现缺失时,要更新TLB,但在更新TLB时访问页表的过程中我们需要的物理地址就已经可以获得了。因此可以并行更新TLB和查询cache。
在我们的实验中,有许多对虚拟地址或者物理地址操作的宏函数(详见include/mmu.h ),那么我们在调用这些宏的时候需要弄清楚需要操作的地址是物理地址还是虚拟地址,阅读下面的代码,指出x是一个物理地址还是虚拟地址。
int x;
char *value = return_a_pointer();
*value = 10;
x = (int) value;
x的值是虚拟地址
我们在 include/queue.h 中定义了一系列的宏函数来简化对链表的操作。实际上,我们在 include/queue.h 文件中定义的链表和 glibc 相关源码较为相似,这一链表设计也应用于 Linux 系统中 (sys/queue.h 文件)。请阅读这些宏函数的代码,说说它们的原理和巧妙之处。
我们注意到我们把宏函数的函数体写成了 do { /* ... */ } while(0)的形式,而不是仅仅写成形如 { /* ... */ } 的语句块,这样的写法好处是什么?
这样写可以保证宏在替换到程序当中时不会产生歧义或错误,使其是一个完整的语句块,相当于一条语句而不是多条语句,用起来更加方便。
注意,我们定义的 Page 结构体只是一个信息的载体,它只代表了相应物理内存页的信息,它本身并不是物理内存页。 那我们的物理内存页究竟在哪呢?Page 结构体又是通过怎样的方式找到它代表的物理内存页的地址呢? 请你阅读 include/pmap.h 与 mm/pmap.c 中相关代码,给出你的想法。
根据pmap.h中关于转换物理地址的函数代码:
static inline u_long
page2ppn(struct Page *pp)
{
return pp - pages;
}
/* Get the physical address of Page ‘pp‘.
*/
static inline u_long
page2pa(struct Page *pp)
{
return page2ppn(pp) << PGSHIFT;
}
可以发现计算物理地址主要用到的数据是指针pp相对于pages的偏移量。
阅读pmap.c可以发现pages定义为Page结构体的指针,容易知道其为一个数组的头指针,数组中的每一项顺序对应一块内存区域,通过辨别在数组中的项数即可对应物理内存页。
请阅读 include/queue.h 以及 include/pmap.h, 将Page\_list的结构梳理清楚,选择正确的展开结构(请注意指针)。
其为C:
struct Page_list{
struct {
struct {
struct Page *le_next;
struct Page **le_prev;
} pp_link;
u_short pp_ref;
}* lh_first;
在 mmu.h 中定义了 bzero(void *b, size_t) 这样一个函数,请你思考,此处的b指针是一个物理地址, 还是一个虚拟地址呢?
根据pmap.c中对这个函数的应用我们可以知道b指针是一个虚拟地址。
了解了二级页表页目录自映射的原理之后,我们知道,Win2k内核的虚存管理也是采用了二级页表的形式,其页表所占的 4M 空间对应的虚存起始地址为 0xC0000000,那么,它的页目录的起始地址是多少呢?
0xC0300000
注意到页表在进程地址空间中连续存放,并线性映射到整个地址空间,思考:是否可以由虚拟地址直接得到对应页表项的虚拟地址?上一节末尾所述转换过程中,第一步查页目录有必要吗,为什么?
可以直接由虚拟地址得到页表项地址,取消二级页表的设定,只使用一级页表;或是通过转换计算亦可。
设置页目录可以节约页表的内存开销,十分必要。其同样可以用于判断也表内内容是否有效。
思考一下tlb_out 汇编函数,结合代码阐述一下跳转到NOFOUND的流程?从MIPS手册中查找tlbp和tlbwi指令,明确其用途,并解释为何第10行处指令后有4条nop指令。
回答见下注释
#include <asm/regdef.h>
#include <asm/cp0regdef.h>
#include <asm/asm.h>
LEAF(tlb_out)
//1: j 1b
nop
//把CP0_ENTRYHI原有值存储到$k1中
mfc0 k1,CP0_ENTRYHI
//把a0中值存放到CP0_ENTRYHI;
//CP0_ENTRYHI存放了虚拟地址空间及其标志位
mtc0 a0,CP0_ENTRYHI
nop
//查询CP0_ENTRYHI中虚拟地址是否存在TLB中:
//如果有则把匹配项的index保存到Index寄存器中;
//没有匹配则置Index的最高位为1.
tlbp
//nop用于等待tlbp执行完毕(流水线暂停)
nop
nop
nop
nop
//读取改写后的CP0_INDEX到$k0
mfc0 k0,CP0_INDEX
//如果$k0中值小于0,即CP0_INDEX最高位置1,即TLB缺失
//则跳转到NOFOUND
bltz k0,NOFOUND
nop
//清空CP0_ENTRYHI和CP0_ENTRYLOW
mtc0 zero,CP0_ENTRYHI
mtc0 zero,CP0_ENTRYLO0
nop
//更新TLB
tlbwi
NOFOUND:
mtc0 k1,CP0_ENTRYHI
j ra
nop
END(tlb_out)
显然,运行后结果与我们预期的不符,va值为0x88888,相应的pa中的值为0。这说明我们的代码中存在问题,请你仔细思考我们的访存模型,指出问题所在。
运用va2pa()只是获得了va对应物理内存中的页的首地址,并未获得实际的va对应的pa地址,即未考虑页内偏移量。
在X86体系结构下的操作系统,有一个特殊的寄存器CR4,在其中有一个PSE位,当该位设为1时将开启4MB大物理页面模式,请查阅相关资料,说明当PSE开启时的页表组织形式与我们当前的页表组织形式的区别。
当开启PSE时,页的划分与当前基本一致,但在一级页表中增加使用了一位用于标识,用于区分从一级页表中寻找得到的地址是二级页表的入口地址还是4MB大小的页面地址。由于一级页表中一项能够映射到的地址本就是4MB,所以整体结构变化不大。
本次实验相比于前几次有了明显的难度提升,花费在其上的时间成倍提升,从周一下午开始几乎一直工作到周三中午。自己对于前半部分实验(2.1-2.4)部分所花费的时间明显多于后部分,一方面在于阅读代码是积累的过程,前面要阅读更多代码,后面则是应用,另一方面是自己对于指针的操作不够熟练。
标签:开启 poi res 删除节点 好处 转换 MIP 不用 形式
原文地址:https://www.cnblogs.com/Suxy-99/p/12716863.html