17a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2cc68765dSAndrew Jones /* 3cc68765dSAndrew Jones * KVM_SET_SREGS tests 4cc68765dSAndrew Jones * 5cc68765dSAndrew Jones * Copyright (C) 2018, Google LLC. 6cc68765dSAndrew Jones * 7cc68765dSAndrew Jones * This is a regression test for the bug fixed by the following commit: 8cc68765dSAndrew Jones * d3802286fa0f ("kvm: x86: Disallow illegal IA32_APIC_BASE MSR values") 9cc68765dSAndrew Jones * 10cc68765dSAndrew Jones * That bug allowed a user-mode program that called the KVM_SET_SREGS 11cc68765dSAndrew Jones * ioctl to put a VCPU's local APIC into an invalid state. 12cc68765dSAndrew Jones */ 13cc68765dSAndrew Jones #define _GNU_SOURCE /* for program_invocation_short_name */ 14cc68765dSAndrew Jones #include <fcntl.h> 15cc68765dSAndrew Jones #include <stdio.h> 16cc68765dSAndrew Jones #include <stdlib.h> 17cc68765dSAndrew Jones #include <string.h> 18cc68765dSAndrew Jones #include <sys/ioctl.h> 19cc68765dSAndrew Jones 20cc68765dSAndrew Jones #include "test_util.h" 21cc68765dSAndrew Jones 22cc68765dSAndrew Jones #include "kvm_util.h" 23cc68765dSAndrew Jones #include "processor.h" 24cc68765dSAndrew Jones 25cc68765dSAndrew Jones #define VCPU_ID 5 26cc68765dSAndrew Jones 27*7a873e45SSean Christopherson static void test_cr4_feature_bit(struct kvm_vm *vm, struct kvm_sregs *orig, 28*7a873e45SSean Christopherson uint64_t feature_bit) 29*7a873e45SSean Christopherson { 30*7a873e45SSean Christopherson struct kvm_sregs sregs; 31*7a873e45SSean Christopherson int rc; 32*7a873e45SSean Christopherson 33*7a873e45SSean Christopherson /* Skip the sub-test, the feature is supported. */ 34*7a873e45SSean Christopherson if (orig->cr4 & feature_bit) 35*7a873e45SSean Christopherson return; 36*7a873e45SSean Christopherson 37*7a873e45SSean Christopherson memcpy(&sregs, orig, sizeof(sregs)); 38*7a873e45SSean Christopherson sregs.cr4 |= feature_bit; 39*7a873e45SSean Christopherson 40*7a873e45SSean Christopherson rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); 41*7a873e45SSean Christopherson TEST_ASSERT(rc, "KVM allowed unsupported CR4 bit (0x%lx)", feature_bit); 42*7a873e45SSean Christopherson 43*7a873e45SSean Christopherson /* Sanity check that KVM didn't change anything. */ 44*7a873e45SSean Christopherson vcpu_sregs_get(vm, VCPU_ID, &sregs); 45*7a873e45SSean Christopherson TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); 46*7a873e45SSean Christopherson } 47*7a873e45SSean Christopherson 48*7a873e45SSean Christopherson static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm) 49*7a873e45SSean Christopherson { 50*7a873e45SSean Christopherson struct kvm_cpuid_entry2 *cpuid_1, *cpuid_7; 51*7a873e45SSean Christopherson uint64_t cr4; 52*7a873e45SSean Christopherson 53*7a873e45SSean Christopherson cpuid_1 = kvm_get_supported_cpuid_entry(1); 54*7a873e45SSean Christopherson cpuid_7 = kvm_get_supported_cpuid_entry(7); 55*7a873e45SSean Christopherson 56*7a873e45SSean Christopherson cr4 = X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | 57*7a873e45SSean Christopherson X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE | X86_CR4_PGE | 58*7a873e45SSean Christopherson X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT; 59*7a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_UMIP) 60*7a873e45SSean Christopherson cr4 |= X86_CR4_UMIP; 61*7a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_LA57) 62*7a873e45SSean Christopherson cr4 |= X86_CR4_LA57; 63*7a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_VMX) 64*7a873e45SSean Christopherson cr4 |= X86_CR4_VMXE; 65*7a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_SMX) 66*7a873e45SSean Christopherson cr4 |= X86_CR4_SMXE; 67*7a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_FSGSBASE) 68*7a873e45SSean Christopherson cr4 |= X86_CR4_FSGSBASE; 69*7a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_PCID) 70*7a873e45SSean Christopherson cr4 |= X86_CR4_PCIDE; 71*7a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_XSAVE) 72*7a873e45SSean Christopherson cr4 |= X86_CR4_OSXSAVE; 73*7a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_SMEP) 74*7a873e45SSean Christopherson cr4 |= X86_CR4_SMEP; 75*7a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_SMAP) 76*7a873e45SSean Christopherson cr4 |= X86_CR4_SMAP; 77*7a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_PKU) 78*7a873e45SSean Christopherson cr4 |= X86_CR4_PKE; 79*7a873e45SSean Christopherson 80*7a873e45SSean Christopherson return cr4; 81*7a873e45SSean Christopherson } 82*7a873e45SSean Christopherson 83cc68765dSAndrew Jones int main(int argc, char *argv[]) 84cc68765dSAndrew Jones { 85cc68765dSAndrew Jones struct kvm_sregs sregs; 86cc68765dSAndrew Jones struct kvm_vm *vm; 87*7a873e45SSean Christopherson uint64_t cr4; 88cc68765dSAndrew Jones int rc; 89cc68765dSAndrew Jones 90cc68765dSAndrew Jones /* Tell stdout not to buffer its content */ 91cc68765dSAndrew Jones setbuf(stdout, NULL); 92cc68765dSAndrew Jones 93*7a873e45SSean Christopherson /* 94*7a873e45SSean Christopherson * Create a dummy VM, specifically to avoid doing KVM_SET_CPUID2, and 95*7a873e45SSean Christopherson * use it to verify all supported CR4 bits can be set prior to defining 96*7a873e45SSean Christopherson * the vCPU model, i.e. without doing KVM_SET_CPUID2. 97*7a873e45SSean Christopherson */ 98*7a873e45SSean Christopherson vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); 99*7a873e45SSean Christopherson vm_vcpu_add(vm, VCPU_ID); 100*7a873e45SSean Christopherson 101*7a873e45SSean Christopherson vcpu_sregs_get(vm, VCPU_ID, &sregs); 102*7a873e45SSean Christopherson 103*7a873e45SSean Christopherson sregs.cr4 |= calc_cr4_feature_bits(vm); 104*7a873e45SSean Christopherson cr4 = sregs.cr4; 105*7a873e45SSean Christopherson 106*7a873e45SSean Christopherson rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); 107*7a873e45SSean Christopherson TEST_ASSERT(!rc, "Failed to set supported CR4 bits (0x%lx)", cr4); 108*7a873e45SSean Christopherson 109*7a873e45SSean Christopherson vcpu_sregs_get(vm, VCPU_ID, &sregs); 110*7a873e45SSean Christopherson TEST_ASSERT(sregs.cr4 == cr4, "sregs.CR4 (0x%llx) != CR4 (0x%lx)", 111*7a873e45SSean Christopherson sregs.cr4, cr4); 112*7a873e45SSean Christopherson 113*7a873e45SSean Christopherson /* Verify all unsupported features are rejected by KVM. */ 114*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_UMIP); 115*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_LA57); 116*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_VMXE); 117*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_SMXE); 118*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_FSGSBASE); 119*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_PCIDE); 120*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_OSXSAVE); 121*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_SMEP); 122*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_SMAP); 123*7a873e45SSean Christopherson test_cr4_feature_bit(vm, &sregs, X86_CR4_PKE); 124*7a873e45SSean Christopherson kvm_vm_free(vm); 125*7a873e45SSean Christopherson 126*7a873e45SSean Christopherson /* Create a "real" VM and verify APIC_BASE can be set. */ 127cc68765dSAndrew Jones vm = vm_create_default(VCPU_ID, 0, NULL); 128cc68765dSAndrew Jones 129cc68765dSAndrew Jones vcpu_sregs_get(vm, VCPU_ID, &sregs); 130cc68765dSAndrew Jones sregs.apic_base = 1 << 10; 131cc68765dSAndrew Jones rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); 132cc68765dSAndrew Jones TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", 133cc68765dSAndrew Jones sregs.apic_base); 134cc68765dSAndrew Jones sregs.apic_base = 1 << 11; 135cc68765dSAndrew Jones rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); 136cc68765dSAndrew Jones TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", 137cc68765dSAndrew Jones sregs.apic_base); 138cc68765dSAndrew Jones 139cc68765dSAndrew Jones kvm_vm_free(vm); 140cc68765dSAndrew Jones 141cc68765dSAndrew Jones return 0; 142cc68765dSAndrew Jones } 143