0001
0002
0003
0004
0005
0006
0007
0008
0009 #define _GNU_SOURCE
0010 #include <fcntl.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include <sys/ioctl.h>
0015 #include <linux/bitmap.h>
0016
0017 #include "test_util.h"
0018
0019 #include "kvm_util.h"
0020 #include "processor.h"
0021 #include "svm_util.h"
0022 #include "hyperv.h"
0023
0024 #define L2_GUEST_STACK_SIZE 256
0025
0026 struct hv_enlightenments {
0027 struct __packed hv_enlightenments_control {
0028 u32 nested_flush_hypercall:1;
0029 u32 msr_bitmap:1;
0030 u32 enlightened_npt_tlb: 1;
0031 u32 reserved:29;
0032 } __packed hv_enlightenments_control;
0033 u32 hv_vp_id;
0034 u64 hv_vm_id;
0035 u64 partition_assist_page;
0036 u64 reserved;
0037 } __packed;
0038
0039
0040
0041
0042 #define VMCB_HV_NESTED_ENLIGHTENMENTS (1U << 31)
0043
0044 void l2_guest_code(void)
0045 {
0046 GUEST_SYNC(3);
0047
0048 vmmcall();
0049
0050
0051 rdmsr(MSR_FS_BASE);
0052 rdmsr(MSR_FS_BASE);
0053 rdmsr(MSR_GS_BASE);
0054 vmmcall();
0055 rdmsr(MSR_GS_BASE);
0056
0057 GUEST_SYNC(5);
0058
0059
0060 vmmcall();
0061 }
0062
0063 static void __attribute__((__flatten__)) guest_code(struct svm_test_data *svm)
0064 {
0065 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
0066 struct vmcb *vmcb = svm->vmcb;
0067 struct hv_enlightenments *hve =
0068 (struct hv_enlightenments *)vmcb->control.reserved_sw;
0069
0070 GUEST_SYNC(1);
0071
0072 wrmsr(HV_X64_MSR_GUEST_OS_ID, (u64)0x8100 << 48);
0073
0074 GUEST_ASSERT(svm->vmcb_gpa);
0075
0076 generic_svm_setup(svm, l2_guest_code,
0077 &l2_guest_stack[L2_GUEST_STACK_SIZE]);
0078
0079 GUEST_SYNC(2);
0080 run_guest(vmcb, svm->vmcb_gpa);
0081 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL);
0082 GUEST_SYNC(4);
0083 vmcb->save.rip += 3;
0084
0085
0086 vmcb->control.intercept |= 1ULL << INTERCEPT_MSR_PROT;
0087 set_bit(2 * (MSR_FS_BASE & 0x1fff), svm->msr + 0x800);
0088 run_guest(vmcb, svm->vmcb_gpa);
0089 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR);
0090 vmcb->save.rip += 2;
0091
0092
0093 hve->hv_enlightenments_control.msr_bitmap = 1;
0094 run_guest(vmcb, svm->vmcb_gpa);
0095 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR);
0096 vmcb->save.rip += 2;
0097
0098
0099 set_bit(2 * (MSR_GS_BASE & 0x1fff), svm->msr + 0x800);
0100
0101 vmcb->control.clean |= VMCB_HV_NESTED_ENLIGHTENMENTS;
0102 run_guest(vmcb, svm->vmcb_gpa);
0103
0104 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL);
0105 vmcb->save.rip += 3;
0106
0107
0108 vmcb->control.clean &= ~VMCB_HV_NESTED_ENLIGHTENMENTS;
0109 run_guest(vmcb, svm->vmcb_gpa);
0110 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_MSR);
0111 vmcb->save.rip += 2;
0112
0113 run_guest(vmcb, svm->vmcb_gpa);
0114 GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL);
0115 GUEST_SYNC(6);
0116
0117 GUEST_DONE();
0118 }
0119
0120 int main(int argc, char *argv[])
0121 {
0122 vm_vaddr_t nested_gva = 0;
0123
0124 struct kvm_vcpu *vcpu;
0125 struct kvm_vm *vm;
0126 struct kvm_run *run;
0127 struct ucall uc;
0128 int stage;
0129
0130 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
0131
0132
0133 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0134 vcpu_set_hv_cpuid(vcpu);
0135 run = vcpu->run;
0136 vcpu_alloc_svm(vm, &nested_gva);
0137 vcpu_args_set(vcpu, 1, nested_gva);
0138
0139 for (stage = 1;; stage++) {
0140 vcpu_run(vcpu);
0141 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
0142 "Stage %d: unexpected exit reason: %u (%s),\n",
0143 stage, run->exit_reason,
0144 exit_reason_str(run->exit_reason));
0145
0146 switch (get_ucall(vcpu, &uc)) {
0147 case UCALL_ABORT:
0148 REPORT_GUEST_ASSERT(uc);
0149
0150 case UCALL_SYNC:
0151 break;
0152 case UCALL_DONE:
0153 goto done;
0154 default:
0155 TEST_FAIL("Unknown ucall %lu", uc.cmd);
0156 }
0157
0158
0159 TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
0160 uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx",
0161 stage, (ulong)uc.args[1]);
0162
0163 }
0164
0165 done:
0166 kvm_vm_free(vm);
0167 }