Skip to content

Commit 508d41c

Browse files
Remove stackoverflow error, have one CORE_INTERNAL error for catastrophic crash
1 parent 59f5d64 commit 508d41c

File tree

10 files changed

+164
-58
lines changed

10 files changed

+164
-58
lines changed

apps/makefile.common

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PREFIX:=riscv64-elf-
2+
OPT ?= -Os
23
CFLAGS+=-I${TOPDIR}/common
34
CFLAGS+=-fno-stack-protector
45
CFLAGS+=-static-libgcc -fdata-sections -ffunction-sections
5-
CFLAGS+=-g -Os -march=rv32im -mabi=ilp32 -static
6+
CFLAGS+=-g ${OPT} -march=rv32im -mabi=ilp32 -static
67
LDFLAGS:= -T ${TOPDIR}/apps/linker.ld -nostdlib -Wl,--gc-sections
78
LIBS:= -lgcc # needed for softfp
89

@@ -21,8 +22,8 @@ else
2122
endif
2223

2324
all_common:
24-
${PREFIX}gcc -o ${PROJECT}.elf ${CFLAGS} ${LDFLAGS} ${SRCS} ${LIBS}
25-
$(PREFIX)objcopy ${PROJECT}.elf -O binary ${PROJECT}.bin
25+
@${PREFIX}gcc -o ${PROJECT}.elf ${CFLAGS} ${LDFLAGS} ${SRCS} ${LIBS}
26+
@$(PREFIX)objcopy ${PROJECT}.elf -O binary ${PROJECT}.bin
2627

2728
disasm_common: all
2829
$(PREFIX)objdump -S -d -f ${PROJECT}.elf

test/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
all:
2-
make -C example_1
2+
@make -C example_1
3+
@make -C stackoverflow
34

45
clean:
56
make -C example_1 clean
7+
make -C stackoverflow clean
8+

test/example_1/Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ INC_DIRS=-I$(UNITY_ROOT)/src -I../../uvm32/ -I../../common -Irom
1717
.PHONY: rom
1818

1919
default: $(SRC_FILES1) rom
20-
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) rom/rom-header.c -o $(TARGET1)
21-
- ./$(TARGET1)
20+
@$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) rom/rom-header.c -o $(TARGET1)
21+
@- ./$(TARGET1)
2222

2323
rom:
24-
(cd rom && make)
24+
@(cd rom && make)
2525

2626
test/test_runners/${SUITE_NAME}_Runner.c: test/${SUITE_NAME}.c
27-
mkdir -p test/test_runners
28-
ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c
27+
@mkdir -p test/test_runners
28+
@ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c
2929

3030
clean:
3131
rm -rf $(TARGET1) test/test_runners

test/example_1/rom/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ TOPDIR=../../../
22
PROJECT:=$(shell basename ${PWD})
33
SRCS=${PROJECT}.c ${TOPDIR}/apps/crt0.S
44
all: all_common
5-
# Convert ROM to C file and header
6-
xxd -i ${PROJECT}.bin > ${PROJECT}-header.c
7-
echo "extern unsigned char ${PROJECT}_bin[]; extern int ${PROJECT}_bin_len;" > ${PROJECT}-header.h
5+
@# Convert ROM to C file and header
6+
@xxd -i ${PROJECT}.bin > ${PROJECT}-header.c
7+
@echo "extern unsigned char ${PROJECT}_bin[]; extern int ${PROJECT}_bin_len;" > ${PROJECT}-header.h
88

99
test: test_common
1010
clean: clean_common

test/stackoverflow/Makefile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
C_COMPILER=gcc
2+
3+
UNITY_ROOT=../unity
4+
5+
CFLAGS=-std=c99
6+
CFLAGS += -Wall
7+
CFLAGS += -Werror
8+
CFLAGS += -DUVM32_MEMORY_SIZE=512
9+
10+
SUITE_NAME=tests
11+
12+
TARGET_BASE1=test1
13+
TARGET1 = $(TARGET_BASE1)
14+
SRC_FILES1=$(UNITY_ROOT)/src/unity.c test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c ../../uvm32/uvm32.c
15+
INC_DIRS=-I$(UNITY_ROOT)/src -I../../uvm32/ -I../../common -Irom
16+
17+
.PHONY: rom
18+
19+
default: $(SRC_FILES1) rom
20+
@$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) rom/rom-header.c -o $(TARGET1)
21+
@- ./$(TARGET1)
22+
23+
rom:
24+
@(cd rom && make)
25+
26+
test/test_runners/${SUITE_NAME}_Runner.c: test/${SUITE_NAME}.c
27+
@mkdir -p test/test_runners
28+
@ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c
29+
30+
clean:
31+
rm -rf $(TARGET1) test/test_runners
32+
(cd rom && make clean)
33+

test/stackoverflow/rom/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
TOPDIR=../../../
2+
PROJECT:=$(shell basename ${PWD})
3+
SRCS=${PROJECT}.c ${TOPDIR}/apps/crt0.S
4+
OPT=-O0 # don't optimise
5+
all: all_common
6+
@# Convert ROM to C file and header
7+
@xxd -i ${PROJECT}.bin > ${PROJECT}-header.c
8+
@echo "extern unsigned char ${PROJECT}_bin[]; extern int ${PROJECT}_bin_len;" > ${PROJECT}-header.h
9+
10+
test: test_common
11+
clean: clean_common
12+
rm -f ${PROJECT}-header.h ${PROJECT}-header.c
13+
14+
include ${TOPDIR}/apps/makefile.common

test/stackoverflow/rom/rom.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include "uvm32_target.h"
2+
3+
int foo(int a) {
4+
yield(0);
5+
printdec(a);
6+
return foo(a+1);
7+
}
8+
9+
void main(void) {
10+
foo(1);
11+
}
12+

test/stackoverflow/test/tests.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <string.h>
2+
#include "unity.h"
3+
#include "uvm32.h"
4+
#include "../common/uvm32_common_custom.h"
5+
6+
#include "rom-header.h"
7+
8+
static uvm32_state_t vmst;
9+
static uvm32_evt_t evt;
10+
11+
void setUp(void) {
12+
// runs before each test
13+
uvm32_init(&vmst);
14+
uvm32_load(&vmst, rom_bin, rom_bin_len);
15+
}
16+
17+
void tearDown(void) {
18+
}
19+
20+
void test_stackoverflow(void) {
21+
// run the vm
22+
while(1) {
23+
uvm32_run(&vmst, &evt, 100);
24+
if (evt.typ == UVM32_EVT_SYSCALL) {
25+
// ignore syscalls
26+
} else {
27+
TEST_ASSERT_EQUAL(UVM32_EVT_ERR, evt.typ);
28+
TEST_ASSERT_EQUAL(UVM32_ERR_INTERNAL_CORE, evt.data.err.errcode);
29+
break;
30+
}
31+
}
32+
}
33+
34+

uvm32/uvm32.c

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
141141
uint32_t num_instr = 0;
142142

143143
if (vmst->stack_canary != UVM32_NULL && *vmst->stack_canary != STACK_CANARY_VALUE) {
144-
setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW);
144+
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
145145
setup_err_evt(vmst, evt);
146146
return num_instr;
147147
}
@@ -159,50 +159,58 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
159159
uint64_t elapsedUs = 1;
160160
uint32_t ret;
161161
ret = MiniRV32IMAStep(vmst, &vmst->core, vmst->memory, 0, elapsedUs, 1);
162-
if (3 == ret) {
163-
// Fetch registers used by syscall
164-
const uint32_t syscall = vmst->core.regs[17]; // a7
165-
// on exception we should jump to mtvec, but we handle directly
166-
// and skip over the ecall instruction
167-
vmst->core.pc += 4;
168-
switch(syscall) {
169-
// inbuilt syscalls
170-
case UVM32_SYSCALL_HALT:
171-
setStatus(vmst, UVM32_STATUS_ENDED);
172-
break;
173-
case UVM32_SYSCALL_STACKPROTECT: {
174-
// don't allow errant code to change it once set
175-
if (vmst->stack_canary == (uint8_t *)UVM32_NULL) {
176-
uint32_t param0 = vmst->core.regs[10]; // a0
177-
uint32_t mem_offset = param0 - MINIRV32_RAM_IMAGE_OFFSET;
178-
179-
// check data fits in ram
180-
if (mem_offset > UVM32_MEMORY_SIZE) {
181-
setStatusErr(vmst, UVM32_ERR_STACKOVERFLOW);
182-
setup_err_evt(vmst, evt);
183-
}
184-
// check canary is inside valid memory
185-
if (mem_offset < UVM32_MEMORY_SIZE) {
186-
// set canary
187-
vmst->stack_canary = &vmst->memory[mem_offset];
188-
*vmst->stack_canary = STACK_CANARY_VALUE;
162+
163+
switch(ret) {
164+
case 0: // ok
165+
break;
166+
case 12: { // ecall
167+
// Fetch registers used by syscall
168+
const uint32_t syscall = vmst->core.regs[17]; // a7
169+
// on exception we should jump to mtvec, but we handle directly
170+
// and skip over the ecall instruction
171+
vmst->core.pc += 4;
172+
switch(syscall) {
173+
// inbuilt syscalls
174+
case UVM32_SYSCALL_HALT:
175+
setStatus(vmst, UVM32_STATUS_ENDED);
176+
break;
177+
case UVM32_SYSCALL_STACKPROTECT: {
178+
// don't allow errant code to change it once set
179+
if (vmst->stack_canary == (uint8_t *)UVM32_NULL) {
180+
uint32_t param0 = vmst->core.regs[10]; // a0
181+
uint32_t mem_offset = param0 - MINIRV32_RAM_IMAGE_OFFSET;
182+
mem_offset &= ~0xF; // round up by 16 bytes
183+
mem_offset += 16*4;
184+
185+
// check data fits in ram
186+
if (mem_offset > UVM32_MEMORY_SIZE) {
187+
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
188+
setup_err_evt(vmst, evt);
189+
}
190+
// check canary is inside valid memory
191+
if (mem_offset < UVM32_MEMORY_SIZE) {
192+
// set canary
193+
vmst->stack_canary = &vmst->memory[mem_offset];
194+
*vmst->stack_canary = STACK_CANARY_VALUE;
195+
}
189196
}
190-
}
191-
} break;
192-
default:
193-
// user defined syscalls
194-
vmst->ioevt.typ = UVM32_EVT_SYSCALL;
195-
vmst->ioevt.data.syscall.code = syscall;
196-
vmst->ioevt.data.syscall.ret = &vmst->core.regs[12]; // a2
197-
vmst->ioevt.data.syscall.params[0] = &vmst->core.regs[10]; // a0
198-
vmst->ioevt.data.syscall.params[1] = &vmst->core.regs[11]; // a1
199-
setStatus(vmst, UVM32_STATUS_PAUSED);
200-
break;
201-
}
202-
} else if (ret != 0) {
203-
// unhandled exception
204-
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
205-
setup_err_evt(vmst, evt);
197+
} break;
198+
default:
199+
// user defined syscalls
200+
vmst->ioevt.typ = UVM32_EVT_SYSCALL;
201+
vmst->ioevt.data.syscall.code = syscall;
202+
vmst->ioevt.data.syscall.ret = &vmst->core.regs[12]; // a2
203+
vmst->ioevt.data.syscall.params[0] = &vmst->core.regs[10]; // a0
204+
vmst->ioevt.data.syscall.params[1] = &vmst->core.regs[11]; // a1
205+
setStatus(vmst, UVM32_STATUS_PAUSED);
206+
break;
207+
} // end switch(syscall)
208+
} break; // end ecall
209+
default:
210+
// unhandled exception
211+
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
212+
setup_err_evt(vmst, evt);
213+
break;
206214
}
207215

208216
num_instr++;
@@ -213,8 +221,10 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
213221
setup_err_evt(vmst, evt);
214222
return num_instr;
215223
}
224+
216225
}
217226

227+
218228
if (vmst->status == UVM32_STATUS_ENDED) {
219229
evt->typ = UVM32_EVT_END;
220230
return num_instr;

uvm32/uvm32.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
X(UVM32_ERR_INTERNAL_CORE) \
2121
X(UVM32_ERR_INTERNAL_STATE) \
2222
X(UVM32_ERR_ARGS) \
23-
X(UVM32_ERR_STACKOVERFLOW) \
2423

2524
#define X(name) name,
2625
typedef enum {
@@ -55,7 +54,7 @@ typedef struct {
5554

5655
#define MINIRV32_DECORATE static
5756
#define MINI_RV32_RAM_SIZE UVM32_MEMORY_SIZE
58-
#define MINIRV32_POSTEXEC(pc, ir, retval) {if (retval > 0) return 3;}
57+
#define MINIRV32_POSTEXEC(pc, ir, retval) {if (retval > 0) return retval;}
5958
#ifndef MINIRV32_IMPLEMENTATION
6059
#define MINIRV32_STEPPROTO
6160
#endif

0 commit comments

Comments
 (0)