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