首页 > 其他分享 >os_lab3

os_lab3

时间:2023-01-20 12:11:06浏览次数:79  
标签:pagetable PTE int os pte lab3 usyscall page

https://pdos.csail.mit.edu/6.828/2021/labs/pgtbl.html

1. 添加一个缓存区

When each process is created, map one read-only page at USYSCALL (a VA defined in memlayout.h). At the start of this page, store a struct usyscall (also defined in memlayout.h), and initialize it to store the PID of the current process. For this lab, ugetpid() has been provided on the userspace side and will automatically use the USYSCALL mapping. You will receive full credit for this part of the lab if the ugetpid test case passes when running pgtbltest.

创建一个USYSCALL的页(虚拟地址),位置就是整个地址空间的顶层第三页(倒数第一第二页分别是TRAMPOLINE,TRAPFRAME:the trampoline page contains the code to transition in and out of the kernel and mapping the trapframe is necessary to save/restore the state of the user process,),并且在其中定义一个usyscall结构体,存储proc的pid。通过访问usyscall这个虚拟地址,可以不用切换到内核态就可以获得pid了。

  1. 在定义整个地址空间的memlayout.h中增加布局
    The file (kernel/memlayout.h) declares the constants for xv6’s kernel memory layout.
#ifdef LAB_PGTBL
#define USYSCALL (TRAPFRAME - PGSIZE)
struct usyscall {
  int pid;
};
#endif

  1. 在proc结构体中增加usyscall的地址
struct proc {
...
struct usyscall *usyscall;
...
}
  1. 在初始化proc时,分配对应的地址空间,并增加对应页的映射
    kernel/proc.c
  2. 分配地址空间
  if((p->usyscall = (struct usyscall *)kalloc()) == 0){
    freeproc(p);
    release(&p->lock);
    return 0;
  }
p->usyscall->pid = p->pid;
  1. 增加映射
  if(mappages(pagetable, USYSCALL, PGSIZE,
              (uint64)p->usyscall, PTE_R | PTE_U) < 0){
    uvmfree(pagetable, 0);
    return 0;
  }
  1. 在free proc时需要free物理空间,并且解除映射
  2. 释放物理空间
  if(p->usyscall)
    kfree((void*)p->usyscall);
  1. 解除映射
  if(mappages(pagetable, USYSCALL, PGSIZE,
              (uint64)p->usyscall, PTE_R | PTE_U) < 0){
    uvmfree(pagetable, 0);
    return 0;
  }

调用

int
ugetpid(void)
{
  struct usyscall *u = (struct usyscall *)USYSCALL;
  return u->pid;
}
// 避免了陷入内核

2. Print a page table

Define a function called vmprint(). It should take a pagetable_t argument, and print that pagetable in the format described below. Insert if(p->pid ==1) vmprint(p->pagetable) in exec.c just before the return argc, to print the first process's page table. You receive full credit for this part of the lab if you pass the pte printout test of make grade.
Now when you start xv6 it should print output like this, describing the page table of the first process at the point when it has just finished exec()ing init:

只需要在初始化exec.c时打印就可以了。
通过提示,知道了vmprint(pagetable)的位置,并且知道了打印的格式,同时kernel/riscv.h定义了PTE2PA其中变换就是和上面一样。通过传入的page directory拿到对应的pte,然后转换为下一级page directory的地址。一直到最后一层。

使用递归来打印地址,注意不同层级的格式有差异,并且最多只能到3级。

void
pgtblprint(pagetable_t pagetable, int level)
{
  // 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) {
      for(int i = 0; i < level; i++) {
        printf(".. ");
      }
    printf("..%d: pte %p pa %p\n", i, pte, PTE2PA(pte));
    printf("pte address: %p\n", pagetable);
    if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0 && level < 3){
      // this PTE points to a lower-level page table.
      uint64 child = PTE2PA(pte);
      pgtblprint((pagetable_t)child, level + 1);
      } 
    }
  }
}

void
vmprint(pagetable_t pagetable) {
  printf("page table %p\n", pagetable);
  pgtblprint(pagetable, 0);
}

3. 统计访问过的页面

Your job is to implement pgaccess(), a system call that reports which pages have been accessed. The system call takes three arguments. First, it takes the starting virtual address of the first user page to check. Second, it takes the number of pages to check. Finally, it takes a user address to a buffer to store the results into a bitmask (a datastructure that uses one bit per page and where the first page corresponds to the least significant bit). You will receive full credit for this part of the lab if the pgaccess test case passes when running pgtbltest.

通过传入参数获得3个值:

  1. 起始页虚拟地址
  2. 需要遍历多少页
  3. disk的user address

通过加上PTE_A来看是否有访问过,记住每次访问完后该位归零,不然之后也会一直算作已经访问过。
关于copyout的解释看os_lab2

int
sys_pgaccess(void)
{
  // lab pgtbl: your code here.
  uint64 first;
  if(argaddr(0, &first) < 0) return -1;
  int number;
  if(argint(1, &number) < 0) return -1;
  uint64 bufaddr;
  if(argaddr(2, &bufaddr) < 0) return -1;
  int ans = 0;
  struct proc *p = myproc();
  if (p == 0) return 1;
  for (int i = 0; i < number; i++) {
    pte_t *pte;
    pte = walk(p->pagetable, first + (uint64)i * PGSIZE, 0);
    if (pte != 0 && ((*pte & PTE_A))) {
      ans |= 1 << i;
      *pte &= ~PTE_A;
    }
  }
  
  return copyout(p->pagetable, bufaddr, (char *)&ans, sizeof(int));
}

标签:pagetable,PTE,int,os,pte,lab3,usyscall,page
From: https://www.cnblogs.com/yych0745/p/17062643.html

相关文章