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