From 9d9e7542fc9dc3adda6ec249894740ed8158eaf6 Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Wed, 10 Dec 2025 22:29:33 +0000 Subject: [PATCH] Test parsing of syscall args, and responses to invalid behaviour --- test/syscall_args/Makefile | 33 +++++++ test/syscall_args/rom/Makefile | 13 +++ test/syscall_args/rom/rom.c | 68 +++++++++++++ test/syscall_args/shared.h | 16 +++ test/syscall_args/test/tests.c | 171 +++++++++++++++++++++++++++++++++ 5 files changed, 301 insertions(+) create mode 100644 test/syscall_args/Makefile create mode 100644 test/syscall_args/rom/Makefile create mode 100644 test/syscall_args/rom/rom.c create mode 100644 test/syscall_args/shared.h create mode 100644 test/syscall_args/test/tests.c diff --git a/test/syscall_args/Makefile b/test/syscall_args/Makefile new file mode 100644 index 0000000..6533b02 --- /dev/null +++ b/test/syscall_args/Makefile @@ -0,0 +1,33 @@ +C_COMPILER=gcc + +UNITY_ROOT=../unity + +CFLAGS=-std=c99 +CFLAGS += -Wall +CFLAGS += -Werror +CFLAGS += -DUVM32_MEMORY_SIZE=16384 + +SUITE_NAME=tests + +TARGET_BASE1=test1 +TARGET1 = $(TARGET_BASE1) +SRC_FILES1=$(UNITY_ROOT)/src/unity.c test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c ../../uvm32/uvm32.c +INC_DIRS=-I$(UNITY_ROOT)/src -I../../uvm32/ -I../../common -Irom + +.PHONY: rom + +default: $(SRC_FILES1) rom + @$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) rom/rom-header.c -o $(TARGET1) + @ ./$(TARGET1) + +rom: + @(cd rom && make) + +test/test_runners/${SUITE_NAME}_Runner.c: test/${SUITE_NAME}.c + @mkdir -p test/test_runners + @ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/${SUITE_NAME}.c test/test_runners/${SUITE_NAME}_Runner.c + +clean: + rm -rf $(TARGET1) test/test_runners + (cd rom && make clean) + diff --git a/test/syscall_args/rom/Makefile b/test/syscall_args/rom/Makefile new file mode 100644 index 0000000..4698f22 --- /dev/null +++ b/test/syscall_args/rom/Makefile @@ -0,0 +1,13 @@ +TOPDIR=../../../ +PROJECT:=$(shell basename ${PWD}) +SRCS=${PROJECT}.c ${TOPDIR}/apps/crt0.S +all: all_common + @# Convert ROM to C file and header + @xxd -i ${PROJECT}.bin > ${PROJECT}-header.c + @echo "extern unsigned char ${PROJECT}_bin[]; extern int ${PROJECT}_bin_len;" > ${PROJECT}-header.h + +test: test_common +clean: clean_common + rm -f ${PROJECT}-header.h ${PROJECT}-header.c + +include ${TOPDIR}/apps/makefile.common diff --git a/test/syscall_args/rom/rom.c b/test/syscall_args/rom/rom.c new file mode 100644 index 0000000..d82e5aa --- /dev/null +++ b/test/syscall_args/rom/rom.c @@ -0,0 +1,68 @@ +#include "uvm32_target.h" +#include "../shared.h" + +void syscall_a_test(void) { + // two strings + syscall((uint32_t)SYSCALL_A, (uint32_t)SYSCALL_A_DATA0, (uint32_t)SYSCALL_A_DATA1); +} + +void syscall_b_test(void) { + // two null values + syscall((uint32_t)SYSCALL_B, 0, 0); +} + +void syscall_c_test(void) { + // valid buffer + uint8_t buf[32]; + for (int i=0;i<32;i++) { + buf[i] = i; + } + syscall((uint32_t)SYSCALL_C, (uint32_t)buf, sizeof(buf)); +} + +void syscall_d_test(void) { + // invalid address + syscall((uint32_t)SYSCALL_D, 0xFF000000, 100); +} + +void syscall_ef_test(void) { + // ask for two values, then send them back + uint32_t a, b; + syscall((uint32_t)SYSCALL_E, (uint32_t)&a, (uint32_t)&b); + syscall((uint32_t)SYSCALL_F, a, b); +} + +void syscall_gh_test(void) { + // ask for a buffer, mutate it, send it back + uint8_t buf[32]; + syscall((uint32_t)SYSCALL_G, (uint32_t)buf, 32); + for (int i=0;i<32;i++) { + buf[i] *= 2; + } + syscall((uint32_t)SYSCALL_H, (uint32_t)buf, 32); +} + +void main(void) { + switch(syscall(SYSCALL_PICKTEST, 0, 0)) { + case SYSCALL_A: + syscall_a_test(); + break; + case SYSCALL_B: + syscall_b_test(); + break; + case SYSCALL_C: + syscall_c_test(); + break; + case SYSCALL_D: + syscall_d_test(); + break; + case SYSCALL_E: + syscall_ef_test(); + break; + case SYSCALL_G: + syscall_gh_test(); + break; + + } +} + diff --git a/test/syscall_args/shared.h b/test/syscall_args/shared.h new file mode 100644 index 0000000..758fc2c --- /dev/null +++ b/test/syscall_args/shared.h @@ -0,0 +1,16 @@ +#define SYSCALL_BASE 0x200 + + +#define SYSCALL_A_DATA0 "Hello\033" // non-printing char +#define SYSCALL_A_DATA1 "" // empty string + +#define SYSCALL_PICKTEST SYSCALL_BASE+0 +#define SYSCALL_A SYSCALL_BASE+1 +#define SYSCALL_B SYSCALL_BASE+2 +#define SYSCALL_C SYSCALL_BASE+3 +#define SYSCALL_D SYSCALL_BASE+4 +#define SYSCALL_E SYSCALL_BASE+5 +#define SYSCALL_F SYSCALL_BASE+6 +#define SYSCALL_G SYSCALL_BASE+7 +#define SYSCALL_H SYSCALL_BASE+8 + diff --git a/test/syscall_args/test/tests.c b/test/syscall_args/test/tests.c new file mode 100644 index 0000000..e97bfe4 --- /dev/null +++ b/test/syscall_args/test/tests.c @@ -0,0 +1,171 @@ +#include +#include "unity.h" +#include "uvm32.h" +#include "../common/uvm32_common_custom.h" + +#include "rom-header.h" +#include "../shared.h" + +static uvm32_state_t vmst; +static uvm32_evt_t evt; + +void setUp(void) { + // runs before each test + uvm32_init(&vmst); + uvm32_load(&vmst, rom_bin, rom_bin_len); +} + +void tearDown(void) { +} + +void test_syscall_args_two_strings(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_A); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_A); + TEST_ASSERT_EQUAL(0, strcmp(uvm32_getcstr(&vmst, &evt, ARG0), SYSCALL_A_DATA0)); + TEST_ASSERT_EQUAL(0, strcmp(uvm32_getcstr(&vmst, &evt, ARG1), SYSCALL_A_DATA1)); + // run vm to completion + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_END); +} + +void test_syscall_args_bad_string(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_B); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_B); + + // try to read C string from the first null ptr + const char *s0 = uvm32_getcstr(&vmst, &evt, ARG0); + TEST_ASSERT_EQUAL(0, strlen(s0)); // tried to read a null pointer, get back a zero length string (not a NULL we might read) + // attempt to run vm, should be stuck in err + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_ERR); + + // try to read C string from the second null ptr + const char *s1 = uvm32_getcstr(&vmst, &evt, ARG1); + TEST_ASSERT_EQUAL(0, strlen(s1)); // tried to read a null pointer, get back a zero length string (not a NULL we might read) + // attempt to run vm, should be stuck in err + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_ERR); +} + +void test_syscall_args_bufrd(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_C); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_C); + + // get buffer described by ptr=ARG0,len=ARG1 + uvm32_evt_syscall_buf_t buf = uvm32_getbuf(&vmst, &evt, ARG0, ARG1); + uint8_t expected[32]; + for (int i=0;i<32;i++) { + expected[i] = i; + } + TEST_ASSERT_EQUAL(32, buf.len); + TEST_ASSERT_EQUAL(0, memcmp(buf.ptr, expected, 32)); +} + +void test_syscall_args_bufrd_bad_addr(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_D); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_D); + + // get buffer described by ptr=ARG0,len=ARG1 + uvm32_evt_syscall_buf_t buf = uvm32_getbuf(&vmst, &evt, ARG0, ARG1); + TEST_ASSERT_EQUAL(0, buf.len); // it was invalid, should get a safe zero length buffer + // attempt to run vm, should be stuck in err + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_ERR); +} + +void test_syscall_args_bufrd_ptrs(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_E); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_E); + + // get uint32_t buffer described by ptr=ARG0 + uvm32_evt_syscall_buf_t buf0 = uvm32_getbuf_fixed(&vmst, &evt, ARG0, 4); + TEST_ASSERT_EQUAL(4, buf0.len); // check read ok + uint32_t rspa = 0xABCD1234; + memcpy(buf0.ptr, &rspa, 4); // send it back + + // get uint32_t buffer described by ptr=ARG1 + uvm32_evt_syscall_buf_t buf1 = uvm32_getbuf_fixed(&vmst, &evt, ARG1, 4); + TEST_ASSERT_EQUAL(4, buf1.len); // check read ok + uint32_t rspb = 0x9876DECF; + memcpy(buf1.ptr, &rspb, 4); // send it back + + // check the same values are sent back + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_F); + TEST_ASSERT_EQUAL(rspa, uvm32_getval(&vmst, &evt, ARG0)); + TEST_ASSERT_EQUAL(rspb, uvm32_getval(&vmst, &evt, ARG1)); +} + +void test_syscall_args_buf_pass(void) { + // run the vm + uvm32_run(&vmst, &evt, 1000); + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, SYSCALL_G); + + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_G); + + // get buffer described by ptr=ARG0,len=ARG1 + uvm32_evt_syscall_buf_t buf0 = uvm32_getbuf(&vmst, &evt, ARG0, ARG1); + TEST_ASSERT_EQUAL(32, buf0.len); + // fill with a pattern + for (int i=0;i<32;i++) { + buf0.ptr[i] = i; + } + // expect every element to be doubled then sent back + uvm32_run(&vmst, &evt, 1000); + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_H); + + // get buffer described by ptr=ARG0,len=ARG1 + uvm32_evt_syscall_buf_t buf1 = uvm32_getbuf(&vmst, &evt, ARG0, ARG1); + TEST_ASSERT_EQUAL(32, buf1.len); + for (int i=0;i<32;i++) { + TEST_ASSERT_EQUAL(i*2, buf1.ptr[i]); + } +} +