diff --git a/apps/crt0.S b/apps/crt0.S index 01afb70..027215c 100644 --- a/apps/crt0.S +++ b/apps/crt0.S @@ -1,19 +1,24 @@ #include "uvm32_sys.h" + +.equ uvm32_syscall_halt, 0x1000000 +.equ uvm32_syscall_yield, 0x1000001 +.equ uvm32_syscall_stackprotect, 0x1000002 + .section .initial_jump , "ax", %progbits .global _start .align 4 _start: + +la a0, _estack +li a7, uvm32_syscall_stackprotect +ecall + # sp is already setup by vm sw ra,12(sp) jal ra, main -#if 1 -// rust will interpret the "#if 1" and "#include" as comments and ignore -// C, asm, zig will include the file below, which references a constant from uvm32_sys.h -#include "non-rust-crt0-hack.S" -#else -// only rust will see this -li a7, {UVM32_SYSCALL_HALT} -#endif + +li a7, uvm32_syscall_halt ecall + .section .data diff --git a/apps/linker.ld b/apps/linker.ld index 57d28b8..f591b15 100644 --- a/apps/linker.ld +++ b/apps/linker.ld @@ -78,8 +78,9 @@ SECTIONS _sstack = .; } */ -/* _sstack = .;*/ - + .stack : ALIGN( 16 ) { + _estack = .; + } } diff --git a/apps/maze/maze.c b/apps/maze/maze.c index 20b5d61..3a811a4 100644 --- a/apps/maze/maze.c +++ b/apps/maze/maze.c @@ -78,6 +78,7 @@ void print_maze() { } } + void main(void) { init_maze(); carve(1, 1); diff --git a/apps/non-rust-crt0-hack.S b/apps/non-rust-crt0-hack.S deleted file mode 100644 index cb3e9ae..0000000 --- a/apps/non-rust-crt0-hack.S +++ /dev/null @@ -1 +0,0 @@ -li a7,UVM32_SYSCALL_HALT diff --git a/apps/rust-hello/src/main.rs b/apps/rust-hello/src/main.rs index 493c9db..7b02068 100644 --- a/apps/rust-hello/src/main.rs +++ b/apps/rust-hello/src/main.rs @@ -9,7 +9,7 @@ use core::panic::PanicInfo; include!(concat!(env!("OUT_DIR"), "/bindings.rs")); // startup code -global_asm!(include_str!("../../crt0.S"), UVM32_SYSCALL_HALT = const UVM32_SYSCALL_HALT); +global_asm!(include_str!("../../crt0.S")); fn syscall(id: u32, param1: u32, param2: u32) -> u32 { let mut value; diff --git a/common/uvm32_sys.h b/common/uvm32_sys.h index 82dec7d..7228d57 100644 --- a/common/uvm32_sys.h +++ b/common/uvm32_sys.h @@ -1,5 +1,6 @@ // System provided UVM32_SYSCALLs, start at 0x10000000 -#define UVM32_SYSCALL_HALT 0x1000000 -#define UVM32_SYSCALL_YIELD 0x1000001 +#define UVM32_SYSCALL_HALT 0x1000000 +#define UVM32_SYSCALL_YIELD 0x1000001 +#define UVM32_SYSCALL_STACKPROTECT 0x1000002 #include "uvm32_common_custom.h" diff --git a/common/uvm32_target.h b/common/uvm32_target.h index ecd6345..4439804 100644 --- a/common/uvm32_target.h +++ b/common/uvm32_target.h @@ -59,5 +59,11 @@ static uint32_t syscall(uint32_t id, uint32_t param1, uint32_t param2) { #define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0, 0) #define printbuf(x, y) syscall_cast(UVM32_SYSCALL_PRINTBUF, x, y) +extern char _estack; + +static void stackprotect(void) { + syscall_cast(UVM32_SYSCALL_STACKPROTECT, &_estack, 0); +} + #include "uvm32_common_custom.h" diff --git a/host/Makefile b/host/Makefile index 8772ac9..628832e 100644 --- a/host/Makefile +++ b/host/Makefile @@ -1,5 +1,5 @@ all: - gcc -Wall -pedantic -std=c99 -O2 -DUVM32_MEMORY_SIZE=65535 -I../uvm32 -I../common -o host ../uvm32/uvm32.c host.c + gcc -Wall -Werror -pedantic -std=c99 -O2 -DUVM32_MEMORY_SIZE=65535 -I../uvm32 -I../common -o host ../uvm32/uvm32.c host.c clean: rm -f host diff --git a/host/host.c b/host/host.c index 2912057..2762881 100644 --- a/host/host.c +++ b/host/host.c @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) { printf("%c", uvm32_getval(&vmst, &evt, ARG0)); break; case UVM32_SYSCALL_PRINTHEX: - printf("%d", uvm32_getval(&vmst, &evt, ARG0)); + printf("%08x", uvm32_getval(&vmst, &evt, ARG0)); break; case UVM32_SYSCALL_MILLIS: { clock_t now = clock() / (CLOCKS_PER_SEC / 1000); diff --git a/precompiled/conio.bin b/precompiled/conio.bin index 9408e45..19eef29 100755 Binary files a/precompiled/conio.bin and b/precompiled/conio.bin differ diff --git a/precompiled/fib.bin b/precompiled/fib.bin index a92bdfd..9d95c6d 100755 Binary files a/precompiled/fib.bin and b/precompiled/fib.bin differ diff --git a/precompiled/helloworld.bin b/precompiled/helloworld.bin index 9fb626f..114d6e1 100755 Binary files a/precompiled/helloworld.bin and b/precompiled/helloworld.bin differ diff --git a/precompiled/lissajous.bin b/precompiled/lissajous.bin index 8d2e570..bf74fc0 100755 Binary files a/precompiled/lissajous.bin and b/precompiled/lissajous.bin differ diff --git a/precompiled/mandel.bin b/precompiled/mandel.bin index ea0fd73..f8d0ffd 100755 Binary files a/precompiled/mandel.bin and b/precompiled/mandel.bin differ diff --git a/precompiled/maze.bin b/precompiled/maze.bin index d292845..ef8446f 100755 Binary files a/precompiled/maze.bin and b/precompiled/maze.bin differ diff --git a/precompiled/rust-hello.bin b/precompiled/rust-hello.bin index 36a3e90..8828769 100755 Binary files a/precompiled/rust-hello.bin and b/precompiled/rust-hello.bin differ diff --git a/precompiled/self.bin b/precompiled/self.bin index cfb0bc0..15a686a 100755 Binary files a/precompiled/self.bin and b/precompiled/self.bin differ diff --git a/precompiled/sketch.bin b/precompiled/sketch.bin index b950f6f..df58077 100755 Binary files a/precompiled/sketch.bin and b/precompiled/sketch.bin differ diff --git a/precompiled/zigtris.bin b/precompiled/zigtris.bin index a648f95..385901b 100755 Binary files a/precompiled/zigtris.bin and b/precompiled/zigtris.bin differ diff --git a/uvm32/uvm32.c b/uvm32/uvm32.c index eee6fc8..6215f09 100644 --- a/uvm32/uvm32.c +++ b/uvm32/uvm32.c @@ -10,6 +10,9 @@ // On an invalid operation, an error is set in uvm32_state_t, but a valid pointer still needs to be temporarily used static uint32_t garbage; +// magic value for stack canary +#define STACK_CANARY_VALUE 0x42 + #ifndef UVM32_MEMCPY #define UVM32_MEMCPY uvm32_memcpy void uvm32_memcpy(void *dst, const void *src, int len) { @@ -84,6 +87,8 @@ bool uvm32_load(uvm32_state_t *vmst, const uint8_t *rom, int len) { } UVM32_MEMCPY(vmst->memory, rom, len); + vmst->stack_canary = (uint8_t *)UVM32_NULL; + return true; } @@ -135,6 +140,12 @@ void uvm32_clearError(uvm32_state_t *vmst) { uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) { uint32_t num_instr = 0; + if (vmst->stack_canary != UVM32_NULL && *vmst->stack_canary != STACK_CANARY_VALUE) { + setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW); + setup_err_evt(vmst, evt); + return num_instr; + } + if (vmst->status != UVM32_STATUS_PAUSED) { setStatusErr(vmst, UVM32_ERR_NOTREADY); setup_err_evt(vmst, evt); @@ -163,6 +174,25 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) vmst->ioevt.typ = UVM32_EVT_YIELD; setStatus(vmst, UVM32_STATUS_PAUSED); break; + case UVM32_SYSCALL_STACKPROTECT: { + // don't allow errant code to change it once set + if (vmst->stack_canary == (uint8_t *)UVM32_NULL) { + uint32_t param0 = vmst->core.regs[10]; + uint32_t mem_offset = param0 - MINIRV32_RAM_IMAGE_OFFSET; + + // check data fits in ram + if (mem_offset > UVM32_MEMORY_SIZE) { + setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW); + setup_err_evt(vmst, evt); + } + // check canary is inside valid memory + if (mem_offset < UVM32_MEMORY_SIZE) { + // set canary + vmst->stack_canary = &vmst->memory[mem_offset]; + *vmst->stack_canary = STACK_CANARY_VALUE; + } + } + } break; default: // user defined syscalls vmst->ioevt.typ = UVM32_EVT_SYSCALL; diff --git a/uvm32/uvm32.h b/uvm32/uvm32.h index a3eec88..588e761 100644 --- a/uvm32/uvm32.h +++ b/uvm32/uvm32.h @@ -15,6 +15,7 @@ X(UVM32_ERR_INTERNAL_CORE) \ X(UVM32_ERR_INTERNAL_STATE) \ X(UVM32_ERR_ARGS) \ + X(UVM32_ERR_STACKOVERFLOW) \ #define X(name) name, typedef enum { @@ -69,6 +70,7 @@ typedef struct { struct MiniRV32IMAState core; uint8_t memory[UVM32_MEMORY_SIZE]; uvm32_evt_t ioevt; // for building up in callbacks + uint8_t *stack_canary; } uvm32_state_t; void uvm32_init(uvm32_state_t *vmst);