第二十九期-Linux内核的异常(1)

作者:罗宇哲,中国科学院软件研究所智能软件研究中心

上一章中我们介绍了与ARM64体系中的异常与中断。这一期我们将介绍Linux 4.19内核中的异常向量表。

一、Linux 4.19内核的异常向量表

上一期中我们提到,异常向量被保存在异常向量表中。在/openeuler/kernel/blob/kernel-4.19/arch/arm64/kernel/entry.S

文件中我们可以找到定义异常向量表的汇编代码:
第二十九期-Linux内核的异常(1)
以上异常向量表共16项并被分为四组,每组包含四项并对应不同的异常处理情形。这四组表项从上到下对应的四种情形分别是12

  • 异常级别EL1生成的异常,使用SP_EL0寄存器;内核不支持带有invalid后缀的异常处理,在entry.S文件中,我们可以找到,通过带有invalid后缀的异常向量可以调用inv_entry宏:
    第二十九期-Linux内核的异常(1)
    这段代码保存三个参数到X0、X1和X2寄存器,然后跳转到bad_mode函数。bad_mode函数在/openeuler/kernel/blob/kernel-4.19/arch/arm64/kernel/traps.c文件中可以找到:
    第二十九期-Linux内核的异常(1)
    该函数打印了异常发生的相关信息并调用local_daif_mask()函数设置调试掩码位D、系统错误掩码位A、中断掩码位I和快速中断掩码位F来禁止调试异常、系统错误异常、外部中断和快速中断。

  • 异常级别EL1生成的异常,使用当前异常级别的SP_ELx寄存器;

  • 64位应用程序在异常级别EL0生成的异常。例如64位用户态程序发生系统调用,处理器从异常级别EL0切换到异常级别EL1,并且使用aarch64执行状态处理异常;

  • 32位应用程序在异常级别EL0生成的异常。例如32位用户态程序发生系统调用,处理器从异常级别EL0切换到异常级别EL1,并且使用aarch32执行状态处理异常;

其中kernel_ventry的定义在同一个文件中可以找到:
第二十九期-Linux内核的异常(1)
该宏的输入是当前异常级别el、跳转入口地址label和寄存器宽度regsize;寄存器宽度用来标识执行状态,regsize = 64标识aarch64执行状态,regsize = 32标识aarch32执行状态。.align 7表示把下一条指令对齐到27byte。该宏的主要作用是跳转到label所对应的地址处。

二、结语

本期我们介绍了Linux 4.19内核的异常向量表,下一期我们将介绍Linux 4.19内核的异常处理。
第二十九期-Linux内核的异常(1)


  1. https://blog.****.net/rikeyone/article/details/79919019 ↩︎

  2. 《Linux内核深度解析》,余华兵著,2019 ↩︎