From nobody Mon May 25 04:34:01 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 66E803932CE; Mon, 18 May 2026 20:25:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135924; cv=none; b=QrgDEaqjIlkTNUj6b2pZL1MSOHWUcx38LkM/MVI1Zf5Lb7Ba6TOqCEM1FilJRIF6QPpngxtqmQ1yEElQsnOOw6MnoQ1y+C1zydPVV+lqEfY6/z7G6BUM1DR8TNT38i3g9nixZczXGdVLdG9HRwCXYlQwacV8s14zZS8RfnHHrwA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135924; c=relaxed/simple; bh=+qgbpnPCsZtacnB8SkWTQSzxBNQtXBDtB8u7+5UFL/E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Sl8Qb75J+ZjkT2nqgeUoKYxry7OZIt8X7KGGW7S+Iidnq7IAU/bJPZ+AZsdZl30puEUtVYcLUTlR9IsFR0ULc1CWoEcr6OHzz3XuuZ0cP6UvxEQ7m2HIh9UM44Qy8dJ+pMs87FkbUKDEhv5tW4zIP7y1ZSv3Uh8WaYg2PVPVJro= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=seXO6iRy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="seXO6iRy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1631BC2BCF6; Mon, 18 May 2026 20:25:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135924; bh=+qgbpnPCsZtacnB8SkWTQSzxBNQtXBDtB8u7+5UFL/E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=seXO6iRy7sshOoFYC/h0y4dgtAQhAhPLY8B7JJn5ECoj6TKFZLdab7t9VavlE0ABt bNMBx2G3QAQ3jZ/NWtROikXorxW0YulXCa0t0F9dRPcadmzqAgJ+kHA2qibD3EO/nz VuMEYBF54GtusEXCfvPQjs/3/z/Md+QtDJ8pP29qek0Nw40WLPoYAVjpQuz0xuxHyf Vjjd4Oi+iWT50J4pk/wDXEG8y4gZAr/bXmX8sQ3VJqw21asoycPCVCwL+zqYG/7XpV jp6j/pv76lcQnuncZh7m5VKjVSkZGgf50wCF8C6pU0FaTi1P2ieLyTIG4wNP1aaxNU ZeDGj5cY9sb4Q== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH 1/8] KVM: selftests: Fix offsets in GPR switching for nSVM Date: Mon, 18 May 2026 20:25:07 +0000 Message-ID: <20260518202514.2037078-2-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" The GPRs switching code uses hardcoded offsets and gets them wrong. For example, the offset of RBX should actually be 0x18. It also uses an offset outside the struct for the last register. Instead of hardcoded offsets, define ASM variables that hold the member offsets using offsetof(), and define a macro that uses those offsets to switch one GPR. Opportunistically drop the separate SAVE/LOAD macros in favor of a single SWITCH macro, and rename it to reflect that it doesn't switch RAX. Also, re-order the registers in the struct alphabetically since the ordering does not matter anymore, and drop RSP as it's not used anyway. Signed-off-by: Yosry Ahmed --- .../selftests/kvm/include/x86/processor.h | 3 +- tools/testing/selftests/kvm/lib/x86/svm.c | 58 ++++++++++++------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index 77f576ee7789d..1482f2b53a9c5 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -381,10 +381,9 @@ static inline unsigned int x86_model(unsigned int eax) /* General Registers in 64-Bit Mode */ struct gpr64_regs { u64 rax; + u64 rbx; u64 rcx; u64 rdx; - u64 rbx; - u64 rsp; u64 rbp; u64 rsi; u64 rdi; diff --git a/tools/testing/selftests/kvm/lib/x86/svm.c b/tools/testing/self= tests/kvm/lib/x86/svm.c index 3b01605ab016c..6a6926b3b9d7c 100644 --- a/tools/testing/selftests/kvm/lib/x86/svm.c +++ b/tools/testing/selftests/kvm/lib/x86/svm.c @@ -131,31 +131,49 @@ void generic_svm_setup(struct svm_test_data *svm, voi= d *guest_rip, void *guest_r } } =20 +#define DEFINE_ASM_GPR64_OFFSET(reg) \ + asm(".equ GPR64_OFF_" #reg ", %c0" : : "i"(offsetof(struct gpr64_regs, re= g))) + +DEFINE_ASM_GPR64_OFFSET(rbx); +DEFINE_ASM_GPR64_OFFSET(rcx); +DEFINE_ASM_GPR64_OFFSET(rdx); +DEFINE_ASM_GPR64_OFFSET(rbp); +DEFINE_ASM_GPR64_OFFSET(rsi); +DEFINE_ASM_GPR64_OFFSET(rdi); +DEFINE_ASM_GPR64_OFFSET(r8); +DEFINE_ASM_GPR64_OFFSET(r9); +DEFINE_ASM_GPR64_OFFSET(r10); +DEFINE_ASM_GPR64_OFFSET(r11); +DEFINE_ASM_GPR64_OFFSET(r12); +DEFINE_ASM_GPR64_OFFSET(r13); +DEFINE_ASM_GPR64_OFFSET(r14); +DEFINE_ASM_GPR64_OFFSET(r15); + +#define GUEST_SWITCH_GPR_ASM(reg) \ + "xchg %%" #reg ", guest_regs + GPR64_OFF_" #reg "\n\t" /* * save/restore 64-bit general registers except rax, rip, rsp * which are directly handed through the VMCB guest processor state */ -#define SAVE_GPR_C \ - "xchg %%rbx, guest_regs+0x20\n\t" \ - "xchg %%rcx, guest_regs+0x10\n\t" \ - "xchg %%rdx, guest_regs+0x18\n\t" \ - "xchg %%rbp, guest_regs+0x30\n\t" \ - "xchg %%rsi, guest_regs+0x38\n\t" \ - "xchg %%rdi, guest_regs+0x40\n\t" \ - "xchg %%r8, guest_regs+0x48\n\t" \ - "xchg %%r9, guest_regs+0x50\n\t" \ - "xchg %%r10, guest_regs+0x58\n\t" \ - "xchg %%r11, guest_regs+0x60\n\t" \ - "xchg %%r12, guest_regs+0x68\n\t" \ - "xchg %%r13, guest_regs+0x70\n\t" \ - "xchg %%r14, guest_regs+0x78\n\t" \ - "xchg %%r15, guest_regs+0x80\n\t" - -#define LOAD_GPR_C SAVE_GPR_C +#define GUEST_SWITCH_GPRS_NORAX_ASM \ + GUEST_SWITCH_GPR_ASM(rbx) \ + GUEST_SWITCH_GPR_ASM(rcx) \ + GUEST_SWITCH_GPR_ASM(rdx) \ + GUEST_SWITCH_GPR_ASM(rbp) \ + GUEST_SWITCH_GPR_ASM(rsi) \ + GUEST_SWITCH_GPR_ASM(rdi) \ + GUEST_SWITCH_GPR_ASM(r8) \ + GUEST_SWITCH_GPR_ASM(r9) \ + GUEST_SWITCH_GPR_ASM(r10) \ + GUEST_SWITCH_GPR_ASM(r11) \ + GUEST_SWITCH_GPR_ASM(r12) \ + GUEST_SWITCH_GPR_ASM(r13) \ + GUEST_SWITCH_GPR_ASM(r14) \ + GUEST_SWITCH_GPR_ASM(r15) =20 /* * selftests do not use interrupts so we dropped clgi/sti/cli/stgi - * for now. registers involved in LOAD/SAVE_GPR_C are eventually + * for now. registers involved in GPRs switching are eventually * unmodified so they do not need to be in the clobber list. */ void run_guest(struct vmcb *vmcb, u64 vmcb_gpa) @@ -166,9 +184,9 @@ void run_guest(struct vmcb *vmcb, u64 vmcb_gpa) "mov %%r15, 0x170(%[vmcb])\n\t" "mov guest_regs, %%r15\n\t" // rax "mov %%r15, 0x1f8(%[vmcb])\n\t" - LOAD_GPR_C + GUEST_SWITCH_GPRS_NORAX_ASM "vmrun %[vmcb_gpa]\n\t" - SAVE_GPR_C + GUEST_SWITCH_GPRS_NORAX_ASM "mov 0x170(%[vmcb]), %%r15\n\t" // rflags "mov %%r15, rflags\n\t" "mov 0x1f8(%[vmcb]), %%r15\n\t" // rax --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 C62563932E6; Mon, 18 May 2026 20:25:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135924; cv=none; b=NWJbLvQeq0JOudoV2XKMprLAJdill0g8ucsh1cuq7D5GoK1KTCL0opxdietm3bgMrNDU85jHRwJSqbg5KFmG6u5VWBACrLEkI1TicZHt2j/lECJPVIN3zdmRN8LrkOgMh1bSB7j+DQ3bhbkdMVtIs+reXoNANDpTawlIbYBlEAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135924; c=relaxed/simple; bh=njX+iJo3+TNYTdvOBhNX5VWPurSrqrigf3nE/wY7WxE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QHtWkQTnDkm1AvpQB1G2mQfc/JW9JOvZDcdjIU5kJpGQ+A8AxQNU38rAbIsyNLJiIFDSML1NcsqJKcd0miLst+9SLnNxfi4iIygXwQum/xA+Nf+aV+XZuEwCDf0dt7S6CtjKBo8yP3CxeuQTtcdrHvGe7AyspbMsVYj09U4SGHo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cKAt6nmY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cKAt6nmY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6FDD8C2BCC6; Mon, 18 May 2026 20:25:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135924; bh=njX+iJo3+TNYTdvOBhNX5VWPurSrqrigf3nE/wY7WxE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cKAt6nmYgToYPx7QoZLnYx4XCsil0pj+qC1/QAtO4nn1Qdnd/EbCgxQWLk6DWyRu1 Lxs4S8Xs3S7yR0yK3vvuFJrpF887g68EYrhy7URbySHBhXGqX4OcMueUt50yGcWUI0 FxZbqDJ6xsPcbeSVs/qAXQwDxCp52MOWWIJg6qtHHMQLTqIuIdXNkBkQkHLbKsZo0l 97WvP6BQvvPqmnS9jAVmN2FAiBRhwd/triMa8aiEVurz8KFRMLToVfLhik/2h8iBbp B50jNtvLHxPDHxQYXNZdEwl4kq3Y6ZtZ++DLsU40I1tbFgHbRZdhfsnbQvG5MiOltP m3ffOuKAbdSvQ== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 2/8] KVM: selftests: Move GPR load/save definitions outside of nSVM code Date: Mon, 18 May 2026 20:25:08 +0000 Message-ID: <20260518202514.2037078-3-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed In preparation for reusing the code for nVMX tests, move the definitions for GPRs switching to processor.h. No functional change intended. Signed-off-by: Yosry Ahmed --- .../selftests/kvm/include/x86/processor.h | 42 +++++++++++++++++++ .../testing/selftests/kvm/lib/x86/processor.c | 2 + tools/testing/selftests/kvm/lib/x86/svm.c | 41 ------------------ 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index 1482f2b53a9c5..8e4eab84b91bc 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -397,6 +397,48 @@ struct gpr64_regs { u64 r15; }; =20 +extern struct gpr64_regs guest_regs; + +#define DEFINE_ASM_GPR64_OFFSET(reg) \ + asm(".equ GPR64_OFF_" #reg ", %c0" : : "i"(offsetof(struct gpr64_regs, re= g))) + +DEFINE_ASM_GPR64_OFFSET(rbx); +DEFINE_ASM_GPR64_OFFSET(rcx); +DEFINE_ASM_GPR64_OFFSET(rdx); +DEFINE_ASM_GPR64_OFFSET(rbp); +DEFINE_ASM_GPR64_OFFSET(rsi); +DEFINE_ASM_GPR64_OFFSET(rdi); +DEFINE_ASM_GPR64_OFFSET(r8); +DEFINE_ASM_GPR64_OFFSET(r9); +DEFINE_ASM_GPR64_OFFSET(r10); +DEFINE_ASM_GPR64_OFFSET(r11); +DEFINE_ASM_GPR64_OFFSET(r12); +DEFINE_ASM_GPR64_OFFSET(r13); +DEFINE_ASM_GPR64_OFFSET(r14); +DEFINE_ASM_GPR64_OFFSET(r15); + +#define GUEST_SWITCH_GPR_ASM(reg) \ + "xchg %%" #reg ", guest_regs + GPR64_OFF_" #reg "\n\t" +/* + * save/restore 64-bit general registers except rax, rip, rsp + * which are directly handed through the VMCB guest processor state + */ +#define GUEST_SWITCH_GPRS_NORAX_ASM \ + GUEST_SWITCH_GPR_ASM(rbx) \ + GUEST_SWITCH_GPR_ASM(rcx) \ + GUEST_SWITCH_GPR_ASM(rdx) \ + GUEST_SWITCH_GPR_ASM(rbp) \ + GUEST_SWITCH_GPR_ASM(rsi) \ + GUEST_SWITCH_GPR_ASM(rdi) \ + GUEST_SWITCH_GPR_ASM(r8) \ + GUEST_SWITCH_GPR_ASM(r9) \ + GUEST_SWITCH_GPR_ASM(r10) \ + GUEST_SWITCH_GPR_ASM(r11) \ + GUEST_SWITCH_GPR_ASM(r12) \ + GUEST_SWITCH_GPR_ASM(r13) \ + GUEST_SWITCH_GPR_ASM(r14) \ + GUEST_SWITCH_GPR_ASM(r15) + struct desc64 { u16 limit0; u16 base0; diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testin= g/selftests/kvm/lib/x86/processor.c index b51467d70f6e7..caefcd12df8d2 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -29,6 +29,8 @@ bool host_cpu_is_amd_compatible; bool is_forced_emulation_enabled; u64 guest_tsc_khz; =20 +struct gpr64_regs guest_regs; + const char *ex_str(int vector) { switch (vector) { diff --git a/tools/testing/selftests/kvm/lib/x86/svm.c b/tools/testing/self= tests/kvm/lib/x86/svm.c index 6a6926b3b9d7c..b4d1a00dbe27f 100644 --- a/tools/testing/selftests/kvm/lib/x86/svm.c +++ b/tools/testing/selftests/kvm/lib/x86/svm.c @@ -13,7 +13,6 @@ =20 #define SEV_DEV_PATH "/dev/sev" =20 -struct gpr64_regs guest_regs; u64 rflags; =20 /* Allocate memory regions for nested SVM tests. @@ -131,46 +130,6 @@ void generic_svm_setup(struct svm_test_data *svm, void= *guest_rip, void *guest_r } } =20 -#define DEFINE_ASM_GPR64_OFFSET(reg) \ - asm(".equ GPR64_OFF_" #reg ", %c0" : : "i"(offsetof(struct gpr64_regs, re= g))) - -DEFINE_ASM_GPR64_OFFSET(rbx); -DEFINE_ASM_GPR64_OFFSET(rcx); -DEFINE_ASM_GPR64_OFFSET(rdx); -DEFINE_ASM_GPR64_OFFSET(rbp); -DEFINE_ASM_GPR64_OFFSET(rsi); -DEFINE_ASM_GPR64_OFFSET(rdi); -DEFINE_ASM_GPR64_OFFSET(r8); -DEFINE_ASM_GPR64_OFFSET(r9); -DEFINE_ASM_GPR64_OFFSET(r10); -DEFINE_ASM_GPR64_OFFSET(r11); -DEFINE_ASM_GPR64_OFFSET(r12); -DEFINE_ASM_GPR64_OFFSET(r13); -DEFINE_ASM_GPR64_OFFSET(r14); -DEFINE_ASM_GPR64_OFFSET(r15); - -#define GUEST_SWITCH_GPR_ASM(reg) \ - "xchg %%" #reg ", guest_regs + GPR64_OFF_" #reg "\n\t" -/* - * save/restore 64-bit general registers except rax, rip, rsp - * which are directly handed through the VMCB guest processor state - */ -#define GUEST_SWITCH_GPRS_NORAX_ASM \ - GUEST_SWITCH_GPR_ASM(rbx) \ - GUEST_SWITCH_GPR_ASM(rcx) \ - GUEST_SWITCH_GPR_ASM(rdx) \ - GUEST_SWITCH_GPR_ASM(rbp) \ - GUEST_SWITCH_GPR_ASM(rsi) \ - GUEST_SWITCH_GPR_ASM(rdi) \ - GUEST_SWITCH_GPR_ASM(r8) \ - GUEST_SWITCH_GPR_ASM(r9) \ - GUEST_SWITCH_GPR_ASM(r10) \ - GUEST_SWITCH_GPR_ASM(r11) \ - GUEST_SWITCH_GPR_ASM(r12) \ - GUEST_SWITCH_GPR_ASM(r13) \ - GUEST_SWITCH_GPR_ASM(r14) \ - GUEST_SWITCH_GPR_ASM(r15) - /* * selftests do not use interrupts so we dropped clgi/sti/cli/stgi * for now. registers involved in GPRs switching are eventually --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B01CD39479C; Mon, 18 May 2026 20:25:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135925; cv=none; b=noEz716bsWqKLnlXTtzXcwG2jGDwGc/5hJClweiD9yROAVtVha9ZCr0P0k/1RUso/zV4mPooxL00WkkcGNUuBTyYnIskd/r8zRPU4dneHfOqBR8H2S4AaT9EMGgVpcTFtm3ycDjD7bCHvo5wjTDp0qC5e8odcx+hlHsZz2NSAD8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135925; c=relaxed/simple; bh=ufaGfnPeyDc9dujy05w2JCVcs25USAABBdfA6RnPZiQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uxIM8ziRmdHTXYgPjUk13nBbcElOIUJYcMGeRQ32gJHVF/dlDtu7U9AyKzaQ4HG00SQLLXomnzW/t5ZdiiXh9QTbI1Li57SIdHmUNUNgeHBHTVcuT2RyUwb4Aluw7aT3BlcEMsdUvp3qnceYVbrCBNqwXfjVN6aar+nOb/T1gvc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bQi6LyrW; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bQi6LyrW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D2462C4AF09; Mon, 18 May 2026 20:25:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135925; bh=ufaGfnPeyDc9dujy05w2JCVcs25USAABBdfA6RnPZiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bQi6LyrW8y7D5Q7P17xG8K3OhIxKWn5GOsoICtweXKHW0C6axZ4ki8CfGR1sk1QDW Gm3Kh/NBWrhyWEmfEeJQhFTDyYHn/I0jqi4wcTGI5wri1Ja+Z2ABM9+Kwnc1TGU7K8 lj3VTy1oNsMFvM6Zkb18WHa0qvi/Gq5GEYeFWovwkzBQAImy57HAqgMkcp4s/XZ0Xr 8psoDKE4zZXL19qVjWerKAjVPJgiu90zJLZsHEvT8xcsNfeUIYo1de3CvXcO6jSVNP gi4eyyq5WgBNdoDThcfIxHoydh6MThR//ucM0a9xSZEUNTwge3FTkggFeVczmODkbY 5Ypgka3bGJ7pQ== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 3/8] KVM: selftests: Reuse GPR switching logic for nVMX Date: Mon, 18 May 2026 20:25:09 +0000 Message-ID: <20260518202514.2037078-4-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Reuse the GPR switching logic for nVMX by adding a wrapper that also switches RAX, replacing the push/pop of a subset of the registers. Signed-off-by: Yosry Ahmed --- .../selftests/kvm/include/x86/processor.h | 5 ++ tools/testing/selftests/kvm/include/x86/vmx.h | 46 +++++-------------- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index 8e4eab84b91bc..ca2ec92490f7c 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -402,6 +402,7 @@ extern struct gpr64_regs guest_regs; #define DEFINE_ASM_GPR64_OFFSET(reg) \ asm(".equ GPR64_OFF_" #reg ", %c0" : : "i"(offsetof(struct gpr64_regs, re= g))) =20 +DEFINE_ASM_GPR64_OFFSET(rax); DEFINE_ASM_GPR64_OFFSET(rbx); DEFINE_ASM_GPR64_OFFSET(rcx); DEFINE_ASM_GPR64_OFFSET(rdx); @@ -439,6 +440,10 @@ DEFINE_ASM_GPR64_OFFSET(r15); GUEST_SWITCH_GPR_ASM(r14) \ GUEST_SWITCH_GPR_ASM(r15) =20 +#define GUEST_SWITCH_GPRS_ASM \ + GUEST_SWITCH_GPR_ASM(rax) \ + GUEST_SWITCH_GPRS_NORAX_ASM + struct desc64 { u16 limit0; u16 base0; diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/= selftests/kvm/include/x86/vmx.h index 90fffaf915958..a7f6f0c9b6b9d 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -363,9 +363,6 @@ static inline u64 vmptrstz(void) return value; } =20 -/* - * No guest state (e.g. GPRs) is established by this vmlaunch. - */ static inline int vmlaunch(void) { int ret; @@ -373,34 +370,23 @@ static inline int vmlaunch(void) if (enable_evmcs) return evmcs_vmlaunch(); =20 - __asm__ __volatile__("push %%rbp;" - "push %%rcx;" - "push %%rdx;" - "push %%rsi;" - "push %%rdi;" - "push $0;" + __asm__ __volatile__("push $0;" "vmwrite %%rsp, %[host_rsp];" "lea 1f(%%rip), %%rax;" "vmwrite %%rax, %[host_rip];" + GUEST_SWITCH_GPRS_ASM "vmlaunch;" "incq (%%rsp);" - "1: pop %%rax;" - "pop %%rdi;" - "pop %%rsi;" - "pop %%rdx;" - "pop %%rcx;" - "pop %%rbp;" + "1: ;" + GUEST_SWITCH_GPRS_ASM + "pop %%rax;" : [ret]"=3D&a"(ret) : [host_rsp]"r"((u64)HOST_RSP), [host_rip]"r"((u64)HOST_RIP) - : "memory", "cc", "rbx", "r8", "r9", "r10", - "r11", "r12", "r13", "r14", "r15"); + : "memory", "cc"); return ret; } =20 -/* - * No guest state (e.g. GPRs) is established by this vmresume. - */ static inline int vmresume(void) { int ret; @@ -408,28 +394,20 @@ static inline int vmresume(void) if (enable_evmcs) return evmcs_vmresume(); =20 - __asm__ __volatile__("push %%rbp;" - "push %%rcx;" - "push %%rdx;" - "push %%rsi;" - "push %%rdi;" - "push $0;" + __asm__ __volatile__("push $0;" "vmwrite %%rsp, %[host_rsp];" "lea 1f(%%rip), %%rax;" "vmwrite %%rax, %[host_rip];" + GUEST_SWITCH_GPRS_ASM "vmresume;" "incq (%%rsp);" - "1: pop %%rax;" - "pop %%rdi;" - "pop %%rsi;" - "pop %%rdx;" - "pop %%rcx;" - "pop %%rbp;" + "1: ;" + GUEST_SWITCH_GPRS_ASM + "pop %%rax;" : [ret]"=3D&a"(ret) : [host_rsp]"r"((u64)HOST_RSP), [host_rip]"r"((u64)HOST_RIP) - : "memory", "cc", "rbx", "r8", "r9", "r10", - "r11", "r12", "r13", "r14", "r15"); + : "memory", "cc"); return ret; } =20 --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B028539479E; Mon, 18 May 2026 20:25:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135925; cv=none; b=BxC5//0Mcw1uGcM8JIhf97RO/bXdhX+eZoxbzqX1cKwrgXLYZyZqrZd0RVbPIcIKIEfGvAZzOE3v9a1KISIsCUrpWNtNy6ehuL9B2uhRqxpru1vpZ6mVW3M3j5zOsZ9HfE+5T58yYRY42Q1yNZWzWOlFUUdNUB1HTeiniEh66S8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135925; c=relaxed/simple; bh=T0i6Ik2CmSyrxKdX3wTZoYvO7kQfKV0rVgmsLlT+bZw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WgmUp+aycgsVzvvmF6V+7g3w0QDN3yBZFJHSMd3AjAke3RD4Yi6+i+719x8uc4MyWz2KDgUw8lGhD4dssTxnJ6apFMFEVn3TgUmEQgn9cKbhVo4nOjBN53O52Uy61VzgtRQhnd09zF/rHcozgDtc0Pw2MttiEt/AATwv0izI/zk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ify8YESl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ify8YESl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 407A0C2BCF5; Mon, 18 May 2026 20:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135925; bh=T0i6Ik2CmSyrxKdX3wTZoYvO7kQfKV0rVgmsLlT+bZw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ify8YESlAPgIecdD3XFRF2kc41kTgiRNK6psaxG1FLbCbmWJmDI4AkpXTSBKc+dgT uv4qtmKOTpl5Swb+BI/SuylAJbRfpSyN1PnPf5Aw1LcF4Knk9NmKOSEXYD3LlIDOFl bBq8GZ9lBEyj9B7cUdGKLplZL5JyJS9vUYO6EE8sozR761z+ljuAv33guxnxqxhzo8 QPuVEK4N6YfcKXhbdL9uABJOTbNqDXbVRecz2GR5a9IB3TayBBv5pctQR32KNLS5cr 9sAMzRw5tDK2fJpdOfKfs1bPOQWWa9/gUT68rdye/Y85lcqXOiodNUGNqrsC77MgsT F8u2jXEwoFnjg== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 4/8] KVM: selftests: Drop HORRIFIC_L2_UCALL_CLOBBER_HACK Date: Mon, 18 May 2026 20:25:10 +0000 Message-ID: <20260518202514.2037078-5-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Now that nVMX test codes preserves GPRs across nested VM-Exits (specifically RBP, RDX, and RDI among others), drop the ucall-specific hack to avoid clobbering these registers. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/lib/x86/ucall.c | 32 ++------------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c b/tools/testing/se= lftests/kvm/lib/x86/ucall.c index e7dd5791959ba..38050c60a0670 100644 --- a/tools/testing/selftests/kvm/lib/x86/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86/ucall.c @@ -10,36 +10,8 @@ =20 void ucall_arch_do_ucall(gva_t uc) { - /* - * FIXME: Revert this hack (the entire commit that added it) once nVMX - * preserves L2 GPRs across a nested VM-Exit. If a ucall from L2, e.g. - * to do a GUEST_SYNC(), lands the vCPU in L1, any and all GPRs can be - * clobbered by L1. Save and restore non-volatile GPRs (clobbering RBP - * in particular is problematic) along with RDX and RDI (which are - * inputs), and clobber volatile GPRs. *sigh* - */ -#define HORRIFIC_L2_UCALL_CLOBBER_HACK \ - "rcx", "rsi", "r8", "r9", "r10", "r11" - - asm volatile("push %%rbp\n\t" - "push %%r15\n\t" - "push %%r14\n\t" - "push %%r13\n\t" - "push %%r12\n\t" - "push %%rbx\n\t" - "push %%rdx\n\t" - "push %%rdi\n\t" - "in %[port], %%al\n\t" - "pop %%rdi\n\t" - "pop %%rdx\n\t" - "pop %%rbx\n\t" - "pop %%r12\n\t" - "pop %%r13\n\t" - "pop %%r14\n\t" - "pop %%r15\n\t" - "pop %%rbp\n\t" - : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory", - HORRIFIC_L2_UCALL_CLOBBER_HACK); + asm volatile("in %[port], %%al" + : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory"); } =20 void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 41C943932F1; Mon, 18 May 2026 20:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; cv=none; b=TySyNX2kGfuOtP5N21EtCApTPuO+zWW9kCROvLPr0gCb4IP7oOD0YpPIZgTlcxqSrlHu5Edb5TQQ/VRM+RIw6IVJrelyD4aeMsuP4G+lvEmZK+XlzIjEkfnbSFt5uQ6o6Hc3b3v+f7WDHI/yCTxS9EjkUPJ+gvdi2EFv0oOyvh8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; c=relaxed/simple; bh=HSb47MisDIWaBtAfUVH6Fca2Jw11AUST0u8QouNfSHc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mJtzt2Fjw8nXJ4BPDcdJ8bjLh3FOPpH+U1D9gI+4T+AiibmtxwM6RpnVBohxqoc2o44Xt8P2aurxGl24OcejPNUBByH+GWHOJKlnYyMYeNg1OBlBxvmJ4IGW5a9VfqYqvPBZOxXHz5ZTmepzJ9lwowIy3hSa3YeStkIfk4/Fn8o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JkdirD9J; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JkdirD9J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A3102C2BCC9; Mon, 18 May 2026 20:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135925; bh=HSb47MisDIWaBtAfUVH6Fca2Jw11AUST0u8QouNfSHc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JkdirD9J+vXNvO4QqPJXaTH7aEnM+gmjWN7uLP0hzRt3oGmx23EPVyXzJD2jrZhNW EzlVXq7jL7lMiwgndTHPe02oa/H+sFDQLj9eTgoAFydq95VWgpH2ELdEpMazMm7BG6 XCOmFfAZCvrHk1FIYbj5gKwxFHYfuBhhLBwY0kJhgpxZI6/jatdmz6hz6iVbDVwNY3 eZhsipc1FVxJR0eeLWWk/X4oB2Kz0Fo5xsjbIR5Ch8zYcyoRLDCZrkpJlDYLFUsJIY sSig/8Fxnqtjq2X0+UhkgnO3yYISiemonjaXQ423zYqIvDfNe2lDU55Xp7MWzpt1os vzAIzyU2/Kntg== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 5/8] KVM: selftests: Add basic stress test for save+restore and #PF handling Date: Mon, 18 May 2026 20:25:11 +0000 Message-ID: <20260518202514.2037078-6-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Add a basic stress test for handling #PFs in a guest while the host is doing save+restore cycles. The guest periodically accesses non-present memory causing a #PF, and the #PF handler walks the page tables and updates the PTE to be present, like a proper #PF handler. After every access (and #PF), the guest triggers a sync and the test performs save+restore of the VM. This is not very meaningful as save+restore are performed after the access and #PF handling complete, but following changes will change that. Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/include/x86/processor.h | 15 ++ .../testing/selftests/kvm/lib/x86/processor.c | 11 ++ .../kvm/x86/stress_save_restore_pf_test.c | 171 ++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/stress_save_restore_pf_= test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 82fa943b95038..9327284dd5bbf 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -110,6 +110,7 @@ TEST_GEN_PROGS_x86 +=3D x86/set_sregs_test TEST_GEN_PROGS_x86 +=3D x86/smaller_maxphyaddr_emulation_test TEST_GEN_PROGS_x86 +=3D x86/smm_test TEST_GEN_PROGS_x86 +=3D x86/state_test +TEST_GEN_PROGS_x86 +=3D x86/stress_save_restore_pf_test TEST_GEN_PROGS_x86 +=3D x86/vmx_preemption_timer_test TEST_GEN_PROGS_x86 +=3D x86/svm_vmcall_test TEST_GEN_PROGS_x86 +=3D x86/svm_int_ctl_test diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index ca2ec92490f7c..41bffe031eb88 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -610,6 +610,15 @@ static inline void set_cr0(u64 val) __asm__ __volatile__("mov %0, %%cr0" : : "r" (val) : "memory"); } =20 +static inline u64 get_cr2(void) +{ + u64 cr2; + + __asm__ __volatile__("mov %%cr2, %[cr2]" + : /* output */ [cr2]"=3Dr"(cr2)); + return cr2; +} + static inline u64 get_cr3(void) { u64 cr3; @@ -905,6 +914,11 @@ static inline void write_sse_reg(int reg, const sse128= _t *data) } } =20 +static inline void invlpg(u64 addr) +{ + __asm__ __volatile__("invlpg (%0)" : : "r"(addr) : "memory"); +} + static inline void cpu_relax(void) { asm volatile("rep; nop" ::: "memory"); @@ -1557,6 +1571,7 @@ void __virt_pg_map(struct kvm_vm *vm, struct kvm_mmu = *mmu, gva_t gva, gpa_t gpa, int level); void virt_map_level(struct kvm_vm *vm, gva_t gva, gpa_t gpa, u64 nr_bytes, int level); +void virt_map_page_tables(struct kvm_vm *vm); =20 void vm_enable_tdp(struct kvm_vm *vm); bool kvm_cpu_has_tdp(void); diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testin= g/selftests/kvm/lib/x86/processor.c index caefcd12df8d2..6708fa8b6a304 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -343,6 +343,17 @@ void virt_map_level(struct kvm_vm *vm, gva_t gva, gpa_= t gpa, } } =20 +void virt_map_page_tables(struct kvm_vm *vm) +{ + gpa_t gpa =3D KVM_GUEST_PAGE_TABLE_MIN_PADDR; + struct userspace_mem_region *region; + u64 pt_size; + + region =3D memslot2region(vm, vm->memslots[MEM_REGION_PT]); + pt_size =3D region->region.guest_phys_addr + region->region.memory_size -= gpa; + virt_map(vm, gpa, gpa, pt_size / getpagesize()); +} + static bool vm_is_target_pte(struct kvm_mmu *mmu, u64 *pte, int *level, int current_level) { diff --git a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c = b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c new file mode 100644 index 0000000000000..12da74b4f725c --- /dev/null +++ b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#define NR_ITERATIONS 500 + +#define CURSOR_UP "\033[A" +#define PRINT_ITER(s, x) \ +({ \ + printf("%s\r%s%d\n", (x ? CURSOR_UP : ""), s, x); \ + fflush(stdout); \ +}) + +#define TEST_MEM_BASE 0xc0000000ULL +#define NR_TEST_ADDRS 512 +#define PATTERN 0xabcdefabcdefabcdULL + +#define PTRS_PER_PTE 512 +#define PXD_INDEX(vaddr, level) (((vaddr) >> PG_LEVEL_SHIFT(level)) & (PTR= S_PER_PTE - 1)) + +static u64 pte_present_mask; +static u64 pte_huge_mask; + +static u64 expected_vaddr; +static u64 guest_accesses; + +static u64 *guest_get_pte(u64 vaddr) +{ + u64 *pgd, *p4d, *pud, *pmd, *pte; + u64 pgde, p4de, pude, pmde; + bool la57; + + la57 =3D !!(get_cr4() & X86_CR4_LA57); + pgd =3D (u64 *)(get_cr3() & PHYSICAL_PAGE_MASK); + + if (la57) { + pgde =3D pgd[PXD_INDEX(vaddr, PG_LEVEL_256T)]; + GUEST_ASSERT(pgde & pte_present_mask); + p4d =3D (u64 *)PTE_GET_PA(pgde); + p4de =3D p4d[PXD_INDEX(vaddr, PG_LEVEL_512G)]; + } else { + pgde =3D pgd[PXD_INDEX(vaddr, PG_LEVEL_512G)]; + p4de =3D pgde; + } + + GUEST_ASSERT(p4de & pte_present_mask); + pud =3D (u64 *)PTE_GET_PA(p4de); + + pude =3D pud[PXD_INDEX(vaddr, PG_LEVEL_1G)]; + GUEST_ASSERT(pude & pte_present_mask); + GUEST_ASSERT(!(pude & pte_huge_mask)); + pmd =3D (u64 *)PTE_GET_PA(pude); + + pmde =3D pmd[PXD_INDEX(vaddr, PG_LEVEL_2M)]; + GUEST_ASSERT(pmde & pte_present_mask); + GUEST_ASSERT(!(pmde & pte_huge_mask)); + pte =3D (u64 *)PTE_GET_PA(pmde); + + return &pte[PXD_INDEX(vaddr, PG_LEVEL_4K)]; +} + +static void guest_pf_handler(struct ex_regs *regs) +{ + u64 fault_addr; + u64 *ptep; + + fault_addr =3D get_cr2(); + GUEST_ASSERT_EQ(fault_addr, READ_ONCE(expected_vaddr)); + + ptep =3D guest_get_pte(fault_addr); + GUEST_ASSERT(ptep); + GUEST_ASSERT(!(*ptep & pte_present_mask)); + + *ptep |=3D pte_present_mask; + invlpg(fault_addr); +} + +static void guest_access_memory(void *arg) +{ + u64 vaddr, val; + + for (;; guest_accesses++) { + vaddr =3D TEST_MEM_BASE + (guest_accesses % NR_TEST_ADDRS) * PAGE_SIZE; + WRITE_ONCE(expected_vaddr, vaddr); + + /* Read to trigger #PF */ + val =3D READ_ONCE(*(u64 *)vaddr); + GUEST_ASSERT_EQ(val, PATTERN); + + /* Clear the present bit again so it faults next time */ + *guest_get_pte(vaddr) &=3D ~pte_present_mask; + invlpg(vaddr); + + GUEST_SYNC(guest_accesses); + } +} + +int main(int argc, char *argv[]) +{ + struct kvm_x86_state *state; + struct kvm_vcpu *vcpu; + int r, i, count =3D 0; + struct kvm_vm *vm; + struct ucall uc; + gva_t gva; + gpa_t gpa; + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_access_memory); + vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); + + pte_present_mask =3D PTE_PRESENT_MASK(&vm->mmu); + pte_huge_mask =3D PTE_HUGE_MASK(&vm->mmu); + sync_global_to_guest(vm, pte_present_mask); + sync_global_to_guest(vm, pte_huge_mask); + + /* Allocate a page and write the pattern to it */ + gva =3D vm_alloc_page(vm); + *(u64 *)addr_gva2hva(vm, gva) =3D PATTERN; + gpa =3D addr_gva2gpa(vm, gva); + + /* + * Map all virtual addresses to the pattern page and clear the present + * bit such that guest accesses will cause a #PF. + */ + for (i =3D 0; i < NR_TEST_ADDRS; i++) { + gva =3D TEST_MEM_BASE + i * getpagesize(); + virt_pg_map(vm, gva, gpa); + *vm_get_pte(vm, gva) &=3D ~pte_present_mask; + } + + /* Map the page tables so that the guest #PF handler can walk them */ + virt_map_page_tables(vm); + + while (count++ < NR_ITERATIONS) { + r =3D __vcpu_run(vcpu); + TEST_ASSERT(!r, "vcpu_run failed"); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + get_ucall(vcpu, &uc); + if (uc.cmd =3D=3D UCALL_ABORT) { + REPORT_GUEST_ASSERT(uc); + break; + } + TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); + TEST_ASSERT_EQ(uc.args[1], count - 1); + + state =3D vcpu_save_state(vcpu); + + kvm_vm_release(vm); + vcpu =3D vm_recreate_with_one_vcpu(vm); + vcpu_load_state(vcpu, state); + kvm_x86_state_cleanup(state); + + PRINT_ITER("Save+restore iterations: ", count); + } + + sync_global_from_guest(vm, guest_accesses); + pr_info("Guest page accesses: %lu\n", guest_accesses); + + kvm_vm_free(vm); + return 0; +} --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 68E15396591; Mon, 18 May 2026 20:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; cv=none; b=i4Qgpbe/ZWA67N2XLmNyuMcuWgROp5DNdUYfUvhd6+oj/GMnzB5M3PgxVM6nQCTjSOWGjuwoMMNPTtLZlqIBUpqQdrswSodo7SK4q3d9yNjAr8oCQhQhgHo7MzBJxVTn/CI75bq+bzW/tVqjBwWOwBX8itI+wrcKotS4PKlpSeg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; c=relaxed/simple; bh=mAo+nNH9B73epRdJSYz4wQGFb0T3sYNTm3+FkEL+Dl8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P1hlfJq0e0qgEHjkbDlXT8JnqH4Hepr3kFyPew66zhCJM6xU/cCYCO8mdz6Gwc0p1+2d7VJVBwAAxPtj0DWZuznm/OYN3gJfMS6tLDRoed05BiUXNWTKckvC7JRv1dujqkYjYtb6esjKHBpsXEN9N6Ps+1EhwlG8HVca/+sAuIU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GLLyCX9H; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GLLyCX9H" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1163EC2BCC6; Mon, 18 May 2026 20:25:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135926; bh=mAo+nNH9B73epRdJSYz4wQGFb0T3sYNTm3+FkEL+Dl8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GLLyCX9H4Kr4vbiBMGoOMN6XW1G7e6nsrqa89blRaChUBFByh/bleDRfMF6FmJy6o EJfFK9s1yNkRWs2Gw8xIKOPTSDtPDrzVxY4g1m48BQ4wVMJrbGwlXkv39Fpe4e0iUT jxmb0eJYBomlPi5jXUxnC0OJ1L8SJTopzTNqDFyvxACUthrxK7UmlQDS6B1E0Bk6BX IBEDw1yLXQZL9+jz6NvAGWH6IYqRub9FwgvrnG3KOryOVQumH3+rhjtjowUBS1at+O tH3Yv1GhMq//khljfbvdGVGcp52YW7OPdVopiQ9xbWor56sPCCAbr8061I9M3FqbWA rjQOLAJRFkhKw== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 6/8] KVM: selftests: Trigger save+restore randomly in the #PF stress test Date: Mon, 18 May 2026 20:25:12 +0000 Message-ID: <20260518202514.2037078-7-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Instead of an explicit GUEST_SYNC() after each access+#PF, run another thread that keeps sending SIGUSR to the vCPU thread, essentially triggering exits to userspace and save+restore on random points in guest execution. This makes the test a lot more meaningful as it opens the door to exercising race conditions between #PF handling in the guest and save+restore in the host. The signals are ignored using SIG_IGN outside of __vcpu_run() to avoid interrupting other ioctls/sysctls performed by the test. Signed-off-by: Yosry Ahmed --- .../kvm/x86/stress_save_restore_pf_test.c | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c = b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c index 12da74b4f725c..60a013e0f14fb 100644 --- a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c +++ b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include =20 #include "test_util.h" @@ -99,14 +101,40 @@ static void guest_access_memory(void *arg) /* Clear the present bit again so it faults next time */ *guest_get_pte(vaddr) &=3D ~pte_present_mask; invlpg(vaddr); + } +} + +static void *sigusr_thread_fn(void *arg) +{ + pthread_t vcpu_thread =3D (pthread_t)arg; =20 - GUEST_SYNC(guest_accesses); + for (;;) { + pthread_testcancel(); + pthread_kill(vcpu_thread, SIGUSR1); + usleep(100); } + return NULL; +} + +static void dummy_signal_handler(int signo) {} +static struct sigaction sa; + +static void vcpu_sigusr_listen(void) +{ + sa.sa_handler =3D dummy_signal_handler; + sigaction(SIGUSR1, &sa, NULL); +} + +static void vcpu_sigusr_ignore(void) +{ + sa.sa_handler =3D SIG_IGN; + sigaction(SIGUSR1, &sa, NULL); } =20 int main(int argc, char *argv[]) { struct kvm_x86_state *state; + pthread_t sigusr_thread; struct kvm_vcpu *vcpu; int r, i, count =3D 0; struct kvm_vm *vm; @@ -140,18 +168,28 @@ int main(int argc, char *argv[]) /* Map the page tables so that the guest #PF handler can walk them */ virt_map_page_tables(vm); =20 + /* Initialize the thread sending SIGUSR and install the handler */ + pthread_create(&sigusr_thread, NULL, sigusr_thread_fn, + (void *)pthread_self()); + while (count++ < NR_ITERATIONS) { + /* + * Only handle SIGUSR while the vCPU is running, otherwise + * ignore it to avoid interrupting other ioctls/syscalls. + */ + vcpu_sigusr_listen(); r =3D __vcpu_run(vcpu); - TEST_ASSERT(!r, "vcpu_run failed"); - TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); - - get_ucall(vcpu, &uc); - if (uc.cmd =3D=3D UCALL_ABORT) { + if (r =3D=3D -1) + TEST_ASSERT_EQ(errno, EINTR); + vcpu_sigusr_ignore(); + + /* The guest only exists due to a signal or failed assertion */ + if (!r) { + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_ABORT); REPORT_GUEST_ASSERT(uc); break; } - TEST_ASSERT_EQ(uc.cmd, UCALL_SYNC); - TEST_ASSERT_EQ(uc.args[1], count - 1); =20 state =3D vcpu_save_state(vcpu); =20 @@ -166,6 +204,8 @@ int main(int argc, char *argv[]) sync_global_from_guest(vm, guest_accesses); pr_info("Guest page accesses: %lu\n", guest_accesses); =20 + pthread_cancel(sigusr_thread); + pthread_join(sigusr_thread, NULL); kvm_vm_free(vm); return 0; } --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 CB30F397E81; Mon, 18 May 2026 20:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; cv=none; b=lkpH/04sa1817msFJC3/yb/jpEd3PSNpitIhsSOSGNE7A+bofcOPXZp4IH91fNcWY8hbmMDXjfYXP/AAgJxzX5lGFC+AzGXn81gQGCWJW6Kg2DiuYD9pyqxFZGcp1YgpRBqs06zNepmdbpz0obSv3uxzOjsFUC4C28pBLCkJcP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135926; c=relaxed/simple; bh=3W1mqMj3S3aKcUENCuMkekxQJwZQe9cxUP021hxxxmk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=plWqVBCMd/QVPiAVwgEV94hQYaTtaEn7NQIi4sewj2Kz1lSam98RV+iybL7Zbr53r7meO1rvATkDcv01KJVebVXo1aBfuyHvG5+v9RglP5EglDza4hvBDDEQEHbnUUeC2wTu1aqtbuCEkeKd5L0YHx/ztlan2Q51nk99EBpeX4I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OZcfQyPI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OZcfQyPI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 73DB1C2BCF6; Mon, 18 May 2026 20:25:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135926; bh=3W1mqMj3S3aKcUENCuMkekxQJwZQe9cxUP021hxxxmk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OZcfQyPI2PDjZOPrvDruwHit2hMiyPaPDTRyBt6SE3c9DnMXcmYrCD97XYzU9ZWmQ Odbl5qY4dP5HTenO3BkZ5fY+nRchwQ83diNSBX00ItyZmE+q7OUYR/brRNfHRikk15 o6Lezeqa2nLbwa0sDQo1eTLLOd/To46lfbQfc7NBJvEyluFdBtZAvSGKs9JZP1f7Dc H+dEIzntxK7clIbBlKOHGwDxyjBAitLzAS9vXg7fF+BUvZSglEJ9f/mFT9O4piQr7R 1MuPc1k4SziaGJ9cz1Xnporv8XTWZQBN7gi0gNCns8QPIum9VB0f4suYDBCGXArvug Dzc9xkSX2Ying== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 7/8] KVM: selftests: Support running stress save+restore and #PF test in L2 Date: Mon, 18 May 2026 20:25:13 +0000 Message-ID: <20260518202514.2037078-8-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Extend the stress test to allow running the access+#PF code in L2 instead of L1 by adding proper L1 guest code to bootstrap L2. The test runs in nested mode if a '-n' flag is added. Signed-off-by: Yosry Ahmed --- .../kvm/x86/stress_save_restore_pf_test.c | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c = b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c index 60a013e0f14fb..ec3d36d6e4846 100644 --- a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c +++ b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c @@ -8,10 +8,13 @@ #include #include #include +#include =20 #include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "svm_util.h" +#include "vmx.h" =20 #define NR_ITERATIONS 500 =20 @@ -26,6 +29,8 @@ #define NR_TEST_ADDRS 512 #define PATTERN 0xabcdefabcdefabcdULL =20 +#define L2_GUEST_STACK_SIZE 64 + #define PTRS_PER_PTE 512 #define PXD_INDEX(vaddr, level) (((vaddr) >> PG_LEVEL_SHIFT(level)) & (PTR= S_PER_PTE - 1)) =20 @@ -104,6 +109,41 @@ static void guest_access_memory(void *arg) } } =20 +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + generic_svm_setup(svm, guest_access_memory, &l2_guest_stack[L2_GUEST_STAC= K_SIZE]); + + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(false); +} + +static void l1_vmx_code(struct vmx_pages *vmx) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx)); + GUEST_ASSERT(load_vmcs(vmx)); + prepare_vmcs(vmx, guest_access_memory, &l2_guest_stack[L2_GUEST_STACK_SIZ= E]); + + /* Ignore any #PF */ + GUEST_ASSERT(!vmwrite(EXCEPTION_BITMAP, BIT(PF_VECTOR))); + GUEST_ASSERT(!vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0)); + GUEST_ASSERT(!vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, -1)); + + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(false); +} + +static void l1_guest_code(void *test_data) +{ + if (this_cpu_has(X86_FEATURE_SVM)) + l1_svm_code(test_data); + else + l1_vmx_code(test_data); +} + static void *sigusr_thread_fn(void *arg) { pthread_t vcpu_thread =3D (pthread_t)arg; @@ -131,6 +171,25 @@ static void vcpu_sigusr_ignore(void) sigaction(SIGUSR1, &sa, NULL); } =20 +static bool parse_args_nested(int argc, char *argv[]) +{ + bool nested =3D false; + int opt; + + while ((opt =3D getopt(argc, argv, "n")) !=3D -1) { + switch (opt) { + case 'n': + nested =3D true; + break; + default: + printf("Usage: %s [-n]\n", argv[0]); + exit(1); + } + } + + return nested; +} + int main(int argc, char *argv[]) { struct kvm_x86_state *state; @@ -139,12 +198,24 @@ int main(int argc, char *argv[]) int r, i, count =3D 0; struct kvm_vm *vm; struct ucall uc; + bool nested; gva_t gva; gpa_t gpa; =20 - vm =3D vm_create_with_one_vcpu(&vcpu, guest_access_memory); + nested =3D parse_args_nested(argc, argv); + + vm =3D vm_create_with_one_vcpu(&vcpu, nested ? l1_guest_code : guest_acce= ss_memory); vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); =20 + if (nested) { + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM) || kvm_cpu_has(X86_FEATURE_VMX= )); + if (kvm_cpu_has(X86_FEATURE_SVM)) + vcpu_alloc_svm(vm, &gva); + else + vcpu_alloc_vmx(vm, &gva); + vcpu_args_set(vcpu, 1, gva); + } + pte_present_mask =3D PTE_PRESENT_MASK(&vm->mmu); pte_huge_mask =3D PTE_HUGE_MASK(&vm->mmu); sync_global_to_guest(vm, pte_present_mask); @@ -202,7 +273,7 @@ int main(int argc, char *argv[]) } =20 sync_global_from_guest(vm, guest_accesses); - pr_info("Guest page accesses: %lu\n", guest_accesses); + pr_info("Guest page accesses%s: %lu\n", nested ? " (from L2)" : "", guest= _accesses); =20 pthread_cancel(sigusr_thread); pthread_join(sigusr_thread, NULL); --=20 2.54.0.563.g4f69b47b94-goog From nobody Mon May 25 04:34:02 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 4D198392837; Mon, 18 May 2026 20:25:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135927; cv=none; b=bSPizq8G4oOBb5r2h73+5MlFg1tWjjGfRBys0MYMhUOSlyjdlOwxrbXvc9i3/NDGpgeJIIn7pb8b7NC2309SfS8Fg1ODeOzBJa3Z+992G6RZ4VcyHVoZZz6sC9wrvs+Np0+VGD7qFITOggSaarqhyy7Se3Wm4pbzgvPpHMlNQXw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779135927; c=relaxed/simple; bh=dTzJGsHSZ8xqNjuDFrBzWN7hB/SUmhWgE/soZ0ivTrc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ebdXCREpHT1yZVc0Zx0zghFooWNtag90JLg+L+l/z3ke0LLFcClBFV9iJa0RtRXjWBkeDaNrFwkN/7in1O7ZSXOd0L3vQHFbi2/NS2VnbRPG+rcXE0AIdlkJ/KnzE8rgwgzNvwhM4NY1gJqgiiVyiGt2KWB3nIE8C0UB4wag5VY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WgS0Xnag; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WgS0Xnag" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D7284C2BCC6; Mon, 18 May 2026 20:25:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1779135927; bh=dTzJGsHSZ8xqNjuDFrBzWN7hB/SUmhWgE/soZ0ivTrc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WgS0Xnagi5hvlqRSd1uaKL28Dup8ukB6XofSFo1/iq3XVPFahNA3301Bl8KrPVVTB uwxWZMinPC3B1l42OooiSOckKNEidbHew9Esa5uyCo2KxaHH0R4gJW/ft4KifnnslI JBGhKOrsFfe5DheeSdMBN5B2b2jBt2vTv0jddYaYW5HSBQ9Lem5fGtwnyhpqVnqNpz VZ/1OUHn5GqKTZZS+RoEgYrxDIZbO1Sd5qbjliRhXRP8G+txx6uT1asReHmZD/+Ku6 vVEulaGvDNJlWv1AfNBF/4esy7AgA3SansaD2t8XWtVPSlhk2rjXIQ8D20i74U4Kni euYZf61oCUxrA== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed , Yosry Ahmed Subject: [PATCH 8/8] KVM: selftests: Trigger L2->L1 exits stress save+restore and #PF test Date: Mon, 18 May 2026 20:25:14 +0000 Message-ID: <20260518202514.2037078-9-yosry@kernel.org> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog In-Reply-To: <20260518202514.2037078-1-yosry@kernel.org> References: <20260518202514.2037078-1-yosry@kernel.org> 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 Content-Type: text/plain; charset="utf-8" From: Yosry Ahmed Extend the testing coverage in L2 by injecting a #UD into the vCPU every other iteration during restore, and intercepting #UD from L1, essentially forcing an L2 -> L1 VM-Exit directly after save+restore. With this change, the test reliably reproduces the CR2 bug fixed by commit 5c247d08bc81 ("KVM: nSVM: Use vcpu->arch.cr2 when updating vmcb12 on nested #VMEXIT") -- at least on Milan, Genoa, and Turin CPUs. Signed-off-by: Yosry Ahmed --- .../kvm/x86/stress_save_restore_pf_test.c | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c = b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c index ec3d36d6e4846..e977d9786e392 100644 --- a/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c +++ b/tools/testing/selftests/kvm/x86/stress_save_restore_pf_test.c @@ -115,8 +115,12 @@ static void l1_svm_code(struct svm_test_data *svm) =20 generic_svm_setup(svm, guest_access_memory, &l2_guest_stack[L2_GUEST_STAC= K_SIZE]); =20 - run_guest(svm->vmcb, svm->vmcb_gpa); - GUEST_ASSERT(false); + svm->vmcb->control.intercept_exceptions |=3D BIT(UD_VECTOR); + + while (1) { + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, (SVM_EXIT_EXCP_BASE + UD_V= ECTOR)); + } } =20 static void l1_vmx_code(struct vmx_pages *vmx) @@ -127,13 +131,17 @@ static void l1_vmx_code(struct vmx_pages *vmx) GUEST_ASSERT(load_vmcs(vmx)); prepare_vmcs(vmx, guest_access_memory, &l2_guest_stack[L2_GUEST_STACK_SIZ= E]); =20 - /* Ignore any #PF */ - GUEST_ASSERT(!vmwrite(EXCEPTION_BITMAP, BIT(PF_VECTOR))); + /* Intercept UD, ignore any #PF */ + GUEST_ASSERT(!vmwrite(EXCEPTION_BITMAP, BIT(UD_VECTOR) | BIT(PF_VECTOR))); GUEST_ASSERT(!vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0)); GUEST_ASSERT(!vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, -1)); =20 GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(false); + while (1) { + GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); + GUEST_ASSERT_EQ(vmreadz(VM_EXIT_INTR_INFO) & 0xff, UD_VECTOR); + GUEST_ASSERT(!vmresume()); + } } =20 static void l1_guest_code(void *test_data) @@ -171,6 +179,23 @@ static void vcpu_sigusr_ignore(void) sigaction(SIGUSR1, &sa, NULL); } =20 +static bool vcpu_state_is_guest_mode(struct kvm_x86_state *state) +{ + return !!(state->nested.flags & KVM_STATE_NESTED_GUEST_MODE); +} + +static void vcpu_state_inject_ud(struct kvm_x86_state *state) +{ + if (state->events.exception.pending || state->events.exception.injected) + return; + + state->events.flags |=3D KVM_VCPUEVENT_VALID_PAYLOAD; + state->events.exception.pending =3D true; + state->events.exception.injected =3D false; + state->events.exception.nr =3D UD_VECTOR; + state->events.exception.has_error_code =3D false; +} + static bool parse_args_nested(int argc, char *argv[]) { bool nested =3D false; @@ -202,10 +227,13 @@ int main(int argc, char *argv[]) gva_t gva; gpa_t gpa; =20 + TEST_REQUIRE(kvm_has_cap(KVM_CAP_EXCEPTION_PAYLOAD)); + nested =3D parse_args_nested(argc, argv); =20 vm =3D vm_create_with_one_vcpu(&vcpu, nested ? l1_guest_code : guest_acce= ss_memory); vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); + vm_enable_cap(vm, KVM_CAP_EXCEPTION_PAYLOAD, -2ul); =20 if (nested) { TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM) || kvm_cpu_has(X86_FEATURE_VMX= )); @@ -264,8 +292,18 @@ int main(int argc, char *argv[]) =20 state =3D vcpu_save_state(vcpu); =20 + /* + * If the vCPU is in guest mode, inject a #UD to trigger an + * L2->L1 VM-Exit every other iteration. + */ + if (vcpu_state_is_guest_mode(state) && count % 2 =3D=3D 0) { + TEST_ASSERT(nested, "Unexpected guest mode"); + vcpu_state_inject_ud(state); + } + kvm_vm_release(vm); vcpu =3D vm_recreate_with_one_vcpu(vm); + vm_enable_cap(vm, KVM_CAP_EXCEPTION_PAYLOAD, -2ul); vcpu_load_state(vcpu, state); kvm_x86_state_cleanup(state); =20 --=20 2.54.0.563.g4f69b47b94-goog