diff --git a/kernel.c b/kernel.c index 99d2539..66e9863 100644 --- a/kernel.c +++ b/kernel.c @@ -2,20 +2,23 @@ #include "ecall.h" #include "sched.h" -void thread_1(); +void create_processes_from_bin_table(); extern ProcessControlBlock processes[PROCESS_COUNT]; loaded_binary binary_table[NUM_BINARIES]; -static int idx = 0; - extern void init() { - for (int i = 0; i < 100; i++) { - idx += binary_table[i].entrypoint + 4; - } + init_ecall_table(); + + create_processes_from_bin_table(); scheduler_run_next(); } +void create_processes_from_bin_table() +{ + +} + diff --git a/kinclude/boot.S b/kinclude/boot.S index 59d1d63..e9ada6d 100644 --- a/kinclude/boot.S +++ b/kinclude/boot.S @@ -88,6 +88,10 @@ trap_vector: mv a0, t6 // save struct address to already saved register csrrw t6, mscratch, t6 // load original t6 register from mscratch sw t6, 120(a0) // save original t6 register + // save mepc to pc field in pcb + csrr t6, mepc + sw t6, -4(a0) + // load mcause and mtval values in the correct registers for call to trap_handle function csrr a1, mcause srli a0, a1, 31 slli a1, a1, 1 diff --git a/kinclude/ecall.c b/kinclude/ecall.c index 348d565..0cd18d9 100644 --- a/kinclude/ecall.c +++ b/kinclude/ecall.c @@ -2,36 +2,71 @@ #include "sched.h" #include "csr.h" -void ecall_handle_spawn(void* entry, void* args) +typedef int (*ecall_handler)(int*,ProcessControlBlock*); + +ecall_handler ecall_table[ECALL_TABLE_LEN] = { 0 }; + +int ecall_handle_spawn_thread(int* args_ptr, ProcessControlBlock* pcb) { + void* entry = (void*) args_ptr[0]; + void* args = (void*) args_ptr[1]; + return EINVAL; +// void* entry, void* args } -void ecall_handle_sleep(int until) +int ecall_handle_sleep(int* args, ProcessControlBlock* pcb) { + int len = *args; + if (len < 0) { + return EINVAL; + } + pcb->asleep_until = read_time() + len; + pcb->status = PROC_WAIT_SLEEP; + + return 0; } -void ecall_handle_join(int pid, int timeout) +int ecall_handle_join(int* args, ProcessControlBlock* pcb) { - + return EINVAL; } -void ecall_handle_kill(int pid) +int ecall_handle_kill(int* args, ProcessControlBlock* pcb) { + return EINVAL; } -void ecall_handle_exit(int status) +int ecall_handle_exit(int* args, ProcessControlBlock* pcb) { + pcb->status = PROC_DEAD; + pcb->exit_code = *args; + return 0; } void trap_handle_ecall() { - int *regs = get_current_process_registers(); + ProcessControlBlock* pcb = get_current_process(); + int *regs = pcb->regs; int code = regs[16]; - __asm__("ebreak"); - HALT(18); + + // check if the code is too large/small or if the handler is zero + if (code < 0 || code > ECALL_TABLE_LEN || ecall_table[code] == 0) { + regs[9] = ENOCODE; + __asm__("ebreak"); + } else { + // get the corresponding ecall handler + ecall_handler handler = ecall_table[code]; + regs[9] = handler(®s[9], pcb); + } + + // increment pc of this process + pcb->pc += 4; + + // try to reschedule + scheduler_try_return_to(pcb); } void trap_handle(int interrupt_bit, int code, int mtval) @@ -58,3 +93,12 @@ void trap_handle(int interrupt_bit, int code, int mtval) HALT(1); __builtin_unreachable(); } + +void init_ecall_table() +{ + ecall_table[ECALL_SPAWN] = ecall_handle_spawn_thread; + ecall_table[ECALL_SLEEP] = ecall_handle_sleep; + ecall_table[ECALL_JOIN] = ecall_handle_join; + ecall_table[ECALL_KILL] = ecall_handle_kill; + ecall_table[ECALL_EXIT] = ecall_handle_exit; +} \ No newline at end of file diff --git a/kinclude/ecall.h b/kinclude/ecall.h index 32fdeef..fce68c2 100644 --- a/kinclude/ecall.h +++ b/kinclude/ecall.h @@ -1,6 +1,8 @@ #ifndef H_ECALL #define H_ECALL +#include "sched.h" + /* ecall codes are defined here * * @@ -13,12 +15,23 @@ enum ecall_codes { ECALL_EXIT = 5, }; +#define ECALL_TABLE_LEN 16 + +enum ecall_errors { + ENOCODE = -1, // invalid syscall code + EINVAL = -2, // invalid argument value + ENOMEM = -3, // not enough memory +}; + +// initializer for ecall lookup table +void init_ecall_table(); + // syscall handlers, are setup in the mtvec csr -void ecall_handle_spawn(void* entry, void* args); -void ecall_handle_sleep(int until); -void ecall_handle_join(int pid, int timeout); -void ecall_handle_kill(int pid); -void ecall_handle_exit(int status); +int ecall_handle_spawn(int*, ProcessControlBlock*); +int ecall_handle_sleep(int*, ProcessControlBlock*); +int ecall_handle_join(int*, ProcessControlBlock*); +int ecall_handle_kill(int*, ProcessControlBlock*); +int ecall_handle_exit(int*, ProcessControlBlock*); void __attribute__((__noreturn__)) trap_handle(int interrupt_bit, int code, int mtval); diff --git a/kinclude/sched.c b/kinclude/sched.c index a6f95a9..d864235 100644 --- a/kinclude/sched.c +++ b/kinclude/sched.c @@ -16,9 +16,22 @@ void scheduler_run_next () scheduler_switch_to(current_process_index); } +void scheduler_try_return_to(ProcessControlBlock* pcb) +{ + if (pcb->status != PROC_RDY) { + scheduler_run_next(); + } else { + current_process_index = scheduler_index_from_pid(pcb->pid); + //FIXME: this refreshes the processes time slice which we actually don't want! + unsigned long long int mtimecmp = read_time() + TIME_SLICE_LEN; + write_mtimecmp(mtimecmp); + scheduler_switch_to(current_process_index); + } +} + int scheduler_select_free() { - long long int mtime; + unsigned long long int mtime; int i; int timeout_available = false; // note if a timeout is available diff --git a/kinclude/sched.h b/kinclude/sched.h index e811e8b..a564fd4 100644 --- a/kinclude/sched.h +++ b/kinclude/sched.h @@ -16,6 +16,7 @@ struct ProcessControlBlock { int pid; int pc; int regs[31]; + int exit_code; // scheduling information enum process_status status; ProcessControlBlock *waiting_for_process; @@ -29,6 +30,7 @@ extern ProcessControlBlock processes[PROCESS_COUNT]; int scheduler_select_free(); int scheduler_create_process(int binid); void __attribute__((noreturn)) scheduler_run_next(); +void __attribute__((noreturn)) scheduler_try_return_to(ProcessControlBlock*); void __attribute__((noreturn)) scheduler_switch_to(int proc_index); int scheduler_index_from_pid(int pid); int* get_current_process_registers();