兼容协作式多任务——做一个task_yield主动放弃CPU.
每个hart的MSIP寄存器的最低位,实际上就是映射到mip寄存器的MISP位,表示是否发生软中断
void task_yield()
{
/* trigger a machine-level software interrupt */
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 1;
}
复制代码
我们写入给这个hart的MSIP写入1时,就表示有一个软中断待处理,具体过程见下面的图:
这样,其实本质上还是去执行switch_to.
trap_vector:
# save context(registers).
csrrw t6, mscratch, t6 # swap t6 and mscratch
reg_save t6
csrw mscratch, t6
# save mepc to context of current task
csrr a0, mepc
sw a0, 124(t6)
# call the C trap handler in trap.c
csrr a0, mepc
csrr a1, mcause
call trap_handler
# trap_handler will return the return address via a0.
csrw mepc, a0
# restore context(registers).
csrr t6, mscratch
reg_restore t6
# return to whatever we were doing before trap.
mret
复制代码
-
mscrach的值为context的地址,调用reg_save t6去将通用寄存器的值保存到这个context中。
.macro reg_save base
sw ra, 0(\base)
sw sp, 4(\base)
sw gp, 8(\base)
sw tp, 12(\base)
sw t0, 16(\base)
sw t1, 20(\base)
sw t2, 24(\base)
sw s0, 28(\base)
sw s1, 32(\base)
sw a0, 36(\base)
sw a1, 40(\base)
sw a2, 44(\base)
sw a3, 48(\base)
sw a4, 52(\base)
sw a5, 56(\base)
sw a6, 60(\base)
sw a7, 64(\base)
sw s2, 68(\base)
sw s3, 72(\base)
sw s4, 76(\base)
sw s5, 80(\base)
sw s6, 84(\base)
sw s7, 88(\base)
sw s8, 92(\base)
sw s9, 96(\base)
sw s10, 100(\base)
sw s11, 104(\base)
sw t3, 108(\base)
sw t4, 112(\base)
sw t5, 116(\base)
sw t6, 120(\base)
.endm
复制代码
store是将内存的数据存到寄存器,所以这里是将通用寄存器的值写到内存中.
-
将
mepc
的值存到context的pc中struct context { /* ignore x0 */ reg_t ra; ... 省略 ... reg_t t6; // upon is trap frame // save the pc to run in next schedule cycle reg_t pc; // offset: 31 *4 = 124 }; 复制代码
-
令参数1:a0=mepc , 参数2:a1=mcause,然后调用trap_handler
去处理中断和异常
reg_t trap_handler(reg_t epc, reg_t cause)
{
reg_t return_pc = epc; // 存放返回地址,这个函数返回这个pc
reg_t cause_code = cause & 0xfff; // 中断的原因
if (cause & 0x80000000) { //最高位为1,表示这是中断
/* Asynchronous trap - interrupt */
switch (cause_code) {
case 3: // 软件中断
uart_puts("software interruption!\n");
/*
* acknowledge the software interrupt by clearing
* the MSIP bit in mip.
*/
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 0;
schedule();
break;
case 7: // 定时器中断
uart_puts("timer interruption!\n");
timer_handler();
break;
case 11: //uart中断
uart_puts("external interruption!\n");
external_interrupt_handler();
break;
default: //其他中断
uart_puts("unknown async exception!\n");
break;
}
} else { //异常
/* Synchronous trap - exception */
printf("Sync exceptions!, code = %d\n", cause_code);
panic("OOPS! What can I do!");
//return_pc += 4;
}
return return_pc;
}
复制代码
如果是一个定时器中断,就是执行timer_handler
函数:
void timer_handler()
{
_tick++;
printf("tick: %d\n", _tick);
timer_load(TIMER_INTERVAL);
schedule();
}
复制代码
本质上还是去执行schedule.