1 /*
2  * Copyright (C) 2020-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <types.h>
8 #include <errno.h>
9 #include <boot.h>
10 #include <asm/pgtable.h>
11 #include "multiboot_priv.h"
12 
13 /**
14  * @pre abi != NULL && mb2_tag_mmap != NULL
15  */
mb2_mmap_to_abi(struct acrn_boot_info * abi,const struct multiboot2_tag_mmap * mb2_tag_mmap)16 static void mb2_mmap_to_abi(struct acrn_boot_info *abi, const struct multiboot2_tag_mmap *mb2_tag_mmap)
17 {
18 	uint32_t i;
19 	struct multiboot2_mmap_entry *mb2_mmap = (struct multiboot2_mmap_entry *)mb2_tag_mmap->entries;
20 
21 	/* multiboot2 mmap tag header occupied 16 bytes */
22 	abi->mmap_entries = (mb2_tag_mmap->size - 16U) / sizeof(struct multiboot2_mmap_entry);
23 	if (abi->mmap_entries > MAX_MMAP_ENTRIES) {
24 		abi->mmap_entries = MAX_MMAP_ENTRIES;
25 	}
26 
27 	for (i = 0U; i < abi->mmap_entries; i++) {
28 		abi->mmap_entry[i].baseaddr = (mb2_mmap + i)->addr;
29 		abi->mmap_entry[i].length = (mb2_mmap + i)->len;
30 		abi->mmap_entry[i].type = (mb2_mmap + i)->type;
31 	}
32 }
33 
34 /**
35  * @pre abi != NULL && mb2_tag_mods != NULL
36  */
mb2_mods_to_abi(struct acrn_boot_info * abi,uint32_t mbi_mod_idx,const struct multiboot2_tag_module * mb2_tag_mods)37 static void mb2_mods_to_abi(struct acrn_boot_info *abi,
38 			uint32_t mbi_mod_idx, const struct multiboot2_tag_module *mb2_tag_mods)
39 {
40 	abi->mods[mbi_mod_idx].start = hpa2hva_early((uint64_t)mb2_tag_mods->mod_start);
41 	if (mb2_tag_mods->mod_end > mb2_tag_mods->mod_start) {
42 		abi->mods[mbi_mod_idx].size = mb2_tag_mods->mod_end - mb2_tag_mods->mod_start;
43 	}
44 
45 	(void)strncpy_s((void *)(abi->mods[mbi_mod_idx].string), MAX_MOD_STRING_SIZE,
46 		(char *)hpa2hva_early((uint64_t)mb2_tag_mods->cmdline),
47 		strnlen_s((char *)hpa2hva_early((uint64_t)mb2_tag_mods->cmdline), MAX_MOD_STRING_SIZE));
48 }
49 
50 /**
51  * @pre abi != NULL && mb2_tag_efi64 != 0
52  */
mb2_efi64_to_abi(struct acrn_boot_info * abi,const struct multiboot2_tag_efi64 * mb2_tag_efi64)53 static void mb2_efi64_to_abi(struct acrn_boot_info *abi, const struct multiboot2_tag_efi64 *mb2_tag_efi64)
54 {
55 	abi->uefi_info.systab = (uint32_t)(uint64_t)mb2_tag_efi64->pointer;
56 	abi->uefi_info.systab_hi = (uint32_t)((uint64_t)mb2_tag_efi64->pointer >> 32U);
57 }
58 
59 /**
60  * @pre abi != NULL && mb2_tag_efimmap != 0
61  */
mb2_efimmap_to_abi(struct acrn_boot_info * abi,const struct multiboot2_tag_efi_mmap * mb2_tag_efimmap)62 static void mb2_efimmap_to_abi(struct acrn_boot_info *abi,
63 			const struct multiboot2_tag_efi_mmap *mb2_tag_efimmap)
64 {
65 	abi->uefi_info.memdesc_size = mb2_tag_efimmap->descr_size;
66 	abi->uefi_info.memdesc_version = mb2_tag_efimmap->descr_vers;
67 	abi->uefi_info.memmap = (uint32_t)(uint64_t)mb2_tag_efimmap->efi_mmap;
68 	abi->uefi_info.memmap_size = mb2_tag_efimmap->size - 16U;
69 	/* Per multiboot2 spec, multiboot info is below 4GB space hence memmap_hi must be 0U. */
70 	abi->uefi_info.memmap_hi = (uint32_t)(((uint64_t)mb2_tag_efimmap->efi_mmap) >> 32U);
71 }
72 
73 /**
74  * @pre abi != NULL
75  */
multiboot2_to_acrn_bi(struct acrn_boot_info * abi,void * mb2_info)76 int32_t multiboot2_to_acrn_bi(struct acrn_boot_info *abi, void *mb2_info)
77 {
78 	int32_t ret = 0;
79 	struct multiboot2_tag *mb2_tag, *mb2_tag_end;
80 	uint32_t mb2_info_size = *(uint32_t *)mb2_info;
81 	uint32_t mod_idx = 0U;
82 	void *str;
83 
84 	/* The start part of multiboot2 info: total mbi size (4 bytes), reserved (4 bytes) */
85 	mb2_tag = (struct multiboot2_tag *)((uint8_t *)mb2_info + 8U);
86 	mb2_tag_end = (struct multiboot2_tag *)((uint8_t *)mb2_info + mb2_info_size);
87 
88 	while ((mb2_tag->type != MULTIBOOT2_TAG_TYPE_END) && (mb2_tag < mb2_tag_end)) {
89 		switch (mb2_tag->type) {
90 		case MULTIBOOT2_TAG_TYPE_CMDLINE:
91 			str = ((struct multiboot2_tag_string *)mb2_tag)->string;
92 			(void)strncpy_s((void *)(abi->cmdline), MAX_BOOTARGS_SIZE, str,
93 						strnlen_s(str, (MAX_BOOTARGS_SIZE - 1U)));
94 			break;
95 		case MULTIBOOT2_TAG_TYPE_MMAP:
96 			mb2_mmap_to_abi(abi, (const struct multiboot2_tag_mmap *)mb2_tag);
97 			break;
98 		case MULTIBOOT2_TAG_TYPE_MODULE:
99 			if (mod_idx < MAX_MODULE_NUM) {
100 				mb2_mods_to_abi(abi, mod_idx, (const struct multiboot2_tag_module *)mb2_tag);
101 				mod_idx++;
102 			}
103 			break;
104 		case MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME:
105 			str = ((struct multiboot2_tag_string *)mb2_tag)->string;
106 			(void)strncpy_s((void *)(abi->loader_name), MAX_LOADER_NAME_SIZE, str,
107 						strnlen_s(str, (MAX_LOADER_NAME_SIZE - 1U)));
108 			break;
109 		case MULTIBOOT2_TAG_TYPE_ACPI_NEW:
110 			abi->acpi_rsdp_va = ((struct multiboot2_tag_new_acpi *)mb2_tag)->rsdp;
111 			break;
112 		case MULTIBOOT2_TAG_TYPE_EFI64:
113 			mb2_efi64_to_abi(abi, (const struct multiboot2_tag_efi64 *)mb2_tag);
114 			break;
115 		case MULTIBOOT2_TAG_TYPE_EFI_MMAP:
116 			mb2_efimmap_to_abi(abi, (const struct multiboot2_tag_efi_mmap *)mb2_tag);
117 			break;
118 		default:
119 			if (mb2_tag->type > MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR) {
120 				ret = -EINVAL;
121 			}
122 			break;
123 		}
124 		if (mb2_tag->size == 0U) {
125 			ret = -EINVAL;
126 		}
127 
128 		if (ret != 0) {
129 			break;
130 		}
131 		/*
132 		 * tag->size does not include padding whearas each tag
133 		 * start at 8-bytes aligned address.
134 		 */
135 		mb2_tag = (struct multiboot2_tag *)((uint8_t *)mb2_tag
136 				+ ((mb2_tag->size + (MULTIBOOT2_INFO_ALIGN - 1U)) & ~(MULTIBOOT2_INFO_ALIGN - 1U)));
137 	}
138 
139 	abi->mods_count = mod_idx;
140 
141 	return ret;
142 }
143