summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2022-01-05 16:18:44 -0800
committerOlof Johansson <olof@lixom.net>2022-01-05 16:18:50 -0800
commit8922bb6526ac4b20bd8de7f47d6e77808670f6c4 (patch)
tree476cd8a432272c29b8a67e679c0aa65e0a12b28e /tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c
parentfde9ec3c1b3dd361bff62fc89d95d03df51a0648 (diff)
parent36de991e93908f7ad5c2a0eac9c4ecf8b723fa4a (diff)
Merge tag 'socfpga_fix_for_v5.16_part_3' of git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux into arm/fixes
SoCFPGA dts updates for v5.16, part 3 - Change the SoCFPGA compatible to "intel,socfpga-qspi" - Update dt-bindings document to include "intel,socfpga-qspi" * tag 'socfpga_fix_for_v5.16_part_3' of git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux: (361 commits) ARM: dts: socfpga: change qspi to "intel,socfpga-qspi" dt-bindings: spi: cadence-quadspi: document "intel,socfpga-qspi" Linux 5.16-rc7 mm/hwpoison: clear MF_COUNT_INCREASED before retrying get_any_page() mm/damon/dbgfs: protect targets destructions with kdamond_lock mm/page_alloc: fix __alloc_size attribute for alloc_pages_exact_nid mm: delete unsafe BUG from page_cache_add_speculative() mm, hwpoison: fix condition in free hugetlb page path MAINTAINERS: mark more list instances as moderated kernel/crash_core: suppress unknown crashkernel parameter warning mm: mempolicy: fix THP allocations escaping mempolicy restrictions kfence: fix memory leak when cat kfence objects platform/x86: intel_pmc_core: fix memleak on registration failure net: stmmac: dwmac-visconti: Fix value of ETHER_CLK_SEL_FREQ_SEL_2P5M r8152: sync ocp base r8152: fix the force speed doesn't work for RTL8156 net: bridge: fix ioctl old_deviceless bridge argument net: stmmac: ptp: fix potentially overflowing expression net: dsa: tag_ocelot: use traffic class to map priority on injected header veth: ensure skb entering GRO are not cloned. ... Link: https://lore.kernel.org/r/20211227103644.566694-1-dinguyen@kernel.org Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c')
-rw-r--r--tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c
new file mode 100644
index 000000000000..489fbed4ca6f
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "vmx.h"
+
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "kselftest.h"
+
+#define VCPU_ID 0
+#define ARBITRARY_IO_PORT 0x2000
+
+static struct kvm_vm *vm;
+
+static void l2_guest_code(void)
+{
+ /*
+ * Generate an exit to L0 userspace, i.e. main(), via I/O to an
+ * arbitrary port.
+ */
+ asm volatile("inb %%dx, %%al"
+ : : [port] "d" (ARBITRARY_IO_PORT) : "rax");
+}
+
+static void l1_guest_code(struct vmx_pages *vmx_pages)
+{
+#define L2_GUEST_STACK_SIZE 64
+ unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
+
+ GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
+ GUEST_ASSERT(load_vmcs(vmx_pages));
+
+ /* Prepare the VMCS for L2 execution. */
+ prepare_vmcs(vmx_pages, l2_guest_code,
+ &l2_guest_stack[L2_GUEST_STACK_SIZE]);
+
+ /*
+ * L2 must be run without unrestricted guest, verify that the selftests
+ * library hasn't enabled it. Because KVM selftests jump directly to
+ * 64-bit mode, unrestricted guest support isn't required.
+ */
+ GUEST_ASSERT(!(vmreadz(CPU_BASED_VM_EXEC_CONTROL) & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) ||
+ !(vmreadz(SECONDARY_VM_EXEC_CONTROL) & SECONDARY_EXEC_UNRESTRICTED_GUEST));
+
+ GUEST_ASSERT(!vmlaunch());
+
+ /* L2 should triple fault after main() stuffs invalid guest state. */
+ GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT);
+ GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+ vm_vaddr_t vmx_pages_gva;
+ struct kvm_sregs sregs;
+ struct kvm_run *run;
+ struct ucall uc;
+
+ nested_vmx_check_supported();
+
+ vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code);
+
+ /* Allocate VMX pages and shared descriptors (vmx_pages). */
+ vcpu_alloc_vmx(vm, &vmx_pages_gva);
+ vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva);
+
+ vcpu_run(vm, VCPU_ID);
+
+ run = vcpu_state(vm, VCPU_ID);
+
+ /*
+ * The first exit to L0 userspace should be an I/O access from L2.
+ * Running L1 should launch L2 without triggering an exit to userspace.
+ */
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+ "Expected KVM_EXIT_IO, got: %u (%s)\n",
+ run->exit_reason, exit_reason_str(run->exit_reason));
+
+ TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT,
+ "Expected IN from port %d from L2, got port %d",
+ ARBITRARY_IO_PORT, run->io.port);
+
+ /*
+ * Stuff invalid guest state for L2 by making TR unusuable. The next
+ * KVM_RUN should induce a TRIPLE_FAULT in L2 as KVM doesn't support
+ * emulating invalid guest state for L2.
+ */
+ memset(&sregs, 0, sizeof(sregs));
+ vcpu_sregs_get(vm, VCPU_ID, &sregs);
+ sregs.tr.unusable = 1;
+ vcpu_sregs_set(vm, VCPU_ID, &sregs);
+
+ vcpu_run(vm, VCPU_ID);
+
+ switch (get_ucall(vm, VCPU_ID, &uc)) {
+ case UCALL_DONE:
+ break;
+ case UCALL_ABORT:
+ TEST_FAIL("%s", (const char *)uc.args[0]);
+ default:
+ TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
+ }
+}