Xv6异常处理(一):用户异常

阅读材料

  • Xv6代码:trampoline.S、trap.c
  • 教材第4章

trapframe页

对于每个用户进程来说,都有一个trapframe页。当用户异常发生时,trapframe页的作用有两个:

  1. 保存用户进程32个通用寄存器的值
  2. 恢复内核寄存器的值
struct trapframe
{/*   0 */ uint64 kernel_satp;	// kernel page table/*   8 */ uint64 kernel_sp;		// top of process's kernel stack/*  16 */ uint64 kernel_trap;	// usertrap()/*  24 */ uint64 epc;			// saved user program counter/*  32 */ uint64 kernel_hartid; // saved kernel tp/*  40 */ uint64 ra;/*  48 */ uint64 sp;/*  56 */ uint64 gp;/*  64 */ uint64 tp;/*  72 */ uint64 t0;/*  80 */ uint64 t1;/*  88 */ uint64 t2;/*  96 */ uint64 s0;/* 104 */ uint64 s1;/* 112 */ uint64 a0;/* 120 */ uint64 a1;/* 128 */ uint64 a2;/* 136 */ uint64 a3;/* 144 */ uint64 a4;/* 152 */ uint64 a5;/* 160 */ uint64 a6;/* 168 */ uint64 a7;/* 176 */ uint64 s2;/* 184 */ uint64 s3;/* 192 */ uint64 s4;/* 200 */ uint64 s5;/* 208 */ uint64 s6;/* 216 */ uint64 s7;/* 224 */ uint64 s8;/* 232 */ uint64 s9;/* 240 */ uint64 s10;/* 248 */ uint64 s11;/* 256 */ uint64 t3;/* 264 */ uint64 t4;/* 272 */ uint64 t5;/* 280 */ uint64 t6;
};

uservec汇编函数

当U模式下发生异常(中断/异常/系统调用),内核将跳转到uservec汇编函数,注意此时虽然处于S模式下,但地址空间仍是用户地址空间,uservec汇编函数的责任之一就是手动切换到内核地址空上去

载入TRAPFRAME地址

首先保存a0寄存器到sscratch寄存器当中,接着将TRAPFRAME的虚拟地址载入a0寄存器。

sscratch寄存器是S模式CSR寄存器,用于内核程序临时保存数据

csrw sscratch, a0
li   a0, TRAPFRAME

TRAOFRAME页通过宏定义在memlayout.h文件当中,对于每个用户进程都一样,是Sv39最大虚拟地址下的第二个页(第一个页是TRAMPOLINE)

#define TRAMPOLINE (MAXVA - PGSIZE)
#define TRAPFRAME (TRAMPOLINE - PGSIZE)

保存用户通用寄存器

注意:这里只保存了30个用户进程的通用寄存器,除了x0寄存器(值衡为0,不用保存)和a0寄存器(稍后保存)

sd ra,  40(a0)
sd sp,  48(a0)
sd gp,  56(a0)
sd tp,  64(a0)
sd t0,  72(a0)
sd t1,  80(a0)
sd t2,  88(a0)
sd s0,  96(a0)
sd s1,  104(a0)
sd a1,  120(a0)
sd a2,  128(a0)
sd a3,  136(a0)
sd a4,  144(a0)
sd a5,  152(a0)
sd a6,  160(a0)
sd a7,  168(a0)
sd s2,  176(a0)
sd s3,  184(a0)
sd s4,  192(a0)
sd s5,  200(a0)
sd s6,  208(a0)
sd s7,  216(a0)
sd s8,  224(a0)
sd s9,  232(a0)
sd s10, 240(a0)
sd s11, 248(a0)
sd t3,  256(a0)
sd t4,  264(a0)
sd t5,  272(a0)
sd t6,  280(a0)

保存a0寄存器

用户进程a0寄存器的原始值保存在了sscratch寄存器当中,此时的a0寄存器的值其实是TRAPFRAME,因此我们将sscratch寄存器的值保存到栈上

csrr t0, sscratch
sd   t0, 112(a0)

恢复内核寄存器

现在,用户进程32个通用寄存器的值都已经保存到用户栈上了,我们可以随意使用这32个寄存器了。首先恢复内核寄存器:

  1. 内核栈指针(sp寄存器)
  2. 内核HART ID(tp寄存器)
  3. usertrap()函数地址

ld sp,  8(a0)
ld tp, 32(a0)
ld t0, 16(a0)

切换到内核地址空间

接着切换地址空间到内核的地址空间。注意切换前后都要使用sfence.vma指令冲刷TLB

        ld   t1, 0(a0)
sfence.vma zero, zerocsrw satp, t1
sfence.vma zero, zero

 跳转到内核中用户异常处理程序处理异常

jr t0

用户异常处理程序

该函数负责处理用户异常

  1. 判断上一个处理器模式是否为U模式,如果不是的话报错
  2. 保存kernelvec函数地址到stvec寄存器
  3. 保存发生异常的用户PC
  4. 根据scause寄存器的值进行判断
  5. 如果是系统调用,则调用syscall()函数进一步处理
  6. 如果是外部中断,则调用devintr()函数进一步处理
  7. 如果是异常,则报错并kill该进程
  8. 调用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 (killed(p))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 sepc, scause, and sstatus,// so enable only now that we're done with those registers.intr_on();syscall();}else if ((which_dev = devintr()) != 0){// ok}else{printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid);printf("            sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());setkilled(p);}if (killed(p))exit(-1);// give up the CPU if this is a timer interrupt.if (which_dev == 2)yield();usertrapret();
}

从内核异常处理程序返回

  1. uservec汇编函数地址写入stvec寄存器中 
  2. 保存内核信息:内核根页表地址、内核栈指针、usertrap函数地址、内核HART ID
  3. 设置返回的处理器模式为U模式,并且返回后开启外部中断
  4. 设置返回后的PC
  5. 保存用户根页表基地址到a0寄存器中
  6. 调用userret汇编函数
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 uservec in trampoline.Suint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline);w_stvec(trampoline_uservec);// set up trapframe values that uservec will need when// the process next traps into 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 userret in 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 trampoline_userret = TRAMPOLINE + (userret - trampoline);((void (*)(uint64))trampoline_userret)(satp);
}

userret汇编函数

userret汇编函数与uservec汇编函数做的工作相反:

  1. 切换到用户地址空间
  2. 恢复用户32个通用寄存器
  3. 执行sret指令返回
.globl userret
userret:# userret(pagetable)# called by usertrapret() in trap.c to# switch from kernel to user.# a0: user page table, for satp.# switch to the user page table.sfence.vma zero, zerocsrw satp, a0sfence.vma zero, zeroli a0, TRAPFRAME# restore all but a0 from TRAPFRAMEld ra, 40(a0)ld sp, 48(a0)ld gp, 56(a0)ld tp, 64(a0)ld t0, 72(a0)ld t1, 80(a0)ld t2, 88(a0)ld s0, 96(a0)ld s1, 104(a0)ld a1, 120(a0)ld a2, 128(a0)ld a3, 136(a0)ld a4, 144(a0)ld a5, 152(a0)ld a6, 160(a0)ld a7, 168(a0)ld s2, 176(a0)ld s3, 184(a0)ld s4, 192(a0)ld s5, 200(a0)ld s6, 208(a0)ld s7, 216(a0)ld s8, 224(a0)ld s9, 232(a0)ld s10, 240(a0)ld s11, 248(a0)ld t3, 256(a0)ld t4, 264(a0)ld t5, 272(a0)ld t6, 280(a0)# restore user a0ld a0, 112(a0)# return to user mode and user pc.# usertrapret() set up sstatus and sepc.sret

 参考资料

The xv6 Kernel-14 Trap Handling_哔哩哔哩_bilibili

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

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

相关文章

最新适用:关于夫妻共同债务的裁判规则+司法观点

✦ 重点条文 ✦ 《民法典》第一千零六十四条 夫妻双方共同签名或者夫妻一方事后追认等共同意思表示所负的债务,以及夫妻一方在婚姻关系存续期间以个人名义为家庭日常生活需要所负的债务,属于夫妻共同债务。 夫妻一方在婚姻关系存续期间以个人名义超…

新手入门:小程序架构快速上手

目录 新建项目和配置 项目基本结构 新建小程序页面 修改项目首页 全局配置 窗口 tabBar 页面配置 小程序基本语法 wxml 数据绑定 条件渲染 列表渲染 wxss wxss 对比 css rpx import 全局样式和局部样式 js wxs 数据请求 get和post请求 小程序和跨域 小程…

特征工程与交叉验证在机器学习中的应用

数据入口:学生考试表现影响因素数据集 - Heywhale.com 本数据集提供了关于影响学生考试成绩的多种因素的全面概述。数据集包含了有关学习习惯、出勤率、家长参与、资源获取等方面的信息。 数据说明 字段名说明Hours_Studied每周学习的小时数Attendance出勤率&…

30个GPT提示词天花板,一小时从大纲到终稿

PROMPT 1 中文:构建研究背景与意义,阐述研究问题的紧迫性和重要性。 English: Establish the research background and significance, elucidating the urgency and importance of the research question. 中文:设计研究目的与目标&#xff…

深入解析:HTTP 和 HTTPS 的区别

网络安全问题正变得日益重要,而 HTTP 与 HTTPS 对用户数据的保护十分关键。本文将深入探讨这两种协议的特点、工作原理,以及保证数据安全的 HTTPS 为何变得至关重要。 认识 HTTP 与 HTTPS HTTP 的工作原理 HTTP,全称超文本传输协议&#xf…

go 安装依赖超时

一、配置代理 go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.io,direct go get github.com/unidoc/unioffice

对象关系映射ORM

目录 ORM【重要】 1、 什么是ORM 2、 实体类 3、 ORM改造登录案例 ORM【重要】 1、 什么是ORM 目前使用JDBC完成了CRUD,但是现在是进行CRUD,增删改方法要设计很多参数,查询的方法需要设计集合才能返回. 在实际开发中,我们需要将零散的数据封装到对象处理. ORM (Object Rela…

十九、石英晶体振荡电路

石英晶体振荡电路 1、石英晶体的特点、等效电路、特性曲线; 2、石英晶体振动器的特点, 3、石英晶体振动器的振荡频率

软考(中级-软件设计师)计算机系统篇(0921)

六、计算机系统组成(五大部件) (冯.诺依曼) 冯.诺依曼计算机的特点: 计算机有五大部件组成:输入设别,输出设备,控制器,运算器,存储器;指令和疏忽都以同等地位存于存储器…

为什么年轻人都热衷找搭子,而不是找对象?

在繁华的都市中,有一个名叫晓悦的年轻人。晓悦每天穿梭于忙碌的工作和快节奏的生活之间,渐渐地,她发现身边的朋友们都开始找起了 “搭子”。 有一天,晓悦结束了一天疲惫的工作,坐在咖啡店里,看着窗外匆匆而…

为写论文头疼?推荐4款ai写毕业论文初稿的软件

写论文对于许多学生来说是一项既重要又具挑战性的任务。为了帮助大家更高效地完成这一过程,我将推荐四款优秀的AI写毕业论文初稿的软件,并详细介绍它们的功能和优势。 传送门:https://www.aipaperpass.com?piclLGw 千笔-AIPassPaper是一款功…

面向对象例题之例题的特性

答案:C 解析:对象里面的方法和属性数量是不确定的,可以不断扩展写多个属性和方法 清洗的边界是对象必备的,哪些是这个类的,哪些是其他类的都有体现。 良好的定义行为一般指定义良好的属性和方法 可扩展性指的是子类…

【问题随记】在使用 AuthenticationManager 的时候,出现循环依赖问题 —— `java.lang.StackOverflowError`

问题随记 在使用 AuthenticationManager 的时候,出现循环依赖问题 —— java.lang.StackOverflowError,查资料查了两天半,终于找到原因。 2024-06-16T17:54:19.48708:00 ERROR 20672 --- [nio-8789-exec-1] o.a.c.c.C.[.[.[/].[dispatcherS…

波分技术基础 -- FEC

信号在传输过程中,不可避免的会出现劣化、误码,FEC (Forward error correction) 技术确保通信系统在噪声和其他损伤的影响下,依然能够实现无错误传输。 应用场景:长途密集波分系统(DWDM)实现方式&#xff…

LED显示屏迎来革新:GOB封装技术引领行业新风尚

在我们日常生活中,LED显示屏无处不在,从繁华的街头广告牌到家庭娱乐中心的大屏幕电视,它们都以鲜明的色彩和清晰的画质吸引着我们的目光。然而,在LED显示屏技术日新月异的今天,一种名为GOB(Glue On Board&a…

python:给1个整数,你怎么判断是否等于2的幂次方?

最近在csdn上刷到一个比较简单的题目,题目要求不使用循环和递归来实现检查1个整数是否等于2的幂次方,题目如下: 题目的答案如下: def isPowerofTwo(n):z bin(n)[2:]print(bin(n))if z[0] ! 1:return Falsefor i in z[1:]:if i !…

华为全联接大会HUAWEI Connect 2024印象(二):昇腾AI端侧推理

此次参加HUAWEI Connect 2024最主要目标是了解昇腾AI端侧推理技术,希望将其融合到我现在嵌入式系统课程中,不过刚开始在一楼找到一个小展台,看到了香橙派Orange Pi。香橙派是深圳迅龙的一个品牌,他们和很多芯片厂商都合作过&#…

IPsec-VPN中文解释

网络括谱图 IPSec-VPN 配置思路 1 配置IP地址 FWA:IP地址的配置 [FW1000-A]interface GigabitEthernet 1/0/0 [FW1000-A-GigabitEthernet1/0/0]ip address 10.1.1.1 24 //配置IP地址 [FW1000-A]interface GigabitEthernet 1/0/2 [FW1000-A-GigabitEthernet1/0/2]ip a…

计算机毕业设计 基于Python的美术馆预约系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

【笔记】第三节 组织与性能

3.1 基本成分 3.2 微观组织特征 0.6-0.8C%碳素钢的组织为珠光体和少量的铁素体。 如何把组织和性能联系起来?德国克虏伯公司的研究——珠光体片间距与渗碳体片层厚度成比例: t s 0 ( ρ 15 ( C % ) − 1 ) ts_0(\frac{\rho}{15(C\%)}-1) ts0​(15(C%)…