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 / el2_mmu.c
3.9 kB 138 lines
1#include "hv/arch.h" 2#include "hv/config.h" 3#include "hv/el2_mmu.h" 4#include "hv/string.h" 5#include "hv/uart.h" 6 7#define EL2_PT_ENTRIES 512u 8#define EL2_L1_SHIFT 30u 9#define EL2_L2_SHIFT 21u 10#define EL2_L2_SIZE (1ull << EL2_L2_SHIFT) 11#define EL2_DESC_VALID HV_BIT(0) 12#define EL2_DESC_TABLE HV_BIT(1) 13#define EL2_DESC_AF HV_BIT(10) 14#define EL2_DESC_SH_INNER (3ull << 8u) 15#define EL2_DESC_ATTR_NORMAL (1ull << 2u) 16#define EL2_DESC_ATTR_DEVICE (0ull << 2u) 17#define EL2_DESC_PXN HV_BIT(53) 18#define EL2_DESC_UXN HV_BIT(54) 19#define EL2_MAIR ((0xffull << 8u) | 0x04ull) 20 21static uint64_t g_el2_l1[EL2_PT_ENTRIES] __attribute__((aligned(4096))); 22static uint64_t g_el2_l2[2][EL2_PT_ENTRIES] __attribute__((aligned(4096))); 23static uint64_t g_guard_low; 24static uint64_t g_guard_high; 25static bool g_ready; 26static bool g_enabled; 27 28static uint64_t block_desc(uint64_t pa, bool device, bool executable) 29{ 30 uint64_t desc = (pa & 0x0000ffffffe00000ull) | EL2_DESC_VALID | EL2_DESC_AF; 31 desc |= device ? EL2_DESC_ATTR_DEVICE : (EL2_DESC_ATTR_NORMAL | EL2_DESC_SH_INNER); 32 if (!executable) { 33 desc |= EL2_DESC_PXN | EL2_DESC_UXN; 34 } 35 return desc; 36} 37 38static bool install_block(uint64_t pa, bool device, bool executable) 39{ 40 uint64_t l1 = (pa >> EL2_L1_SHIFT) & 0x1ffu; 41 uint64_t l2 = (pa >> EL2_L2_SHIFT) & 0x1ffu; 42 if (l1 >= HV_ARRAY_SIZE(g_el2_l2)) { 43 return false; 44 } 45 g_el2_l1[l1] = ((uint64_t)(uintptr_t)g_el2_l2[l1] & 0x0000fffffffff000ull) | 46 EL2_DESC_TABLE | EL2_DESC_VALID; 47 g_el2_l2[l1][l2] = block_desc(pa, device, executable); 48 return true; 49} 50 51void el2_mmu_init_plan(void) 52{ 53 uint64_t image_start = HV_ALIGN_DOWN((uint64_t)(uintptr_t)__image_start, EL2_L2_SIZE); 54 uint64_t image_end = HV_ALIGN_UP((uint64_t)(uintptr_t)__image_end, EL2_L2_SIZE); 55 56 hv_memset(g_el2_l1, 0, sizeof(g_el2_l1)); 57 hv_memset(g_el2_l2, 0, sizeof(g_el2_l2)); 58 g_guard_low = image_start >= EL2_L2_SIZE ? image_start - EL2_L2_SIZE : 0u; 59 g_guard_high = image_end; 60 g_ready = true; 61 g_enabled = false; 62 63 for (uint64_t pa = image_start; pa < image_end; pa += EL2_L2_SIZE) { 64 if (!install_block(pa, false, true)) { 65 g_ready = false; 66 } 67 } 68 for (uint64_t pa = CONFIG_GUEST_RAM_BASE; 69 pa < CONFIG_GUEST_RAM_BASE + CONFIG_GUEST_RAM_SIZE; 70 pa += EL2_L2_SIZE) { 71 if (!install_block(pa, false, false)) { 72 g_ready = false; 73 } 74 } 75 if (!install_block(CONFIG_UART_BASE, true, false) || 76 !install_block(CONFIG_GICD_BASE, true, false) || 77 !install_block(CONFIG_GICR_BASE, true, false) || 78 !install_block(0x0a000000ull, true, false)) { 79 g_ready = false; 80 } 81} 82 83uint64_t el2_mmu_root(void) 84{ 85 return (uint64_t)(uintptr_t)g_el2_l1; 86} 87 88uint64_t el2_mmu_tcr(void) 89{ 90 uint64_t tcr = 0u; 91 tcr |= 25ull; 92 tcr |= (1ull << 8u); 93 tcr |= (1ull << 10u); 94 tcr |= (3ull << 12u); 95 tcr |= (2ull << 16u); 96 return tcr; 97} 98 99uint64_t el2_mmu_mair(void) 100{ 101 return EL2_MAIR; 102} 103 104void el2_mmu_enable(void) 105{ 106 if (!g_ready) { 107 return; 108 } 109 arch_enable_el2_mmu(el2_mmu_root(), el2_mmu_tcr(), el2_mmu_mair()); 110 g_enabled = true; 111} 112 113void el2_mmu_dump(void) 114{ 115 uart_puts("el2mmu planned="); 116 uart_puts(g_ready ? "yes" : "no"); 117 uart_puts(" enabled="); 118 uart_puts(g_enabled ? "yes" : "no"); 119 uart_puts(" root="); 120 uart_put_hex64(el2_mmu_root()); 121 uart_puts(" tcr="); 122 uart_put_hex64(el2_mmu_tcr()); 123 uart_puts(" mair="); 124 uart_put_hex64(el2_mmu_mair()); 125 uart_puts(" guard_low="); 126 uart_put_hex64(g_guard_low); 127 uart_puts(" guard_high="); 128 uart_put_hex64(g_guard_high); 129 uart_puts("\n"); 130} 131 132bool el2_mmu_selftest(void) 133{ 134 return g_ready && 135 g_enabled && 136 hv_is_aligned_u64(el2_mmu_root(), CONFIG_PAGE_SIZE) && 137 (g_guard_high == 0u || (g_guard_high & (EL2_L2_SIZE - 1u)) == 0u); 138}