AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1

Configure Feed

Select the types of activity you want to include in your feed.

ariel / drivers / gicv3.c
3.1 kB 125 lines
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}