summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2022-09-26 20:59:56 +0000
committerPatrick Mooney <pmooney@oxide.computer>2022-10-02 01:02:06 +0000
commit3f6fd99d844f7d4b62e4e1ddb0c29a4c2f7eca15 (patch)
tree495821bf09970e63556179d2f4e412c8e3c76d77
parent17c4dadf772c2bfb28130f501dc6e1f46f8b1250 (diff)
downloadillumos-joyent-3f6fd99d844f7d4b62e4e1ddb0c29a4c2f7eca15.tar.gz
14952 bhyve should expose PAGING exits to userspace
Reviewed by: Andy Fiddaman <illumos@fiddaman.net> Approved by: Gordon Ross <gordon.w.ross@gmail.com>
-rw-r--r--usr/src/cmd/bhyve/bhyverun.c15
-rw-r--r--usr/src/pkg/manifests/system-bhyve-tests.p5m1
-rw-r--r--usr/src/test/bhyve-tests/runfiles/default.run3
-rw-r--r--usr/src/test/bhyve-tests/tests/common/in_guest.c28
-rw-r--r--usr/src/test/bhyve-tests/tests/common/payload_common.h1
-rw-r--r--usr/src/test/bhyve-tests/tests/inst_emul/Makefile6
-rw-r--r--usr/src/test/bhyve-tests/tests/inst_emul/exit_paging.c79
-rw-r--r--usr/src/test/bhyve-tests/tests/inst_emul/payload_exit_paging.s30
-rw-r--r--usr/src/uts/intel/io/vmm/vmm.c21
9 files changed, 170 insertions, 14 deletions
diff --git a/usr/src/cmd/bhyve/bhyverun.c b/usr/src/cmd/bhyve/bhyverun.c
index 63dd6a129a..3ad546ddb8 100644
--- a/usr/src/cmd/bhyve/bhyverun.c
+++ b/usr/src/cmd/bhyve/bhyverun.c
@@ -39,7 +39,7 @@
*
* Copyright 2015 Pluribus Networks Inc.
* Copyright 2018 Joyent, Inc.
- * Copyright 2021 Oxide Computer Company
+ * Copyright 2022 Oxide Computer Company
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -836,6 +836,18 @@ vmexit_run_state(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
fprintf(stderr, "unexpected run-state VM exit");
return (VMEXIT_ABORT);
}
+
+static int
+vmexit_paging(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
+{
+ fprintf(stderr, "vm exit[%d]\n", *pvcpu);
+ fprintf(stderr, "\treason\t\tPAGING\n");
+ fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip);
+ fprintf(stderr, "\tgpa\t\t0x%016lx\n", vmexit->u.paging.gpa);
+ fprintf(stderr, "\tfault_type\t\t%d\n", vmexit->u.paging.fault_type);
+
+ return (VMEXIT_ABORT);
+}
#endif /* __FreeBSD__ */
#ifdef __FreeBSD__
@@ -1109,6 +1121,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
#else
[VM_EXITCODE_RUN_STATE] = vmexit_run_state,
+ [VM_EXITCODE_PAGING] = vmexit_paging,
#endif
[VM_EXITCODE_SUSPENDED] = vmexit_suspend,
[VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch,
diff --git a/usr/src/pkg/manifests/system-bhyve-tests.p5m b/usr/src/pkg/manifests/system-bhyve-tests.p5m
index a5ba4e375e..1f20e5cfbd 100644
--- a/usr/src/pkg/manifests/system-bhyve-tests.p5m
+++ b/usr/src/pkg/manifests/system-bhyve-tests.p5m
@@ -32,6 +32,7 @@ file path=opt/bhyve-tests/runfiles/default.run mode=0444
dir path=opt/bhyve-tests/tests
dir path=opt/bhyve-tests/tests/inst_emul
file path=opt/bhyve-tests/tests/inst_emul/cpuid mode=0555
+file path=opt/bhyve-tests/tests/inst_emul/exit_paging mode=0555
file path=opt/bhyve-tests/tests/inst_emul/rdmsr mode=0555
file path=opt/bhyve-tests/tests/inst_emul/triple_fault mode=0555
file path=opt/bhyve-tests/tests/inst_emul/wrmsr mode=0555
diff --git a/usr/src/test/bhyve-tests/runfiles/default.run b/usr/src/test/bhyve-tests/runfiles/default.run
index 9402a3051b..89d296f8b2 100644
--- a/usr/src/test/bhyve-tests/runfiles/default.run
+++ b/usr/src/test/bhyve-tests/runfiles/default.run
@@ -52,7 +52,8 @@ tests = [
'cpuid',
'rdmsr',
'wrmsr',
- 'triple_fault'
+ 'triple_fault',
+ 'exit_paging'
]
[/opt/bhyve-tests/tests/viona]
diff --git a/usr/src/test/bhyve-tests/tests/common/in_guest.c b/usr/src/test/bhyve-tests/tests/common/in_guest.c
index dbd6bdf22a..7d27cf194d 100644
--- a/usr/src/test/bhyve-tests/tests/common/in_guest.c
+++ b/usr/src/test/bhyve-tests/tests/common/in_guest.c
@@ -27,6 +27,7 @@
#include <sys/sysmacros.h>
#include <sys/varargs.h>
#include <sys/debug.h>
+#include <sys/mman.h>
#include <sys/vmm.h>
#include <sys/vmm_dev.h>
@@ -61,6 +62,28 @@
static struct vmctx *test_vmctx = NULL;
static const char *test_name = NULL;
+static int
+setup_rom(struct vmctx *ctx)
+{
+ const size_t seg_sz = 0x1000;
+ const uintptr_t seg_addr = MEM_LOC_ROM;
+ const int fd = vm_get_device_fd(ctx);
+ int err;
+
+ struct vm_memseg memseg = {
+ .segid = VM_BOOTROM,
+ .len = 0x1000,
+ };
+ (void) strlcpy(memseg.name, "testrom", sizeof (memseg.name));
+ err = ioctl(fd, VM_ALLOC_MEMSEG, &memseg);
+ if (err != 0) {
+ return (err);
+ }
+ err = vm_mmap_memseg(ctx, seg_addr, VM_BOOTROM, 0, seg_sz,
+ PROT_READ | PROT_EXEC);
+ return (err);
+}
+
static void
populate_identity_table(struct vmctx *ctx)
{
@@ -313,6 +336,11 @@ test_initialize(const char *tname)
test_fail_errno(err, "Could not set up VM memory");
}
+ err = setup_rom(ctx);
+ if (err != 0) {
+ test_fail_errno(err, "Could not set up VM ROM segment");
+ }
+
populate_identity_table(ctx);
populate_desc_tables(ctx);
diff --git a/usr/src/test/bhyve-tests/tests/common/payload_common.h b/usr/src/test/bhyve-tests/tests/common/payload_common.h
index 4141cec219..826927f884 100644
--- a/usr/src/test/bhyve-tests/tests/common/payload_common.h
+++ b/usr/src/test/bhyve-tests/tests/common/payload_common.h
@@ -27,6 +27,7 @@
#define MEM_LOC_IDT 0x207000
#define MEM_LOC_STACK 0x400000
#define MEM_LOC_PAYLOAD 0x800000
+#define MEM_LOC_ROM 0xffff000
/* IO port set aside for emitting test result */
#define IOP_TEST_RESULT 0xef00U
diff --git a/usr/src/test/bhyve-tests/tests/inst_emul/Makefile b/usr/src/test/bhyve-tests/tests/inst_emul/Makefile
index 7a7844d65c..023a416ae9 100644
--- a/usr/src/test/bhyve-tests/tests/inst_emul/Makefile
+++ b/usr/src/test/bhyve-tests/tests/inst_emul/Makefile
@@ -17,9 +17,13 @@ include $(SRC)/test/Makefile.com
PROG = rdmsr \
wrmsr \
- triple_fault \
cpuid
+# These should probably go in the `vmm` tests, but since they depend on
+# in-guest payloads, it is easier to build them here.
+PROG += triple_fault \
+ exit_paging
+
# C-based payloads need additional utils object
CPAYLOADS = cpuid
diff --git a/usr/src/test/bhyve-tests/tests/inst_emul/exit_paging.c b/usr/src/test/bhyve-tests/tests/inst_emul/exit_paging.c
new file mode 100644
index 0000000000..8b0ce84e41
--- /dev/null
+++ b/usr/src/test/bhyve-tests/tests/inst_emul/exit_paging.c
@@ -0,0 +1,79 @@
+/*
+ * 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 <stdlib.h>
+#include <strings.h>
+#include <libgen.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/debug.h>
+#include <sys/mman.h>
+#include <sys/vmm.h>
+#include <sys/vmm_dev.h>
+#include <vmmapi.h>
+
+#include "in_guest.h"
+
+int
+main(int argc, char *argv[])
+{
+ const char *test_suite_name = basename(argv[0]);
+ struct vmctx *ctx = NULL;
+ int err;
+
+ ctx = test_initialize(test_suite_name);
+
+ err = test_setup_vcpu(ctx, 0, MEM_LOC_PAYLOAD, MEM_LOC_STACK);
+ if (err != 0) {
+ test_fail_errno(err, "Could not initialize vcpu0");
+ }
+
+ struct vm_entry ventry = { 0 };
+ struct vm_exit vexit = { 0 };
+
+ const uintptr_t expected_gpa = MEM_LOC_ROM;
+ const int expected_ftype = PROT_WRITE;
+
+ do {
+ const enum vm_exit_kind kind =
+ test_run_vcpu(ctx, 0, &ventry, &vexit);
+ switch (kind) {
+ case VEK_REENTR:
+ break;
+ case VEK_UNHANDLED:
+ if (vexit.exitcode != VM_EXITCODE_PAGING) {
+ test_fail_vmexit(&vexit);
+ }
+ if (vexit.u.paging.gpa != expected_gpa) {
+ test_fail_msg("gpa %08x != %08x\n",
+ vexit.u.paging.gpa, expected_gpa);
+ }
+ if (vexit.u.paging.fault_type != expected_ftype) {
+ test_fail_msg("fault_type %x != %x\n",
+ vexit.u.paging.fault_type, expected_ftype);
+ }
+ test_pass();
+ break;
+
+ default:
+ test_fail_vmexit(&vexit);
+ break;
+ }
+ } while (true);
+}
diff --git a/usr/src/test/bhyve-tests/tests/inst_emul/payload_exit_paging.s b/usr/src/test/bhyve-tests/tests/inst_emul/payload_exit_paging.s
new file mode 100644
index 0000000000..836f6b62cd
--- /dev/null
+++ b/usr/src/test/bhyve-tests/tests/inst_emul/payload_exit_paging.s
@@ -0,0 +1,30 @@
+/*
+ * 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 <sys/asm_linkage.h>
+#include "payload_common.h"
+
+
+ENTRY(start)
+ /* Attempt to write to ROM, which should result in paging exit */
+ xorl %eax, %eax
+ movq %rax, MEM_LOC_ROM
+
+ /* This should not be reached */
+ movw $IOP_TEST_RESULT, %dx
+ movb $TEST_RESULT_FAIL, %al
+ outb (%dx)
+ hlt
+SET_SIZE(start)
diff --git a/usr/src/uts/intel/io/vmm/vmm.c b/usr/src/uts/intel/io/vmm/vmm.c
index e28c235b4c..6f85f13be6 100644
--- a/usr/src/uts/intel/io/vmm/vmm.c
+++ b/usr/src/uts/intel/io/vmm/vmm.c
@@ -1516,20 +1516,19 @@ vm_handle_paging(struct vm *vm, int vcpuid)
struct vcpu *vcpu = &vm->vcpu[vcpuid];
vm_client_t *vmc = vcpu->vmclient;
struct vm_exit *vme = &vcpu->exitinfo;
- int rv, ftype;
+ const int ftype = vme->u.paging.fault_type;
- KASSERT(vme->inst_length == 0, ("%s: invalid inst_length %d",
- __func__, vme->inst_length));
+ ASSERT0(vme->inst_length);
+ ASSERT(ftype == PROT_READ || ftype == PROT_WRITE || ftype == PROT_EXEC);
- ftype = vme->u.paging.fault_type;
- KASSERT(ftype == PROT_READ ||
- ftype == PROT_WRITE || ftype == PROT_EXEC,
- ("vm_handle_paging: invalid fault_type %d", ftype));
-
- rv = vmc_fault(vmc, vme->u.paging.gpa, ftype);
+ if (vmc_fault(vmc, vme->u.paging.gpa, ftype) != 0) {
+ /*
+ * If the fault cannot be serviced, kick it out to userspace for
+ * handling (or more likely, halting the instance).
+ */
+ return (-1);
+ }
- if (rv != 0)
- return (EFAULT);
return (0);
}