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 / core / mmio_policy.c
3.8 kB 120 lines
1#include "hv/config.h" 2#include "hv/mmio.h" 3#include "hv/mmio_policy.h" 4#include "hv/uart.h" 5#include "hv/vcpu.h" 6 7static const struct mmio_policy_region g_mmio_regions[] = { 8 { CONFIG_UART_BASE, CONFIG_UART_SIZE, "pl011-uart", MMIO_POLICY_EMULATE_PL011 }, 9 { CONFIG_GICD_BASE, CONFIG_GICD_SIZE, "gicd", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 10 { CONFIG_GITS_BASE, CONFIG_GITS_SIZE, "gits", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 11 { CONFIG_GICR_BASE, CONFIG_GICR_SIZE, "gicr", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 12 { CONFIG_RTC_BASE, CONFIG_RTC_SIZE, "pl031-rtc", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 13 { CONFIG_FW_CFG_BASE, CONFIG_FW_CFG_SIZE, "fw-cfg", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 14 { CONFIG_GPIO_BASE, CONFIG_GPIO_SIZE, "pl061-gpio", MMIO_POLICY_EMULATE_READONLY_DEVICE }, 15 { CONFIG_PCI_ECAM_BASE, CONFIG_PCI_ECAM_SIZE, "pci-ecam", MMIO_POLICY_EMULATE_ZERO }, 16 { 0x0a000000ull, 0x00004000ull, "virtio-mmio", MMIO_POLICY_EMULATE_VIRTIO_MMIO }, 17}; 18 19const struct mmio_policy_region *mmio_policy_lookup(ipa_t ipa) 20{ 21 for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_mmio_regions); i++) { 22 uint64_t end; 23 if (hv_add_overflow_u64(g_mmio_regions[i].base, g_mmio_regions[i].size, &end)) { 24 continue; 25 } 26 if (ipa >= g_mmio_regions[i].base && ipa < end) { 27 return &g_mmio_regions[i]; 28 } 29 } 30 return (const struct mmio_policy_region *)0; 31} 32 33static bool decode_abort_access(uint64_t esr, bool *is_write, uint32_t *rt) 34{ 35 if ((esr & HV_BIT(24)) == 0u) { 36 return false; 37 } 38 *rt = (uint32_t)((esr >> 16u) & 0x1fu); 39 *is_write = (esr & HV_BIT(6)) != 0u; 40 return true; 41} 42 43static uint64_t virtio_read(uint64_t off) 44{ 45 if ((off & ~0x1ffull) != 0u) { 46 return 0u; 47 } 48 off &= 0x1ffu; 49 switch (off) { 50 case 0x000u: return 0x74726976u; 51 case 0x004u: return 2u; 52 case 0x008u: return 3u; 53 case 0x00cu: return 0x41524945u; 54 case 0x010u: return 0u; 55 case 0x034u: return 0u; 56 case 0x070u: return 0u; 57 default: return 0u; 58 } 59} 60 61static uint64_t readonly_device_read32(ipa_t ipa) 62{ 63 if (!hv_is_aligned_u64(ipa, 4u)) { 64 return 0u; 65 } 66 return (uint64_t)mmio_read32((uintptr_t)ipa); 67} 68 69bool mmio_policy_emulate(struct vcpu *vcpu, ipa_t ipa, uint64_t esr_el2) 70{ 71 const struct mmio_policy_region *region = mmio_policy_lookup(ipa); 72 bool is_write; 73 uint32_t rt; 74 uint64_t off; 75 uint64_t value = 0u; 76 77 if (vcpu == (struct vcpu *)0 || region == (const struct mmio_policy_region *)0 || 78 !decode_abort_access(esr_el2, &is_write, &rt)) { 79 return false; 80 } 81 82 off = ipa - region->base; 83 if (region->action == MMIO_POLICY_EMULATE_PL011) { 84 if (is_write && off == 0u) { 85 uart_putc((char)(vcpu_read_gpr(vcpu, rt) & 0xffu)); 86 } else if (!is_write && off == 0x18u) { 87 value = 0x10u; 88 } 89 } else if (region->action == MMIO_POLICY_EMULATE_VIRTIO_MMIO) { 90 if (!is_write) { 91 value = virtio_read(off); 92 } 93 } else if (region->action == MMIO_POLICY_EMULATE_READONLY_DEVICE) { 94 if (!is_write) { 95 value = readonly_device_read32(ipa); 96 } 97 } else if (region->action != MMIO_POLICY_EMULATE_ZERO) { 98 return false; 99 } 100 101 if (!is_write) { 102 vcpu_write_gpr(vcpu, rt, value); 103 } 104 return true; 105} 106 107void mmio_policy_dump(void) 108{ 109 for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_mmio_regions); i++) { 110 uart_puts("mmio name="); 111 uart_puts(g_mmio_regions[i].name); 112 uart_puts(" base="); 113 uart_put_hex64(g_mmio_regions[i].base); 114 uart_puts(" size="); 115 uart_put_hex64(g_mmio_regions[i].size); 116 uart_puts(" action="); 117 uart_put_dec64((uint64_t)g_mmio_regions[i].action); 118 uart_puts("\n"); 119 } 120}