系统模式:用户态和内核态
系统模式的切换
ecall:实质上是一种异常,陷入trap,所以会自动变成Machine模式.
ecall-Environment Call and BreakPointepc存放的是ECALL指令本身的地址,如果想要接着往下执行,那么异常处理程序最后mret前需要将其变成下一条指令的地址.
系统调用的执行流程
gethid——获取hartID.
gethid:
li a7, SYS_gethid # a7 = 这个函数的系统调用编号
ecall # 执行ecall去执行这个函数
ret
ecall的时候,执行trap_vector函数:
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
csrr a2, mscratch
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
主体是执行trap_handler:
reg_t trap_handler(reg_t epc, reg_t cause, struct context *cxt)
{
reg_t return_pc = epc;
reg_t cause_code = cause & 0xfff;
if (cause & 0x80000000) {
/* 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_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);
switch (cause_code) {
case 8:
uart_puts("System call from U-mode!\n");
do_syscall(cxt);
return_pc += 4;
break;
default:
panic("OOPS! What can I do!");
//return_pc += 4;
}
}
return return_pc;
}
实际上是执行do_syscall函数:
void do_syscall(struct context *cxt)
{
uint32_t syscall_num = cxt->a7;
switch (syscall_num) {
case SYS_gethid:
cxt->a0 = sys_gethid((unsigned int *)(cxt->a0));
break;
default:
printf("Unknown syscall no: %d\n", syscall_num);
cxt->a0 = -1;
}
return;
}
这里是一个根据系统调用编号分流,如果是SYS_gethid,就执行sys_gethid函数:
int sys_gethid(unsigned int *ptr_hid)
{
printf("--> sys_gethid, arg0 = 0x%x\n", ptr_hid);
if (ptr_hid == NULL) {
return -1;
} else {
*ptr_hid = r_mhartid();
return 0;
}
}
系统调用的传参
系统调用号放在a7