Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021, Red Hat Inc.
0004  *
0005  * Generic tests for KVM CPUID set/get ioctls
0006  */
0007 #include <asm/kvm_para.h>
0008 #include <linux/kvm_para.h>
0009 #include <stdint.h>
0010 
0011 #include "test_util.h"
0012 #include "kvm_util.h"
0013 #include "processor.h"
0014 
0015 /* CPUIDs known to differ */
0016 struct {
0017     u32 function;
0018     u32 index;
0019 } mangled_cpuids[] = {
0020     /*
0021      * These entries depend on the vCPU's XCR0 register and IA32_XSS MSR,
0022      * which are not controlled for by this test.
0023      */
0024     {.function = 0xd, .index = 0},
0025     {.function = 0xd, .index = 1},
0026 };
0027 
0028 static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid)
0029 {
0030     int i;
0031     u32 eax, ebx, ecx, edx;
0032 
0033     for (i = 0; i < guest_cpuid->nent; i++) {
0034         __cpuid(guest_cpuid->entries[i].function,
0035             guest_cpuid->entries[i].index,
0036             &eax, &ebx, &ecx, &edx);
0037 
0038         GUEST_ASSERT(eax == guest_cpuid->entries[i].eax &&
0039                  ebx == guest_cpuid->entries[i].ebx &&
0040                  ecx == guest_cpuid->entries[i].ecx &&
0041                  edx == guest_cpuid->entries[i].edx);
0042     }
0043 
0044 }
0045 
0046 static void test_cpuid_40000000(struct kvm_cpuid2 *guest_cpuid)
0047 {
0048     u32 eax, ebx, ecx, edx;
0049 
0050     cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
0051 
0052     GUEST_ASSERT(eax == 0x40000001);
0053 }
0054 
0055 static void guest_main(struct kvm_cpuid2 *guest_cpuid)
0056 {
0057     GUEST_SYNC(1);
0058 
0059     test_guest_cpuids(guest_cpuid);
0060 
0061     GUEST_SYNC(2);
0062 
0063     test_cpuid_40000000(guest_cpuid);
0064 
0065     GUEST_DONE();
0066 }
0067 
0068 static bool is_cpuid_mangled(const struct kvm_cpuid_entry2 *entrie)
0069 {
0070     int i;
0071 
0072     for (i = 0; i < sizeof(mangled_cpuids); i++) {
0073         if (mangled_cpuids[i].function == entrie->function &&
0074             mangled_cpuids[i].index == entrie->index)
0075             return true;
0076     }
0077 
0078     return false;
0079 }
0080 
0081 static void compare_cpuids(const struct kvm_cpuid2 *cpuid1,
0082                const struct kvm_cpuid2 *cpuid2)
0083 {
0084     const struct kvm_cpuid_entry2 *e1, *e2;
0085     int i;
0086 
0087     TEST_ASSERT(cpuid1->nent == cpuid2->nent,
0088             "CPUID nent mismatch: %d vs. %d", cpuid1->nent, cpuid2->nent);
0089 
0090     for (i = 0; i < cpuid1->nent; i++) {
0091         e1 = &cpuid1->entries[i];
0092         e2 = &cpuid2->entries[i];
0093 
0094         TEST_ASSERT(e1->function == e2->function &&
0095                 e1->index == e2->index && e1->flags == e2->flags,
0096                 "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n",
0097                 i, e1->function, e1->index, e1->flags,
0098                 e2->function, e2->index, e2->flags);
0099 
0100         if (is_cpuid_mangled(e1))
0101             continue;
0102 
0103         TEST_ASSERT(e1->eax == e2->eax && e1->ebx == e2->ebx &&
0104                 e1->ecx == e2->ecx && e1->edx == e2->edx,
0105                 "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x",
0106                 e1->function, e1->index,
0107                 e1->eax, e1->ebx, e1->ecx, e1->edx,
0108                 e2->eax, e2->ebx, e2->ecx, e2->edx);
0109     }
0110 }
0111 
0112 static void run_vcpu(struct kvm_vcpu *vcpu, int stage)
0113 {
0114     struct ucall uc;
0115 
0116     vcpu_run(vcpu);
0117 
0118     switch (get_ucall(vcpu, &uc)) {
0119     case UCALL_SYNC:
0120         TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
0121                 uc.args[1] == stage + 1,
0122                 "Stage %d: Unexpected register values vmexit, got %lx",
0123                 stage + 1, (ulong)uc.args[1]);
0124         return;
0125     case UCALL_DONE:
0126         return;
0127     case UCALL_ABORT:
0128         REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx");
0129     default:
0130         TEST_ASSERT(false, "Unexpected exit: %s",
0131                 exit_reason_str(vcpu->run->exit_reason));
0132     }
0133 }
0134 
0135 struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid)
0136 {
0137     int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]);
0138     vm_vaddr_t gva = vm_vaddr_alloc(vm, size, KVM_UTIL_MIN_VADDR);
0139     struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva);
0140 
0141     memcpy(guest_cpuids, cpuid, size);
0142 
0143     *p_gva = gva;
0144     return guest_cpuids;
0145 }
0146 
0147 static void set_cpuid_after_run(struct kvm_vcpu *vcpu)
0148 {
0149     struct kvm_cpuid_entry2 *ent;
0150     int rc;
0151     u32 eax, ebx, x;
0152 
0153     /* Setting unmodified CPUID is allowed */
0154     rc = __vcpu_set_cpuid(vcpu);
0155     TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc);
0156 
0157     /* Changing CPU features is forbidden */
0158     ent = vcpu_get_cpuid_entry(vcpu, 0x7);
0159     ebx = ent->ebx;
0160     ent->ebx--;
0161     rc = __vcpu_set_cpuid(vcpu);
0162     TEST_ASSERT(rc, "Changing CPU features should fail");
0163     ent->ebx = ebx;
0164 
0165     /* Changing MAXPHYADDR is forbidden */
0166     ent = vcpu_get_cpuid_entry(vcpu, 0x80000008);
0167     eax = ent->eax;
0168     x = eax & 0xff;
0169     ent->eax = (eax & ~0xffu) | (x - 1);
0170     rc = __vcpu_set_cpuid(vcpu);
0171     TEST_ASSERT(rc, "Changing MAXPHYADDR should fail");
0172     ent->eax = eax;
0173 }
0174 
0175 int main(void)
0176 {
0177     struct kvm_vcpu *vcpu;
0178     vm_vaddr_t cpuid_gva;
0179     struct kvm_vm *vm;
0180     int stage;
0181 
0182     vm = vm_create_with_one_vcpu(&vcpu, guest_main);
0183 
0184     compare_cpuids(kvm_get_supported_cpuid(), vcpu->cpuid);
0185 
0186     vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid);
0187 
0188     vcpu_args_set(vcpu, 1, cpuid_gva);
0189 
0190     for (stage = 0; stage < 3; stage++)
0191         run_vcpu(vcpu, stage);
0192 
0193     set_cpuid_after_run(vcpu);
0194 
0195     kvm_vm_free(vm);
0196 }