diff options
| author | Tim Newsome <tim@sifive.com> | 2020-05-26 12:37:09 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-26 12:37:09 -0700 |
| commit | fbe74f48e16be28a2b360e8a9e845b01d9e4b167 (patch) | |
| tree | 869b79d740a4c5f405f35eb0cab9275ea7da47e0 /debug/programs | |
| parent | bc4c1d2866b896f6234d19111993fae4a9f47d74 (diff) | |
| download | riscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.zip riscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.tar.gz riscv-tests-fbe74f48e16be28a2b360e8a9e845b01d9e4b167.tar.bz2 | |
Test semihosting calls (#280)
* Add a basic semihosting test.
* Need to configure semihosting on each target.
* WIP
* Parse "cannot insert breakpoint" message.
Also use sys.exit instead of exit, per new pylint's suggestion.
Diffstat (limited to 'debug/programs')
| -rw-r--r-- | debug/programs/semihosting.c | 73 | ||||
| -rw-r--r-- | debug/programs/semihosting.h | 82 |
2 files changed, 155 insertions, 0 deletions
diff --git a/debug/programs/semihosting.c b/debug/programs/semihosting.c new file mode 100644 index 0000000..2ceea8c --- /dev/null +++ b/debug/programs/semihosting.c @@ -0,0 +1,73 @@ +#include <stdint.h> + +#include "semihosting.h" + +size_t strlen(const char *buf) +{ + int len = 0; + while (buf[len]) + len++; + return len; +} + +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_RDWR 2 +#define O_TRUNC 0x0800 + +int errno; + +/* These semihosting functions came from the Freedom Metal source. */ +static int open(const char *name, int flags, int mode) { + int semiflags = 0; + + switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) { + case O_RDONLY: + semiflags = 0; /* 'r' */ + break; + case O_WRONLY: + if (flags & O_TRUNC) + semiflags = 4; /* 'w' */ + else + semiflags = 8; /* 'a' */ + break; + default: + if (flags & O_TRUNC) + semiflags = 6; /* 'w+' */ + else + semiflags = 10; /* 'a+' */ + break; + } + + volatile semihostparam_t arg = {.param1 = (uintptr_t)name, + .param2 = (uintptr_t)semiflags, + .param3 = (uintptr_t)strlen(name)}; + + int ret = (int)semihost_call_host(SEMIHOST_SYS_OPEN, (uintptr_t)&arg); + if (ret == -1) + errno = semihost_call_host(SEMIHOST_SYS_ERRNO, 0); + return ret; +} + +static ssize_t write(int file, const void *ptr, size_t len) +{ + volatile semihostparam_t arg = {.param1 = (uintptr_t)file, + .param2 = (uintptr_t)ptr, + .param3 = (uintptr_t)len}; + ssize_t ret = + (ssize_t)semihost_call_host(SEMIHOST_SYS_WRITE, (uintptr_t)&arg); + + return (len - ret); +} + +int main() +{ + char *filename = NULL; + const char *message = "Hello, world!\n"; + int fd; + +begin: + fd = open(filename, O_WRONLY, 0644); + write(fd, message, strlen(message)); +}
\ No newline at end of file diff --git a/debug/programs/semihosting.h b/debug/programs/semihosting.h new file mode 100644 index 0000000..201e414 --- /dev/null +++ b/debug/programs/semihosting.h @@ -0,0 +1,82 @@ +#include <sys/types.h> + +#ifndef _SEMIHOSTING_H_ +#define _SEMIHOSTING_H_ + +// ---------------------------------------------------------------------------- + +// Semihosting operations. +enum Semihost_Sys_Op { + // Regular operations + SEMIHOST_SYS_CLOCK = 0x10, + SEMIHOST_SYS_CLOSE = 0x02, + SEMIHOST_SYS_ELAPSED = 0x30, + SEMIHOST_SYS_ERRNO = 0x13, + SEMIHOST_SYS_EXIT = 0x18, + SEMIHOST_SYS_EXIT_EXTENDED = 0x20, + SEMIHOST_SYS_FLEN = 0x0C, + SEMIHOST_SYS_GET_CMDLINE = 0x15, + SEMIHOST_SYS_HEAPINFO = 0x16, + SEMIHOST_SYS_ISERROR = 0x08, + SEMIHOST_SYS_ISTTY = 0x09, + SEMIHOST_SYS_OPEN = 0x01, + SEMIHOST_SYS_READ = 0x06, + SEMIHOST_SYS_READC = 0x07, + SEMIHOST_SYS_REMOVE = 0x0E, + SEMIHOST_SYS_RENAME = 0x0F, + SEMIHOST_SYS_SEEK = 0x0A, + SEMIHOST_SYS_SYSTEM = 0x12, + SEMIHOST_SYS_TICKFREQ = 0x31, + SEMIHOST_SYS_TIME = 0x11, + SEMIHOST_SYS_TMPNAM = 0x0D, + SEMIHOST_SYS_WRITE = 0x05, + SEMIHOST_SYS_WRITEC = 0x03, + SEMIHOST_SYS_WRITE0 = 0x04, +}; + +enum ADP_Code { + ADP_Stopped_BranchThroughZero = 0x20000, + ADP_Stopped_UndefinedInstr = 0x20001, + ADP_Stopped_SoftwareInterrupt = 0x20002, + ADP_Stopped_PrefetchAbort = 0x20003, + ADP_Stopped_DataAbort = 0x20004, + ADP_Stopped_AddressException = 0x20005, + ADP_Stopped_IRQ = 0x20006, + ADP_Stopped_FIQ = 0x20007, + ADP_Stopped_BreakPoint = 0x20020, + ADP_Stopped_WatchPoint = 0x20021, + ADP_Stopped_StepComplete = 0x20022, + ADP_Stopped_RunTimeErrorUnknown = 0x20023, + ADP_Stopped_InternalError = 0x20024, + ADP_Stopped_UserInterruption = 0x20025, + ADP_Stopped_ApplicationExit = 0x20026, + ADP_Stopped_StackOverflow = 0x20027, + ADP_Stopped_DivisionByZero = 0x20028, + ADP_Stopped_OSSpecific = 0x20029, +}; + +typedef struct { + uintptr_t param1; + uintptr_t param2; + uintptr_t param3; +} semihostparam_t; + +static inline uintptr_t __attribute__((always_inline)) +semihost_call_host(uintptr_t op, uintptr_t arg) { + register uintptr_t r0 asm("a0") = op; + register uintptr_t r1 asm("a1") = arg; + + asm volatile(".option push \n" + ".option norvc \n" + " slli zero,zero,0x1f \n" + " ebreak \n" + " srai zero,zero,0x7 \n" + ".option pop \n" + + : "=r"(r0) /* Outputs */ + : "r"(r0), "r"(r1) /* Inputs */ + : "memory"); + return r0; +} + +#endif
\ No newline at end of file |
