1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <unistd.h> 11#include <fcntl.h> 12 13#include <elf/elf.h> 14#include <vka/capops.h> 15#include <cpio/cpio.h> 16#include <sel4utils/sel4_zf_logif.h> 17 18#include <sel4vm/guest_vm.h> 19#include <sel4vm/guest_memory.h> 20#include <sel4vm/guest_ram.h> 21 22#include <sel4vmmplatsupport/guest_image.h> 23 24#define UIMAGE_MAGIC 0x56190527 25#define ZIMAGE_MAGIC 0x016F2818 26#define DTB_MAGIC 0xedfe0dd0 27#define INITRD_GZ_MAGIC 0x8b1f 28 29struct dtb_hdr { 30 uint32_t magic; 31#if 0 32 uint32_t size; 33 uint32_t off_dt_struct; 34 uint32_t off_dt_strings; 35 uint32_t off_mem_rsvmap; 36 uint32_t version; 37 uint32_t comp_version; 38 uint32_t boot_cpuid; 39 uint32_t size_dt_strings; 40 uint32_t size_dt_struct; 41#endif 42}; 43 44struct initrd_gz_hdr { 45 uint16_t magic; 46 uint8_t compression; 47 uint8_t flags; 48}; 49 50struct zimage_hdr { 51 uint32_t code[9]; 52 uint32_t magic; 53 uint32_t start; 54 uint32_t end; 55}; 56 57static int is_uImage(void *file) 58{ 59 uint32_t magic = UIMAGE_MAGIC; 60 return memcmp(file, &magic, sizeof(magic)); 61} 62 63static int is_zImage(void *file) 64{ 65 struct zimage_hdr *hdr; 66 hdr = (struct zimage_hdr *)file; 67 return hdr->magic != ZIMAGE_MAGIC; 68} 69 70static int is_dtb(void *file) 71{ 72 struct dtb_hdr *hdr; 73 hdr = (struct dtb_hdr *)file; 74 return hdr->magic != DTB_MAGIC; 75} 76 77static int is_initrd(void *file) 78{ 79 /* We currently only support initrd files in the gzip format */ 80 struct initrd_gz_hdr *hdr; 81 hdr = (struct initrd_gz_hdr *)file; 82 return hdr->magic != INITRD_GZ_MAGIC; 83} 84 85enum img_type image_get_type(void *file) 86{ 87 if (elf_check_magic(file) == 0) { 88 return IMG_ELF; 89 } else if (is_zImage(file) == 0) { 90 return IMG_ZIMAGE; 91 } else if (is_uImage(file) == 0) { 92 return IMG_UIMAGE; 93 } else if (is_dtb(file) == 0) { 94 return IMG_DTB; 95 } else if (is_initrd(file) == 0) { 96 return IMG_INITRD_GZ; 97 } else { 98 return IMG_BIN; 99 } 100} 101 102uintptr_t zImage_get_load_address(void *file, uintptr_t ram_base) 103{ 104 struct zimage_hdr *hdr; 105 hdr = (struct zimage_hdr *)file; 106 if (hdr->start == 0) { 107 return ram_base + 0x8000; 108 } else { 109 return hdr->start; 110 } 111 return 0; 112} 113 114static int get_guest_image_type(const char *image_name, enum img_type *image_type, Elf64_Ehdr *header) 115{ 116 int fd; 117 uintptr_t load_addr; 118 fd = open(image_name, 0); 119 if (fd == -1) { 120 ZF_LOGE("Error: Unable to open image \'%s\'", image_name); 121 return -1; 122 } 123 124 size_t len = read(fd, header, sizeof(*header)); 125 if (len != sizeof(*header)) { 126 ZF_LOGE("Could not read len. File is likely corrupt"); 127 close(fd); 128 return -1; 129 } 130 *image_type = image_get_type(header); 131 close(fd); 132 return 0; 133} 134 135static int guest_write_address(vm_t *vm, uintptr_t paddr, void *vaddr, size_t size, size_t offset, void *cookie) 136{ 137 memcpy(vaddr, cookie + offset, size); 138 if (config_set(CONFIG_PLAT_TX1) || config_set(CONFIG_PLAT_TX2)) { 139 seL4_CPtr cap = vspace_get_cap(&vm->mem.vmm_vspace, vaddr); 140 if (cap == seL4_CapNull) { 141 /* Not sure how we would get here, something has gone pretty wrong */ 142 ZF_LOGE("Failed to get vmm cap for vaddr: %p", vaddr); 143 return -1; 144 } 145 int error = seL4_ARM_Page_CleanInvalidate_Data(cap, 0, PAGE_SIZE_4K); 146 ZF_LOGF_IFERR(error, "seL4_ARM_Page_CleanInvalidate_Data failed"); 147 } 148 return 0; 149} 150 151static int load_image(vm_t *vm, const char *image_name, uintptr_t load_addr, size_t *resulting_image_size) 152{ 153 int fd; 154 size_t len; 155 int error; 156 fd = open(image_name, 0); 157 if (fd == -1) { 158 ZF_LOGE("Error: Unable to find image \'%s\'", image_name); 159 return -1; 160 } 161 162 /* Try and load the image 1MiB at a time. Reduce the size by half if 163 * there isn't enough memory available. The total loading time may be 164 * faster if a larger buffer is used as it allows for more batching. 165 */ 166 size_t read_size = BIT(20); 167 char *buf = malloc(read_size); 168 while (buf == NULL) { 169 read_size /= 2; 170 if (read_size < 4096) { 171 ZF_LOGE("Not enough memory for copy buffer"); 172 } 173 buf = malloc(read_size); 174 } 175 size_t offset = 0; 176 while (1) { 177 /* Load the image */ 178 len = read(fd, buf, read_size); 179 if (!len) { 180 break; 181 } 182 vm_ram_mark_allocated(vm, load_addr + offset, len); 183 error = vm_ram_touch(vm, load_addr + offset, len, guest_write_address, (void *)buf); 184 if (error) { 185 ZF_LOGE("Error: Failed to load \'%s\'", image_name); 186 close(fd); 187 return -1; 188 } 189 offset += len; 190 } 191 free(buf); 192 *resulting_image_size = offset; 193 close(fd); 194 return 0; 195} 196 197static void *load_guest_kernel_image(vm_t *vm, const char *kernel_image_name, uintptr_t load_base_addr, 198 size_t *image_size) 199{ 200 int err; 201 uintptr_t load_addr; 202 enum img_type ret_file_type; 203 Elf64_Ehdr header = {0}; 204 err = get_guest_image_type(kernel_image_name, &ret_file_type, &header); 205 if (err) { 206 return NULL; 207 } 208 /* Determine the load address */ 209 switch (ret_file_type) { 210 case IMG_BIN: 211 if (config_set(CONFIG_PLAT_TX1) || config_set(CONFIG_PLAT_TX2) || config_set(CONFIG_PLAT_QEMU_ARM_VIRT) 212 || config_set(CONFIG_PLAT_ODROIDC2)) { 213 /* This is likely an aarch64/aarch32 linux difference */ 214 load_addr = load_base_addr + 0x80000; 215 } else { 216 load_addr = load_base_addr + 0x8000; 217 } 218 break; 219 case IMG_ZIMAGE: 220 load_addr = zImage_get_load_address(&header, load_base_addr); 221 break; 222 default: 223 ZF_LOGE("Error: Unknown Linux image format for \'%s\'", kernel_image_name); 224 return NULL; 225 } 226 err = load_image(vm, kernel_image_name, load_addr, image_size); 227 if (err) { 228 return NULL; 229 } 230 return (void *)load_addr; 231} 232 233static void *load_guest_module_image(vm_t *vm, const char *image_name, uintptr_t load_base_addr, size_t *image_size) 234{ 235 int err; 236 uintptr_t load_addr; 237 enum img_type ret_file_type; 238 Elf64_Ehdr header = {0}; 239 err = get_guest_image_type(image_name, &ret_file_type, &header); 240 if (err) { 241 return NULL; 242 } 243 /* Determine the load address */ 244 switch (ret_file_type) { 245 case IMG_DTB: 246 case IMG_INITRD_GZ: 247 load_addr = load_base_addr; 248 break; 249 default: 250 ZF_LOGE("Error: Unknown Linux image format for \'%s\'", image_name); 251 return NULL; 252 } 253 err = load_image(vm, image_name, load_addr, image_size); 254 if (err) { 255 return NULL; 256 } 257 return (void *)load_addr; 258} 259 260int vm_load_guest_kernel(vm_t *vm, const char *kernel_name, uintptr_t load_address, size_t alignment, 261 guest_kernel_image_t *guest_kernel_image) 262{ 263 void *load_addr; 264 size_t kernel_len; 265 if (!guest_kernel_image) { 266 ZF_LOGE("Invalid guest_image_t object"); 267 return -1; 268 } 269 load_addr = load_guest_kernel_image(vm, kernel_name, load_address, &kernel_len); 270 if (!load_addr) { 271 return -1; 272 } 273 guest_kernel_image->kernel_image.load_paddr = (uintptr_t)load_addr; 274 guest_kernel_image->kernel_image.size = kernel_len; 275 return 0; 276} 277 278int vm_load_guest_module(vm_t *vm, const char *module_name, uintptr_t load_address, size_t alignment, 279 guest_image_t *guest_image) 280{ 281 void *load_addr; 282 size_t module_len; 283 284 if (!guest_image) { 285 ZF_LOGE("Invalid guest_image_t object"); 286 return -1; 287 } 288 289 load_addr = load_guest_module_image(vm, module_name, load_address, &module_len); 290 if (!load_addr) { 291 return -1; 292 } 293 294 guest_image->load_paddr = (uintptr_t)load_addr; 295 guest_image->size = module_len; 296 return 0; 297} 298