Closed ckf104 closed 3 years ago
建议给具体代码,更加详细地描述一下,方便项目维护者理解
具体来说,可以删除proc结构体的kpagetable成员。然后这样实现proc_pagetable函数,该函数为进程初始化页表
int
Proc::proc_pagetable(){
pagetable = (pagetable_t)kalloc(); // 申请页表
if(pagetable == 0)
return 0;
kstack = (uint64)kalloc(); // 申请内核栈
if(kstack == 0){
kfree(pagetable);
return 0;
}
memmove(pagetable, kernel_pagetable, PGSIZE); //现在有了映射到内核的页表项
for(uint i=0; i < PX(2, MAXUVA); ++i){
pagetable[i] = 0;
}
trapframe = (Trapframe*)kalloc(); // 申请trapframe页
if(trapframe == 0){
kfree(pagetable);
kfree((void*)kstack);
return 0;
}
return 1;
}
pagetable的前两项用于用户空间的映射,对应地址空间为0x0 -> 0x80000000 限制了地址空间后,省去了为每个用户进程建立trapframe和kstack的页表映射的麻烦。proc->kstack,proc->trapframe分别记录内核栈和trapframe页的物理地址,usertrapret返回时不再使用虚地址TRAMFRAME,而直接使用物理地址p->trapframe。 以后为用户空间建立地址映射时,就不需要分别为pagetable,kpagetable建立映射了,只给pagetable建立地址映射即可。
pagetable的前两项用于用户空间的映射,对应地址空间为0x0 -> 0x80000000 限制了地址空间后,省去了为每个用户进程建立trapframe和kstack的页表映射的麻烦。proc->kstack,proc->trapframe分别记录内核栈和trapframe页的物理地址,usertrapret返回时不再使用虚地址TRAMFRAME,而直接使用物理地址p->trapframe。
我认为使用虚地址去访问trampoline仍然是必要的,总是将trampoline放在某一特定的地址(在xv6-k210 中是虚拟地址的最高处)可以简化代码的编写,而且对于每个用户进程来说使用不同虚拟地址的trampoline似乎 也不是很有必要。
以后为用户空间建立地址映射时,就不需要分别为pagetable,kpagetable建立映射了,只给pagetable建立地址映射即可。
对的,是可以这样处理的。但前提必须是用户程序可信。如果要在用户态与内核态使用同一页表,那么就必须 要考虑如何禁止用户态程序访问内核态的地址空间————显然我们不希望用户态程序能够轻而易举地访问到内核 的地址空间并搞崩内核。RISC-V的分页机制里似乎有一些机制可以限制U态代码对内存空间的访问,但具体的实现 我也不是很清楚。
它这样的做法也是能保证禁止用户访问内核态的地址空间的,U 特权级只能访问有 U 权限的页表
既然proc的kpagetable既有用户地址空间和内核地址空间,这样显得pagetable就多余了,在限制用户地址空间小于0x80000000的前提下,删除pagetable也能正常工作?这样每个进程的pagetable的0,1项对应用户地址空间的映射,后面的项对应内核空间的映射。只保留一个页表的话可以简化vm.c的代码?