arm64--异常处理与中断处理

一、异常等级

EL0 非特权模式,用于运行应用程序

EL1为特权模式,用于运行操作系统内核

EL2用于运行虚拟化管理程序

EL3用于运行安全世界的管理程序

二、同步异常与异步异常

1. 同步异常:处理器执行某条指令而直接导致的异常,往往需要在异常函数里处理该异常之后,处理器才能继续运行,常见的同步异常如下:

  • 尝试访问异常等级不恰当的寄存器

  • 尝试执行关闭或没有定义的指令

  • 使用没有对齐的SP

  • 尝试执行与PC指针没有对齐的指令

  • 软件产生的异常,如执行SVC,HVC或SMC指令

  • 地址翻译或者权限等导致的数据异常

  • 地址翻译或者权限等导致的指令异常

  • 调试导致的异常,如断点异常,观察点异常,软件单步异常等

2. 异步异常:异常触发的原因与处理器当前正在执行的指令无关的异常,中断属于异步异常的一种,常见的异步异常包括物理中断和虚拟中断

  • 物理中断分为3种:分别是SError、IRQ、FIQ

  • 虚拟中断分为3种:分别是vSError、vIRQ、vFIQ

三、异常处理与返回

  1. 异常入口

处理器检测到异常后自动做的事

  • 把PSTATE寄存器的值保存到对应目标异常等级的SPSR_ELx中

  • 把返回等级保存到对应目标异常等级的ELR_RLx中

  • 把PSTATE寄存器中的D、A、I、F标志位都设置为1,相当于把调试异常,SError、IRQ、FIQ都关闭

  • 对于同步异常,要分析异常的原因,把具体的原因写入ESR_ELx中

  • 切换SP寄存器未目标等级的SP_ELx或者SP_EL0

  • 从异常发生现场的异常等级切换到对应目标异常等级,然后跳转到异常向量表中

操作系统做的事

  • 从中断向量表开始,根据异常发生的类型,跳转到合适的异常向量表。异常向量表的每个项都会保存一条跳转指令,然后跳转到恰当的异常处理函数并处理异常

2. 异常返回

当操作系统的异常处理完成后,执行一条ERET指令即可从异常返回,这条指令会自动处理如下工作

  • 从ELR_EL中恢复PC指针

  • 从SPSR_ELx中恢复PSTATE寄存器的状态

四、异常处理的路由 SCR_EL3

HCR_EL2

栈的选择 我们可以通过SPSel寄存器来配置SP。SPSel寄存器中的SP字段设置为0表示所有的EL中使用SP_EL0作为栈指针寄存器,设置为1表示使用SP_ELx作为栈指针寄存器 ARMV8异常向量表

ARMV8向量表有如下特点

  • 除EL0之后,每个EL都有自己的异常向量表

  • 异常向量表的基地址需要设置到VBAR_ELx中

  • 异常向量表的起始地址必须以2KB字节对齐

  • 每个表项可以存放32条指令,一共128字节

从EL2切换到EL1相关寄存器

 #define BAD_SYNC        0
#define BAD_IRQ         1
#define BAD_FIQ         2
#define BAD_ERROR       3
/*
   处理无效的异常向量
 */
    .macro inv_entry el, reason
    //kernel_entry el
    mov x0, sp
    mov x1, #\reason
    mrs x2, esr_el1
    b bad_mode
    .endm
/*
   vector table entry
   每个表项是128字节, align 7表示128字节对齐
 */
    .macro vtentry label
    .align 7
    b \label
    .endm
/*
 * Vector Table
 *
 * ARM64的异常向量表一共占用2048个字节
 * 分成4组,每组4个表项,每个表项占128字节
 * 参见ARMv8 spec v8.6第D1.10节
 * align 11表示2048字节对齐
 */
.align 11
.global vectors
vectors:
    /* Current EL with SP0
       当前系统运行在EL1时使用EL0的栈指针SP
       这是一种异常错误的类型
     */
    vtentry el1_sync_invalid
    vtentry el1_irq_invalid
    vtentry el1_fiq_invalid
    vtentry el1_error_invalid
    /* Current EL with SPx
       当前系统运行在EL1时使用EL1的栈指针SP
       这说明系统在内核态发生了异常
       Note: 我们暂时只实现IRQ中断
     */
    vtentry el1_sync_invalid
    vtentry el1_irq_invalid
    vtentry el1_fiq_invalid
    vtentry el1_error_invalid
    /* Lower EL using AArch64
       在用户态的aarch64的程序发生了异常
     */
    vtentry el0_sync_invalid
    vtentry el0_irq_invalid
    vtentry el0_fiq_invalid
    vtentry el0_error_invalid
    /* Lower EL using AArch32
       在用户态的aarch32的程序发生了异常
     */
    vtentry el0_sync_invalid
    vtentry el0_irq_invalid
    vtentry el0_fiq_invalid
    vtentry el0_error_invalid
el1_sync_invalid:
    inv_entry 1, BAD_SYNC
el1_irq_invalid:
    inv_entry 1, BAD_IRQ
el1_fiq_invalid:
    inv_entry 1, BAD_FIQ
el1_error_invalid:
    inv_entry 1, BAD_ERROR
el0_sync_invalid:
    inv_entry 0, BAD_SYNC
el0_irq_invalid:
    inv_entry 0, BAD_IRQ
el0_fiq_invalid:
    inv_entry 0, BAD_FIQ
el0_error_invalid:
    inv_entry 0, BAD_ERROR

五、中断处理

#define S_FRAME_SIZE 272 /* sizeof(struct pt_regs)  // */
#define S_X0 0 /* offsetof(struct pt_regs, regs[0]) // */
#define S_X1 8 /* offsetof(struct pt_regs, regs[1]) // */
#define S_X2 16 /* offsetof(struct pt_regs, regs[2])    // */
#define S_X3 24 /* offsetof(struct pt_regs, regs[3])    // */
#define S_X4 32 /* offsetof(struct pt_regs, regs[4])    // */
#define S_X5 40 /* offsetof(struct pt_regs, regs[5])    // */
#define S_X6 48 /* offsetof(struct pt_regs, regs[6])    // */
#define S_X7 56 /* offsetof(struct pt_regs, regs[7])    // */
#define S_X8 64 /* offsetof(struct pt_regs, regs[8])    // */
#define S_X10 80 /* offsetof(struct pt_regs, regs[10])  // */
#define S_X12 96 /* offsetof(struct pt_regs, regs[12])  // */
#define S_X14 112 /* offsetof(struct pt_regs, regs[14]) // */
#define S_X16 128 /* offsetof(struct pt_regs, regs[16]) // */
#define S_X18 144 /* offsetof(struct pt_regs, regs[18]) // */
#define S_X20 160 /* offsetof(struct pt_regs, regs[20]) // */
#define S_X22 176 /* offsetof(struct pt_regs, regs[22]) // */
#define S_X24 192 /* offsetof(struct pt_regs, regs[24]) // */
#define S_X26 208 /* offsetof(struct pt_regs, regs[26]) // */
#define S_X28 224 /* offsetof(struct pt_regs, regs[28]) // */
#define S_FP 232 /* offsetof(struct pt_regs, regs[29])  // */
#define S_LR 240 /* offsetof(struct pt_regs, regs[30])  // */
#define S_SP 248 /* offsetof(struct pt_regs, sp)    // */
#define S_PC 256 /* offsetof(struct pt_regs, pc)    // */
#define S_PSTATE 264 /* offsetof(struct pt_regs, pstate)    // */
#define BAD_SYNC        0
#define BAD_IRQ         1
#define BAD_FIQ         2
#define BAD_ERROR       3
    .macro kernel_entry
    sub sp, sp, #S_FRAME_SIZE
    /*
       保存通用寄存器x0~x29到栈框里pt_regs->x0~x29
     */
    stp x0, x1, [sp, #16 *0]
    stp x2, x3, [sp, #16 *1]
    stp x4, x5, [sp, #16 *2]
    stp x6, x7, [sp, #16 *3]
    stp x8, x9, [sp, #16 *4]
    stp x10, x11, [sp, #16 *5]
    stp x12, x13, [sp, #16 *6]
    stp x14, x15, [sp, #16 *7]
    stp x16, x17, [sp, #16 *8]
    stp x18, x19, [sp, #16 *9]
    stp x20, x21, [sp, #16 *10]
    stp x22, x23, [sp, #16 *11]
    stp x24, x25, [sp, #16 *12]
    stp x26, x27, [sp, #16 *13]
    stp x28, x29, [sp, #16 *14]
    /* x21: 栈顶 的位置*/
    add     x21, sp, #S_FRAME_SIZE
    mrs     x22, elr_el1
    mrs     x23, spsr_el1
    /* 把lr保存到pt_regs->lr, 把sp保存到pt_regs->sp位置*/
    stp     lr, x21, [sp, #S_LR]
    /* 把elr_el1保存到pt_regs->pc中
       把spsr_elr保存到pt_regs->pstate中*/
    stp     x22, x23, [sp, #S_PC]
    .endm
    .macro kernel_exit
    /* 从pt_regs->pc中恢复elr_el1,
       从pt_regs->pstate中恢复spsr_el1
       */
    ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSR
    msr     elr_el1, x21                    // set up the return data
    msr     spsr_el1, x22
    ldp     x0, x1, [sp, #16 * 0]
    ldp     x2, x3, [sp, #16 * 1]
    ldp     x4, x5, [sp, #16 * 2]
    ldp     x6, x7, [sp, #16 * 3]
    ldp     x8, x9, [sp, #16 * 4]
    ldp     x10, x11, [sp, #16 * 5]
    ldp     x12, x13, [sp, #16 * 6]
    ldp     x14, x15, [sp, #16 * 7]
    ldp     x16, x17, [sp, #16 * 8]
    ldp     x18, x19, [sp, #16 * 9]
    ldp     x20, x21, [sp, #16 * 10]
    ldp     x22, x23, [sp, #16 * 11]
    ldp     x24, x25, [sp, #16 * 12]
    ldp     x26, x27, [sp, #16 * 13]
    ldp     x28, x29, [sp, #16 * 14]

    /* 从pt_regs->lr中恢复lr*/
    ldr     lr, [sp, #S_LR]
    add     sp, sp, #S_FRAME_SIZE           // restore sp
    eret
    .endm
/*
   处理无效的异常向量
 */
    .macro inv_entry el, reason
    //kernel_entry el
    mov x0, sp
    mov x1, #\reason
    mrs x2, esr_el1
    b bad_mode
    .endm
/*
   vector table entry
   每个表项是128字节, align 7表示128字节对齐
 */
    .macro vtentry label
    .align 7
    b \label
    .endm
/*
 * Vector Table
 *
 * ARM64的异常向量表一共占用2048个字节
 * 分成4组,每组4个表项,每个表项占128字节
 * 参见ARMv8 spec v8.6第D1.10节
 * align 11表示2048字节对齐
 */
.align 11
.global vectors
vectors:
    /* Current EL with SP0
       当前系统运行在EL1时使用EL0的栈指针SP
       这是一种异常错误的类型
     */
    vtentry el1_sync_invalid
    vtentry el1_irq_invalid
    vtentry el1_fiq_invalid
    vtentry el1_error_invalid
    /* Current EL with SPx
       当前系统运行在EL1时使用EL1的栈指针SP
       这说明系统在内核态发生了异常
       Note: 我们暂时只实现IRQ中断
     */
    vtentry el1_sync_invalid
    vtentry el1_irq
    vtentry el1_fiq_invalid
    vtentry el1_error_invalid
    /* Lower EL using AArch64
       在用户态的aarch64的程序发生了异常
     */
    vtentry el0_sync_invalid
    vtentry el0_irq_invalid
    vtentry el0_fiq_invalid
    vtentry el0_error_invalid
    /* Lower EL using AArch32
       在用户态的aarch32的程序发生了异常
     */
    vtentry el0_sync_invalid
    vtentry el0_irq_invalid
    vtentry el0_fiq_invalid
    vtentry el0_error_invalid
el1_sync_invalid:
    //inv_entry 1, BAD_SYNC
    kernel_entry
    mov x0, sp
    mov x1, 0
    mrs x2, esr_el1
    bl bad_mode
    kernel_exit
el1_irq_invalid:
    inv_entry 1, BAD_IRQ
el1_fiq_invalid:
    inv_entry 1, BAD_FIQ
el1_error_invalid:
    inv_entry 1, BAD_ERROR
el0_sync_invalid:
    inv_entry 0, BAD_SYNC
el0_irq_invalid:
    inv_entry 0, BAD_IRQ
el0_fiq_invalid:
    inv_entry 0, BAD_FIQ
el0_error_invalid:
    inv_entry 0, BAD_ERROR
el1_irq:
    kernel_entry
    bl irq_handle
    kernel_exit
//string_test:
//  .string "t"
.global trigger_alignment
trigger_alignment:
    ldr x0, =0x80002
    str wzr, [x0]
    ret

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值