11// SPDX-License-Identifier: GPL-2.0-only
22/*
3- * vmx_set_nested_state_test
4- *
53 * Copyright (C) 2019, Google LLC.
64 *
75 * This test verifies the integrity of calling the ioctl KVM_SET_NESTED_STATE.
119#include "kvm_util.h"
1210#include "processor.h"
1311#include "vmx.h"
12+ #include "svm_util.h"
1413
1514#include <errno.h>
1615#include <linux/kvm.h>
@@ -249,6 +248,104 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu)
249248 free (state );
250249}
251250
251+ static void vcpu_efer_enable_svm (struct kvm_vcpu * vcpu )
252+ {
253+ uint64_t old_efer = vcpu_get_msr (vcpu , MSR_EFER );
254+
255+ vcpu_set_msr (vcpu , MSR_EFER , old_efer | EFER_SVME );
256+ }
257+
258+ static void vcpu_efer_disable_svm (struct kvm_vcpu * vcpu )
259+ {
260+ uint64_t old_efer = vcpu_get_msr (vcpu , MSR_EFER );
261+
262+ vcpu_set_msr (vcpu , MSR_EFER , old_efer & ~EFER_SVME );
263+ }
264+
265+ void set_default_svm_state (struct kvm_nested_state * state , int size )
266+ {
267+ memset (state , 0 , size );
268+ state -> format = 1 ;
269+ state -> size = size ;
270+ state -> hdr .svm .vmcb_pa = 0x3000 ;
271+ }
272+
273+ void test_svm_nested_state (struct kvm_vcpu * vcpu )
274+ {
275+ /* Add a page for VMCB. */
276+ const int state_sz = sizeof (struct kvm_nested_state ) + getpagesize ();
277+ struct kvm_nested_state * state =
278+ (struct kvm_nested_state * )malloc (state_sz );
279+
280+ vcpu_set_cpuid_feature (vcpu , X86_FEATURE_SVM );
281+
282+ /* The format must be set to 1. 0 for VMX, 1 for SVM. */
283+ set_default_svm_state (state , state_sz );
284+ state -> format = 0 ;
285+ test_nested_state_expect_einval (vcpu , state );
286+
287+ /* Invalid flags are rejected, KVM_STATE_NESTED_EVMCS is VMX-only */
288+ set_default_svm_state (state , state_sz );
289+ state -> flags = KVM_STATE_NESTED_EVMCS ;
290+ test_nested_state_expect_einval (vcpu , state );
291+
292+ /*
293+ * If EFER.SVME is clear, guest mode is disallowed and GIF can be set or
294+ * cleared.
295+ */
296+ vcpu_efer_disable_svm (vcpu );
297+
298+ set_default_svm_state (state , state_sz );
299+ state -> flags = KVM_STATE_NESTED_GUEST_MODE ;
300+ test_nested_state_expect_einval (vcpu , state );
301+
302+ state -> flags = 0 ;
303+ test_nested_state (vcpu , state );
304+
305+ state -> flags = KVM_STATE_NESTED_GIF_SET ;
306+ test_nested_state (vcpu , state );
307+
308+ /* Enable SVM in the guest EFER. */
309+ vcpu_efer_enable_svm (vcpu );
310+
311+ /* Setting vmcb_pa to a non-aligned address is only fine when not entering guest mode */
312+ set_default_svm_state (state , state_sz );
313+ state -> hdr .svm .vmcb_pa = -1ull ;
314+ state -> flags = 0 ;
315+ test_nested_state (vcpu , state );
316+ state -> flags = KVM_STATE_NESTED_GUEST_MODE ;
317+ test_nested_state_expect_einval (vcpu , state );
318+
319+ /*
320+ * Size must be large enough to fit kvm_nested_state and VMCB
321+ * only when entering guest mode.
322+ */
323+ set_default_svm_state (state , state_sz /2 );
324+ state -> flags = 0 ;
325+ test_nested_state (vcpu , state );
326+ state -> flags = KVM_STATE_NESTED_GUEST_MODE ;
327+ test_nested_state_expect_einval (vcpu , state );
328+
329+ /*
330+ * Test that if we leave nesting the state reflects that when we get it
331+ * again, except for vmcb_pa, which is always returned as 0 when not in
332+ * guest mode.
333+ */
334+ set_default_svm_state (state , state_sz );
335+ state -> hdr .svm .vmcb_pa = -1ull ;
336+ state -> flags = KVM_STATE_NESTED_GIF_SET ;
337+ test_nested_state (vcpu , state );
338+ vcpu_nested_state_get (vcpu , state );
339+ TEST_ASSERT (state -> size >= sizeof (* state ) && state -> size <= state_sz ,
340+ "Size must be between %ld and %d. The size returned was %d." ,
341+ sizeof (* state ), state_sz , state -> size );
342+
343+ TEST_ASSERT_EQ (state -> hdr .svm .vmcb_pa , 0 );
344+ TEST_ASSERT_EQ (state -> flags , KVM_STATE_NESTED_GIF_SET );
345+
346+ free (state );
347+ }
348+
252349int main (int argc , char * argv [])
253350{
254351 struct kvm_vm * vm ;
@@ -257,20 +354,20 @@ int main(int argc, char *argv[])
257354
258355 have_evmcs = kvm_check_cap (KVM_CAP_HYPERV_ENLIGHTENED_VMCS );
259356
357+ TEST_REQUIRE (kvm_cpu_has (X86_FEATURE_VMX ) ||
358+ kvm_cpu_has (X86_FEATURE_SVM ));
260359 TEST_REQUIRE (kvm_has_cap (KVM_CAP_NESTED_STATE ));
261360
262- /*
263- * AMD currently does not implement set_nested_state, so for now we
264- * just early out.
265- */
266- TEST_REQUIRE (kvm_cpu_has (X86_FEATURE_VMX ));
267-
268361 vm = vm_create_with_one_vcpu (& vcpu , NULL );
269362
270363 /*
271- * First run tests with VMX disabled to check error handling.
364+ * First run tests with VMX/SVM disabled to check error handling.
365+ * test_{vmx/svm}_nested_state() will re-enable as needed.
272366 */
273- vcpu_clear_cpuid_feature (vcpu , X86_FEATURE_VMX );
367+ if (kvm_cpu_has (X86_FEATURE_VMX ))
368+ vcpu_clear_cpuid_feature (vcpu , X86_FEATURE_VMX );
369+ else
370+ vcpu_clear_cpuid_feature (vcpu , X86_FEATURE_SVM );
274371
275372 /* Passing a NULL kvm_nested_state causes a EFAULT. */
276373 test_nested_state_expect_efault (vcpu , NULL );
@@ -299,7 +396,10 @@ int main(int argc, char *argv[])
299396 state .flags = KVM_STATE_NESTED_RUN_PENDING ;
300397 test_nested_state_expect_einval (vcpu , & state );
301398
302- test_vmx_nested_state (vcpu );
399+ if (kvm_cpu_has (X86_FEATURE_VMX ))
400+ test_vmx_nested_state (vcpu );
401+ else
402+ test_svm_nested_state (vcpu );
303403
304404 kvm_vm_free (vm );
305405 return 0 ;
0 commit comments