Path: blob/main/usr.sbin/bhyve/aarch64/bhyverun_machdep.c
110707 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2011 NetApp, Inc.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <sys/mman.h>30#include <sys/stat.h>3132#include <machine/armreg.h>3334#include <assert.h>35#include <err.h>36#include <errno.h>37#include <fcntl.h>38#include <stdlib.h>39#include <string.h>40#include <sysexits.h>41#include <unistd.h>4243#include <vmmapi.h>4445#include "bhyve_machdep.h"46#include "bhyverun.h"47#include "config.h"48#include "debug.h"49#include "fdt.h"50#include "mem.h"51#include "pci_emul.h"52#include "pci_irq.h"53#include "rtc_pl031.h"54#include "uart_emul.h"5556/* Start of mem + 1M */57#define FDT_BASE 0x10000058#define FDT_SIZE (64 * 1024)5960/* Start of lowmem + 64K */61#define UART_MMIO_BASE 0x1000062#define UART_MMIO_SIZE 0x100063#define UART_INTR 3264#define RTC_MMIO_BASE 0x1100065#define RTC_MMIO_SIZE 0x100066#define RTC_INTR 336768#define GIC_DIST_BASE 0x2f00000069#define GIC_DIST_SIZE 0x1000070#define GIC_REDIST_BASE 0x2f10000071#define GIC_REDIST_SIZE(ncpu) ((ncpu) * 2 * PAGE_SIZE_64K)7273#define PCIE_INTA 3474#define PCIE_INTB 3575#define PCIE_INTC 3676#define PCIE_INTD 377778uint64_t *cpu_to_mpidr;7980void81bhyve_init_config(void)82{83init_config();8485/* Set default values prior to option parsing. */86set_config_bool("acpi_tables", false);87set_config_bool("acpi_tables_in_memory", false);88set_config_value("memory.size", "256M");89}9091void92bhyve_usage(int code)93{94const char *progname;9596progname = getprogname();9798fprintf(stderr,99"Usage: %s [-CDHhSW]\n"100" %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"101" %*s [-k config_file] [-m mem] [-o var=value]\n"102" %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"103" -C: include guest memory in core file\n"104" -c: number of CPUs and/or topology specification\n"105" -D: destroy on power-off\n"106" -G: start a debug server\n"107" -h: help\n"108" -k: key=value flat config file\n"109" -M: monitor mode\n"110" -m: memory size\n"111" -o: set config 'var' to 'value'\n"112" -p: pin 'vcpu' to 'hostcpu'\n"113" -S: guest memory cannot be swapped\n"114" -s: <slot,driver,configinfo> PCI slot config\n"115" -U: UUID\n"116" -W: force virtio to use single-vector MSI\n",117progname, (int)strlen(progname), "", (int)strlen(progname), "",118(int)strlen(progname), "");119exit(code);120}121122void123bhyve_optparse(int argc, char **argv)124{125const char *optstr;126int c;127128optstr = "hCDMSWk:f:o:p:G:c:s:m:U:";129while ((c = getopt(argc, argv, optstr)) != -1) {130switch (c) {131case 'c':132if (bhyve_topology_parse(optarg) != 0) {133errx(EX_USAGE, "invalid cpu topology '%s'",134optarg);135}136break;137case 'C':138set_config_bool("memory.guest_in_core", true);139break;140case 'D':141set_config_bool("destroy_on_poweroff", true);142break;143case 'G':144bhyve_parse_gdb_options(optarg);145break;146case 'k':147bhyve_parse_simple_config_file(optarg);148break;149case 'm':150set_config_value("memory.size", optarg);151break;152case 'M':153set_config_bool("monitor", true);154break;155case 'o':156if (!bhyve_parse_config_option(optarg)) {157errx(EX_USAGE,158"invalid configuration option '%s'",159optarg);160}161break;162case 'p':163if (bhyve_pincpu_parse(optarg) != 0) {164errx(EX_USAGE,165"invalid vcpu pinning configuration '%s'",166optarg);167}168break;169case 's':170if (strncmp(optarg, "help", strlen(optarg)) == 0) {171pci_print_supported_devices();172exit(0);173} else if (pci_parse_slot(optarg) != 0)174exit(BHYVE_EXIT_ERROR);175else176break;177case 'S':178set_config_bool("memory.wired", true);179break;180case 'U':181set_config_value("uuid", optarg);182break;183case 'W':184set_config_bool("virtio_msix", false);185break;186case 'h':187bhyve_usage(0);188default:189bhyve_usage(1);190}191}192}193194void195bhyve_init_vcpu(struct vcpu *vcpu __unused)196{197}198199void200bhyve_start_vcpu(struct vcpu *vcpu, bool bsp __unused)201{202fbsdrun_addcpu(vcpu_id(vcpu));203}204205/*206* Load the specified boot code at the beginning of high memory.207*/208static void209load_bootrom(struct vmctx *ctx, const char *path, uint64_t *elrp)210{211struct stat sb;212void *data, *gptr;213vm_paddr_t loadaddr;214off_t size;215int fd;216217fd = open(path, O_RDONLY);218if (fd < 0)219err(1, "open(%s)", path);220if (fstat(fd, &sb) != 0)221err(1, "fstat(%s)", path);222223size = sb.st_size;224225loadaddr = vm_get_highmem_base(ctx);226gptr = vm_map_gpa(ctx, loadaddr, round_page(size));227228data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);229if (data == MAP_FAILED)230err(1, "mmap(%s)", path);231(void)close(fd);232memcpy(gptr, data, size);233234if (munmap(data, size) != 0)235err(1, "munmap(%s)", path);236237*elrp = loadaddr;238}239240static void241mmio_uart_intr_assert(void *arg)242{243struct vmctx *ctx = arg;244245vm_assert_irq(ctx, UART_INTR);246}247248static void249mmio_uart_intr_deassert(void *arg)250{251struct vmctx *ctx = arg;252253vm_deassert_irq(ctx, UART_INTR);254}255256static int257mmio_uart_mem_handler(struct vcpu *vcpu __unused, int dir,258uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2)259{260struct uart_pl011_softc *sc = arg1;261long reg;262263reg = (addr - arg2) >> 2;264if (dir == MEM_F_WRITE)265uart_pl011_write(sc, reg, *val);266else267*val = uart_pl011_read(sc, reg);268269return (0);270}271272static int273init_mmio_uart(struct vmctx *ctx)274{275struct uart_pl011_softc *sc;276struct mem_range mr;277const char *path;278int error;279280path = get_config_value("console");281if (path == NULL)282return (1);283284sc = uart_pl011_init(mmio_uart_intr_assert, mmio_uart_intr_deassert,285ctx);286if (uart_pl011_tty_open(sc, path) != 0) {287EPRINTLN("Unable to initialize backend '%s' for mmio uart",288path);289return (-1);290}291292bzero(&mr, sizeof(struct mem_range));293mr.name = "uart";294mr.base = UART_MMIO_BASE;295mr.size = UART_MMIO_SIZE;296mr.flags = MEM_F_RW;297mr.handler = mmio_uart_mem_handler;298mr.arg1 = sc;299mr.arg2 = mr.base;300error = register_mem(&mr);301assert(error == 0);302303return (0);304}305306static void307mmio_rtc_intr_assert(void *arg)308{309struct vmctx *ctx = arg;310311vm_assert_irq(ctx, RTC_INTR);312}313314static void315mmio_rtc_intr_deassert(void *arg)316{317struct vmctx *ctx = arg;318319vm_deassert_irq(ctx, RTC_INTR);320}321322static int323mmio_rtc_mem_handler(struct vcpu *vcpu __unused, int dir,324uint64_t addr, int size __unused, uint64_t *val, void *arg1, long arg2)325{326struct rtc_pl031_softc *sc = arg1;327long reg;328329reg = addr - arg2;330if (dir == MEM_F_WRITE)331rtc_pl031_write(sc, reg, *val);332else333*val = rtc_pl031_read(sc, reg);334335return (0);336}337338static void339init_mmio_rtc(struct vmctx *ctx)340{341struct rtc_pl031_softc *sc;342struct mem_range mr;343int error;344345sc = rtc_pl031_init(mmio_rtc_intr_assert, mmio_rtc_intr_deassert,346ctx);347348bzero(&mr, sizeof(struct mem_range));349mr.name = "rtc";350mr.base = RTC_MMIO_BASE;351mr.size = RTC_MMIO_SIZE;352mr.flags = MEM_F_RW;353mr.handler = mmio_rtc_mem_handler;354mr.arg1 = sc;355mr.arg2 = mr.base;356error = register_mem(&mr);357assert(error == 0);358}359360static vm_paddr_t361fdt_gpa(struct vmctx *ctx)362{363return (vm_get_highmem_base(ctx) + FDT_BASE);364}365366int367bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp)368{369const char *bootrom;370uint64_t elr;371int error;372int pcie_intrs[4] = {PCIE_INTA, PCIE_INTB, PCIE_INTC, PCIE_INTD};373374cpu_to_mpidr = calloc(guest_ncpus, sizeof(*cpu_to_mpidr));375if (cpu_to_mpidr == NULL) {376warnx("unable to allocate space for mpidr list");377return (ENOMEM);378}379380for (uint64_t cpu = 0; cpu < (uint64_t)guest_ncpus; cpu++) {381uint64_t mpidr;382383error = vm_get_register(fbsdrun_vcpu(cpu), VM_REG_GUEST_MPIDR_EL1,384&mpidr);385assert(error == 0);386#define MPIDR_AFF_MASK (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK | MPIDR_AFF3_MASK)387cpu_to_mpidr[cpu] = mpidr & MPIDR_AFF_MASK;388#undef MPIDR_AFF_MASK389}390391bootrom = get_config_value("bootrom");392if (bootrom == NULL) {393warnx("no bootrom specified");394return (ENOENT);395}396load_bootrom(ctx, bootrom, &elr);397error = vm_set_register(bsp, VM_REG_GUEST_PC, elr);398if (error != 0) {399warn("vm_set_register(GUEST_PC)");400return (error);401}402403error = fdt_init(ctx, guest_ncpus, fdt_gpa(ctx), FDT_SIZE);404if (error != 0)405return (error);406407fdt_add_gic(GIC_DIST_BASE, GIC_DIST_SIZE, GIC_REDIST_BASE,408GIC_REDIST_SIZE(guest_ncpus));409error = vm_attach_vgic(ctx, GIC_DIST_BASE, GIC_DIST_SIZE,410GIC_REDIST_BASE, GIC_REDIST_SIZE(guest_ncpus));411if (error != 0) {412warn("vm_attach_vgic()");413return (error);414}415416error = init_mmio_uart(ctx);417if (error == 0)418fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR);419else if (error < 0)420return (error);421init_mmio_rtc(ctx);422fdt_add_rtc(RTC_MMIO_BASE, RTC_MMIO_SIZE, RTC_INTR);423fdt_add_timer();424pci_irq_init(pcie_intrs);425fdt_add_pcie(pcie_intrs);426427/* Mark CPU0 as running */428CPU_SET(0, &running_cpumask);429430return (0);431}432433int434bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused)435{436int error;437438fdt_finalize();439440error = vm_set_register(bsp, VM_REG_GUEST_X0, fdt_gpa(ctx));441assert(error == 0);442443return (0);444}445446447