Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107167012
D45512.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
43 KB
Referenced Files
None
Subscribers
None
D45512.diff
View Options
diff --git a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -202,7 +202,8 @@
SUBDIR.${MK_PMC}+= libipt
.endif
-.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64"
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64" || \
+ ${MACHINE_CPUARCH} == "riscv"
SUBDIR.${MK_BHYVE}+= libvmmapi
.endif
diff --git a/lib/libvmmapi/riscv/Makefile.inc b/lib/libvmmapi/riscv/Makefile.inc
new file mode 100644
--- /dev/null
+++ b/lib/libvmmapi/riscv/Makefile.inc
@@ -0,0 +1 @@
+SRCS+= vmmapi_machdep.c
diff --git a/lib/libvmmapi/riscv/vmmapi_machdep.c b/lib/libvmmapi/riscv/vmmapi_machdep.c
new file mode 100644
--- /dev/null
+++ b/lib/libvmmapi/riscv/vmmapi_machdep.c
@@ -0,0 +1,117 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011 NetApp, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+#include <machine/vmm_snapshot.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include "vmmapi.h"
+#include "internal.h"
+
+const char *vm_capstrmap[] = {
+ [VM_CAP_MAX] = NULL,
+};
+
+#define VM_MD_IOCTLS \
+ VM_ATTACH_APLIC, \
+ VM_ASSERT_IRQ, \
+ VM_DEASSERT_IRQ, \
+ VM_RAISE_MSI
+
+const cap_ioctl_t vm_ioctl_cmds[] = {
+ VM_COMMON_IOCTLS,
+ VM_MD_IOCTLS,
+};
+size_t vm_ioctl_ncmds = nitems(vm_ioctl_cmds);
+
+int
+vm_attach_aplic(struct vmctx *ctx, uint64_t mem_start, size_t mem_size)
+{
+ struct vm_aplic_descr aplic;
+
+ bzero(&aplic, sizeof(aplic));
+ aplic.mem_start = mem_start;
+ aplic.mem_size = mem_size;
+
+ return (ioctl(ctx->fd, VM_ATTACH_APLIC, &aplic));
+}
+
+int
+vm_assert_irq(struct vmctx *ctx, uint32_t irq)
+{
+ struct vm_irq vi;
+
+ bzero(&vi, sizeof(vi));
+ vi.irq = irq;
+
+ return (ioctl(ctx->fd, VM_ASSERT_IRQ, &vi));
+}
+
+int
+vm_deassert_irq(struct vmctx *ctx, uint32_t irq)
+{
+ struct vm_irq vi;
+
+ bzero(&vi, sizeof(vi));
+ vi.irq = irq;
+
+ return (ioctl(ctx->fd, VM_DEASSERT_IRQ, &vi));
+}
+
+int
+vm_raise_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg,
+ int bus, int slot, int func)
+{
+ struct vm_msi vmsi;
+
+ bzero(&vmsi, sizeof(vmsi));
+ vmsi.addr = addr;
+ vmsi.msg = msg;
+ vmsi.bus = bus;
+ vmsi.slot = slot;
+ vmsi.func = func;
+
+ return (ioctl(ctx->fd, VM_RAISE_MSI, &vmsi));
+}
+
+int
+vm_inject_exception(struct vcpu *vcpu, uint64_t scause)
+{
+ struct vm_exception vmexc;
+
+ bzero(&vmexc, sizeof(vmexc));
+ vmexc.scause = scause;
+
+ return (vcpu_ioctl(vcpu, VM_INJECT_EXCEPTION, &vmexc));
+}
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -161,12 +161,17 @@
int vm_reinit(struct vmctx *ctx);
int vm_raise_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg,
int bus, int slot, int func);
-#ifdef __aarch64__
+#if defined(__aarch64__)
int vm_attach_vgic(struct vmctx *ctx, uint64_t dist_start, size_t dist_size,
uint64_t redist_start, size_t redist_size);
+int vm_inject_exception(struct vcpu *vcpu, uint64_t esr, uint64_t far);
+#elif defined(__riscv)
+int vm_attach_aplic(struct vmctx *ctx, uint64_t mem_start, size_t mem_size);
+int vm_inject_exception(struct vcpu *vcpu, uint64_t scause);
+#endif
+#if defined(__aarch64__) || defined(__riscv)
int vm_assert_irq(struct vmctx *ctx, uint32_t irq);
int vm_deassert_irq(struct vmctx *ctx, uint32_t irq);
-int vm_inject_exception(struct vcpu *vcpu, uint64_t esr, uint64_t far);
#endif
#ifdef __amd64__
int vm_apicid2vcpu(struct vmctx *ctx, int apicid);
diff --git a/usr.sbin/Makefile.riscv b/usr.sbin/Makefile.riscv
new file mode 100644
--- /dev/null
+++ b/usr.sbin/Makefile.riscv
@@ -0,0 +1,2 @@
+SUBDIR+= bhyve
+SUBDIR+= bhyvectl
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -136,7 +136,7 @@
* change this address without changing it in OVMF.
*/
#define PCI_EMUL_MEMBASE32 0xc0000000
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(__riscv)
#define PCI_EMUL_IOBASE 0xdf000000UL
#define PCI_EMUL_IOLIMIT 0xe0000000UL
#define PCI_EMUL_MEMBASE32 0xa0000000UL
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/pci_irq.h
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/pci_irq.h
@@ -36,6 +36,8 @@
#include "amd64/pci_irq_machdep.h"
#elif defined(__aarch64__)
#include "aarch64/pci_irq_machdep.h"
+#elif defined(__riscv)
+#include "riscv/pci_irq_machdep.h"
#else
#error Unsupported platform
#endif
diff --git a/usr.sbin/bhyve/riscv/Makefile.inc b/usr.sbin/bhyve/riscv/Makefile.inc
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/riscv/Makefile.inc
@@ -0,0 +1,7 @@
+SRCS+= \
+ fdt.c
+
+.PATH: ${BHYVE_SYSDIR}/sys/riscv/vmm
+SRCS+= vmm_instruction_emul.c
+
+BHYVE_FDT_SUPPORT=
diff --git a/usr.sbin/bhyve/riscv/bhyverun_machdep.c b/usr.sbin/bhyve/riscv/bhyverun_machdep.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/riscv/bhyverun_machdep.c
@@ -0,0 +1,357 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011 NetApp, Inc.
+ * All rights reserved.
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <vmmapi.h>
+
+#include "bhyverun.h"
+#include "config.h"
+#include "debug.h"
+#include "fdt.h"
+#include "mem.h"
+#include "pci_emul.h"
+#include "pci_irq.h"
+#include "uart_emul.h"
+#include "riscv.h"
+
+#define FDT_SIZE (64 * 1024)
+#define FDT_DTB_ALIGN 8
+
+/* Start of lowmem + 64K */
+#define UART_MMIO_BASE 0x10000
+#define UART_MMIO_SIZE 0x1000
+#define UART_INTR 1
+
+#define APLIC_MEM_BASE 0x2f000000
+#define APLIC_MEM_SIZE 0x10000
+
+#define PCIE_INTA 2
+#define PCIE_INTB 3
+#define PCIE_INTC 4
+#define PCIE_INTD 5
+
+void
+bhyve_init_config(void)
+{
+ init_config();
+
+ /* Set default values prior to option parsing. */
+ set_config_bool("acpi_tables", false);
+ set_config_bool("acpi_tables_in_memory", false);
+ set_config_value("memory.size", "256M");
+}
+
+void
+bhyve_usage(int code)
+{
+ const char *progname;
+
+ progname = getprogname();
+
+ fprintf(stderr,
+ "Usage: %s [-CDHhSW]\n"
+ " %*s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
+ " %*s [-k config_file] [-m mem] [-o var=value]\n"
+ " %*s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
+ " -C: include guest memory in core file\n"
+ " -c: number of CPUs and/or topology specification\n"
+ " -D: destroy on power-off\n"
+ " -h: help\n"
+ " -k: key=value flat config file\n"
+ " -m: memory size\n"
+ " -o: set config 'var' to 'value'\n"
+ " -p: pin 'vcpu' to 'hostcpu'\n"
+ " -S: guest memory cannot be swapped\n"
+ " -s: <slot,driver,configinfo> PCI slot config\n"
+ " -U: UUID\n"
+ " -W: force virtio to use single-vector MSI\n",
+ progname, (int)strlen(progname), "", (int)strlen(progname), "",
+ (int)strlen(progname), "");
+ exit(code);
+}
+
+void
+bhyve_optparse(int argc, char **argv)
+{
+ const char *optstr;
+ int c;
+
+ optstr = "hCDSWk:f:o:p:c:s:m:U:";
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'c':
+ if (bhyve_topology_parse(optarg) != 0) {
+ errx(EX_USAGE, "invalid cpu topology '%s'",
+ optarg);
+ }
+ break;
+ case 'C':
+ set_config_bool("memory.guest_in_core", true);
+ break;
+ case 'D':
+ set_config_bool("destroy_on_poweroff", true);
+ break;
+ case 'k':
+ bhyve_parse_simple_config_file(optarg);
+ break;
+ case 'm':
+ set_config_value("memory.size", optarg);
+ break;
+ case 'o':
+ if (!bhyve_parse_config_option(optarg)) {
+ errx(EX_USAGE,
+ "invalid configuration option '%s'",
+ optarg);
+ }
+ break;
+ case 'p':
+ if (bhyve_pincpu_parse(optarg) != 0) {
+ errx(EX_USAGE,
+ "invalid vcpu pinning configuration '%s'",
+ optarg);
+ }
+ break;
+ case 's':
+ if (strncmp(optarg, "help", strlen(optarg)) == 0) {
+ pci_print_supported_devices();
+ exit(0);
+ } else if (pci_parse_slot(optarg) != 0)
+ exit(4);
+ else
+ break;
+ case 'S':
+ set_config_bool("memory.wired", true);
+ break;
+ case 'U':
+ set_config_value("uuid", optarg);
+ break;
+ case 'W':
+ set_config_bool("virtio_msix", false);
+ break;
+ case 'h':
+ bhyve_usage(0);
+ default:
+ bhyve_usage(1);
+ }
+ }
+}
+
+void
+bhyve_init_vcpu(struct vcpu *vcpu __unused)
+{
+}
+
+void
+bhyve_start_vcpu(struct vcpu *vcpu, bool bsp __unused)
+{
+ int error;
+
+ /* Set hart ID. */
+ error = vm_set_register(vcpu, VM_REG_GUEST_A0, vcpu_id(vcpu));
+ assert(error == 0);
+
+ fbsdrun_addcpu(vcpu_id(vcpu));
+}
+
+/*
+ * Load the specified boot code at the beginning of high memory.
+ */
+static void
+load_bootrom(struct vmctx *ctx, const char *path, uint64_t *elrp,
+ uint64_t *lenp)
+{
+ struct stat sb;
+ void *data, *gptr;
+ vm_paddr_t loadaddr;
+ off_t size;
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ err(1, "open(%s)", path);
+ if (fstat(fd, &sb) != 0)
+ err(1, "fstat(%s)", path);
+
+ size = sb.st_size;
+
+ loadaddr = vm_get_highmem_base(ctx);
+ gptr = vm_map_gpa(ctx, loadaddr, round_page(size));
+
+ data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED)
+ err(1, "mmap(%s)", path);
+ (void)close(fd);
+ memcpy(gptr, data, size);
+
+ if (munmap(data, size) != 0)
+ err(1, "munmap(%s)", path);
+
+ *elrp = loadaddr;
+ *lenp = size;
+}
+
+static void
+mmio_uart_intr_assert(void *arg)
+{
+ struct vmctx *ctx = arg;
+
+ vm_assert_irq(ctx, UART_INTR);
+}
+
+static void
+mmio_uart_intr_deassert(void *arg)
+{
+ struct vmctx *ctx = arg;
+
+ vm_deassert_irq(ctx, UART_INTR);
+}
+
+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)
+{
+ struct uart_ns16550_softc *sc = arg1;
+ long reg;
+
+ reg = addr - arg2;
+ if (dir == MEM_F_WRITE)
+ uart_ns16550_write(sc, reg, *val);
+ else
+ *val = uart_ns16550_read(sc, reg);
+
+ return (0);
+}
+
+static bool
+init_mmio_uart(struct vmctx *ctx)
+{
+ struct uart_ns16550_softc *sc;
+ struct mem_range mr;
+ const char *path;
+ int error;
+
+ path = get_config_value("console");
+ if (path == NULL)
+ return (false);
+
+ sc = uart_ns16550_init(mmio_uart_intr_assert, mmio_uart_intr_deassert,
+ ctx);
+ if (uart_ns16550_tty_open(sc, path) != 0) {
+ EPRINTLN("Unable to initialize backend '%s' for mmio uart",
+ path);
+ assert(0);
+ }
+
+ bzero(&mr, sizeof(struct mem_range));
+ mr.name = "uart";
+ mr.base = UART_MMIO_BASE;
+ mr.size = UART_MMIO_SIZE;
+ mr.flags = MEM_F_RW;
+ mr.handler = mmio_uart_mem_handler;
+ mr.arg1 = sc;
+ mr.arg2 = mr.base;
+ error = register_mem(&mr);
+ assert(error == 0);
+
+ return (true);
+}
+
+int
+bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp)
+{
+ const char *bootrom;
+ uint64_t elr;
+ uint64_t len;
+ int error;
+ int pcie_intrs[4] = {PCIE_INTA, PCIE_INTB, PCIE_INTC, PCIE_INTD};
+ vm_paddr_t fdt_gpa;
+
+ bootrom = get_config_value("bootrom");
+ if (bootrom == NULL) {
+ warnx("no bootrom specified");
+ return (ENOENT);
+ }
+ load_bootrom(ctx, bootrom, &elr, &len);
+ error = vm_set_register(bsp, VM_REG_GUEST_SEPC, elr);
+ if (error != 0) {
+ warn("vm_set_register(GUEST_SEPC)");
+ return (error);
+ }
+
+ fdt_gpa = vm_get_highmem_base(ctx) + roundup2(len, FDT_DTB_ALIGN);
+ error = fdt_init(ctx, guest_ncpus, fdt_gpa, FDT_SIZE);
+ if (error != 0)
+ return (error);
+
+ /* Set FDT base address to the bootable hart. */
+ error = vm_set_register(bsp, VM_REG_GUEST_A1, fdt_gpa);
+ assert(error == 0);
+
+ fdt_add_aplic(APLIC_MEM_BASE, APLIC_MEM_SIZE);
+ error = vm_attach_aplic(ctx, APLIC_MEM_BASE, APLIC_MEM_SIZE);
+ if (error != 0) {
+ warn("vm_attach_aplic()");
+ return (error);
+ }
+
+ if (init_mmio_uart(ctx))
+ fdt_add_uart(UART_MMIO_BASE, UART_MMIO_SIZE, UART_INTR);
+
+ pci_irq_init(pcie_intrs);
+ fdt_add_pcie(pcie_intrs);
+ vmexit_set_bsp(vcpu_id(bsp));
+
+ return (0);
+}
+
+int
+bhyve_init_platform_late(struct vmctx *ctx __unused, struct vcpu *bsp __unused)
+{
+
+ fdt_finalize();
+
+ return (0);
+}
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/riscv/fdt.h
copy from usr.sbin/bhyve/pci_irq.h
copy to usr.sbin/bhyve/riscv/fdt.h
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/riscv/fdt.h
@@ -1,9 +1,10 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2014 Hudson River Trading LLC
- * Written by: John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
+ * Copyright (c) 2022 The FreeBSD Foundation
+ *
+ * This software was developed by Andrew Turner under sponsorship from
+ * the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -17,7 +18,7 @@
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -27,21 +28,18 @@
* SUCH DAMAGE.
*/
-#ifndef __PCI_IRQ_H__
-#define __PCI_IRQ_H__
+#ifndef _FDT_H_
+#define _FDT_H_
-struct pci_devinst;
+#include <sys/types.h>
-#if defined(__amd64__)
-#include "amd64/pci_irq_machdep.h"
-#elif defined(__aarch64__)
-#include "aarch64/pci_irq_machdep.h"
-#else
-#error Unsupported platform
-#endif
+struct vmctx;
-void pci_irq_assert(struct pci_devinst *pi);
-void pci_irq_deassert(struct pci_devinst *pi);
-void pci_irq_route(struct pci_devinst *pi, struct pci_irq *irq);
+int fdt_init(struct vmctx *ctx, int ncpu, vm_paddr_t addrp,
+ vm_size_t size);
+void fdt_add_aplic(uint64_t dist_base, uint64_t dist_size);
+void fdt_add_pcie(int intrs[static 4]);
+void fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr);
+void fdt_finalize(void);
-#endif
+#endif /* _FDT_H_ */
diff --git a/usr.sbin/bhyve/riscv/fdt.c b/usr.sbin/bhyve/riscv/fdt.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/riscv/fdt.c
@@ -0,0 +1,326 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 The FreeBSD Foundation
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by Andrew Turner under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <libfdt.h>
+#include <vmmapi.h>
+
+#include "config.h"
+#include "bhyverun.h"
+#include "fdt.h"
+
+#define SET_PROP_U32(prop, idx, val) \
+ ((uint32_t *)(prop))[(idx)] = cpu_to_fdt32(val)
+#define SET_PROP_U64(prop, idx, val) \
+ ((uint64_t *)(prop))[(idx)] = cpu_to_fdt64(val)
+
+#define IRQ_TYPE_LEVEL_HIGH 4
+#define IRQ_TYPE_LEVEL_LOW 8
+
+static void *fdtroot;
+static uint32_t aplic_phandle = 0;
+static uint32_t intc0_phandle = 0;
+
+static uint32_t
+assign_phandle(void *fdt)
+{
+ static uint32_t next_phandle = 1;
+ uint32_t phandle;
+
+ phandle = next_phandle;
+ next_phandle++;
+ fdt_property_u32(fdt, "phandle", phandle);
+
+ return (phandle);
+}
+
+static void
+set_single_reg(void *fdt, uint64_t start, uint64_t len)
+{
+ void *reg;
+
+ fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), ®);
+ SET_PROP_U64(reg, 0, start);
+ SET_PROP_U64(reg, 1, len);
+}
+
+static void
+add_cpu(void *fdt, int cpuid)
+{
+ char node_name[16];
+
+ snprintf(node_name, sizeof(node_name), "cpu@%d", cpuid);
+
+ fdt_begin_node(fdt, node_name);
+ fdt_property_string(fdt, "device_type", "cpu");
+ fdt_property_string(fdt, "compatible", "riscv");
+ fdt_property_u32(fdt, "reg", cpuid);
+ fdt_property_string(fdt, "riscv,isa", "rv64imafdc_sstc");
+ fdt_property_string(fdt, "mmu-type", "riscv,sv39");
+ fdt_property_string(fdt, "clock-frequency", "1000000000");
+
+ fdt_begin_node(fdt, "interrupt-controller");
+ intc0_phandle = assign_phandle(fdt);
+ fdt_property_u32(fdt, "#address-cells", 2);
+ fdt_property_u32(fdt, "#interrupt-cells", 1);
+ fdt_property(fdt, "interrupt-controller", NULL, 0);
+ fdt_property_string(fdt, "compatible", "riscv,cpu-intc");
+ fdt_end_node(fdt);
+
+ fdt_end_node(fdt);
+}
+
+static void
+add_cpus(void *fdt, int ncpu)
+{
+ int cpuid;
+
+ fdt_begin_node(fdt, "cpus");
+ /* XXX: Needed given the root #address-cells? */
+ fdt_property_u32(fdt, "#address-cells", 1);
+ fdt_property_u32(fdt, "#size-cells", 0);
+ fdt_property_u32(fdt, "timebase-frequency", 10000000);
+
+ for (cpuid = 0; cpuid < ncpu; cpuid++) {
+ add_cpu(fdt, cpuid);
+ }
+ fdt_end_node(fdt);
+}
+
+int
+fdt_init(struct vmctx *ctx, int ncpu, vm_paddr_t fdtaddr, vm_size_t fdtsize)
+{
+ void *fdt;
+ const char *bootargs;
+
+ fdt = paddr_guest2host(ctx, fdtaddr, fdtsize);
+ if (fdt == NULL)
+ return (EFAULT);
+
+ fdt_create(fdt, (int)fdtsize);
+
+ /* Add the memory reserve map (needed even if none is reserved) */
+ fdt_finish_reservemap(fdt);
+
+ /* Create the root node */
+ fdt_begin_node(fdt, "");
+
+ fdt_property_string(fdt, "compatible", "freebsd,bhyve");
+ fdt_property_u32(fdt, "#address-cells", 2);
+ fdt_property_u32(fdt, "#size-cells", 2);
+
+ fdt_begin_node(fdt, "chosen");
+ fdt_property_string(fdt, "stdout-path", "serial0:115200n8");
+ bootargs = get_config_value("fdt.bootargs");
+ if (bootargs != NULL)
+ fdt_property_string(fdt, "bootargs", bootargs);
+ fdt_end_node(fdt);
+
+ fdt_begin_node(fdt, "memory");
+ fdt_property_string(fdt, "device_type", "memory");
+ /* There is no lowmem on riscv. */
+ assert(vm_get_lowmem_size(ctx) == 0);
+ set_single_reg(fdt, vm_get_highmem_base(ctx), vm_get_highmem_size(ctx));
+ fdt_end_node(fdt);
+
+ add_cpus(fdt, ncpu);
+
+ /* Finalized by fdt_finalized(). */
+ fdtroot = fdt;
+
+ return (0);
+}
+
+void
+fdt_add_aplic(uint64_t mem_base, uint64_t mem_size)
+{
+ char node_name[32];
+ void *fdt, *prop;
+
+ fdt = fdtroot;
+
+ snprintf(node_name, sizeof(node_name), "interrupt-controller@%lx",
+ (unsigned long)mem_base);
+ fdt_begin_node(fdt, node_name);
+
+ aplic_phandle = assign_phandle(fdt);
+ fdt_property_string(fdt, "compatible", "riscv,aplic");
+ fdt_property(fdt, "interrupt-controller", NULL, 0);
+#if notyet
+ fdt_property(fdt, "msi-controller", NULL, 0);
+#endif
+ /* XXX: Needed given the root #address-cells? */
+ fdt_property_u32(fdt, "#address-cells", 2);
+ fdt_property_u32(fdt, "#interrupt-cells", 2);
+ fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), &prop);
+ SET_PROP_U64(prop, 0, mem_base);
+ SET_PROP_U64(prop, 1, mem_size);
+
+ fdt_property_placeholder(fdt, "interrupts-extended",
+ 2 * sizeof(uint32_t), &prop);
+ SET_PROP_U32(prop, 0, intc0_phandle);
+ SET_PROP_U32(prop, 1, 9);
+ fdt_property_u32(fdt, "riscv,num-sources", 63);
+
+ fdt_end_node(fdt);
+
+ fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
+}
+
+void
+fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr)
+{
+ void *fdt, *interrupts;
+ char node_name[32];
+
+ assert(aplic_phandle != 0);
+
+ fdt = fdtroot;
+
+ snprintf(node_name, sizeof(node_name), "serial@%lx", uart_base);
+ fdt_begin_node(fdt, node_name);
+ fdt_property_string(fdt, "compatible", "ns16550");
+ set_single_reg(fdt, uart_base, uart_size);
+ fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
+ fdt_property_placeholder(fdt, "interrupts", 2 * sizeof(uint32_t),
+ &interrupts);
+ SET_PROP_U32(interrupts, 0, intr);
+ SET_PROP_U32(interrupts, 1, IRQ_TYPE_LEVEL_HIGH);
+
+ fdt_end_node(fdt);
+
+ snprintf(node_name, sizeof(node_name), "/serial@%lx", uart_base);
+ fdt_begin_node(fdt, "aliases");
+ fdt_property_string(fdt, "serial0", node_name);
+ fdt_end_node(fdt);
+}
+
+void
+fdt_add_pcie(int intrs[static 4])
+{
+ void *fdt, *prop;
+ int slot, pin, intr, i;
+
+ assert(aplic_phandle != 0);
+
+ fdt = fdtroot;
+
+ fdt_begin_node(fdt, "pcie@1f0000000");
+ fdt_property_string(fdt, "compatible", "pci-host-ecam-generic");
+ fdt_property_u32(fdt, "#address-cells", 3);
+ fdt_property_u32(fdt, "#size-cells", 2);
+ fdt_property_string(fdt, "device_type", "pci");
+ fdt_property_u64(fdt, "bus-range", (0ul << 32) | 1);
+ set_single_reg(fdt, 0xe0000000, 0x10000000);
+ fdt_property_placeholder(fdt, "ranges",
+ 2 * 7 * sizeof(uint32_t), &prop);
+ SET_PROP_U32(prop, 0, 0x01000000);
+
+ SET_PROP_U32(prop, 1, 0);
+ SET_PROP_U32(prop, 2, 0xdf000000);
+
+ SET_PROP_U32(prop, 3, 0);
+ SET_PROP_U32(prop, 4, 0xdf000000);
+
+ SET_PROP_U32(prop, 5, 0);
+ SET_PROP_U32(prop, 6, 0x01000000);
+
+ SET_PROP_U32(prop, 7, 0x02000000);
+
+ SET_PROP_U32(prop, 8, 0);
+ SET_PROP_U32(prop, 9, 0xa0000000);
+
+ SET_PROP_U32(prop, 10, 0);
+ SET_PROP_U32(prop, 11, 0xa0000000);
+
+ SET_PROP_U32(prop, 12, 0);
+ SET_PROP_U32(prop, 13, 0x3f000000);
+
+#if notyet
+ fdt_property_placeholder(fdt, "msi-map", 4 * sizeof(uint32_t), &prop);
+ SET_PROP_U32(prop, 0, 0); /* RID base */
+ SET_PROP_U32(prop, 1, aplic_phandle); /* MSI parent */
+ SET_PROP_U32(prop, 2, 0); /* MSI base */
+ SET_PROP_U32(prop, 3, 0x10000); /* RID length */
+ fdt_property_u32(fdt, "msi-parent", aplic_phandle);
+#endif
+
+ fdt_property_u32(fdt, "#interrupt-cells", 1);
+ fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
+
+ /*
+ * Describe standard swizzled interrupts routing (pins rotated by one
+ * for each consecutive slot). Must match pci_irq_route().
+ */
+ fdt_property_placeholder(fdt, "interrupt-map-mask",
+ 4 * sizeof(uint32_t), &prop);
+ SET_PROP_U32(prop, 0, 3 << 11);
+ SET_PROP_U32(prop, 1, 0);
+ SET_PROP_U32(prop, 2, 0);
+ SET_PROP_U32(prop, 3, 7);
+ fdt_property_placeholder(fdt, "interrupt-map",
+ 16 * 9 * sizeof(uint32_t), &prop);
+ for (i = 0; i < 16; ++i) {
+ pin = i % 4;
+ slot = i / 4;
+ intr = intrs[(pin + slot) % 4];
+ SET_PROP_U32(prop, 10 * i + 0, slot << 11);
+ SET_PROP_U32(prop, 10 * i + 1, 0);
+ SET_PROP_U32(prop, 10 * i + 2, 0);
+ SET_PROP_U32(prop, 10 * i + 3, pin + 1);
+ SET_PROP_U32(prop, 10 * i + 4, aplic_phandle);
+ SET_PROP_U32(prop, 10 * i + 5, 0);
+ SET_PROP_U32(prop, 10 * i + 6, 0);
+ SET_PROP_U32(prop, 10 * i + 7, intr);
+ SET_PROP_U32(prop, 10 * i + 8, IRQ_TYPE_LEVEL_HIGH);
+ }
+
+ fdt_end_node(fdt);
+}
+
+void
+fdt_finalize(void)
+{
+ fdt_end_node(fdtroot);
+
+ fdt_finish(fdtroot);
+}
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/riscv/pci_irq.c
copy from usr.sbin/bhyve/pci_irq.h
copy to usr.sbin/bhyve/riscv/pci_irq.c
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/riscv/pci_irq.c
@@ -1,9 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2014 Hudson River Trading LLC
- * Written by: John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
+ * Copyright (c) 2024 Jessica Clarke <jrtc27@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,21 +25,42 @@
* SUCH DAMAGE.
*/
-#ifndef __PCI_IRQ_H__
-#define __PCI_IRQ_H__
+#include <vmmapi.h>
-struct pci_devinst;
+#include "pci_emul.h"
+#include "pci_irq.h"
-#if defined(__amd64__)
-#include "amd64/pci_irq_machdep.h"
-#elif defined(__aarch64__)
-#include "aarch64/pci_irq_machdep.h"
-#else
-#error Unsupported platform
-#endif
+static int aplic_irqs[4];
-void pci_irq_assert(struct pci_devinst *pi);
-void pci_irq_deassert(struct pci_devinst *pi);
-void pci_irq_route(struct pci_devinst *pi, struct pci_irq *irq);
+void
+pci_irq_init(int intrs[static 4])
+{
+ int i;
-#endif
+ for (i = 0; i < 4; ++i)
+ aplic_irqs[i] = intrs[i];
+}
+
+void
+pci_irq_assert(struct pci_devinst *pi)
+{
+ vm_assert_irq(pi->pi_vmctx, pi->pi_lintr.irq.aplic_irq);
+}
+
+void
+pci_irq_deassert(struct pci_devinst *pi)
+{
+ vm_deassert_irq(pi->pi_vmctx, pi->pi_lintr.irq.aplic_irq);
+}
+
+void
+pci_irq_route(struct pci_devinst *pi, struct pci_irq *irq)
+{
+ /*
+ * Assign swizzled IRQ for this INTx if one is not yet assigned. Must
+ * match fdt_add_pcie().
+ */
+ if (irq->aplic_irq == 0)
+ irq->aplic_irq =
+ aplic_irqs[(pi->pi_slot + pi->pi_lintr.pin - 1) % 4];
+}
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/riscv/pci_irq_machdep.h
copy from usr.sbin/bhyve/pci_irq.h
copy to usr.sbin/bhyve/riscv/pci_irq_machdep.h
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/riscv/pci_irq_machdep.h
@@ -1,9 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2014 Hudson River Trading LLC
- * Written by: John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
+ * Copyright (c) 2024 Jessica Clarke <jrtc27@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,21 +25,25 @@
* SUCH DAMAGE.
*/
-#ifndef __PCI_IRQ_H__
-#define __PCI_IRQ_H__
+#ifndef __PCI_IRQ_MD_H__
+#define __PCI_IRQ_MD_H__
-struct pci_devinst;
+struct pci_irq {
+ int aplic_irq;
+};
-#if defined(__amd64__)
-#include "amd64/pci_irq_machdep.h"
-#elif defined(__aarch64__)
-#include "aarch64/pci_irq_machdep.h"
-#else
-#error Unsupported platform
-#endif
+void pci_irq_init(int intrs[static 4]);
+
+static inline void
+pci_irq_init_irq(struct pci_irq *irq)
+{
+ irq->aplic_irq = 0;
+}
-void pci_irq_assert(struct pci_devinst *pi);
-void pci_irq_deassert(struct pci_devinst *pi);
-void pci_irq_route(struct pci_devinst *pi, struct pci_irq *irq);
+static inline uint8_t
+pci_irq_intline(struct pci_irq *irq __unused)
+{
+ return (255);
+}
#endif
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/riscv/riscv.h
copy from usr.sbin/bhyve/pci_irq.h
copy to usr.sbin/bhyve/riscv/riscv.h
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/riscv/riscv.h
@@ -1,9 +1,12 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2014 Hudson River Trading LLC
- * Written by: John H. Baldwin <jhb@FreeBSD.org>
- * All rights reserved.
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -14,10 +17,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -27,21 +30,12 @@
* SUCH DAMAGE.
*/
-#ifndef __PCI_IRQ_H__
-#define __PCI_IRQ_H__
-
-struct pci_devinst;
+#ifndef _RISCV_H_
+#define _RISCV_H_
-#if defined(__amd64__)
-#include "amd64/pci_irq_machdep.h"
-#elif defined(__aarch64__)
-#include "aarch64/pci_irq_machdep.h"
-#else
-#error Unsupported platform
-#endif
+#define CPU_TO_HART(x) (x)
+#define HART_TO_CPU(x) (x)
-void pci_irq_assert(struct pci_devinst *pi);
-void pci_irq_deassert(struct pci_devinst *pi);
-void pci_irq_route(struct pci_devinst *pi, struct pci_irq *irq);
+void vmexit_set_bsp(int hart_id);
-#endif
+#endif /* !_RISCV_H_ */
diff --git a/usr.sbin/bhyve/riscv/vmexit.c b/usr.sbin/bhyve/riscv/vmexit.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyve/riscv/vmexit.c
@@ -0,0 +1,366 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2011 NetApp, Inc.
+ * All rights reserved.
+ * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/cpuset.h>
+
+#include <machine/riscvreg.h>
+#include <machine/cpu.h>
+#include <machine/sbi.h>
+#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
+#include <machine/vmm_instruction_emul.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vmmapi.h>
+
+#include "bhyverun.h"
+#include "config.h"
+#include "debug.h"
+#include "mem.h"
+#include "vmexit.h"
+#include "riscv.h"
+
+#define BHYVE_VERSION ((uint64_t)__FreeBSD_version)
+#define SBI_VERS_MAJOR 2
+#define SBI_VERS_MINOR 0
+
+static cpuset_t running_hartmask = CPUSET_T_INITIALIZER(0);
+
+void
+vmexit_set_bsp(int hart_id)
+{
+
+ CPU_SET_ATOMIC(hart_id, &running_hartmask);
+}
+
+static int
+vmexit_inst_emul(struct vmctx *ctx __unused, struct vcpu *vcpu,
+ struct vm_run *vmrun)
+{
+ struct vm_exit *vme;
+ struct vie *vie;
+ int err;
+
+ vme = vmrun->vm_exit;
+ vie = &vme->u.inst_emul.vie;
+
+ err = emulate_mem(vcpu, vme->u.inst_emul.gpa, vie,
+ &vme->u.inst_emul.paging);
+ if (err) {
+ if (err == ESRCH) {
+ EPRINTLN("Unhandled memory access to 0x%lx\n",
+ vme->u.inst_emul.gpa);
+ }
+ goto fail;
+ }
+
+ return (VMEXIT_CONTINUE);
+
+fail:
+ fprintf(stderr, "Failed to emulate instruction ");
+ FPRINTLN(stderr, "at 0x%lx", vme->pc);
+ return (VMEXIT_ABORT);
+}
+
+static int
+vmexit_suspend(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun)
+{
+ struct vm_exit *vme;
+ enum vm_suspend_how how;
+ int vcpuid = vcpu_id(vcpu);
+
+ vme = vmrun->vm_exit;
+ how = vme->u.suspended.how;
+
+ fbsdrun_deletecpu(vcpuid);
+
+ switch (how) {
+ case VM_SUSPEND_RESET:
+ exit(0);
+ case VM_SUSPEND_POWEROFF:
+ if (get_config_bool_default("destroy_on_poweroff", false))
+ vm_destroy(ctx);
+ exit(1);
+ case VM_SUSPEND_HALT:
+ exit(2);
+ default:
+ fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
+ exit(100);
+ }
+
+ /* NOT REACHED. */
+
+ return (0);
+}
+
+static int
+vmexit_debug(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
+ struct vm_run *vmrun __unused)
+{
+
+ return (VMEXIT_CONTINUE);
+}
+
+static int
+vmexit_bogus(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
+ struct vm_run *vmrun __unused)
+{
+
+ return (VMEXIT_CONTINUE);
+}
+
+static int
+vmm_sbi_probe_extension(int ext_id)
+{
+
+ switch (ext_id) {
+ case SBI_EXT_ID_HSM:
+ case SBI_EXT_ID_TIME:
+ case SBI_EXT_ID_IPI:
+ case SBI_EXT_ID_RFNC:
+ case SBI_EXT_ID_SRST:
+ case SBI_CONSOLE_PUTCHAR:
+ case SBI_CONSOLE_GETCHAR:
+ break;
+ default:
+ return (0);
+ }
+
+ return (1);
+}
+
+static void
+vmexit_ecall_time(struct vmctx *ctx __unused, struct vm_exit *vme __unused)
+{
+
+}
+
+static void
+vmexit_ecall_hsm(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
+ struct vm_exit *vme)
+{
+ struct vcpu *newvcpu;
+ uint64_t hart_id;
+ int func_id;
+ int error;
+ int ret;
+
+ hart_id = vme->u.ecall.args[0];
+ func_id = vme->u.ecall.args[6];
+
+ ret = -1;
+
+ if (HART_TO_CPU(hart_id) >= (uint64_t)guest_ncpus)
+ goto done;
+
+ newvcpu = fbsdrun_vcpu(HART_TO_CPU(hart_id));
+ assert(newvcpu != NULL);
+
+ switch (func_id) {
+ case SBI_HSM_HART_START:
+ if (CPU_ISSET(hart_id, &running_hartmask))
+ break;
+
+ /* Set hart ID. */
+ error = vm_set_register(newvcpu, VM_REG_GUEST_A0, hart_id);
+ assert(error == 0);
+
+ /* Set PC. */
+ error = vm_set_register(newvcpu, VM_REG_GUEST_SEPC,
+ vme->u.ecall.args[1]);
+ assert(error == 0);
+
+ vm_resume_cpu(newvcpu);
+ CPU_SET_ATOMIC(hart_id, &running_hartmask);
+
+ ret = 0;
+ break;
+ case SBI_HSM_HART_STOP:
+ if (!CPU_ISSET(hart_id, &running_hartmask))
+ break;
+ CPU_CLR_ATOMIC(hart_id, &running_hartmask);
+ vm_suspend_cpu(newvcpu);
+ ret = 0;
+ break;
+ case SBI_HSM_HART_STATUS:
+ /* TODO. */
+ break;
+ default:
+ break;
+ }
+
+done:
+ error = vm_set_register(vcpu, VM_REG_GUEST_A0, ret);
+ assert(error == 0);
+}
+
+static void
+vmexit_ecall_base(struct vmctx *ctx __unused, struct vcpu *vcpu,
+ struct vm_exit *vme)
+{
+ int sbi_function_id;
+ int ext_id;
+ int error;
+ uint32_t val;
+ int ret;
+
+ sbi_function_id = vme->u.ecall.args[6];
+
+ ret = 0;
+
+ switch (sbi_function_id) {
+ case SBI_BASE_GET_SPEC_VERSION:
+ val = SBI_VERS_MAJOR << SBI_SPEC_VERS_MAJOR_OFFSET;
+ val |= SBI_VERS_MINOR << SBI_SPEC_VERS_MINOR_OFFSET;
+ break;
+ case SBI_BASE_GET_IMPL_ID:
+ val = SBI_IMPL_ID_BHYVE;
+ break;
+ case SBI_BASE_GET_IMPL_VERSION:
+ val = BHYVE_VERSION;
+ break;
+ case SBI_BASE_PROBE_EXTENSION:
+ ext_id = vme->u.ecall.args[0];
+ val = vmm_sbi_probe_extension(ext_id);
+ break;
+ case SBI_BASE_GET_MVENDORID:
+ val = MVENDORID_UNIMPL;
+ break;
+ case SBI_BASE_GET_MARCHID:
+ val = MARCHID_UNIMPL;
+ break;
+ case SBI_BASE_GET_MIMPID:
+ val = 0;
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+
+ error = vm_set_register(vcpu, VM_REG_GUEST_A0, ret);
+ assert(error == 0);
+
+ if (ret == 0) {
+ error = vm_set_register(vcpu, VM_REG_GUEST_A1, val);
+ assert(error == 0);
+ }
+}
+
+static void
+vmexit_ecall_srst(struct vmctx *ctx, struct vm_exit *vme)
+{
+ enum vm_suspend_how how;
+ int func_id;
+ int type;
+
+ func_id = vme->u.ecall.args[6];
+ type = vme->u.ecall.args[0];
+
+ switch (func_id) {
+ case SBI_SRST_SYSTEM_RESET:
+ switch (type) {
+ case SBI_SRST_TYPE_SHUTDOWN:
+ case SBI_SRST_TYPE_COLD_REBOOT:
+ case SBI_SRST_TYPE_WARM_REBOOT:
+ how = VM_SUSPEND_POWEROFF;
+ vm_suspend(ctx, how);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static int
+vmexit_ecall(struct vmctx *ctx, struct vcpu *vcpu, struct vm_run *vmrun)
+{
+ int sbi_extension_id;
+ struct vm_exit *vme;
+
+ vme = vmrun->vm_exit;
+
+ sbi_extension_id = vme->u.ecall.args[7];
+ switch (sbi_extension_id) {
+ case SBI_EXT_ID_SRST:
+ vmexit_ecall_srst(ctx, vme);
+ break;
+ case SBI_EXT_ID_BASE:
+ vmexit_ecall_base(ctx, vcpu, vme);
+ break;
+ case SBI_EXT_ID_TIME:
+ vmexit_ecall_time(ctx, vme);
+ break;
+ case SBI_EXT_ID_HSM:
+ vmexit_ecall_hsm(ctx, vcpu, vme);
+ break;
+ case SBI_CONSOLE_PUTCHAR:
+ case SBI_CONSOLE_GETCHAR:
+ default:
+ /* Unknown SBI extension. */
+ break;
+ }
+
+ return (VMEXIT_CONTINUE);
+}
+
+
+static int
+vmexit_hyp(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
+ struct vm_run *vmrun)
+{
+ struct vm_exit *vme;
+
+ vme = vmrun->vm_exit;
+
+ printf("unhandled exception: scause %#lx\n", vme->u.hyp.scause);
+
+ return (VMEXIT_ABORT);
+}
+
+const vmexit_handler_t vmexit_handlers[VM_EXITCODE_MAX] = {
+ [VM_EXITCODE_BOGUS] = vmexit_bogus,
+ [VM_EXITCODE_HYP] = vmexit_hyp,
+ [VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
+ [VM_EXITCODE_SUSPENDED] = vmexit_suspend,
+ [VM_EXITCODE_DEBUG] = vmexit_debug,
+ [VM_EXITCODE_ECALL] = vmexit_ecall,
+};
diff --git a/usr.sbin/bhyvectl/riscv/Makefile.inc b/usr.sbin/bhyvectl/riscv/Makefile.inc
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyvectl/riscv/Makefile.inc
@@ -0,0 +1 @@
+SRCS+= bhyvectl_machdep.c
diff --git a/usr.sbin/bhyvectl/riscv/bhyvectl_machdep.c b/usr.sbin/bhyvectl/riscv/bhyvectl_machdep.c
new file mode 100644
--- /dev/null
+++ b/usr.sbin/bhyvectl/riscv/bhyvectl_machdep.c
@@ -0,0 +1,82 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ *
+ * This software was developed by the University of Cambridge Computer
+ * Laboratory (Department of Computer Science and Technology) under Innovate
+ * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
+ * Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <vmmapi.h>
+
+#include "bhyvectl.h"
+
+void
+bhyvectl_dump_vm_run_exitcode(struct vm_exit *vmexit __unused,
+ int vcpu __unused)
+{
+}
+
+struct option *
+bhyvectl_opts(const struct option *options, size_t count)
+{
+ struct option *all_opts;
+
+ all_opts = calloc(count + 1, sizeof(struct option));
+ if (all_opts == NULL)
+ err(1, "calloc");
+ memcpy(all_opts, options, count * sizeof(struct option));
+ return (all_opts);
+}
+
+void
+bhyvectl_handle_opt(const struct option *opts __unused, int opt __unused)
+{
+}
+
+const char *
+bhyvectl_opt_desc(int opt __unused)
+{
+ /* No riscv-specific options yet. */
+ return ("???");
+}
+
+void
+bhyvectl_md_main(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
+ int vcpuid __unused, bool get_all __unused)
+{
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 12, 3:46 AM (21 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15760780
Default Alt Text
D45512.diff (43 KB)
Attached To
Mode
D45512: bhyve/riscv userspace part
Attached
Detach File
Event Timeline
Log In to Comment