AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/config.h"
2#include "hv/gicv3.h"
3#include "hv/log.h"
4#include "hv/mmio.h"
5#include "hv/uart.h"
6#include "hv/vcpu.h"
7
8#define GICD_CTLR 0x0000u
9#define GICD_TYPER 0x0004u
10#define GICR_CTLR 0x0000u
11#define GICR_WAKER 0x0014u
12#define GICR_WAKER_PROCESSOR_SLEEP (1u << 1)
13#define GICR_WAKER_CHILDREN_ASLEEP (1u << 2)
14
15static uintptr_t gicd(uint32_t off)
16{
17 return (uintptr_t)(CONFIG_GICD_BASE + (uint64_t)off);
18}
19
20static uintptr_t gicr(uint32_t off)
21{
22 return (uintptr_t)(CONFIG_GICR_BASE + (uint64_t)off);
23}
24
25void gicv3_init(void)
26{
27 uint32_t typer = mmio_read32(gicd(GICD_TYPER));
28 mmio_write32(gicd(GICD_CTLR), 0u);
29
30 uint32_t waker = mmio_read32(gicr(GICR_WAKER));
31 waker &= ~GICR_WAKER_PROCESSOR_SLEEP;
32 mmio_write32(gicr(GICR_WAKER), waker);
33 for (uint32_t i = 0; i < 100000u; i++) {
34 if ((mmio_read32(gicr(GICR_WAKER)) & GICR_WAKER_CHILDREN_ASLEEP) == 0u) {
35 break;
36 }
37 }
38
39 __asm__ volatile(
40 "msr ICC_SRE_EL2, %0\n"
41 "isb\n"
42 "msr ICC_SRE_EL1, %0\n"
43 "isb\n"
44 "msr ICC_PMR_EL1, %1\n"
45 "msr ICC_IGRPEN1_EL1, %0\n"
46 "isb\n"
47 :: "r"(1ull), "r"(0xffull)
48 : "memory");
49
50 mmio_write32(gicd(GICD_CTLR), 0x3u);
51 log_simple(LOG_BOOT, 20u, typer, 0u);
52 gicv3_vcpu_init();
53}
54
55void gicv3_dump(void)
56{
57 uart_puts("gicv3 gicd=");
58 uart_put_hex64(CONFIG_GICD_BASE);
59 uart_puts(" gicr=");
60 uart_put_hex64(CONFIG_GICR_BASE);
61 uart_puts(" typer=");
62 uart_put_hex64(mmio_read32(gicd(GICD_TYPER)));
63 uart_puts("\n");
64}
65
66uint32_t gicv3_ack_irq(void)
67{
68 uint64_t irq;
69 __asm__ volatile("mrs %0, ICC_IAR1_EL1" : "=r"(irq));
70 return (uint32_t)(irq & 0x3ffu);
71}
72
73void gicv3_eoi(uint32_t irq)
74{
75 __asm__ volatile("msr ICC_EOIR1_EL1, %0\nisb" :: "r"((uint64_t)irq) : "memory");
76}
77
78void gicv3_vcpu_init(void)
79{
80 __asm__ volatile(
81 "msr ICH_HCR_EL2, %0\n"
82 "msr ICH_VMCR_EL2, %1\n"
83 "msr ICH_LR0_EL2, xzr\n"
84 "isb\n"
85 :: "r"(1ull), "r"(0xff0000ull)
86 : "memory");
87}
88
89void gicv3_sync_vcpu_state(struct vcpu *vcpu)
90{
91 uint64_t lr;
92 uint64_t state;
93
94 if (vcpu == (struct vcpu *)0 || vcpu->active_virtual_irq == 0u) {
95 return;
96 }
97
98 __asm__ volatile("mrs %0, ICH_LR0_EL2" : "=r"(lr));
99 state = (lr >> 62u) & 0x3u;
100 if (state == 0u) {
101 vcpu_clear_pending_irq(vcpu, (uint32_t)vcpu->active_virtual_irq);
102 vcpu->active_virtual_irq = 0u;
103 vcpu->stats.virtual_irqs_completed++;
104 }
105}
106
107void gicv3_flush_vcpu_state(struct vcpu *vcpu)
108{
109 if (vcpu == (struct vcpu *)0) {
110 return;
111 }
112
113 if ((vcpu->pending_virtual_irq & (1ull << CONFIG_VTIMER_IRQ)) == 0u) {
114 vcpu->active_virtual_irq = 0u;
115 __asm__ volatile("msr ICH_LR0_EL2, xzr\nisb" ::: "memory");
116 return;
117 }
118
119 uint64_t lr = (uint64_t)CONFIG_VTIMER_IRQ | (1ull << 62u) | (1ull << 60u);
120 if (vcpu->active_virtual_irq != CONFIG_VTIMER_IRQ) {
121 vcpu->stats.virtual_irqs_injected++;
122 }
123 vcpu->active_virtual_irq = CONFIG_VTIMER_IRQ;
124 __asm__ volatile("msr ICH_LR0_EL2, %0\nisb" :: "r"(lr) : "memory");
125}