ch16-系统调用

285 阅读1分钟

系统模式:用户态和内核态

image-20210816161343518

image-20210816161428967

系统模式的切换

image-20210816162457301

  • ecall:实质上是一种异常,陷入trap,所以会自动变成Machine模式.

image-20210816162538346

  • ecall-Environment Call and BreakPoint
  • epc存放的是ECALL指令本身的地址,如果想要接着往下执行,那么异常处理程序最后mret前需要将其变成下一条指令的地址.

系统调用的执行流程

image-20210816162737119

image-20210816162913017

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;
	}
}

系统调用的传参

image-20210816163614447

  • 系统调用号放在a7

image-20210816164229082

系统调用的封装

image-20210816164446199