1、异常处理函数的注册
对RISC-V架构中断不熟悉,可参考博客:《RISC-V架构——中断处理和中断控制器介绍》;
2、异常处理函数分析
2.1、数调用关系
freertos_risc_v_trap_handler //异常处理函数入口
portcontextSAVE_CONTEXT_INTERNAL //保存任务切换上下文
asynchronous_interrupt //异步异常:时钟中断
handle_interrupt //异步异常:时钟中断
portUPDATE_MTIMER_COMPARE_REGISTER//更新产生时钟中断的时间
xTaskIncrementTick//决定是否切换任务
processed_source//中断返回,恢复中断现场
vTaskSwitchContext//切换上下文
processed_source//中断返回,恢复任务上下文
synchronous_exception //同步异常:ecall调用
handle_exception
vTaskSwitchContext//切换任务
processed_source//中断返回,恢恢复任务上下文
2.2、源码
.section .text.freertos_risc_v_trap_handler
.align 8
freertos_risc_v_trap_handler: //异常处理入口函数
portcontextSAVE_CONTEXT_INTERNAL //保存任务上下文
csrr a0, mcause //读取mcause寄存
csrr a1, mepc //读取发生异常时候的地址
//注意这里把mcause中读出来的数当做符号数,高位1表示负数
//异常异常时,mcause寄存器的高位是1(负数);同步异常,mcause寄存的高位是0
bge a0, x0, synchronous_exception
//异步异常:时钟中断
asynchronous_interrupt:
store_x a1, 0( sp ) //保存发生异常返回的地址
load_x sp, xISRStackTop //切换到中断特有的栈空间, xISRStackTop记录的栈顶
j handle_interrupt
//同步异常:ecall调用
synchronous_exception:
addi a1, a1, 4 //mepc的值+4,这里只处理ecall调用,所以默认+4。并不是所有的同步异常都要+4
store_x a1, 0( sp ) //保存发生异常返回的地址
load_x sp, xISRStackTop //切换到中断特有的栈空间, xISRStackTop记录的栈顶
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
//任务主动切换,调用ecall进入中断
handle_exception:
/* a0 contains mcause. */
li t0, 11 /* 11表示是M模式的系统调用 */
bne a0, t0, application_exception_handler /* 不是ecall调用,则执行application_exception_handler */
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 //中断返回,恢复任务上下文
FreeRTOSv202212.01\FreeRTOS\Source\portable\GCC\RISC-V\portASM.S