AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/arch.h"
2#include "hv/config.h"
3#include "hv/log.h"
4#include "hv/string.h"
5#include "hv/timer.h"
6#include "hv/uart.h"
7
8struct log_ring {
9 struct log_event events[CONFIG_LOG_CAPACITY];
10 volatile unsigned lock;
11 uint64_t next_seq;
12 uint32_t write_index;
13 bool wrapped;
14};
15
16static struct log_ring g_log;
17static struct log_ring g_log_selftest_backup;
18
19static void lock_log(void)
20{
21 while (__atomic_test_and_set(&g_log.lock, __ATOMIC_ACQUIRE)) {
22 }
23}
24
25static void unlock_log(void)
26{
27 __atomic_clear(&g_log.lock, __ATOMIC_RELEASE);
28}
29
30void log_init(void)
31{
32 hv_memset(&g_log, 0, sizeof(g_log));
33}
34
35void log_event_commit(const struct log_event *event)
36{
37 if (event == (const struct log_event *)0) {
38 return;
39 }
40
41 uint64_t irq_flags = arch_irq_save();
42 lock_log();
43 struct log_event *slot = &g_log.events[g_log.write_index];
44 *slot = *event;
45 slot->seq = g_log.next_seq++;
46 slot->cpu = arch_mpidr_el1() & 0xffu;
47 slot->timestamp = timer_now();
48 g_log.write_index++;
49 if (g_log.write_index == CONFIG_LOG_CAPACITY) {
50 g_log.write_index = 0;
51 g_log.wrapped = true;
52 }
53 unlock_log();
54 arch_irq_restore(irq_flags);
55}
56
57void log_simple(enum log_kind kind, uint32_t reason, uint64_t a, uint64_t b)
58{
59 struct log_event ev;
60 hv_memset(&ev, 0, sizeof(ev));
61 ev.kind = (uint32_t)kind;
62 ev.reason = reason;
63 ev.iss = a;
64 ev.elr = b;
65 log_event_commit(&ev);
66}
67
68static const char *kind_name(uint32_t kind)
69{
70 switch (kind) {
71 case LOG_BOOT: return "boot";
72 case LOG_TRAP: return "trap";
73 case LOG_POLICY: return "policy";
74 case LOG_HVC: return "hvc";
75 case LOG_ABORT: return "abort";
76 case LOG_MONITOR: return "monitor";
77 case LOG_PANIC: return "panic";
78 case LOG_SELFTEST: return "selftest";
79 default: return "unknown";
80 }
81}
82
83void log_dump(unsigned limit)
84{
85 uint64_t irq_flags = arch_irq_save();
86 lock_log();
87 uint32_t count = g_log.wrapped ? CONFIG_LOG_CAPACITY : g_log.write_index;
88 if (limit != 0u && limit < count) {
89 count = limit;
90 }
91
92 uint32_t start = g_log.wrapped ? g_log.write_index : 0u;
93 if (g_log.wrapped && count < CONFIG_LOG_CAPACITY) {
94 start = (g_log.write_index + CONFIG_LOG_CAPACITY - count) % CONFIG_LOG_CAPACITY;
95 }
96
97 for (uint32_t i = 0; i < count; i++) {
98 const struct log_event *ev = &g_log.events[(start + i) % CONFIG_LOG_CAPACITY];
99 uart_puts("event seq=");
100 uart_put_dec64(ev->seq);
101 uart_puts(" cpu=");
102 uart_put_dec64(ev->cpu);
103 uart_puts(" vcpu=");
104 uart_put_dec64(ev->vcpu);
105 uart_puts(" ts=");
106 uart_put_dec64(ev->timestamp);
107 uart_puts(" kind=");
108 uart_puts(kind_name(ev->kind));
109 uart_puts(" ec=");
110 uart_put_hex64(ev->ec);
111 uart_puts(" iss=");
112 uart_put_hex64(ev->iss);
113 uart_puts(" elr=");
114 uart_put_hex64(ev->elr);
115 uart_puts(" far=");
116 uart_put_hex64(ev->far);
117 uart_puts(" hpfar=");
118 uart_put_hex64(ev->hpfar);
119 uart_puts(" sysreg=");
120 uart_put_hex64(ev->sysreg_key);
121 uart_puts(" name=");
122 uart_puts(ev->name != (const char *)0 ? ev->name : "-");
123 uart_puts(" dir=");
124 uart_puts(ev->is_read != 0u ? "read" : "write");
125 uart_puts(" rt=");
126 uart_put_dec64(ev->rt);
127 uart_puts(" operand=");
128 uart_put_hex64(ev->operand);
129 uart_puts(" result=");
130 uart_put_hex64(ev->result);
131 uart_puts(" action=");
132 uart_put_dec64(ev->action);
133 uart_puts(" pstate=");
134 uart_put_hex64(ev->pstate);
135 uart_puts(" reason=");
136 uart_put_dec64(ev->reason);
137 uart_puts("\n");
138 }
139 unlock_log();
140 arch_irq_restore(irq_flags);
141}
142
143void log_clear(void)
144{
145 uint64_t irq_flags = arch_irq_save();
146 lock_log();
147 hv_memset(g_log.events, 0, sizeof(g_log.events));
148 g_log.write_index = 0;
149 g_log.wrapped = false;
150 unlock_log();
151 arch_irq_restore(irq_flags);
152}
153
154bool log_selftest(void)
155{
156 g_log_selftest_backup = g_log;
157 log_init();
158 for (uint32_t i = 0; i < CONFIG_LOG_CAPACITY + 3u; i++) {
159 log_simple(LOG_SELFTEST, i, i, i + 1u);
160 }
161 bool ok = g_log.wrapped && g_log.next_seq == (uint64_t)CONFIG_LOG_CAPACITY + 3u;
162 g_log = g_log_selftest_backup;
163 return ok;
164}