关于linux:笨叔点滴1-为什么dopagefault函数里代码需要判断用户态还是内核态

44次阅读

共计 1860 个字符,预计需要花费 5 分钟才能阅读完成。

“各位小伙伴,我是小笨叔,从明天开始,笨叔尽量每天给大家分享一点点小东西,可能是笨笨的小点滴,就像小雨点一样,它会缓缓会合到大江大海!”

前两天有一个两个小伙伴探讨这么一个问题。

A : 在 do_page_fault 函数中有这样一段代码,这都是在内核中的代码了为什么还要判断是在内核态还是在用户态?解决异样时必定是在内核态吧?

if (!user_mode(regs))

    goto no_context;


B:内核常驻内存,不会缺页,相同,用户态内存有可能会产生缺页,进入内核的异样解决流程入口执行异样解决,没感觉有什么不妥,缺页不肯定是在内核态,这个假如错的。

A:既然这样的话,那么内核的代码永远不会产生缺页中断了。只能是用户过程产生缺页中断了。

A 同学持续说。

A:当产生异样时,arm 的状态就会发生变化,此时不会是用户态的。arm 不是有 7 种工作模式吗?

cpsr 寄存器的低四位都为 0 的话,阐明是用户模式,产生异样时有相应的异样模式,然而必定不会是用户模式,所以我感觉内核代码中

if (user_mode(regs))

这条语句永远不会成立,

define user_mode(regs) \

(((regs)->ARM_cpsr & 0xf) == 0)

从它的实现来看,就是判断最低 4 位是否为 0,显然在异样模式下,不可能为 0 的

下面是 A 同学和 B 同学的对话,你们感觉他们探讨的货色都对吗?

图片

01 对于异样

咱们了解的 CPU 不就是干两件事件嘛?一个是取指令,另外一个是把指令给执行了。就好比我家小朋友,她名字叫做小笨笨。我和她说,小笨笨,你去冰箱里帮爸爸拿一罐可乐。小朋友第一件事件,就是要听到我说的话,这个就是取指令,她听懂了之后,她可能有如下几个行为。

        1. 她去冰箱给我拿了一罐可乐给我

         2. 她走去冰箱那里,然而中途遇到妈妈,妈妈逗她玩了一会,她去厨房给我拿了一个苹果

         3. 耍赖,跑了


下面三种状况,就是 CPU 的三种状况,第一个是 CPU 失常执行了这条命令,第二种状况,正在执行这条指令的时候,中途遇到问题了,后果产生谬误了。第三条,几乎就是一条非法指令。

对于 ARM 处理器来说,反对 4 大类的异样。

  1. 中断(interrupt)。就是咱们平时了解的中断,次要由外设触发,是典型的异步异样。ARM 中次要包含两种类型的中断:IRQ(一般中断) 和 FIQ。2. 异样(aborts)可能是同步或异步异样。包含指令异样 (取指令时产生)、数据异样 (读写内存数据时产生),能够由 MMU 产生 (比方典型的缺页异样),也能够由内部存储系统产生 (通常是硬件问题)。3.  复位(reset)复位被视为一种非凡的异样。4. 异样指令。由异样触发指令触发的异样,比方 Supervisor Call (SVC)、Hypervisor Call (HVC)、Secure monitor Call (SMC),SWI 等


那么 ARM 处理器在产生异样之后,通常会有一个异样向量表来和软件进行交互,因为异样产生了,处理器本人解决不了,须要操作系统或者软件来参加。上面这张图就是 ARM 手册上的列出来的异样向量表。

这张图是比较简单的明了的 vector table。

通常异样产生之后,ARM 处理器会帮咱们做一些事件,这些事件是硬件帮忙咱们做的:

  1. 把下一条指令的地址(返回地址)保留到新处理器模式的 LR 寄存器
  2. 把 cpsr 保留到 spsr 中
  3. 设置适当的 cpsr(扭转处理器的 ARM 状态、扭转处理器进入相应的异样模式、(视状况)扭转中断禁止位禁止相应中断)
  1. 设置 PC 指向异样向量表中对应的中央

那么软件须要做些啥呢???

  1. 保留以后共用寄存器的值,(如 SVC 模式和 IRQ 模式共用 r0~r12 以及 r15 及 pc)到以后模式的栈内存。保障之前模式的值不被毁坏。

    1. 进入异样处理函数。解决异样。

      1. 中断返回,将之前保留到栈里的值读回,并 SPSR 的值赋值给 CPSR 实现被动切换到之前的模式

02

所以回到方才那个同学的探讨,当执行到 do_page_fault 时,这时候曾经是在 SVC 模式,也就是内核模式,然而产生异样的那个工夫点,有可能是在用户模式也可能是在内核模式,所以,在 do_page_fault 时,数据结构 struct pt_regs 保留的是 产生异样现场时候的寄存器上下文,而不是 do_page_fault 以后的寄存器的状态,比方 CPSR。

留神这里 do_page_fault 函数里的第三个参数 regs, 不要被 regs 的名字蛊惑了,尽管她长得难看,然而不是示意以后这个工夫点的 寄存器的状态哟。

struct pt_regs 数据结构定义如下。

最初记得关注笨叔的 奔跑吧 Linux 社区哟!

正文完
 0