1 /*
2  * Copyright (C) 2019-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <types.h>
8 #include <rtl.h>
9 #include <errno.h>
10 #include <asm/per_cpu.h>
11 #include <asm/irq.h>
12 #include <boot.h>
13 #include <asm/pgtable.h>
14 #include <asm/zeropage.h>
15 #include <asm/seed.h>
16 #include <asm/mmu.h>
17 #include <asm/guest/vm.h>
18 #include <asm/guest/ept.h>
19 #include <reloc.h>
20 #include <logmsg.h>
21 #include <vboot.h>
22 #include <vacpi.h>
23 
24 #define DBG_LEVEL_BOOT	6U
25 
26 /**
27  * @pre vm != NULL && mod != NULL
28  */
init_vm_ramdisk_info(struct acrn_vm * vm,const struct abi_module * mod)29 static void init_vm_ramdisk_info(struct acrn_vm *vm, const struct abi_module *mod)
30 {
31 	if (mod->start != NULL) {
32 		vm->sw.ramdisk_info.src_addr = mod->start;
33 		vm->sw.ramdisk_info.size = mod->size;
34 	}
35 
36 	dev_dbg(DBG_LEVEL_BOOT, "ramdisk mod start=0x%x, size=0x%x", (uint64_t)mod->start, mod->size);
37 }
38 
39 /**
40  * @pre vm != NULL && mod != NULL
41  */
init_vm_acpi_info(struct acrn_vm * vm,const struct abi_module * mod)42 static void init_vm_acpi_info(struct acrn_vm *vm, const struct abi_module *mod)
43 {
44 	vm->sw.acpi_info.src_addr = mod->start;
45 	vm->sw.acpi_info.load_addr = (void *)VIRT_ACPI_DATA_ADDR;
46 	vm->sw.acpi_info.size = ACPI_MODULE_SIZE;
47 }
48 
49 /**
50  * @pre vm != NULL && mod != NULL
51  */
init_vm_kernel_info(struct acrn_vm * vm,const struct abi_module * mod)52 static int32_t init_vm_kernel_info(struct acrn_vm *vm, const struct abi_module *mod)
53 {
54 	int32_t ret = -EINVAL;
55 	struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
56 
57 	dev_dbg(DBG_LEVEL_BOOT, "kernel mod start=0x%x, size=0x%x",
58 			(uint64_t)mod->start, mod->size);
59 
60 	vm->sw.kernel_type = vm_config->os_config.kernel_type;
61 	if ((mod->start != NULL) && (mod->size != 0U)) {
62 		vm->sw.kernel_info.kernel_src_addr = mod->start;
63 		vm->sw.kernel_info.kernel_size = mod->size;
64 		if ((vm->sw.kernel_type > 0) && (vm->sw.kernel_type < KERNEL_UNKNOWN)) {
65 			ret = 0;
66 		} else {
67 			pr_err("Unsupported Kernel type.");
68 		}
69 	}
70 
71 	return ret;
72 }
73 
74 /* cmdline parsed from abi module string, for pre-launched VMs and Service VM only. */
75 static char mod_cmdline[PRE_VM_NUM + SERVICE_VM_NUM][MAX_BOOTARGS_SIZE] = { 0 };
76 
77 /**
78  * @pre vm != NULL && abi != NULL
79  */
init_vm_bootargs_info(struct acrn_vm * vm,const struct acrn_boot_info * abi)80 static void init_vm_bootargs_info(struct acrn_vm *vm, const struct acrn_boot_info *abi)
81 {
82 	struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
83 
84 	vm->sw.bootargs_info.src_addr = vm_config->os_config.bootargs;
85 	/* If module string of the kernel module exists, it would OVERRIDE the pre-configured build-in VM bootargs,
86 	 * which means we give user a chance to re-configure VM bootargs at bootloader runtime. e.g. GRUB menu
87 	 */
88 	if (mod_cmdline[vm->vm_id][0] != '\0') {
89 		vm->sw.bootargs_info.src_addr = &mod_cmdline[vm->vm_id][0];
90 	}
91 
92 	if (vm_config->load_order == SERVICE_VM) {
93 		if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE, " ", 1U) == 0) {
94 			char seed_args[MAX_SEED_ARG_SIZE] = "";
95 
96 			fill_seed_arg(seed_args, MAX_SEED_ARG_SIZE);
97 			/* Fill seed argument for Service VM
98 			 * seed_args string ends with a white space and '\0', so no additional delimiter is needed
99 			 */
100 			if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE,
101 					seed_args, (MAX_BOOTARGS_SIZE - 1U)) != 0) {
102 				pr_err("failed to fill seed arg to Service VM bootargs!");
103 			}
104 
105 			/* If there is cmdline from abi->cmdline, merge it with configured Service VM bootargs.
106 			 * This is very helpful when one of configured bootargs need to be revised at GRUB runtime
107 			 * (e.g. "root="), since the later one would override the previous one if multiple bootargs exist.
108 			 */
109 			if (abi->cmdline[0] != '\0') {
110 				if (strncat_s((char *)vm->sw.bootargs_info.src_addr, MAX_BOOTARGS_SIZE,
111 						abi->cmdline, (MAX_BOOTARGS_SIZE - 1U)) != 0) {
112 					pr_err("failed to merge mbi cmdline to Service VM bootargs!");
113 				}
114 			}
115 		} else {
116 			pr_err("no space to append Service VM bootargs!");
117 		}
118 
119 	}
120 
121 	vm->sw.bootargs_info.size = strnlen_s((const char *)vm->sw.bootargs_info.src_addr, (MAX_BOOTARGS_SIZE - 1U)) + 1U;
122 
123 }
124 
125 /* @pre abi != NULL && tag != NULL
126  */
get_mod_by_tag(const struct acrn_boot_info * abi,const char * tag)127 struct abi_module *get_mod_by_tag(const struct acrn_boot_info *abi, const char *tag)
128 {
129 	uint32_t i;
130 	struct abi_module *mod = NULL;
131 	struct abi_module *mods = (struct abi_module *)(&abi->mods[0]);
132 	uint32_t tag_len = strnlen_s(tag, MAX_MOD_TAG_LEN);
133 
134 	for (i = 0U; i < abi->mods_count; i++) {
135 		const char *string = (char *)hpa2hva((uint64_t)(mods + i)->string);
136 		uint32_t str_len = strnlen_s(string, MAX_MOD_TAG_LEN);
137 		const char *p_chr = string + tag_len; /* point to right after the end of tag */
138 
139 		/* The tag must be located at the first word in string and end with SPACE/TAB or EOL since
140 		 * when do file stitch by tool, the tag in string might be followed by EOL(0x0d/0x0a).
141 		 */
142 		if ((str_len >= tag_len) && (strncmp(string, tag, tag_len) == 0)
143 				&& (is_space(*p_chr) || is_eol(*p_chr))) {
144 			mod = mods + i;
145 			break;
146 		}
147 	}
148 	/* GRUB might put module at address 0 or under 1MB in the case that the module size is less then 1MB
149 	 * ACRN will not support these cases
150 	 */
151 	if ((mod != NULL) && (mod->start == NULL)) {
152 		pr_err("Unsupported module: start at HPA 0, size 0x%x .", mod->size);
153 		mod = NULL;
154 	}
155 
156 	return mod;
157 }
158 
159 /* @pre vm != NULL && abi != NULL
160  */
init_vm_sw_load(struct acrn_vm * vm,const struct acrn_boot_info * abi)161 static int32_t init_vm_sw_load(struct acrn_vm *vm, const struct acrn_boot_info *abi)
162 {
163 	struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
164 	struct abi_module *mod;
165 	int32_t ret = -EINVAL;
166 
167 	dev_dbg(DBG_LEVEL_BOOT, "mod counts=%d\n", abi->mods_count);
168 
169 	/* find kernel module first */
170 	mod = get_mod_by_tag(abi, vm_config->os_config.kernel_mod_tag);
171 	if (mod != NULL) {
172 		const char *string = (char *)hpa2hva((uint64_t)mod->string);
173 		uint32_t str_len = strnlen_s(string, MAX_BOOTARGS_SIZE);
174 		uint32_t tag_len = strnlen_s(vm_config->os_config.kernel_mod_tag, MAX_MOD_TAG_LEN);
175 		const char *p_chr = string + tag_len + 1; /* point to the possible start of cmdline */
176 
177 		/* check whether there is a cmdline configured in module string */
178 		if (((str_len > (tag_len + 1U))) && (is_space(*(p_chr - 1))) && (!is_eol(*p_chr))) {
179 			(void)strncpy_s(&mod_cmdline[vm->vm_id][0], MAX_BOOTARGS_SIZE,
180 					p_chr, (MAX_BOOTARGS_SIZE - 1U));
181 		}
182 
183 		ret = init_vm_kernel_info(vm, mod);
184 	}
185 
186 	if (ret == 0) {
187 		init_vm_bootargs_info(vm, abi);
188 
189 		/* check whether there is a ramdisk module */
190 		mod = get_mod_by_tag(abi, vm_config->os_config.ramdisk_mod_tag);
191 		if (mod != NULL) {
192 			init_vm_ramdisk_info(vm, mod);
193 		}
194 
195 		if (is_prelaunched_vm(vm)) {
196 			mod = get_mod_by_tag(abi, vm_config->acpi_config.acpi_mod_tag);
197 			if ((mod != NULL) && (mod->size == ACPI_MODULE_SIZE)) {
198 				init_vm_acpi_info(vm, mod);
199 			} else {
200 				pr_err("failed to load VM %d acpi module", vm->vm_id);
201 			}
202 		}
203 
204 	} else {
205 		pr_err("failed to load VM %d kernel module", vm->vm_id);
206 	}
207 	return ret;
208 }
209 
210 /**
211  * @param[inout] vm pointer to a vm descriptor
212  *
213  * @retval 0 on success
214  * @retval -EINVAL on invalid parameters
215  *
216  * @pre vm != NULL
217  */
init_vm_boot_info(struct acrn_vm * vm)218 int32_t init_vm_boot_info(struct acrn_vm *vm)
219 {
220 	struct acrn_boot_info *abi = get_acrn_boot_info();
221 	int32_t ret = -EINVAL;
222 
223 	stac();
224 	ret = init_vm_sw_load(vm, abi);
225 	clac();
226 
227 	return ret;
228 }
229