Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018, Red Hat, Inc.
0004  *
0005  * Tests for Enlightened VMCS, including nested guest state.
0006  */
0007 #define _GNU_SOURCE /* for program_invocation_short_name */
0008 #include <fcntl.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <sys/ioctl.h>
0013 #include <linux/bitmap.h>
0014 
0015 #include "test_util.h"
0016 
0017 #include "kvm_util.h"
0018 
0019 #include "vmx.h"
0020 
0021 static int ud_count;
0022 
0023 static void guest_ud_handler(struct ex_regs *regs)
0024 {
0025     ud_count++;
0026     regs->rip += 3; /* VMLAUNCH */
0027 }
0028 
0029 static void guest_nmi_handler(struct ex_regs *regs)
0030 {
0031 }
0032 
0033 /* Exits to L1 destroy GRPs! */
0034 static inline void rdmsr_fs_base(void)
0035 {
0036     __asm__ __volatile__ ("mov $0xc0000100, %%rcx; rdmsr" : : :
0037                   "rax", "rbx", "rcx", "rdx",
0038                   "rsi", "rdi", "r8", "r9", "r10", "r11", "r12",
0039                   "r13", "r14", "r15");
0040 }
0041 static inline void rdmsr_gs_base(void)
0042 {
0043     __asm__ __volatile__ ("mov $0xc0000101, %%rcx; rdmsr" : : :
0044                   "rax", "rbx", "rcx", "rdx",
0045                   "rsi", "rdi", "r8", "r9", "r10", "r11", "r12",
0046                   "r13", "r14", "r15");
0047 }
0048 
0049 void l2_guest_code(void)
0050 {
0051     GUEST_SYNC(7);
0052 
0053     GUEST_SYNC(8);
0054 
0055     /* Forced exit to L1 upon restore */
0056     GUEST_SYNC(9);
0057 
0058     vmcall();
0059 
0060     /* MSR-Bitmap tests */
0061     rdmsr_fs_base(); /* intercepted */
0062     rdmsr_fs_base(); /* intercepted */
0063     rdmsr_gs_base(); /* not intercepted */
0064     vmcall();
0065     rdmsr_gs_base(); /* intercepted */
0066 
0067     /* Done, exit to L1 and never come back.  */
0068     vmcall();
0069 }
0070 
0071 void guest_code(struct vmx_pages *vmx_pages)
0072 {
0073 #define L2_GUEST_STACK_SIZE 64
0074     unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
0075 
0076     x2apic_enable();
0077 
0078     GUEST_SYNC(1);
0079     GUEST_SYNC(2);
0080 
0081     enable_vp_assist(vmx_pages->vp_assist_gpa, vmx_pages->vp_assist);
0082 
0083     GUEST_ASSERT(vmx_pages->vmcs_gpa);
0084     GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages));
0085     GUEST_SYNC(3);
0086     GUEST_ASSERT(load_vmcs(vmx_pages));
0087     GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
0088 
0089     GUEST_SYNC(4);
0090     GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
0091 
0092     prepare_vmcs(vmx_pages, l2_guest_code,
0093              &l2_guest_stack[L2_GUEST_STACK_SIZE]);
0094 
0095     GUEST_SYNC(5);
0096     GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
0097     current_evmcs->revision_id = -1u;
0098     GUEST_ASSERT(vmlaunch());
0099     current_evmcs->revision_id = EVMCS_VERSION;
0100     GUEST_SYNC(6);
0101 
0102     vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmreadz(PIN_BASED_VM_EXEC_CONTROL) |
0103         PIN_BASED_NMI_EXITING);
0104 
0105     GUEST_ASSERT(!vmlaunch());
0106     GUEST_ASSERT(vmptrstz() == vmx_pages->enlightened_vmcs_gpa);
0107 
0108     /*
0109      * NMI forces L2->L1 exit, resuming L2 and hope that EVMCS is
0110      * up-to-date (RIP points where it should and not at the beginning
0111      * of l2_guest_code(). GUEST_SYNC(9) checkes that.
0112      */
0113     GUEST_ASSERT(!vmresume());
0114 
0115     GUEST_SYNC(10);
0116 
0117     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
0118     current_evmcs->guest_rip += 3; /* vmcall */
0119 
0120     /* Intercept RDMSR 0xc0000100 */
0121     vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmreadz(CPU_BASED_VM_EXEC_CONTROL) |
0122         CPU_BASED_USE_MSR_BITMAPS);
0123     set_bit(MSR_FS_BASE & 0x1fff, vmx_pages->msr + 0x400);
0124     GUEST_ASSERT(!vmresume());
0125     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ);
0126     current_evmcs->guest_rip += 2; /* rdmsr */
0127 
0128     /* Enable enlightened MSR bitmap */
0129     current_evmcs->hv_enlightenments_control.msr_bitmap = 1;
0130     GUEST_ASSERT(!vmresume());
0131     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ);
0132     current_evmcs->guest_rip += 2; /* rdmsr */
0133 
0134     /* Intercept RDMSR 0xc0000101 without telling KVM about it */
0135     set_bit(MSR_GS_BASE & 0x1fff, vmx_pages->msr + 0x400);
0136     /* Make sure HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP is set */
0137     current_evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP;
0138     GUEST_ASSERT(!vmresume());
0139     /* Make sure we don't see EXIT_REASON_MSR_READ here so eMSR bitmap works */
0140     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
0141     current_evmcs->guest_rip += 3; /* vmcall */
0142 
0143     /* Now tell KVM we've changed MSR-Bitmap */
0144     current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP;
0145     GUEST_ASSERT(!vmresume());
0146     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ);
0147     current_evmcs->guest_rip += 2; /* rdmsr */
0148 
0149     GUEST_ASSERT(!vmresume());
0150     GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
0151     GUEST_SYNC(11);
0152 
0153     /* Try enlightened vmptrld with an incorrect GPA */
0154     evmcs_vmptrld(0xdeadbeef, vmx_pages->enlightened_vmcs);
0155     GUEST_ASSERT(vmlaunch());
0156     GUEST_ASSERT(ud_count == 1);
0157     GUEST_DONE();
0158 }
0159 
0160 void inject_nmi(struct kvm_vcpu *vcpu)
0161 {
0162     struct kvm_vcpu_events events;
0163 
0164     vcpu_events_get(vcpu, &events);
0165 
0166     events.nmi.pending = 1;
0167     events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING;
0168 
0169     vcpu_events_set(vcpu, &events);
0170 }
0171 
0172 static struct kvm_vcpu *save_restore_vm(struct kvm_vm *vm,
0173                     struct kvm_vcpu *vcpu)
0174 {
0175     struct kvm_regs regs1, regs2;
0176     struct kvm_x86_state *state;
0177 
0178     state = vcpu_save_state(vcpu);
0179     memset(&regs1, 0, sizeof(regs1));
0180     vcpu_regs_get(vcpu, &regs1);
0181 
0182     kvm_vm_release(vm);
0183 
0184     /* Restore state in a new VM.  */
0185     vcpu = vm_recreate_with_one_vcpu(vm);
0186     vcpu_set_hv_cpuid(vcpu);
0187     vcpu_enable_evmcs(vcpu);
0188     vcpu_load_state(vcpu, state);
0189     kvm_x86_state_cleanup(state);
0190 
0191     memset(&regs2, 0, sizeof(regs2));
0192     vcpu_regs_get(vcpu, &regs2);
0193     TEST_ASSERT(!memcmp(&regs1, &regs2, sizeof(regs2)),
0194             "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx",
0195             (ulong) regs2.rdi, (ulong) regs2.rsi);
0196     return vcpu;
0197 }
0198 
0199 int main(int argc, char *argv[])
0200 {
0201     vm_vaddr_t vmx_pages_gva = 0;
0202 
0203     struct kvm_vcpu *vcpu;
0204     struct kvm_vm *vm;
0205     struct kvm_run *run;
0206     struct ucall uc;
0207     int stage;
0208 
0209     vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0210 
0211     TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
0212     TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
0213     TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS));
0214 
0215     vcpu_set_hv_cpuid(vcpu);
0216     vcpu_enable_evmcs(vcpu);
0217 
0218     vcpu_alloc_vmx(vm, &vmx_pages_gva);
0219     vcpu_args_set(vcpu, 1, vmx_pages_gva);
0220 
0221     vm_init_descriptor_tables(vm);
0222     vcpu_init_descriptor_tables(vcpu);
0223     vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler);
0224     vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler);
0225 
0226     pr_info("Running L1 which uses EVMCS to run L2\n");
0227 
0228     for (stage = 1;; stage++) {
0229         run = vcpu->run;
0230 
0231         vcpu_run(vcpu);
0232         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0233                 "Stage %d: unexpected exit reason: %u (%s),\n",
0234                 stage, run->exit_reason,
0235                 exit_reason_str(run->exit_reason));
0236 
0237         switch (get_ucall(vcpu, &uc)) {
0238         case UCALL_ABORT:
0239             REPORT_GUEST_ASSERT(uc);
0240             /* NOT REACHED */
0241         case UCALL_SYNC:
0242             break;
0243         case UCALL_DONE:
0244             goto done;
0245         default:
0246             TEST_FAIL("Unknown ucall %lu", uc.cmd);
0247         }
0248 
0249         /* UCALL_SYNC is handled here.  */
0250         TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
0251                 uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx",
0252                 stage, (ulong)uc.args[1]);
0253 
0254         vcpu = save_restore_vm(vm, vcpu);
0255 
0256         /* Force immediate L2->L1 exit before resuming */
0257         if (stage == 8) {
0258             pr_info("Injecting NMI into L1 before L2 had a chance to run after restore\n");
0259             inject_nmi(vcpu);
0260         }
0261 
0262         /*
0263          * Do KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE for a freshly
0264          * restored VM (before the first KVM_RUN) to check that
0265          * KVM_STATE_NESTED_EVMCS is not lost.
0266          */
0267         if (stage == 9) {
0268             pr_info("Trying extra KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE cycle\n");
0269             vcpu = save_restore_vm(vm, vcpu);
0270         }
0271     }
0272 
0273 done:
0274     kvm_vm_free(vm);
0275 }