diff options
| -rw-r--r-- | tools/testing/selftests/kvm/.gitignore | 1 | ||||
| -rw-r--r-- | tools/testing/selftests/kvm/Makefile | 1 | ||||
| -rw-r--r-- | tools/testing/selftests/kvm/include/kvm_util.h | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/kvm/lib/kvm_util.c | 32 | ||||
| -rw-r--r-- | tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c | 280 |
5 files changed, 318 insertions, 0 deletions
diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 2a9209d18684..df1bf9230a74 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | /x86_64/state_test | 8 | /x86_64/state_test |
| 9 | /x86_64/sync_regs_test | 9 | /x86_64/sync_regs_test |
| 10 | /x86_64/vmx_close_while_nested_test | 10 | /x86_64/vmx_close_while_nested_test |
| 11 | /x86_64/vmx_set_nested_state_test | ||
| 11 | /x86_64/vmx_tsc_adjust_test | 12 | /x86_64/vmx_tsc_adjust_test |
| 12 | /clear_dirty_log_test | 13 | /clear_dirty_log_test |
| 13 | /dirty_log_test | 14 | /dirty_log_test |
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 6b7b3617d25c..79c524395ebe 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile | |||
| @@ -21,6 +21,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid | |||
| 21 | TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test | 21 | TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test |
| 22 | TEST_GEN_PROGS_x86_64 += x86_64/smm_test | 22 | TEST_GEN_PROGS_x86_64 += x86_64/smm_test |
| 23 | TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus | 23 | TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus |
| 24 | TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test | ||
| 24 | TEST_GEN_PROGS_x86_64 += dirty_log_test | 25 | TEST_GEN_PROGS_x86_64 += dirty_log_test |
| 25 | TEST_GEN_PROGS_x86_64 += clear_dirty_log_test | 26 | TEST_GEN_PROGS_x86_64 += clear_dirty_log_test |
| 26 | 27 | ||
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 07b71ad9734a..8c6b9619797d 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h | |||
| @@ -118,6 +118,10 @@ void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | |||
| 118 | struct kvm_vcpu_events *events); | 118 | struct kvm_vcpu_events *events); |
| 119 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | 119 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, |
| 120 | struct kvm_vcpu_events *events); | 120 | struct kvm_vcpu_events *events); |
| 121 | void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 122 | struct kvm_nested_state *state); | ||
| 123 | int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 124 | struct kvm_nested_state *state, bool ignore_error); | ||
| 121 | 125 | ||
| 122 | const char *exit_reason_str(unsigned int exit_reason); | 126 | const char *exit_reason_str(unsigned int exit_reason); |
| 123 | 127 | ||
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 4ca96b228e46..e9113857f44e 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c | |||
| @@ -1250,6 +1250,38 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | |||
| 1250 | ret, errno); | 1250 | ret, errno); |
| 1251 | } | 1251 | } |
| 1252 | 1252 | ||
| 1253 | void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 1254 | struct kvm_nested_state *state) | ||
| 1255 | { | ||
| 1256 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
| 1257 | int ret; | ||
| 1258 | |||
| 1259 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
| 1260 | |||
| 1261 | ret = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, state); | ||
| 1262 | TEST_ASSERT(ret == 0, | ||
| 1263 | "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", | ||
| 1264 | ret, errno); | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 1268 | struct kvm_nested_state *state, bool ignore_error) | ||
| 1269 | { | ||
| 1270 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
| 1271 | int ret; | ||
| 1272 | |||
| 1273 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
| 1274 | |||
| 1275 | ret = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state); | ||
| 1276 | if (!ignore_error) { | ||
| 1277 | TEST_ASSERT(ret == 0, | ||
| 1278 | "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", | ||
| 1279 | ret, errno); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | return ret; | ||
| 1283 | } | ||
| 1284 | |||
| 1253 | /* | 1285 | /* |
| 1254 | * VM VCPU System Regs Get | 1286 | * VM VCPU System Regs Get |
| 1255 | * | 1287 | * |
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c new file mode 100644 index 000000000000..61a2163cf9f1 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* | ||
| 2 | * vmx_set_nested_state_test | ||
| 3 | * | ||
| 4 | * Copyright (C) 2019, Google LLC. | ||
| 5 | * | ||
| 6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
| 7 | * | ||
| 8 | * This test verifies the integrity of calling the ioctl KVM_SET_NESTED_STATE. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include "test_util.h" | ||
| 12 | #include "kvm_util.h" | ||
| 13 | #include "processor.h" | ||
| 14 | #include "vmx.h" | ||
| 15 | |||
| 16 | #include <errno.h> | ||
| 17 | #include <linux/kvm.h> | ||
| 18 | #include <string.h> | ||
| 19 | #include <sys/ioctl.h> | ||
| 20 | #include <unistd.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Mirror of VMCS12_REVISION in arch/x86/kvm/vmx/vmcs12.h. If that value | ||
| 24 | * changes this should be updated. | ||
| 25 | */ | ||
| 26 | #define VMCS12_REVISION 0x11e57ed0 | ||
| 27 | #define VCPU_ID 5 | ||
| 28 | |||
| 29 | void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state) | ||
| 30 | { | ||
| 31 | volatile struct kvm_run *run; | ||
| 32 | |||
| 33 | vcpu_nested_state_set(vm, VCPU_ID, state, false); | ||
| 34 | run = vcpu_state(vm, VCPU_ID); | ||
| 35 | vcpu_run(vm, VCPU_ID); | ||
| 36 | TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, | ||
| 37 | "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n", | ||
| 38 | run->exit_reason, | ||
| 39 | exit_reason_str(run->exit_reason)); | ||
| 40 | } | ||
| 41 | |||
| 42 | void test_nested_state_expect_errno(struct kvm_vm *vm, | ||
| 43 | struct kvm_nested_state *state, | ||
| 44 | int expected_errno) | ||
| 45 | { | ||
| 46 | volatile struct kvm_run *run; | ||
| 47 | int rv; | ||
| 48 | |||
| 49 | rv = vcpu_nested_state_set(vm, VCPU_ID, state, true); | ||
| 50 | TEST_ASSERT(rv == -1 && errno == expected_errno, | ||
| 51 | "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)", | ||
| 52 | strerror(expected_errno), expected_errno, rv, strerror(errno), | ||
| 53 | errno); | ||
| 54 | run = vcpu_state(vm, VCPU_ID); | ||
| 55 | vcpu_run(vm, VCPU_ID); | ||
| 56 | TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, | ||
| 57 | "Got exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s),\n", | ||
| 58 | run->exit_reason, | ||
| 59 | exit_reason_str(run->exit_reason)); | ||
| 60 | } | ||
| 61 | |||
| 62 | void test_nested_state_expect_einval(struct kvm_vm *vm, | ||
| 63 | struct kvm_nested_state *state) | ||
| 64 | { | ||
| 65 | test_nested_state_expect_errno(vm, state, EINVAL); | ||
| 66 | } | ||
| 67 | |||
| 68 | void test_nested_state_expect_efault(struct kvm_vm *vm, | ||
| 69 | struct kvm_nested_state *state) | ||
| 70 | { | ||
| 71 | test_nested_state_expect_errno(vm, state, EFAULT); | ||
| 72 | } | ||
| 73 | |||
| 74 | void set_revision_id_for_vmcs12(struct kvm_nested_state *state, | ||
| 75 | u32 vmcs12_revision) | ||
| 76 | { | ||
| 77 | /* Set revision_id in vmcs12 to vmcs12_revision. */ | ||
| 78 | *(u32 *)(state->data) = vmcs12_revision; | ||
| 79 | } | ||
| 80 | |||
| 81 | void set_default_state(struct kvm_nested_state *state) | ||
| 82 | { | ||
| 83 | memset(state, 0, sizeof(*state)); | ||
| 84 | state->flags = KVM_STATE_NESTED_RUN_PENDING | | ||
| 85 | KVM_STATE_NESTED_GUEST_MODE; | ||
| 86 | state->format = 0; | ||
| 87 | state->size = sizeof(*state); | ||
| 88 | } | ||
| 89 | |||
| 90 | void set_default_vmx_state(struct kvm_nested_state *state, int size) | ||
| 91 | { | ||
| 92 | memset(state, 0, size); | ||
| 93 | state->flags = KVM_STATE_NESTED_GUEST_MODE | | ||
| 94 | KVM_STATE_NESTED_RUN_PENDING | | ||
| 95 | KVM_STATE_NESTED_EVMCS; | ||
| 96 | state->format = 0; | ||
| 97 | state->size = size; | ||
| 98 | state->vmx.vmxon_pa = 0x1000; | ||
| 99 | state->vmx.vmcs_pa = 0x2000; | ||
| 100 | state->vmx.smm.flags = 0; | ||
| 101 | set_revision_id_for_vmcs12(state, VMCS12_REVISION); | ||
| 102 | } | ||
| 103 | |||
| 104 | void test_vmx_nested_state(struct kvm_vm *vm) | ||
| 105 | { | ||
| 106 | /* Add a page for VMCS12. */ | ||
| 107 | const int state_sz = sizeof(struct kvm_nested_state) + getpagesize(); | ||
| 108 | struct kvm_nested_state *state = | ||
| 109 | (struct kvm_nested_state *)malloc(state_sz); | ||
| 110 | |||
| 111 | /* The format must be set to 0. 0 for VMX, 1 for SVM. */ | ||
| 112 | set_default_vmx_state(state, state_sz); | ||
| 113 | state->format = 1; | ||
| 114 | test_nested_state_expect_einval(vm, state); | ||
| 115 | |||
| 116 | /* | ||
| 117 | * We cannot virtualize anything if the guest does not have VMX | ||
| 118 | * enabled. | ||
| 119 | */ | ||
| 120 | set_default_vmx_state(state, state_sz); | ||
| 121 | test_nested_state_expect_einval(vm, state); | ||
| 122 | |||
| 123 | /* | ||
| 124 | * We cannot virtualize anything if the guest does not have VMX | ||
| 125 | * enabled. We expect KVM_SET_NESTED_STATE to return 0 if vmxon_pa | ||
| 126 | * is set to -1ull. | ||
| 127 | */ | ||
| 128 | set_default_vmx_state(state, state_sz); | ||
| 129 | state->vmx.vmxon_pa = -1ull; | ||
| 130 | test_nested_state(vm, state); | ||
| 131 | |||
| 132 | /* Enable VMX in the guest CPUID. */ | ||
| 133 | vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); | ||
| 134 | |||
| 135 | /* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */ | ||
| 136 | set_default_vmx_state(state, state_sz); | ||
| 137 | state->vmx.vmxon_pa = -1ull; | ||
| 138 | state->vmx.smm.flags = 1; | ||
| 139 | test_nested_state_expect_einval(vm, state); | ||
| 140 | |||
| 141 | /* It is invalid to have vmxon_pa == -1ull and vmcs_pa != -1ull. */ | ||
| 142 | set_default_vmx_state(state, state_sz); | ||
| 143 | state->vmx.vmxon_pa = -1ull; | ||
| 144 | state->vmx.vmcs_pa = 0; | ||
| 145 | test_nested_state_expect_einval(vm, state); | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without | ||
| 149 | * setting the nested state. | ||
| 150 | */ | ||
| 151 | set_default_vmx_state(state, state_sz); | ||
| 152 | state->vmx.vmxon_pa = -1ull; | ||
| 153 | state->vmx.vmcs_pa = -1ull; | ||
| 154 | test_nested_state(vm, state); | ||
| 155 | |||
| 156 | /* It is invalid to have vmxon_pa set to a non-page aligned address. */ | ||
| 157 | set_default_vmx_state(state, state_sz); | ||
| 158 | state->vmx.vmxon_pa = 1; | ||
| 159 | test_nested_state_expect_einval(vm, state); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * It is invalid to have KVM_STATE_NESTED_SMM_GUEST_MODE and | ||
| 163 | * KVM_STATE_NESTED_GUEST_MODE set together. | ||
| 164 | */ | ||
| 165 | set_default_vmx_state(state, state_sz); | ||
| 166 | state->flags = KVM_STATE_NESTED_GUEST_MODE | | ||
| 167 | KVM_STATE_NESTED_RUN_PENDING; | ||
| 168 | state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE; | ||
| 169 | test_nested_state_expect_einval(vm, state); | ||
| 170 | |||
| 171 | /* | ||
| 172 | * It is invalid to have any of the SMM flags set besides: | ||
| 173 | * KVM_STATE_NESTED_SMM_GUEST_MODE | ||
| 174 | * KVM_STATE_NESTED_SMM_VMXON | ||
| 175 | */ | ||
| 176 | set_default_vmx_state(state, state_sz); | ||
| 177 | state->vmx.smm.flags = ~(KVM_STATE_NESTED_SMM_GUEST_MODE | | ||
| 178 | KVM_STATE_NESTED_SMM_VMXON); | ||
| 179 | test_nested_state_expect_einval(vm, state); | ||
| 180 | |||
| 181 | /* Outside SMM, SMM flags must be zero. */ | ||
| 182 | set_default_vmx_state(state, state_sz); | ||
| 183 | state->flags = 0; | ||
| 184 | state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE; | ||
| 185 | test_nested_state_expect_einval(vm, state); | ||
| 186 | |||
| 187 | /* Size must be large enough to fit kvm_nested_state and vmcs12. */ | ||
| 188 | set_default_vmx_state(state, state_sz); | ||
| 189 | state->size = sizeof(*state); | ||
| 190 | test_nested_state(vm, state); | ||
| 191 | |||
| 192 | /* vmxon_pa cannot be the same address as vmcs_pa. */ | ||
| 193 | set_default_vmx_state(state, state_sz); | ||
| 194 | state->vmx.vmxon_pa = 0; | ||
| 195 | state->vmx.vmcs_pa = 0; | ||
| 196 | test_nested_state_expect_einval(vm, state); | ||
| 197 | |||
| 198 | /* The revision id for vmcs12 must be VMCS12_REVISION. */ | ||
| 199 | set_default_vmx_state(state, state_sz); | ||
| 200 | set_revision_id_for_vmcs12(state, 0); | ||
| 201 | test_nested_state_expect_einval(vm, state); | ||
| 202 | |||
| 203 | /* | ||
| 204 | * Test that if we leave nesting the state reflects that when we get | ||
| 205 | * it again. | ||
| 206 | */ | ||
| 207 | set_default_vmx_state(state, state_sz); | ||
| 208 | state->vmx.vmxon_pa = -1ull; | ||
| 209 | state->vmx.vmcs_pa = -1ull; | ||
| 210 | state->flags = 0; | ||
| 211 | test_nested_state(vm, state); | ||
| 212 | vcpu_nested_state_get(vm, VCPU_ID, state); | ||
| 213 | TEST_ASSERT(state->size >= sizeof(*state) && state->size <= state_sz, | ||
| 214 | "Size must be between %d and %d. The size returned was %d.", | ||
| 215 | sizeof(*state), state_sz, state->size); | ||
| 216 | TEST_ASSERT(state->vmx.vmxon_pa == -1ull, "vmxon_pa must be -1ull."); | ||
| 217 | TEST_ASSERT(state->vmx.vmcs_pa == -1ull, "vmcs_pa must be -1ull."); | ||
| 218 | |||
| 219 | free(state); | ||
| 220 | } | ||
| 221 | |||
| 222 | int main(int argc, char *argv[]) | ||
| 223 | { | ||
| 224 | struct kvm_vm *vm; | ||
| 225 | struct kvm_nested_state state; | ||
| 226 | struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); | ||
| 227 | |||
| 228 | if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) { | ||
| 229 | printf("KVM_CAP_NESTED_STATE not available, skipping test\n"); | ||
| 230 | exit(KSFT_SKIP); | ||
| 231 | } | ||
| 232 | |||
| 233 | /* | ||
| 234 | * AMD currently does not implement set_nested_state, so for now we | ||
| 235 | * just early out. | ||
| 236 | */ | ||
| 237 | if (!(entry->ecx & CPUID_VMX)) { | ||
| 238 | fprintf(stderr, "nested VMX not enabled, skipping test\n"); | ||
| 239 | exit(KSFT_SKIP); | ||
| 240 | } | ||
| 241 | |||
| 242 | vm = vm_create_default(VCPU_ID, 0, 0); | ||
| 243 | |||
| 244 | /* Passing a NULL kvm_nested_state causes a EFAULT. */ | ||
| 245 | test_nested_state_expect_efault(vm, NULL); | ||
| 246 | |||
| 247 | /* 'size' cannot be smaller than sizeof(kvm_nested_state). */ | ||
| 248 | set_default_state(&state); | ||
| 249 | state.size = 0; | ||
| 250 | test_nested_state_expect_einval(vm, &state); | ||
| 251 | |||
| 252 | /* | ||
| 253 | * Setting the flags 0xf fails the flags check. The only flags that | ||
| 254 | * can be used are: | ||
| 255 | * KVM_STATE_NESTED_GUEST_MODE | ||
| 256 | * KVM_STATE_NESTED_RUN_PENDING | ||
| 257 | * KVM_STATE_NESTED_EVMCS | ||
| 258 | */ | ||
| 259 | set_default_state(&state); | ||
| 260 | state.flags = 0xf; | ||
| 261 | test_nested_state_expect_einval(vm, &state); | ||
| 262 | |||
| 263 | /* | ||
| 264 | * If KVM_STATE_NESTED_RUN_PENDING is set then | ||
| 265 | * KVM_STATE_NESTED_GUEST_MODE has to be set as well. | ||
| 266 | */ | ||
| 267 | set_default_state(&state); | ||
| 268 | state.flags = KVM_STATE_NESTED_RUN_PENDING; | ||
| 269 | test_nested_state_expect_einval(vm, &state); | ||
| 270 | |||
| 271 | /* | ||
| 272 | * TODO: When SVM support is added for KVM_SET_NESTED_STATE | ||
| 273 | * add tests here to support it like VMX. | ||
| 274 | */ | ||
| 275 | if (entry->ecx & CPUID_VMX) | ||
| 276 | test_vmx_nested_state(vm); | ||
| 277 | |||
| 278 | kvm_vm_free(vm); | ||
| 279 | return 0; | ||
| 280 | } | ||
