mips 异常处理和进程切换

一. 内核栈


每个进程拥有一个内核栈,调度切换至一个新进程时,会根据task_struct->stack(struct thread_info 结构体类型) 的值设置 *kernelsp(当前正在运行进程之内核栈栈顶),将kernelsp的值设置为 task_struct->stack + THREAD_SIZE - 32MIPS 下,使用set_saved_sp 宏来完成设置)。

内核栈主要用于进程运行时产生异常,将异常的现场保存在内核栈上(使用SAVE_ALL宏,SAVE_ALL宏包括SAVE_SOME宏)。


二.
异常产生时现场的保存

使用SAVE_SOME 保存上下文时,如发现从用户态切入核心态,则首先用 get_saved_sp 宏将*kernelsp 置入sp,也就是说:

若是用户态 --> 内核态,则 k0 = sp, sp = *kernelsp - PT_SIZEstore k0, PT_R29(sp),保存其它寄存器。

若是内核态 --> 内核态,直接 k0 = sp, sp = sp - PT_SIZEstore k0, PT_R29(sp),然后保存其它寄存器。

本质是内核栈上分配 PT_SIZE=sizeof(struct pt_regs))大小的空间,作为上下文的保存空间。保存时所有数据精心组织,最后就是一个 struct pt_regs 结构。

三. 进程的切换过程

进程A --> 时钟中断 --> schedule --> switch_to(resume) --> schedule 返回 --> ret_from_irq --> 进程B


1
、时钟中断后使用 SAVE_ALL 在内核栈上保存 $0, $2, $3, $4~$7, $8~$9(64bit), $25, $28, $29, $31, STATUS, CAUSE, EPC

2
、随后调用 switch_toswitch_to调用叶函数resume,完成两个工作:

1)、保存正在运行任务的上下文:

保存 STATUS,使用cpu_save_nonscratch 保存$16~$23, $29(sp), $30,以及 $31,FPU还要fpu_save_double 保存FPU的寄存器。所有都保存于thread_struct 结构中,该结构为 task_struct 的一部分。

这些保存的是 switch_to 前后的上下文


2
)、将要运行的任务上下文加载:

$28 <---- &thread_info
cpu_restore_nonscratch
恢复 $16~$23, $29(sp), $30
*(kernelsp) <---- &thread_info + THREAD_SIZE - 32
恢复 thread_struct 中保存的 STATUSbit 0, bit 8~15 用当前STATUS值替换)


新进程加载也是 switch_to 前后上下文。

3
do_IRQ 返回后,回到handle_int宏执行ref_from_irq,此时sp指向新进程的 pt_regs 结构(即*kernelsp - PT_SIZE + 压入栈中寄存器个数*每个寄存器所占字节数)。

ref_from_irq调用RESTORE_ALL从新进程的 pt_regs 结构中弹出新进程产生时钟中断的时候调用SAVE_ALL保存到pt_regs 结构中的值,并把这些寄存器的值放到cpu中,最后ref_from_irq调用eret返回用户态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值