Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
110707 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2011 NetApp, Inc.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/mman.h>
31
#include <sys/stat.h>
32
33
#include <machine/armreg.h>
34
35
#include <assert.h>
36
#include <err.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <sysexits.h>
42
#include <unistd.h>
43
44
#include <vmmapi.h>
45
46
#include "bhyve_machdep.h"
47
#include "bhyverun.h"
48
#include "config.h"
49
#include "debug.h"
50
#include "fdt.h"
51
#include "mem.h"
52
#include "pci_emul.h"
53
#include "pci_irq.h"
54
#include "rtc_pl031.h"
55
#include "uart_emul.h"
56
57
/* Start of mem + 1M */
58
#define FDT_BASE 0x100000
59
#define FDT_SIZE (64 * 1024)
60
61
/* Start of lowmem + 64K */
62
#define UART_MMIO_BASE 0x10000
63
#define UART_MMIO_SIZE 0x1000
64
#define UART_INTR 32
65
#define RTC_MMIO_BASE 0x11000
66
#define RTC_MMIO_SIZE 0x1000
67
#define RTC_INTR 33
68
69
#define GIC_DIST_BASE 0x2f000000
70
#define GIC_DIST_SIZE 0x10000
71
#define GIC_REDIST_BASE 0x2f100000
72
#define GIC_REDIST_SIZE(ncpu) ((ncpu) * 2 * PAGE_SIZE_64K)
73
74
#define PCIE_INTA 34
75
#define PCIE_INTB 35
76
#define PCIE_INTC 36
77
#define PCIE_INTD 37
78
79
uint64_t *cpu_to_mpidr;
80
81
void
82
bhyve_init_config(void)
83
{
84
init_config();
85
86
/* Set default values prior to option parsing. */
87
set_config_bool("acpi_tables", false);
88
set_config_bool("acpi_tables_in_memory", false);
89
set_config_value("memory.size", "256M");
90
}
91
92
void
93
bhyve_usage(int code)
94
{
95
const char *progname;
96
97
progname = getprogname();
98
99
fprintf(stderr,
100
"Usage: %s [-CDHhSW]\n"
101
" %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
102
" %*s [-k config_file] [-m mem] [-o var=value]\n"
103
" %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
104
" -C: include guest memory in core file\n"
105
" -c: number of CPUs and/or topology specification\n"
106
" -D: destroy on power-off\n"
107
" -G: start a debug server\n"
108
" -h: help\n"
109
" -k: key=value flat config file\n"
110
" -M: monitor mode\n"
111
" -m: memory size\n"
112
" -o: set config 'var' to 'value'\n"
113
" -p: pin 'vcpu' to 'hostcpu'\n"
114
" -S: guest memory cannot be swapped\n"
115
" -s: <slot,driver,configinfo> PCI slot config\n"
116
" -U: UUID\n"
117
" -W: force virtio to use single-vector MSI\n",
118
progname, (int)strlen(progname), "", (int)strlen(progname), "",
119
(int)strlen(progname), "");
120
exit(code);
121
}
122
123
void
124
bhyve_optparse(int argc, char **argv)
125
{
126
const char *optstr;
127
int c;
128
129
optstr = "hCDMSWk:f:o:p:G:c:s:m:U:";
130
while ((c = getopt(argc, argv, optstr)) != -1) {
131
switch (c) {
132
case 'c':
133
if (bhyve_topology_parse(optarg) != 0) {
134
errx(EX_USAGE, "invalid cpu topology '%s'",
135
optarg);
136
}
137
break;
138
case 'C':
139
set_config_bool("memory.guest_in_core", true);
140
break;
141
case 'D':
142
set_config_bool("destroy_on_poweroff", true);
143
break;
144
case 'G':
145
bhyve_parse_gdb_options(optarg);
146
break;
147
case 'k':
148
bhyve_parse_simple_config_file(optarg);
149
break;
150
case 'm':
151
set_config_value("memory.size", optarg);
152
break;
153
case 'M':
154
set_config_bool("monitor", true);
155
break;
156
case 'o':
157
if (!bhyve_parse_config_option(optarg)) {
158
errx(EX_USAGE,
159
"invalid configuration option '%s'",
160
optarg);
161
}
162
break;
163
case 'p':
164
if (bhyve_pincpu_parse(optarg) != 0) {
165
errx(EX_USAGE,
166
"invalid vcpu pinning configuration '%s'",
167
optarg);
168
}
169
break;
170
case 's':
171
if (strncmp(optarg, "help", strlen(optarg)) == 0) {
172
pci_print_supported_devices();
173
exit(0);
174
} else if (pci_parse_slot(optarg) != 0)
175
exit(BHYVE_EXIT_ERROR);
176
else
177
break;
178
case 'S':
179
set_config_bool("memory.wired", true);
180
break;
181
case 'U':
182
set_config_value("uuid", optarg);
183
break;
184
case 'W':
185
set_config_bool("virtio_msix", false);
186
break;
187
case 'h':
188
bhyve_usage(0);
189
default:
190
bhyve_usage(1);
191
}
192
}
193
}
194
195
void
196
bhyve_init_vcpu(struct vcpu *vcpu __unused)
197
{
198
}
199
200
void
201
bhyve_start_vcpu(struct vcpu *vcpu, bool bsp __unused)
202
{
203
fbsdrun_addcpu(vcpu_id(vcpu));
204
}
205
206
/*
207
* Load the specified boot code at the beginning of high memory.
208
*/
209
static void
210
load_bootrom(struct vmctx *ctx, const char *path, uint64_t *elrp)
211
{
212
struct stat sb;
213
void *data, *gptr;
214
vm_paddr_t loadaddr;
215
off_t size;
216
int fd;
217
218
fd = open(path, O_RDONLY);
219
if (fd < 0)
220
err(1, "open(%s)", path);
221
if (fstat(fd, &sb) != 0)
222
err(1, "fstat(%s)", path);
223
224
size = sb.st_size;
225
226
loadaddr = vm_get_highmem_base(ctx);
227
gptr = vm_map_gpa(ctx, loadaddr, round_page(size));
228
229
data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
230
if (data == MAP_FAILED)
231
err(1, "mmap(%s)", path);
232
(void)close(fd);
233
memcpy(gptr, data, size);
234
235
if (munmap(data, size) != 0)
236
err(1, "munmap(%s)", path);
237
238
*elrp = loadaddr;
239
}
240
241
static void
242
mmio_uart_intr_assert(void *arg)
243
{
244
struct vmctx *ctx = arg;
245
246
vm_assert_irq(ctx, UART_INTR);
247
}
248
249
static void
250
mmio_uart_intr_deassert(void *arg)
251
{
252
struct vmctx *ctx = arg;
253
254
vm_deassert_irq(ctx, UART_INTR);
255
}
256
257
static int
258
mmio_uart_mem_handler(struct vcpu *vcpu __unused, int dir,
259
uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2)
260
{
261
struct uart_pl011_softc *sc = arg1;
262
long reg;
263
264
reg = (addr - arg2) >> 2;
265
if (dir == MEM_F_WRITE)
266
uart_pl011_write(sc, reg, *val);
267
else
268
*val = uart_pl011_read(sc, reg);
269
270
return (0);
271
}
272
273
static int
274
init_mmio_uart(struct vmctx *ctx)
275
{
276
struct uart_pl011_softc *sc;
277
struct mem_range mr;
278
const char *path;
279
int error;
280
281
path = get_config_value("console");
282
if (path == NULL)
283
return (1);
284
285
sc = uart_pl011_init(mmio_uart_intr_assert, mmio_uart_intr_deassert,
286
ctx);
287
if (uart_pl011_tty_open(sc, path) != 0) {
288
EPRINTLN("Unable to initialize backend '%s' for mmio uart",
289
path);
290
return (-1);
291
}
292
293
bzero(&mr, sizeof(struct mem_range));
294
mr.name = "uart";
295
mr.base = UART_MMIO_BASE;
296
mr.size = UART_MMIO_SIZE;
297
mr.flags = MEM_F_RW;
298
mr.handler = mmio_uart_mem_handler;
299
mr.arg1 = sc;
300
mr.arg2 = mr.base;
301
error = register_mem(&mr);
302
assert(error == 0);
303
304
return (0);
305
}
306
307
static void
308
mmio_rtc_intr_assert(void *arg)
309
{
310
struct vmctx *ctx = arg;
311
312
vm_assert_irq(ctx, RTC_INTR);
313
}
314
315
static void
316
mmio_rtc_intr_deassert(void *arg)
317
{
318
struct vmctx *ctx = arg;
319
320
vm_deassert_irq(ctx, RTC_INTR);
321
}
322
323
static int
324
mmio_rtc_mem_handler(struct vcpu *vcpu __unused, int dir,
325
uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2)
326
{
327
struct rtc_pl031_softc *sc = arg1;
328
long reg;
329
330
reg = addr - arg2;
331
if (dir == MEM_F_WRITE)
332
rtc_pl031_write(sc, reg, *val);
333
else
334
*val = rtc_pl031_read(sc, reg);
335
336
return (0);
337
}
338
339
static void
340
init_mmio_rtc(struct vmctx *ctx)
341
{
342
struct rtc_pl031_softc *sc;
343
struct mem_range mr;
344
int error;
345
346
sc = rtc_pl031_init(mmio_rtc_intr_assert, mmio_rtc_intr_deassert,
347
ctx);
348
349
bzero(&mr, sizeof(struct mem_range));
350
mr.name = "rtc";
351
mr.base = RTC_MMIO_BASE;
352
mr.size = RTC_MMIO_SIZE;
353
mr.flags = MEM_F_RW;
354
mr.handler = mmio_rtc_mem_handler;
355
mr.arg1 = sc;
356
mr.arg2 = mr.base;
357
error = register_mem(&mr);
358
assert(error == 0);
359
}
360
361
static vm_paddr_t
362
fdt_gpa(struct vmctx *ctx)
363
{
364
return (vm_get_highmem_base(ctx) + FDT_BASE);
365
}
366
367
int
368
bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp)
369
{
370
const char *bootrom;
371
uint64_t elr;
372
int error;
373
int pcie_intrs[4] = {PCIE_INTA, PCIE_INTB, PCIE_INTC, PCIE_INTD};
374
375
cpu_to_mpidr = calloc(guest_ncpus, sizeof(*cpu_to_mpidr));
376
if (cpu_to_mpidr == NULL) {
377
warnx("unable to allocate space for mpidr list");
378
return (ENOMEM);
379
}
380
381
for (uint64_t cpu = 0; cpu < (uint64_t)guest_ncpus; cpu++) {
382
uint64_t mpidr;
383
384
error = vm_get_register(fbsdrun_vcpu(cpu), VM_REG_GUEST_MPIDR_EL1,
385
&mpidr);
386
assert(error == 0);
387
#define MPIDR_AFF_MASK (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK | MPIDR_AFF3_MASK)
388
cpu_to_mpidr[cpu] = mpidr & MPIDR_AFF_MASK;
389
#undef MPIDR_AFF_MASK
390
}
391
392
bootrom = get_config_value("bootrom");
393
if (bootrom == NULL) {
394
warnx("no bootrom specified");
395
return (ENOENT);
396
}
397
load_bootrom(ctx, bootrom, &elr);
398
error = vm_set_register(bsp, VM_REG_GUEST_PC, elr);
399
if (error != 0) {
400
warn("vm_set_register(GUEST_PC)");
401
return (error);
402
}
403
404
error = fdt_init(ctx, guest_ncpus, fdt_gpa(ctx), FDT_SIZE);
405
if (error != 0)
406
return (error);
407
408
fdt_add_gic(GIC_DIST_BASE, GIC_DIST_SIZE, GIC_REDIST_BASE,
409
GIC_REDIST_SIZE(guest_ncpus));
410
error = vm_attach_vgic(ctx, GIC_DIST_BASE, GIC_DIST_SIZE,
411
GIC_REDIST_BASE, GIC_REDIST_SIZE(guest_ncpus));
412
if (error != 0) {
413
warn("vm_attach_vgic()");
414
return (error);
415
}
416
417
error = init_mmio_uart(ctx);
418
if (error == 0)
419
fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR);
420
else if (error < 0)
421
return (error);
422
init_mmio_rtc(ctx);
423
fdt_add_rtc(RTC_MMIO_BASE, RTC_MMIO_SIZE, RTC_INTR);
424
fdt_add_timer();
425
pci_irq_init(pcie_intrs);
426
fdt_add_pcie(pcie_intrs);
427
428
/* Mark CPU0 as running */
429
CPU_SET(0, &running_cpumask);
430
431
return (0);
432
}
433
434
int
435
bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused)
436
{
437
int error;
438
439
fdt_finalize();
440
441
error = vm_set_register(bsp, VM_REG_GUEST_X0, fdt_gpa(ctx));
442
assert(error == 0);
443
444
return (0);
445
}
446
447