1// See LICENSE for license details. 2 3#include "htif.h" 4#include "atomic.h" 5#include "mtrap.h" 6#include "fdt.h" 7#include "syscall.h" 8#include <string.h> 9 10extern uint64_t __htif_base; 11volatile uint64_t tohost __attribute__((section(".htif"))); 12volatile uint64_t fromhost __attribute__((section(".htif"))); 13volatile int htif_console_buf; 14static spinlock_t htif_lock = SPINLOCK_INIT; 15uintptr_t htif; 16 17#define TOHOST(base_int) (uint64_t *)(base_int + TOHOST_OFFSET) 18#define FROMHOST(base_int) (uint64_t *)(base_int + FROMHOST_OFFSET) 19 20#define TOHOST_OFFSET ((uintptr_t)tohost - (uintptr_t)__htif_base) 21#define FROMHOST_OFFSET ((uintptr_t)fromhost - (uintptr_t)__htif_base) 22 23static void __check_fromhost() 24{ 25 uint64_t fh = fromhost; 26 if (!fh) 27 return; 28 fromhost = 0; 29 30 // this should be from the console 31 assert(FROMHOST_DEV(fh) == 1); 32 switch (FROMHOST_CMD(fh)) { 33 case 0: 34 htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh); 35 break; 36 case 1: 37 break; 38 default: 39 assert(0); 40 } 41} 42 43static void __set_tohost(uintptr_t dev, uintptr_t cmd, uintptr_t data) 44{ 45 while (tohost) 46 __check_fromhost(); 47 tohost = TOHOST_CMD(dev, cmd, data); 48} 49 50int htif_console_getchar() 51{ 52#if __riscv_xlen == 32 53 // HTIF devices are not supported on RV32 54 return -1; 55#endif 56 57 spinlock_lock(&htif_lock); 58 __check_fromhost(); 59 int ch = htif_console_buf; 60 if (ch >= 0) { 61 htif_console_buf = -1; 62 __set_tohost(1, 0, 0); 63 } 64 spinlock_unlock(&htif_lock); 65 66 return ch - 1; 67} 68 69static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data) 70{ 71 spinlock_lock(&htif_lock); 72 __set_tohost(dev, cmd, data); 73 74 while (1) { 75 uint64_t fh = fromhost; 76 if (fh) { 77 if (FROMHOST_DEV(fh) == dev && FROMHOST_CMD(fh) == cmd) { 78 fromhost = 0; 79 break; 80 } 81 __check_fromhost(); 82 } 83 } 84 spinlock_unlock(&htif_lock); 85} 86 87void htif_syscall(uintptr_t arg) 88{ 89 do_tohost_fromhost(0, 0, arg); 90} 91 92void htif_console_putchar(uint8_t ch) 93{ 94#if __riscv_xlen == 32 95 // HTIF devices are not supported on RV32, so proxy a write system call 96 volatile uint64_t magic_mem[8]; 97 magic_mem[0] = SYS_write; 98 magic_mem[1] = 1; 99 magic_mem[2] = (uintptr_t)&ch; 100 magic_mem[3] = 1; 101 do_tohost_fromhost(0, 0, (uintptr_t)magic_mem); 102#else 103 spinlock_lock(&htif_lock); 104 __set_tohost(1, 1, ch); 105 spinlock_unlock(&htif_lock); 106#endif 107} 108 109void htif_poweroff() 110{ 111 while (1) { 112 fromhost = 0; 113 tohost = 1; 114 } 115} 116 117struct htif_scan 118{ 119 int compat; 120}; 121 122static void htif_open(const struct fdt_scan_node *node, void *extra) 123{ 124 struct htif_scan *scan = (struct htif_scan *)extra; 125 memset(scan, 0, sizeof(*scan)); 126} 127 128static void htif_prop(const struct fdt_scan_prop *prop, void *extra) 129{ 130 struct htif_scan *scan = (struct htif_scan *)extra; 131 if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ucb,htif0")) { 132 scan->compat = 1; 133 } 134} 135 136static void htif_done(const struct fdt_scan_node *node, void *extra) 137{ 138 struct htif_scan *scan = (struct htif_scan *)extra; 139 if (!scan->compat) return; 140 141 htif = 1; 142} 143 144void query_htif(uintptr_t fdt) 145{ 146 struct fdt_cb cb; 147 struct htif_scan scan; 148 149 memset(&cb, 0, sizeof(cb)); 150 cb.open = htif_open; 151 cb.prop = htif_prop; 152 cb.done = htif_done; 153 cb.extra = &scan; 154 155 fdt_scan(fdt, &cb); 156} 157