xv6项目开源—05

news/2024/4/30 7:09:10

xv6项目开源—05.md

理论:

1、设备驱动程序在两种环境中执行代码:上半部分在进程的内核线程中运行,下半部分在中断时执行。上半部分通过系统调用进行调用,如希望设备执行I/O操作的readwrite。这段代码可能会要求硬件执行操作(例如,要求磁盘读取块);然后代码等待操作完成。最终设备完成操作并引发中断。驱动程序的中断处理程序充当下半部分,计算出已经完成的操作,如果合适的话唤醒等待中的进程,并告诉硬件开始执行下一个正在等待的操作。

2、驱动程序管理的UART硬件是由QEMU仿真的16550芯片。在真正的计算机上,16550将管理连接到终端或其他计算机的RS232串行链路。运行QEMU时,它连接到键盘和显示器。

3、xv6的shell通过*init.c* (*user/init.c*:19)中打开的文件描述符从控制台读取输入。对read的调用实现了从内核流向consoleread (*kernel/console.c*:82)的数据通路。consoleread等待输入到达(通过中断)并在cons.buf中缓冲,将输入复制到用户空间,然后(在整行到达后)返回给用户进程。如果用户还没有键入整行,任何读取进程都将在sleep系统调用中等待(kernel/console.c:98)

4、计时器中断可能发生在用户或内核代码正在执行的任何时候;内核无法在临界区操作期间禁用计时器中断。因此,计时器中断处理程序必须保证不干扰中断的内核代码。基本策略是处理程序要求RISC-V发出“软件中断”并立即返回。RISC-V用普通陷阱机制将软件中断传递给内核,并允许内核禁用它们。处理由定时器中断产生的软件中断的代码可以在devintr (*kernel/trap.c*:204)中看到

5、UART驱动程序首先将传入的数据复制到内核中的缓冲区,然后复制到用户空间。这在低数据速率下是可行的,但是这种双重复制会显著降低快速生成或消耗数据的设备的性能。一些操作系统能够直接在用户空间缓冲区和设备硬件之间移动数据,通常带有DMA。

6、延迟分配用户空间堆内存(lazy allocation of user-space heap memory)

实践:

1、Lazy allocation

​ 修改***trap.c***中的代码以响应来自用户空间的页面错误,方法是新分配一个物理页面并映射到发生错误的地址,然后返回到用户空间,让进程继续执行。您应该在生成“usertrap(): …”消息的printf调用之前添加代码。你可以修改任何其他xv6内核代码,以使echo hi正常工作。

​ 这个实验很简单,就仅仅改动sys_sbrk()函数即可,将实际分配内存的函数删除,而仅仅改变进程的sz属性

uint64
sys_sbrk(void)
{int addr;int n;if(argint(0, &n) < 0)return -1;addr = myproc()->sz;// lazy allocationmyproc()->sz += n;return addr;
}

(1). 修改usertrap()(*kernel/trap.c*)函数,使用r_scause()判断是否为页面错误,在页面错误处理的过程中,先判断发生错误的虚拟地址(r_stval()读取)是否位于栈空间之上,进程大小(虚拟地址从0开始,进程大小表征了进程的最高虚拟地址)之下,然后分配物理内存并添加映射

  uint64 cause = r_scause();if(cause == 8) {...} else if((which_dev = devintr()) != 0) {// ok} else if(cause == 13 || cause == 15) {// 处理页面错误uint64 fault_va = r_stval();  // 产生页面错误的虚拟地址char* pa;                     // 分配的物理地址if(PGROUNDUP(p->trapframe->sp) - 1 < fault_va && fault_va < p->sz &&(pa = kalloc()) != 0) {memset(pa, 0, PGSIZE);if(mappages(p->pagetable, PGROUNDDOWN(fault_va), PGSIZE, (uint64)pa, PTE_R | PTE_W | PTE_X | PTE_U) != 0) {kfree(pa);p->killed = 1;}} else {// printf("usertrap(): out of memory!\n");p->killed = 1;}} else {...}

(2). 修改uvmunmap()(*kernel/vm.c*),之所以修改这部分代码是因为lazy allocation中首先并未实际分配内存,所以当解除映射关系的时候对于这部分内存要略过,而不是使系统崩溃,这部分在课程视频中已经解答。

void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{...for(a = va; a < va + npages*PGSIZE; a += PGSIZE){if((pte = walk(pagetable, a, 0)) == 0)panic("uvmunmap: walk");if((*pte & PTE_V) == 0)continue;...}
}

2、Lazytests and Usertests

​ 我们为您提供了lazytests,这是一个xv6用户程序,它测试一些可能会给您的惰性内存分配器带来压力的特定情况。修改内核代码,使所有lazytestsusertests都通过。

  • 处理sbrk()参数为负的情况。
  • 如果某个进程在高于sbrk()分配的任何虚拟内存地址上出现页错误,则终止该进程。
  • fork()中正确处理父到子内存拷贝。
  • 处理这种情形:进程从sbrk()向系统调用(如readwrite)传递有效地址,但尚未分配该地址的内存。
  • 正确处理内存不足:如果在页面错误处理程序中执行kalloc()失败,则终止当前进程。
  • 处理用户栈下面的无效页面上发生的错误。

(1). 处理sbrk()参数为负数的情况,参考之前sbrk()调用的growproc()程序,如果为负数,就调用uvmdealloc()函数,但需要限制缩减后的内存空间不能小于0

uint64
sys_sbrk(void)
{int addr;int n;if(argint(0, &n) < 0)return -1;struct proc* p = myproc();addr = p->sz;uint64 sz = p->sz;if(n > 0) {// lazy allocationp->sz += n;} else if(sz + n > 0) {sz = uvmdealloc(p->pagetable, sz, sz + n);p->sz = sz;} else {return -1;}return addr;
}

(2). 正确处理fork的内存拷贝:fork调用了uvmcopy进行内存拷贝,所以修改uvmcopy如下

int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{...for(i = 0; i < sz; i += PGSIZE){if((pte = walk(old, i, 0)) == 0)continue;if((*pte & PTE_V) == 0)continue;...}...
}

(3). 还需要继续修改uvmunmap,否则会运行出错

void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{...for(a = va; a < va + npages*PGSIZE; a += PGSIZE){if((pte = walk(pagetable, a, 0)) == 0)continue;if((*pte & PTE_V) == 0)continue;...}
}

(4). 处理通过sbrk申请内存后还未实际分配就传给系统调用使用的情况,系统调用的处理会陷入内核,scause寄存器存储的值是8,如果此时传入的地址还未实际分配,就不能走到上文usertrap中判断scause是13或15后进行内存分配的代码,syscall执行就会失败

  • 系统调用流程:
    • 陷入内核**>usertrapr_scause()==8的分支>syscall()==>**回到用户空间
  • 页面错误流程:
    • 陷入内核**>usertrapr_scause()==13||r_scause()==15的分支>分配内存==>**回到用户空间

因此就需要找到在何时系统调用会使用这些地址,将地址传入系统调用后,会通过argaddr函数(*kernel/syscall.c*)从寄存器中读取,因此在这里添加物理内存分配的代码

int
argaddr(int n, uint64 *ip)
{*ip = argraw(n);struct proc* p = myproc();// 处理向系统调用传入lazy allocation地址的情况if(walkaddr(p->pagetable, *ip) == 0) {if(PGROUNDUP(p->trapframe->sp) - 1 < *ip && *ip < p->sz) {char* pa = kalloc();if(pa == 0)return -1;memset(pa, 0, PGSIZE);if(mappages(p->pagetable, PGROUNDDOWN(*ip), PGSIZE, (uint64)pa, PTE_R | PTE_W | PTE_X | PTE_U) != 0) {kfree(pa);return -1;}} else {return -1;}}return 0;
}

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

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

相关文章

腾讯云容器与Serverless的融合:探索《2023技术实践精选集》中的创新实践

腾讯云容器与Serverless的融合&#xff1a;探索《2023技术实践精选集》中的创新实践 文章目录 腾讯云容器与Serverless的融合&#xff1a;探索《2023技术实践精选集》中的创新实践引言《2023腾讯云容器和函数计算技术实践精选集》整体评价特色亮点分析Serverless与Kubernetes的…

整理的微信小程序日历(单选/多选/筛选)

一、日历横向多选&#xff0c;支持单日、双日、三日、工作日等选择 效果图 wxml文件 <view class"calendar"><view class"section"><view class"title flex-box"><button bindtap"past">上一页</button&…

N5171B是德科技N5171B信号发生器

181/2461/8938产品概述&#xff1a; N5171B EXG 射频模拟信号发生器具有最佳的 EXG&#xff0c;旨在满足您对组件参数测试和接收器校准的信号需求。其出色的硬件性能可提供更快的吞吐量、更长的正常运行时间以及极好的准确性和可重复性。 Agilent / HP N5171B EXG 射频模拟信…

与机器对话:ChatGPT 和 AI 语言模型的奇妙故事

原文&#xff1a;Talking to Machines: The Fascinating Story of ChatGPT and AI Language Models 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 从 ELIZA 到 ChatGPT&#xff1a;会话式人工智能的简史 会话式人工智能是人工智能&#xff08;AI&#xff09;的一个分…

app上架-您的应用存在最近任务列表隐藏风险活动的行为,不符合华为应用市场审核标准。

上架提示 您的应用存在最近任务列表隐藏风险活动的行为&#xff0c;不符合华为应用市场审核标准。 修改建议&#xff1a;请参考测试结果进行修改。 请参考《审核指南》第2.19相关审核要求&#xff1a;https://developer.huawei.com/consumer/cn/doc/app/50104-02 造成原因 …

OpenCV单通道图像按像素成倍比例放大(无高斯平滑处理)

OpenCV中的resize函数可以对图像做任意比例的放大(/缩小)处理&#xff0c;该处理过程会对图像做高斯模糊化以保证图像在进行放大&#xff08;/缩小&#xff09;后尽可能保留源图像所展现的具体内容&#xff08;消除固定频率插值/采样带来的香农采样信息损失&#xff09;&#x…