23
#include "qemu/osdep.h"
24
#include "qapi/error.h"
26
#include "hw/char/riscv_htif.h"
27
#include "hw/char/serial.h"
28
#include "chardev/char.h"
29
#include "chardev/char-fe.h"
30
#include "qemu/timer.h"
31
#include "qemu/error-report.h"
32
#include "exec/address-spaces.h"
33
#include "exec/tswap.h"
34
#include "sysemu/dma.h"
35
#include "sysemu/runstate.h"
37
#define RISCV_DEBUG_HTIF 0
38
#define HTIF_DEBUG(fmt, ...) \
40
if (RISCV_DEBUG_HTIF) { \
41
qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
45
#define HTIF_DEV_SHIFT 56
46
#define HTIF_CMD_SHIFT 48
48
#define HTIF_DEV_SYSTEM 0
49
#define HTIF_DEV_CONSOLE 1
51
#define HTIF_SYSTEM_CMD_SYSCALL 0
52
#define HTIF_CONSOLE_CMD_GETC 0
53
#define HTIF_CONSOLE_CMD_PUTC 1
56
#define PK_SYS_WRITE 64
59
uint8_t line_size = 16;
61
static uint64_t fromhost_addr, tohost_addr, begin_sig_addr, end_sig_addr;
63
void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value,
66
if (strcmp("fromhost", st_name) == 0) {
67
fromhost_addr = st_value;
69
error_report("HTIF fromhost must be 8 bytes");
72
} else if (strcmp("tohost", st_name) == 0) {
73
tohost_addr = st_value;
75
error_report("HTIF tohost must be 8 bytes");
78
} else if (strcmp("begin_signature", st_name) == 0) {
79
begin_sig_addr = st_value;
80
} else if (strcmp("end_signature", st_name) == 0) {
81
end_sig_addr = st_value;
88
static int htif_can_recv(void *opaque)
97
static void htif_recv(void *opaque, const uint8_t *buf, int size)
99
HTIFState *s = opaque;
111
uint64_t val_written = s->pending_read;
112
uint64_t resp = 0x100 | *buf;
114
s->fromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
121
static void htif_event(void *opaque, QEMUChrEvent event)
126
static int htif_be_change(void *opaque)
128
HTIFState *s = opaque;
130
qemu_chr_fe_set_handlers(&s->chr, htif_can_recv, htif_recv, htif_event,
131
htif_be_change, s, NULL, true);
156
static void htif_handle_tohost_write(HTIFState *s, uint64_t val_written)
158
uint8_t device = val_written >> HTIF_DEV_SHIFT;
159
uint8_t cmd = val_written >> HTIF_CMD_SHIFT;
160
uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
163
HTIF_DEBUG("mtohost write: device: %d cmd: %d what: %02" PRIx64
164
" -payload: %016" PRIx64 "\n", device, cmd, payload & 0xFF, payload);
171
if (unlikely(device == HTIF_DEV_SYSTEM)) {
173
if (cmd == HTIF_SYSTEM_CMD_SYSCALL) {
176
int exit_code = payload >> 1;
182
if (sig_file && begin_sig_addr && end_sig_addr) {
183
uint64_t sig_len = end_sig_addr - begin_sig_addr;
184
char *sig_data = g_malloc(sig_len);
185
dma_memory_read(&address_space_memory, begin_sig_addr,
186
sig_data, sig_len, MEMTXATTRS_UNSPECIFIED);
187
FILE *signature = fopen(sig_file, "w");
188
if (signature == NULL) {
189
error_report("Unable to open %s with error %s",
190
sig_file, strerror(errno));
194
for (int i = 0; i < sig_len; i += line_size) {
195
for (int j = line_size; j > 0; j--) {
196
if (i + j <= sig_len) {
197
fprintf(signature, "%02x",
198
sig_data[i + j - 1] & 0xff);
200
fprintf(signature, "%02x", 0);
203
fprintf(signature, "\n");
210
qemu_system_shutdown_request_with_code(
211
SHUTDOWN_CAUSE_GUEST_SHUTDOWN, exit_code);
215
cpu_physical_memory_read(payload, syscall, sizeof(syscall));
216
if (tswap64(syscall[0]) == PK_SYS_WRITE &&
217
tswap64(syscall[1]) == HTIF_DEV_CONSOLE &&
218
tswap64(syscall[3]) == HTIF_CONSOLE_CMD_PUTC) {
220
cpu_physical_memory_read(tswap64(syscall[2]), &ch, 1);
221
qemu_chr_fe_write(&s->chr, &ch, 1);
222
resp = 0x100 | (uint8_t)payload;
224
qemu_log_mask(LOG_UNIMP,
225
"pk syscall proxy not supported\n");
229
qemu_log("HTIF device %d: unknown command\n", device);
231
} else if (likely(device == HTIF_DEV_CONSOLE)) {
233
if (cmd == HTIF_CONSOLE_CMD_GETC) {
235
s->pending_read = val_written;
238
} else if (cmd == HTIF_CONSOLE_CMD_PUTC) {
239
uint8_t ch = (uint8_t)payload;
240
qemu_chr_fe_write(&s->chr, &ch, 1);
241
resp = 0x100 | (uint8_t)payload;
243
qemu_log("HTIF device %d: unknown command\n", device);
246
qemu_log("HTIF unknown device or command\n");
247
HTIF_DEBUG("device: %d cmd: %d what: %02" PRIx64
248
" payload: %016" PRIx64, device, cmd, payload & 0xFF, payload);
260
s->fromhost = (val_written >> 48 << 48) | (resp << 16 >> 16);
264
#define TOHOST_OFFSET1 (s->tohost_offset)
265
#define TOHOST_OFFSET2 (s->tohost_offset + 4)
266
#define FROMHOST_OFFSET1 (s->fromhost_offset)
267
#define FROMHOST_OFFSET2 (s->fromhost_offset + 4)
270
static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size)
272
HTIFState *s = opaque;
273
if (addr == TOHOST_OFFSET1) {
274
return s->tohost & 0xFFFFFFFF;
275
} else if (addr == TOHOST_OFFSET2) {
276
return (s->tohost >> 32) & 0xFFFFFFFF;
277
} else if (addr == FROMHOST_OFFSET1) {
278
return s->fromhost & 0xFFFFFFFF;
279
} else if (addr == FROMHOST_OFFSET2) {
280
return (s->fromhost >> 32) & 0xFFFFFFFF;
282
qemu_log("Invalid htif read: address %016" PRIx64 "\n",
289
static void htif_mm_write(void *opaque, hwaddr addr,
290
uint64_t value, unsigned size)
292
HTIFState *s = opaque;
293
if (addr == TOHOST_OFFSET1) {
294
if (s->tohost == 0x0) {
296
s->tohost = value & 0xFFFFFFFF;
300
} else if (addr == TOHOST_OFFSET2) {
301
if (s->allow_tohost) {
302
s->tohost |= value << 32;
303
htif_handle_tohost_write(s, s->tohost);
305
} else if (addr == FROMHOST_OFFSET1) {
306
s->fromhost_inprogress = 1;
307
s->fromhost = value & 0xFFFFFFFF;
308
} else if (addr == FROMHOST_OFFSET2) {
309
s->fromhost |= value << 32;
310
s->fromhost_inprogress = 0;
312
qemu_log("Invalid htif write: address %016" PRIx64 "\n",
317
static const MemoryRegionOps htif_mm_ops = {
318
.read = htif_mm_read,
319
.write = htif_mm_write,
322
HTIFState *htif_mm_init(MemoryRegion *address_space, Chardev *chr,
323
uint64_t nonelf_base, bool custom_base)
325
uint64_t base, size, tohost_offset, fromhost_offset;
328
fromhost_addr = nonelf_base;
329
tohost_addr = nonelf_base + 8;
331
if (!fromhost_addr || !tohost_addr) {
332
error_report("Invalid HTIF fromhost or tohost address");
337
base = MIN(tohost_addr, fromhost_addr);
338
size = MAX(tohost_addr + 8, fromhost_addr + 8) - base;
339
tohost_offset = tohost_addr - base;
340
fromhost_offset = fromhost_addr - base;
342
HTIFState *s = g_new0(HTIFState, 1);
343
s->tohost_offset = tohost_offset;
344
s->fromhost_offset = fromhost_offset;
347
s->fromhost_inprogress = 0;
348
qemu_chr_fe_init(&s->chr, chr, &error_abort);
349
qemu_chr_fe_set_handlers(&s->chr, htif_can_recv, htif_recv, htif_event,
350
htif_be_change, s, NULL, true);
352
memory_region_init_io(&s->mmio, NULL, &htif_mm_ops, s,
353
TYPE_HTIF_UART, size);
354
memory_region_add_subregion_overlap(address_space, base,