Chinaunix首页 | 论坛 | 博客
  • 博客访问: 511028
  • 博文数量: 52
  • 博客积分: 1223
  • 博客等级: 少尉
  • 技术积分: 751
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-23 21:32
文章分类

全部博文(52)

文章存档

2016年(1)

2015年(5)

2013年(1)

2012年(45)

分类: LINUX

2012-03-24 11:44:23

一. 内核栈


每个进程拥有一个内核栈,调度切换至一个新进程时,会根据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返回用户态。

阅读(3748) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~