6.s081操作系统Lab4: trap

文章目录

  • chapter 4
    • 概览
    • 4.1 CPU trap流程
      • 使用寄存器
      • 如果cpu想处理1个trap
    • 4.2 用户态引发的trap
      • 4.2.1 uservec
      • 4.2.2 usertrap
      • 4.2.3 usertrapret和userret
        • usertrapret
        • userret
  • Lab4
    • Backtrace (moderate)
    • Alarm (hard)

chapter 4

概览

  1. trap的场景:系统调用,设备中断,异常
  2. trap对用户是透明的,用户不会察觉发生了1个trap:内核会保存trap前的状态,在trap后恢复

4.1 CPU trap流程

使用寄存器

stvec: 保存trap程序地址
sepc: 临时保存pc寄存器,trap结束时,sret(TODO 不知道是什么,可能是一段程序)会重新将sepc复杂到pc中
scause: trap原因
sscratch: 方便上下文切换

  1. 见userret,sscratch寄存器保存用户页表的trapframe
  2. 见uservec,trapframe页可以用来暂存用户态的寄存器,中断后切换回来;同时保存内核页表在中断时从用户页表切换到内核页表,可以认为是个中介的临时仓库

sstatus: SPP表示从用户态(0)或从内核态(1)切换过来的trap;SIE表示是否启用设备中断

如果cpu想处理1个trap

trap相关:设置scause和sstatus,保存trap原因和来源
状态保存相关:把pc暂存到sepc
执行相关:切换到监督者模式,把stvec复制到pc
cpu不会切换内核页表,不会切换内核栈。但是必须切换pc。

4.2 用户态引发的trap

4.2.1 uservec

uservec就是用户态的trap入口,即cpu的stvec会被设成uservec。
这里要完成3个事:

  1. 保存用户态的32个寄存器
  2. 切换satp寄存器,使用内核页表
  3. 调用处理中断的函数usertrap

(倒叙,写用户进程开始执行前的事情,可参见4.2.3节usertrapret和userret的功能)
在进入用户空间之前,内核会分配1页TRAPFRAME,专门用来暂存trap发生时需要的东西,这个TRAPFRAME的地址放在sscratch寄存器中,TRAPFRAME页还会预先放着开始就已经知道且在trap发生时需要用到的东西:usertrap的地址(进行trap类型判断并调用相应处理函数)、cpu的hartid(TODO,还不知道作用,可能是CPU的id,可以记录处理trap的CPU)、内核页表地址(uservec需要进行用户态页表到内核态页表的切换)。

.globl uservec
uservec:    ## trap.c sets stvec to point here, so# traps from user space start here,# in supervisor mode, but with a# user page table.## sscratch points to where the process's p->trapframe is# mapped into user space, at TRAPFRAME.## swap a0 and sscratch# so that a0 is TRAPFRAMEcsrrw a0, sscratch, a0# save the user registers in TRAPFRAMEsd ra, 40(a0)sd sp, 48(a0)sd gp, 56(a0).............# save the user a0 in p->trapframe->a0csrr t0, sscratchsd t0, 112(a0)# restore kernel stack pointer from p->trapframe->kernel_spld sp, 8(a0)# make tp hold the current hartid, from p->trapframe->kernel_hartidld tp, 32(a0)# load the address of usertrap(), p->trapframe->kernel_trapld t0, 16(a0)# restore kernel page table from p->trapframe->kernel_satpld t1, 0(a0)csrw satp, t1sfence.vma zero, zero# a0 is no longer valid, since the kernel page# table does not specially map p->tf.# jump to usertrap(), which does not returnjr t0

4.2.2 usertrap

usertrap函数会处理来自用户态的中断、异常或系统调用,由uservec汇编代码调用;这里会判断trap的原因,以调用合适的处理函数。最后调用usertrapret()返回用户态。

//
// handle an interrupt, exception, or system call from user space.
// called from trampoline.S
//
void
usertrap(void)
{int which_dev = 0;if((r_sstatus() & SSTATUS_SPP) != 0)panic("usertrap: not from user mode");// send interrupts and exceptions to kerneltrap(),// since we're now in the kernel.w_stvec((uint64)kernelvec);struct proc *p = myproc();// save user program counter.p->trapframe->epc = r_sepc();if(r_scause() == 8){// system callif(p->killed)exit(-1);// sepc points to the ecall instruction,// but we want to return to the next instruction.p->trapframe->epc += 4;// an interrupt will change sstatus &c registers,// so don't enable until done with those registers.intr_on();syscall();} else if((which_dev = devintr()) != 0){// ok} 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);// give up the CPU if this is a timer interrupt.if(which_dev == 2)yield();usertrapret();
}

4.2.3 usertrapret和userret

usertrapret

usertrapret:切换pc寄存器
userret:恢复寄存器,切换页表
usertrapret代码如下,

  1. 临时关闭中断功能:
    intr_off();将中断开关临时关闭(TODO:如何关闭),在从内核态到用户态的转换过程中,暂时停止中断功能,等切换完毕后再开启,可能是为了避免状态机紊乱。
  2. 改变 stvec 来引用 uservec:
    w_stvec(TRAMPOLINE + (uservec - trampoline));推测是重新写cpu的stvec寄存器为uservec地址,以保证下次中断时,cpu仍然跳转到uservec 去处理中断。
  3. 准备 uservec 所依赖的 trapframe 字段,如kernel_satp为内核页表地址等等。
  4. 写一些CPU寄存器:如设sstatus的SPP为0,表示为用户态的中断;设sstatus的SPIE为1,表示在用户态使能中断
  5. 将 sepc 设置为先前保存的用户程序计数器w_sepc(p->trapframe->epc);
  6. 调用 userret,并把TRAPFRAMEsatp作为参数传递过去,userret会切换用户态页表,重设用户态寄存器,最后切换回用户态
//
// return to user space
//
void
usertrapret(void)
{struct proc *p = myproc();// we're about to switch the destination of traps from// kerneltrap() to usertrap(), so turn off interrupts until// we're back in user space, where usertrap() is correct.intr_off();// send syscalls, interrupts, and exceptions to trampoline.Sw_stvec(TRAMPOLINE + (uservec - trampoline));// set up trapframe values that uservec will need when// the process next re-enters the kernel.p->trapframe->kernel_satp = r_satp();         // kernel page tablep->trapframe->kernel_sp = p->kstack + PGSIZE; // process's kernel stackp->trapframe->kernel_trap = (uint64)usertrap;p->trapframe->kernel_hartid = r_tp();         // hartid for cpuid()// set up the registers that trampoline.S's sret will use// to get to user space.// set S Previous Privilege mode to User.unsigned long x = r_sstatus();x &= ~SSTATUS_SPP; // clear SPP to 0 for user modex |= SSTATUS_SPIE; // enable interrupts in user modew_sstatus(x);// set S Exception Program Counter to the saved user pc.w_sepc(p->trapframe->epc);// tell trampoline.S the user page table to switch to.uint64 satp = MAKE_SATP(p->pagetable);// jump to trampoline.S at the top of memory, which // switches to the user page table, restores user registers,// and switches to user mode with sret.uint64 fn = TRAMPOLINE + (userret - trampoline);((void (*)(uint64,uint64))fn)(TRAPFRAME, satp);
}
userret
  1. 将 satp 切换到进程的用户页表,因为用户态和内核态的trampoline都是直接映射,因此在此时进行页表切换后,trampoline的程序仍能继续往下执行。此时a0寄存器指向用户页表的TRAPFRAME页,先将其保存到sscratch
.globl userret
userret:# userret(TRAPFRAME, pagetable)# switch from kernel to user.# usertrapret() calls here.# a0: TRAPFRAME, in user page table.# a1: user page table, for satp.# switch to the user page table.csrw satp, a1sfence.vma zero, zero# put the saved user a0 in sscratch, so we# can swap it with our a0 (TRAPFRAME) in the last step.ld t0, 112(a0)csrw sscratch, t0# restore all but a0 from TRAPFRAMEld ra, 40(a0)ld sp, 48(a0)ld gp, 56(a0)。。。。# restore user a0, and save TRAPFRAME in sscratchcsrrw a0, sscratch, a0# return to user mode and user pc.# usertrapret() set up sstatus and sepc.sret

Lab4

Backtrace (moderate)

实验内容:添加栈帧信息打印
考察点:xv6的栈结构;栈以类似链表的形式保存在1个页面中
关键提示:address lives at a fixed offset (-8) from the frame pointer of a stackframe, and that the saved frame pointer lives at fixed offset (-16) from the frame pointer.
在这里插入图片描述

关键代码:

void
backtrace(void)
{printf("backtrace:\n");uint64 fp = r_fp();uint64 down = PGROUNDDOWN(fp);uint64 up = PGROUNDUP(fp);while (fp >= down && fp < up){uint64* res_addr = (uint64*)(fp - 8);uint64* next_fp_addr = (uint64*)(fp - 16);printf("%p\n", *res_addr);fp = *next_fp_addr;}
}

Alarm (hard)

实验内容:实现系统调用,在进程使用CPU时间超时时,进行回调函数调用,并能正常返回用户态
考察点:系统调用流程;usertrap的寄存器保存位置在trapframe页面;usertrap的pc计数器存储在epc寄存器;
关键提示:

  • When a trap on the RISC-V returns to user space, what determines the instruction address at which user-space code resumes execution?
  • Your solution will require you to save and restore registers—what registers do you need to save and restore to resume the interrupted code correctly? (Hint: it will be many).

关键代码:

// kernel/sysproc.c
int
sys_sigreturn(void)
{memmove(myproc()->trapframe, myproc()->trapframe_back, sizeof(struct trapframe));myproc()->calling = 0;return 0;
}
//kernel/trap.c// give up the CPU if this is a timer interrupt.if(which_dev == 2){p->ticks_count ++;if (p->alarmInterval != -1 && p->ticks_count >= p->alarmInterval && p->calling != 1){// if a handler hasn't returned yet, the kernel shouldn't call it againp->calling = 1;//"re-arm" the alarm counter after each time it goes offp->ticks_count = 0;//save and restore registersmemmove(p->trapframe_back, p->trapframe, sizeof(struct trapframe));//Q:When a trap on the RISC-V returns to user space,//what determines the instruction address at which user-space code resumes execution?//A: epc!p->trapframe->epc = p->alarmHandler;}yield();}

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

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

相关文章

2024年手把手教CleanMyMac X v4.14.6破解版安装激活图文教程

小编给您带来CleanMyMac X v4.14.6中文破解版&#xff0c;CleanMyMac X破解版是应用在MacOS上的一款Mac系统清理优化工具&#xff0c;使用cleanmymac x 中文破解版只需两个简单步骤就可以把系统里那些乱七八糟的无用文件统统清理掉&#xff0c;节省宝贵的磁盘空间。 CleanMyMac…

redis各种数据类型的应用场景

String应用场景 单值缓存 SET key value GET key 对象缓存 SET user:1 value(json格式数据)MSET user:1:name zhuge user:1:balance 1888 MGET user:1:name user:1:balance 分布式锁 SETNX product:10001 true //返回1代表获取锁成功 …

使用案例总结Vlookup函数的30种用法

1 基础用法 =VLOOKUP(A12,B$1:D$8,3,0) 2 批量查找 =VLOOKUP(A11:A13,A2:C8,3,0) 3 模糊查找 =VLOOKUP("*"&D2&"*",A:B,2,0) 4 模糊查找2 =VLOOKUP(D10&"??",A:B,2,0) 5 模糊查找3 =

pycharm通过ssh连接远程服务器的docker容器进行运行和调试代码

pycharm连接远程服务器的docker容器通常有两种方法&#xff1a; 第一种&#xff1a;pycharm通过ssh连接已在运行中的docker容器 第二种&#xff1a;pycharm连接docker镜像&#xff0c;pycharm运行代码再自动创建容器 第一种方法比较通用简单&#xff0c;作者比较推崇。 条件…

特氟龙材质PFA、FEP、PTFE三种氟塑料试剂瓶区别

PFA、FEP、PTFE三种材质&#xff0c;都具有良好的耐化学性和耐热性。适合用于微量分析&#xff0c;痕量分析&#xff0c;超痕量分析ICP-MS/OES/AAS分析等实验。PFA、FEP、PTFE是三种常见的氟塑料材料&#xff0c;它们在石油化工、机械、半导体电子等领域得到广泛应用。虽然它们…

展示一段比较简单的人工智能自动做模型的程序

人工智能是一种模拟或模仿人类智能的技术。它通过使计算机系统具有一定的认知能力和学习能力&#xff0c;使其能够自动完成一系列复杂的任务。人工智能可以在各个领域应用&#xff0c;包括图像识别、语音识别、自然语言处理、机器学习等。人工智能还可以用于解决各种问题&#…

Docker 的基本概念、优势、及在程序开发中的应用

Docker 是一种容器化平台,它通过使用容器化技术,将应用程序及其依赖性打包到一个独立的、可移植的容器中,从而实现应用程序的快速部署、可靠性和可扩展性。 下面是 Docker 的一些基本概念和优势: 容器:Docker 使用容器化技术,将应用程序及其依赖性打包到一个可移植的容器…

CUDA C:线程、线程块与线程格

相关阅读 CUDA Chttps://blog.csdn.net/weixin_45791458/category_12530616.html?spm1001.2014.3001.5482 第一百篇博客&#xff0c;写点不一样的。 当核函数在主机端被调用时&#xff0c;它会被转移到设备端执行&#xff0c;此时设备会根据核函数的调用格式产生对应的线程(…

docker在线安装minio

1、下载最新minio docker pull minio/minio 2、在宿主机创建 /usr/local/data/miniodocker/config 和 /usr/local/data/miniodocker/data,执行docker命令 docker run -p 9000:9000 -p 9090:9090 --name minio -d --restartalways -e MINIO_ACCESS_KEYminio -e MINIO_SECRET_K…

力扣225. 用队列实现栈【附进阶版】

文章目录 力扣225. 用队列实现栈示例思路及其实现两个队列模拟栈一个队列模拟栈 力扣225. 用队列实现栈 示例 思路及其实现 两个队列模拟栈 队列是先进先出的规则&#xff0c;把一个队列中的数据导入另一个队列中&#xff0c;数据的顺序并没有变&#xff0c;并没有变成先进后…

引领半导体划片机行业,实现钛酸锶基片切割的卓越效能

在当今快速发展的半导体行业中&#xff0c;博捷芯以其卓越的技术实力和精准的行业应用&#xff0c;脱颖而出&#xff0c;再次引领行业潮流。这次&#xff0c;他们将先进的BJX3356划片机技术应用于钛酸锶基片的切割&#xff0c;为半导体制造行业的进一步发展提供了强大的技术支持…

基于知识库的接口自动化测试——结果模型化方法与装置的分析

一、背景 随着自动化测试的设计理念不断完善、新的技术不断应用&#xff0c;自动化测试资产的积累代价和维护成本不断降低&#xff0c;自动化测试资产的数量持续增长。同时&#xff0c;随着DevOps的普及&#xff0c;应用研发过程越来越敏捷&#xff0c;自动化测试能力逐步从测…

js输入框部分内容不可编辑,其余正常输入,el-input和el-select输入框和多个下拉框联动后的内容不可修改

<tr>//格式// required自定义指令<e-td :required"!read" label><span>地区&#xff1a;</span></e-td><td>//v-if"!read && this.data.nationCode 148"显示逻辑<divclass"table-cell-flex"sty…

camera曝光时间

曝光和传感器读数 相机上的图像采集过程由两个不同的部分组成。第一部分是曝光。曝光完成后&#xff0c;第二步就是从传感器的寄存器中读取数据并传输&#xff08;readout&#xff09;。 曝光&#xff1a;曝光是图像传感器进行感光的一个过程&#xff0c;相机曝光时间&#xf…

技术阅读周刊第十期

技术阅读周刊&#xff0c;每周更新。 周四加了个班&#xff0c;周五没缓过来&#xff0c;就推迟到今天更新了 历史更新 20231117&#xff1a;第六期20231124&#xff1a;第七期20231201&#xff1a;第八期20231215&#xff1a;第九期 Golang: 14 Shorthand Tricks You Might No…

LLMs 玩狼人杀:清华大学验证大模型参与复杂交流博弈游戏的能力

作者&#xff1a;彬彬 编辑&#xff1a;李宝珠&#xff0c;三羊 清华大学研究团队提出了一种用于交流游戏的框架&#xff0c;展示了大语言模型从经验中学习的能力&#xff0c;还发现大语言模型具有非预编程的策略行为&#xff0c;如信任、对抗、伪装和领导力。 近年来&#x…

设计模式——迭代器模式

引言 迭代器模式是一种行为设计模式&#xff0c; 让你能在不暴露集合底层表现形式 &#xff08;列表、 栈和树等&#xff09; 的情况下遍历集合中所有的元素。 问题 集合是编程中最常使用的数据类型之一。 尽管如此&#xff0c; 集合只是一组对象的容器而已。 大部分集合使用…

Spring 原理(一)

Spring 原理 它是一个全面的、企业应用开发一站式的解决方案&#xff0c;贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。 Spring 特点 轻量级控制反转面向切面容器框架集合 Spring 核心组件 Spring 常用模块 Spring 主要包 Spring 常用注解 bean …

达索系统SOLIDWORKS 2024 云服务新功能

“云服务 是基于互联网的相关服务的增加、使用和交互模式&#xff0c;通常涉及通过互联网来提供动态易扩展且经常是虚拟化的资源。 云是网络、互联网的一种比喻说法。过去在图中往往用云来表示电信网&#xff0c;后来也用来表示互联网和底层基础设施的抽象。云服务指通过网络以…

小贴士:知道方程的解如何求通解

1.思路&#xff1a;认知&#xff1a;题中的所有解都是特解&#xff0c;解的形式为kxb 1.如何求通解&#xff1a;a1a2是题目中提供的条件&#xff0c;根据认知它们的和是2b&#xff0c;所以b等于a1a3除2&#xff0c;而有一条认知&#xff0c;为两个特解的差为通解向量&#xff0…