【MTI 6.S081 Lab】Page tables

news2024/9/24 15:28:02

【MTI 6.S081 Lab】Page tables

  • Speed up system calls (easy)
    • 实验任务
    • Hints
    • 哪些其它的系统调用能通过这个共享页面变得更快,请解释。
    • 解决方案
      • 分配和释放页面
      • 初始化结构
    • 实验心得
  • Print a page table (easy)
    • 实验任务
    • Hints
    • 根据图3-4从文本中解释vmprint的输出。第0页包含什么?第2页是什么?在用户模式下运行时,进程是否可以读取/写入第1页映射的内存?倒数第三页包含什么?
    • 解决方案
  • Detect which pages have been accessed (hard)
    • 实验任务
    • Hint
    • 解决方案
      • 访问位
      • sys_pgaccess()

Speed up system calls (easy)

一些操作系统(如Linux)通过在用户空间和内核之间共享只读区域来加速某些系统调用。这就消除了在执行这些系统调用时对内核交叉的需要。为了帮助您了解如何将映射插入到页面表中,您的第一个任务是为xv6中的getpid()系统调用实现此优化。

实验任务

当一个进程被创建,映射一个只读页在USYSCALL(在memlayout.h中定义的一个虚拟地址)。在这个页的开始位置,存储一个结构struct usyscall(也被定义在memlayout.h中),初始化它并且存储当前进程的PID。对于这个lab,ugetpid()已经在用户空间端提供,并且将自动使用USYSCALL的映射。当你运行pgtbltest,如果ugetpid测试例子全部通过,你将得到这个部分的全部的分数。

Hints

  • 你将在kernel/proc.c执行映射proc_pagetable()
  • 确定权限位,使得用户空间对这个页面只读
  • mappages是一个有用的工具
  • 不要忘记在allocproc()分配和初始化这个页面
  • 确保在freeproc()释放这个页面

哪些其它的系统调用能通过这个共享页面变得更快,请解释。

:不需要修改内核维护的信息的那些系统调用都可以通过这个共享页面变得更快。

解决方案

分配和释放页面

// Create a user page table for a given process, with no user memory,
// but with trampoline and trapframe pages.
pagetable_t
proc_pagetable(struct proc *p)
{
  pagetable_t pagetable;

  // An empty page table.
  pagetable = uvmcreate();
  if(pagetable == 0)
    return 0;

  // map the trampoline code (for system call return)
  // at the highest user virtual address.
  // only the supervisor uses it, on the way
  // to/from user space, so not PTE_U.
  if(mappages(pagetable, TRAMPOLINE, PGSIZE,
              (uint64)trampoline, PTE_R | PTE_X) < 0){
    uvmfree(pagetable, 0);
    return 0;
  }

  // map the trapframe page just below the trampoline page, for
  // trampoline.S.
  if(mappages(pagetable, TRAPFRAME, PGSIZE,
              (uint64)(p->trapframe), PTE_R | PTE_W) < 0){
    uvmunmap(pagetable, TRAMPOLINE, 1, 0);
    uvmfree(pagetable, 0);
    return 0;
  }

  // 映射一个页面,确定许可位, 这个页面用户只要可读即可
  if (mappages(pagetable, USYSCALL, PGSIZE, (uint64)(p->usyscall), PTE_U | PTE_R) < 0) {	// 这里分配不成功,那么要把前两个分配成功的给取消映射,避免内存泄漏
    uvmunmap(pagetable, TRAMPOLINE, 1, 0);
    uvmunmap(pagetable, TRAPFRAME, 1, 0);
    uvmfree(pagetable, 0);
    return 0;
  }

  return pagetable;
}

// Free a process's page table, and free the
// physical memory it refers to.
void
proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
  uvmunmap(pagetable, TRAMPOLINE, 1, 0);
  uvmunmap(pagetable, TRAPFRAME, 1, 0);
  uvmunmap(pagetable, USYSCALL, 1, 0);
  uvmfree(pagetable, sz);
}

初始化结构

static struct proc*
allocproc(void)
{
  ...
  // 注意,要先在这里分配一个物理页面,才能把这个物理页面映射到虚拟地址上,再往页表添加条目PTE
  // 在此处将系统调用优化映射的页面初始化
  if((p->usyscall = (uint64)kalloc()) == 0) {
    freeproc(p);
    release(&p->lock);
    return 0;
  }
  (*(struct usyscall *)p->usyscall).pid = p->pid;

  // An empty user page table.
  ...
  return p;
}

实验心得

  • 先要分配物理页面,然后再将这个物理页面映射到进程虚拟地址的USYSCALL位置
  • 在进程释放页表时,要先取消这个映射。

Print a page table (easy)

为了帮助你可视化RISC-V的页表,也或许可以辅助之后的debug,你的第二个任务是写一个函数用于打印页表的内容。

实验任务

定义一个函数名为vmprint()。他以pagetable_t为参数,按照下面的格式打印这个页表。在exec.c中的返回argc之前插入if(p->pid==1)vmprint(p->pagetable),以打印第一个进程的页表。如果你通过了合格等级的pte printout 测试,你将获得lab这一部分的全部分数。

完成后,当你启动xv6,它应该输出如下内容,描述第一个进程刚刚完成exec()初始化时的页表:

在这里插入图片描述

第一行显示vmprint的参数。之后,每个PTE都有一行,包括引用树中更深层次的页面表页面的PTE。" …"代表PTE在树中的深度。每个PTE行在其页面表页面中显示PTE索引、PTE位和从PTE中提取的物理地址。不要打印无效的PTE。在上面的示例中,顶级页面表页面具有条目0和255的映射。条目0的下一级仅映射了索引0,该索引0的底层映射了条目0、1和2。

你的代码可能会发出与上面显示的物理地址不同的物理地址。条目数和虚拟地址应相同。

Hints

  • kernel/vm.c中添加vmprint()
  • 使用在kernel/riscv.h文件中最后定义的那些宏定义
  • freewalk能给你灵感
  • kernel/defs.h中定义vmprint的原型,以便于你能从exec.c中调用它
  • 在printf调用中使用%p可以打印出完整的64位十六进制PTE和地址,如示例所示。

根据图3-4从文本中解释vmprint的输出。第0页包含什么?第2页是什么?在用户模式下运行时,进程是否可以读取/写入第1页映射的内存?倒数第三页包含什么?

:xv6为39为虚拟地址,高27位用于通过页表查找物理页,每级页表分配9位。最低级的页表查询的结果即为虚拟地址空间中某地址对应物理内存中那一页所在的位置,然后和虚拟地址的第12位组成实际的物理地址,即为进程所需要的数据。vmprint中,

  • 第0页的高27为均为0,所以此处存放的是程序指令。
  • 后面接着放程序数据,包括初始化全局和静态变量和未初始化全局和静态变量。
  • 保护页面,避免栈溢出.。如果用户栈溢出并且进程试图使用栈下方的地址,那么由于映射无效(PTE_V为0)硬件将生成一个页面故障异常。当用户栈溢出时,实际的操作系统可能会自动为其分配更多内存。
  • 用户栈
  • 蹦床页面

在这里插入图片描述

NOTE可以看到xv6的进程虚拟地址空间的布局和x86不一样,它的栈紧接着程序数据,然后高地址才是堆。

解决方案

static void
vmprintwalk(pagetable_t pagetable, int level) {
  char prefix[10] = " .. .. ..";
  prefix[level * 3] = '\0';
  for (int i = 0; i < 512; ++i) {
    pte_t pte = pagetable[i];
    if ((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0) {
      uint64 child = PTE2PA(pte);
      printf("%s%d: pte %p pa %p\n", prefix, i, pte, child);
      vmprintwalk((pagetable_t)child, level+1);
    } else if (pte & PTE_V) {
      // pte指向的页面 可读 或 可写 或 可执行,说明已经指向了进程自己的虚拟地址了,此时应该会是第三级页表了
      printf("%s%d: pte %p pa %p\n", prefix, i, pte, PTE2PA(pte));
    }
  }
}

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

Detect which pages have been accessed (hard)

一些垃圾收集器(自动内存管理的一种形式)可以从有关哪些页面已被访问(读取或写入)的信息中受益。在Lab的这一部分中,您将向xv6添加一个新功能,该功能通过检查RISC-V页面表中的访问位来检测并向用户空间报告这些信息。RISC-V硬件页面walker在PTE中标记这些位,每当它解决TLB未命中时。

实验任务

您的工作是实现pgaccess(),这是一个报告哪些页面已被访问的系统调用。系统调用需要三个参数。第一个的参数为第一个用户页面的起始虚拟地址。第二个参数为需要检查的页数。第三个参数,它将用户地址带到缓冲区,将结果存储到位掩码(一种每页使用一位的数据结构,其中第一页对应于最低有效位)。如果在运行pgtbltest时pgaccess测试用例通过,您将获得实验室这一部分的全部学分。

Hint

  • 阅读user/pgtlbtest.c中的函数pgaccess_test()去了解pgaccess是如何被使用的
  • kernel/sysproc.c中开始执行sys_pgaccess()
  • 你需要使用argaddr()argint()解析参数
  • 对于输出位掩码,可以更容易地在内核中存储一个临时缓冲区,并在填充正确的位后将其复制到用户(通过copiout())。
  • 可以对可以扫描的页数设置上限。
  • kernel/vm.c中的walk()对于找到正确的PTEs是非常有用的
  • 你需要在kernel/riscv.h中定义访问位PEE_A。
  • 确保在检查PTE_A后清除它。否则,确定一个页面在上一次pgaccess()后是否被访问是不可能的,因为它一直被置位了。
  • vmprint()在调试页面表时可能会派上用场。

解决方案

访问位

#define PTE_A (1L << 6)   // access bit, 访问位

sys_pgaccess()

int
sys_pgaccess(void)
{
  // lab pgtbl: your code here.
  uint64 base;
  int len;
  uint64 mask = 0;
  uint64 mask_addr;
  argaddr(0, &base);
  if(base == 0) {
    return -1;      // 解析参数失败
  }
  // base可能不是PGSIZE的整数倍,因为用户malloc时只需要8或者16字节对齐即可
  base = PGROUNDDOWN(base);   // 向下舍入,得到buf中第一个字节所在的页面
  argint(1, &len);
  if (len < 0 || len > 64) {    // 暂时只能处理64个页面的检测
    return -1;
  }
  argaddr(2, &mask_addr);
  struct proc *p = myproc();
  for (int i = 0; i < len; ++i) {
    pte_t *pte = walk(p->pagetable, base + i * PGSIZE, 0);    // alloc为0说明不要为页表分配,其实如果此时要分配,实际上就没有访问过
    if (pte == 0 || (*pte & PTE_A) == 0) {
      // 没有访问过
      continue;
    } else {
      mask |= (1L << i);    // 第i个页面访问过
      *pte = (*pte & ~PTE_A);     // 清除PTE_A位
    }
  }
  // 将mask写入传入的地址中
  copyout(p->pagetable, mask_addr, (char *)&mask, sizeof(mask));
  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/810570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习:自动编码器Auto-encoder

Self-supervised Learning Framework 不用标注数据就能学习的任务&#xff0c;比如Bert之类的。但最早的方法是Auto-encoder。 Outline Auto-encoder encoder输出的向量&#xff0c;被decoder还原的图片&#xff0c;让输出的图片与输入的图片越接近越好。 将原始的高维向量变…

红黑树解密:为什么根节点必须是黑色,两个红色节点不能挨着?

红黑树解密&#xff1a;为什么根节点必须是黑色&#xff0c;两个红色节点不能挨着&#xff1f; 博主简介一、引言1.1、红黑树是什么及其特点1.2、根节点为黑色和红色节点不连续的性质介绍 二、为何根节点必须是黑色&#xff1f;三、为何两个红色节点不能挨着&#xff1f;总结 博…

PCB绘制时踩的坑 - SOT-223封装

SOT-223封装并不是同一的&#xff0c;细分的话可以分为两种常用的封装。尤其是tab脚的属性很容易搞错。如果你想着用tab脚连接有属性的铺铜&#xff0c;来提高散热效率&#xff0c;那么你一定要注意你购买的器件tab脚的属性。 第一种如下图&#xff0c;第1脚为GND&#xff0c;第…

Packet Tracer - 备份配置文件

Packet Tracer - 备份配置文件 目标 第 1 部分&#xff1a;与 TFTP 服务器建立连接 第 2 部分&#xff1a;从 TFTP 服务器传输配置 第 3 部分&#xff1a;将配置和 IOS 备份到 TFTP 服务器上 拓扑图 背景/场景 本练习旨在展示如何从备份恢复配置&#xff0c;然后执行新的…

Stephen Wolfram:神经网络

Neural Nets 神经网络 OK, so how do our typical models for tasks like image recognition actually work? The most popular—and successful—current approach uses neural nets. Invented—in a form remarkably close to their use today—in the 1940s, neural nets …

如何查找网页的cookie【以两步路平台】

登录/注册账号【重要】 进入开发人员工具 刷新页面&#xff0c;发现“全部”对应的列表发生改变 找到列表首页的文本后缀.htm的信息&#xff0c;点开后查找网站的Cookie。 注意&#xff1a;Cookie必须在登陆后的才有效&#xff0c;并且每次爬取都需要重新查找更新Cookie&…

六、初始化和清理(1)

本章概要 利用构造器保证初始化方法重载 区分重载方法重载与基本类型返回值的重载无参构造器 this 关键字在构造器中调用构造器static 的含义 利用构造器保证初始化 "不安全"的编程是造成编程代价昂贵的罪魁祸首之一。有两个安全性问题&#xff1a;初始化和清理。…

redis和数据库双写不一致一般如何解决-面试

先介绍一下常规的几种做法 1、先删缓存&#xff0c;在改数据库 2、先改数据库&#xff0c;在删缓存 3、先改数据库&#xff0c;在改缓存 4、延迟双删&#xff08;先删缓存&#xff0c;再改数据库&#xff0c;延迟几百毫秒&#xff0c;再删缓存&#xff09;&#xff0c;此方…

通过gre隧道建立私有专用网络

Internet 配置 vlan 128 vlan 202 router1&#xff1a; router2&#xff1a; router1 ping router 2

一起学SF框架系列5.11-spring-beans-数据校验validation

在日常的项目开发中&#xff0c;应用在执行业务逻辑之前&#xff0c;为了防止非法参数对业务造成的影响&#xff0c;必须通过校验保证传入数据是合法正确的&#xff0c;但很多时候同样的校验出现了多次&#xff0c;在不同的层&#xff0c;不同的方法上&#xff0c;导致代码冗余…

map求和accumulate、参数互换

运行代码&#xff1a; //map求和accumulate、参数互换 #include"std_lib_facilities.h"istream& operator>>(istream& is, map<string, int>&mm) {string ss"";int ii0;is >> ss;if(is>>ii)mm[ss] ii;return is; }t…

VSCode中python代码输出中文乱码解决

前言 最近在vs code里面执行python脚本时&#xff0c;只有打印中文&#xff0c;就会乱码。 内容 先检查右下角编码集设置是否正确 检查右下角编码集设置是否正确 &#xff1a; 如果不是utf-8点击修改。 如果还是不行&#xff0c;就进行下面的操作 修改用户设置 路径&a…

【算法基础:动态规划】5.1 背包问题

文章目录 01背包例题&#xff1a;2. 01背包问题 完全背包例题&#xff1a;3. 完全背包问题 多重背包例题&#xff1a;4. 多重背包问题 I例题&#xff1a;5. 多重背包问题 II&#xff08;数据范围较大&#xff1a;二进制优化&#xff09; 分组背包例题&#xff1a;9. 分组背包问…

2023/7/29总结

项目&#xff1a; 这几天主要实现了评论的功能点: 还是有点小bug&#xff0c;还在更改中…… 修改个人中心的界面 接下来是把收藏完善&#xff0c;因为收藏需要用户自己创建一个新的收藏夹

iOS开发-转场动画切换界面(类似系统动画)

iOS开发-转场动画切换界面&#xff08;类似系统动画&#xff09; 在开发中&#xff0c;无论我们使用 push 还是 present 推出新的 viewcontroller 时&#xff0c;系统为了提高用户体验都会为我们默认加上一些过渡动画。但是开发中需要自定义过度动画效果。这里就需要用到了转场…

二十五章:用于弱监督语义分割的激活调节和重新校准方案

0.摘要 图像级弱监督语义分割&#xff08;WSSS&#xff09;是一项基础而具有挑战性的计算机视觉任务&#xff0c;有助于场景理解和自动驾驶。大多数现有方法利用基于分类的类激活图&#xff08;CAMs&#xff09;作为初始伪标签&#xff0c;但这些方法往往关注区分性的图像区域&…

Leetcode刷题---C语言实现初阶数据结构---单链表

1 删除链表中等于给定值 val 的所有节点 删除链表中等于给定值 val 的所有节点 给你一个链表的头节点head和一个整数val&#xff0c;请你删除链表中所有满足Node.valval的节点&#xff0c;并返回新的头节点 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[…

Tomcat 的使用(图文教学)

Tomcat 的使用&#xff08;图文教学&#xff09; 前言一、什么是Tomcat&#xff1f;二、Tomcat 服务器和 Servlet 版本的对应关系三、Tomcat 的使用1、安装2、目录介绍3、如何启动4、Tomcat 的停止5、如何修改 Tomcat 的端口号6、如何部暑 web 工程到 Tomcat 中6.1 方式一6.2 …

建设银行秋招指南,备考技巧和考试内容详解

建设银行秋招简介 银行作为非常吃香的岗位&#xff0c;每年都有不少同学通过投递简历&#xff0c;进入笔试&#xff0c;再到面试成功&#xff0c;成功到银行就职&#xff0c;也有相当一部分同学因为信息差&#xff0c;符合条件却没有报名。无法进入银行工作。 建设银行的秋招…

从保存受限的手机APP中提取文件(读取Android系统中的新增缓存文件)

这个手机APP的权限可能设置了无法在应用内保存文件&#xff0c;但是这个文件实际上一定存在于本地的某个地方&#xff0c;本文的方法通过遍历最后修改日期在今天的文件&#xff0c;很容易就可以找到它。 首先安装一个QPython&#xff0c;这个软件可以允许你在安卓手机上运行Py…