From nobody Thu Oct 31 20:25:34 2024
X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1])
by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Xfb8t4GZSz5cKPb;
Thu, 31 Oct 2024 20:25:34 +0000 (UTC)
(envelope-from git@FreeBSD.org)
Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256
client-signature RSA-PSS (4096 bits) client-digest SHA256)
(Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK))
by mx1.freebsd.org (Postfix) with ESMTPS id 4Xfb8t3WB9z4VGc;
Thu, 31 Oct 2024 20:25:34 +0000 (UTC)
(envelope-from git@FreeBSD.org)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim;
t=1730406334;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding;
bh=XP1+lIMW0gSec8TSA2QJkiCKPagTjxmFepARBBe4ssU=;
b=DXMKkc6jFQOEd6qTrWAwEfkLuse7OpAzKJ3sHYSNi6SYFHmfz/3La1RxO08kq8HIlg3MHF
ASHNfTq1cIRdN1TEDJsseMHCH/6GTR7+VXDLuFAJbfYhgxMsqx7EN013mZB9Wc686zz09u
sZ7S0YnPLebQ3j3xUA0jnIYldFhDhFyHz+XhkF/P5VV+R7M8sOTTW9EqSSxAkp/IUOXeUv
iOrKnietTuEOvxPQPNez8fdSByjSgJrwqov7FxLYEL9vNvaUunHX6Q9cq61MSuh2kVUHg5
8hxZ1X2rxQh+/QvKl2JrXvFRzRQLrGB4gRg/AqU5zSHA4GQU0UXpGsIOoe177A==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org;
s=dkim; t=1730406334;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding;
bh=XP1+lIMW0gSec8TSA2QJkiCKPagTjxmFepARBBe4ssU=;
b=b9QDaxNatHjj4COej83yrgwpyvJulP6FJ9Uk5NRMs7KNyw6yPHcreUIRrszm5l9dNTWvIg
R2JyPEpKlJw47bGoylWE4Z4sYDKVxwJLYKErerEQdyZi4N0jGtJYqWa2XzHs+3+xDbEswK
YGaJ2+tbCOMN5IdFTHs1jCEacBPyvCGy9qtZQKA1d11rZj5B22Eyg2uTD1HBuZZ6C+jrtS
99lkve5pENsRY53wVITqeLj/aHvOXyB34x6gje1qLETD+Mw2e6mQeYL3s8RaHlqt6vTymC
tpQ0kSDKk2klbfG4evcATv1G/VGHZx91fmJyXTpTNdhRw2VRzLOKWD1oEWx2WQ==
ARC-Authentication-Results: i=1;
mx1.freebsd.org;
none
ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1730406334; a=rsa-sha256; cv=none;
b=EOSdC8pWMq5QABnuZ2PueR2TkMx34I3flFo4TQBh5TB3h8nWWEHWTgS1snrOdziVn0Yht8
+9AmG2FM+8SsYg45E1BXie7lbK8Gqf7Bx6YFGMs+pbcGRrhRLskt/0y3nw5cZdHi3J2AUI
aXNcvManagtU8HUuQh0NTJgQ5tTfR+AncfAOO9yVasXk5Nl37KMZQSvB3BTrmIJiWS6Y1Y
khNRPgOBzYQEpTw3CrkDJ23xXly8pkRM/OgZgO/cZYsYBhg0iTCTq0giJSwZ8hE2NY5CBf
Prhjl8tQKGzAQ4KGV5qQK0pAdBIM9IPp9djJMx52Z0iZ+JL1UNxDGhp5rRsPvQ==
Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256)
(Client did not present a certificate)
by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Xfb8t35sRzqd5;
Thu, 31 Oct 2024 20:25:34 +0000 (UTC)
(envelope-from git@FreeBSD.org)
Received: from gitrepo.freebsd.org ([127.0.1.44])
by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 49VKPYsI063797;
Thu, 31 Oct 2024 20:25:34 GMT
(envelope-from git@gitrepo.freebsd.org)
Received: (from git@localhost)
by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 49VKPYbK063789;
Thu, 31 Oct 2024 20:25:34 GMT
(envelope-from git)
Date: Thu, 31 Oct 2024 20:25:34 GMT
Message-Id: <202410312025.49VKPYbK063789@gitrepo.freebsd.org>
To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org,
dev-commits-src-main@FreeBSD.org
From: Ruslan Bukin
Subject: git: 7ab1a32cd43c - main - bhyve/riscv: Initial import.
List-Id: Commit messages for all branches of the src repository
List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all
List-Help:
List-Post:
List-Subscribe:
List-Unsubscribe:
X-BeenThere: dev-commits-src-all@freebsd.org
Sender: owner-dev-commits-src-all@FreeBSD.org
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Git-Committer: br
X-Git-Repository: src
X-Git-Refname: refs/heads/main
X-Git-Reftype: branch
X-Git-Commit: 7ab1a32cd43cbae61ad4dd435d6a482bbf61cb52
Auto-Submitted: auto-generated
The branch main has been updated by br:
URL: https://cgit.FreeBSD.org/src/commit/?id=7ab1a32cd43cbae61ad4dd435d6a482bbf61cb52
commit 7ab1a32cd43cbae61ad4dd435d6a482bbf61cb52
Author: Ruslan Bukin
AuthorDate: 2024-10-31 16:14:32 +0000
Commit: Ruslan Bukin
CommitDate: 2024-10-31 20:24:12 +0000
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
---
lib/Makefile | 3 +-
lib/libvmmapi/riscv/Makefile.inc | 1 +
lib/libvmmapi/riscv/vmmapi_machdep.c | 117 +++++++++
lib/libvmmapi/vmmapi.h | 9 +-
usr.sbin/Makefile.riscv | 2 +
usr.sbin/bhyve/pci_emul.c | 2 +-
usr.sbin/bhyve/pci_irq.h | 2 +
usr.sbin/bhyve/riscv/Makefile.inc | 7 +
usr.sbin/bhyve/riscv/bhyverun_machdep.c | 357 ++++++++++++++++++++++++++++
usr.sbin/bhyve/riscv/fdt.c | 326 +++++++++++++++++++++++++
usr.sbin/bhyve/riscv/fdt.h | 45 ++++
usr.sbin/bhyve/riscv/pci_irq.c | 66 ++++++
usr.sbin/bhyve/riscv/pci_irq_machdep.h | 49 ++++
usr.sbin/bhyve/riscv/riscv.h | 41 ++++
usr.sbin/bhyve/riscv/vmexit.c | 366 +++++++++++++++++++++++++++++
usr.sbin/bhyvectl/riscv/Makefile.inc | 1 +
usr.sbin/bhyvectl/riscv/bhyvectl_machdep.c | 82 +++++++
17 files changed, 1472 insertions(+), 4 deletions(-)
diff --git a/lib/Makefile b/lib/Makefile
index fdfe198bea10..af0079978075 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/libvmmapi/riscv/Makefile.inc b/lib/libvmmapi/riscv/Makefile.inc
new file mode 100644
index 000000000000..663ea0ab90a3
--- /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
index 000000000000..9c70185942c9
--- /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
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#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
index d2a217c4d2e9..0ea1d5824271 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -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);
diff --git a/usr.sbin/Makefile.riscv b/usr.sbin/Makefile.riscv
new file mode 100644
index 000000000000..a8897983059c
--- /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
index b61f29aa6830..2f04a488d9c1 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -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
diff --git a/usr.sbin/bhyve/pci_irq.h b/usr.sbin/bhyve/pci_irq.h
index 8b556ddc91a2..8078583add52 100644
--- a/usr.sbin/bhyve/pci_irq.h
+++ b/usr.sbin/bhyve/pci_irq.h
@@ -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
diff --git a/usr.sbin/bhyve/riscv/Makefile.inc b/usr.sbin/bhyve/riscv/Makefile.inc
new file mode 100644
index 000000000000..2b57201c6259
--- /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
index 000000000000..39d6a7cdf231
--- /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
+ *
+ * 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
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#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: 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/riscv/fdt.c b/usr.sbin/bhyve/riscv/fdt.c
new file mode 100644
index 000000000000..54b75c68ea76
--- /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
+ *
+ * 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
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#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/riscv/fdt.h b/usr.sbin/bhyve/riscv/fdt.h
new file mode 100644
index 000000000000..9bebe6ffa29d
--- /dev/null
+++ b/usr.sbin/bhyve/riscv/fdt.h
@@ -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_
+
*** 653 LINES SKIPPED ***