Lab3
Page Table
函数 | 作用 |
---|---|
copyin | copy data to user space |
copyout | copy data from user space |
mappages | install PTE for new mappings |
walk | find PA for VA |
XV6 Book
- 从3.5 开始, 都没读懂, 后续补上: <13-04-23, David Chen> -
implement pageing in practice
in main.c
, it calls kvminit
, and kvminit
calls kvmmake
. kvmmake
returns a pointer (kernel_pagetable).
kvmmake first init allocate a PAGE for root pagetable, and then call mappages
to allocate memory for hardware
(At this point, paging is not started, so virtual address is directed mapped to physical address)
kvmmap
calls mappages
, mappages
first align the start address and end address, and start allocate PA for VA at page intervals
mappages
function makes me confusing- what is macro
PAGEROUNDDOWN
means- I guess this macro is used to align the size of a and size.
lab
Speed up system calls
某些现代操作系统通过一个只读区域来在用户与内核之间共享数据,以加速系统调用的执行速度。这样的策略能够减少系统在地址转换上花费的时间。为了帮助你更好的理解如何向 page table
中插入映射,你的第一个任务就是为 getpid
这个系统调用实现这样的优化。
Solution
The life cycle of a xv6 process is as follows.
We can call allocproc
to create a new process. allocproc
first use kalloc
to allocate physical space for p->trapframe
and p->usyscall
.
if((p->usyscall = (struct usyscall *)kalloc()) == 0){
freeproc(p);
release(&p->lock);
return 0;
}
p->usyscall->pid = p->pid;
Then allocproc
call proc_pagetabl
to initialize the pagetable for the process.
proc_pagetable
use uvmmap
to map virtual memory to corresponding physical memory.
// map a page for speed up syscall
if(mappages(pagetable, USYSCALL, PGSIZE,
(uint64)(p->usyscall), PTE_R) < 0){
uvmunmap(pagetable, USYSCALL, 1, 0);
uvmfree(pagetable, 0);
return 0;
}
return pagetable;
}
We can call freeproc
to free an running process. freeproc
first use kfree
to free process memory, Then call proc_freepagetabl
to initialize free pagetable for the process.
if(p->usyscall)
kfree((void*)p->usyscall);
p->usyscall = 0;
proc_pagetable
use uvmummap
to cancel mapping for virtual memory to corresponding physical memory.
And then call uvmfree
to free pagetable.
void
proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmunmap(pagetable, TRAPFRAME, 1, 0);
uvmunmap(pagetable, USYSCALL, 1, 0);
uvmfree(pagetable, sz);
}
Detecting which page have been accessed
and according to the PA, find corresponding VA for kernel. But How to do this. Or we insert a new mapping for this copyin and copyout confused me. I guess they work as follows. copyin use process pagetable to find PA of the argument
实现的时候,只需通过 walkaddr 找到 用户虚拟地址对应的 物理地址,再对物理地址进行操作即可。
How to write content to corresponding addr
- First we need to define
PTE_A
inriscv.h
- add stub for
walk
indef.h
- implement
sys_pgaccess
insysproc.c
- 遍历就好
注意我们不需要手动设置 PTE_A 位,硬件帮我们做好了
int sys_pgaccess()
{
// lab pgtbl: your code here.
uint64 va0;
int num;
uint64 usr_cnt;
// 从 trapframe 获取参数
if(argaddr(0, &va0) > 0) {
return -1;
}
if(argint(1, &num) > 0) {
return -1;
}
if(argaddr(2, &usr_cnt) > 0) {
return -1;
}
uint64 k_cnt = 0;
// 向下取整,保证地址对齐
va0 = PGROUNDDOWN(va0);
struct proc* p = myproc();
// 从 va0 -> va0 + num * pagesize 遍历 页表
// 查看其 PTE_A 是否为 1
// 为 1 的话,置结果第 1 << num 位 为 1,
// 再将 access 位 置 0
for (int i = 0; i < num; i++) {
pte_t* pte = walk(p->pagetable, va0, 0);
if (*pte & PTE_A) {
k_cnt |= (1 << i);
*pte = *pte & (~PTE_A);
}
va0 += PGSIZE;
}
copyout(p->pagetable, usr_cnt, (char* )&k_cnt, sizeof(uint64) / sizeof(char));
return 0;
}
<++>
```json