diff --git a/Makefile b/Makefile index 62d6331..ef6f291 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,15 @@ GCC_PREF=riscv32-unknown-elf- CC=$(GCC_PREF)gcc OBJDUMP=$(GCC_PREF)objdump -CFLAGS=-I$(KLIBDIR) -O3 -MD -mcmodel=medany -Wall -Wextra -pedantic-errors +CFLAGS=-I$(KLIBDIR) -MD -mcmodel=medany -Wall -Wextra -pedantic-errors KERNEL_CFLAGS=-nostdlib -T linker.ld ARCH = rv32im # here you ### Build configuration: +# comment out if you don't have any text IO device memory mapped +CFLAGS += -DTEXT_IO_ADDR=0xff0000 -DTEXT_IO_BUFLEN=64 + # uncomment these to build with only the rv32i standard #CFLAGS += -D__risc_no_ext=1 #ARCH = rv32i @@ -30,10 +33,10 @@ ARCH = rv32im # here you CFLAGS += -march=$(ARCH) # dependencies that need to be built: -_DEPS = ecall.c csr.c sched.c +_DEPS = ecall.c csr.c sched.c io.o # dependencies as object files: -_OBJ = ecall.o sched.o boot.o csr.o +_OBJ = ecall.o sched.o boot.o csr.o io.o DEPS = $(patsubst %,$(KLIBDIR)/%,$(_DEPS)) diff --git a/kernel.c b/kernel.c index f16c1bd..730ee17 100644 --- a/kernel.c +++ b/kernel.c @@ -1,6 +1,7 @@ #include "kernel.h" #include "ecall.h" #include "sched.h" +#include "io.h" void create_processes_from_bin_table(); @@ -8,10 +9,14 @@ extern ProcessControlBlock processes[PROCESS_COUNT]; loaded_binary binary_table[NUM_BINARIES] __attribute__ ((section (".data"))); +extern void memset(unsigned int, void*, void*); + extern void init() { init_ecall_table(); + dbgln("Kernel started!", 15); + create_processes_from_bin_table(); scheduler_run_next(); diff --git a/kernel.h b/kernel.h index 47b53e4..5cfa869 100644 --- a/kernel.h +++ b/kernel.h @@ -20,7 +20,7 @@ typedef struct loaded_binary { int binid; int entrypoint; - int bounds[2]; + void* bounds[2]; } loaded_binary; // create a global table holding all loaded binaries. diff --git a/kinclude/boot.S b/kinclude/boot.S index e9ada6d..6c1e495 100644 --- a/kinclude/boot.S +++ b/kinclude/boot.S @@ -106,18 +106,21 @@ trap_vector: jal trap_handle +// make memset global +.global memset +.type memset, @function #ifdef __risc_no_ext // "dumb" memset, if RV32M is not present on the target // since memset is currently only used at startup, the performance implications // should be minimal. memset: - bge a1, a2, 2f + bge a1, a2, 2f 1: - sw a0, 0(a1) - addi a1, a1, 4 - blt a1, a2, 1b + sw a0, 0(a1) + addi a1, a1, 4 + blt a1, a2, 1b 2: - ret + ret #else diff --git a/kinclude/ecall.c b/kinclude/ecall.c index 90d01ff..8af3db2 100644 --- a/kinclude/ecall.c +++ b/kinclude/ecall.c @@ -1,6 +1,7 @@ #include "ecall.h" #include "sched.h" #include "csr.h" +#include "io.h" typedef int (*ecall_handler)(int*,ProcessControlBlock*); @@ -44,6 +45,13 @@ int ecall_handle_exit(int* args, ProcessControlBlock* pcb) pcb->status = PROC_DEAD; pcb->exit_code = *args; + char msg[34] = "process exited with code "; + + itoa(pcb->pid, &msg[8], 10); + itoa(*args % 10, &msg[28], 10); + + dbgln(msg, 34); + return 0; } @@ -54,7 +62,7 @@ void trap_handle_ecall() { }; ProcessControlBlock* pcb = get_current_process(); int *regs = pcb->regs; - int code = regs[16]; + int code = regs[16]; // code is inside a7 // 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) { @@ -129,5 +137,6 @@ void init_ecall_table() void handle_exception(int ecode, int mtval) { - + dbgln("Trap encountered!", 17); + __asm__("ebreak"); } diff --git a/kinclude/ecall.h b/kinclude/ecall.h index e786c72..242302b 100644 --- a/kinclude/ecall.h +++ b/kinclude/ecall.h @@ -17,7 +17,7 @@ enum ecall_codes { #define ECALL_TABLE_LEN 16 -enum ecall_errors { +enum error_code { ENOCODE = -1, // invalid syscall code EINVAL = -2, // invalid argument value ENOMEM = -3, // not enough memory diff --git a/kinclude/io.c b/kinclude/io.c new file mode 100644 index 0000000..590afd2 --- /dev/null +++ b/kinclude/io.c @@ -0,0 +1,63 @@ +#include "io.h" + +#ifdef TEXT_IO_ADDR + +#ifndef TEXT_IO_BUFLEN +#error "When defining TEXT_IO_ADDR, please also provide TEXT_IO_BUFLEN, otherwise textIO won't work!" +#endif + +void dbgln(char* text, int len) +{ + while (len > TEXT_IO_BUFLEN) { + dbgln(text, TEXT_IO_BUFLEN); + text += TEXT_IO_BUFLEN; + len -= TEXT_IO_BUFLEN; + } + + char* ioaddr = (char*) TEXT_IO_ADDR + 4; + + for (int i = 0; i < len; i++) { + if (*text == 0) + break; + *ioaddr++ = *text++; + } + + if (len < TEXT_IO_BUFLEN) + *ioaddr = '\n'; + + // write a 1 to the start of the textIO to signal a buffer flush + *((char*) TEXT_IO_ADDR) = 1; +} + +#else + +/* if no textIO module loaded, dbgln is a noop :( */ +void dbgln(char*, int){} + +#endif + + +/* alphabet for itoa */ +char alpha[16] = "0123456789abcdef"; +char* itoa (int value, char* str, int base) +{ + if (base > 16 || base < 2) { + *str++ = '?'; + return str; + } + + if (value < 0) { + *str++ = '-'; + value *= -1; + } + + int num; + do { + num = value % base; + value = value / base; + *str++ = alpha[num]; + } + while (value > 0); + + return str; +} \ No newline at end of file diff --git a/kinclude/io.h b/kinclude/io.h new file mode 100644 index 0000000..1009f59 --- /dev/null +++ b/kinclude/io.h @@ -0,0 +1,10 @@ +#ifndef H_IO +#define H_IO + +/* print a line to the debug textIO module */ +void dbgln(char* text, int len); + +/* alphabet for itoa */ +char* itoa (int value, char* str, int base); + +#endif