1 /*
2 * Copyright (c) 2021 - 2022, Intel Corporation.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Intel Corporation nor the names of its
15 * contributors may be used to endorse or promote products
16 * derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Library to support ACRN HV booting with Slim Bootloader container
35 *
36 */
37
38 #include <elf.h>
39 #include <efi.h>
40 #include <efilib.h>
41 #include "boot.h"
42 #include "stdlib.h"
43 #include "efilinux.h"
44 #include "multiboot.h"
45 #include "container.h"
46 #include "elf32.h"
47
48 #define LZH_BOOT_CMD 0u
49 #define LZH_BOOT_IMG 1u
50 #define LZH_MOD0_CMD 2u
51
52 #define MAX_BOOTCMD_SIZE (2048 + 256) /* Max linux command line size plus uefi boot options */
53 #define MAX_MODULE_COUNT 32
54
55 typedef struct multiboot2_header_tag_relocatable RELOC_INFO;
56 typedef struct multiboot2_header_tag_address LADDR_INFO;
57
58 typedef struct {
59 UINT32 Signature;
60 UINT8 Version;
61 UINT8 Svn;
62 UINT16 DataOffset;
63 UINT32 DataSize;
64 UINT8 AuthType;
65 UINT8 ImageType;
66 UINT8 Flags;
67 UINT8 Count;
68 } CONTAINER_HDR;
69
70 typedef struct {
71 UINT32 Name;
72 UINT32 Offset;
73 UINT32 Size;
74 UINT8 Attribute;
75 UINT8 Alignment;
76 UINT8 AuthType;
77 UINT8 HashSize;
78 UINT8 HashData[0];
79 } COMPONENT_ENTRY;
80
81 typedef struct {
82 UINT32 Signature;
83 UINT32 CompressedSize;
84 UINT32 Size;
85 UINT16 Version;
86 UINT8 Svn;
87 UINT8 Attribute;
88 UINT8 Data[];
89 } LOADER_COMPRESSED_HEADER;
90
91 struct container {
92 struct hv_loader ops; /* loader operation table */
93
94 UINT8 mb_version; /* multiboot version of hv image. Can be either 1 or 2. */
95
96 CHAR16 *options; /* uefi boot option passed by efibootmgr -u */
97 UINT32 options_size; /* length of UEFI boot option */
98 char boot_cmd[MAX_BOOTCMD_SIZE]; /* hv boot command line */
99 UINTN boot_cmdsize; /* length of boot command to pass hypervisor */
100
101 EFI_PHYSICAL_ADDRESS hv_hpa; /* start of memory stored hv image */
102 EFI_PHYSICAL_ADDRESS mod_hpa; /* start of memory stored module files */
103 EFI_PHYSICAL_ADDRESS hv_entry; /* entry point of hv */
104 RELOC_INFO *reloc; /* relocation info */
105 LADDR_INFO *laddr; /* load address info */
106 UINT32 est_hv_ram_size; /* estimated hv ram size when load address info is NULL. */
107
108 MB_MODULE_INFO mod_info[MAX_MODULE_COUNT]; /* modules info */
109 UINTN mod_count; /* num of modules */
110 UINTN total_modsize; /* memory size allocated to load modules */
111 UINTN total_modcmdsize; /* memory size to store module commands */
112
113 UINTN lzh_count; /* num of files in container */
114 LOADER_COMPRESSED_HEADER *lzh_ptr[]; /* cache of each file header in container */
115 };
116
117 /**
118 * @brief Load acrn.32.out ELF file. If the hv_ram_start and hv_ram_size are both zero,
119 * these two parameters will be obtained from the ELF header.
120 *
121 * @param[in] elf_image ELF image
122 * @param[out] hv_hpa The physical memory address the relocated hypervisor is stored
123 * @param[in] hv_ram_start The link address of the hv, e.g. the address used in a linker script.
124 * @param[in,out] hv_ram_size A pointer to the size of the hv image. If the value of *hv_ram_size and hv_ram_start is 0,
125 * *hv_ram_size will be updated to reflect a conservative estimate of hv_ram_size from ELF header.
126 * @param[in] reloc A pointer to the relocation information. Can be NULL.
127 *
128 * @return EFI_SUCCESS(0) on success, non-zero on error
129 */
load_acrn_elf(const UINT8 * elf_image,EFI_PHYSICAL_ADDRESS * hv_hpa,UINT32 hv_ram_start,UINT32 * hv_ram_size,const RELOC_INFO * reloc)130 static EFI_STATUS load_acrn_elf(const UINT8 *elf_image, EFI_PHYSICAL_ADDRESS *hv_hpa,
131 UINT32 hv_ram_start, UINT32 *hv_ram_size, const RELOC_INFO *reloc)
132 {
133 EFI_STATUS err = EFI_SUCCESS;
134
135 if (validate_elf_header((Elf32_Ehdr *)elf_image) < 0) {
136 err = EFI_LOAD_ERROR;
137 goto out;
138 }
139
140 if (hv_ram_start == 0 && *hv_ram_size == 0) {
141 UINT64 ram_low, ram_high;
142
143 if (elf_calc_link_addr_range((Elf32_Ehdr *)elf_image, &ram_low, &ram_high) < 0) {
144 err = EFI_LOAD_ERROR;
145 goto out;
146 }
147
148 hv_ram_start = ram_low;
149 *hv_ram_size = ram_high - ram_low;
150
151 /* According to board_defconfig.py, the size required might include:
152 * hv_base_ram + post_launched_ram * postlaunched_num + ivshmem (if enabled).
153 * i.e., 20MB + 16MB * postlaunched_num + 2 * max(total_ivshmem, 0x200000)
154 *
155 * From bootloader we can only do conservative estimate. I.e., we will calculate
156 * using maximum possible number of postlaunched number and total_ivshmem.
157 */
158
159 /* 16MB * postlaunched_num */
160 *hv_ram_size += (16 * 1024 * 1024) * 7;
161
162 /* total size of ivshmem will be at least 2 * 200000. Here we double the region. */
163 *hv_ram_size += 4 * 0x200000;
164
165 /* Typically this can use memory up to 0xAA00000, compared to the size calculated
166 * for a typical hybrid_rt: 0x3800000.
167 *
168 * It might seemed a little bit wasteful but that's the best we can do without
169 * an address tag in multiboot header.
170 */
171 }
172
173 if (reloc) {
174 err = emalloc_reserved_aligned(hv_hpa, *hv_ram_size, reloc->align,
175 reloc->min_addr, reloc->max_addr);
176 }
177 else {
178 err = emalloc_fixed_addr(hv_hpa, *hv_ram_size, hv_ram_start);
179 }
180
181 if (err != EFI_SUCCESS) {
182 Print(L"Failed to allocate memory for ACRN HV %r\n", err);
183 goto out;
184 }
185
186 if (elf_load((Elf32_Ehdr *)elf_image, *hv_hpa, hv_ram_start) < 0) {
187 err = EFI_LOAD_ERROR;
188 goto out;
189 }
190
191 out:
192 return err;
193 }
194
parse_boot_image(const UINT8 * data,EFI_PHYSICAL_ADDRESS * hv_entry,UINT8 * mb_version,LADDR_INFO ** laddr,RELOC_INFO ** reloc,const void ** mb_header)195 static int parse_boot_image(const UINT8 *data, EFI_PHYSICAL_ADDRESS *hv_entry,
196 UINT8 *mb_version, LADDR_INFO **laddr, RELOC_INFO **reloc, const void **mb_header)
197 {
198 const void *mb_hdr;
199 UINT8 mbver = 0;
200
201 mb_hdr = find_mb2header(data, MULTIBOOT2_SEARCH);
202 if (mb_hdr) {
203 struct hv_mb2header_tag_list hv_tags;
204 mbver = 2;
205 if (parse_mb2header(mb_hdr, &hv_tags) < 0) {
206 Print(L"Illegal multiboot2 header tags\n");
207 return -1;
208 }
209
210 if (hv_tags.addr) *laddr = hv_tags.addr;
211 if (hv_tags.entry) *hv_entry = hv_tags.entry->entry_addr;
212 if (hv_tags.reloc) *reloc = hv_tags.reloc;
213 } else {
214 mb_hdr = (struct multiboot_header *)find_mb1header(data, MULTIBOOT_SEARCH);
215 if (!mb_hdr) {
216 Print(L"Image is not multiboot compatible\n");
217 return -1;
218 }
219 mbver = 1;
220 }
221
222 *mb_version = mbver;
223 *mb_header = mb_hdr;
224
225 return 0;
226 }
227
228 /**
229 * @brief Load hypervisor into memory from a container blob
230 *
231 * @param[in] hvld Loader handle
232 *
233 * @return EFI_SUCCESS(0) on success, non-zero on error
234 */
container_load_boot_image(HV_LOADER hvld)235 static EFI_STATUS container_load_boot_image(HV_LOADER hvld)
236 {
237 int i;
238 EFI_STATUS err = EFI_SUCCESS;
239 struct container *ctr = (struct container *)hvld;
240 const void *mb_hdr;
241
242 LOADER_COMPRESSED_HEADER *lzh = NULL;
243
244 /* prepare boot command line: stitched from hv_cmdline.txt and argument from efibootmgr -u */
245 lzh = ctr->lzh_ptr[LZH_BOOT_CMD];
246 ctr->boot_cmdsize = lzh->Size + StrnLen(ctr->options, ctr->options_size);
247 if (ctr->boot_cmdsize >= MAX_BOOTCMD_SIZE) {
248 Print(L"Boot command size 0x%x exceeding limit 0x%x\n", ctr->boot_cmdsize, MAX_BOOTCMD_SIZE);
249 return EFI_INVALID_PARAMETER;
250 }
251 memcpy(ctr->boot_cmd, (const char *)lzh->Data, lzh->Size - 1);
252 if (ctr->options) {
253 ctr->boot_cmd[lzh->Size - 1] = ' ';
254 for (i = lzh->Size; i < ctr->boot_cmdsize; i++) {
255 ctr->boot_cmd[i] = ctr->options[i - lzh->Size];
256 }
257 }
258
259 /* parse and load boot image */
260 lzh = ctr->lzh_ptr[LZH_BOOT_IMG];
261
262 if (parse_boot_image((const UINT8 *)lzh->Data, &ctr->hv_entry, &ctr->mb_version,
263 &ctr->laddr, &ctr->reloc, &mb_hdr) < 0) {
264 err = EFI_INVALID_PARAMETER;
265 goto out;
266 }
267
268 if (ctr->mb_version == 2) {
269 /* Multiboot 2 */
270 if (!ctr->laddr) {
271 /* GRUB will fail if the elf image contains ".rela" section. We simply ignore it. */
272 UINT32 hv_ram_size = 0;
273 err = load_acrn_elf(lzh->Data, &ctr->hv_hpa, 0, &hv_ram_size, ctr->reloc);
274 ctr->est_hv_ram_size = hv_ram_size;
275 ctr->hv_entry = elf_get_entry((Elf32_Ehdr *)lzh->Data);
276 } else {
277 /*
278 * Multiboot2 specs address tag contains only one pair of load address and end address, which implies that
279 * the text and data segments in image must be consecutive. This is true for the a.out binary format
280 * but not the ELF format.
281 *
282 * We can either implement a "load_acrn_binary" to substitute load_acrn_elf here and tell people
283 * to use a flat binary (acrn.bin), or left it untouched and tell people to use an ELF (which is
284 * what we're doing now).
285 */
286 UINT32 load_addr = ctr->laddr->load_addr;
287 UINT32 load_size = ctr->laddr->load_end_addr - ctr->laddr->load_addr;
288
289 err = load_acrn_elf(lzh->Data, &ctr->hv_hpa, load_addr, &load_size, ctr->reloc);
290 }
291
292 if (err != EFI_SUCCESS) {
293 Print(L"Failed to load ACRN HV ELF Image%r\n", err);
294 goto out;
295 }
296
297 /* Fix up entry address */
298 if (ctr->reloc) {
299 ctr->hv_entry += (ctr->hv_hpa >= ctr->laddr->load_addr) ?
300 ctr->hv_hpa - ctr->laddr->load_addr :
301 ctr->laddr->load_addr - ctr->hv_hpa;
302 }
303 } else {
304 /* Multiboot 1. We don't do relocation for MB1 case. The ".rela" section will be ignored. */
305 /* TODO: add support for the case when AOUT_KLUDGE flag is set */
306 UINT32 hv_ram_size = 0;
307 err = load_acrn_elf(lzh->Data, &ctr->hv_hpa, 0, &hv_ram_size, NULL);
308 if (err != EFI_SUCCESS) {
309 Print(L"Failed to load ACRN HV ELF Image%r\n", err);
310 goto out;
311 }
312 ctr->est_hv_ram_size = hv_ram_size;
313 ctr->hv_entry = elf_get_entry((Elf32_Ehdr *)lzh->Data);
314 }
315
316 out:
317 return err;
318 }
319
320 /**
321 * @brief Load kernel modules and acpi tables into memory from a container blob
322 *
323 * @param[in] hvld Loader handle
324 *
325 * @return EFI_SUCCESS(0) on success, non-zero on error
326 */
container_load_modules(HV_LOADER hvld)327 static EFI_STATUS container_load_modules(HV_LOADER hvld)
328 {
329 EFI_STATUS err = EFI_SUCCESS;
330 struct container *ctr = (struct container *)hvld;
331
332 UINTN i, j;
333
334 UINT8 * p = NULL;
335 LOADER_COMPRESSED_HEADER *lzh = NULL;
336 LOADER_COMPRESSED_HEADER *cmd_lzh = NULL;
337
338 /* scan module headers to calculate required memory size to store files */
339 for (i = LZH_MOD0_CMD; i < ctr->lzh_count - 1; i++) {
340 if ((i % 2) == 0) { /* vm0_tag.txt, vm1_tag.txt, acpi_vm0.txt ... */
341 ctr->total_modcmdsize += ctr->lzh_ptr[i]->Size;
342 } else { /* vm0_kernel, vm1_kernel, vm0_acpi.bin ... */
343 ctr->total_modsize += ALIGN_UP(ctr->lzh_ptr[i]->Size, EFI_PAGE_SIZE);
344 }
345 }
346 /* exclude hypervisor and SBL signature files. e.g.)
347 * lzh_count = 9 (hv_cmdline, acrn.32.out, vm0_tag, vm0_kernel, vm1_tag, vm1_kernel, vm0_acpi_tag, vm0_acpi, sig)
348 * mod_count = 3 (vm0_tag + vm0_kernel, vm1_tag + vm1_kernel, vm0_acpi_tag + vm0_acpi)
349 */
350 ctr->mod_count = (ctr->lzh_count - 3) / 2;
351
352 if (ctr->mod_count >= MAX_MODULE_COUNT) {
353 Print(L"Too many modules: 0x%x\n", ctr->mod_count);
354 return EFI_INVALID_PARAMETER;
355 }
356
357 /* allocate single memory region to store all binary files to avoid mmap fragmentation */
358 if (ctr->reloc) {
359 err = emalloc_reserved_aligned(&(ctr->mod_hpa), ctr->total_modsize,
360 EFI_PAGE_SIZE, ctr->reloc->min_addr, ctr->reloc->max_addr);
361 } else {
362 /* We put modules after hv */
363 UINTN hv_ram_size = ctr->laddr->load_end_addr - ctr->laddr->load_addr;
364 err = emalloc_fixed_addr(&(ctr->mod_hpa), hv_ram_size, ctr->hv_hpa + ALIGN_UP(hv_ram_size, EFI_PAGE_SIZE));
365 }
366 if (err != EFI_SUCCESS) {
367 Print(L"Failed to allocate memory for modules %r\n", err);
368 goto out;
369 }
370
371 p = (UINT8 *)ctr->mod_hpa;
372 for (i = LZH_BOOT_IMG + 2, j = 0; i < ctr->lzh_count - 1; i = i + 2) {
373 lzh = ctr->lzh_ptr[i];
374 cmd_lzh = ctr->lzh_ptr[i - 1];
375 memcpy((char *)p, (const char *)lzh->Data, lzh->Size);
376 ctr->mod_info[j].mod_start = (EFI_PHYSICAL_ADDRESS)p;
377 ctr->mod_info[j].mod_end = (EFI_PHYSICAL_ADDRESS)p + lzh->Size;
378 ctr->mod_info[j].cmd = (const char *)cmd_lzh->Data;
379 ctr->mod_info[j].cmdsize = cmd_lzh->Size;
380 p += ALIGN_UP(lzh->Size, EFI_PAGE_SIZE);
381 j++;
382 }
383
384 out:
385 return err;
386 }
387
388 /**
389 * @brief Get hypervisor boot commandline.
390 *
391 * @param[in] hvld Loader handle
392 *
393 * @return Hypervisor boot command line.
394 */
container_get_boot_cmd(HV_LOADER hvld)395 static const char *container_get_boot_cmd(HV_LOADER hvld)
396 {
397 return ((struct container *)hvld)->boot_cmd;
398 }
399
400 /**
401 * @brief Get hypervisor boot command length
402 *
403 * @param[in] hvld Loader handle
404 *
405 * @return the length of hypervisor boot command
406 */
container_get_boot_cmdsize(HV_LOADER hvld)407 static UINTN container_get_boot_cmdsize(HV_LOADER hvld)
408 {
409 /* boot_cmd = hv_cmdline.txt in container + extra arg given by the 'efibootmgr -u' option */
410 return ((struct container *)hvld)->boot_cmdsize;
411 }
412
413 /**
414 * @brief Get boot module info
415 *
416 * @param[in] hvld Loader handle
417 * @param[in] index index to the list of boot modules
418 *
419 * @return the boot module info at index
420 */
container_get_mods_info(HV_LOADER hvld,UINTN index)421 static MB_MODULE_INFO *container_get_mods_info(HV_LOADER hvld, UINTN index)
422 {
423 return &(((struct container *)hvld)->mod_info)[index];
424 }
425
426 /**
427 * @brief Get the number of multiboot2 modules
428 *
429 * @param[in] hvld Loader handle
430 *
431 * @return the number of multiboot2 modules
432 */
container_get_mod_count(HV_LOADER hvld)433 static UINTN container_get_mod_count(HV_LOADER hvld)
434 {
435 return ((struct container *)hvld)->mod_count;
436 }
437
438 /**
439 * @brief Get the total memory size allocated to load module files
440 *
441 * @param[in] hvld Loader handle
442 *
443 * @return the total size of memory allocated to store the module files
444 */
container_get_total_modsize(HV_LOADER hvld)445 static UINTN container_get_total_modsize(HV_LOADER hvld)
446 {
447 return ((struct container *)hvld)->total_modsize;
448 }
449
450 /**
451 * @brief Get the total lengths of the module commands
452 *
453 * @param[in] hvld Loader handle
454 *
455 * @return the total lengths of module command files
456 */
container_get_total_modcmdsize(HV_LOADER hvld)457 static UINTN container_get_total_modcmdsize(HV_LOADER hvld)
458 {
459 return ((struct container *)hvld)->total_modcmdsize;
460 }
461
462 /**
463 * @brief Get the start address of the memory region stored ACRN hypervisor image
464 *
465 * @param[in] hvld Loader handle
466 *
467 * @return the address of hv image
468 */
container_get_hv_hpa(HV_LOADER hvld)469 static EFI_PHYSICAL_ADDRESS container_get_hv_hpa(HV_LOADER hvld)
470 {
471 return ((struct container *)hvld)->hv_hpa;
472 }
473
474 /**
475 * @brief Get the start address of the memory region stored module files
476 *
477 * @param[in] hvld Loader handle
478 *
479 * @return the address of modules
480 */
container_get_mod_hpa(HV_LOADER hvld)481 static EFI_PHYSICAL_ADDRESS container_get_mod_hpa(HV_LOADER hvld)
482 {
483 return ((struct container *)hvld)->mod_hpa;
484 }
485
486 /**
487 * @brief Get the supported multiboot version of ACRN hypervisor image
488 *
489 * @param[in] hvld Loader handle
490 *
491 * @return supported multiboot version. Can be either 1 or 2.
492 */
container_get_multiboot_version(HV_LOADER hvld)493 static int container_get_multiboot_version(HV_LOADER hvld)
494 {
495 return ((struct container *)hvld)->mb_version;
496 }
497
498 /**
499 * @brief Get the entry point of ACRN hypervisor
500 *
501 * @param[in] hvld Loader handle
502 *
503 * @return the entry point of hypervisor
504 */
container_get_hv_entry(HV_LOADER hvld)505 static EFI_PHYSICAL_ADDRESS container_get_hv_entry(HV_LOADER hvld)
506 {
507 return ((struct container *)hvld)->hv_entry;
508 }
509
510 /**
511 * @brief Get the total memory size of hv image
512 *
513 * @param[in] hvld Loader handle
514 *
515 * @return the memory size of hv image
516 */
container_get_hv_ram_size(HV_LOADER hvld)517 static UINTN container_get_hv_ram_size(HV_LOADER hvld)
518 {
519 struct container *ctr = (struct container *)hvld;
520 if (ctr->laddr) {
521 return ctr->laddr->load_end_addr - ctr->laddr->load_addr;
522 }
523
524 return ctr->est_hv_ram_size;
525 }
526
527 /**
528 * @brief Free up memory allocated by the container loader
529 *
530 * @param[in] hvld Loader handle
531 */
container_deinit(HV_LOADER hvld)532 static void container_deinit(HV_LOADER hvld)
533 {
534 struct container *ctr = (struct container *)hvld;
535
536 if (ctr->lzh_ptr) {
537 free_pool(ctr->lzh_ptr);
538 free_pool(ctr);
539 }
540
541 if (ctr->mod_hpa) {
542 free_pages(ctr->mod_hpa, EFI_SIZE_TO_PAGES(ctr->total_modsize));
543 }
544 }
545
546 /* hypervisor loader operation table */
547 static struct hv_loader container_ops = {
548 .load_boot_image = container_load_boot_image,
549 .load_modules = container_load_modules,
550 .get_boot_cmd = container_get_boot_cmd,
551 .get_boot_cmdsize = container_get_boot_cmdsize,
552 .get_mods_info = container_get_mods_info,
553 .get_total_modsize = container_get_total_modsize,
554 .get_total_modcmdsize = container_get_total_modcmdsize,
555 .get_mod_count = container_get_mod_count,
556 .get_hv_hpa = container_get_hv_hpa,
557 .get_mod_hpa = container_get_mod_hpa,
558 .get_hv_entry = container_get_hv_entry,
559 .get_multiboot_version = container_get_multiboot_version,
560 .get_hv_ram_size = container_get_hv_ram_size,
561 .deinit = container_deinit,
562 };
563
564 /**
565 * @brief Initialize Container Library and returned the loader operation table
566 *
567 * @param[in] info Firmware-allocated handle that identifies the EFI application image (i.e. acrn.efi)
568 * @param[out] info Allocated loader operation table
569 *
570 * @return EFI_SUCCESS(0) on success, non-zero on error
571 */
container_init(EFI_LOADED_IMAGE * info,HV_LOADER * hvld)572 EFI_STATUS container_init(EFI_LOADED_IMAGE *info, HV_LOADER *hvld)
573 {
574 EFI_STATUS err = EFI_SUCCESS;
575
576 struct container *ctr = NULL;
577
578 UINTN sec_addr = 0u;
579 UINTN sec_size = 0u;
580 char *section = ".hv";
581
582 UINTN i;
583 CONTAINER_HDR *hdr = NULL;
584 COMPONENT_ENTRY *comp = NULL;
585
586 UINTN offset = 0u;
587
588 err = allocate_pool(EfiLoaderData, sizeof(struct container), (void **)&ctr);
589 if (EFI_ERROR(err)) {
590 Print(L"Failed to allocate memory for Container Library %r\n", err);
591 goto out;
592 }
593
594 (void)memset((void *)ctr, 0x0, sizeof(struct container));
595 memcpy((char *)&ctr->ops, (const char *)&container_ops, sizeof(struct hv_loader));
596
597 /* store the options */
598 ctr->options = info->LoadOptions;
599 ctr->options_size = info->LoadOptionsSize;
600
601 /* read a container stitched at the .hv section */
602 err = get_pe_section(info->ImageBase, section, strlen(section), &sec_addr, &sec_size);
603 if (EFI_ERROR(err)) {
604 Print(L"Unable to locate section of ACRNHV Container %r ", err);
605 goto out;
606 }
607
608 hdr = (CONTAINER_HDR*)(info->ImageBase + sec_addr);
609 ctr->lzh_count = hdr->Count;
610
611 err = allocate_pool(EfiLoaderData, sizeof(LOADER_COMPRESSED_HEADER *) * hdr->Count, (void **)&ctr->lzh_ptr);
612 if (EFI_ERROR(err)) {
613 Print(L"Failed to allocate memory for Container Library %r\n", err);
614 goto out;
615 }
616
617 /* cache each file's header point for later use */
618 comp = (COMPONENT_ENTRY *)(hdr + 1);
619 for (i = 0; i < hdr->Count; i++) {
620 offset = hdr->DataOffset + comp->Offset;
621 ctr->lzh_ptr[i] = (LOADER_COMPRESSED_HEADER *)((UINT8 *)(hdr) + offset);
622
623 comp = (COMPONENT_ENTRY *)((UINT8 *)(comp + 1) + comp->HashSize);
624 }
625
626 *hvld = (struct hv_loader *)ctr;
627 out:
628 if (EFI_ERROR(err)) {
629 if (ctr) {
630 container_deinit((HV_LOADER)ctr);
631 }
632 }
633 return err;
634 }
635