OS-xv6-lab3:页表

lab3 页表

加速getpid

核心就是为每一个进程的单独内存空间添加一个USYSCALL页,这样用户程序可无需陷入内核中,而直接从这个页面获取数据(在本实验中为pid),进而省去系统开销,加速系统调用。

根据实验文档,USYSCALL相关的定义在memlayout.h文件中:

// User memory layout.
// Address zero first:
//   text
//   original data and bss
//   fixed-size stack
//   expandable heap
//   ...
//   USYSCALL (shared with kernel)
//   TRAPFRAME (p->trapframe, used by the trampoline)
//   TRAMPOLINE (the same page as in the kernel)
#define TRAPFRAME (TRAMPOLINE - PGSIZE)
#ifdef LAB_PGTBL
#define USYSCALL (TRAPFRAME - PGSIZE)

struct usyscall {
  int pid;  // Process ID
};
#endif

在这里插入图片描述

memlayout.h文件中主要是用户空间内存布局的定义,上图为xv6手册中给出的进程的用户地址空间,可以看到与代码的注释是对应的,虚拟地址空间从0到MAXVA,依次是

​ text:程序代码段

​ data(bss):程序的数据

​ guard page:检测用户栈是否溢出了分配的栈内存

​ stack:固定大小的用户栈

​ heap:可拓展的堆区

​ trapframe:陷入内核时保存用户上下文的区域

​ trampoline:用户态跳转到内核态的特殊“跳板”页,与内核共享,用于进入内核。

USYSCALL定义应该是位于trapframe和heap之间,单独开辟一个新页来存储数据。首先要在proc.h的proc结构体中添加usyscall变量,然后修改proc.c文件中关于进程和映射的函数。在allocproc分配物理页时添加分配usyscall空间的代码,并将pid对应存储;在proc_pagetable中建立虚拟地址到物理地址的映射,设置权限用户可读;在freeproc中释放进程资源时释放掉新加的usyscall页的空间,并且由于在释放时调用了proc_freepagetable释放页表中对应的页表项,还需要在这个函数中增加解除usyscall映射的代码。

PTE标志位
  • PTE_P:PTE是否陈列在页表中
  • PTE_W:能否对页执行写操作
  • PTE_U:控制用户程序能否使用该页
  • PTE_R:用户能否读取
  • PTE_V:PTE是否存在或有效,若不存在,则尝试引用时会报缺页错误。
函数解释
  • mappages

    在页表中建立虚拟地址到物理地址的映射,并设置相应的访问权限。

  • uvmfree

    释放一个进程所使用的用户空间内存,并销毁与之相关的页表(包括页目录和页表本身使用的物理内存)。

  • kfree

    当某个物理页不再被使用时,释放这个物理页,并将其返回给内核的空闲页管理系统。

  • uvmunmap

    取消一段虚拟地址范围内的页表映射,即把虚拟地址和物理地址的绑定关系解除

  • freewalk

    递归释放页表结构所有的中间页。利用递归的思想,递归遍历页表项,取出每个页表项,判断它是否有效、是否是中间页表(是指向下一级页表而非指向物理页表的),利用PTE2PA宏从PTE中提取物理地址,然后将这个子页表递归地传递给freewalk释放,把当前页表项清零,表示它不再有效。若不是中间页而是叶子页表,则不应该释放,打印报错的信息。最后递归地处理完所有的子页表后,释放当前这个页表本身所占的物理页。

    编写vmprint函数

    首先查看利用递归来释放页表结构所有的中间页。首先遍历页表项,取出每个页表项,判断它是否有效、是否是中间页表(即是指向下一级页表而非指向物理内存的),是的话,利用PTE2PA宏从PTE中提取物理地址,然后将这个子页表递归地传给freewalk释放,把当前页表项清零,表示它不再有效。若不是中间页表,而是叶子页表,则不应该释放,打印报错信息。最后递归地处理完所有的子页表后,释放当前这个页表本身所占的物理页。

    // Recursively free page-table pages.
    // All leaf mappings must already have been removed.
    void
    freewalk(pagetable_t pagetable)
    {
      // there are 2^9 = 512 PTEs in a page table.
      for(int i = 0; i < 512; i++){
        pte_t pte = pagetable[i];
        if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
          // this PTE points to a lower-level page table.
          uint64 child = PTE2PA(pte);
          freewalk((pagetable_t)child);
          pagetable[i] = 0;
        } else if(pte & PTE_V){
          panic("freewalk: leaf");
        }
      }
      kfree((void*)pagetable);
    }
    

    仿照freewalk的递归思路,另外设置一个printdeep的变量来指示打印当前页的深度。初始深度为0打印当前页表,然后遍历当前页表的所有页表项,如果是有效的叶子页表则打印出当前的索引、页表项的值和物理地址,并根据深度打印缩放,如果是中间页表,则增加深度,调用vmprint递归打印子页表,回溯完成后再将深度减一。

static int printdeep = 0;
void
vmprint(pagetable_t pagetable)
{
  if (printdeep == 0)
    printf("page table %p\n", (uint64)pagetable);
  for (int i = 0; i < 512; i++) {
    pte_t pte = pagetable[i];
    if (pte & PTE_V) {
      for (int j = 0; j <= printdeep; j++) {
        printf("..");
      }
      printf("%d: pte %p pa %p\n", i, (uint64)pte, (uint64)PTE2PA(pte));
    }
    // pintes to lower-level page table
    if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){
      printdeep++;
      uint64 child_pa = PTE2PA(pte);
      vmprint((pagetable_t)child_pa);
      printdeep--;
    }
  }
}

最后在defs.h中添加定义:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值