summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2022-02-16 18:04:54 +0000
committerPatrick Mooney <pmooney@oxide.computer>2022-03-02 16:31:35 +0000
commit3d0662810ae7f231943be2eb0bf9cd8b25496ddb (patch)
treed16f7a5d492b09b285953b8442fb64c33aa2984c
parentd2b76ef70a19a09ea9aab5aaeb614dc7c9d195ed (diff)
downloadillumos-gate-3d0662810ae7f231943be2eb0bf9cd8b25496ddb.tar.gz
14511 bhyve needs devmem access for all segments
Reviewed by: Dan Cross <cross@oxidecomputer.com> Reviewed by: Luqman Aden <luqman@oxide.computer> Reviewed by: Andy Fiddaman <andy@omnios.org> Approved by: Robert Mustacchi <rm@fingolfin.org>
-rw-r--r--usr/src/pkg/manifests/system-bhyve-tests.p5m1
-rw-r--r--usr/src/test/bhyve-tests/runfiles/default.run8
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/Makefile1
-rw-r--r--usr/src/test/bhyve-tests/tests/vmm/mem_devmem.c160
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c58
5 files changed, 200 insertions, 28 deletions
diff --git a/usr/src/pkg/manifests/system-bhyve-tests.p5m b/usr/src/pkg/manifests/system-bhyve-tests.p5m
index 823ed69a60..d0d31a0190 100644
--- a/usr/src/pkg/manifests/system-bhyve-tests.p5m
+++ b/usr/src/pkg/manifests/system-bhyve-tests.p5m
@@ -39,6 +39,7 @@ file path=opt/bhyve-tests/tests/mevent/vnode_file mode=0555
file path=opt/bhyve-tests/tests/mevent/vnode_zvol mode=0555
dir path=opt/bhyve-tests/tests/vmm
file path=opt/bhyve-tests/tests/vmm/fpu_getset mode=0555
+file path=opt/bhyve-tests/tests/vmm/mem_devmem mode=0555
file path=opt/bhyve-tests/tests/vmm/mem_partial mode=0555
file path=opt/bhyve-tests/tests/vmm/mem_seg_map mode=0555
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/test/bhyve-tests/runfiles/default.run b/usr/src/test/bhyve-tests/runfiles/default.run
index 3055f3e2d8..0aae1bcb46 100644
--- a/usr/src/test/bhyve-tests/runfiles/default.run
+++ b/usr/src/test/bhyve-tests/runfiles/default.run
@@ -20,7 +20,13 @@ post =
outputdir = /var/tmp/test_results
[/opt/bhyve-tests/tests/vmm]
-tests = ['mem_partial', 'mem_seg_map', 'fpu_getset']
+user = root
+tests = [
+ 'fpu_getset',
+ 'mem_devmem',
+ 'mem_partial',
+ 'mem_seg_map'
+ ]
# Tests of userspace mevent system, built from cmd/bhyve
[/opt/bhyve-tests/tests/mevent]
diff --git a/usr/src/test/bhyve-tests/tests/vmm/Makefile b/usr/src/test/bhyve-tests/tests/vmm/Makefile
index 30d06a0f6b..97cf709ca3 100644
--- a/usr/src/test/bhyve-tests/tests/vmm/Makefile
+++ b/usr/src/test/bhyve-tests/tests/vmm/Makefile
@@ -17,6 +17,7 @@ include $(SRC)/test/Makefile.com
PROG = mem_partial \
mem_seg_map \
+ mem_devmem \
fpu_getset
COMMON_OBJS = common.o
diff --git a/usr/src/test/bhyve-tests/tests/vmm/mem_devmem.c b/usr/src/test/bhyve-tests/tests/vmm/mem_devmem.c
new file mode 100644
index 0000000000..5742739f39
--- /dev/null
+++ b/usr/src/test/bhyve-tests/tests/vmm/mem_devmem.c
@@ -0,0 +1,160 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2022 Oxide Computer Company
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <strings.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <libgen.h>
+
+#include <sys/vmm.h>
+#include <sys/vmm_dev.h>
+#include <sys/mman.h>
+#include <vmmapi.h>
+
+#include "common.h"
+
+enum test_segs {
+ SEG_LOWMEM = 0,
+ SEG_BOOTROM = 1,
+};
+#define PAGE_CNT 2
+#define PAGE_SZ 4096
+#define SEG_SZ (PAGE_CNT * PAGE_SZ)
+#define WHOLE_SZ (SEG_SZ * 2)
+
+#define TESTVAL_LOWMEM 0x1000ffff
+#define TESTVAL_BOOTROM 0x2000eeee
+
+int
+main(int argc, char *argv[])
+{
+ struct vmctx *ctx;
+ int res, fd;
+ const char *suite_name = basename(argv[0]);
+
+ ctx = create_test_vm(suite_name);
+ if (ctx == NULL) {
+ perror("could open test VM");
+ return (1);
+ }
+ fd = vm_get_device_fd(ctx);
+
+ res = alloc_memseg(ctx, SEG_LOWMEM, SEG_SZ, "");
+ if (res != 0) {
+ perror("could not alloc lowmem seg");
+ goto bail;
+ }
+ res = alloc_memseg(ctx, SEG_BOOTROM, SEG_SZ, "bootrom");
+ if (res != 0) {
+ perror("could not alloc bootrom seg");
+ goto bail;
+ }
+
+ res = vm_mmap_memseg(ctx, 0, SEG_LOWMEM, 0, SEG_SZ, PROT_ALL);
+ if (res != 0) {
+ perror("could not map lowmem into vmspace");
+ goto bail;
+ }
+ res = vm_mmap_memseg(ctx, SEG_SZ, SEG_BOOTROM, 0, SEG_SZ, PROT_READ);
+ if (res != 0) {
+ perror("could not map bootrom into vmspace");
+ goto bail;
+ }
+
+ void *guest_mem;
+ guest_mem = mmap(NULL, WHOLE_SZ, PROT_READ, MAP_SHARED, fd, 0);
+ if (guest_mem == MAP_FAILED) {
+ perror("could not mmap guest-physical memory");
+ goto bail;
+ }
+
+ void *direct_lowmem, *direct_bootrom;
+ off_t seg_obj_off;
+
+ res = vm_get_devmem_offset(ctx, SEG_LOWMEM, &seg_obj_off);
+ if (res != 0) {
+ perror("could not find mapping offset for lowmem seg");
+ goto bail;
+ }
+ direct_lowmem = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, seg_obj_off);
+ if (direct_lowmem == MAP_FAILED) {
+ perror("could not mmap lowmem directly");
+ goto bail;
+ }
+
+ res = vm_get_devmem_offset(ctx, SEG_BOOTROM, &seg_obj_off);
+ if (res != 0) {
+ perror("could not find mapping offset for lowmem seg");
+ goto bail;
+ }
+ direct_bootrom = mmap(NULL, SEG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, seg_obj_off);
+ if (direct_bootrom == MAP_FAILED) {
+ perror("could not mmap bootrom directly");
+ goto bail;
+ }
+
+ uint32_t *datap;
+
+ datap = direct_lowmem;
+ *datap = TESTVAL_LOWMEM;
+ datap = direct_bootrom;
+ *datap = TESTVAL_BOOTROM;
+
+ /* check that data written though direct access is as expected */
+ datap = guest_mem;
+ if (*datap != TESTVAL_LOWMEM) {
+ (void) fprintf(stderr, "unexpected data in lowmem %x != %x\n",
+ *datap, TESTVAL_LOWMEM);
+ goto bail;
+ }
+ datap = (guest_mem + SEG_SZ);
+ if (*datap != TESTVAL_BOOTROM) {
+ (void) fprintf(stderr, "unexpected data in bootrom %x != %x\n",
+ *datap, TESTVAL_BOOTROM);
+ goto bail;
+ }
+
+ /* unmap access mappings */
+ res = munmap(guest_mem, WHOLE_SZ);
+ if (res != 0) {
+ perror("could not munmap vmspace");
+ goto bail;
+ }
+ res = munmap(direct_lowmem, SEG_SZ);
+ if (res != 0) {
+ perror("could not munmap lowmem object");
+ goto bail;
+ }
+ res = munmap(direct_bootrom, SEG_SZ);
+ if (res != 0) {
+ perror("could not munmap bootrom object");
+ goto bail;
+ }
+
+ /* mission accomplished */
+ vm_destroy(ctx);
+ (void) printf("%s\tPASS\n", suite_name);
+ return (0);
+
+bail:
+ vm_destroy(ctx);
+ return (1);
+}
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 4ef2e5f583..24dd851831 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -115,6 +115,33 @@ static int vmm_kstat_alloc(vmm_softc_t *, minor_t, const cred_t *);
static void vmm_kstat_init(vmm_softc_t *);
static void vmm_kstat_fini(vmm_softc_t *);
+/*
+ * The 'devmem' hack:
+ *
+ * On native FreeBSD, bhyve consumers are allowed to create 'devmem' segments
+ * in the vm which appear with their own name related to the vm under /dev.
+ * Since this would be a hassle from an sdev perspective and would require a
+ * new cdev interface (or complicate the existing one), we choose to implement
+ * this in a different manner. Direct access to the underlying vm memory
+ * segments is exposed by placing them in a range of offsets beyond the normal
+ * guest memory space. Userspace can query the appropriate offset to mmap()
+ * for a given segment-id with the VM_DEVMEM_GETOFFSET ioctl.
+ */
+
+static vmm_devmem_entry_t *
+vmmdev_devmem_find(vmm_softc_t *sc, int segid)
+{
+ vmm_devmem_entry_t *ent = NULL;
+ list_t *dl = &sc->vmm_devmem_list;
+
+ for (ent = list_head(dl); ent != NULL; ent = list_next(dl, ent)) {
+ if (ent->vde_segid == segid) {
+ return (ent);
+ }
+ }
+ return (NULL);
+}
+
static int
vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
{
@@ -128,13 +155,8 @@ vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
if (!sysmem) {
vmm_devmem_entry_t *de;
- list_t *dl = &sc->vmm_devmem_list;
- for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
- if (de->vde_segid == mseg->segid) {
- break;
- }
- }
+ de = vmmdev_devmem_find(sc, mseg->segid);
if (de != NULL) {
(void) strlcpy(mseg->name, de->vde_name,
sizeof (mseg->name));
@@ -146,19 +168,6 @@ vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
return (error);
}
-/*
- * The 'devmem' hack:
- *
- * On native FreeBSD, bhyve consumers are allowed to create 'devmem' segments
- * in the vm which appear with their own name related to the vm under /dev.
- * Since this would be a hassle from an sdev perspective and would require a
- * new cdev interface (or complicate the existing one), we choose to implement
- * this in a different manner. When 'devmem' mappings are created, an
- * identifying off_t is communicated back out to userspace. That off_t,
- * residing above the normal guest memory space, can be used to mmap the
- * 'devmem' mapping from the already-open vm device.
- */
-
static int
vmmdev_devmem_create(vmm_softc_t *sc, struct vm_memseg *mseg, const char *name)
{
@@ -239,7 +248,7 @@ vmmdev_alloc_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
}
error = vm_alloc_memseg(sc->vmm_vm, mseg->segid, mseg->len, sysmem);
- if (error == 0 && VM_MEMSEG_NAME(mseg)) {
+ if (error == 0) {
/*
* Rather than create a whole fresh device from which userspace
* can mmap this segment, instead make it available at an
@@ -1442,19 +1451,14 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
}
case VM_DEVMEM_GETOFFSET: {
struct vm_devmem_offset vdo;
- list_t *dl = &sc->vmm_devmem_list;
- vmm_devmem_entry_t *de = NULL;
+ vmm_devmem_entry_t *de;
if (ddi_copyin(datap, &vdo, sizeof (vdo), md) != 0) {
error = EFAULT;
break;
}
- for (de = list_head(dl); de != NULL; de = list_next(dl, de)) {
- if (de->vde_segid == vdo.segid) {
- break;
- }
- }
+ de = vmmdev_devmem_find(sc, vdo.segid);
if (de != NULL) {
vdo.offset = de->vde_off;
if (ddi_copyout(&vdo, datap, sizeof (vdo), md) != 0) {