先搞清两种页表:
页表是虚拟地址实现的基础
1.内核页表:
- 操作系统映射完之后,由芯片查表,所以我们看不到查内核页表的代码,只有建立内核页表的代码。
- 内核页表不是从0开始,而是在某些特定地址上有特定的映射,貌似和设计者有关系。(像xv6这种直接映射页表,也就是内核页表的虚拟地址和物理地址一样的,就和芯片硬件有关)图的左侧是内核页表
2.用户页表:
- 操作系统建表并且查表。
- 从虚拟地址0开始,用多少就建多少,这也是为什么实验第三问有PLIC限制条件的原因,因为虚拟地址从0开始往上加,控制最高的地址就好。
问:题目中要我们写的进程内核页表,是属于内核页表,还是用户页表?
答:应该是内核页表,因为它的建立由程序完成,查表由芯片完成。
查表由芯片完成——这句话的意思。我是这么认为的:在第三问的copyin_new()里边有:
memmove((void *) dst, (void *)srcva, len);
意思就是直接把虚拟地址srcva的内容复制到虚拟地址dst。中间的把虚拟地址映射成物理地址的代码没有写。这不是交给芯片完成了吗?
难点
- 理解问题啥意思有点难,第二问的意思是:为每个进程加一个内核页表。(这里比较难以捉摸,因为usertests本来就可以运行,然后题目要求加完内核页表之后,也要能运行usertests。)
- 为啥作业要这么折腾,本来可以跑的代码,还要加个内核页表,这不多此一举?可能是内核页表是由芯片进行查表,而用户页表由操作系统进行查表。老师的目的是要我们区分这两点。
- 说说我遇到的代码上的问题,针对第三问(复制用户页表到内核页表):
1.在freeproc里边释放内核页表的时候,sz一定要向上取整PGROUNDUP(sz):
查看图片
2.在sys_sbrk里边增加内核页表的时候,如果参考的是文章开头给出的简洁版答案:uvm2k(p->pagetable, p->kpagetable, sz-n, sz),请一定注意这里的sz,sz经前面的sz = uvmalloc(p->pagetable, sz, sz + n),已经是增加之后的大小,所以一定的要减去n。
3.参考的两篇博客都没有提到过。这个在实验的提示里边有:在userinit函数添加复制用户页表到内核页表的代码。
4.复制内核的内核页到进程的内核页时。注意不要把CLINT复制过去,以及在freeproc里面不要释放CLINT。(原因是题目提示说,从进程的进程页表复制到进程的内核页表,最多不超过PLIC,然后可以看到在PLIC下面只有CLINT,也就是说这里可以给进程随便用,别分配给CLINT了)
具体的可以看地址图,图的左边有PLIC和CLINT的位置关系。
最后:
只需要细心点,这个原理前面大佬的答案都有说到。就是复制已有的用户页表到内核页表。受限于水平,这次实验得分只有30/66:
== Test pte printout ==
$ make qemu-gdb
pte printout: FAIL (9.8s)
...
.. .. ..511: pte 0x0000000020001c0b pa 0x0000000080007000
init: starting sh
$ echo hi
hi
$ qemu-system-riscv64: terminating on signal 15 from pid 2732 (make)
MISSING '^page table (0x00000000[0-9a-f]+)$'
QEMU output saved to xv6.out.pteprint
== Test answers-pgtbl.txt == answers-pgtbl.txt: FAIL
Cannot read answers-pgtbl.txt
== Test count copyin ==
$ make qemu-gdb
count copyin: OK (2.0s)
== Test usertests ==
$ make qemu-gdb
Timeout! (300.1s)
== Test usertests: copyin ==
usertests: copyin: OK
== Test usertests: copyinstr1 ==
usertests: copyinstr1: OK
== Test usertests: copyinstr2 ==
usertests: copyinstr2: OK
== Test usertests: copyinstr3 ==
usertests: copyinstr3: OK
== Test usertests: sbrkmuch ==
usertests: sbrkmuch: OK
== Test usertests: all tests ==
usertests: all tests: FAIL
...
sepc=0x0000000000002188 stval=0x000000000000fbc0
OK
test opentest: OK
test writetest: OK
test writebig: qemu-system-riscv64: terminating on signal 15 from pid 3178 (make)
MISSING '^ALL TESTS PASSED$'
== Test time ==
time: FAIL
Cannot read time.txt
Score: 30/66
Makefile:314: recipe for target 'grade' failed
make: *** [grade] Error 1