MIT6.s081-2020 Lab3 Page Tables

MIT6.s081-2020 Lab3 Page Tables

lab 3 文档

在本实验中,您将探索页表并修改它们以简化将数据从用户空间复制到内核空间的函数。

准备

git fetch
git checkout pgtbl
make clean

Print a page table

引言

为了帮助您了解 RISC-V 页表,并且可能有助于将来的调试,首要任务是编写一个打印页表内容的函数。

定义一个名为vmprint(). 它应该需要一个pagetable_t参数,并以下面描述的格式打印该页表。插入if(p->pid==1) vmprint(p->pagetable)exec.c 之前return argc, 打印第一个进程的页表。

实现

vmprint函数添加到kernel/vm.c文件中并在kernel/defs.h文件中添加该函数的声明。

//vm.c
//...
int             copyinstr(pagetable_t, char *, uint64, uint64);
void            vmprint(pagetable_t);

使用格式符%p打印16进制数,使用kernel/riscv.h文件中定义的宏, 参考freewalk函数以递归的形式完成。

//kernel/riscv.h
#define PGROUNDUP(sz)  (((sz)+PGSIZE-1) & ~(PGSIZE-1))
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE-1))

#define PTE_V (1L << 0) // valid
#define PTE_R (1L << 1)
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // 1 -> user can access

#define PTE2PA(pte) (((pte) >> 10) << 12)

//...
typedef uint64 pte_t;
typedef uint64 *pagetable_t; // 512 PTEs

//kernel/vm.c
// 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);
}

需要注意的说遍历到最后一层页表就停止,最后一层页表中页表项中W位,R位,X位起码有一位会被设置为1。

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

//Print a page table
void vmprint(pagetable_t pagetable){
   
  // there are 2^9 = 512 PTEs in a page table.
  printf("page table %p\n",pagetable);
  vmprint_helper(pagetable,1);
}

结果

实验测试结果:

在这里插入图片描述

A kernel page table per process

引言

Xv6 有一个内核页表,每当它在内核中执行时都会使用它。内核页表直接映射到物理地址,因此内核虚拟地址x映射到物理地址x。Xv6 还为每个进程的用户地址空间提供了一个单独的页表,仅包含该进程的用户内存的映射,从虚拟地址零开始。因为内核页表不包含这些映射,所以用户地址在内核中是无效的。因此,当内核需要使用在系统调用中传递的用户指针(例如,传递给write()),内核必须首先将指针转换为物理地址。本节和下一节的目标是允许内核直接取消引用用户指针.

实现

这一部分是要求我们给每个进程维护一个各自不同的内核页表,当陷入内核时,切换到这个特有内核页表,内核就直接可以使用虚拟地址来访问系统调用参数了。按照HINT一步步做下去即可。

HINT1

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值