From nobody Wed Oct 1 20:28:49 2025 Received: from out-188.mta1.migadu.com (out-188.mta1.migadu.com [95.215.58.188]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D741A304BD0 for ; Wed, 1 Oct 2025 14:58:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330724; cv=none; b=naeifZJxoeg8eaun63f6YczLpwg2Qbwykn/VxHxXkG4G2w7YAsYz0rnnqPZQBg8WO3hW/6QPnB29WOj8m/dKAvc82ALRlU2fi3PeXPNqQUr9R9P8wZxUKvfBMcNdlEatQryP/AQEIHLtQllabe/fO2URNOmNnL41mdIR4Mk8MTo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330724; c=relaxed/simple; bh=imkiUoz4g7AHZ4k9B6g4aWyy2WAIjiLuKFQB7Ec6R+E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gE0ukE9NLH+15SnrljIAuJ9GLwy9WuyhNFIz6SKyU+/Oy0T7AcE9XJguJVqfrOZdiHE9BxV32uFBmsogeHRRxOIiXqwFtYkfKVMS4I8g/V89LjYFTnILBBylpdMJL4Yss/21bOGLNOSCPAe3dq/P98nrc2Nxley3ZjKLM4azyH0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Fl1Vne7R; arc=none smtp.client-ip=95.215.58.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Fl1Vne7R" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330719; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZiG7uEL/pYERdGHD4GxrFZAThJNX66jF2OETI45KlPk=; b=Fl1Vne7RufEndIrp4NkcLeBvYi4kY9q4ac36GwxzPmG2t8xTJlm8ERzRxPv/0fW4VNhSbF 9+r/8C6Au7CgzOecVy49ryT+90ER7TsEnqR8KwjnW5EBUyX3D9sVeVBjW7nnEv8LnB7xmx qIWey+M/xudePDn6g0moJhffgNudiSM= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 01/12] KVM: selftests: Minor improvements to asserts in test_vmx_nested_state() Date: Wed, 1 Oct 2025 14:58:05 +0000 Message-ID: <20251001145816.1414855-2-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Display the address as hex if the asserts for the vmxon_pa and vmcs12_pa fail, and assert that the flags are 0 as expected. Signed-off-by: Yosry Ahmed --- .../selftests/kvm/x86/vmx_set_nested_state_test.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c b/= tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c index 67a62a5a88951..c4c400d2824c1 100644 --- a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c @@ -241,8 +241,14 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) TEST_ASSERT(state->size >=3D sizeof(*state) && state->size <=3D state_sz, "Size must be between %ld and %d. The size returned was %d.", sizeof(*state), state_sz, state->size); - TEST_ASSERT(state->hdr.vmx.vmxon_pa =3D=3D -1ull, "vmxon_pa must be -1ull= ."); - TEST_ASSERT(state->hdr.vmx.vmcs12_pa =3D=3D -1ull, "vmcs_pa must be -1ull= ."); + TEST_ASSERT(state->hdr.vmx.vmxon_pa =3D=3D -1ull, + "vmxon_pa must be 0x%llx, but was 0x%llx", + -1ull, state->hdr.vmx.vmxon_pa); + TEST_ASSERT(state->hdr.vmx.vmcs12_pa =3D=3D -1ull, + "vmcs12_pa must be 0x%llx, but was 0x%llx", + -1llu, state->hdr.vmx.vmcs12_pa); + TEST_ASSERT(state->flags =3D=3D 0, + "Flags must be equal to 0, but was 0x%hx", state->flags); =20 free(state); } --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-182.mta1.migadu.com (out-182.mta1.migadu.com [95.215.58.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93DF3304BC6; Wed, 1 Oct 2025 14:58:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330725; cv=none; b=pRrLNCqVcWKJuVl8i5aOuExcTqhqCB0cEmAQv9zjsyZisZvtpBSSo0AUyKsP55SaMU5FoP0A4giLRN+hkbplY7g4OYPXNXCab35pBGukQBeC6HS4jvvaU3XUHrWgN7vtYicervOBYCSY3ps1YRROj1b+hBZExXL7LxlaqN36XeY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330725; c=relaxed/simple; bh=ceAZ4PjmP3sd/XfFUS76NUQmGMmpIwOKSc+9I8nxVDo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TZ5KQRfBYkqYdD33b6mNEiJi553U/9HbK+v37DGnKahTEykcgtIzhLmZXFzEqh6wd8ROagYVDWb/5cemGtrmKAecYUPkcQewkVNQCLjBNdux7O89in2o6KyiqpZLeUjhQKzyszwnTT8M6n5RqXzbzejQfCwQRGywG+PVm+Rgsi8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=fbKidQ23; arc=none smtp.client-ip=95.215.58.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="fbKidQ23" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330721; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ICnHDNBwoB1fVGmbv1qEbjn1Z8+EX9iLIuDTuF6fUy8=; b=fbKidQ23eafd9R627wbdXyEzi+LpC5gbz0h012JleBGuIbX9lqNkLwwM08ZjuTb8oq7Xao PasiKZBNlmOsYofZY5m6lAMPnZk6/BGq3jWmQXHL+2tVpdpUJu8CLY/qRM601Zhl0r95YX LwWbFBuMtXjpQ/VUQwXRsvsAlm8cQE0= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 02/12] KVM: selftests: Extend vmx_set_nested_state_test to cover SVM Date: Wed, 1 Oct 2025 14:58:06 +0000 Message-ID: <20251001145816.1414855-3-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add test cases for the validation checks in svm_set_nested_state(), and allow the test to run with SVM as well as VMX. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- ...d_state_test.c =3D> set_nested_state_test.c} | 122 ++++++++++++++++-- 2 files changed, 113 insertions(+), 11 deletions(-) rename tools/testing/selftests/kvm/x86/{vmx_set_nested_state_test.c =3D> s= et_nested_state_test.c} (70%) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 148d427ff24be..6582396518b19 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -116,7 +116,7 @@ TEST_GEN_PROGS_x86 +=3D x86/vmx_dirty_log_test TEST_GEN_PROGS_x86 +=3D x86/vmx_exception_with_invalid_guest_state TEST_GEN_PROGS_x86 +=3D x86/vmx_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_invalid_nested_guest_state -TEST_GEN_PROGS_x86 +=3D x86/vmx_set_nested_state_test +TEST_GEN_PROGS_x86 +=3D x86/set_nested_state_test TEST_GEN_PROGS_x86 +=3D x86/vmx_tsc_adjust_test TEST_GEN_PROGS_x86 +=3D x86/vmx_nested_tsc_scaling_test TEST_GEN_PROGS_x86 +=3D x86/apic_bus_clock_test diff --git a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c b/= tools/testing/selftests/kvm/x86/set_nested_state_test.c similarity index 70% rename from tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c rename to tools/testing/selftests/kvm/x86/set_nested_state_test.c index c4c400d2824c1..98a9cd4873d19 100644 --- a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86/set_nested_state_test.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_set_nested_state_test + * set_nested_state_test * * Copyright (C) 2019, Google LLC. * @@ -11,6 +11,7 @@ #include "kvm_util.h" #include "processor.h" #include "vmx.h" +#include "svm_util.h" =20 #include #include @@ -253,6 +254,104 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) free(state); } =20 +static void vcpu_efer_enable_svm(struct kvm_vcpu *vcpu) +{ + uint64_t old_efer =3D vcpu_get_msr(vcpu, MSR_EFER); + + vcpu_set_msr(vcpu, MSR_EFER, old_efer | EFER_SVME); +} + +static void vcpu_efer_disable_svm(struct kvm_vcpu *vcpu) +{ + uint64_t old_efer =3D vcpu_get_msr(vcpu, MSR_EFER); + + vcpu_set_msr(vcpu, MSR_EFER, old_efer & ~EFER_SVME); +} + +void set_default_svm_state(struct kvm_nested_state *state, int size) +{ + memset(state, 0, size); + state->format =3D 1; + state->size =3D size; + state->hdr.svm.vmcb_pa =3D 0x3000; +} + +void test_svm_nested_state(struct kvm_vcpu *vcpu) +{ + /* Add a page for VMCB. */ + const int state_sz =3D sizeof(struct kvm_nested_state) + getpagesize(); + struct kvm_nested_state *state =3D + (struct kvm_nested_state *)malloc(state_sz); + + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_SVM); + + /* The format must be set to 1. 0 for VMX, 1 for SVM. */ + set_default_svm_state(state, state_sz); + state->format =3D 0; + test_nested_state_expect_einval(vcpu, state); + + /* Invalid flags are rejected, KVM_STATE_NESTED_EVMCS is VMX-only */ + set_default_svm_state(state, state_sz); + state->flags =3D KVM_STATE_NESTED_EVMCS; + test_nested_state_expect_einval(vcpu, state); + + /* If EFER.SVME is clear, GIF must be set and guest mode is disallowed */ + vcpu_efer_disable_svm(vcpu); + + set_default_svm_state(state, state_sz); + state->flags =3D 0; + test_nested_state_expect_einval(vcpu, state); + + state->flags =3D KVM_STATE_NESTED_GUEST_MODE; + test_nested_state_expect_einval(vcpu, state); + + state->flags =3D KVM_STATE_NESTED_GIF_SET; + test_nested_state(vcpu, state); + + /* Enable SVM in the guest EFER. */ + vcpu_efer_enable_svm(vcpu); + + /* Setting vmcb_pa to a non-aligned address is only fine when not enterin= g guest mode */ + set_default_svm_state(state, state_sz); + state->hdr.svm.vmcb_pa =3D -1ull; + state->flags =3D 0; + test_nested_state(vcpu, state); + state->flags =3D KVM_STATE_NESTED_GUEST_MODE; + test_nested_state_expect_einval(vcpu, state); + + /* + * Size must be large enough to fit kvm_nested_state and VMCB + * only when entering guest mode. + */ + set_default_svm_state(state, state_sz/2); + state->flags =3D 0; + test_nested_state(vcpu, state); + state->flags =3D KVM_STATE_NESTED_GUEST_MODE; + test_nested_state_expect_einval(vcpu, state); + + /* + * Test that if we leave nesting the state reflects that when we get it + * again, except for vmcb_pa, which is always returned as 0 when not in + * guest mode. + */ + set_default_svm_state(state, state_sz); + state->hdr.svm.vmcb_pa =3D -1ull; + state->flags =3D KVM_STATE_NESTED_GIF_SET; + test_nested_state(vcpu, state); + vcpu_nested_state_get(vcpu, state); + TEST_ASSERT(state->size >=3D sizeof(*state) && state->size <=3D state_sz, + "Size must be between %ld and %d. The size returned was %d.", + sizeof(*state), state_sz, state->size); + TEST_ASSERT(state->hdr.svm.vmcb_pa =3D=3D 0, + "vmcb_pa must be 0, but was %llx", + state->hdr.svm.vmcb_pa); + TEST_ASSERT(state->flags =3D=3D KVM_STATE_NESTED_GIF_SET, + "Flags must be equal to 0x%hx, but was 0x%hx", + KVM_STATE_NESTED_GIF_SET, state->flags); + + free(state); +} + int main(int argc, char *argv[]) { struct kvm_vm *vm; @@ -261,20 +360,20 @@ int main(int argc, char *argv[]) =20 have_evmcs =3D kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS); =20 + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); =20 - /* - * AMD currently does not implement set_nested_state, so for now we - * just early out. - */ - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); - vm =3D vm_create_with_one_vcpu(&vcpu, NULL); =20 /* - * First run tests with VMX disabled to check error handling. + * First run tests with VMX/SVM disabled to check error handling. + * test_{vmx/svm}_nested_state() will re-enable as needed. */ - vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_VMX); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_VMX); + else + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_SVM); =20 /* Passing a NULL kvm_nested_state causes a EFAULT. */ test_nested_state_expect_efault(vcpu, NULL); @@ -303,7 +402,10 @@ int main(int argc, char *argv[]) state.flags =3D KVM_STATE_NESTED_RUN_PENDING; test_nested_state_expect_einval(vcpu, &state); =20 - test_vmx_nested_state(vcpu); + if (kvm_cpu_has(X86_FEATURE_VMX)) + test_vmx_nested_state(vcpu); + else + test_svm_nested_state(vcpu); =20 kvm_vm_free(vm); return 0; --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-171.mta1.migadu.com (out-171.mta1.migadu.com [95.215.58.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE5CA3074BE for ; Wed, 1 Oct 2025 14:58:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330727; cv=none; b=aRu9dvQPDRFRwvl1kmU0hPL6FkeYthEBbzwsKe2Pp1tA8VAUGld9pKFSNn+EtOf3qL2E4T0pE8gami4F3uI8Zstk5904koF6CoAqcGDShKRoLVw2QIE+neVVHaOyvncq6g4ryuBtgwxQqijwdvjzE5k+1vbxA5E0coyXWwJdoHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330727; c=relaxed/simple; bh=CGMcfC36OTSYbmPfj/jQC5cJfDOp207Bq+fccU7iqDs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mZGjAfEMvs/U9PObpBkRt/yRdb49m505Ruur7SCcmrzWrV4AXZ8U4l4IyudCM1VJmFgrQG/OIu2xcq9kOM5UHkOLsYyx0dd26Ov/AUJxdYFaM/ZbhSWB9rzfMjybxY89sD9avvoZoovxiQrNr/MTjfJJ/XEPTFZguVFN9CY57hE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=f7wrumUP; arc=none smtp.client-ip=95.215.58.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="f7wrumUP" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330723; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+F6Vu+KTu5FASHI0ttB5Ihjm76gIpztWw/dzq8NRVEU=; b=f7wrumUPg9nvXSMDQ2+4Wkl4kF5vSloyYZASiA+1Lw9/93D2yy+4iS63tWyUBBxHL8O6CU w+OmWtk/qOwJsBWASkIlJv14l6o2Jc2siZE1tgZFO9OazzGERzlGzfnCQ+mDp/Uop8DQaP hzhn8mZ7R3LivcBqRmhYcsLlv+tLXvA= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 03/12] KVM: selftests: Extend vmx_close_while_nested_test to cover SVM Date: Wed, 1 Oct 2025 14:58:07 +0000 Message-ID: <20251001145816.1414855-4-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add SVM L1 code to run the nested guest, and allow the test to run with SVM as well as VMX. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- ...ested_test.c =3D> close_while_nested_test.c} | 42 +++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) rename tools/testing/selftests/kvm/x86/{vmx_close_while_nested_test.c =3D>= close_while_nested_test.c} (64%) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 6582396518b19..61c6abdc9b36f 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -111,7 +111,7 @@ TEST_GEN_PROGS_x86 +=3D x86/ucna_injection_test TEST_GEN_PROGS_x86 +=3D x86/userspace_io_test TEST_GEN_PROGS_x86 +=3D x86/userspace_msr_exit_test TEST_GEN_PROGS_x86 +=3D x86/vmx_apic_access_test -TEST_GEN_PROGS_x86 +=3D x86/vmx_close_while_nested_test +TEST_GEN_PROGS_x86 +=3D x86/close_while_nested_test TEST_GEN_PROGS_x86 +=3D x86/vmx_dirty_log_test TEST_GEN_PROGS_x86 +=3D x86/vmx_exception_with_invalid_guest_state TEST_GEN_PROGS_x86 +=3D x86/vmx_msrs_test diff --git a/tools/testing/selftests/kvm/x86/vmx_close_while_nested_test.c = b/tools/testing/selftests/kvm/x86/close_while_nested_test.c similarity index 64% rename from tools/testing/selftests/kvm/x86/vmx_close_while_nested_test.c rename to tools/testing/selftests/kvm/x86/close_while_nested_test.c index dad988351493e..cf5f24c83c448 100644 --- a/tools/testing/selftests/kvm/x86/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86/close_while_nested_test.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_close_while_nested + * close_while_nested_test * * Copyright (C) 2019, Red Hat, Inc. * @@ -12,6 +12,7 @@ #include "kvm_util.h" #include "processor.h" #include "vmx.h" +#include "svm_util.h" =20 #include #include @@ -22,6 +23,8 @@ enum { PORT_L0_EXIT =3D 0x2000, }; =20 +#define L2_GUEST_STACK_SIZE 64 + static void l2_guest_code(void) { /* Exit to L0 */ @@ -29,9 +32,8 @@ static void l2_guest_code(void) : : [port] "d" (PORT_L0_EXIT) : "rax"); } =20 -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_vmx_code(struct vmx_pages *vmx_pages) { -#define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; =20 GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); @@ -45,19 +47,43 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(0); } =20 +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + /* Prepare the VMCB for L2 execution. */ + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(0); +} + +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + int main(int argc, char *argv[]) { - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t guest_gva; struct kvm_vcpu *vcpu; struct kvm_vm *vm; =20 - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); =20 vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); =20 - /* Allocate VMX pages and shared descriptors (vmx_pages). */ - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &guest_gva); + else + vcpu_alloc_svm(vm, &guest_gva); + + vcpu_args_set(vcpu, 1, guest_gva); =20 for (;;) { volatile struct kvm_run *run =3D vcpu->run; --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-181.mta1.migadu.com (out-181.mta1.migadu.com [95.215.58.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93DAC3081D0; Wed, 1 Oct 2025 14:58:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330729; cv=none; b=VeDj1MAX+O6jMqlyLVVIT9o4SFGjy+bkK3ELe6LS3npeEBWyvPtKsD55Q5AfcCRWYJwv4FXYMRR4lk6Do+tM90yNeuSfCINm8Bgw//ce9OPbwJ+uqBRxnr5KL2KxwKSDlrns2T5RRj/mhEetlsNPn/hGDaBgyn50FtHMhS4ZLms= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330729; c=relaxed/simple; bh=0ny01fyobqxjAnm6uXFZVM72aMuxfZRp2EZ46DIuNH0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AJTk6ieCpLqHxPLpkkGbswYHqP2m1175o8oe7U/Q7c6Rg280ULozpUIUDqYvHKKE+XG+fEay92FARcaC2oUBLvkNoz5tS2UvGLSSQ2hEKAaw0fnW2/GURfnzfdFBNU9/0BvyjQEupf3Ue8U5YfJ+bXAydo8eXnx/quZ4+pwETiw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=MIgiL3fY; arc=none smtp.client-ip=95.215.58.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="MIgiL3fY" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330724; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+QjjmE9vEaeLSoBGTp7DarXM/3YAC80aS5KCWqMf5Rw=; b=MIgiL3fYTukTvgNwWXxkfXQ+63vOzsEUKTpAAdLse1HFrq84npcaUGtV4pt5sp/AlBkjAm 0LfXg4ObNjj/TnXgMyvmJQUcAErAdAZN27bm9NVsP9tI8A3Ki/3r7KK902/iQNABO4EmCg PWkqz5ZUqxfQ8iTXmeJpp3rCzdGMDr8= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 04/12] KVM: selftests: Extend vmx_nested_tsc_scaling_test to cover SVM Date: Wed, 1 Oct 2025 14:58:08 +0000 Message-ID: <20251001145816.1414855-5-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add SVM L1 code to run the nested guest, and allow the test to run with SVM as well as VMX. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- ...aling_test.c =3D> nested_tsc_scaling_test.c} | 48 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) rename tools/testing/selftests/kvm/x86/{vmx_nested_tsc_scaling_test.c =3D>= nested_tsc_scaling_test.c} (83%) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 61c6abdc9b36f..dc68147ace97f 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -118,7 +118,7 @@ TEST_GEN_PROGS_x86 +=3D x86/vmx_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_invalid_nested_guest_state TEST_GEN_PROGS_x86 +=3D x86/set_nested_state_test TEST_GEN_PROGS_x86 +=3D x86/vmx_tsc_adjust_test -TEST_GEN_PROGS_x86 +=3D x86/vmx_nested_tsc_scaling_test +TEST_GEN_PROGS_x86 +=3D x86/nested_tsc_scaling_test TEST_GEN_PROGS_x86 +=3D x86/apic_bus_clock_test TEST_GEN_PROGS_x86 +=3D x86/xapic_ipi_test TEST_GEN_PROGS_x86 +=3D x86/xapic_state_test diff --git a/tools/testing/selftests/kvm/x86/vmx_nested_tsc_scaling_test.c = b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c similarity index 83% rename from tools/testing/selftests/kvm/x86/vmx_nested_tsc_scaling_test.c rename to tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c index 1759fa5cb3f29..56ab91544775f 100644 --- a/tools/testing/selftests/kvm/x86/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c @@ -13,6 +13,7 @@ =20 #include "kvm_util.h" #include "vmx.h" +#include "svm_util.h" #include "kselftest.h" =20 /* L2 is scaled up (from L1's perspective) by this factor */ @@ -79,7 +80,30 @@ static void l2_guest_code(void) __asm__ __volatile__("vmcall"); } =20 -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + /* check that L1's frequency looks alright before launching L2 */ + check_tsc_freq(UCHECK_L1); + + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* enable TSC scaling for L2 */ + wrmsr(MSR_AMD64_TSC_RATIO, (L2_SCALE_FACTOR << 32) | 1); + + /* launch L2 */ + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code =3D=3D SVM_EXIT_VMMCALL); + + /* check that L1's frequency still looks good */ + check_tsc_freq(UCHECK_L1); + + GUEST_DONE(); +} + +static void l1_vmx_code(struct vmx_pages *vmx_pages) { unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; uint32_t control; @@ -116,11 +140,19 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_DONE(); } =20 +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t guest_gva =3D 0; =20 uint64_t tsc_start, tsc_end; uint64_t tsc_khz; @@ -129,7 +161,8 @@ int main(int argc, char *argv[]) uint64_t l1_tsc_freq =3D 0; uint64_t l2_tsc_freq =3D 0; =20 - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); =20 @@ -152,8 +185,13 @@ int main(int argc, char *argv[]) printf("real TSC frequency is around: %"PRIu64"\n", l0_tsc_freq); =20 vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &guest_gva); + else + vcpu_alloc_svm(vm, &guest_gva); + + vcpu_args_set(vcpu, 1, guest_gva); =20 tsc_khz =3D __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); TEST_ASSERT(tsc_khz !=3D -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D18C3093B2 for ; Wed, 1 Oct 2025 14:58:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330731; cv=none; b=utvTR9YN5T3fGcnu7T3sg+3uyXlxmY2iNwgx2PQfitwjS9b7/n9wvSykFVYv5Fmhsr4HTIAMm3LfzGL6IL5Kc164OOjzvG//TYgGezGjZILtjgaHzYpPI+nb1b/4RGr/bMy6E1YvFinUg7UnoKVmlQUQQa0D4pu9UkFkqwoMbwI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330731; c=relaxed/simple; bh=6SGHwTCW76SAXH2tSGEBWFouR6y2PQD5qeTAYrlPQ58=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tYIFrXqkdI3Pt43QM4KL7HPck0lPgLQEGyGWAZhDUkKzmp7fgQSlpbgAsrtVwyA0VKvy+EuffQfncfpXFXKujpXSn9BKWoiAY0BP1NGYlfWazcbwe/t6HQeGmyI3KhnubnYfXAuil0O7201jA60ah8KG4lbpYCUwfyy8BKIwArM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=PxYdpL8H; arc=none smtp.client-ip=95.215.58.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="PxYdpL8H" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330727; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FhGl9Un/NM4vpn3T/c8IJ7g/Ysq6DiXQ9SLpXMtc+aI=; b=PxYdpL8Hwwq+VUp+nIpiOmktruiQuvbM5oIi2D8W8vSFgso+QFCfDFJkeay+wxDNZRROz1 W9dmeQa7iWqNKbvRrTGy+BgQgNIOsTett4r4qvoFqzrmIbpXUmRNqd73WzsyNkBVnB6F3u Jvg0lMbEotnxglC/qfJ2GOPrNbb0DFw= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 05/12] KVM: selftests: Remove invalid CR3 test from vmx_tsc_adjust_test Date: Wed, 1 Oct 2025 14:58:09 +0000 Message-ID: <20251001145816.1414855-6-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Checking that VMLAUNCH fails with an invalid CR3 is irrelevant to this test. Remove it to simplify the test a little bit before generalizing it to cover SVM. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c b/tools/= testing/selftests/kvm/x86/vmx_tsc_adjust_test.c index 2ceb5c78c4427..2dcc0306a0d9b 100644 --- a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c @@ -77,7 +77,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) #define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; uint32_t control; - uintptr_t save_cr3; =20 GUEST_ASSERT(rdtsc() < TSC_ADJUST_VALUE); wrmsr(MSR_IA32_TSC, rdtsc() - TSC_ADJUST_VALUE); @@ -94,15 +93,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); =20 - /* Jump into L2. First, test failure to load guest CR3. */ - save_cr3 =3D vmreadz(GUEST_CR3); - vmwrite(GUEST_CR3, -1ull); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D - (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE)); - check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); - vmwrite(GUEST_CR3, save_cr3); - GUEST_ASSERT(!vmlaunch()); GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); =20 --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CAF6D309F0A; Wed, 1 Oct 2025 14:58:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330734; cv=none; b=ShCwJ93cQPKEh3nPuZjC/Uy2cYh8gKnFlGo+k1isw1YseJbVIZLG+On2UmBsauWZlDqJSM4r54ZwgpNA87pk5bP8SkQZ+uqd+ta9CkB/Iq5TVPPEIkbS6oxVPOzntqLzDIZiKXAqZ5kJ4ZWaWIIwD8/srAJkCbzpkxWRDLIj+Go= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330734; c=relaxed/simple; bh=+mvnZ/3nh84CfbeisOMB+kyaEVFHU84gm6MRFvEyixg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dARasVOT+6KW0+C/hoTtA14enolYC9Xm0XJY8PlfzmFzPyBmx3wZWsjSoPKMCg89nSjZFjhkZVCivsEc33RQvoe+Va6jyH1ngx88xnKShpZRlvvFcdM1HD1KxpRWDUgzCru/bld/NvC+VDc8wV0LYphM86dTijjCvZcGsaoiJng= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=LjNztcnF; arc=none smtp.client-ip=95.215.58.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="LjNztcnF" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330730; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HleGFx1sF8yP1tUynV7GpVNP3oSoHkyyTlg/BPojzJs=; b=LjNztcnFjhqcUtr6P6IMbuAIgDKVTkgbBD2cgephPfLsBChzrZg/xS5f7aqFjALl+Y8oNV aWgMJHt9gks9ThWMcYi0WDgFIQ9p+62XRJe1SJX4PoZH1XXhLUkvwpO3pRsiSSRtg3j7YA R5xJ5e69FkOUqJzK7FPaFrs3Evh659Y= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 06/12] KVM: selftests: Extend vmx_tsc_adjust_test to cover SVM Date: Wed, 1 Oct 2025 14:58:10 +0000 Message-ID: <20251001145816.1414855-7-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add SVM L1 code to run the nested guest, and allow the test to run with SVM as well as VMX. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- ...adjust_test.c =3D> nested_tsc_adjust_test.c} | 69 ++++++++++++------- 2 files changed, 46 insertions(+), 25 deletions(-) rename tools/testing/selftests/kvm/x86/{vmx_tsc_adjust_test.c =3D> nested_= tsc_adjust_test.c} (61%) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index dc68147ace97f..9b3c99acd51a3 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -117,7 +117,7 @@ TEST_GEN_PROGS_x86 +=3D x86/vmx_exception_with_invalid_= guest_state TEST_GEN_PROGS_x86 +=3D x86/vmx_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_invalid_nested_guest_state TEST_GEN_PROGS_x86 +=3D x86/set_nested_state_test -TEST_GEN_PROGS_x86 +=3D x86/vmx_tsc_adjust_test +TEST_GEN_PROGS_x86 +=3D x86/nested_tsc_adjust_test TEST_GEN_PROGS_x86 +=3D x86/nested_tsc_scaling_test TEST_GEN_PROGS_x86 +=3D x86/apic_bus_clock_test TEST_GEN_PROGS_x86 +=3D x86/xapic_ipi_test diff --git a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c b/tools/= testing/selftests/kvm/x86/nested_tsc_adjust_test.c similarity index 61% rename from tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c rename to tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c index 2dcc0306a0d9b..cc825a0b41dbf 100644 --- a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_tsc_adjust_test + * nested_tsc_adjust_test * * Copyright (C) 2018, Google LLC. * @@ -22,6 +22,7 @@ #include "kvm_util.h" #include "processor.h" #include "vmx.h" +#include "svm_util.h" =20 #include #include @@ -35,6 +36,8 @@ #define TSC_ADJUST_VALUE (1ll << 32) #define TSC_OFFSET_VALUE -(1ll << 48) =20 +#define L2_GUEST_STACK_SIZE 64 + enum { PORT_ABORT =3D 0x1000, PORT_REPORT, @@ -72,32 +75,47 @@ static void l2_guest_code(void) __asm__ __volatile__("vmcall"); } =20 -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_guest_code(void *data) { -#define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; - uint32_t control; =20 + /* Set TSC from L1 and make sure TSC_ADJUST is updated correctly */ GUEST_ASSERT(rdtsc() < TSC_ADJUST_VALUE); wrmsr(MSR_IA32_TSC, rdtsc() - TSC_ADJUST_VALUE); check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); =20 - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); - - /* Prepare the VMCS for L2 execution. */ - prepare_vmcs(vmx_pages, l2_guest_code, - &l2_guest_stack[L2_GUEST_STACK_SIZE]); - control =3D vmreadz(CPU_BASED_VM_EXEC_CONTROL); - control |=3D CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; - vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); - - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); + /* + * Run L2 with TSC_OFFSET. L2 will write to TSC, and L1 is not + * intercepting the write so it should update L1's TSC_ADJUST. + */ + if (this_cpu_has(X86_FEATURE_VMX)) { + struct vmx_pages *vmx_pages =3D data; + uint32_t control; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + control =3D vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control |=3D CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; + vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); + vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); + + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); + } else { + struct svm_test_data *svm =3D data; + + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + svm->vmcb->control.tsc_offset =3D TSC_OFFSET_VALUE; + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code =3D=3D SVM_EXIT_VMMCALL); + } =20 check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); - GUEST_DONE(); } =20 @@ -109,16 +127,19 @@ static void report(int64_t val) =20 int main(int argc, char *argv[]) { - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t nested_gva; struct kvm_vcpu *vcpu; =20 - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); =20 - vm =3D vm_create_with_one_vcpu(&vcpu, (void *) l1_guest_code); + vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &nested_gva); + else + vcpu_alloc_svm(vm, &nested_gva); =20 - /* Allocate VMX pages and shared descriptors (vmx_pages). */ - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, nested_gva); =20 for (;;) { struct ucall uc; --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-172.mta1.migadu.com (out-172.mta1.migadu.com [95.215.58.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A6EE30AD19 for ; Wed, 1 Oct 2025 14:58:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330735; cv=none; b=qkb8hhmkLVajktOdJRjZbg9i8tT3uhnUKpqesHkOcRHJtObjvGtQY8tzPKSq2MLY9uUQWB1E1eCs8bcgoV4L783CTSm20i+qjL6CHgz7S/oXOjl/IAGqtDrWy3asnxd7QvV6r1Liv9o4BeiHyUgPVQ6XBpEEwCq6P0ouXDf6lQE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330735; c=relaxed/simple; bh=PoyR2ZY6GSsug/ZnMOiuT6hdgnY+8NNEflpyqeTNBAU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pFjDS/v8shoPT0k7SrY4/VeM6VYYTGuuJtzuvSiKJaoGFbAhd2Cc4q4jYh9M9Qt3C8l3QDSdQYN/ZLLQreYOwxCoWFNJ7elz9fppmIMuwS/XZxAns4L6uNc+XCtLLDthnUZVtnhrlbs44ENI3WIgcrGXrYVpv0agYQNLp9QqqLc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=bYrSxoPg; arc=none smtp.client-ip=95.215.58.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="bYrSxoPg" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330731; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pkZED150T2wLLTSKFE9dwj5Dxedh3WTVdUnAFT4nOkU=; b=bYrSxoPgzfbwEagdRuvobCtdcC1XKJsrbpkiwvuC6PxPWwggFlsPPv5OAja42NxFQ84F/H 6VZ29bjw4WErwfVA4+3GqVTF4mMNyRTGKx6KA65rVRMJvF27BiUHI/QZDy3M7dM8ByvMna jongPK6gHcXP9c1f2+bLsOCOdnXuJ9Y= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 07/12] KVM: selftests: Pass the root HVA directly to nested mapping functions Date: Wed, 1 Oct 2025 14:58:11 +0000 Message-ID: <20251001145816.1414855-8-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed The nested mapping functions used to create EPT mappings currently accept a struct vmx_pages argument, only to get the EPT root from it later. In preparation for generalizing these functions to work for NPTs, pass the EPT root HVA directly instead. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/include/x86/vmx.h | 8 +++---- .../testing/selftests/kvm/lib/x86/memstress.c | 4 ++-- tools/testing/selftests/kvm/lib/x86/vmx.c | 24 +++++++++---------- .../selftests/kvm/x86/vmx_dirty_log_test.c | 6 ++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/= selftests/kvm/include/x86/vmx.h index edb3c391b9824..06ae68cf9635c 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -559,13 +559,13 @@ bool load_vmcs(struct vmx_pages *vmx); =20 bool ept_1g_pages_supported(void); =20 -void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_pg_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr); -void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size); -void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_map_memslot(void *root_hva, struct kvm_vm *vm, uint32_t memslot); -void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, uint64_t addr, uint64_t size); bool kvm_cpu_has_ept(void); void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm, diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testin= g/selftests/kvm/lib/x86/memstress.c index 7f5d62a65c68a..7981e295cac70 100644 --- a/tools/testing/selftests/kvm/lib/x86/memstress.c +++ b/tools/testing/selftests/kvm/lib/x86/memstress.c @@ -70,11 +70,11 @@ void memstress_setup_ept(struct vmx_pages *vmx, struct = kvm_vm *vm) * KVM can shadow the EPT12 with the maximum huge page size supported * by the backing source. */ - nested_identity_map_1g(vmx, vm, 0, 0x100000000ULL); + nested_identity_map_1g(vmx->eptp_hva, vm, 0, 0x100000000ULL); =20 start =3D align_down(memstress_args.gpa, PG_SIZE_1G); end =3D align_up(memstress_args.gpa + memstress_args.size, PG_SIZE_1G); - nested_identity_map_1g(vmx, vm, start, end - start); + nested_identity_map_1g(vmx->eptp_hva, vm, start, end - start); } =20 void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vc= pu *vcpus[]) diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index d4d1208dd0238..04c4b97bcd1e7 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -394,11 +394,11 @@ static void nested_create_pte(struct kvm_vm *vm, } =20 =20 -void __nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void __nested_pg_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, int target_level) { const uint64_t page_size =3D PG_LEVEL_SIZE(target_level); - struct eptPageTableEntry *pt =3D vmx->eptp_hva, *pte; + struct eptPageTableEntry *pt =3D root_hva, *pte; uint16_t index; =20 TEST_ASSERT(vm->mode =3D=3D VM_MODE_PXXV48_4K, "Attempt to use " @@ -445,10 +445,10 @@ void __nested_pg_map(struct vmx_pages *vmx, struct kv= m_vm *vm, =20 } =20 -void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_pg_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr) { - __nested_pg_map(vmx, vm, nested_paddr, paddr, PG_LEVEL_4K); + __nested_pg_map(root_hva, vm, nested_paddr, paddr, PG_LEVEL_4K); } =20 /* @@ -468,7 +468,7 @@ void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm= *vm, * Within the VM given by vm, creates a nested guest translation for the * page range starting at nested_paddr to the page range starting at paddr. */ -void __nested_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void __nested_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size, int level) { @@ -479,22 +479,22 @@ void __nested_map(struct vmx_pages *vmx, struct kvm_v= m *vm, TEST_ASSERT(paddr + size > paddr, "Paddr overflow"); =20 while (npages--) { - __nested_pg_map(vmx, vm, nested_paddr, paddr, level); + __nested_pg_map(root_hva, vm, nested_paddr, paddr, level); nested_paddr +=3D page_size; paddr +=3D page_size; } } =20 -void nested_map(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, uint64_t size) { - __nested_map(vmx, vm, nested_paddr, paddr, size, PG_LEVEL_4K); + __nested_map(root_hva, vm, nested_paddr, paddr, size, PG_LEVEL_4K); } =20 /* Prepare an identity extended page table that maps all the * physical pages in VM. */ -void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_map_memslot(void *root_hva, struct kvm_vm *vm, uint32_t memslot) { sparsebit_idx_t i, last; @@ -508,7 +508,7 @@ void nested_map_memslot(struct vmx_pages *vmx, struct k= vm_vm *vm, if (i > last) break; =20 - nested_map(vmx, vm, + nested_map(root_hva, vm, (uint64_t)i << vm->page_shift, (uint64_t)i << vm->page_shift, 1 << vm->page_shift); @@ -516,10 +516,10 @@ void nested_map_memslot(struct vmx_pages *vmx, struct= kvm_vm *vm, } =20 /* Identity map a region with 1GiB Pages. */ -void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm, +void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, uint64_t addr, uint64_t size) { - __nested_map(vmx, vm, addr, addr, size, PG_LEVEL_1G); + __nested_map(root_hva, vm, addr, addr, size, PG_LEVEL_1G); } =20 bool kvm_cpu_has_ept(void) diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/t= esting/selftests/kvm/x86/vmx_dirty_log_test.c index fa512d033205f..21a57805e9780 100644 --- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c @@ -121,9 +121,9 @@ static void test_vmx_dirty_log(bool enable_ept) */ if (enable_ept) { prepare_eptp(vmx, vm, 0); - nested_map_memslot(vmx, vm, 0); - nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096); - nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096); + nested_map_memslot(vmx->eptp_hva, vm, 0); + nested_map(vmx->eptp_hva, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096); + nested_map(vmx->eptp_hva, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096); } =20 bmap =3D bitmap_zalloc(TEST_MEM_PAGES); --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-179.mta1.migadu.com (out-179.mta1.migadu.com [95.215.58.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C05AF30BBBC for ; Wed, 1 Oct 2025 14:58:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330736; cv=none; b=OO1x3sXJFMqpVqKrjVIY6IzeGhGM9x64r1jndy1wjVOX4PqtIa8dCJY5QN9Jy8nnjKNyV+pkf3E1YFZrJAKozEP/mx/jN30GgtJbgcrOlXht6VVvwXN+nIDQmIixKqw2kgZzokRZur5o6Y2j7ipo8BEsOdV9YhHnDLCLCz2algE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330736; c=relaxed/simple; bh=mbOhnxuG8ulswfPMlF0N9ZTEVLzFWKgBEB2IUkzLVlg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uuFQcJtUSq3tmf4M9FOcNv/ZBMtBNGCJ+EGH7ZJEPEqKOVA7LEkSLWk2/JhF8O27b/8X/msyWq53A/4bLxVT0EjPA1Mz1gKnEjOdzKkKu2kPvbe6flRLfa0GYZ3bYNZHfang8HcMS5phg0X5FXz7rh0YHxuy5QQpkzW5JDK4wdM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=l4eiNaMK; arc=none smtp.client-ip=95.215.58.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="l4eiNaMK" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330733; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cNK27Cs7fKo0r1Ea9VAB8EPPFw2zlK9HqEAKfMAfOo0=; b=l4eiNaMK6iUmhJHj7eLOZwGAtlj1AC4SL0RZ6zu/t2ZAjdfz03JSgGho/xxOZaOQ1j8ccz OcXSNQOIylmqKqmEHOahH/w2QUyUt8gPcckuuyavqaqnRYf7wpp5/nDwGq376Jv+G3Fou4 ZP1lTqm4uGBMJCfZYeY3b300Z4zM5JI= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 08/12] KVM: selftests: Use 'leaf' instead of hugepage to describe EPT entries Date: Wed, 1 Oct 2025 14:58:12 +0000 Message-ID: <20251001145816.1414855-9-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed The assertions use 'hugepage' to describe a terminal EPT entry, but 'leaf' is more accruate as a PG_LEVEL_4K EPT entry is a leaf but not a hugepage. The distincion will be useful in coming changes that will pass the value around and 'leaf' is clearer than hugepage or page_size. Leave the EPT bit named page_size to keep it conforming to the manual. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/lib/x86/vmx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index 04c4b97bcd1e7..673756b27e903 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -380,15 +380,15 @@ static void nested_create_pte(struct kvm_vm *vm, pte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; } else { /* - * Entry already present. Assert that the caller doesn't want - * a hugepage at this level, and that there isn't a hugepage at - * this level. + * Entry already present. Assert that the caller doesn't want a + * leaf entry at this level, and that there isn't a leaf entry + * at this level. */ TEST_ASSERT(current_level !=3D target_level, - "Cannot create hugepage at level: %u, nested_paddr: 0x%lx", + "Cannot create leaf entry at level: %u, nested_paddr: 0x%lx", current_level, nested_paddr); TEST_ASSERT(!pte->page_size, - "Cannot create page table at level: %u, nested_paddr: 0x%lx", + "Leaf entry already exists at level: %u, nested_paddr: 0x%lx", current_level, nested_paddr); } } --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-170.mta1.migadu.com (out-170.mta1.migadu.com [95.215.58.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3FF6A30CB34 for ; Wed, 1 Oct 2025 14:58:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330739; cv=none; b=sigoTYnJ9SMqfMg2Y3vHgBlTYlqVXJBkW/Uqo3FM+LB9ijXK7W+Iw+odRg+ljdRqlMauuVn2HvvAB4BB1tnwXthWtfhhoGDpe7h9k63i2Px2v3ZpFnmdB4MQ1eijR3UUDDlxCYUIGCiJry0D7Je36Vv4BHywzk5hv1GcoZg9N6g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330739; c=relaxed/simple; bh=ZTJmiiqWLF+y1Q/GfcH8oyakTOF9fQGNWmPwrUbydkc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZNVX7AT9Ee91gERjgTgDSqNSfKxN/aBnuEOkW8mIL6AV+hLpQ6K8abwzuwkEO4pD/deK7+hj4QsEiTg8CqFKoCmpdQBMBDQRN1JrhGoiC6wZsFwQn9jbAwP/jH12UiIHY92nrAMQDFRos4aDvpDELSyq3yRlFqSigKIj6JbhhzI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=jiLgnmFd; arc=none smtp.client-ip=95.215.58.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="jiLgnmFd" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330735; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=snKvlr6OPxDH7X56qF+PKa57E0gslaeWbzsu8swX4+Q=; b=jiLgnmFdkLDz60zGIOOG64drX8YhhbA/c56BH4vZJD21NIou0HIapJjv/42xDbby7yQO+j qyxHj8jaZcz3pNzpTCcOSRmRwPCDKCjUs4Zcd9J0pzaAHQnRPcZv07nLcv3wsCrzZkvVM4 U4O+hCdoSr5zg26+wtoAImaEEfCaxzQ= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 09/12] KVM: selftests: Move all PTE accesses into nested_create_pte() Date: Wed, 1 Oct 2025 14:58:13 +0000 Message-ID: <20251001145816.1414855-10-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed In preparation for making the nested mapping functions work for NPT, move all logic that directly accesses the PTE into nested_create_pte(), as these accesses will be different for SVM. Stop using struct eptPageTableEntry in the caller, instead pass a uint64_t pointer (and add an assertion on the size to make sure it stays correct). Calculate whether or not an EPT entry is a leaf in __nested_pg_map(), and return the address from nested_create_pte() to __nested_pg_map(). Also, set the access and dirty bits in nested_create_pte() for leaf entries. This matches the current behavior and removes all direct accesses to the EPT entry from __nested_pg_map(). Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/lib/x86/vmx.c | 69 +++++++++++++---------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index 673756b27e903..b0e6267eac806 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -33,6 +33,7 @@ struct eptPageTableEntry { uint64_t ignored_62_52:11; uint64_t suppress_ve:1; }; +kvm_static_assert(sizeof(struct eptPageTableEntry) =3D=3D sizeof(uint64_t)= ); =20 struct eptPageTablePointer { uint64_t memory_type:3; @@ -42,6 +43,8 @@ struct eptPageTablePointer { uint64_t address:40; uint64_t reserved_63_52:12; }; +kvm_static_assert(sizeof(struct eptPageTablePointer) =3D=3D sizeof(uint64_= t)); + int vcpu_enable_evmcs(struct kvm_vcpu *vcpu) { uint16_t evmcs_ver; @@ -362,35 +365,46 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_= rip, void *guest_rsp) init_vmcs_guest_state(guest_rip, guest_rsp); } =20 -static void nested_create_pte(struct kvm_vm *vm, - struct eptPageTableEntry *pte, - uint64_t nested_paddr, - uint64_t paddr, - int current_level, - int target_level) +static uint64_t nested_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t nested_paddr, + uint64_t paddr, + int level, + bool leaf) { - if (!pte->readable) { - pte->writable =3D true; - pte->readable =3D true; - pte->executable =3D true; - pte->page_size =3D (current_level =3D=3D target_level); - if (pte->page_size) - pte->address =3D paddr >> vm->page_shift; + struct eptPageTableEntry *epte =3D (struct eptPageTableEntry *)pte; + + if (!epte->readable) { + epte->writable =3D true; + epte->readable =3D true; + epte->executable =3D true; + epte->page_size =3D leaf; + + if (leaf) + epte->address =3D paddr >> vm->page_shift; else - pte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; + epte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; + + /* + * For now mark these as accessed and dirty because the only + * testcase we have needs that. Can be reconsidered later. + */ + epte->accessed =3D leaf; + epte->dirty =3D leaf; } else { /* * Entry already present. Assert that the caller doesn't want a * leaf entry at this level, and that there isn't a leaf entry * at this level. */ - TEST_ASSERT(current_level !=3D target_level, + TEST_ASSERT(!leaf, "Cannot create leaf entry at level: %u, nested_paddr: 0x%lx", - current_level, nested_paddr); - TEST_ASSERT(!pte->page_size, + level, nested_paddr); + TEST_ASSERT(!epte->page_size, "Leaf entry already exists at level: %u, nested_paddr: 0x%lx", - current_level, nested_paddr); + level, nested_paddr); } + return epte->address; } =20 =20 @@ -398,8 +412,9 @@ void __nested_pg_map(void *root_hva, struct kvm_vm *vm, uint64_t nested_paddr, uint64_t paddr, int target_level) { const uint64_t page_size =3D PG_LEVEL_SIZE(target_level); - struct eptPageTableEntry *pt =3D root_hva, *pte; - uint16_t index; + uint64_t *pt =3D root_hva, *pte; + uint16_t index, address; + bool leaf; =20 TEST_ASSERT(vm->mode =3D=3D VM_MODE_PXXV48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); @@ -427,22 +442,16 @@ void __nested_pg_map(void *root_hva, struct kvm_vm *v= m, for (int level =3D PG_LEVEL_512G; level >=3D PG_LEVEL_4K; level--) { index =3D (nested_paddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu; pte =3D &pt[index]; + leaf =3D (level =3D=3D target_level); =20 - nested_create_pte(vm, pte, nested_paddr, paddr, level, target_level); + address =3D nested_create_pte(vm, pte, nested_paddr, paddr, level, leaf); =20 - if (pte->page_size) + if (leaf) break; =20 - pt =3D addr_gpa2hva(vm, pte->address * vm->page_size); + pt =3D addr_gpa2hva(vm, address * vm->page_size); } =20 - /* - * For now mark these as accessed and dirty because the only - * testcase we have needs that. Can be reconsidered later. - */ - pte->accessed =3D true; - pte->dirty =3D true; - } =20 void nested_pg_map(void *root_hva, struct kvm_vm *vm, --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-171.mta1.migadu.com (out-171.mta1.migadu.com [95.215.58.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4FE2C30DD3D for ; Wed, 1 Oct 2025 14:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330742; cv=none; b=VFIl4c8xxo04i7ujrbBR0EO7dUKSQMUCT2h7IJouUlkIj1bUQ0rzfXB5d/S97D4FvkWZjBfNaXPMPMPJqeBKTsY5QpESwDmUFi+Hnti78AE/7oqljkoqpKTmZJX4EKUz+NsvywXcK3VSGKs+bCPiidYatJd0gSSIZ667NdJc8tQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330742; c=relaxed/simple; bh=ThlnxXJnBzPguOtYLCHF06DSVYgTHIi41nnNBzqrW0I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R5DY1V2zCf5RH4KoHSZeGqFNbZ/Lfj0N2mQ9qrmr26bn8q2Cr09Bwf4GfDSXOBP55+jL095d03Re5pOHE0v27rs818+Zm/wfKtR45iTu4xzHEom54IZscMnjLSvMihiOBcw/sg9CKSP30E6bnUduuGRuBVwfSpCNGljZker/AEw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=BveAUWQG; arc=none smtp.client-ip=95.215.58.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="BveAUWQG" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330737; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TQv4BWEKXzFdMwpyunqs9lX/Regx9S1cRjNZtX+om4M=; b=BveAUWQG1NY93jMjPhQYH2Qlm28DnNa78EPzh2GnhhBD3yfioVR4wuXpb4fH8X0NQBkg1i t9wEHvYsubJWeVgZU+5TojhiB6QjpgjlovyCaMJxTgHVcEOss0zGEbRh/Q7DqFM7Opdbo8 D2UFRL/4l+3ub/tWY0I9uIUxHy/ACrc= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 10/12] KVM: selftests: Move EPT-specific init outside nested_create_pte() Date: Wed, 1 Oct 2025 14:58:14 +0000 Message-ID: <20251001145816.1414855-11-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Refactor the EPT specific initialization into nested_ept_create_pte(), in preparation for making nested_create_pte() NPT-friendly. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/lib/x86/vmx.c | 71 ++++++++++++++--------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index b0e6267eac806..eeacf42bf30b1 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -365,46 +365,61 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_= rip, void *guest_rsp) init_vmcs_guest_state(guest_rip, guest_rsp); } =20 +static bool nested_ept_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t paddr, + uint64_t *address, + bool *leaf) +{ + struct eptPageTableEntry *epte =3D (struct eptPageTableEntry *)pte; + + /* PTE already exists? */ + if (epte->readable) { + *leaf =3D epte->page_size; + *address =3D epte->address; + return false; + } + + epte->writable =3D true; + epte->readable =3D true; + epte->executable =3D true; + epte->page_size =3D *leaf; + + if (*leaf) + epte->address =3D paddr >> vm->page_shift; + else + epte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; + + *address =3D epte->address; + + /* + * For now mark these as accessed and dirty because the only + * testcase we have needs that. Can be reconsidered later. + */ + epte->accessed =3D *leaf; + epte->dirty =3D *leaf; + return true; +} + static uint64_t nested_create_pte(struct kvm_vm *vm, uint64_t *pte, uint64_t nested_paddr, uint64_t paddr, int level, - bool leaf) + bool want_leaf) { - struct eptPageTableEntry *epte =3D (struct eptPageTableEntry *)pte; - - if (!epte->readable) { - epte->writable =3D true; - epte->readable =3D true; - epte->executable =3D true; - epte->page_size =3D leaf; + bool leaf =3D want_leaf; + uint64_t address; =20 - if (leaf) - epte->address =3D paddr >> vm->page_shift; - else - epte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; - - /* - * For now mark these as accessed and dirty because the only - * testcase we have needs that. Can be reconsidered later. - */ - epte->accessed =3D leaf; - epte->dirty =3D leaf; - } else { - /* - * Entry already present. Assert that the caller doesn't want a - * leaf entry at this level, and that there isn't a leaf entry - * at this level. - */ - TEST_ASSERT(!leaf, + if (!nested_ept_create_pte(vm, pte, paddr, &address, &leaf)) { + TEST_ASSERT(!want_leaf, "Cannot create leaf entry at level: %u, nested_paddr: 0x%lx", level, nested_paddr); - TEST_ASSERT(!epte->page_size, + TEST_ASSERT(!leaf, "Leaf entry already exists at level: %u, nested_paddr: 0x%lx", level, nested_paddr); } - return epte->address; + return address; } =20 =20 --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-181.mta1.migadu.com (out-181.mta1.migadu.com [95.215.58.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E3A0930CB26 for ; Wed, 1 Oct 2025 14:59:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330744; cv=none; b=agYxicAntFgEco+dpAQ9FKhWyErelWENkIMm8f4sSQJmLeOWXpyJ7AnhxrsaC737xUUPVAV53CWzUj+nBaDKHw3n95Z/R3afXKT43Z5IWVoHAgu03LgnDwCtfrA3PwAoW+3jDYnmGBgQBWD8X1PDFbyqveeunhQK1mcaI1+/etM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330744; c=relaxed/simple; bh=cTQXGUYVVEI0C0zMAxK/fgTuCww5s7JNxb7uIbmmSuo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lkbc3P8nKHy6KeTjFygsOqOBDt1zB6cWkNt0oofUXzn0nX2bHYIReHSMd3blEydcDxQItfr+F/AuhO8IlyPXK4V6eanuE0UlW8BWymvR1srxfuRYVeR/LTZRwsVVoIoVlQwiTa8SmjmyUflz5a8K+TjflEObjR9rjDKYyErV4YE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=M74zuC+x; arc=none smtp.client-ip=95.215.58.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="M74zuC+x" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330739; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ibrGkq3SxosgUA5keIrPxQk0XJRBo1woRRNtpr/YYnE=; b=M74zuC+x1/Ccv0M9v1P9jcUvWiAbo/kSQvydEatpnYA3fUEHx7/LLd+oKL4dklO1ZflvJf zJDN2283ArjLom2L5qbKpgMKbGqcSvkOAVjvlxNIyPH+f/35F1iYo+1GLqUnvjmvdE3P5x XePzus2KAkxth1TP84N7MygvPFhUwcg= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 11/12] KVM: selftests: Refactor generic nested mapping outside VMX code Date: Wed, 1 Oct 2025 14:58:15 +0000 Message-ID: <20251001145816.1414855-12-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Now that the nested mapping functions in vmx.c are all generic except for nested_ept_create_pte(), move them all out into a new nested_map.c lib file and expose nested_ept_create_pte() in vmx.h. This allows reusing the code for NPT in following changes. While we're at it, merge nested_pg_map() and __nested_pg_map(), as the former is unused, and make sure all functions not exposed in the header are static. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/include/x86/nested_map.h | 20 +++ tools/testing/selftests/kvm/include/x86/vmx.h | 13 +- .../testing/selftests/kvm/lib/x86/memstress.c | 1 + .../selftests/kvm/lib/x86/nested_map.c | 150 +++++++++++++++++ tools/testing/selftests/kvm/lib/x86/vmx.c | 155 +----------------- .../selftests/kvm/x86/vmx_dirty_log_test.c | 1 + 7 files changed, 183 insertions(+), 158 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/x86/nested_map.h create mode 100644 tools/testing/selftests/kvm/lib/x86/nested_map.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 9b3c99acd51a3..9547d7263e236 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -23,6 +23,7 @@ LIBKVM_x86 +=3D lib/x86/apic.c LIBKVM_x86 +=3D lib/x86/handlers.S LIBKVM_x86 +=3D lib/x86/hyperv.c LIBKVM_x86 +=3D lib/x86/memstress.c +LIBKVM_x86 +=3D lib/x86/nested_map.c LIBKVM_x86 +=3D lib/x86/pmu.c LIBKVM_x86 +=3D lib/x86/processor.c LIBKVM_x86 +=3D lib/x86/sev.c diff --git a/tools/testing/selftests/kvm/include/x86/nested_map.h b/tools/t= esting/selftests/kvm/include/x86/nested_map.h new file mode 100644 index 0000000000000..362162dd6db43 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86/nested_map.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tools/testing/selftests/kvm/include/x86_64/nested_map.h + * + * Copyright (C) 2025, Google LLC. + */ + +#ifndef SELFTEST_KVM_NESTED_MAP_H +#define SELFTEST_KVM_NESTED_MAP_H + +#include "kvm_util.h" + +void nested_map(void *root_hva, struct kvm_vm *vm, + uint64_t nested_paddr, uint64_t paddr, uint64_t size); +void nested_map_memslot(void *root_hva, struct kvm_vm *vm, + uint32_t memslot); +void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, + uint64_t addr, uint64_t size); + +#endif /* SELFTEST_KVM_NESTED_MAP_H */ diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/= selftests/kvm/include/x86/vmx.h index 06ae68cf9635c..49d763144dbfe 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -559,14 +559,11 @@ bool load_vmcs(struct vmx_pages *vmx); =20 bool ept_1g_pages_supported(void); =20 -void nested_pg_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr); -void nested_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr, uint64_t size); -void nested_map_memslot(void *root_hva, struct kvm_vm *vm, - uint32_t memslot); -void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, - uint64_t addr, uint64_t size); +bool nested_ept_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t paddr, + uint64_t *address, + bool *leaf); bool kvm_cpu_has_ept(void); void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm, uint32_t eptp_memslot); diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testin= g/selftests/kvm/lib/x86/memstress.c index 7981e295cac70..d3e2fbd550acd 100644 --- a/tools/testing/selftests/kvm/lib/x86/memstress.c +++ b/tools/testing/selftests/kvm/lib/x86/memstress.c @@ -12,6 +12,7 @@ #include "test_util.h" #include "kvm_util.h" #include "memstress.h" +#include "nested_map.h" #include "processor.h" #include "vmx.h" =20 diff --git a/tools/testing/selftests/kvm/lib/x86/nested_map.c b/tools/testi= ng/selftests/kvm/lib/x86/nested_map.c new file mode 100644 index 0000000000000..454ab3e2f5b7e --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86/nested_map.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tools/testing/selftests/kvm/lib/x86_64/nested_map.c + * + * Copyright (C) 2025, Google LLC. + */ + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "nested_map.h" +#include "vmx.h" + +static uint64_t nested_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t nested_paddr, + uint64_t paddr, + int level, + bool want_leaf) +{ + bool leaf =3D want_leaf; + uint64_t address; + + if (!nested_ept_create_pte(vm, pte, paddr, &address, &leaf)) { + TEST_ASSERT(!want_leaf, + "Cannot create leaf entry at level: %u, nested_paddr: 0x%lx", + level, nested_paddr); + TEST_ASSERT(!leaf, + "Leaf entry already exists at level: %u, nested_paddr: 0x%lx", + level, nested_paddr); + } + return address; +} + +static void nested_pg_map(void *root_hva, struct kvm_vm *vm, uint64_t + nested_paddr, uint64_t paddr, int target_level) +{ + const uint64_t page_size =3D PG_LEVEL_SIZE(target_level); + uint64_t *pt =3D root_hva, *pte; + uint16_t index, address; + bool leaf; + + TEST_ASSERT(vm->mode =3D=3D VM_MODE_PXXV48_4K, "Attempt to use " + "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + + TEST_ASSERT((nested_paddr >> 48) =3D=3D 0, + "Nested physical address 0x%lx requires 5-level paging", + nested_paddr); + TEST_ASSERT((nested_paddr % page_size) =3D=3D 0, + "Nested physical address not on page boundary,\n" + " nested_paddr: 0x%lx page_size: 0x%lx", + nested_paddr, page_size); + TEST_ASSERT((nested_paddr >> vm->page_shift) <=3D vm->max_gfn, + "Physical address beyond beyond maximum supported,\n" + " nested_paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", + paddr, vm->max_gfn, vm->page_size); + TEST_ASSERT((paddr % page_size) =3D=3D 0, + "Physical address not on page boundary,\n" + " paddr: 0x%lx page_size: 0x%lx", + paddr, page_size); + TEST_ASSERT((paddr >> vm->page_shift) <=3D vm->max_gfn, + "Physical address beyond beyond maximum supported,\n" + " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", + paddr, vm->max_gfn, vm->page_size); + + for (int level =3D PG_LEVEL_512G; level >=3D PG_LEVEL_4K; level--) { + index =3D (nested_paddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu; + pte =3D &pt[index]; + leaf =3D (level =3D=3D target_level); + + address =3D nested_create_pte(vm, pte, nested_paddr, paddr, level, leaf); + + if (leaf) + break; + + pt =3D addr_gpa2hva(vm, address * vm->page_size); + } + +} + +/* + * Map a range of EPT guest physical addresses to the VM's physical address + * + * Input Args: + * vm - Virtual Machine + * nested_paddr - Nested guest physical address to map + * paddr - VM Physical Address + * size - The size of the range to map + * level - The level at which to map the range + * + * Output Args: None + * + * Return: None + * + * Within the VM given by vm, creates a nested guest translation for the + * page range starting at nested_paddr to the page range starting at paddr. + */ +static void __nested_map(void *root_hva, struct kvm_vm *vm, uint64_t + nested_paddr, uint64_t paddr, uint64_t size, int level) +{ + size_t page_size =3D PG_LEVEL_SIZE(level); + size_t npages =3D size / page_size; + + TEST_ASSERT(nested_paddr + size > nested_paddr, "Vaddr overflow"); + TEST_ASSERT(paddr + size > paddr, "Paddr overflow"); + + while (npages--) { + nested_pg_map(root_hva, vm, nested_paddr, paddr, level); + nested_paddr +=3D page_size; + paddr +=3D page_size; + } +} + +void nested_map(void *root_hva, struct kvm_vm *vm, + uint64_t nested_paddr, uint64_t paddr, uint64_t size) +{ + __nested_map(root_hva, vm, nested_paddr, paddr, size, PG_LEVEL_4K); +} + +/* + * Prepare an identity nested page table that maps all the + * physical pages in VM. + */ +void nested_map_memslot(void *root_hva, struct kvm_vm *vm, + uint32_t memslot) +{ + sparsebit_idx_t i, last; + struct userspace_mem_region *region =3D + memslot2region(vm, memslot); + + i =3D (region->region.guest_phys_addr >> vm->page_shift) - 1; + last =3D i + (region->region.memory_size >> vm->page_shift); + for (;;) { + i =3D sparsebit_next_clear(region->unused_phy_pages, i); + if (i > last) + break; + + nested_map(root_hva, vm, + (uint64_t)i << vm->page_shift, + (uint64_t)i << vm->page_shift, + 1 << vm->page_shift); + } +} + +/* Identity map a region with 1GiB Pages. */ +void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, + uint64_t addr, uint64_t size) +{ + __nested_map(root_hva, vm, addr, addr, size, PG_LEVEL_1G); +} diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index eeacf42bf30b1..24345213fcd04 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -365,11 +365,11 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_= rip, void *guest_rsp) init_vmcs_guest_state(guest_rip, guest_rsp); } =20 -static bool nested_ept_create_pte(struct kvm_vm *vm, - uint64_t *pte, - uint64_t paddr, - uint64_t *address, - bool *leaf) +bool nested_ept_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t paddr, + uint64_t *address, + bool *leaf) { struct eptPageTableEntry *epte =3D (struct eptPageTableEntry *)pte; =20 @@ -401,151 +401,6 @@ static bool nested_ept_create_pte(struct kvm_vm *vm, return true; } =20 -static uint64_t nested_create_pte(struct kvm_vm *vm, - uint64_t *pte, - uint64_t nested_paddr, - uint64_t paddr, - int level, - bool want_leaf) -{ - bool leaf =3D want_leaf; - uint64_t address; - - if (!nested_ept_create_pte(vm, pte, paddr, &address, &leaf)) { - TEST_ASSERT(!want_leaf, - "Cannot create leaf entry at level: %u, nested_paddr: 0x%lx", - level, nested_paddr); - TEST_ASSERT(!leaf, - "Leaf entry already exists at level: %u, nested_paddr: 0x%lx", - level, nested_paddr); - } - return address; -} - - -void __nested_pg_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr, int target_level) -{ - const uint64_t page_size =3D PG_LEVEL_SIZE(target_level); - uint64_t *pt =3D root_hva, *pte; - uint16_t index, address; - bool leaf; - - TEST_ASSERT(vm->mode =3D=3D VM_MODE_PXXV48_4K, "Attempt to use " - "unknown or unsupported guest mode, mode: 0x%x", vm->mode); - - TEST_ASSERT((nested_paddr >> 48) =3D=3D 0, - "Nested physical address 0x%lx requires 5-level paging", - nested_paddr); - TEST_ASSERT((nested_paddr % page_size) =3D=3D 0, - "Nested physical address not on page boundary,\n" - " nested_paddr: 0x%lx page_size: 0x%lx", - nested_paddr, page_size); - TEST_ASSERT((nested_paddr >> vm->page_shift) <=3D vm->max_gfn, - "Physical address beyond beyond maximum supported,\n" - " nested_paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", - paddr, vm->max_gfn, vm->page_size); - TEST_ASSERT((paddr % page_size) =3D=3D 0, - "Physical address not on page boundary,\n" - " paddr: 0x%lx page_size: 0x%lx", - paddr, page_size); - TEST_ASSERT((paddr >> vm->page_shift) <=3D vm->max_gfn, - "Physical address beyond beyond maximum supported,\n" - " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", - paddr, vm->max_gfn, vm->page_size); - - for (int level =3D PG_LEVEL_512G; level >=3D PG_LEVEL_4K; level--) { - index =3D (nested_paddr >> PG_LEVEL_SHIFT(level)) & 0x1ffu; - pte =3D &pt[index]; - leaf =3D (level =3D=3D target_level); - - address =3D nested_create_pte(vm, pte, nested_paddr, paddr, level, leaf); - - if (leaf) - break; - - pt =3D addr_gpa2hva(vm, address * vm->page_size); - } - -} - -void nested_pg_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr) -{ - __nested_pg_map(root_hva, vm, nested_paddr, paddr, PG_LEVEL_4K); -} - -/* - * Map a range of EPT guest physical addresses to the VM's physical address - * - * Input Args: - * vm - Virtual Machine - * nested_paddr - Nested guest physical address to map - * paddr - VM Physical Address - * size - The size of the range to map - * level - The level at which to map the range - * - * Output Args: None - * - * Return: None - * - * Within the VM given by vm, creates a nested guest translation for the - * page range starting at nested_paddr to the page range starting at paddr. - */ -void __nested_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr, uint64_t size, - int level) -{ - size_t page_size =3D PG_LEVEL_SIZE(level); - size_t npages =3D size / page_size; - - TEST_ASSERT(nested_paddr + size > nested_paddr, "Vaddr overflow"); - TEST_ASSERT(paddr + size > paddr, "Paddr overflow"); - - while (npages--) { - __nested_pg_map(root_hva, vm, nested_paddr, paddr, level); - nested_paddr +=3D page_size; - paddr +=3D page_size; - } -} - -void nested_map(void *root_hva, struct kvm_vm *vm, - uint64_t nested_paddr, uint64_t paddr, uint64_t size) -{ - __nested_map(root_hva, vm, nested_paddr, paddr, size, PG_LEVEL_4K); -} - -/* Prepare an identity extended page table that maps all the - * physical pages in VM. - */ -void nested_map_memslot(void *root_hva, struct kvm_vm *vm, - uint32_t memslot) -{ - sparsebit_idx_t i, last; - struct userspace_mem_region *region =3D - memslot2region(vm, memslot); - - i =3D (region->region.guest_phys_addr >> vm->page_shift) - 1; - last =3D i + (region->region.memory_size >> vm->page_shift); - for (;;) { - i =3D sparsebit_next_clear(region->unused_phy_pages, i); - if (i > last) - break; - - nested_map(root_hva, vm, - (uint64_t)i << vm->page_shift, - (uint64_t)i << vm->page_shift, - 1 << vm->page_shift); - } -} - -/* Identity map a region with 1GiB Pages. */ -void nested_identity_map_1g(void *root_hva, struct kvm_vm *vm, - uint64_t addr, uint64_t size) -{ - __nested_map(root_hva, vm, addr, addr, size, PG_LEVEL_1G); -} - bool kvm_cpu_has_ept(void) { uint64_t ctrl; diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/t= esting/selftests/kvm/x86/vmx_dirty_log_test.c index 21a57805e9780..db88a1e5e9d0c 100644 --- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c @@ -11,6 +11,7 @@ =20 #include "test_util.h" #include "kvm_util.h" +#include "nested_map.h" #include "processor.h" #include "vmx.h" =20 --=20 2.51.0.618.g983fd99d29-goog From nobody Wed Oct 1 20:28:49 2025 Received: from out-171.mta1.migadu.com (out-171.mta1.migadu.com [95.215.58.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C732730DEDE for ; Wed, 1 Oct 2025 14:59:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330745; cv=none; b=R2ddszUKs8jcipqtGuulMRDT2c0HfvzgIcRBi1M4hCgOQrCPBX4mSKGPuRS4xEvbtRW3SDYmdRWtn7AeAAJYvgNcrXTR5+VdRw80rwcZH8hc5L/fyzDuknf+jk0UK4JZd77XTHgX73YZQdMKcEC+dbndRCvp3Ik6cvGNeYh1gjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759330745; c=relaxed/simple; bh=3XZH7BRfy9GZsl2l9dW0v0fS+AFAUfjkshK6UQgXYew=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WPW/KupyUXqX6VehX5fymU24AdCWHtAb3//gWJXn5IU6tQjqYqJxxTqRPyh0/nGC+BVVXWAgfzPA8Z0C0nnv02cKlpYofPZqGwJBdi1VGf2cWaKAhAdDyaJQci/LmbBHR/dwTg8ICWs2c8U46fpufiIuVU1CWT8W83Xc3DPm5Xw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=FZ1Y/c5W; arc=none smtp.client-ip=95.215.58.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="FZ1Y/c5W" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1759330740; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=njLgviB8zkOyaMBe4TukJ4UcfLgF0Cr0ukv2OYqfgrI=; b=FZ1Y/c5WydlXzXQ6g6dQwVlvLoBYC2BsJimarpYifney7ha8MVlq//kjk06omLorh+N8M7 MPgvAE86qGjwt0h982X1UV5eAQSlwZE70GTZXqvyy4FNon70Qg6sm7kY3CBJcL9+APUWag aofYjPDQ6e0IsCBl3BLG8ng6elG9y6Q= From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 12/12] KVM: selftests: Extend vmx_dirty_log_test to cover SVM Date: Wed, 1 Oct 2025 14:58:16 +0000 Message-ID: <20251001145816.1414855-13-yosry.ahmed@linux.dev> In-Reply-To: <20251001145816.1414855-1-yosry.ahmed@linux.dev> References: <20251001145816.1414855-1-yosry.ahmed@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add the necessary infrastructure to support setting up nested NPTs and creating nested NPT mappings. There is some redundancy between nested_npt_create_pte() and nested_ept_create_pte(), especially that we access the same fields in both. An alternative is to have a single function in nested_map.c, and use macros to cast an obaque PTE pointer to the correct type (EPT entry vs NPT entry). Add a check in kvm_cpu_has_ept() to return false on AMD CPUs without attempting to read VMX-specific MSRs, since now it can be called on AMD CPUs. Generalize the code in vmx_dirty_log_test.c by adding SVM-specific L1 code, doing some renaming (e.g. EPT -> TDP), and having setup code for both SVM and VMX in test_dirty_log(). Having multiple points to check for SVM vs VMX is not ideal, but the alternatives either include a lot of redundancy or a lot of abstracting functions that will make the test logic harder to follow. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 2 +- .../selftests/kvm/include/x86/svm_util.h | 13 +++ tools/testing/selftests/kvm/lib/x86/svm.c | 70 ++++++++++++++ tools/testing/selftests/kvm/lib/x86/vmx.c | 3 + ...rty_log_test.c =3D> nested_dirty_log_test.c} | 94 ++++++++++++++----- 5 files changed, 155 insertions(+), 27 deletions(-) rename tools/testing/selftests/kvm/x86/{vmx_dirty_log_test.c =3D> nested_d= irty_log_test.c} (62%) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 9547d7263e236..acedbf726f493 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -113,7 +113,7 @@ TEST_GEN_PROGS_x86 +=3D x86/userspace_io_test TEST_GEN_PROGS_x86 +=3D x86/userspace_msr_exit_test TEST_GEN_PROGS_x86 +=3D x86/vmx_apic_access_test TEST_GEN_PROGS_x86 +=3D x86/close_while_nested_test -TEST_GEN_PROGS_x86 +=3D x86/vmx_dirty_log_test +TEST_GEN_PROGS_x86 +=3D x86/nested_dirty_log_test TEST_GEN_PROGS_x86 +=3D x86/vmx_exception_with_invalid_guest_state TEST_GEN_PROGS_x86 +=3D x86/vmx_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_invalid_nested_guest_state diff --git a/tools/testing/selftests/kvm/include/x86/svm_util.h b/tools/tes= ting/selftests/kvm/include/x86/svm_util.h index b74c6dcddcbd6..84b79113b5433 100644 --- a/tools/testing/selftests/kvm/include/x86/svm_util.h +++ b/tools/testing/selftests/kvm/include/x86/svm_util.h @@ -27,6 +27,11 @@ struct svm_test_data { void *msr; /* gva */ void *msr_hva; uint64_t msr_gpa; + + /* NPT */ + void *ncr3; /* gva */ + void *ncr3_hva; + uint64_t ncr3_gpa; }; =20 static inline void vmmcall(void) @@ -57,6 +62,14 @@ struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, = vm_vaddr_t *p_svm_gva); void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *g= uest_rsp); void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa); =20 +bool nested_npt_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t paddr, + uint64_t *address, + bool *leaf); +bool kvm_cpu_has_npt(void); +void prepare_npt(struct svm_test_data *svm, struct kvm_vm *vm); + int open_sev_dev_path_or_exit(void); =20 #endif /* SELFTEST_KVM_SVM_UTILS_H */ diff --git a/tools/testing/selftests/kvm/lib/x86/svm.c b/tools/testing/self= tests/kvm/lib/x86/svm.c index d239c20973918..9524abf7e779a 100644 --- a/tools/testing/selftests/kvm/lib/x86/svm.c +++ b/tools/testing/selftests/kvm/lib/x86/svm.c @@ -16,6 +16,23 @@ struct gpr64_regs guest_regs; u64 rflags; =20 +struct nptPageTableEntry { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t pwt:1; + uint64_t pcd:1; + uint64_t accessed:1; + uint64_t dirty:1; + uint64_t page_size:1; + uint64_t global:1; + uint64_t avail1:3; + uint64_t address:40; + uint64_t avail2:11; + uint64_t nx:1; +}; +static_assert(sizeof(struct nptPageTableEntry) =3D=3D sizeof(uint64_t)); + /* Allocate memory regions for nested SVM tests. * * Input Args: @@ -59,6 +76,54 @@ static void vmcb_set_seg(struct vmcb_seg *seg, u16 selec= tor, seg->base =3D base; } =20 +bool nested_npt_create_pte(struct kvm_vm *vm, + uint64_t *pte, + uint64_t paddr, + uint64_t *address, + bool *leaf) +{ + struct nptPageTableEntry *npte =3D (struct nptPageTableEntry *)pte; + + if (npte->present) { + *leaf =3D npte->page_size; + *address =3D npte->address; + return false; + } + + npte->present =3D true; + npte->writable =3D true; + npte->page_size =3D *leaf; + + if (*leaf) + npte->address =3D paddr >> vm->page_shift; + else + npte->address =3D vm_alloc_page_table(vm) >> vm->page_shift; + + *address =3D npte->address; + + /* + * For now mark these as accessed and dirty because the only + * testcase we have needs that. Can be reconsidered later. + */ + npte->accessed =3D *leaf; + npte->dirty =3D *leaf; + return true; +} + +bool kvm_cpu_has_npt(void) +{ + return kvm_cpu_has(X86_FEATURE_NPT); +} + +void prepare_npt(struct svm_test_data *svm, struct kvm_vm *vm) +{ + TEST_ASSERT(kvm_cpu_has_npt(), "KVM doesn't support nested NPT"); + + svm->ncr3 =3D (void *)vm_vaddr_alloc_page(vm); + svm->ncr3_hva =3D addr_gva2hva(vm, (uintptr_t)svm->ncr3); + svm->ncr3_gpa =3D addr_gva2gpa(vm, (uintptr_t)svm->ncr3); +} + void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *g= uest_rsp) { struct vmcb *vmcb =3D svm->vmcb; @@ -102,6 +167,11 @@ void generic_svm_setup(struct svm_test_data *svm, void= *guest_rip, void *guest_r vmcb->save.rip =3D (u64)guest_rip; vmcb->save.rsp =3D (u64)guest_rsp; guest_regs.rdi =3D (u64)svm; + + if (svm->ncr3_gpa) { + ctrl->nested_ctl |=3D SVM_NESTED_CTL_NP_ENABLE; + ctrl->nested_cr3 =3D svm->ncr3_gpa; + } } =20 /* diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/self= tests/kvm/lib/x86/vmx.c index 24345213fcd04..0ced959184cd9 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -405,6 +405,9 @@ bool kvm_cpu_has_ept(void) { uint64_t ctrl; =20 + if (!kvm_cpu_has(X86_FEATURE_VMX)) + return false; + ctrl =3D kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32; if (!(ctrl & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) return false; diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/t= esting/selftests/kvm/x86/nested_dirty_log_test.c similarity index 62% rename from tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c rename to tools/testing/selftests/kvm/x86/nested_dirty_log_test.c index db88a1e5e9d0c..56f741ddce944 100644 --- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c @@ -13,6 +13,7 @@ #include "kvm_util.h" #include "nested_map.h" #include "processor.h" +#include "svm_util.h" #include "vmx.h" =20 /* The memory slot index to track dirty pages */ @@ -26,6 +27,8 @@ #define NESTED_TEST_MEM1 0xc0001000 #define NESTED_TEST_MEM2 0xc0002000 =20 +#define L2_GUEST_STACK_SIZE 64 + static void l2_guest_code(u64 *a, u64 *b) { READ_ONCE(*a); @@ -43,20 +46,19 @@ static void l2_guest_code(u64 *a, u64 *b) vmcall(); } =20 -static void l2_guest_code_ept_enabled(void) +static void l2_guest_code_tdp_enabled(void) { l2_guest_code((u64 *)NESTED_TEST_MEM1, (u64 *)NESTED_TEST_MEM2); } =20 -static void l2_guest_code_ept_disabled(void) +static void l2_guest_code_tdp_disabled(void) { - /* Access the same L1 GPAs as l2_guest_code_ept_enabled() */ + /* Access the same L1 GPAs as l2_guest_code_tdp_enabled() */ l2_guest_code((u64 *)GUEST_TEST_MEM, (u64 *)GUEST_TEST_MEM); } =20 -void l1_guest_code(struct vmx_pages *vmx) +void l1_vmx_code(struct vmx_pages *vmx) { -#define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; void *l2_rip; =20 @@ -65,9 +67,9 @@ void l1_guest_code(struct vmx_pages *vmx) GUEST_ASSERT(load_vmcs(vmx)); =20 if (vmx->eptp_gpa) - l2_rip =3D l2_guest_code_ept_enabled; + l2_rip =3D l2_guest_code_tdp_enabled; else - l2_rip =3D l2_guest_code_ept_disabled; + l2_rip =3D l2_guest_code_tdp_disabled; =20 prepare_vmcs(vmx, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]); =20 @@ -78,10 +80,38 @@ void l1_guest_code(struct vmx_pages *vmx) GUEST_DONE(); } =20 -static void test_vmx_dirty_log(bool enable_ept) +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + void *l2_rip; + + if (svm->ncr3_gpa) + l2_rip =3D l2_guest_code_tdp_enabled; + else + l2_rip =3D l2_guest_code_tdp_disabled; + + generic_svm_setup(svm, l2_rip, &l2_guest_stack[L2_GUEST_STACK_SIZE]= ); + + GUEST_SYNC(false); + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_SYNC(false); + GUEST_ASSERT(svm->vmcb->control.exit_code =3D=3D SVM_EXIT_VMMCALL); + GUEST_DONE(); +} + +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + +static void test_dirty_log(bool enable_tdp) { - vm_vaddr_t vmx_pages_gva =3D 0; - struct vmx_pages *vmx; + struct svm_test_data *svm =3D NULL; + struct vmx_pages *vmx =3D NULL; + vm_vaddr_t nested_gva =3D 0; unsigned long *bmap; uint64_t *host_test_mem; =20 @@ -90,12 +120,16 @@ static void test_vmx_dirty_log(bool enable_ept) struct ucall uc; bool done =3D false; =20 - pr_info("Nested EPT: %s\n", enable_ept ? "enabled" : "disabled"); + pr_info("Nested TDP: %s\n", enable_tdp ? "enabled" : "disabled"); =20 /* Create VM */ vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); - vmx =3D vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vmx =3D vcpu_alloc_vmx(vm, &nested_gva); + else + svm =3D vcpu_alloc_svm(vm, &nested_gva); + + vcpu_args_set(vcpu, 1, nested_gva); =20 /* Add an extra memory slot for testing dirty logging */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, @@ -114,17 +148,25 @@ static void test_vmx_dirty_log(bool enable_ept) * ... pages in the L2 GPA range [0xc0001000, 0xc0003000) will map to * 0xc0000000. * - * Note that prepare_eptp should be called only L1's GPA map is done, - * meaning after the last call to virt_map. + * Note that prepare_eptp()/prepare_npt() should be called only when + * L1's GPA map is done, meaning after the last call to virt_map. * - * When EPT is disabled, the L2 guest code will still access the same L1 - * GPAs as the EPT enabled case. + * When TDP is disabled, the L2 guest code will still access the same L1 + * GPAs as the TDP enabled case. */ - if (enable_ept) { - prepare_eptp(vmx, vm, 0); - nested_map_memslot(vmx->eptp_hva, vm, 0); - nested_map(vmx->eptp_hva, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096); - nested_map(vmx->eptp_hva, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096); + if (enable_tdp) { + void *root_hva; + + if (kvm_cpu_has(X86_FEATURE_VMX)) { + prepare_eptp(vmx, vm, 0); + root_hva =3D vmx->eptp_hva; + } else { + prepare_npt(svm, vm); + root_hva =3D svm->ncr3_hva; + } + nested_map_memslot(root_hva, vm, 0); + nested_map(root_hva, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096); + nested_map(root_hva, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096); } =20 bmap =3D bitmap_zalloc(TEST_MEM_PAGES); @@ -169,12 +211,12 @@ static void test_vmx_dirty_log(bool enable_ept) =20 int main(int argc, char *argv[]) { - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || kvm_cpu_has(X86_FEATURE_SVM)= ); =20 - test_vmx_dirty_log(/*enable_ept=3D*/false); + test_dirty_log(/*enable_tdp=3D*/false); =20 - if (kvm_cpu_has_ept()) - test_vmx_dirty_log(/*enable_ept=3D*/true); + if (kvm_cpu_has_ept() || kvm_cpu_has_npt()) + test_dirty_log(/*enable_tdp=3D*/true); =20 return 0; } --=20 2.51.0.618.g983fd99d29-goog