JOS 用户态page fault保护处理机制分析

JOS 用户态page fault保护处理机制分析


常常会在用户态触发page fault,如果直接让其因为page fault跌入内核触发panic目测是不是"太残忍了"

你想想,一个刚学会写C程序的童鞋,就经常干 *(int *)0x00.

当然,我只是比较赤果果的指出这种问题而已,这位同学可能经常用各种指针,然后指针为初始化亦或等于NULL的时候,对其进行赋值或解引用.总不至于让一个刚学C的人就把整个系统都给挂了吧?恩.我们需要一种保护机制.


可以在用户态触发page fault,跌入内核时,我们可以做点"手脚",不要让他触发panic.

内核稍作处理,程序执行流返回到用户,并提示用户"同学,对非法的地址这么读写都是不对的哇"[ core dump大家一定都很熟悉了...哈哈]


好吧需求背景说完了,进入正题.

faultdie.c用户程序

JOS 用户态page fault保护处理机制分析_第1张图片

集中精力关注,umain函数.

无非就是在对一个非法地址赋值前进行了一点"小动作"--set_pgfault_handler.


这里传入了一个普通的函数地址handler.我们看看set_pgfault_handler 做了什么

全局变量 _pgfault_handler是个函数指针.初始全局变量被初始化为0.

JOS 用户态page fault保护处理机制分析_第2张图片

这个函数第一次运行的时候,会为当前进程 thisenv申请一页的内存,把这一页内存,映射到虚拟地址 va.

而后,通过sys_env_set_pgfault_upcall设置了_pgfault_upcall(一个汇编代码的入口)为返回地址.

最后把 _pgfault_handler设置为 handler.


用户触发page fault异常之后,跌入内核态,

struct Trapframe储存在内核栈上

_alltraps会把寄存器各种压栈,然后调用trap(),进而调用trap_dispatch()

于是就会根据触发trap的是什么类型的异常来进行相依的处理,这里是Page fault.

JOS 用户态page fault保护处理机制分析_第3张图片

于是,开始调用page_fault_handler. 

tf指针还是指向刚刚我们压栈好的内核栈上struct Trapframe的首地址处. 


在page_fault_handler内部.首先会检测我们是不是已经申请了用户异常栈的地址(翻到这篇博客看前面set_pgfault_handler里怎么申请的).

JOS 用户态page fault保护处理机制分析_第4张图片

只要申请好了用户异常栈,于是就开始各种寄存器的拷贝.把当前内核栈上面的struct Trapframe拷贝到异常栈上去.

反正内核态有权限嘛~

细心的话你会发现,这里的拷贝是夸段的,内核堆栈段的数据拷贝到用户的异常栈上.因为内核有读写权限~



把utf指向的用户异常栈的栈顶指针赋值给当前内核栈内struct Trapframe的tf_esp成员,这个家伙会在之后内核弹栈切换进程的时候赋值给esp寄存器,进而设置好用户态的栈顶指针!那时候栈的切换就完成了.


env_run开始重新运行当前进程.env_run会调用 env_pop_tf()把内核栈上的struct Trapframe弹栈.切换进程!


我们来测试,就是切换进程后的栈顶是不是在UXSTACKTOP ( 0xeec00000)下面


测试:

我们把断点设置在handler的入口.看 esp在 UXSTACKTOP下面.






你可能感兴趣的:(JOS 用户态page fault保护处理机制分析)