ch13-抢占式多任务

·  阅读 138

image-20210816094433585

image-20210816094717998

兼容协作式多任务——做一个task_yield主动放弃CPU.

image-20210816120143744

image-20210816120416528

image-20210815234405541

每个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时,就表示有一个软中断待处理,具体过程见下面的图:

image-20210816120853959

这样,其实本质上还是去执行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
复制代码
  • image-20210816114456835

    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是将内存的数据存到寄存器,所以这里是将通用寄存器的值写到内存中.

  • image-20210816114605538

    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
    };
    复制代码
  • image-20210816114627469

令参数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.

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改