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 25d31e1500SSean Christopherson static void test_cr4_feature_bit(struct kvm_vcpu *vcpu, struct kvm_sregs *orig, 267a873e45SSean Christopherson uint64_t feature_bit) 277a873e45SSean Christopherson { 287a873e45SSean Christopherson struct kvm_sregs sregs; 297a873e45SSean Christopherson int rc; 307a873e45SSean Christopherson 317a873e45SSean Christopherson /* Skip the sub-test, the feature is supported. */ 327a873e45SSean Christopherson if (orig->cr4 & feature_bit) 337a873e45SSean Christopherson return; 347a873e45SSean Christopherson 357a873e45SSean Christopherson memcpy(&sregs, orig, sizeof(sregs)); 367a873e45SSean Christopherson sregs.cr4 |= feature_bit; 377a873e45SSean Christopherson 38d31e1500SSean Christopherson rc = _vcpu_sregs_set(vcpu->vm, vcpu->id, &sregs); 397a873e45SSean Christopherson TEST_ASSERT(rc, "KVM allowed unsupported CR4 bit (0x%lx)", feature_bit); 407a873e45SSean Christopherson 417a873e45SSean Christopherson /* Sanity check that KVM didn't change anything. */ 42d31e1500SSean Christopherson vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); 437a873e45SSean Christopherson TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); 447a873e45SSean Christopherson } 457a873e45SSean Christopherson 467a873e45SSean Christopherson static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm) 477a873e45SSean Christopherson { 487a873e45SSean Christopherson struct kvm_cpuid_entry2 *cpuid_1, *cpuid_7; 497a873e45SSean Christopherson uint64_t cr4; 507a873e45SSean Christopherson 517a873e45SSean Christopherson cpuid_1 = kvm_get_supported_cpuid_entry(1); 527a873e45SSean Christopherson cpuid_7 = kvm_get_supported_cpuid_entry(7); 537a873e45SSean Christopherson 547a873e45SSean Christopherson cr4 = X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | 557a873e45SSean Christopherson X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE | X86_CR4_PGE | 567a873e45SSean Christopherson X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT; 577a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_UMIP) 587a873e45SSean Christopherson cr4 |= X86_CR4_UMIP; 597a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_LA57) 607a873e45SSean Christopherson cr4 |= X86_CR4_LA57; 617a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_VMX) 627a873e45SSean Christopherson cr4 |= X86_CR4_VMXE; 637a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_SMX) 647a873e45SSean Christopherson cr4 |= X86_CR4_SMXE; 657a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_FSGSBASE) 667a873e45SSean Christopherson cr4 |= X86_CR4_FSGSBASE; 677a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_PCID) 687a873e45SSean Christopherson cr4 |= X86_CR4_PCIDE; 697a873e45SSean Christopherson if (cpuid_1->ecx & CPUID_XSAVE) 707a873e45SSean Christopherson cr4 |= X86_CR4_OSXSAVE; 717a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_SMEP) 727a873e45SSean Christopherson cr4 |= X86_CR4_SMEP; 737a873e45SSean Christopherson if (cpuid_7->ebx & CPUID_SMAP) 747a873e45SSean Christopherson cr4 |= X86_CR4_SMAP; 757a873e45SSean Christopherson if (cpuid_7->ecx & CPUID_PKU) 767a873e45SSean Christopherson cr4 |= X86_CR4_PKE; 777a873e45SSean Christopherson 787a873e45SSean Christopherson return cr4; 797a873e45SSean Christopherson } 807a873e45SSean Christopherson 81cc68765dSAndrew Jones int main(int argc, char *argv[]) 82cc68765dSAndrew Jones { 83cc68765dSAndrew Jones struct kvm_sregs sregs; 84d31e1500SSean Christopherson struct kvm_vcpu *vcpu; 85cc68765dSAndrew Jones struct kvm_vm *vm; 867a873e45SSean Christopherson uint64_t cr4; 87cc68765dSAndrew Jones int rc; 88cc68765dSAndrew Jones 89cc68765dSAndrew Jones /* Tell stdout not to buffer its content */ 90cc68765dSAndrew Jones setbuf(stdout, NULL); 91cc68765dSAndrew Jones 927a873e45SSean Christopherson /* 937a873e45SSean Christopherson * Create a dummy VM, specifically to avoid doing KVM_SET_CPUID2, and 947a873e45SSean Christopherson * use it to verify all supported CR4 bits can be set prior to defining 957a873e45SSean Christopherson * the vCPU model, i.e. without doing KVM_SET_CPUID2. 967a873e45SSean Christopherson */ 9795fb0460SSean Christopherson vm = vm_create_barebones(); 98*f742d94fSSean Christopherson vcpu = __vm_vcpu_add(vm, 0); 997a873e45SSean Christopherson 100d31e1500SSean Christopherson vcpu_sregs_get(vm, vcpu->id, &sregs); 1017a873e45SSean Christopherson 1027a873e45SSean Christopherson sregs.cr4 |= calc_cr4_feature_bits(vm); 1037a873e45SSean Christopherson cr4 = sregs.cr4; 1047a873e45SSean Christopherson 105d31e1500SSean Christopherson rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); 1067a873e45SSean Christopherson TEST_ASSERT(!rc, "Failed to set supported CR4 bits (0x%lx)", cr4); 1077a873e45SSean Christopherson 108d31e1500SSean Christopherson vcpu_sregs_get(vm, vcpu->id, &sregs); 1097a873e45SSean Christopherson TEST_ASSERT(sregs.cr4 == cr4, "sregs.CR4 (0x%llx) != CR4 (0x%lx)", 1107a873e45SSean Christopherson sregs.cr4, cr4); 1117a873e45SSean Christopherson 1127a873e45SSean Christopherson /* Verify all unsupported features are rejected by KVM. */ 113d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_UMIP); 114d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_LA57); 115d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_VMXE); 116d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMXE); 117d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_FSGSBASE); 118d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_PCIDE); 119d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_OSXSAVE); 120d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMEP); 121d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMAP); 122d31e1500SSean Christopherson test_cr4_feature_bit(vcpu, &sregs, X86_CR4_PKE); 1237a873e45SSean Christopherson kvm_vm_free(vm); 1247a873e45SSean Christopherson 1257a873e45SSean Christopherson /* Create a "real" VM and verify APIC_BASE can be set. */ 126d31e1500SSean Christopherson vm = vm_create_with_one_vcpu(&vcpu, NULL); 127cc68765dSAndrew Jones 128d31e1500SSean Christopherson vcpu_sregs_get(vm, vcpu->id, &sregs); 129cc68765dSAndrew Jones sregs.apic_base = 1 << 10; 130d31e1500SSean Christopherson rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); 131cc68765dSAndrew Jones TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", 132cc68765dSAndrew Jones sregs.apic_base); 133cc68765dSAndrew Jones sregs.apic_base = 1 << 11; 134d31e1500SSean Christopherson rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); 135cc68765dSAndrew Jones TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", 136cc68765dSAndrew Jones sregs.apic_base); 137cc68765dSAndrew Jones 138cc68765dSAndrew Jones kvm_vm_free(vm); 139cc68765dSAndrew Jones 140cc68765dSAndrew Jones return 0; 141cc68765dSAndrew Jones } 142