--------24.6.13------------
目前,我通过了 MIT6.S081
Lab3
的实验,通过各种办法,阅读 xv6
的中文译本,参考别人的思路、代码等等,不完全是自己的思路,但也总算是将该实验完成了。
所以就有了一些想法,想要通过博客的方式记录自己做 lab3
的过程,以及对操作系统的相关收获,预计会写几篇博客来叙述,目前还没有怎么构思好,因为在这个lab着实花费了不少时间,踩了不少坑,想要更完整地记录学习的过程。
虚拟内存地址和物理地址转换
如图1所示
- 虚拟地址使用了低39位,其中高27位作为页表的索引,低12位作为物理地址的偏移量
- 页表索引具体又分为三级页表,每级页表包含512条PTE,每条PTE大小为8个字节,所以每级页表大小占4KB
代码解读
walk
函数
// Return the address of the PTE in page table pagetable
// that corresponds to virtual address va. If alloc!=0,
// create any required page-table pages.
//
// The risc-v Sv39 scheme has three levels of page-table
// pages. A page-table page contains 512 64-bit PTEs.
// A 64-bit virtual address is split into five fields:
// 39..63 -- must be zero.
// 30..38 -- 9 bits of level-2 index.
// 21..29 -- 9 bits of level-1 index.
// 12..20 -- 9 bits of level-0 index.
// 0..11 -- 12 bits of byte offset within the page.
pte_t* walk(pagetable_t pagetable, uint64 va, int alloc) {
// 如果当前虚拟地址超过了定义的虚拟地址最大值MAXVA,返回错误
if(va >= MAXVA)
panic("walk");
// 三级页表的遍历
for(int level = 2; level > 0; level--) {
// PX() 可以获得va的第level级页表的索引位置,范围为 0-511,取出对应的PTE
pte_t *pte = &pagetable[PX(level, va)];
if(*pte & PTE_V) { // PTE存在,切换页表页到下一级的页表页
// PTE2PA是将页表条目右移10位再左移12位,可以获得下一个页表的PPN
pagetable = (pagetable_t)PTE2PA(*pte);
} else { // 处理PTE不存在,alloc为1,分配一个新的页表页,alloc为0,直接返回0,不进行页表分配
if(!alloc || (pagetable = (pde_t*)kalloc()) == 0)
return 0;
memset(pagetable, 0, PGSIZE); // 初始化新页表
// 新页表的物理地址转换为PTE,右移12位,再左移10位,同时PTE_V置1,放入到当前页表条目中
*pte = PA2PTE(pagetable) | PTE_V;
}
}
// 返回最后一级页表记录的PTE
return &pagetable[PX(0, va)];
}
mappages
函数
// Create PTEs for virtual addresses starting at va that refer to
// physical addresses starting at pa. va and size might not
// be page-aligned. Returns 0 on success, -1 if walk() couldn't
// allocate a needed page-table page.
int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm) {
uint64 a, last;
pte_t *pte;
// a = 虚拟地址 va 低12位置 0
a = PGROUNDDOWN(va);
// last是要分配的结束地址
last = PGROUNDDOWN(va + size - 1);
for(;;){
// 判断walk函数的结果
if((pte = walk(pagetable, a, 1)) == 0)
return -1;
// 判断PTE是否存在,存在则重新分配,因为目的是要将va映射到pa,取到页表条目应该不存在,这时候为他分配
if(*pte & PTE_V)
panic("remap");
// 转换物理地址为PTE,存入到当前的页表条目中
*pte = PA2PTE(pa) | perm | PTE_V;
// 如果到达分配结束地址,停止循环
if(a == last)
break;
a += PGSIZE;
pa += PGSIZE;
}
return 0;
}
参考
- 图1参考自MIT book-riscv-rev1