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