1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2018, Google LLC.
7 * This is a regression test for the bug fixed by the following commit:
8 * d3802286fa0f ("kvm: x86: Disallow illegal IA32_APIC_BASE MSR values")
10 * That bug allowed a user-mode program that called the KVM_SET_SREGS
11 * ioctl to put a VCPU's local APIC into an invalid state.
13 #define _GNU_SOURCE /* for program_invocation_short_name */
18 #include <sys/ioctl.h>
20 #include "test_util.h"
23 #include "processor.h"
27 static void test_cr4_feature_bit(struct kvm_vm
*vm
, struct kvm_sregs
*orig
,
30 struct kvm_sregs sregs
;
33 /* Skip the sub-test, the feature is supported. */
34 if (orig
->cr4
& feature_bit
)
37 memcpy(&sregs
, orig
, sizeof(sregs
));
38 sregs
.cr4
|= feature_bit
;
40 rc
= _vcpu_sregs_set(vm
, VCPU_ID
, &sregs
);
41 TEST_ASSERT(rc
, "KVM allowed unsupported CR4 bit (0x%lx)", feature_bit
);
43 /* Sanity check that KVM didn't change anything. */
44 vcpu_sregs_get(vm
, VCPU_ID
, &sregs
);
45 TEST_ASSERT(!memcmp(&sregs
, orig
, sizeof(sregs
)), "KVM modified sregs");
48 static uint64_t calc_cr4_feature_bits(struct kvm_vm
*vm
)
50 struct kvm_cpuid_entry2
*cpuid_1
, *cpuid_7
;
53 cpuid_1
= kvm_get_supported_cpuid_entry(1);
54 cpuid_7
= kvm_get_supported_cpuid_entry(7);
56 cr4
= X86_CR4_VME
| X86_CR4_PVI
| X86_CR4_TSD
| X86_CR4_DE
|
57 X86_CR4_PSE
| X86_CR4_PAE
| X86_CR4_MCE
| X86_CR4_PGE
|
58 X86_CR4_PCE
| X86_CR4_OSFXSR
| X86_CR4_OSXMMEXCPT
;
59 if (cpuid_7
->ecx
& CPUID_UMIP
)
61 if (cpuid_7
->ecx
& CPUID_LA57
)
63 if (cpuid_1
->ecx
& CPUID_VMX
)
65 if (cpuid_1
->ecx
& CPUID_SMX
)
67 if (cpuid_7
->ebx
& CPUID_FSGSBASE
)
68 cr4
|= X86_CR4_FSGSBASE
;
69 if (cpuid_1
->ecx
& CPUID_PCID
)
71 if (cpuid_1
->ecx
& CPUID_XSAVE
)
72 cr4
|= X86_CR4_OSXSAVE
;
73 if (cpuid_7
->ebx
& CPUID_SMEP
)
75 if (cpuid_7
->ebx
& CPUID_SMAP
)
77 if (cpuid_7
->ecx
& CPUID_PKU
)
83 int main(int argc
, char *argv
[])
85 struct kvm_sregs sregs
;
90 /* Tell stdout not to buffer its content */
94 * Create a dummy VM, specifically to avoid doing KVM_SET_CPUID2, and
95 * use it to verify all supported CR4 bits can be set prior to defining
96 * the vCPU model, i.e. without doing KVM_SET_CPUID2.
98 vm
= vm_create(VM_MODE_DEFAULT
, DEFAULT_GUEST_PHY_PAGES
, O_RDWR
);
99 vm_vcpu_add(vm
, VCPU_ID
);
101 vcpu_sregs_get(vm
, VCPU_ID
, &sregs
);
103 sregs
.cr4
|= calc_cr4_feature_bits(vm
);
106 rc
= _vcpu_sregs_set(vm
, VCPU_ID
, &sregs
);
107 TEST_ASSERT(!rc
, "Failed to set supported CR4 bits (0x%lx)", cr4
);
109 vcpu_sregs_get(vm
, VCPU_ID
, &sregs
);
110 TEST_ASSERT(sregs
.cr4
== cr4
, "sregs.CR4 (0x%llx) != CR4 (0x%lx)",
113 /* Verify all unsupported features are rejected by KVM. */
114 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_UMIP
);
115 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_LA57
);
116 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_VMXE
);
117 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_SMXE
);
118 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_FSGSBASE
);
119 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_PCIDE
);
120 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_OSXSAVE
);
121 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_SMEP
);
122 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_SMAP
);
123 test_cr4_feature_bit(vm
, &sregs
, X86_CR4_PKE
);
126 /* Create a "real" VM and verify APIC_BASE can be set. */
127 vm
= vm_create_default(VCPU_ID
, 0, NULL
);
129 vcpu_sregs_get(vm
, VCPU_ID
, &sregs
);
130 sregs
.apic_base
= 1 << 10;
131 rc
= _vcpu_sregs_set(vm
, VCPU_ID
, &sregs
);
132 TEST_ASSERT(rc
, "Set IA32_APIC_BASE to %llx (invalid)",
134 sregs
.apic_base
= 1 << 11;
135 rc
= _vcpu_sregs_set(vm
, VCPU_ID
, &sregs
);
136 TEST_ASSERT(!rc
, "Couldn't set IA32_APIC_BASE to %llx (valid)",