• 【RISC-V】Trap和Exception


    控制流 (Control Flow)和Trap

    • 控制流(Control Flow)
      • branch(条件分支指令), jump (无条件跳转指令),由程序正常自主控制的流程
    • 异常控制流 (Exceptional Control Flow,简称 ECP, 又称Trap)
      • 不在程序的控制范围之内
      • exception
      • interrupt

    RISC-V Trap处理中涉及的寄存器

    八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分:

    • mtvec(Machine Trap Vector)它保存发生异常时处理器需要跳转到的地址。
    • mepc(Machine Exception PC)它指向发生异常的指令。
    • mcause(Machine Exception Cause)它指示发生异常的种类。
    • mie(Machine Interrupt Enable)它指出处理器目前能处理和必须忽略的中断。
    • mip(Machine Interrupt Pending)它列出目前正准备处理的中断。
    • mtval(Machine Trap Value)它保存了陷入(trap)的附加信息:地址例外中出错
    • 的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。
    • mscratch(Machine Scratch)它暂时存放一个字大小的数据。
    • mstatus(Machine Status)它保存全局中断使能,以及许多其他的状态,如图

    mtvec (Machine Trap-Vector Base-Address)

    请添加图片描述

    • BASE: trap入口函数的及地址,必须保证四字节对其
    • MODE: 进一步用于控制入口函数的地址配置方式
      • Direct: 所有的exception和interrupt发生后pc都跳转到BASE指定的地址处。其实就是一个中断处理函数。
      • Vectored: exception处理方式同Direct;但interrupt的入口地址以数组方式排列。其实就是多向量指向不同的中断处理函数。

    请添加图片描述
    请添加图片描述

    mepc (Machine Exception Program Counter)

    请添加图片描述

    • 当trap发生时,pc会被替换为mtvec设定的地址,同时hart会设置mepc为当前指令或者下一条指令的地址(如果是异常则设置当前指令,如果是中断则设置下一条指令的地址),当我们需要退出trap时可以调用特殊的mret指令,该指令会将mepc中的值恢复到pc中(实现返回的效果)。
    • 在处理trap的程序中我们可以修改mepc的值达到改变mret返回地址的目的。

    mcause (Machine Cause)

    请添加图片描述

    • 当trap发生时,hart会设置该寄存器通知我们trap发生的原因。
    • 最高位Interrupt为1时标识了当前trap为interrupt,否则是exception。通过此标识能快速分辨发生了中断还是异常。
    • 剩余的Exception Code用于标识具体的interrupt或者exception的种类。
    • WLRL(Write/Read Only Legal Values)

    mstatus (Machine Status)

    • MIE: 分别用于打开(1)或者关闭(0) M/S/U模式下的全局中断。当trap发生时,hart会自动将MIE设置为0。
    • MPIE: 当trap发生时用于保存trap发生之前的MIE值。
    • MPP: 当trap发生时用于保存trap发生之前的权限级别值。M/S/U三种模式用两个bit表示。

    中断与异常含义

    请添加图片描述

    RISC-V Trap处理流程

    Trap初始化(设置入口地址等)-> Trap的Top Half(硬件处理过程)-> Trap的Bottom Half(软件逻辑部分)-> 从Trap返回
    请添加图片描述
    请添加图片描述

    Top Half(Trap发生时,Hart自动执行流)

    • 先把 mstatus 的MIE值复制到MPIE中,清除 mstatus 中的MIE标志位,效果是中断被禁止。(这就是硬件上不支持中断嵌套,但可以手动将中断再次打开实现中断嵌套)
    • 设置 mepc,同时PC被设置为 mtvec。(需要注意的是,对于 exception, mepc 指向导致异常的指令;对于 interrupt,它指向被中断的指令的下一条指令。)
    • 根据 trap 的种类设置 mcausem,并根据需要为 mtval 设置附加信息。
    • 将 trap发生之前的权限模式保存在 mstatus 的 MPP 域中,再把 hart 权限模式更改为M(也就是说无论在任何 Level 下触发 trap, hart首先切换到 Machine 模式)

    Bottom Half(软件需要做的事情)

    • 保存(save) 当前控制流的上下文信息,是指保存x1~x31寄存器的值。(利用 mscratch)
    • 调用C语言的trap handler
    • 中断C程序执行完毕之后从trap handler函数返回,mepc的值可能需要调整。
    • 恢复 (restore)上下文的信息。
    • 执行 MRET指令返回到trap之前的状态。

    退出 trap:编程调用 MRET 指令

    请添加图片描述

    • 针对不同权限级别下有各自退出trap的返回指令xRET (x=M/S/U)
    • 以在M模式下指令mret指令为例,会执行开中断(mstatus.MIE = mstatus.MPIE; mstatus.MPIE = 1),然后返回进入trap之前的指令,如果是中断的话返回进入trap之前的下一条指令。(pc = mepc)

    请添加图片描述

    portASM.S
    /*-----------------------------------------------------------*/
    
    .section .text.freertos_risc_v_trap_handler
    .align 8
    freertos_risc_v_trap_handler:
        portcontextSAVE_CONTEXT_INTERNAL
    
        csrr a0, mcause
        csrr a1, mepc
    
        bge a0, x0, synchronous_exception
    
    asynchronous_interrupt:
        store_x a1, 0( sp )                 /* Asynchronous interrupt so save unmodified exception return address. */
        load_x sp, xISRStackTop             /* Switch to ISR stack. */
        j handle_interrupt
    
    synchronous_exception:
        addi a1, a1, 4                      /* Synchronous so update exception return address to the instruction after the instruction that generated the exeption. */
        store_x a1, 0( sp )                 /* Save updated exception return address. */
        load_x sp, xISRStackTop             /* Switch to ISR stack. */
        j handle_exception
    
    handle_interrupt:
    #if( portasmHAS_MTIME != 0 )
    
        test_if_mtimer:                     /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */
            addi t0, x0, 1
            slli t0, t0, __riscv_xlen - 1   /* LSB is already set, shift into MSB.  Shift 31 on 32-bit or 63 on 64-bit cores. */
            addi t1, t0, 7                  /* 0x8000[]0007 == machine timer interrupt. */
            bne a0, t1, application_interrupt_handler
    
            portUPDATE_MTIMER_COMPARE_REGISTER
            call xTaskIncrementTick
            beqz a0, processed_source       /* Don't switch context if incrementing tick didn't unblock a task. */
            call vTaskSwitchContext
            j processed_source
    
    #endif /* portasmHAS_MTIME */
    
    application_interrupt_handler:
        call freertos_risc_v_application_interrupt_handler
        j processed_source
    
    handle_exception:
        /* a0 contains mcause. */
        li t0, 11                                   /* 11 == environment call. */
        bne a0, t0, application_exception_handler   /* Not an M environment call, so some other exception. */
        call vTaskSwitchContext
        j processed_source
    
    application_exception_handler:
        call freertos_risc_v_application_exception_handler
        j processed_source                  /* No other exceptions handled yet. */
    
    processed_source:
        portcontextRESTORE_CONTEXT
    /*-----------------------------------------------------------*/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
  • 相关阅读:
    「行泊一体」市场有多大?2025年前装搭载率将超40%
    数据校验JSR303入门实践
    rrweb入门
    service 自我升级遇到的问题
    【数学】主成分分析(PCA)的详细深度推导过程
    day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)
    CSS实现空心的“尖角”
    不能乱动的依赖包glibc,openssl,libcom_err
    Web前后端漏洞分析与防御
    【UNR #6 B】机器人表演(DP)
  • 原文地址:https://blog.csdn.net/qq_43189737/article/details/126008009