QEMU裸机开发之S模式中断设置
1. 中断初始化
S模式下的中断初始化和M模式基本类似,只不过操作的是S模式下的CSR寄存器,如下所示。
static void supervisor_trap_init(void) { //this stack is used for supervisor_trap_entry in entry.S sscratch_set((unsigned long)(__stack_start + 4096 * 3)); // set the supervisor trap handler. stvec_set((unsigned long)supervisor_trap_entry); // enable supervisor interrupts. sstatus_set(sstatus_get() | SSTATUS_SIE); // enable supervisor timer and soft interrupts. sie_set(sie_get() | SIE_STIE | SIE_SSIE); } static void main(void) { printf("%s %d.\r\n", __func__, __LINE__); supervisor_trap_init(); while(1); }
唯一不同的是S模式的中断栈使用的是__stack_start往上第三个4KB的空间,其余的和m模式下都差不多,这里就不在赘述了。
2. 中断处理
2.1 中断入口
在“entry.S”中,我们需要实现s模式中断和异常处理的入口,如下所示。
# # supervisor trap entry. # .globl supervisor_trap_entry .align 4 supervisor_trap_entry: # sscratch holds smode trap stack address, # swap current sp and smode trap stack address csrrw sp, sscratch, sp // call the C trap handler in trap.c call supervisor_trap # restore old sp value csrrw sp, sscratch, sp sret
处理逻辑也和m模式下一样,就是设置好栈地址后,然后调用“supervisor_trap”C函数进行处理。
2.2 中断C函数处理
S模式的C处理函数和m模式同样基本类似,只不过将相关CSR寄存器换成S模式下的,如下所示。
void supervisor_trap(void) { unsigned long tval = stval_get(); unsigned long sepc = sepc_get(); unsigned long cause = scause_get(); int is_int = (cause & (1l << 63l)) ? 1 : 0; int scode = cause & 0xff; if (scode >= 16) { printf("%s : %s.\r\n", is_int ? "Interrupt" : "Exception", "Unknown code"); return; } if (is_int) { printf("Interrupt : %s.\r\n", interrupt_cause[scode]); switch (scode) { case S_SOFT_INT: break; case S_TIMER_INT: break; } } else { printf("Exception : %s.\r\n", exception_cause[scode]); switch (scode) { case ILLEGAL_INSTRUCTION: printf("tval = %p\r\n", tval); printf("sepc = %p\r\n", sepc); break; } sepc_set(sepc + 4); } return; }
这里只预留了空位,在后续章节会添加相关的处理代码。
3. 测试
由于需要触发中断才能测试中断处理是不是真的被执行了,所以本章节只是准备好这些设置和处理,在下一章节中,通过S模式软中断来一起验证和测试。
4. 工程源码
链接:https://pan.baidu.com/s/1TnTYr7mywdKj5bxpdmWnyA,提取码:q772,见lesson8。
评论