diff options
-rw-r--r-- | machine/finisher.c | 58 | ||||
-rw-r--r-- | machine/finisher.h | 13 | ||||
-rw-r--r-- | machine/machine.mk.in | 2 | ||||
-rw-r--r-- | machine/minit.c | 4 | ||||
-rw-r--r-- | machine/mtrap.c | 7 | ||||
-rw-r--r-- | machine/mtrap.h | 4 |
6 files changed, 84 insertions, 4 deletions
diff --git a/machine/finisher.c b/machine/finisher.c new file mode 100644 index 0000000..d113096 --- /dev/null +++ b/machine/finisher.c @@ -0,0 +1,58 @@ +#include <string.h> +#include "finisher.h" +#include "fdt.h" + +volatile uint32_t* finisher; + +void finisher_exit(uint16_t code) +{ + if (!finisher) return; + if (code == 0) { + *finisher = FINISHER_PASS; + } else { + *finisher = code << 16 | FINISHER_FAIL; + } +} + +struct finisher_scan +{ + int compat; + uint64_t reg; +}; + +static void finisher_open(const struct fdt_scan_node *node, void *extra) +{ + struct finisher_scan *scan = (struct finisher_scan *)extra; + memset(scan, 0, sizeof(*scan)); +} + +static void finisher_prop(const struct fdt_scan_prop *prop, void *extra) +{ + struct finisher_scan *scan = (struct finisher_scan *)extra; + if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,test0")) { + scan->compat = 1; + } else if (!strcmp(prop->name, "reg")) { + fdt_get_address(prop->node->parent, prop->value, &scan->reg); + } +} + +static void finisher_done(const struct fdt_scan_node *node, void *extra) +{ + struct finisher_scan *scan = (struct finisher_scan *)extra; + if (!scan->compat || !scan->reg || finisher) return; + finisher = (uint32_t*)(uintptr_t)scan->reg; +} + +void query_finisher(uintptr_t fdt) +{ + struct fdt_cb cb; + struct finisher_scan scan; + + memset(&cb, 0, sizeof(cb)); + cb.open = finisher_open; + cb.prop = finisher_prop; + cb.done = finisher_done; + cb.extra = &scan; + + fdt_scan(fdt, &cb); +} diff --git a/machine/finisher.h b/machine/finisher.h new file mode 100644 index 0000000..60d10b4 --- /dev/null +++ b/machine/finisher.h @@ -0,0 +1,13 @@ +#ifndef _RISCV_FINISHER_H +#define _RISCV_FINISHER_H + +#include <stdint.h> + +#define FINISHER_REG_FINISH 0 +#define FINISHER_FAIL 0x3333 +#define FINISHER_PASS 0x5555 + +void finisher_exit(uint16_t code); +void query_finisher(uintptr_t fdt); + +#endif diff --git a/machine/machine.mk.in b/machine/machine.mk.in index 76e02d9..59d0eb4 100644 --- a/machine/machine.mk.in +++ b/machine/machine.mk.in @@ -13,6 +13,7 @@ machine_hdrs = \ mcall.h \ mtrap.h \ uart.h \ + finisher.h \ unprivileged_memory.h \ vm.h \ @@ -26,6 +27,7 @@ machine_c_srcs = \ fp_emulation.c \ fp_ldst.c \ uart.c \ + finisher.c \ misaligned_ldst.c \ machine_asm_srcs = \ diff --git a/machine/minit.c b/machine/minit.c index 0fb5f21..187bef7 100644 --- a/machine/minit.c +++ b/machine/minit.c @@ -4,6 +4,7 @@ #include "fp_emulation.h" #include "fdt.h" #include "uart.h" +#include "finisher.h" #include "platform_interface.h" #include <string.h> #include <limits.h> @@ -136,6 +137,9 @@ void init_first_hart(uintptr_t hartid, uintptr_t dtb) // Confirm console as early as possible query_uart(dtb); + // Find the power button early as well so die() works + query_finisher(dtb); + query_mem(dtb); query_harts(dtb); query_clint(dtb); diff --git a/machine/mtrap.c b/machine/mtrap.c index a72b373..e5faae3 100644 --- a/machine/mtrap.c +++ b/machine/mtrap.c @@ -5,6 +5,7 @@ #include "bits.h" #include "vm.h" #include "uart.h" +#include "finisher.h" #include "fdt.h" #include "unprivileged_memory.h" #include "platform_interface.h" @@ -27,8 +28,10 @@ static uintptr_t mcall_console_putchar(uint8_t ch) return 0; } -void poweroff() +void poweroff(uint16_t code) { + printm("Power off\n"); + finisher_exit(code); if (platform__use_htif()) { htif_poweroff(); } else { @@ -84,7 +87,7 @@ static uintptr_t mcall_clear_ipi() static uintptr_t mcall_shutdown() { - poweroff(); + poweroff(0); } static uintptr_t mcall_set_timer(uint64_t when) diff --git a/machine/mtrap.h b/machine/mtrap.h index a15b265..eafdb14 100644 --- a/machine/mtrap.h +++ b/machine/mtrap.h @@ -56,12 +56,12 @@ typedef struct { hls_t* hls_init(uintptr_t hart_id); void parse_config_string(); -void poweroff(void) __attribute((noreturn)); +void poweroff(uint16_t code) __attribute((noreturn)); void printm(const char* s, ...); void vprintm(const char *s, va_list args); void putstring(const char* s); #define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); }) -#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(); }) +#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); }) void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1) __attribute__((noreturn)); |