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 / guest_loader.c
5.0 kB 151 lines
1#include "hv/arch.h" 2#include "hv/config.h" 3#include "hv/fdt.h" 4#include "hv/guest_loader.h" 5#include "hv/log.h" 6#include "hv/string.h" 7 8#define ARM64_IMAGE_MAGIC 0x644d5241u 9#define ARM64_IMAGE_MAGIC_OFFSET 0x38u 10#define ARM64_IMAGE_TEXT_OFFSET 0x08u 11#define ARM64_IMAGE_SIZE_OFFSET 0x10u 12#define LINUX_BOOTARGS "console=ttyAMA0 earlycon" 13 14static uint32_t read_le32(const uint8_t *p) 15{ 16 return (uint32_t)p[0] | ((uint32_t)p[1] << 8u) | 17 ((uint32_t)p[2] << 16u) | ((uint32_t)p[3] << 24u); 18} 19 20static uint64_t read_le64(const uint8_t *p) 21{ 22 return (uint64_t)read_le32(p) | ((uint64_t)read_le32(p + 4u) << 32u); 23} 24 25bool guest_load_diagnostic(struct guest_image_info *info) 26{ 27 uintptr_t guest_start; 28 uintptr_t guest_end; 29 uint64_t guest_size; 30 31 if (info == (struct guest_image_info *)0) { 32 return false; 33 } 34 35 guest_start = (uintptr_t)__guest_image_start; 36 guest_end = (uintptr_t)__guest_image_end; 37 guest_size = (uint64_t)(guest_end - guest_start); 38 39 if (guest_size == 0u || guest_size > CONFIG_GUEST_RAM_SIZE) { 40 return false; 41 } 42 if (hv_range_overlaps(CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE, 43 (uint64_t)(uintptr_t)__image_start, 44 (uint64_t)((uintptr_t)__image_end - (uintptr_t)__image_start))) { 45 return false; 46 } 47 48 hv_memset((void *)(uintptr_t)CONFIG_GUEST_RAM_BASE, 0, CONFIG_GUEST_RAM_SIZE); 49 hv_memcpy((void *)(uintptr_t)CONFIG_GUEST_RAM_BASE, (const void *)guest_start, (size_t)guest_size); 50 51 info->kind = GUEST_PAYLOAD_DIAGNOSTIC; 52 info->ipa_entry = CONFIG_GUEST_ENTRY; 53 info->ipa_load = CONFIG_GUEST_IPA_BASE; 54 info->size = guest_size; 55 info->dtb_ipa = 0u; 56 info->initrd_ipa = 0u; 57 info->initrd_size = 0u; 58 return true; 59} 60 61bool guest_validate_linux_image_header(const void *image, uint64_t size, 62 struct guest_image_info *info) 63{ 64 const uint8_t *p = (const uint8_t *)image; 65 uint64_t text_offset; 66 uint64_t image_size; 67 uint64_t entry; 68 69 if (image == (const void *)0 || info == (struct guest_image_info *)0 || size < 0x40u) { 70 return false; 71 } 72 if (read_le32(p + ARM64_IMAGE_MAGIC_OFFSET) != ARM64_IMAGE_MAGIC) { 73 return false; 74 } 75 76 text_offset = read_le64(p + ARM64_IMAGE_TEXT_OFFSET); 77 image_size = read_le64(p + ARM64_IMAGE_SIZE_OFFSET); 78 if (image_size == 0u) { 79 image_size = size; 80 } 81 if (image_size > CONFIG_GUEST_RAM_SIZE || text_offset >= CONFIG_GUEST_RAM_SIZE) { 82 return false; 83 } 84 if (hv_add_overflow_u64(CONFIG_GUEST_IPA_BASE, text_offset, &entry)) { 85 return false; 86 } 87 88 info->kind = GUEST_PAYLOAD_LINUX_IMAGE; 89 info->ipa_entry = entry; 90 info->ipa_load = entry; 91 info->size = image_size; 92 info->dtb_ipa = 0u; 93 info->initrd_ipa = 0u; 94 info->initrd_size = 0u; 95 return true; 96} 97 98bool guest_load_external_linux(struct guest_image_info *info, paddr_t image_pa, 99 uint64_t image_max_size, paddr_t dtb_pa, 100 uint64_t dtb_max_size, paddr_t initrd_pa, 101 uint64_t initrd_size) 102{ 103 struct fdt_platform_info dtb_info; 104 uint64_t initrd_start = 0u; 105 uint64_t initrd_end = 0u; 106 107 if (info == (struct guest_image_info *)0 || 108 image_max_size == 0u || image_max_size > CONFIG_GUEST_RAM_SIZE) { 109 return false; 110 } 111 if (!guest_validate_linux_image_header((const void *)(uintptr_t)image_pa, 112 image_max_size, info)) { 113 return false; 114 } 115 if (!fdt_probe(dtb_pa, &dtb_info) || dtb_info.size > dtb_max_size) { 116 return false; 117 } 118 if (initrd_size != 0u) { 119 if (initrd_size > CONFIG_LINUX_INITRD_MAX_SIZE || 120 initrd_pa != CONFIG_LINUX_INITRD_PA || 121 hv_add_overflow_u64(CONFIG_LINUX_INITRD_IPA, initrd_size, &initrd_end) || 122 initrd_end > CONFIG_LINUX_DTB_IPA) { 123 return false; 124 } 125 initrd_start = CONFIG_LINUX_INITRD_IPA; 126 } 127 if (!fdt_patch_memory(dtb_pa, CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_SIZE)) { 128 return false; 129 } 130 if (!fdt_patch_linux_guest(dtb_pa, dtb_max_size, LINUX_BOOTARGS, 131 initrd_start, initrd_end)) { 132 return false; 133 } 134 if (!fdt_probe(dtb_pa, &dtb_info)) { 135 return false; 136 } 137 log_simple(LOG_BOOT, 33u, dtb_info.size, dtb_info.memory_size); 138 if (dtb_info.initrd_start != 0u || dtb_info.initrd_end != 0u) { 139 log_simple(LOG_BOOT, 34u, dtb_info.initrd_start, dtb_info.initrd_end); 140 } 141 fdt_dump(&dtb_info); 142 143 info->kind = GUEST_PAYLOAD_LINUX_IMAGE; 144 info->ipa_load = CONFIG_GUEST_IPA_BASE; 145 info->dtb_ipa = CONFIG_LINUX_DTB_IPA; 146 if (initrd_start != 0u && initrd_end > initrd_start) { 147 info->initrd_ipa = initrd_start; 148 info->initrd_size = initrd_end - initrd_start; 149 } 150 return true; 151}