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 <stdbool.h>
31 
32 #include "dm.h"
33 #include "vmmapi.h"
34 #include "sw_load.h"
35 #include "log.h"
36 
37 #define SETUP_SIG 0x5a5aaa55
38 
39 /* If we load kernel/ramdisk/bootargs directly, the User VM
40  * memory layout will be like:
41  *
42  * | ...                                                 |
43  * +-----------------------------------------------------+
44  * | offset: 0xf2400 (ACPI table)                        |
45  * +-----------------------------------------------------+
46  * | ...                                                 |
47  * +-----------------------------------------------------+
48  * | offset: 16MB (kernel image)                         |
49  * +-----------------------------------------------------+
50  * | ...                                                 |
51  * +-----------------------------------------------------+
52  * | offset: lowmem - RAMDISK_LOAD_SIZE - 2K (kernel gdt)|
53  * +-----------------------------------------------------+
54  * | offset: lowmem - RAMDISK_LOAD_SIZE (ramdisk image)  |
55  * +-----------------------------------------------------+
56  * | offset: lowmem - 8K (bootargs)                      |
57  * +-----------------------------------------------------+
58  * | offset: lowmem - 6K (kernel entry address)          |
59  * +-----------------------------------------------------+
60  * | offset: lowmem - 4K (zero_page include e820 table)  |
61  * +-----------------------------------------------------+
62  */
63 
64 /* Check default e820 table in sw_load_common.c for info about ctx->lowmem */
65 /* use ramdisk size for ramdisk load offset, leave 8KB room for bootargs */
66 #define RAMDISK_LOAD_SIZE	roundup2(ramdisk_size + 8*KB, 4*KB)
67 #define GDT_LOAD_OFF(ctx)	(ctx->lowmem - RAMDISK_LOAD_SIZE - 2*KB)
68 #define RAMDISK_LOAD_OFF(ctx)	(ctx->lowmem - RAMDISK_LOAD_SIZE)
69 #define BOOTARGS_LOAD_OFF(ctx)	(ctx->lowmem - 8*KB)
70 #define KERNEL_ENTRY_OFF(ctx)	(ctx->lowmem - 6*KB)
71 #define ZEROPAGE_LOAD_OFF(ctx)	(ctx->lowmem - 4*KB)
72 #define KERNEL_LOAD_OFF(ctx)	(16*MB)
73 
74 /* The real mode kernel header, refer to Documentation/x86/boot.txt */
75 struct _zeropage {
76 	uint8_t pad1[0x1e8];                    /* 0x000 */
77 	uint8_t e820_nentries;                  /* 0x1e8 */
78 	uint8_t pad2[0x8];                      /* 0x1e9 */
79 
80 	struct	{
81 		uint8_t setup_sects;		/* 0x1f1 */
82 		uint8_t hdr_pad1[0x1e];         /* 0x1f2 */
83 		uint8_t loader_type;            /* 0x210 */
84 		uint8_t load_flags;             /* 0x211 */
85 		uint8_t hdr_pad2[0x2];          /* 0x212 */
86 		uint32_t code32_start;          /* 0x214 */
87 		uint32_t ramdisk_addr;          /* 0x218 */
88 		uint32_t ramdisk_size;          /* 0x21c */
89 		uint8_t hdr_pad3[0x8];          /* 0x220 */
90 		uint32_t bootargs_addr;         /* 0x228 */
91 		uint8_t hdr_pad4[0x3c];         /* 0x22c */
92 	} __attribute__((packed)) hdr;
93 
94 	uint8_t pad3[0x68];                     /* 0x268 */
95 	struct e820_entry e820[0x80];           /* 0x2d0 */
96 	uint8_t pad4[0x330];                    /* 0xcd0 */
97 } __attribute__((packed));
98 
99 static char ramdisk_path[STR_LEN];
100 static char kernel_path[STR_LEN];
101 static int with_ramdisk;
102 static int with_kernel;
103 static size_t ramdisk_size;
104 static size_t kernel_size;
105 
106 static int
acrn_get_bzimage_setup_size(struct vmctx * ctx)107 acrn_get_bzimage_setup_size(struct vmctx *ctx)
108 {
109 	struct _zeropage *kernel_load = (struct _zeropage *)
110 		(ctx->baseaddr + KERNEL_LOAD_OFF(ctx));
111 
112 	/* For backwards compatibility, if the setup_sects field
113 	 * is 0, the real value is 4.
114 	 */
115 	if (kernel_load->hdr.setup_sects == 0) {
116 		kernel_load->hdr.setup_sects = 4;
117 	}
118 
119 	return (kernel_load->hdr.setup_sects + 1) * 512;
120 }
121 
122 int
acrn_parse_kernel(char * arg)123 acrn_parse_kernel(char *arg)
124 {
125 	size_t len = strnlen(arg, STR_LEN);
126 
127 	if (len < STR_LEN) {
128 		strncpy(kernel_path, arg, len + 1);
129 		if (check_image(kernel_path, 0, &kernel_size) != 0){
130 			pr_err("SW_LOAD: check_image failed for '%s'\n",
131 				kernel_path);
132 			exit(10); /* Non-zero */
133 		}
134 		kernel_file_name = kernel_path;
135 
136 		with_kernel = 1;
137 		pr_notice("SW_LOAD: get kernel path %s\n", kernel_path);
138 		return 0;
139 	} else
140 		return -1;
141 }
142 
143 int
acrn_parse_ramdisk(char * arg)144 acrn_parse_ramdisk(char *arg)
145 {
146 	size_t len = strnlen(arg, STR_LEN);
147 
148 	if (len < STR_LEN) {
149 		strncpy(ramdisk_path, arg, len + 1);
150 		if (check_image(ramdisk_path, 0, &ramdisk_size) != 0){
151 			pr_err("SW_LOAD: check_image failed for '%s'\n",
152 				ramdisk_path);
153 			exit(11); /* Non-zero */
154 		}
155 
156 		with_ramdisk = 1;
157 		pr_notice("SW_LOAD: get ramdisk path %s\n", ramdisk_path);
158 		return 0;
159 	} else
160 		return -1;
161 }
162 
163 static int
acrn_prepare_ramdisk(struct vmctx * ctx)164 acrn_prepare_ramdisk(struct vmctx *ctx)
165 {
166 	FILE *fp;
167 	long len;
168 	size_t read;
169 
170 	fp = fopen(ramdisk_path, "r");
171 	if (fp == NULL) {
172 		pr_err("SW_LOAD ERR: could not open ramdisk file %s\n",
173 				ramdisk_path);
174 		return -1;
175 	}
176 
177 	fseek(fp, 0, SEEK_END);
178 	len = ftell(fp);
179 
180 	if (len != ramdisk_size) {
181 		fprintf(stderr,
182 			"SW_LOAD ERR: ramdisk file changed\n");
183 		fclose(fp);
184 		return -1;
185 	}
186 
187 	/* make sure there is enough room for the theoretical maximum ramdisk
188 	 * size (kernel size is not yet available)
189 	 */
190 	if (ctx->lowmem <= (RAMDISK_LOAD_SIZE + 2*KB + KERNEL_LOAD_OFF(ctx))) {
191 		pr_err("SW_LOAD ERR: the size of ramdisk file is too big"
192 			" file len=0x%lx\n", len);
193 		fclose(fp);
194 		return -1;
195 	}
196 
197 	fseek(fp, 0, SEEK_SET);
198 	read = fread(ctx->baseaddr + RAMDISK_LOAD_OFF(ctx),
199 			sizeof(char), len, fp);
200 	if (read < len) {
201 		pr_err("SW_LOAD ERR: could not read the whole ramdisk file,"
202 				" file len=%ld, read %lu\n", len, read);
203 		fclose(fp);
204 		return -1;
205 	}
206 	fclose(fp);
207 	pr_info("SW_LOAD: ramdisk %s size %lu copied to guest 0x%lx\n",
208 			ramdisk_path, ramdisk_size, RAMDISK_LOAD_OFF(ctx));
209 
210 	return 0;
211 }
212 
213 static int
acrn_prepare_kernel(struct vmctx * ctx)214 acrn_prepare_kernel(struct vmctx *ctx)
215 {
216 	FILE *fp;
217 	long len;
218 	size_t read;
219 
220 	fp = fopen(kernel_path, "r");
221 	if (fp == NULL) {
222 		pr_err("SW_LOAD ERR: could not open kernel file %s\n",
223 				kernel_path);
224 		return -1;
225 	}
226 
227 	fseek(fp, 0, SEEK_END);
228 	len = ftell(fp);
229 
230 	if (len != kernel_size) {
231 		fprintf(stderr,
232 			"SW_LOAD ERR: kernel file changed\n");
233 		fclose(fp);
234 		return -1;
235 	}
236 
237 	if ((len + KERNEL_LOAD_OFF(ctx)) > RAMDISK_LOAD_OFF(ctx)) {
238 		pr_err("SW_LOAD ERR: need big system memory to fit image\n");
239 		fclose(fp);
240 		return -1;
241 	}
242 
243 	fseek(fp, 0, SEEK_SET);
244 	read = fread(ctx->baseaddr + KERNEL_LOAD_OFF(ctx),
245 			sizeof(char), len, fp);
246 	if (read < len) {
247 		pr_err("SW_LOAD ERR: could not read the whole kernel file,"
248 				" file len=%ld, read %lu\n", len, read);
249 		fclose(fp);
250 		return -1;
251 	}
252 	fclose(fp);
253 	pr_info("SW_LOAD: kernel %s size %lu copied to guest 0x%lx\n",
254 			kernel_path, kernel_size, KERNEL_LOAD_OFF(ctx));
255 
256 	return 0;
257 }
258 
259 static int
acrn_prepare_zeropage(struct vmctx * ctx,int setup_size)260 acrn_prepare_zeropage(struct vmctx *ctx, int setup_size)
261 {
262 	struct _zeropage *zeropage = (struct _zeropage *)
263 		(ctx->baseaddr + ZEROPAGE_LOAD_OFF(ctx));
264 	struct _zeropage *kernel_load = (struct _zeropage *)
265 		(ctx->baseaddr + KERNEL_LOAD_OFF(ctx));
266 
267 	/* clear the zeropage */
268 	memset(zeropage, 0, 2*KB);
269 
270 	/* copy part of the header into the zero page */
271 	memcpy(&(zeropage->hdr), &(kernel_load->hdr), sizeof(zeropage->hdr));
272 
273 	if (with_ramdisk) {
274 		/*Copy ramdisk load_addr and size in zeropage header structure*/
275 		zeropage->hdr.ramdisk_addr = (uint32_t)
276 			((uint64_t)RAMDISK_LOAD_OFF(ctx));
277 		zeropage->hdr.ramdisk_size = (uint32_t)ramdisk_size;
278 
279 		pr_info("SW_LOAD: build zeropage for ramdisk addr: 0x%x,"
280 				" size: %d\n", zeropage->hdr.ramdisk_addr,
281 				zeropage->hdr.ramdisk_size);
282 	}
283 
284 	/* Copy bootargs load_addr in zeropage header structure */
285 	zeropage->hdr.bootargs_addr = (uint32_t)
286 		((uint64_t)BOOTARGS_LOAD_OFF(ctx));
287 	pr_info("SW_LOAD: build zeropage for bootargs addr: 0x%x\n",
288 			zeropage->hdr.bootargs_addr);
289 
290 	/* set constant arguments in zero page */
291 	zeropage->hdr.loader_type     = 0xff;
292 	zeropage->hdr.load_flags     |= (1<<5); /* quiet */
293 
294 	/* Create/add e820 table entries in zeropage */
295 	zeropage->e820_nentries = acrn_create_e820_table(ctx, zeropage->e820);
296 
297 	return 0;
298 }
299 
300 static const uint64_t bzimage_init_gdt[] = {
301 	0x0UL,
302 	0x0UL,
303 	0x00CF9B000000FFFFUL,	/* Linear Code */
304 	0x00CF93000000FFFFUL,	/* Linear Data */
305 };
306 
307 int
acrn_sw_load_bzimage(struct vmctx * ctx)308 acrn_sw_load_bzimage(struct vmctx *ctx)
309 {
310 	int ret, setup_size;
311 
312 	memset(&ctx->bsp_regs, 0, sizeof(struct acrn_vcpu_regs));
313 	ctx->bsp_regs.vcpu_id = 0;
314 
315 	if (with_bootargs) {
316 		strncpy(ctx->baseaddr + BOOTARGS_LOAD_OFF(ctx), get_bootargs(), STR_LEN);
317 		pr_info("SW_LOAD: bootargs copied to guest 0x%lx\n",
318 				BOOTARGS_LOAD_OFF(ctx));
319 	}
320 
321 	if (with_ramdisk) {
322 		ret = acrn_prepare_ramdisk(ctx);
323 		if (ret)
324 			return ret;
325 	}
326 
327 	if (with_kernel) {
328 		ret = acrn_prepare_kernel(ctx);
329 		if (ret)
330 			return ret;
331 		setup_size = acrn_get_bzimage_setup_size(ctx);
332 		if (setup_size <= 0)
333 			return -1;
334 
335 		ctx->bsp_regs.vcpu_regs.rip = (uint64_t)
336 			(KERNEL_LOAD_OFF(ctx) + setup_size);
337 
338 		ret = acrn_prepare_zeropage(ctx, setup_size);
339 		if (ret)
340 			return ret;
341 
342 		pr_info("SW_LOAD: zeropage prepared @ 0x%lx, "
343 				"kernel_entry_addr=0x%lx\n",
344 				ZEROPAGE_LOAD_OFF(ctx),
345 				(KERNEL_LOAD_OFF(ctx) + setup_size));
346 	}
347 
348 	memcpy(ctx->baseaddr + GDT_LOAD_OFF(ctx), &bzimage_init_gdt,
349 			sizeof(bzimage_init_gdt));
350 	ctx->bsp_regs.vcpu_regs.gdt.limit = sizeof(bzimage_init_gdt) - 1;
351 	ctx->bsp_regs.vcpu_regs.gdt.base = GDT_LOAD_OFF(ctx);
352 
353 	/* CR0_ET | CR0_NE | CR0_PE */
354 	ctx->bsp_regs.vcpu_regs.cr0 = 0x31U;
355 
356 	ctx->bsp_regs.vcpu_regs.cs_sel = 0x10U;
357 	ctx->bsp_regs.vcpu_regs.cs_ar = 0xC09BU;
358 	ctx->bsp_regs.vcpu_regs.cs_limit = 0xFFFFFFFFU;
359 
360 	ctx->bsp_regs.vcpu_regs.ds_sel = 0x18U;
361 	ctx->bsp_regs.vcpu_regs.ss_sel = 0x18U;
362 	ctx->bsp_regs.vcpu_regs.es_sel = 0x18U;
363 
364 	ctx->bsp_regs.vcpu_regs.gprs.rsi = ZEROPAGE_LOAD_OFF(ctx);
365 
366 	return 0;
367 }
368 
369