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
4.2 kB 129 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, 1001u }, 9 { CONFIG_GICD_BASE, CONFIG_GICD_SIZE, "gicd", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1002u }, 10 { CONFIG_GITS_BASE, CONFIG_GITS_SIZE, "gits", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1003u }, 11 { CONFIG_GICR_BASE, CONFIG_GICR_SIZE, "gicr", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1004u }, 12 { CONFIG_RTC_BASE, CONFIG_RTC_SIZE, "pl031-rtc", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1005u }, 13 { CONFIG_FW_CFG_BASE, CONFIG_FW_CFG_SIZE, "fw-cfg", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1006u }, 14 { CONFIG_GPIO_BASE, CONFIG_GPIO_SIZE, "pl061-gpio", MMIO_POLICY_EMULATE_READONLY_DEVICE, 1007u }, 15 { CONFIG_PCI_ECAM_BASE, CONFIG_PCI_ECAM_SIZE, "pci-ecam", MMIO_POLICY_EMULATE_ZERO, 1008u }, 16 { 0x0a000000ull, 0x00004000ull, "virtio-mmio", MMIO_POLICY_EMULATE_VIRTIO_MMIO, 1009u }, 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 69static bool emulate_readonly_probe(struct vcpu *vcpu, ipa_t ipa, bool is_write, uint32_t rt) 70{ 71 if (is_write) { 72 return true; 73 } 74 vcpu_write_gpr(vcpu, rt, readonly_device_read32(ipa)); 75 return true; 76} 77 78bool mmio_policy_emulate(struct vcpu *vcpu, ipa_t ipa, uint64_t esr_el2) 79{ 80 const struct mmio_policy_region *region = mmio_policy_lookup(ipa); 81 bool is_write; 82 uint32_t rt; 83 uint64_t off; 84 uint64_t value = 0u; 85 86 if (vcpu == (struct vcpu *)0 || region == (const struct mmio_policy_region *)0 || 87 !decode_abort_access(esr_el2, &is_write, &rt)) { 88 return false; 89 } 90 91 off = ipa - region->base; 92 if (region->action == MMIO_POLICY_EMULATE_PL011) { 93 if (is_write && off == 0u) { 94 uart_putc((char)(vcpu_read_gpr(vcpu, rt) & 0xffu)); 95 } else if (!is_write && off == 0x18u) { 96 value = 0x10u; 97 } 98 } else if (region->action == MMIO_POLICY_EMULATE_VIRTIO_MMIO) { 99 if (!is_write) { 100 value = virtio_read(off); 101 } 102 } else if (region->action == MMIO_POLICY_EMULATE_READONLY_DEVICE) { 103 return emulate_readonly_probe(vcpu, ipa, is_write, rt); 104 } else if (region->action != MMIO_POLICY_EMULATE_ZERO) { 105 return false; 106 } 107 108 if (!is_write) { 109 vcpu_write_gpr(vcpu, rt, value); 110 } 111 return true; 112} 113 114void mmio_policy_dump(void) 115{ 116 for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_mmio_regions); i++) { 117 uart_puts("mmio name="); 118 uart_puts(g_mmio_regions[i].name); 119 uart_puts(" base="); 120 uart_put_hex64(g_mmio_regions[i].base); 121 uart_puts(" size="); 122 uart_put_hex64(g_mmio_regions[i].size); 123 uart_puts(" action="); 124 uart_put_dec64((uint64_t)g_mmio_regions[i].action); 125 uart_puts(" provenance="); 126 uart_put_dec64(g_mmio_regions[i].provenance); 127 uart_puts("\n"); 128 } 129}