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