当前位置: 首页 > Linux

【笨叔比特1】为什么do_page_fault函数中的代码需要判断用户态还是内核态?

时间:2023-04-06 11:17:49 Linux

》朋友们,我是本叔叔。从今天开始,本叔叔会尽量每天给大家分享一点点小事。可能有点笨,就像一点点雨滴,它会慢慢汇聚到大江大海!”前两天,几个朋友讨论了这样一个问题。A:do_page_fault函数中有这么一段代码,都是内核中的代码。为什么要判断是内核态还是用户态呢?处理异常的时候一定是在内核态吧?如果(!user_mode(regs))转到no_context;B:内核常驻内存,不会缺页。相反,用户模式内存可能会导致页面错误。进入内核的异常处理进程入口,进行异常处理。没啥感觉不,pagefault不一定是内核态的,这个假设是错误的。A:在这种情况下,内核代码永远不会被页面错误中断。只能是用户进程被页面错误中断了。学生A继续说。A:发生异常时,arm的状态会发生变化,此时不会处于用户态。arm不是有7种工作模式吗?如果cpsr寄存器的低四位全为0,则表示是用户态。当异常发生时,有对应的异常模式,但肯定不是用户模式,所以我认为内核代码中的语句if(user_mode(regs))永远不会为真,定义user_mode(regs)\(((regs)->ARM_cpsr&0xf)==0)从它的实现来看,就是判断最低4位是否为0,显然在异常模式下,是不可能在0之上的同学A和同学B的对话,你认为他们讨论的内容正确吗?图01关于异常——我们理解的CPU不就是做两件事吗?一个是取指令,一个是执行指令。就像我的小朋友一样,她的名字叫小奔奔。我告诉她,小笨笨,去冰箱帮爸爸拿一罐可乐。孩子做的第一件事就是听我说什么。这是听取指示。在她明白之后,她可能会有以下行为。1.她去冰箱给我拿了一罐可乐2.她去冰箱,路上遇到她妈妈,她妈妈逗了她一会儿,她就去厨房给我拿了一个苹果3.她骗跑了以上三种情况就是CPU的三种情况。首先是CPU正常执行这条命令。第二种情况是这条指令在执行的时候,中途出现问题,导致错误。第三个简直就是非法指令。对于ARM处理器,支持四种类型的异常。1.中断。就是我们平时理解的中断,主要由外设触发,是典型的异步异常。ARM中主要包括两种中断:IRQ(普通中断)和FIQ。2.中止可以是同步的或异步的。包括指令异常(取指令时产生)、数据异常(读写内存数据时产生),可以是MMU产生的(比如典型的pagefault异常),也可以是外部存储系统产生的(一般是硬件问题)).3.复位(reset)复位被认为是一种特殊的异常。4.异常说明。对于由异常触发指令引发的异常,如SupervisorCall(SVC)、HypervisorCall(HVC)、SecuremonitorCall(SMC)、SWI等,异常发生后,ARM处理器通常有异常向量表进行通信与软件。交互,因为发生异常,处理器无法自己处理,需要操作系统或软件参与。下图是ARM手册中列出的异常向量表。这张图是一个比较简单明了的向量表。通常发生异常后,ARM处理器会帮我们做一些事情,这些事情都是硬件帮我们做的:将下一条指令的地址(返回地址)保存到新处理器模式的LR寄存器中,将cpsr保存到spsr并设置适当的cpsr(改变处理器的ARM状态,将处理器改变到相应的异常模式,(视情况)改变中断禁止位来禁止相应的中断)设置PC指向相应的地方异常向量表那么软件需要做什么呢???将当前共享寄存器(如r0~r12和r15以及SVC模式和IRQ模式共享的pc)的值保存到当前模式的栈内存中。保证先前架构的值未损坏。进入异常处理函数。处理异常。从中断返回,读回之前存入栈的值,将SPSR的值赋值给CPSR,实现主动切换到之前的模式02——所以回到刚才同学的讨论,执行到do_page_fault时,已经是SVC模式,也就是内核态,但是异常发生的时候,可能是用户态,也可能是内核态。所以在do_page_fault时,数据结构structpt_regs保存了异常发生时的寄存器上下文。而不是do_page_fault当前寄存器的状态,比如CPSR。注意这里do_page_fault函数中的第三个参数regs,不要被regs这个名字给迷惑了,虽然她看起来不错,但是它并不表示寄存器在当前时间点的状态。structpt_regs数据结构定义如下。最后记得关注笨叔叔的奔跑吧!Linux社区!