aboutsummaryrefslogtreecommitdiff
path: root/machine/htif.c
blob: a513305141e1bdb220635efb94c90f69dce5dd1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include "htif.h"
#include "atomic.h"
#include "mtrap.h"

volatile uint64_t tohost __attribute__((aligned(64))) __attribute__((section("htif")));
volatile uint64_t fromhost __attribute__((aligned(64))) __attribute__((section("htif")));
volatile int htif_console_buf;
static spinlock_t htif_lock = SPINLOCK_INIT;

static void request_htif_keyboard_interrupt()
{
  assert(tohost == 0);
  tohost = TOHOST_CMD(1, 0, 0);
}

static void __check_fromhost()
{
  // we should only be interrupted by keypresses
  uint64_t fh = fromhost;
  if (!fh)
    return;
  if (!(FROMHOST_DEV(fh) == 1 && FROMHOST_CMD(fh) == 0))
    die("unexpected htif interrupt");
  htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
  fromhost = 0;
}

int htif_console_getchar()
{
  if (spinlock_trylock(&htif_lock) == 0) {
    __check_fromhost();
    spinlock_unlock(&htif_lock);
  }

  int ch = atomic_swap(&htif_console_buf, -1);
  if (ch >= 0)
    request_htif_keyboard_interrupt();
  return ch - 1;
}

static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
{
  spinlock_lock(&htif_lock);
    while (tohost)
      __check_fromhost();
    tohost = TOHOST_CMD(dev, cmd, data);

    while (1) {
      uint64_t fh = fromhost;
      if (fh) {
        if (FROMHOST_DEV(fh) == dev && FROMHOST_CMD(fh) == cmd) {
          fromhost = 0;
          break;
        }
        __check_fromhost();
      }
    }
  spinlock_unlock(&htif_lock);
}

uintptr_t htif_syscall(uintptr_t arg)
{
  do_tohost_fromhost(0, 0, arg);
  return 0;
}

void htif_console_putchar(uint8_t ch)
{
  do_tohost_fromhost(1, 1, ch);
}

void htif_poweroff()
{
  while (1) {
    fromhost = 0;
    tohost = 1;
  }
}