/* * Utility functions for trap handling in Supervisor mode. */ #include "riscv.h" #include "process.h" #include "strap.h" #include "syscall.h" #include "pmm.h" #include "vmm.h" #include "sched.h" #include "util/functions.h" #include "spike_interface/spike_utils.h" // // handling the syscalls. will call do_syscall() defined in kernel/syscall.c // static void handle_syscall(trapframe *tf) { // tf->epc points to the address that our computer will jump to after the trap handling. // for a syscall, we should return to the NEXT instruction after its handling. // in RV64G, each instruction occupies exactly 32 bits (i.e., 4 Bytes) tf->epc += 4; // TODO (lab1_1): remove the panic call below, and call do_syscall (defined in // kernel/syscall.c) to conduct real operations of the kernel side for a syscall. // IMPORTANT: return value should be returned to user app, or else, you will encounter // problems in later experiments! panic( "call do_syscall to accomplish the syscall and lab1_1 here.\n" ); } // // global variable that store the recorded "ticks". added @lab1_3 static uint64 g_ticks = 0; // // added @lab1_3 // void handle_mtimer_trap() { sprint("Ticks %d\n", g_ticks); // TODO (lab1_3): increase g_ticks to record this "tick", and then clear the "SIP" // field in sip register. // hint: use write_csr to disable the SIP_SSIP bit in sip. panic( "lab1_3: increase g_ticks by one, and clear SIP field in sip register.\n" ); } // // the page fault handler. added @lab2_3. parameters: // sepc: the pc when fault happens; // stval: the virtual address that causes pagefault when being accessed. // void handle_user_page_fault(uint64 mcause, uint64 sepc, uint64 stval) { sprint("handle_page_fault: %lx\n", stval); switch (mcause) { case CAUSE_STORE_PAGE_FAULT: // TODO (lab2_3): implement the operations that solve the page fault to // dynamically increase application stack. // hint: first allocate a new physical page, and then, maps the new page to the // virtual address that causes the page fault. panic( "You need to implement the operations that actually handle the page fault in lab2_3.\n" ); break; default: sprint("unknown page fault.\n"); break; } } // // implements round-robin scheduling. added @lab3_3 // void rrsched() { // TODO (lab3_3): implements round-robin scheduling. // hint: increase the tick_count member of current process by one, if it is bigger than // TIME_SLICE_LEN (means it has consumed its time slice), change its status into READY, // place it in the rear of ready queue, and finally schedule next process to run. panic( "You need to further implement the timer handling in lab3_3.\n" ); } // // kernel/smode_trap.S will pass control to smode_trap_handler, when a trap happens // in S-mode. // void smode_trap_handler(void) { // make sure we are in User mode before entering the trap handling. // we will consider other previous case in lab1_3 (interrupt). if ((read_csr(sstatus) & SSTATUS_SPP) != 0) panic("usertrap: not from user mode"); assert(current); // save user process counter. current->trapframe->epc = read_csr(sepc); // if the cause of trap is syscall from user application. // read_csr() and CAUSE_USER_ECALL are macros defined in kernel/riscv.h uint64 cause = read_csr(scause); // use switch-case instead of if-else, as there are many cases since lab2_3. switch (cause) { case CAUSE_USER_ECALL: handle_syscall(current->trapframe); break; case CAUSE_MTIMER_S_TRAP: handle_mtimer_trap(); // invoke round-robin scheduler. added @lab3_3 rrsched(); break; case CAUSE_STORE_PAGE_FAULT: case CAUSE_LOAD_PAGE_FAULT: // the address of missing page is stored in stval // call handle_user_page_fault to process page faults handle_user_page_fault(cause, read_csr(sepc), read_csr(stval)); break; default: sprint("smode_trap_handler(): unexpected scause %p\n", read_csr(scause)); sprint(" sepc=%p stval=%p\n", read_csr(sepc), read_csr(stval)); panic( "unexpected exception happened.\n" ); break; } // continue (come back to) the execution of current process. switch_to(current); }