summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/deps/picotls/deps/cifra/src/arm/semihost.c
blob: cbe5aa2ead394b09a17654c8c9d78d99ed4bcc92 (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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "semihost.h"

#define OP_WRITE0 0x04
#define OP_EXIT 0x18
#define OP_EXIT_ARG_FAILURE 0x0
#define OP_EXIT_ARG_SUCCESS 0x20026

extern uint32_t semihost(uint32_t, volatile void *);

__attribute__((noreturn))
void quit_success(void)
{
  semihost(OP_EXIT, (void *) OP_EXIT_ARG_SUCCESS);
  while (1)
    ;
}

__attribute__((noreturn))
void quit_failure(void)
{
  semihost(OP_EXIT, (void *) OP_EXIT_ARG_FAILURE);
  while (1)
    ;
}

void emit(const char *buf)
{
  semihost(OP_WRITE0, (volatile void *) buf);
}

static void emit_extent(const char *start, const char *end)
{
  char buf[32+1];
  size_t bufmax = sizeof(buf) - 1;
  buf[32] = 0;

  size_t bytes = end - start + 1;

  while (bytes >= bufmax)
  {
    memcpy(buf, start, bufmax);
    emit(buf);
    bytes -= bufmax;
    start += bufmax;
  }
  
  if (bytes == 0)
    return;
  
  memcpy(buf, start, bytes);
  buf[bytes] = 0;
  emit(buf);
}

void emitf(const char *fmt, ...)
{
  const char *start = fmt, *end = fmt;

  va_list args;
  va_start(args, fmt);

  while (*fmt)
  {
    switch (*fmt)
    {
      case '%':
        emit_extent(start, end);

        switch (fmt[1])
        {
          case '%':
            emit("%");
            break;

          case 'u':
            emit_uint32(va_arg(args, uint32_t));
            break;

          case 's':
            emit(va_arg(args, const char *));
            break;
        }
        start = end = fmt + 2;
        break;

      default:
        end = fmt;
        break;
    }

    fmt++;
  }

  va_end(args);
  emit_extent(start, end);
}
  
static const char *hex_chars = "0123456789abcdef";
  
void emit_hex(const void *ptr, size_t len)
{
  const uint8_t *bb = ptr;
  char byte[3];

  byte[2] = 0;

  for (size_t i = 0; i < len; i++)
  {
    byte[0] = hex_chars[(bb[i] >> 4) & 0xf];
    byte[1] = hex_chars[bb[i] & 0xf];
    emit(byte);
  }
}

void emit_uint32(uint32_t x)
{
  char buf[sizeof "0x11223344"];
  buf[0] = '0';
  buf[1] = 'x';
  buf[2] = hex_chars[(x >> 28) & 0xf];
  buf[3] = hex_chars[(x >> 24) & 0xf];
  buf[4] = hex_chars[(x >> 20) & 0xf];
  buf[5] = hex_chars[(x >> 16) & 0xf];
  buf[6] = hex_chars[(x >> 12) & 0xf];
  buf[7] = hex_chars[(x >> 8) & 0xf];
  buf[8] = hex_chars[(x >> 4) & 0xf];
  buf[9] = hex_chars[x & 0xf];
  buf[10] = 0;

  emit(buf);
}

typedef struct
{
  volatile uint32_t ctrl;
  volatile uint32_t reload;
  volatile uint32_t current;
} systick;

#define SysTick ((systick *)0xe000e010)

#define STCTRL_SYSCLOCK 0x04
#define STCTRL_TICKINT  0x02
#define STCTRL_ENABLE   0x01

#define STCTRL_MAX 0xffffff
#define STCTRL_SHIFT 24

extern uint32_t get_ticks(void);
extern void reset_ticks(void);

uint32_t reset_cycles(void)
{
  SysTick->reload = STCTRL_MAX;
  SysTick->ctrl = STCTRL_SYSCLOCK | STCTRL_TICKINT | STCTRL_ENABLE;
  SysTick->current = 0;
  reset_ticks();
  return get_ticks();
}

uint32_t get_cycles(void)
{
  return (get_ticks() << STCTRL_SHIFT) + (STCTRL_MAX - SysTick->current);
}