System mode: user mode and kernel mode

Switching system mode

  • ecall: Essentially, it is an exception that falls into a trap, so it automatically changes to Machine mode.

  • ecallEnvironment Call and BreakPoint
  • epcIt stores the address of the ECALL directive itself, which the exception handler needs to change to the address of the next directive before the last MRET is executed.

System call execution flow

Get hartID gethid -.

Gethid: li a7, SYS_gethid # a7 = system call number of this function ecall # execute ecall to execute retCopy the code

With ecall, we call 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
Copy the code

The main is to execute 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. */
			intid = 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;
}
Copy the code

The do_syscall function is actually executed:

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;
}
Copy the code

If SYS_gethid is used, the SYS_gethid function is executed:

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; }}Copy the code

Parameter passing to the system call

  • The system call number is placed in A7

System call encapsulation