bhyve/riscv: Initial import.

Add machine-dependent parts for bhyve hypervisor to support
virtualization on RISC-V ISA.

No objection:	markj
Sponsored by: UK Research and Innovation
Differential Revision: https://reviews.freebsd.org/D45512
This commit is contained in:
Ruslan Bukin 2024-10-31 16:14:32 +00:00
parent d3916eace5
commit 7ab1a32cd4
17 changed files with 1472 additions and 4 deletions

View File

@ -202,7 +202,8 @@ SUBDIR.${MK_PMC}+= libopencsd
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

View File

@ -0,0 +1 @@
SRCS+= vmmapi_machdep.c

View File

@ -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));
}

View File

@ -161,12 +161,17 @@ int vm_suspend(struct vmctx *ctx, enum vm_suspend_how how);
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);

2
usr.sbin/Makefile.riscv Normal file
View File

@ -0,0 +1,2 @@
SUBDIR+= bhyve
SUBDIR+= bhyvectl

View File

@ -136,7 +136,7 @@ static TAILQ_HEAD(boot_list, boot_device) boot_devices = TAILQ_HEAD_INITIALIZER(
* 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

View File

@ -36,6 +36,8 @@ struct pci_devinst;
#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

View File

@ -0,0 +1,7 @@
SRCS+= \
fdt.c
.PATH: ${BHYVE_SYSDIR}/sys/riscv/vmm
SRCS+= vmm_instruction_emul.c
BHYVE_FDT_SUPPORT=

View File

@ -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);
}

326
usr.sbin/bhyve/riscv/fdt.c Normal file
View File

@ -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), &reg);
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);
}

View File

@ -0,0 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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
* 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.
*/
#ifndef _FDT_H_
#define _FDT_H_
#include <sys/types.h>
struct vmctx;
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 /* _FDT_H_ */

View File

@ -0,0 +1,66 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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
* 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 <vmmapi.h>
#include "pci_emul.h"
#include "pci_irq.h"
static int aplic_irqs[4];
void
pci_irq_init(int intrs[static 4])
{
int i;
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];
}

View File

@ -0,0 +1,49 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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
* 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.
*/
#ifndef __PCI_IRQ_MD_H__
#define __PCI_IRQ_MD_H__
struct pci_irq {
int aplic_irq;
};
void pci_irq_init(int intrs[static 4]);
static inline void
pci_irq_init_irq(struct pci_irq *irq)
{
irq->aplic_irq = 0;
}
static inline uint8_t
pci_irq_intline(struct pci_irq *irq __unused)
{
return (255);
}
#endif

View File

@ -0,0 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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.
*/
#ifndef _RISCV_H_
#define _RISCV_H_
#define CPU_TO_HART(x) (x)
#define HART_TO_CPU(x) (x)
void vmexit_set_bsp(int hart_id);
#endif /* !_RISCV_H_ */

View File

@ -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,
};

View File

@ -0,0 +1 @@
SRCS+= bhyvectl_machdep.c

View File

@ -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)
{
}