AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/config.h"
2#include "hv/arch.h"
3#include "hv/panic.h"
4#include "hv/string.h"
5#include "hv/sysreg.h"
6#include "hv/uart.h"
7#include "hv/vcpu.h"
8
9_Static_assert(offsetof(struct trap_frame, x) == 0u, "trap_frame x offset");
10_Static_assert(offsetof(struct trap_frame, sp_el0) == 248u, "trap_frame sp_el0 offset");
11_Static_assert(offsetof(struct trap_frame, sp_el1) == 256u, "trap_frame sp_el1 offset");
12_Static_assert(offsetof(struct trap_frame, elr_el2) == 264u, "trap_frame elr offset");
13_Static_assert(offsetof(struct trap_frame, spsr_el2) == 272u, "trap_frame spsr offset");
14_Static_assert(offsetof(struct trap_frame, esr_el2) == 280u, "trap_frame esr offset");
15_Static_assert(offsetof(struct trap_frame, far_el2) == 288u, "trap_frame far offset");
16_Static_assert(offsetof(struct trap_frame, hpfar_el2) == 296u, "trap_frame hpfar offset");
17_Static_assert(sizeof(struct trap_frame) == 304u, "trap_frame size");
18
19_Static_assert(offsetof(struct vcpu, x) == 0u, "vcpu x offset");
20_Static_assert(offsetof(struct vcpu, sp_el0) == 248u, "vcpu sp_el0 offset");
21_Static_assert(offsetof(struct vcpu, sp_el1) == 256u, "vcpu sp_el1 offset");
22_Static_assert(offsetof(struct vcpu, pc) == 264u, "vcpu pc offset");
23_Static_assert(offsetof(struct vcpu, pstate) == 272u, "vcpu pstate offset");
24
25static struct vcpu *g_current_vcpu;
26
27void vcpu_init(struct vcpu *vcpu, uint32_t id, uint64_t entry, uint64_t stack_top)
28{
29 BUG_ON(vcpu == (struct vcpu *)0);
30 hv_memset(vcpu, 0, sizeof(*vcpu));
31 vcpu->id = id;
32 vcpu->state = VCPU_CREATED;
33 vcpu->pc = entry;
34 vcpu->pstate = 0x3c5u;
35 vcpu->sp_el1 = stack_top;
36 vcpu->sysregs.sctlr_el1 = 0x30d00800ull;
37 vcpu->sysregs.mair_el1 = 0xffull;
38 vcpu->sysregs.cntkctl_el1 = 0u;
39 vcpu->pending_virtual_irq = 0u;
40 vcpu->active_virtual_irq = 0u;
41 vcpu->state = VCPU_READY;
42}
43
44void vcpu_load_frame(struct vcpu *vcpu, const struct trap_frame *frame)
45{
46 BUG_ON(vcpu == (struct vcpu *)0 || frame == (const struct trap_frame *)0);
47 for (uint32_t i = 0; i < 31u; i++) {
48 vcpu->x[i] = frame->x[i];
49 }
50 vcpu->sp_el0 = frame->sp_el0;
51 vcpu->sp_el1 = frame->sp_el1;
52 vcpu->pc = frame->elr_el2;
53 vcpu->pstate = frame->spsr_el2;
54 vcpu->last_esr = frame->esr_el2;
55 vcpu->last_far = frame->far_el2;
56 vcpu->last_hpfar = frame->hpfar_el2;
57 arch_capture_el1_sysregs(vcpu);
58}
59
60void vcpu_store_frame(const struct vcpu *vcpu, struct trap_frame *frame)
61{
62 BUG_ON(vcpu == (const struct vcpu *)0 || frame == (struct trap_frame *)0);
63 for (uint32_t i = 0; i < 31u; i++) {
64 frame->x[i] = vcpu->x[i];
65 }
66 frame->sp_el0 = vcpu->sp_el0;
67 frame->sp_el1 = vcpu->sp_el1;
68 frame->elr_el2 = vcpu->pc;
69 frame->spsr_el2 = vcpu->pstate;
70}
71
72uint64_t vcpu_read_gpr(const struct vcpu *vcpu, uint32_t rt)
73{
74 BUG_ON(vcpu == (const struct vcpu *)0);
75 if (rt >= 31u) {
76 return 0u;
77 }
78 return vcpu->x[rt];
79}
80
81void vcpu_write_gpr(struct vcpu *vcpu, uint32_t rt, uint64_t value)
82{
83 BUG_ON(vcpu == (struct vcpu *)0);
84 if (rt < 31u) {
85 vcpu->x[rt] = value;
86 }
87}
88
89void vcpu_set_pending_irq(struct vcpu *vcpu, uint32_t intid)
90{
91 BUG_ON(vcpu == (struct vcpu *)0);
92 if (intid < 64u) {
93 vcpu->pending_virtual_irq |= (1ull << intid);
94 }
95}
96
97void vcpu_clear_pending_irq(struct vcpu *vcpu, uint32_t intid)
98{
99 BUG_ON(vcpu == (struct vcpu *)0);
100 if (intid < 64u) {
101 vcpu->pending_virtual_irq &= ~(1ull << intid);
102 }
103}
104
105struct vcpu *vcpu_current(void)
106{
107 return g_current_vcpu;
108}
109
110void vcpu_set_current(struct vcpu *vcpu)
111{
112 g_current_vcpu = vcpu;
113}
114
115static void vcpu_dump_exception_telemetry(const struct vcpu *vcpu)
116{
117 uart_puts("trap_ec ec=");
118 uart_put_hex64(ESR_EC_HVC64);
119 uart_puts(" name=");
120 uart_puts(esr_ec_name(ESR_EC_HVC64));
121 uart_puts(" count=");
122 uart_put_dec64(vcpu->stats.hvc_calls);
123 uart_puts("\ntrap_ec ec=");
124 uart_put_hex64(ESR_EC_SYSREG);
125 uart_puts(" name=");
126 uart_puts(esr_ec_name(ESR_EC_SYSREG));
127 uart_puts(" count=");
128 uart_put_dec64(vcpu->stats.sysreg_traps);
129 uart_puts("\ntrap_ec ec=");
130 uart_put_hex64(ESR_EC_SMC64);
131 uart_puts(" name=");
132 uart_puts(esr_ec_name(ESR_EC_SMC64));
133 uart_puts(" denied=");
134 uart_put_dec64(vcpu->stats.smc_denied);
135 uart_puts("\ntrap_ec ec=");
136 uart_put_hex64(ESR_EC_WFI_WFE);
137 uart_puts(" name=");
138 uart_puts(esr_ec_name(ESR_EC_WFI_WFE));
139 uart_puts(" count=");
140 uart_put_dec64(vcpu->stats.wfx_traps);
141 uart_puts("\ntrap_ec ec=");
142 uart_put_hex64(ESR_EC_IABT_LOWER);
143 uart_puts(" name=");
144 uart_puts(esr_ec_name(ESR_EC_IABT_LOWER));
145 uart_puts(" count=");
146 uart_put_dec64(vcpu->stats.instruction_aborts);
147 uart_puts("\ntrap_ec ec=");
148 uart_put_hex64(ESR_EC_DABT_LOWER);
149 uart_puts(" name=");
150 uart_puts(esr_ec_name(ESR_EC_DABT_LOWER));
151 uart_puts(" count=");
152 uart_put_dec64(vcpu->stats.data_aborts);
153 uart_puts("\ntrap_ec ec=");
154 uart_put_hex64(ESR_EC_UNKNOWN);
155 uart_puts(" name=");
156 uart_puts(esr_ec_name(ESR_EC_UNKNOWN));
157 uart_puts(" count=");
158 uart_put_dec64(vcpu->stats.unknown_exceptions);
159 uart_puts("\n");
160}
161
162void vcpu_dump(const struct vcpu *vcpu)
163{
164 if (vcpu == (const struct vcpu *)0) {
165 uart_puts("vcpu none\n");
166 return;
167 }
168 uart_puts("vcpu id=");
169 uart_put_dec64(vcpu->id);
170 uart_puts(" state=");
171 uart_put_dec64((uint64_t)vcpu->state);
172 uart_puts(" pc=");
173 uart_put_hex64(vcpu->pc);
174 uart_puts(" pstate=");
175 uart_put_hex64(vcpu->pstate);
176 uart_puts(" sp_el1=");
177 uart_put_hex64(vcpu->sp_el1);
178 uart_puts(" traps=");
179 uart_put_dec64(vcpu->stats.traps);
180 uart_puts(" last_ec=");
181 uart_put_hex64(esr_ec(vcpu->last_esr));
182 uart_puts(" last_ecname=");
183 uart_puts(esr_ec_name(esr_ec(vcpu->last_esr)));
184 uart_puts(" injected_undefs=");
185 uart_put_dec64(vcpu->stats.injected_undefs);
186 uart_puts(" pending_irq=");
187 uart_put_hex64(vcpu->pending_virtual_irq);
188 uart_puts(" virq_inj=");
189 uart_put_dec64(vcpu->stats.virtual_irqs_injected);
190 uart_puts(" virq_done=");
191 uart_put_dec64(vcpu->stats.virtual_irqs_completed);
192 uart_puts(" timer_syncs=");
193 uart_put_dec64(vcpu->stats.timer_syncs);
194 uart_puts(" timer_delta=");
195 uart_put_dec64(vcpu->stats.timer_last_delta);
196 uart_puts("\n");
197 vcpu_dump_exception_telemetry(vcpu);
198 for (uint32_t i = 0; i < 31u; i++) {
199 uart_puts("x");
200 uart_put_dec64(i);
201 uart_puts("=");
202 uart_put_hex64(vcpu->x[i]);
203 uart_puts((i % 4u) == 3u ? "\n" : " ");
204 }
205 uart_puts("\n");
206}
207
208bool vcpu_frame_selftest(void)
209{
210 struct trap_frame frame;
211 struct trap_frame out;
212 struct vcpu vcpu;
213
214 hv_memset(&frame, 0, sizeof(frame));
215 hv_memset(&out, 0, sizeof(out));
216 hv_memset(&vcpu, 0, sizeof(vcpu));
217 for (uint32_t i = 0; i < 31u; i++) {
218 frame.x[i] = 0x1000u + i;
219 }
220 frame.sp_el0 = 0x2000u;
221 frame.sp_el1 = 0x3000u;
222 frame.elr_el2 = 0x4000u;
223 frame.spsr_el2 = 0x3c5u;
224 frame.esr_el2 = 0x96000000u;
225 frame.far_el2 = 0x5000u;
226 frame.hpfar_el2 = 0x6000u;
227
228 vcpu_load_frame(&vcpu, &frame);
229 vcpu_store_frame(&vcpu, &out);
230 return hv_memcmp(frame.x, out.x, sizeof(frame.x)) == 0 &&
231 frame.sp_el0 == out.sp_el0 &&
232 frame.sp_el1 == out.sp_el1 &&
233 frame.elr_el2 == out.elr_el2 &&
234 frame.spsr_el2 == out.spsr_el2 &&
235 vcpu.last_esr == frame.esr_el2 &&
236 vcpu.last_far == frame.far_el2 &&
237 vcpu.last_hpfar == frame.hpfar_el2;
238}