1 /*-
2  * Copyright (c) 2017-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 "vmmapi.h"
33 #include "sw_load.h"
34 #include "dm.h"
35 #include "pci_core.h"
36 #include "vssram.h"
37 
38 int with_bootargs;
39 static char bootargs[BOOT_ARG_LEN];
40 
41 /*
42  * Default e820 mem map:
43  *
44  * there is reserved memory hole for PCI hole and APIC etc
45  * so the memory layout could be separated into lowmem & highmem.
46  * - if request memory size <= ctx->lowmem_limit, then there is only
47  *   map[0]:0~ctx->lowmem for RAM
48  *   ctx->lowmem = request_memory_size
49  * - if request memory size > ctx->lowmem_limit, then there are
50  *   map[0]:0~ctx->lowmem_limit & map[2]:4G~ctx->highmem for RAM
51  *   ctx->highmem = request_memory_size - ctx->lowmem_limit
52  *
53  *             Begin    Limit        Type            Length
54  * 0:              0 -  0xA0000      RAM             0xA0000
55  * 1:       0x100000 -  lowmem part1 RAM             0x0
56  * 2:   SW SRAM_bot  -  SW SRAM_top  (reserved)      VSSRAM_MAX_SIZE
57  * 3:   gpu_rsvd_bot -  gpu_rsvd_top (reserved)      0x4004000
58  * 4:   lowmem part2 -  0x80000000   (reserved)      0x0
59  * 5:     0xE0000000 -  0x100000000  MCFG, MMIO      512MB
60  * 6:  HIGHRAM_START_ADDR -  mmio64 start  RAM       ctx->highmem
61  *
62  * FIXME: Do we need to reserve DSM and OPREGION for GVTD here.
63  */
64 const struct e820_entry e820_default_entries[NUM_E820_ENTRIES] = {
65 	{	/* 0 to video memory */
66 		.baseaddr = 0x00000000,
67 		.length   = 0xA0000,
68 		.type     = E820_TYPE_RAM
69 	},
70 
71 	{	/* 1MB to lowmem part1 */
72 		.baseaddr = 1 * MB,
73 		.length   = 0x0,
74 		.type     = E820_TYPE_RAM
75 	},
76 
77 	/*
78 	 * VSSRAM area: size: 0x800000
79 	 * In native, the VSSRAM region should be part of DRAM memory.
80 	 * But one fixed VSSRAM gpa is friendly for virtualization due
81 	 * to decoupled with various guest memory size.
82 	 */
83 	{
84 		.baseaddr = 0x0,
85 		.length   = 0x0,
86 		.type	  = E820_TYPE_RESERVED
87 	},
88 
89 	{	/* GPU DSM & OpRegion reserved region */
90 		.baseaddr = 0x0,
91 		.length   = 0x0,
92 		.type     = E820_TYPE_RESERVED
93 	},
94 
95 	{	/* lowmem part2 to lowmem_limit */
96 		.baseaddr = 0x0,
97 		.length   = 0x0,
98 		.type     = E820_TYPE_RESERVED
99 	},
100 
101 	{	/* ECFG_BASE to 4GB */
102 		.baseaddr = PCI_EMUL_ECFG_BASE,
103 		.length   = (4 * GB) - PCI_EMUL_ECFG_BASE,
104 		.type     = E820_TYPE_RESERVED
105 	},
106 
107 	{	/* 5GB to highmem */
108 		.baseaddr = HIGHRAM_START_ADDR,
109 		.length   = 0x0,
110 		.type     = E820_TYPE_RESERVED
111 	},
112 };
113 
114 int
acrn_parse_bootargs(char * arg)115 acrn_parse_bootargs(char *arg)
116 {
117 	size_t len = strnlen(arg, BOOT_ARG_LEN);
118 
119 	if (len < BOOT_ARG_LEN) {
120 		strncpy(bootargs, arg, len + 1);
121 		with_bootargs = 1;
122 		pr_notice("SW_LOAD: get bootargs %s\n", bootargs);
123 		return 0;
124 	}
125 	return -1;
126 }
127 
128 char*
get_bootargs(void)129 get_bootargs(void)
130 {
131 	return bootargs;
132 }
133 
134 int
check_image(char * path,size_t size_limit,size_t * size)135 check_image(char *path, size_t size_limit, size_t *size)
136 {
137 	FILE *fp;
138 	long len;
139 
140 	fp = fopen(path, "r");
141 
142 	if (fp == NULL) {
143 		pr_err("SW_LOAD ERR: image file failed to open\n");
144 		return -1;
145 	}
146 
147 	fseek(fp, 0, SEEK_END);
148 	len = ftell(fp);
149 
150 	if (len == 0 || (size_limit && len > size_limit)) {
151 		pr_err("SW_LOAD ERR: file is %s\n",
152 			len ? "too large" : "empty");
153 		fclose(fp);
154 		return -1;
155 	}
156 
157 	fclose(fp);
158 	*size = len;
159 	return 0;
160 }
161 
162 /* Assumption:
163  * the range [start, start + size] belongs to one entry of e820 table
164  */
165 int
add_e820_entry(struct e820_entry * e820,int len,uint64_t start,uint64_t size,uint32_t type)166 add_e820_entry(struct e820_entry *e820, int len, uint64_t start,
167 	uint64_t size, uint32_t type)
168 {
169 	int i, length = len;
170 	uint64_t e_s, e_e;
171 
172 	for (i = 0; i < len; i++) {
173 		e_s = e820[i].baseaddr;
174 		e_e = e820[i].baseaddr + e820[i].length;
175 		if ((e_s <= start) && ((start + size) <= e_e)) {
176 			int index_s = 0, index_e = 3;
177 			uint64_t pt[4];
178 			uint32_t pt_t[3];
179 
180 			pt[0] = e_s;
181 			pt[1] = start;
182 			pt[2] = start + size;
183 			pt[3] = e_e;
184 
185 			pt_t[0] = e820[i].type;
186 			pt_t[1] = type;
187 			pt_t[2] = e820[i].type;
188 
189 			if (e_s == start) {
190 				index_s = 1;
191 			}
192 
193 			if (e_e == (start + size)) {
194 				index_e = 2;
195 			}
196 			length += index_e - index_s - 1;
197 
198 			if ((i != (len - 1) && ((index_e - index_s) > 1))) {
199 				memmove(&e820[i + index_e - index_s],
200 					&e820[i + 1], (len - i - 1) *
201 					sizeof(struct e820_entry));
202 			}
203 
204 			for (; index_s < index_e; index_s++, i++) {
205 				e820[i].baseaddr = pt[index_s];
206 				e820[i].length = pt[index_s + 1] - pt[index_s];
207 				e820[i].type = pt_t[index_s];
208 			}
209 
210 			break;
211 		}
212 	}
213 
214 	return length;
215 }
216 
217 uint32_t
acrn_create_e820_table(struct vmctx * ctx,struct e820_entry * e820)218 acrn_create_e820_table(struct vmctx *ctx, struct e820_entry *e820)
219 {
220 	uint32_t removed = 0, k;
221 	uint32_t gpu_rsvmem_base_gpa = 0;
222 	uint64_t vssram_gpa = 0;
223 
224 	memcpy(e820, e820_default_entries, sizeof(e820_default_entries));
225 
226 	/* FIXME: Here wastes 8MB memory if VSSRAM is enabled, and 64MB+16KB if
227 	 * GPU reserved memory is exist.
228 	 *
229 	 * Determines the GPU region due to DSM identical mapping.
230 	 */
231 	gpu_rsvmem_base_gpa = get_gpu_rsvmem_base_gpa();
232 	if (gpu_rsvmem_base_gpa) {
233 		e820[LOWRAM_E820_ENTRY + 2].baseaddr = gpu_rsvmem_base_gpa;
234 		e820[LOWRAM_E820_ENTRY + 2].length = get_gpu_rsvmem_size();
235 	} else {
236 		e820[LOWRAM_E820_ENTRY + 2].baseaddr = ctx->lowmem_limit;
237 	}
238 
239 	/* Always put VSSRAM before GPU region and keep 1MB boundary for protection. */
240 	vssram_gpa = get_vssram_gpa_base();
241 	if (vssram_gpa) {
242 		e820[LOWRAM_E820_ENTRY + 1].baseaddr = vssram_gpa;
243 		e820[LOWRAM_E820_ENTRY + 1].length = get_vssram_size();
244 	} else {
245 		e820[LOWRAM_E820_ENTRY + 1].baseaddr = e820[LOWRAM_E820_ENTRY + 2].baseaddr;
246 	}
247 
248 	if (ctx->lowmem <= e820[LOWRAM_E820_ENTRY + 1].baseaddr) {
249 		/* Caculation for lowmem part1 */
250 		e820[LOWRAM_E820_ENTRY].length =
251 			ctx->lowmem - e820[LOWRAM_E820_ENTRY].baseaddr;
252 	} else {
253 		/* Caculation for lowmem part1 */
254 		e820[LOWRAM_E820_ENTRY].length =
255 			e820[LOWRAM_E820_ENTRY + 1].baseaddr - e820[LOWRAM_E820_ENTRY].baseaddr;
256 		/* Caculation for lowmem part2 */
257 		e820[LOWRAM_E820_ENTRY + 3].baseaddr =
258 			e820[LOWRAM_E820_ENTRY + 2].baseaddr + e820[LOWRAM_E820_ENTRY + 2].length;
259 		if (ctx->lowmem > e820[LOWRAM_E820_ENTRY + 3].baseaddr) {
260 			e820[LOWRAM_E820_ENTRY + 3].length =
261 				ctx->lowmem - e820[LOWRAM_E820_ENTRY + 3].baseaddr;
262 			e820[LOWRAM_E820_ENTRY + 3].type = E820_TYPE_RAM;
263 		}
264 	}
265 
266 	/* Caculation for highmem */
267 	if (ctx->highmem > 0) {
268 		e820[HIGHRAM_E820_ENTRY].type = E820_TYPE_RAM;
269 		e820[HIGHRAM_E820_ENTRY].length = ctx->highmem;
270 	}
271 
272 	/* Remove empty entries in e820 table */
273 	for (k = 0; k < (NUM_E820_ENTRIES - 1 - removed); k++) {
274 		if (e820[k].length == 0x0) {
275 			memmove(&e820[k], &e820[k + 1], sizeof(struct e820_entry) *
276 					(NUM_E820_ENTRIES - (k + 1)));
277 			k--;
278 			removed++;
279 		}
280 	}
281 
282 	pr_info("SW_LOAD: build e820 %d entries to addr: %p\r\n",
283 			NUM_E820_ENTRIES - removed, (void *)e820);
284 
285 	for (k = 0; k < NUM_E820_ENTRIES - removed; k++)
286 		pr_info("SW_LOAD: entry[%d]: addr 0x%016lx, size 0x%016lx, "
287 				" type 0x%x\r\n",
288 				k, e820[k].baseaddr,
289 				e820[k].length,
290 				e820[k].type);
291 
292 	return (NUM_E820_ENTRIES - removed);
293 }
294 
295 int
acrn_sw_load(struct vmctx * ctx)296 acrn_sw_load(struct vmctx *ctx)
297 {
298 	if (vsbl_file_name)
299 		return acrn_sw_load_vsbl(ctx);
300 	else if (ovmf_loaded)
301 		return acrn_sw_load_ovmf(ctx);
302 	else if (kernel_file_name)
303 		return acrn_sw_load_bzimage(ctx);
304 	else if (elf_file_name)
305 		return acrn_sw_load_elf(ctx);
306 	else
307 		return -1;
308 }
309