1 /*-
2  * Copyright (c) 2018-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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  */
26 
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <sys/mman.h>
34 
35 #include "dm.h"
36 #include "vmmapi.h"
37 #include "sw_load.h"
38 #include "log.h"
39 
40 
41 /*                 ovmf binary layout:
42  *
43  * +--------------------------------------------------+ <--OVMF Top
44  * |             |offset: Top - 0x10 (reset vector)   |
45  * + SECFV       |------------------------------------+
46  * |             |other                               |
47  * +--------------------------------------------------+
48  * |                                                  |
49  * + FVMAIN_COMPACT                                   +
50  * |                                                  |
51  * +--------------------------------------------------+
52  * |                                                  |
53  * + NV data storage                                  +
54  * |                                                  |
55  * +--------------------------------------------------+ <--OVMF offset 0
56  */
57 
58 /* ovmf real entry is reset vector, which is (OVMF_TOP - 16) */
59 #define OVMF_TOP(ctx)		(4*GB)
60 
61 /* ovmf image size limit */
62 #define OVMF_SZ_LIMIT		(2*MB)
63 
64 /* ovmf split images size limit */
65 #define OVMF_VARS_SZ_LIMIT	(128*KB)
66 #define OVMF_CODE_SZ_LIMIT	(OVMF_SZ_LIMIT - OVMF_VARS_SZ_LIMIT)
67 
68 /* ovmf NV storage begins at offset 0 */
69 #define OVMF_NVSTORAGE_OFFSET	(OVMF_TOP(ctx) - ovmf_image_size())
70 
71 /* ovmf NV storage size */
72 #define OVMF_NVSTORAGE_SZ	(ovmf_file_name ? OVMF_VARS_SZ_LIMIT : ovmf_vars_size)
73 
74 /* located in the ROM area */
75 #define OVMF_E820_BASE		0x000EF000UL
76 
77 static char ovmf_path[STR_LEN];
78 static char ovmf_code_path[STR_LEN];
79 static char ovmf_vars_path[STR_LEN];
80 static size_t ovmf_size;
81 static size_t ovmf_code_size;
82 static size_t ovmf_vars_size;
83 static char *mmap_vars;
84 static bool writeback_nv_storage;
85 
86 extern int init_cmos_vrpmb(struct vmctx *ctx);
87 
88 size_t
ovmf_image_size(void)89 ovmf_image_size(void)
90 {
91 	size_t size = 0;
92 
93 	if (ovmf_file_name)
94 		size = ovmf_size;
95 	else if (ovmf_code_file_name && ovmf_vars_file_name)
96 		size = ovmf_code_size + ovmf_vars_size;
97 
98 	return size;
99 }
100 
101 int
acrn_parse_ovmf(char * arg)102 acrn_parse_ovmf(char *arg)
103 {
104 	int error = -1;
105 	char *str, *cp, *token;
106 
107 	if (strnlen(arg, STR_LEN) < STR_LEN) {
108 		str = cp = strdup(arg);
109 
110 		while ((token = strsep(&cp, ",")) != NULL) {
111 			if (!strcmp(token, "w")) {
112 				writeback_nv_storage = true;
113 			} else if (!strncmp(token, "code=", sizeof("code=") - 1)) {
114 				token += sizeof("code=") - 1;
115 				strncpy(ovmf_code_path, token, sizeof(ovmf_code_path));
116 				if (check_image(ovmf_code_path, OVMF_CODE_SZ_LIMIT,
117 						&ovmf_code_size) != 0)
118 					break;
119 				ovmf_code_file_name = ovmf_code_path;
120 				pr_notice("SW_LOAD: get ovmf code path %s, size 0x%lx\n",
121 					ovmf_code_path, ovmf_code_size);
122 			} else if (!strncmp(token, "vars=", sizeof("vars=") - 1)) {
123 				token += sizeof("vars=") - 1;
124 				strncpy(ovmf_vars_path, token, sizeof(ovmf_vars_path));
125 				if (check_image(ovmf_vars_path, OVMF_VARS_SZ_LIMIT,
126 						&ovmf_vars_size) != 0)
127 					break;
128 				ovmf_vars_file_name = ovmf_vars_path;
129 				pr_notice("SW_LOAD: get ovmf vars path %s, size 0x%lx\n",
130 					ovmf_vars_path, ovmf_vars_size);
131 			} else {
132 				strncpy(ovmf_path, token, sizeof(ovmf_path));
133 				if (check_image(ovmf_path, OVMF_SZ_LIMIT, &ovmf_size) != 0)
134 					break;
135 				ovmf_file_name = ovmf_path;
136 				pr_notice("SW_LOAD: get ovmf path %s, size 0x%lx\n",
137 					ovmf_path, ovmf_size);
138 			}
139 		}
140 		free(str);
141 	}
142 
143 	if ((ovmf_file_name != NULL) ^ (ovmf_code_file_name && ovmf_vars_file_name))
144 		error = 0;
145 
146 	return error;
147 }
148 
149 static int
acrn_prepare_ovmf(struct vmctx * ctx)150 acrn_prepare_ovmf(struct vmctx *ctx)
151 {
152 	int i, flags, fd;
153 	char *path, *addr;
154 	size_t size, size_limit, cur_size, read;
155 	struct flock fl;
156 	FILE *fp;
157 
158 	if (ovmf_file_name) {
159 		path = ovmf_file_name;
160 		size = ovmf_size;
161 		size_limit = OVMF_SZ_LIMIT;
162 	} else {
163 		path = ovmf_vars_file_name;
164 		size = ovmf_vars_size;
165 		size_limit = OVMF_VARS_SZ_LIMIT;
166 	}
167 
168 	flags = writeback_nv_storage ? O_RDWR : O_RDONLY;
169 	addr = ctx->baseaddr + OVMF_TOP(ctx) - ovmf_image_size();
170 
171 	for (i = 0; i < 2; i++) {
172 		fd = open(path, flags);
173 
174 		if (fd == -1) {
175 			pr_err("SW_LOAD ERR: could not open ovmf file: %s (%s)\n",
176 				path, strerror(errno));
177 			return -1;
178 		}
179 
180 		/* acquire read lock over the entire file */
181 		memset(&fl, 0, sizeof(fl));
182 		fl.l_type = F_RDLCK;
183 		fl.l_whence = SEEK_SET;
184 		fl.l_start = 0;
185 		fl.l_len = 0;
186 
187 		if (fcntl(fd, F_SETLK, &fl)) {
188 			pr_err("SW_LOAD ERR: could not fcntl(F_RDLCK) "
189 				"ovmf file: %s (%s)\n",
190 				path, strerror(errno));
191 			close(fd);
192 			return -1;
193 		}
194 
195 		if (check_image(path, size_limit, &cur_size) != 0) {
196 			close(fd);
197 			return -1;
198 		}
199 
200 		if (cur_size != size) {
201 			pr_err("SW_LOAD ERR: ovmf file %s changed\n", path);
202 			close(fd);
203 			return -1;
204 		}
205 
206 		if (flags == O_RDWR) {
207 			/* upgrade to write lock */
208 			memset(&fl, 0, sizeof(fl));
209 			fl.l_type = F_WRLCK;
210 			fl.l_whence = SEEK_SET;
211 			fl.l_start = 0;
212 			fl.l_len = OVMF_NVSTORAGE_SZ;
213 
214 			if (fcntl(fd, F_SETLK, &fl)) {
215 				pr_err("SW_LOAD ERR: could not fcntl(F_WRLCK) "
216 					"ovmf file: %s (%s)\n",
217 					path, strerror(errno));
218 				close(fd);
219 				return -1;
220 			}
221 
222 			mmap_vars = mmap(NULL, OVMF_NVSTORAGE_SZ, PROT_WRITE,
223 					MAP_SHARED, fd, 0);
224 
225 			if (mmap_vars == MAP_FAILED) {
226 				pr_err("SW_LOAD ERR: could not mmap "
227 					"ovmf file: %s (%s)\n",
228 					path, strerror(errno));
229 				close(fd);
230 				return -1;
231 			}
232 		}
233 
234 		fp = fdopen(fd, "r");
235 
236 		if (fp == NULL) {
237 			pr_err("SW_LOAD ERR: could not fdopen "
238 				"ovmf file: %s (%s)\n",
239 				path, strerror(errno));
240 			close(fd);
241 			return -1;
242 		}
243 
244 		fseek(fp, 0, SEEK_SET);
245 		read = fread(addr, sizeof(char), size, fp);
246 		fclose(fp);
247 
248 		if (read < size) {
249 			pr_err("SW_LOAD ERR: could not read whole partition blob %s\n",
250 				path);
251 			return -1;
252 		}
253 
254 		pr_info("SW_LOAD: partition blob %s size 0x%lx copied to addr %p\n",
255 			path, size, addr);
256 
257 		if (!ovmf_file_name) {
258 			addr += size;
259 			path = ovmf_code_file_name;
260 			size = ovmf_code_size;
261 			size_limit = OVMF_CODE_SZ_LIMIT;
262 			flags = O_RDONLY;
263 		} else
264 			break;
265 	}
266 
267 	return 0;
268 }
269 
270 int
acrn_sw_load_ovmf(struct vmctx * ctx)271 acrn_sw_load_ovmf(struct vmctx *ctx)
272 {
273 	int ret;
274 	struct {
275 		char signature[4];
276 		uint32_t nentries;
277 		struct e820_entry map[];
278 	} __attribute__((packed)) *e820;
279 
280 	init_cmos_vrpmb(ctx);
281 
282 	ret = acrn_prepare_ovmf(ctx);
283 
284 	if (ret)
285 		return ret;
286 
287 	e820 = paddr_guest2host(ctx, OVMF_E820_BASE,
288 			e820_default_entries[LOWRAM_E820_ENTRY].baseaddr -
289 			OVMF_E820_BASE);
290 	if (e820 == NULL)
291 		return -1;
292 
293 	strncpy(e820->signature, "820", sizeof(e820->signature));
294 	e820->nentries = acrn_create_e820_table(ctx, e820->map);
295 
296 	pr_info("SW_LOAD: ovmf_entry 0x%lx\n", OVMF_TOP(ctx) - 16);
297 
298 	/* set guest bsp state. Will call hypercall set bsp state
299 	 * after bsp is created.
300 	 */
301 	memset(&ctx->bsp_regs, 0, sizeof(struct acrn_vcpu_regs));
302 	ctx->bsp_regs.vcpu_id = 0;
303 
304 	/* CR0_ET | CR0_NE */
305 	ctx->bsp_regs.vcpu_regs.cr0 = 0x30U;
306 	ctx->bsp_regs.vcpu_regs.cs_ar = 0x009FU;
307 	ctx->bsp_regs.vcpu_regs.cs_sel = 0xF000U;
308 	ctx->bsp_regs.vcpu_regs.cs_limit = 0xFFFFU;
309 	ctx->bsp_regs.vcpu_regs.cs_base = (OVMF_TOP(ctx) - 16) & 0xFFFF0000UL;
310 	ctx->bsp_regs.vcpu_regs.rip = (OVMF_TOP(ctx) - 16) & 0xFFFFUL;
311 
312 	return 0;
313 }
314 
315 /*
316  * The NV data section is the first 128KB in the OVMF image. At runtime,
317  * it's copied into guest memory and behave as RAM to OVMF. It can be
318  * accessed and updated by OVMF. To preserve NV section (referred to
319  * as Non-Volatile Data Store section in the OVMF spec), we're flushing
320  * in-memory data back to the NV data section of the OVMF image file
321  * at designated points.
322  */
323 int
acrn_writeback_ovmf_nvstorage(struct vmctx * ctx)324 acrn_writeback_ovmf_nvstorage(struct vmctx *ctx)
325 {
326 	int i, fd, ret = 0;
327 	char *path;
328 	struct flock fl;
329 
330 	if (!writeback_nv_storage)
331 		return 0;
332 
333 	memcpy(mmap_vars, ctx->baseaddr + OVMF_NVSTORAGE_OFFSET,
334 		OVMF_NVSTORAGE_SZ);
335 
336 	if (munmap(mmap_vars, OVMF_NVSTORAGE_SZ)) {
337 		pr_err("SW_LOAD ERR: could not munmap (%s)\n",
338 			strerror(errno));
339 		ret = -1;
340 	}
341 
342 	mmap_vars = NULL;
343 
344 	path = ovmf_file_name ? ovmf_file_name : ovmf_vars_file_name;
345 	pr_info("OVMF_WRITEBACK: OVMF has been written back "
346 		"to partition blob %s size 0x%lx @ gpa %p\n",
347 		path, OVMF_NVSTORAGE_SZ, (void *)OVMF_NVSTORAGE_OFFSET);
348 
349 	for (i = 0; i < 2; i++) {
350 		fd = open(path, O_RDONLY);
351 
352 		if (fd == -1) {
353 			pr_err("SW_LOAD ERR: could not open ovmf file: %s (%s)\n",
354 				path, strerror(errno));
355 			ret = -1;
356 			goto next;
357 		}
358 
359 		/* unlock the entire file */
360 		memset(&fl, 0, sizeof(fl));
361 		fl.l_type = F_UNLCK;
362 		fl.l_whence = SEEK_SET;
363 		fl.l_start = 0;
364 		fl.l_len = 0;
365 
366 		if (fcntl(fd, F_SETLK, &fl)) {
367 			pr_err("SW_LOAD ERR: could not fcntl(F_UNLCK) "
368 				"ovmf file: %s (%s)\n",
369 				path, strerror(errno));
370 			ret = -1;
371 		}
372 
373 		close(fd);
374 
375 next:
376 		if (!ovmf_file_name)
377 			path = ovmf_code_file_name;
378 		else
379 			break;
380 	}
381 
382 	return ret;
383 }
384