17ab1a32cSRuslan Bukin /*-
27ab1a32cSRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause
37ab1a32cSRuslan Bukin *
47ab1a32cSRuslan Bukin * Copyright (c) 2011 NetApp, Inc.
57ab1a32cSRuslan Bukin * All rights reserved.
67ab1a32cSRuslan Bukin * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
77ab1a32cSRuslan Bukin *
87ab1a32cSRuslan Bukin * This software was developed by the University of Cambridge Computer
97ab1a32cSRuslan Bukin * Laboratory (Department of Computer Science and Technology) under Innovate
107ab1a32cSRuslan Bukin * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
117ab1a32cSRuslan Bukin * Prototype".
127ab1a32cSRuslan Bukin *
137ab1a32cSRuslan Bukin * Redistribution and use in source and binary forms, with or without
147ab1a32cSRuslan Bukin * modification, are permitted provided that the following conditions
157ab1a32cSRuslan Bukin * are met:
167ab1a32cSRuslan Bukin * 1. Redistributions of source code must retain the above copyright
177ab1a32cSRuslan Bukin * notice, this list of conditions and the following disclaimer.
187ab1a32cSRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright
197ab1a32cSRuslan Bukin * notice, this list of conditions and the following disclaimer in the
207ab1a32cSRuslan Bukin * documentation and/or other materials provided with the distribution.
217ab1a32cSRuslan Bukin *
227ab1a32cSRuslan Bukin * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
237ab1a32cSRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
247ab1a32cSRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
257ab1a32cSRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
267ab1a32cSRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277ab1a32cSRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
287ab1a32cSRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
297ab1a32cSRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
307ab1a32cSRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
317ab1a32cSRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327ab1a32cSRuslan Bukin * SUCH DAMAGE.
337ab1a32cSRuslan Bukin */
347ab1a32cSRuslan Bukin
357ab1a32cSRuslan Bukin #include <sys/param.h>
367ab1a32cSRuslan Bukin #include <sys/mman.h>
377ab1a32cSRuslan Bukin #include <sys/stat.h>
387ab1a32cSRuslan Bukin
397ab1a32cSRuslan Bukin #include <assert.h>
407ab1a32cSRuslan Bukin #include <err.h>
417ab1a32cSRuslan Bukin #include <errno.h>
427ab1a32cSRuslan Bukin #include <fcntl.h>
437ab1a32cSRuslan Bukin #include <stdlib.h>
447ab1a32cSRuslan Bukin #include <string.h>
457ab1a32cSRuslan Bukin #include <sysexits.h>
467ab1a32cSRuslan Bukin #include <unistd.h>
477ab1a32cSRuslan Bukin
487ab1a32cSRuslan Bukin #include <vmmapi.h>
497ab1a32cSRuslan Bukin
507ab1a32cSRuslan Bukin #include "bhyverun.h"
517ab1a32cSRuslan Bukin #include "config.h"
527ab1a32cSRuslan Bukin #include "debug.h"
537ab1a32cSRuslan Bukin #include "fdt.h"
547ab1a32cSRuslan Bukin #include "mem.h"
557ab1a32cSRuslan Bukin #include "pci_emul.h"
567ab1a32cSRuslan Bukin #include "pci_irq.h"
577ab1a32cSRuslan Bukin #include "uart_emul.h"
587ab1a32cSRuslan Bukin #include "riscv.h"
597ab1a32cSRuslan Bukin
607ab1a32cSRuslan Bukin #define FDT_SIZE (64 * 1024)
617ab1a32cSRuslan Bukin #define FDT_DTB_ALIGN 8
627ab1a32cSRuslan Bukin
637ab1a32cSRuslan Bukin /* Start of lowmem + 64K */
647ab1a32cSRuslan Bukin #define UART_MMIO_BASE 0x10000
657ab1a32cSRuslan Bukin #define UART_MMIO_SIZE 0x1000
667ab1a32cSRuslan Bukin #define UART_INTR 1
677ab1a32cSRuslan Bukin
687ab1a32cSRuslan Bukin #define APLIC_MEM_BASE 0x2f000000
697ab1a32cSRuslan Bukin #define APLIC_MEM_SIZE 0x10000
707ab1a32cSRuslan Bukin
717ab1a32cSRuslan Bukin #define PCIE_INTA 2
727ab1a32cSRuslan Bukin #define PCIE_INTB 3
737ab1a32cSRuslan Bukin #define PCIE_INTC 4
747ab1a32cSRuslan Bukin #define PCIE_INTD 5
757ab1a32cSRuslan Bukin
767ab1a32cSRuslan Bukin void
bhyve_init_config(void)777ab1a32cSRuslan Bukin bhyve_init_config(void)
787ab1a32cSRuslan Bukin {
797ab1a32cSRuslan Bukin init_config();
807ab1a32cSRuslan Bukin
817ab1a32cSRuslan Bukin /* Set default values prior to option parsing. */
827ab1a32cSRuslan Bukin set_config_bool("acpi_tables", false);
837ab1a32cSRuslan Bukin set_config_bool("acpi_tables_in_memory", false);
847ab1a32cSRuslan Bukin set_config_value("memory.size", "256M");
857ab1a32cSRuslan Bukin }
867ab1a32cSRuslan Bukin
877ab1a32cSRuslan Bukin void
bhyve_usage(int code)887ab1a32cSRuslan Bukin bhyve_usage(int code)
897ab1a32cSRuslan Bukin {
907ab1a32cSRuslan Bukin const char *progname;
917ab1a32cSRuslan Bukin
927ab1a32cSRuslan Bukin progname = getprogname();
937ab1a32cSRuslan Bukin
947ab1a32cSRuslan Bukin fprintf(stderr,
957ab1a32cSRuslan Bukin "Usage: %s [-CDHhSW]\n"
967ab1a32cSRuslan Bukin " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
977ab1a32cSRuslan Bukin " %*s [-k config_file] [-m mem] [-o var=value]\n"
987ab1a32cSRuslan Bukin " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
997ab1a32cSRuslan Bukin " -C: include guest memory in core file\n"
1007ab1a32cSRuslan Bukin " -c: number of CPUs and/or topology specification\n"
1017ab1a32cSRuslan Bukin " -D: destroy on power-off\n"
1027ab1a32cSRuslan Bukin " -h: help\n"
1037ab1a32cSRuslan Bukin " -k: key=value flat config file\n"
1047ab1a32cSRuslan Bukin " -m: memory size\n"
1057ab1a32cSRuslan Bukin " -o: set config 'var' to 'value'\n"
1067ab1a32cSRuslan Bukin " -p: pin 'vcpu' to 'hostcpu'\n"
1077ab1a32cSRuslan Bukin " -S: guest memory cannot be swapped\n"
1087ab1a32cSRuslan Bukin " -s: <slot,driver,configinfo> PCI slot config\n"
1097ab1a32cSRuslan Bukin " -U: UUID\n"
1107ab1a32cSRuslan Bukin " -W: force virtio to use single-vector MSI\n",
1117ab1a32cSRuslan Bukin progname, (int)strlen(progname), "", (int)strlen(progname), "",
1127ab1a32cSRuslan Bukin (int)strlen(progname), "");
1137ab1a32cSRuslan Bukin exit(code);
1147ab1a32cSRuslan Bukin }
1157ab1a32cSRuslan Bukin
1167ab1a32cSRuslan Bukin void
bhyve_optparse(int argc,char ** argv)1177ab1a32cSRuslan Bukin bhyve_optparse(int argc, char **argv)
1187ab1a32cSRuslan Bukin {
1197ab1a32cSRuslan Bukin const char *optstr;
1207ab1a32cSRuslan Bukin int c;
1217ab1a32cSRuslan Bukin
1227ab1a32cSRuslan Bukin optstr = "hCDSWk:f:o:p:c:s:m:U:";
1237ab1a32cSRuslan Bukin while ((c = getopt(argc, argv, optstr)) != -1) {
1247ab1a32cSRuslan Bukin switch (c) {
1257ab1a32cSRuslan Bukin case 'c':
1267ab1a32cSRuslan Bukin if (bhyve_topology_parse(optarg) != 0) {
1277ab1a32cSRuslan Bukin errx(EX_USAGE, "invalid cpu topology '%s'",
1287ab1a32cSRuslan Bukin optarg);
1297ab1a32cSRuslan Bukin }
1307ab1a32cSRuslan Bukin break;
1317ab1a32cSRuslan Bukin case 'C':
1327ab1a32cSRuslan Bukin set_config_bool("memory.guest_in_core", true);
1337ab1a32cSRuslan Bukin break;
1347ab1a32cSRuslan Bukin case 'D':
1357ab1a32cSRuslan Bukin set_config_bool("destroy_on_poweroff", true);
1367ab1a32cSRuslan Bukin break;
1377ab1a32cSRuslan Bukin case 'k':
1387ab1a32cSRuslan Bukin bhyve_parse_simple_config_file(optarg);
1397ab1a32cSRuslan Bukin break;
1407ab1a32cSRuslan Bukin case 'm':
1417ab1a32cSRuslan Bukin set_config_value("memory.size", optarg);
1427ab1a32cSRuslan Bukin break;
1437ab1a32cSRuslan Bukin case 'o':
1447ab1a32cSRuslan Bukin if (!bhyve_parse_config_option(optarg)) {
1457ab1a32cSRuslan Bukin errx(EX_USAGE,
1467ab1a32cSRuslan Bukin "invalid configuration option '%s'",
1477ab1a32cSRuslan Bukin optarg);
1487ab1a32cSRuslan Bukin }
1497ab1a32cSRuslan Bukin break;
1507ab1a32cSRuslan Bukin case 'p':
1517ab1a32cSRuslan Bukin if (bhyve_pincpu_parse(optarg) != 0) {
1527ab1a32cSRuslan Bukin errx(EX_USAGE,
1537ab1a32cSRuslan Bukin "invalid vcpu pinning configuration '%s'",
1547ab1a32cSRuslan Bukin optarg);
1557ab1a32cSRuslan Bukin }
1567ab1a32cSRuslan Bukin break;
1577ab1a32cSRuslan Bukin case 's':
1587ab1a32cSRuslan Bukin if (strncmp(optarg, "help", strlen(optarg)) == 0) {
1597ab1a32cSRuslan Bukin pci_print_supported_devices();
1607ab1a32cSRuslan Bukin exit(0);
1617ab1a32cSRuslan Bukin } else if (pci_parse_slot(optarg) != 0)
1627ab1a32cSRuslan Bukin exit(4);
1637ab1a32cSRuslan Bukin else
1647ab1a32cSRuslan Bukin break;
1657ab1a32cSRuslan Bukin case 'S':
1667ab1a32cSRuslan Bukin set_config_bool("memory.wired", true);
1677ab1a32cSRuslan Bukin break;
1687ab1a32cSRuslan Bukin case 'U':
1697ab1a32cSRuslan Bukin set_config_value("uuid", optarg);
1707ab1a32cSRuslan Bukin break;
1717ab1a32cSRuslan Bukin case 'W':
1727ab1a32cSRuslan Bukin set_config_bool("virtio_msix", false);
1737ab1a32cSRuslan Bukin break;
1747ab1a32cSRuslan Bukin case 'h':
1757ab1a32cSRuslan Bukin bhyve_usage(0);
1767ab1a32cSRuslan Bukin default:
1777ab1a32cSRuslan Bukin bhyve_usage(1);
1787ab1a32cSRuslan Bukin }
1797ab1a32cSRuslan Bukin }
1807ab1a32cSRuslan Bukin }
1817ab1a32cSRuslan Bukin
1827ab1a32cSRuslan Bukin void
bhyve_init_vcpu(struct vcpu * vcpu __unused)1837ab1a32cSRuslan Bukin bhyve_init_vcpu(struct vcpu *vcpu __unused)
1847ab1a32cSRuslan Bukin {
1857ab1a32cSRuslan Bukin }
1867ab1a32cSRuslan Bukin
1877ab1a32cSRuslan Bukin void
bhyve_start_vcpu(struct vcpu * vcpu,bool bsp __unused)1887ab1a32cSRuslan Bukin bhyve_start_vcpu(struct vcpu *vcpu, bool bsp __unused)
1897ab1a32cSRuslan Bukin {
1907ab1a32cSRuslan Bukin int error;
1917ab1a32cSRuslan Bukin
1927ab1a32cSRuslan Bukin /* Set hart ID. */
1937ab1a32cSRuslan Bukin error = vm_set_register(vcpu, VM_REG_GUEST_A0, vcpu_id(vcpu));
1947ab1a32cSRuslan Bukin assert(error == 0);
1957ab1a32cSRuslan Bukin
1967ab1a32cSRuslan Bukin fbsdrun_addcpu(vcpu_id(vcpu));
1977ab1a32cSRuslan Bukin }
1987ab1a32cSRuslan Bukin
1997ab1a32cSRuslan Bukin /*
2007ab1a32cSRuslan Bukin * Load the specified boot code at the beginning of high memory.
2017ab1a32cSRuslan Bukin */
2027ab1a32cSRuslan Bukin static void
load_bootrom(struct vmctx * ctx,const char * path,uint64_t * elrp,uint64_t * lenp)2037ab1a32cSRuslan Bukin load_bootrom(struct vmctx *ctx, const char *path, uint64_t *elrp,
2047ab1a32cSRuslan Bukin uint64_t *lenp)
2057ab1a32cSRuslan Bukin {
2067ab1a32cSRuslan Bukin struct stat sb;
2077ab1a32cSRuslan Bukin void *data, *gptr;
2087ab1a32cSRuslan Bukin vm_paddr_t loadaddr;
2097ab1a32cSRuslan Bukin off_t size;
2107ab1a32cSRuslan Bukin int fd;
2117ab1a32cSRuslan Bukin
2127ab1a32cSRuslan Bukin fd = open(path, O_RDONLY);
2137ab1a32cSRuslan Bukin if (fd < 0)
2147ab1a32cSRuslan Bukin err(1, "open(%s)", path);
2157ab1a32cSRuslan Bukin if (fstat(fd, &sb) != 0)
2167ab1a32cSRuslan Bukin err(1, "fstat(%s)", path);
2177ab1a32cSRuslan Bukin
2187ab1a32cSRuslan Bukin size = sb.st_size;
2197ab1a32cSRuslan Bukin
2207ab1a32cSRuslan Bukin loadaddr = vm_get_highmem_base(ctx);
2217ab1a32cSRuslan Bukin gptr = vm_map_gpa(ctx, loadaddr, round_page(size));
2227ab1a32cSRuslan Bukin
2237ab1a32cSRuslan Bukin data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
2247ab1a32cSRuslan Bukin if (data == MAP_FAILED)
2257ab1a32cSRuslan Bukin err(1, "mmap(%s)", path);
2267ab1a32cSRuslan Bukin (void)close(fd);
2277ab1a32cSRuslan Bukin memcpy(gptr, data, size);
2287ab1a32cSRuslan Bukin
2297ab1a32cSRuslan Bukin if (munmap(data, size) != 0)
2307ab1a32cSRuslan Bukin err(1, "munmap(%s)", path);
2317ab1a32cSRuslan Bukin
2327ab1a32cSRuslan Bukin *elrp = loadaddr;
2337ab1a32cSRuslan Bukin *lenp = size;
2347ab1a32cSRuslan Bukin }
2357ab1a32cSRuslan Bukin
2367ab1a32cSRuslan Bukin static void
mmio_uart_intr_assert(void * arg)2377ab1a32cSRuslan Bukin mmio_uart_intr_assert(void *arg)
2387ab1a32cSRuslan Bukin {
2397ab1a32cSRuslan Bukin struct vmctx *ctx = arg;
2407ab1a32cSRuslan Bukin
2417ab1a32cSRuslan Bukin vm_assert_irq(ctx, UART_INTR);
2427ab1a32cSRuslan Bukin }
2437ab1a32cSRuslan Bukin
2447ab1a32cSRuslan Bukin static void
mmio_uart_intr_deassert(void * arg)2457ab1a32cSRuslan Bukin mmio_uart_intr_deassert(void *arg)
2467ab1a32cSRuslan Bukin {
2477ab1a32cSRuslan Bukin struct vmctx *ctx = arg;
2487ab1a32cSRuslan Bukin
2497ab1a32cSRuslan Bukin vm_deassert_irq(ctx, UART_INTR);
2507ab1a32cSRuslan Bukin }
2517ab1a32cSRuslan Bukin
2527ab1a32cSRuslan Bukin static int
mmio_uart_mem_handler(struct vcpu * vcpu __unused,int dir,uint64_t addr,int size __unused,uint64_t * val,void * arg1,long arg2)2537ab1a32cSRuslan Bukin mmio_uart_mem_handler(struct vcpu *vcpu __unused, int dir, uint64_t addr,
2547ab1a32cSRuslan Bukin int size __unused, uint64_t *val, void *arg1, long arg2)
2557ab1a32cSRuslan Bukin {
2567ab1a32cSRuslan Bukin struct uart_ns16550_softc *sc = arg1;
2577ab1a32cSRuslan Bukin long reg;
2587ab1a32cSRuslan Bukin
2597ab1a32cSRuslan Bukin reg = addr - arg2;
2607ab1a32cSRuslan Bukin if (dir == MEM_F_WRITE)
2617ab1a32cSRuslan Bukin uart_ns16550_write(sc, reg, *val);
2627ab1a32cSRuslan Bukin else
2637ab1a32cSRuslan Bukin *val = uart_ns16550_read(sc, reg);
2647ab1a32cSRuslan Bukin
2657ab1a32cSRuslan Bukin return (0);
2667ab1a32cSRuslan Bukin }
2677ab1a32cSRuslan Bukin
2687ab1a32cSRuslan Bukin static bool
init_mmio_uart(struct vmctx * ctx)2697ab1a32cSRuslan Bukin init_mmio_uart(struct vmctx *ctx)
2707ab1a32cSRuslan Bukin {
2717ab1a32cSRuslan Bukin struct uart_ns16550_softc *sc;
2727ab1a32cSRuslan Bukin struct mem_range mr;
2737ab1a32cSRuslan Bukin const char *path;
2747ab1a32cSRuslan Bukin int error;
2757ab1a32cSRuslan Bukin
2767ab1a32cSRuslan Bukin path = get_config_value("console");
2777ab1a32cSRuslan Bukin if (path == NULL)
2787ab1a32cSRuslan Bukin return (false);
2797ab1a32cSRuslan Bukin
2807ab1a32cSRuslan Bukin sc = uart_ns16550_init(mmio_uart_intr_assert, mmio_uart_intr_deassert,
2817ab1a32cSRuslan Bukin ctx);
2827ab1a32cSRuslan Bukin if (uart_ns16550_tty_open(sc, path) != 0) {
2837ab1a32cSRuslan Bukin EPRINTLN("Unable to initialize backend '%s' for mmio uart",
2847ab1a32cSRuslan Bukin path);
2857ab1a32cSRuslan Bukin assert(0);
2867ab1a32cSRuslan Bukin }
2877ab1a32cSRuslan Bukin
2887ab1a32cSRuslan Bukin bzero(&mr, sizeof(struct mem_range));
2897ab1a32cSRuslan Bukin mr.name = "uart";
2907ab1a32cSRuslan Bukin mr.base = UART_MMIO_BASE;
2917ab1a32cSRuslan Bukin mr.size = UART_MMIO_SIZE;
2927ab1a32cSRuslan Bukin mr.flags = MEM_F_RW;
2937ab1a32cSRuslan Bukin mr.handler = mmio_uart_mem_handler;
2947ab1a32cSRuslan Bukin mr.arg1 = sc;
2957ab1a32cSRuslan Bukin mr.arg2 = mr.base;
2967ab1a32cSRuslan Bukin error = register_mem(&mr);
2977ab1a32cSRuslan Bukin assert(error == 0);
2987ab1a32cSRuslan Bukin
2997ab1a32cSRuslan Bukin return (true);
3007ab1a32cSRuslan Bukin }
3017ab1a32cSRuslan Bukin
3027ab1a32cSRuslan Bukin int
bhyve_init_platform(struct vmctx * ctx,struct vcpu * bsp)3037ab1a32cSRuslan Bukin bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp)
3047ab1a32cSRuslan Bukin {
3057ab1a32cSRuslan Bukin const char *bootrom;
3067ab1a32cSRuslan Bukin uint64_t elr;
3077ab1a32cSRuslan Bukin uint64_t len;
3087ab1a32cSRuslan Bukin int error;
3097ab1a32cSRuslan Bukin int pcie_intrs[4] = {PCIE_INTA, PCIE_INTB, PCIE_INTC, PCIE_INTD};
3107ab1a32cSRuslan Bukin vm_paddr_t fdt_gpa;
311a7bf553dSRuslan Bukin char isa[32];
312a7bf553dSRuslan Bukin int retval;
3137ab1a32cSRuslan Bukin
3147ab1a32cSRuslan Bukin bootrom = get_config_value("bootrom");
3157ab1a32cSRuslan Bukin if (bootrom == NULL) {
3167ab1a32cSRuslan Bukin warnx("no bootrom specified");
3177ab1a32cSRuslan Bukin return (ENOENT);
3187ab1a32cSRuslan Bukin }
3197ab1a32cSRuslan Bukin load_bootrom(ctx, bootrom, &elr, &len);
3207ab1a32cSRuslan Bukin error = vm_set_register(bsp, VM_REG_GUEST_SEPC, elr);
3217ab1a32cSRuslan Bukin if (error != 0) {
3227ab1a32cSRuslan Bukin warn("vm_set_register(GUEST_SEPC)");
3237ab1a32cSRuslan Bukin return (error);
3247ab1a32cSRuslan Bukin }
3257ab1a32cSRuslan Bukin
326a7bf553dSRuslan Bukin error = vm_get_capability(bsp, VM_CAP_SSTC, &retval);
327a7bf553dSRuslan Bukin assert(error == 0);
328a7bf553dSRuslan Bukin snprintf(isa, sizeof(isa), "%s%s", "rv64imafdc",
329a7bf553dSRuslan Bukin retval == 1 ? "_sstc" : "");
330a7bf553dSRuslan Bukin
3317ab1a32cSRuslan Bukin fdt_gpa = vm_get_highmem_base(ctx) + roundup2(len, FDT_DTB_ALIGN);
332a7bf553dSRuslan Bukin error = fdt_init(ctx, guest_ncpus, fdt_gpa, FDT_SIZE, isa);
3337ab1a32cSRuslan Bukin if (error != 0)
3347ab1a32cSRuslan Bukin return (error);
3357ab1a32cSRuslan Bukin
3367ab1a32cSRuslan Bukin /* Set FDT base address to the bootable hart. */
3377ab1a32cSRuslan Bukin error = vm_set_register(bsp, VM_REG_GUEST_A1, fdt_gpa);
3387ab1a32cSRuslan Bukin assert(error == 0);
3397ab1a32cSRuslan Bukin
340*7ac65902SRuslan Bukin fdt_add_aplic(APLIC_MEM_BASE, APLIC_MEM_SIZE, guest_ncpus);
3417ab1a32cSRuslan Bukin error = vm_attach_aplic(ctx, APLIC_MEM_BASE, APLIC_MEM_SIZE);
3427ab1a32cSRuslan Bukin if (error != 0) {
3437ab1a32cSRuslan Bukin warn("vm_attach_aplic()");
3447ab1a32cSRuslan Bukin return (error);
3457ab1a32cSRuslan Bukin }
3467ab1a32cSRuslan Bukin
3477ab1a32cSRuslan Bukin if (init_mmio_uart(ctx))
3487ab1a32cSRuslan Bukin fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR);
3497ab1a32cSRuslan Bukin
3507ab1a32cSRuslan Bukin pci_irq_init(pcie_intrs);
3517ab1a32cSRuslan Bukin fdt_add_pcie(pcie_intrs);
3527ab1a32cSRuslan Bukin vmexit_set_bsp(vcpu_id(bsp));
3537ab1a32cSRuslan Bukin
3547ab1a32cSRuslan Bukin return (0);
3557ab1a32cSRuslan Bukin }
3567ab1a32cSRuslan Bukin
3577ab1a32cSRuslan Bukin int
bhyve_init_platform_late(struct vmctx * ctx __unused,struct vcpu * bsp __unused)3587ab1a32cSRuslan Bukin bhyve_init_platform_late(struct vmctx *ctx __unused, struct vcpu *bsp __unused)
3597ab1a32cSRuslan Bukin {
3607ab1a32cSRuslan Bukin
3617ab1a32cSRuslan Bukin fdt_finalize();
3627ab1a32cSRuslan Bukin
3637ab1a32cSRuslan Bukin return (0);
3647ab1a32cSRuslan Bukin }
365