#include #include #include // static _Context* (*user_handler)(_Event, _Context*) = NULL; static _Context* (*custom_soft_handler)(_Event, _Context*) = NULL; static _Context* (*custom_timer_handler)(_Event, _Context*) = NULL; static _Context* (*custom_external_handler)(_Event, _Context*) = NULL; static _Context* (*custom_secall_handler)(_Event, _Context*) = NULL; void __am_get_cur_as(_Context *c); void __am_switch(_Context *c); #define INTR_BIT (1ul << (sizeof(uintptr_t) * 8 - 1)) _Context* (*interrupt_handler[INTERRUPT_CAUSE_SIZE])(_Event *ev, _Context *c); _Context* (*exception_handler[EXCEPTION_CAUSE_SIZE])(_Event *ev, _Context *c); /* * default handler for all possible irqs * just panic */ _Context* __am_irq_default_handler(_Event *ev, _Context *c) { printf("unregisted irq detected, scause=%d, sepc=%llx\n", c->scause, c->sepc); ev->event = _EVENT_ERROR; _halt(2); // should never reach here return c; } /* * default handler for Supervisor Software Interrupt * set event to IRQ_SOFT * may call custom soft handler if registered */ _Context* __am_irq_SSIP_handler(_Event *ev, _Context *c) { #if __riscv_xlen == 64 asm volatile ("csrwi sip, 0"); #endif // printf("inside irq SSIP handler\n"); ev->event = _EVENT_IRQ_SOFT; if (custom_soft_handler != NULL) { // printf("dive into custom soft handler"); custom_soft_handler(*ev, c); } // machine mode will clear stip asm volatile("csrs mie, 0"); // printf("SSIP handler finished\n"); return c; } /* * default handler for Supervisor Timer Interrupt * set event to IRQ_TIMER * may call custom timer handler if registered */ _Context* __am_irq_STIP_handler(_Event *ev, _Context *c) { #if __riscv_xlen == 64 asm volatile ("csrwi sip, 0"); #endif // printf("inside irq STIP handler\n"); ev->event = _EVENT_IRQ_TIMER; if (custom_timer_handler != NULL) { // printf("dive into custom timer handler"); custom_timer_handler(*ev, c); } // machine mode will clear stip asm volatile("csrs mie, 0"); // printf("STIP handler finished\n"); return c; } /* * default handler for Supervisor External Interrupt * set event to IEQ_IODEV * may call custom external handler if registered */ _Context* __am_irq_SEIP_handler(_Event *ev, _Context *c) { // WARNING: this has no effect since in S mode only SSIP can be cleared. // It's not deleted because we want to test sip write mask. asm volatile ("csrwi sip, 0"); ev->event = _EVENT_IRQ_IODEV; printf("inside irq SEIP handler\n"); if (custom_external_handler != NULL) custom_external_handler(*ev, c); return c; } /* * default handler for Supervisor Ecall Exception * set event to YIELD or SYSCALL according to a7 * may call custom secall handler if registered */ _Context* __am_irq_SECALL_handler(_Event *ev, _Context *c) { ev->event = (c->GPR1 == -1) ? _EVENT_YIELD : _EVENT_SYSCALL; c->sepc += 4; //if (ev->event == _EVENT_YIELD) // printf("SECALL: is YIELD\n"); // printf("Inside secall handler\n"); if (custom_secall_handler != NULL) { custom_secall_handler(*ev, c); } return c; } _Context* __am_irq_handle(_Context *c) { __am_get_cur_as(c); _Event ev = {0}; uintptr_t scause_code = c->scause & SCAUSE_MASK; // printf("am irq triggered %llx\n", c->scause); if (c->scause & INTR_BIT) { assert(scause_code < INTERRUPT_CAUSE_SIZE); // printf("is an interrupt\n"); interrupt_handler[scause_code](&ev, c); } else { assert(scause_code < EXCEPTION_CAUSE_SIZE); // printf("is an exception\n"); exception_handler[scause_code](&ev, c); } __am_switch(c); #if __riscv_xlen == 64 asm volatile("fence.i"); #endif return c; } extern void __am_asm_trap(void); /* * Supervisor soft interrupt custom handler register function * handler: the function to be registered */ void ssip_handler_reg(_Context*(*handler)(_Event, _Context*)) { custom_soft_handler = handler; } /* * Supervisor timer interrupt custom handler register function * handler: the function to be registered */ void stip_handler_reg(_Context*(*handler)(_Event, _Context*)) { custom_timer_handler = handler; } /* * Supervisor external interrupt custom handler register function * handler: the function to be registered */ void seip_handler_reg(_Context*(*handler)(_Event, _Context*)) { custom_external_handler = handler; } /* * Supervisor ecall exception custom handler register function * handler: the function to be registered */ void secall_handler_reg(_Context*(*handler)(_Event, _Context*)) { custom_secall_handler = handler; } /* * Generic interrupt/exception CUSTOM handler register function * code: scause code * handler: the function to be registered */ void custom_handler_reg(uintptr_t code, _Context*(*handler)(_Event, _Context*)) { switch (code) { #if __riscv_xlen == 64 case INTR_BIT | SCAUSE_SSIP: ssip_handler_reg(handler); break; #endif case INTR_BIT | SCAUSE_STIP: stip_handler_reg(handler); break; case INTR_BIT | SCAUSE_SEIP: seip_handler_reg(handler); break; case SCAUSE_SECALL: secall_handler_reg(handler); break; default: printf("Unrecognized code, custom handler reg ignored\n"); _halt(2); } } /* * Generic interrupt/exception handler register function * code: scause code * handler: the function to be registered */ void irq_handler_reg(uintptr_t code, _Context*(*handler)(_Event*, _Context*)) { uintptr_t offset = (code << 1) >> 1; if (INTR_BIT & code) { assert(offset < INTERRUPT_CAUSE_SIZE); interrupt_handler[offset] = handler; } else { assert(offset < EXCEPTION_CAUSE_SIZE); exception_handler[offset] = handler; } } int _cte_init(_Context *(*handler)(_Event ev, _Context *ctx)) { // initialize exception entry asm volatile("csrw stvec, %0" : : "r"(__am_asm_trap)); asm volatile("csrw sscratch, zero"); // cte init handler has no effect for now #if __riscv_xlen == 64 // printf("CTE64 inited\n"); extern void __am_init_cte64(); __am_init_cte64(); #endif for (int i = 0; i < INTERRUPT_CAUSE_SIZE; i++) { irq_handler_reg(INTR_BIT | i, __am_irq_default_handler); // interrupt_handler[i] = __am_irq_default_handler; } for (int i = 0; i < EXCEPTION_CAUSE_SIZE; i++) { exception_handler[i] = __am_irq_default_handler; } #if __riscv_xlen == 64 interrupt_handler[SCAUSE_SSIP] = __am_irq_SSIP_handler; #endif interrupt_handler[SCAUSE_STIP] = __am_irq_STIP_handler; interrupt_handler[SCAUSE_SEIP] = __am_irq_SEIP_handler; exception_handler[SCAUSE_SECALL] = __am_irq_SECALL_handler; return 0; } _Context *_kcontext(_Area kstack, void (*entry)(void *), void *arg) { _Context *c = (_Context*)kstack.end - 1; c->pdir = NULL; c->sepc = (uintptr_t)entry; c->GPR2 = (uintptr_t)arg; c->sstatus = MSTATUS_SPP(MODE_S) | MSTATUS_PIE(MODE_S); c->gpr[2] = 0; // sp slot, used as usp return c; } void _yield() { //printf("before ecall\n"); asm volatile("li a7, -1; ecall"); //printf("after ecall\n"); } int _intr_read() { return 0; } void _intr_write(int enable) { if (enable) asm volatile("csrs sstatus, 0x2"); else asm volatile("csrc sstatus, 0x2"); }