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