1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * vcpu_width_config - Test KVM_ARM_VCPU_INIT() with KVM_ARM_VCPU_EL1_32BIT.
4 *
5 * Copyright (c) 2022 Google LLC.
6 *
7 * This is a test that ensures that non-mixed-width vCPUs (all 64bit vCPUs
8 * or all 32bit vcPUs) can be configured and mixed-width vCPUs cannot be
9 * configured.
10 */
11
12 #include "kvm_util.h"
13 #include "processor.h"
14 #include "test_util.h"
15
16
17 /*
18 * Add a vCPU, run KVM_ARM_VCPU_INIT with @init0, and then
19 * add another vCPU, and run KVM_ARM_VCPU_INIT with @init1.
20 */
add_init_2vcpus(struct kvm_vcpu_init * init0,struct kvm_vcpu_init * init1)21 static int add_init_2vcpus(struct kvm_vcpu_init *init0,
22 struct kvm_vcpu_init *init1)
23 {
24 struct kvm_vcpu *vcpu0, *vcpu1;
25 struct kvm_vm *vm;
26 int ret;
27
28 vm = vm_create_barebones();
29
30 vcpu0 = __vm_vcpu_add(vm, 0);
31 ret = __vcpu_ioctl(vcpu0, KVM_ARM_VCPU_INIT, init0);
32 if (ret)
33 goto free_exit;
34
35 vcpu1 = __vm_vcpu_add(vm, 1);
36 ret = __vcpu_ioctl(vcpu1, KVM_ARM_VCPU_INIT, init1);
37
38 free_exit:
39 kvm_vm_free(vm);
40 return ret;
41 }
42
43 /*
44 * Add two vCPUs, then run KVM_ARM_VCPU_INIT for one vCPU with @init0,
45 * and run KVM_ARM_VCPU_INIT for another vCPU with @init1.
46 */
add_2vcpus_init_2vcpus(struct kvm_vcpu_init * init0,struct kvm_vcpu_init * init1)47 static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init0,
48 struct kvm_vcpu_init *init1)
49 {
50 struct kvm_vcpu *vcpu0, *vcpu1;
51 struct kvm_vm *vm;
52 int ret;
53
54 vm = vm_create_barebones();
55
56 vcpu0 = __vm_vcpu_add(vm, 0);
57 vcpu1 = __vm_vcpu_add(vm, 1);
58
59 ret = __vcpu_ioctl(vcpu0, KVM_ARM_VCPU_INIT, init0);
60 if (ret)
61 goto free_exit;
62
63 ret = __vcpu_ioctl(vcpu1, KVM_ARM_VCPU_INIT, init1);
64
65 free_exit:
66 kvm_vm_free(vm);
67 return ret;
68 }
69
70 /*
71 * Tests that two 64bit vCPUs can be configured, two 32bit vCPUs can be
72 * configured, and two mixed-width vCPUs cannot be configured.
73 * Each of those three cases, configure vCPUs in two different orders.
74 * The one is running KVM_CREATE_VCPU for 2 vCPUs, and then running
75 * KVM_ARM_VCPU_INIT for them.
76 * The other is running KVM_CREATE_VCPU and KVM_ARM_VCPU_INIT for a vCPU,
77 * and then run those commands for another vCPU.
78 */
main(void)79 int main(void)
80 {
81 struct kvm_vcpu_init init0, init1;
82 struct kvm_vm *vm;
83 int ret;
84
85 TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_EL1_32BIT));
86
87 /* Get the preferred target type and copy that to init1 for later use */
88 vm = vm_create_barebones();
89 vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init0);
90 kvm_vm_free(vm);
91 init1 = init0;
92
93 /* Test with 64bit vCPUs */
94 ret = add_init_2vcpus(&init0, &init0);
95 TEST_ASSERT(ret == 0,
96 "Configuring 64bit EL1 vCPUs failed unexpectedly");
97 ret = add_2vcpus_init_2vcpus(&init0, &init0);
98 TEST_ASSERT(ret == 0,
99 "Configuring 64bit EL1 vCPUs failed unexpectedly");
100
101 /* Test with 32bit vCPUs */
102 init0.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT);
103 ret = add_init_2vcpus(&init0, &init0);
104 TEST_ASSERT(ret == 0,
105 "Configuring 32bit EL1 vCPUs failed unexpectedly");
106 ret = add_2vcpus_init_2vcpus(&init0, &init0);
107 TEST_ASSERT(ret == 0,
108 "Configuring 32bit EL1 vCPUs failed unexpectedly");
109
110 /* Test with mixed-width vCPUs */
111 init0.features[0] = 0;
112 init1.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT);
113 ret = add_init_2vcpus(&init0, &init1);
114 TEST_ASSERT(ret != 0,
115 "Configuring mixed-width vCPUs worked unexpectedly");
116 ret = add_2vcpus_init_2vcpus(&init0, &init1);
117 TEST_ASSERT(ret != 0,
118 "Configuring mixed-width vCPUs worked unexpectedly");
119
120 return 0;
121 }
122