diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2022-09-26 20:59:56 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@oxide.computer> | 2022-10-02 01:02:06 +0000 |
commit | 3f6fd99d844f7d4b62e4e1ddb0c29a4c2f7eca15 (patch) | |
tree | 495821bf09970e63556179d2f4e412c8e3c76d77 | |
parent | 17c4dadf772c2bfb28130f501dc6e1f46f8b1250 (diff) | |
download | illumos-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.c | 15 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-bhyve-tests.p5m | 1 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/runfiles/default.run | 3 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/tests/common/in_guest.c | 28 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/tests/common/payload_common.h | 1 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/tests/inst_emul/Makefile | 6 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/tests/inst_emul/exit_paging.c | 79 | ||||
-rw-r--r-- | usr/src/test/bhyve-tests/tests/inst_emul/payload_exit_paging.s | 30 | ||||
-rw-r--r-- | usr/src/uts/intel/io/vmm/vmm.c | 21 |
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); } |