【MIT 6.S081】Lab3: page tables

本文介绍了如何优化操作系统页表功能,包括添加打印页表的函数vmprint,每个进程拥有独立的内核页表副本,以及简化copyin/copyinstr操作。通过proc_kvminit初始化进程内核页表,并在scheduler中切换页表,实现进程间内核页表的独立。同时,实现了uvm2ukvm函数,将用户空间映射复制到内核页表,方便内核直接访问用户空间数据。


本Lab简单优化了系统的页表功能,使得程序在内核态时可以直接解析用户态的指针。
笔者用时约8h

Print a page table

第一部分是为系统添加一个打印给定页表的函数vmprint,该函数接收一个参数pagetable(根页表的物理地址),递归遍历整张页表,打印有效的表项。
参考freewalk函数(定义在kernel/vm.c:331),每次遍历512个表项,若表项有效,则打印相关信息(第几级、第几项、pte内容和pte内容对应的物理地址),且若为一二级页表则继续递归,直到第三级页表返回。参考代码如下:

void 
vmprint_helper(pagetable_t pgtbl, int level) 
{
   
   
  // there are 2^9 = 512 PTEs in a page table.
  for(int i = 0; i < 512; i++){
   
   
    pte_t pte = pgtbl[i];
    if(pte & PTE_V){
   
   
      for (int j = 0; j < level; j ++ ) {
   
   
        if (j) printf(" ");
        printf("..");
      }
      printf("%d: pte %p pa %p\n", i, pte, PTE2PA(pte));
      if ((pte & (PTE_R|PTE_W|PTE_X)) == 0) {
   
   
        // this PTE points to a lower-level page table.
        uint64 child = PTE2PA(pte);
        vmprint_helper((pagetable_t)child, level + 1);
      }
    }
  }
}

void
vmprint(pagetable_t pgtbl) 
{
   
   
  printf("page table %p\n", pgtbl);
  vmprint_helper(pgtbl, 1);
}

A kernel page table per process

如标题,第二部分的内容是为每一个进程添加一个单独的内核页表副本,为下一节直接解引用用户态指针做铺垫。

首先需要在进程的结构体(定义在kernel/proc.h中)struct proc中添加一个字段维护内核页表副本,如下图所示
在这里插入图片描述

然后,由于我们需要在分配进程时需要为每一个进程初始化一个内核页表的副本,于是需要参考kvminit函数(定义在kernel/vm.c:66),编写一个初始化进程中内核页表副本的函数proc_kvminit,代码如下所示。该函数内容与kvminit函数基本一致。其中的uvmmapkvmmap函数(定义在kernel/vm.c:171)类似,映射给定的虚拟地址和物理地址范围,唯一不同点是前者修改的是传入的指定页表而不仅仅是全局的内核页表。

void 
uvmmap(pagetable_t pagetable, uint64 va, uint64 pa, uint64 sz, int perm) 
{
   
   
  if(mappages(pagetable, va, sz, pa, perm) != 0)
    panic("uvmmap");
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值