惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
H
Hacker News: Front Page
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cisco Blogs
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cybersecurity and Infrastructure Security Agency CISA
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
S
Schneier on Security
The Hacker News
The Hacker News
Cyberwarzone
Cyberwarzone
T
Tenable Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tailwind CSS Blog
S
Secure Thoughts
N
Netflix TechBlog - Medium
T
The Exploit Database - CXSecurity.com
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Help Net Security
Help Net Security
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
L
LangChain Blog
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
Hacker News: Ask HN
Hacker News: Ask HN
www.infosecurity-magazine.com
www.infosecurity-magazine.com
有赞技术团队
有赞技术团队
P
Privacy International News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Recent Announcements
Recent Announcements
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
Recorded Future
Recorded Future
The Last Watchdog
The Last Watchdog
G
Google Developers Blog
T
Threatpost
小众软件
小众软件
S
Securelist
Recent Commits to openclaw:main
Recent Commits to openclaw:main
O
OpenAI News

VnYzm的博客

游戏玩后感:ReLief:献给亲爱的你 我的周边(谷子)分享 游戏玩后感:Kanon 简谱:致真实的你 《Rust中常见的有关生命周期的误解》学习笔记 简谱:StarMap 简谱:かく咲きたらばいと恋ひめやも 简谱:东风 简谱:无法诉说的思念 简谱:Girlish 游戏玩后感:时钟机关的Layline 简谱:风之琶音 简谱:星空的记忆 简谱:因为遇见了你 简谱:月童 番茄简谱脚本转调器 游戏玩后感:青空下的约定:Refine 游戏玩后感:在这苍穹展翅 书籍读后感:控制论与科学方法论 游戏玩后感:恋爱表达式 游戏玩后感:樱之诗 MLIR-tutorial学习笔记 游戏玩后感:潜伏之赤途 游戏玩后感:纯爱咖啡厅:帕露菲重制版 游戏玩后感:智以泪聚 游戏玩后感:初雪樱 游戏玩后感:告别回忆:从今以后 游戏玩后感:梦灯花 游戏玩后感:金辉恋曲四重奏 游戏玩后感:五彩斑斓的世界 昇腾310P使用记录 游戏玩后感:AIR 游戏玩后感:弹丸论破 游戏玩后感:流景之海的艾佩莉亚 Xilinx_HLS上板过程记录 游戏玩后感:告别回忆2 游戏玩后感:恋爱绮谭 Faiss和Rapidsai_Raft使用记录 游戏玩后感:近月少女的礼仪 游戏玩后感:樱色之云,绯色之恋 游戏玩后感:幸运草的约定 游戏玩后感:星之梦、候鸟和丸子与银河龙 游戏玩后感:白色相簿2 Windows上使用VTune分析PyTorchExtension调用的Cpp程序 SpinalHDL上板过程记录 游戏玩后感:仰望夜空的星辰 最简单的算卦方法之一:梅花易数法 游戏玩后感:苍之彼方的四重奏 krkr引擎解包工具介绍 自定义CUDA实现PyTorch算子的四种简单方法 游戏玩后感:星空的记忆 游戏玩后感:9nine 游戏玩后感:AtriMyDearMoments 游戏玩后感:极限脱出 游戏玩后感:魔女的夜宴 SSH实现多跳代理 动漫观后感:向山进发 flv重封装H264、AAC流 动漫观后感:夏日重现 CSP模板 游戏玩后感:海沙风云 动漫观后感:灵能百分百 游戏玩后感:交响乐之雨 游戏玩后感:爱上火车LastRun 游戏玩后感:LittleBustersEX 游戏玩后感:SummerPockets 游戏玩后感:逆转裁判 Ultra96V2开发板简单使用 SpinalWorkshop实验笔记(三) SpinalWorkshop实验笔记(二) SpinalWorkshop实验笔记(一) PYNQ开发板上使用USB声卡+OSS兼容层播放音频 TestOS移植K210开发板 rCore-Tutorial-Book-v3学习笔记(七) 动漫观后感:凉宫春日的忧郁 rCore-Tutorial-Book-v3学习笔记(♭七) rCore-Tutorial-Book-v3学习笔记(六) rCore-Tutorial-Book-v3学习笔记(五) rCore-Tutorial-Book-v3学习笔记(四) rCore-Tutorial-Book-v3学习笔记(三) rCore-Tutorial-Book-v3学习笔记(二) rCore-Tutorial-Book-v3学习笔记(一) 游戏玩后感:RewritePlus MIT-6.S081-2020实验(xv6-riscv64)十一:net MIT-6.S081-2020实验(xv6-riscv64)十:mmap MIT-6.S081-2020实验(xv6-riscv64)九:fs MIT-6.S081-2020实验(xv6-riscv64)八:lock MIT-6.S081-2020实验(xv6-riscv64)七:thread MIT-6.S081-2020实验(xv6-riscv64)六:cow MIT-6.S081-2020实验(xv6-riscv64)四:traps MIT-6.S081-2020实验(xv6-riscv64)三:pgtbl MIT-6.S081-2020实验(xv6-riscv64)二:syscall 动漫观后感:吹响吧上低音号 MIT-6.S081-2020实验(xv6-riscv64)一:util 快速生成网络mp4视频缩略图技术 用plantuml画图示例 QQ缩略图和大图不同实现 Python制作字符图片 动漫观后感:命运石之门 使用OpenCV对图片进行特征点检测和匹配
MIT-6.S081-2020实验(xv6-riscv64)五:lazy
VnYzm · 2021-01-02 · via VnYzm的博客

实验文档

概述

这次实验主要实现Lazy allocation的功能,即进程在动态分配内存的时候先不分配,等到要用到发生缺页中断的时候再实际分配,核心是实现缺页中断的处理。xv6的文档介绍了三种缺页中断的应用,第一为Copy on write,即fork的时候先不复制内存,等到要用到发生缺页中断的时候再实际分配;第二为硬盘虚拟内存,就是当内存不够大的时候将一部分硬盘区域当作内存交换区,虚拟地址只映射到一个无效位置,当访问该虚拟地址发生缺页中断时再把一个页的内容保存进磁盘,然后从磁盘中加载当前这个虚拟地址指向的实际内容;第三就是本实验的内容。

内容

Eliminate allocation from sbrk()

这个任务非常简单,没啥好说的:

uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  struct proc *p = myproc();
  addr = p->sz;
  if (n < 0) p->sz = uvmdealloc(p->pagetable, p->sz, p->sz + n);
  else p->sz += n;
  // if(growproc(n) < 0)
  //   return -1;
  return addr;
}

对n小于0情况的处理是第三个任务的内容,这里可以忽略。

Lazy allocation

这个任务要求实现对缺页中断的处理,因为在sbrk的时候仅仅指扩大了进程的虚拟地址区域,所以在访问这些虚拟地址时会发生缺页中断,这里就需要在发生缺页中断的时候分配物理内存然后映射,中断处理函数usertrap()对缺页中断进行处理:

    ......
    syscall();
  } else if((which_dev = devintr()) != 0){
    // ok
  } else {
      if (r_scause() == 13 || r_scause() == 15) {
          uint64 va = r_stval(); if (handle_page(va, p) == -1) p->killed = 1;
      } else {
          printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
          printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());
          p->killed = 1;
      }
  }
  if(p->killed)
    exit(-1);

这里把缺页中断的实际处理过程抽象成了一个函数,实际上仅从任务2考虑是没有必要的,但是任务3中还需要对copyin、copyout这些函数中发生缺页的情况进行处理,所以抽象成一个函数方便各处调用。

handle_page函数我写在proc.c里,因为这里已经包含了所需要的头文件:

int handle_page(uint64 va, struct proc *p) {
    uint64 base =  PGROUNDDOWN(va);
    if (va >= p->sz || va < p->trapframe->sp) return -1;
    char *mem = kalloc();
    if (mem == 0) return -1;
    memset(mem, 0, PGSIZE);
    if(mappages(p->pagetable, base, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0) {
        kfree(mem); return -1;
    }
    return 0;
}

这些return -1的情况也是任务3的内容,任务2可以忽略,主要都是借鉴函数uvmalloc。然后修改一下uvmunmap(),即把一些因为缺页导致的panic跳掉了,因为这些页从来就没分配过,也就不用释放:

  for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
    if((pte = walk(pagetable, a, 0)) == 0) continue;
      // panic("uvmunmap: walk");
    if((*pte & PTE_V) == 0) continue;
      // panic("uvmunmap: not mapped");
    if(PTE_FLAGS(*pte) == PTE_V)
      panic("uvmunmap: not a leaf");
    ......

Lazytests and Usertests

这个任务主要是把上个任务遗留的一些不合法情况进行处理。

第一是sbrk的参数为负数的问题,根据growproc函数的内容,对参数为负数的情况就是释放参数绝对值大小的内存,仿造growproc()就行了,见上面的代码。uvmdealloc本身不用修改,因为内部就是调用uvmunmap的。

第二是缺页中断中当虚拟地址不合法时应该直接返回并杀掉进程,不合法包含两种情况,一是虚拟地址太大,大出了进程所申请的内存(不管实际有没有分配),因为进程虚拟地址从0开始,所以只要保证虚拟地址小于p->sz即可;而是虚拟地址太小,比进程的栈顶还低(注意栈是从高往低增长的),这就需要知道栈顶的位置,查看测试程序usertests,发现它获取栈顶的方法就是读sp寄存器,但是缺页中断的处理是在内核态,sp指向的也是内核栈的栈顶,想要获得用户栈的栈顶,可以借助进程的中断帧来实现,即读取p->trapframe->sp,需要保证虚拟地址大于等于这个值。杀掉进程可以观察usertrap函数的其他位置,发现只要令p->killed=1即可,见上面的代码。

第三是如果申请物理内存失败时也要杀掉进程,加上映射失败,照着uvmalloc里写就行了。

第四是fork的时候复制到缺页的虚拟地址时的处理,注意到fork的这部分是调用的uvmcopy,所以改uvmcopy,和uvmunmap一样,缺页导致的panic跳掉:

  for(i = 0; i < sz; i += PGSIZE){
    if((pte = walk(old, i, 0)) == 0) continue;
      // panic("uvmcopy: pte should exist");
    if((*pte & PTE_V) == 0) continue;
      // panic("uvmcopy: page not present");
    ......

第五是read和write文件的时候如果传入了一个缺页的虚拟地址(在将文件读入内存和将内存写入文件时需要传入地址),追踪这两个函数的过程可以发现最终处理地址调用的是copyin、copyinstr和copyout函数,注意到这几个函数会先walk一下传入的虚拟地址,如果得不到物理地址就直接返回失败,而不会经过缺页中断的过程,所以直接加入代码让其在判断得不到物理地址的情况下调用handle_page函数即可:

    va0 = PGROUNDDOWN(srcva);
    pa0 = walkaddr(pagetable, va0);
    if(pa0 == 0) {
        if (handle_page(va0, myproc()) == -1) return -1; else pa0 = walkaddr(pagetable, va0);
      // return -1;
    }
    ......

总结一下,缺页中断的发生时刻应该是在MMU访问到一个PTE_V位为0的PTE时,在xv6中这个PTE的其他位是没有意义的,而在riscv-pk(用在spike模拟器上的代理内核)则让PTE的其他位指向一个标记结构体,里面包含了这个缺页的信息,比如该缺页是否是因为内存被置换到硬盘上了,置换到了哪个位置等信息,这样就使得该系统可以处理多种原因导致的缺页中断,而xv6应该是不支持硬盘虚拟内存的。