From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 B0E124519B3; Mon, 14 Sep 2026 12:26:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388804; cv=none; b=RXMUhe5oohFU2/SMoQnd7Xu49McWDWGwFEv2eGOLdMAWWldCE2FwJ6lhx34w0lkGqVk/UCz8zpibmzKwTlhMu/xRvKVsTtzq65DZMbYZjnI4YIAh7jk/SpAid3xHdH6oTv/5YyeMz1oz7pwBJ8XV3SMB/JOBiRK+IevHf0G3Bg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388804; c=relaxed/simple; bh=FkM4itvypge8Pbdv2hNT3etSW8HCq6WaKSFba5FDN3g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UEXOJkPWBMBrzEc8AvKhsnpqulfre8kmdxCF/zdB6PCqC6TyrwJGzopYJEUATZTyiD3byzyi0DGB1joOYe7yDYQK0QzfbvKyWIIx+n4FSBlJgnYqPA90zfjhmm7qAjdWIJ5FuJKfS54BVFMcT5ZM7UPJTtIl6cEcACASJVEFNZw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=evBgVX9f; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="evBgVX9f" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F11201F00893; Mon, 14 Sep 2026 12:26:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388802; bh=IltVU/Tm8cDWFzMWlzQM5EZpC+rhcddrPgEAjZb7DaQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=evBgVX9fcgctqjU/P4XLiikqSwC3qJATbp1xuK0PDwxm6u/W7htpP8UpqTrCABPzI qMP8MUGiPYv1A/E8mgbWkRakxNRFRrF1ms8HdfeRnR6lnvHNNRnBLQ1edf8Wp1fQoy Irbl3a3yeoeErjBBDfodEwVP0JOnMTE416m0/CF7duUHBzy2oEK0zO8SMgtsejoVOT dxpHB+/RP9NwrsHoQWOIIFMCHmns3Dj5kuD8U8LR5/bsqCYAGPVK9FpeZbZtZClqfS GOLRYyV00Vti9L39D31cytbIKFH2sIf3+IsnVAYPvFiYhfgLgYo/xG7qs6S4XTrHmX 2ZP6iUNJMrNxg== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:12 +0100 Subject: [PATCH v2 01/13] arm64: Add ESR fault helpers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-1-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2048; i=ljs@kernel.org; h=from:subject:message-id; bh=FkM4itvypge8Pbdv2hNT3etSW8HCq6WaKSFba5FDN3g=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/8SOunBN559SX9WX5hiINcvMcuk9NwJpzN8690FV KMFtnFO7yhlYRDjYpAVU2R5/kV8f5BI2LzOC/5uMHNYmUCGMHBxCsBEjNYw/He+Jlh/cNXL/lW+ xUvsxPgnK5YtLT/xbodZUeC9debPl7oyMnw85LPo450cJbagUvHrrWGBG632f1XerR52Qmd9wdI 5N7kA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Add helper functions which operate directly on an ESR value rather than trying to access the register itself. These mirror equivalent KVM vCPU wrappers in kvm_emulate.h and allow those wrappers and KVM's stage-2 fault handling to operate on a plain ESR value. This is needed to later generate a synthetic fault for the stage-2 page table pre-faulting mechanism. No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/include/asm/esr.h | 44 ++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index f816f5d77f1a..9c0205983d9a 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -437,6 +437,50 @@ #ifndef __ASSEMBLER__ #include =20 +static __always_inline u8 esr_get_ec(unsigned long esr) +{ + return ESR_ELx_EC(esr); +} + +static __always_inline bool esr_trap_is_iabt(unsigned long esr) +{ + return esr_get_ec(esr) =3D=3D ESR_ELx_EC_IABT_LOW; +} + +static __always_inline bool esr_abt_is_s1ptw(unsigned long esr) +{ + return esr & ESR_ELx_S1PTW; +} + +/* Always check for S1PTW *before* using this. */ +static __always_inline bool esr_dabt_is_write(unsigned long esr) +{ + return esr & ESR_ELx_WNR; +} + +static __always_inline bool esr_dabt_is_cm(unsigned long esr) +{ + return esr & ESR_ELx_CM; +} + +static __always_inline bool esr_abt_is_exec_fault(unsigned long esr) +{ + return esr_trap_is_iabt(esr) && !esr_abt_is_s1ptw(esr); +} + +static __always_inline bool esr_abt_is_sea(unsigned long esr) +{ + switch (esr & ESR_ELx_FSC) { + case ESR_ELx_FSC_EXTABT: + case ESR_ELx_FSC_SEA_TTW(-1) ... ESR_ELx_FSC_SEA_TTW(3): + case ESR_ELx_FSC_SECC: + case ESR_ELx_FSC_SECC_TTW(-1) ... ESR_ELx_FSC_SECC_TTW(3): + return true; + default: + return false; + } +} + static inline unsigned long esr_brk_comment(unsigned long esr) { return esr & ESR_ELx_BRK64_ISS_COMMENT_MASK; --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 01DAC44A3F8; Mon, 14 Sep 2026 12:26:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388811; cv=none; b=mrCxeZeOgy+zH5mfFaw7aIu/oKTGbgwrBT1mMhAXZYvLIj9xTOD/qHrKxyE2gCnoVWMqGVd18VxqmyYHBlBrO9UnCGSmMpp+UuUrM1C7JAThbkxTFCJ/FafdKt1ZCLeOFdQlq3i6M12fODhvaZfpwtzMdlw6wCC8DYwor7jShuc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388811; c=relaxed/simple; bh=fIq7c7NosQluNd1wcSt3bKR0J0yMAk54TnpDrLsyF14=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jBl/qhP6YX3BD4zlCZSjHMcZqwxX5L7+BSRIV+HwOzU7u6zVjSr4m0SbRqhqHbVHCHYqYbspXDTDwY02XOsox6lba7SEMtJig2M1h/SWqtgyfkcq6F93MeMJ7VrijfnfvmzaC4ggOLW4pyfUcLib1RU8IydI0j+lyJp4rni/kxQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=c0gNSMNr; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="c0gNSMNr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CD7B11F000FF; Mon, 14 Sep 2026 12:26:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388808; bh=7hHvSdejwspFN3tARjyhrRDDM0g+bZnTuzQzER/4tyI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=c0gNSMNr9hy1e4CtRubKuQQd4Fi15rc90CqFs8OYUia4kTtS4y3kP18HmwuhuTIHp 1NZP2ddIU5otSn8laEWJhWGN66TolylvtmlgxcQbI//pAtSkSCo5mouGaNQV1uNaeh Qf/LFbRn16j0aSYMxlGsyq6XbkAarX4nad9lTBYseUSpjLR2UOWoNCkWrHXvLfPI3c j4itilX5MOelV7wonjR/1ptQcAsfcB2rnbzuWHmbmwl4NVEordJsSYBXj6gSsVDdeX p4qDzhJlQPmqkaxFusE5qv2zoVE8ABJicK7GydiCb5IsC1q7UML1KfszGFWgUkNgBx 1/Hk6hdJBaf4w== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:13 +0100 Subject: [PATCH v2 02/13] KVM: arm64: Use ESR helpers in guest abort handling Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-2-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=12281; i=ljs@kernel.org; h=from:subject:message-id; bh=fIq7c7NosQluNd1wcSt3bKR0J0yMAk54TnpDrLsyF14=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/+ieJtHaXlDw3WB13w57is+CNWoOLcYr+9uPLCmf NPJm2udOkpZGMS4GGTFFFmefxHfHyQSNq/zgr8bzBxWJpAhDFycAjCR6jxGhnt/2H/a5ZXmf7J5 NKd6998CmS9LTXnvnZryQdf6y+vFobcYGfbPCHnOpMb2ad6ZjAbrT+rVIRPe7d/EPC1XWJabR8S qnwMA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Convert kvm_vcpu_* ESR wrappers in kvm_emulate.h and the stage-2 abort handling logic in mmu.c to use the newly introduced ESR helpers. kvm_is_write_fault() is split in two, with esr_abt_is_write_fault() handling the esr parts of the operation and kvm_is_write_fault() wraps it. Introduce/modify kvm_s2_fault_is_{perm,exec,write}(), kvm_s2_perm_fault_granule() so the abort path reads the ESR from a single place. This is to allow a later change to permit stage 2 pre-faulting via a synthetic ESR value. Remove now-unused kvm_vcpu_dabt_is_cm(), kvm_vcpu_trap_is_exec_fault() and kvm_vcpu_trap_get_perm_fault_granule(). No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/include/asm/kvm_emulate.h | 52 +++++++----------------- arch/arm64/kvm/mmu.c | 76 ++++++++++++++++++++++----------= ---- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/= kvm_emulate.h index a3c1928bdf74..a3b272265554 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -411,18 +411,13 @@ static __always_inline int kvm_vcpu_dabt_get_rd(const= struct kvm_vcpu *vcpu) =20 static __always_inline bool kvm_vcpu_abt_iss1tw(const struct kvm_vcpu *vcp= u) { - return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_S1PTW); + return esr_abt_is_s1ptw(kvm_vcpu_get_esr(vcpu)); } =20 /* Always check for S1PTW *before* using this. */ static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *v= cpu) { - return kvm_vcpu_get_esr(vcpu) & ESR_ELx_WNR; -} - -static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu) -{ - return !!(kvm_vcpu_get_esr(vcpu) & ESR_ELx_CM); + return esr_dabt_is_write(kvm_vcpu_get_esr(vcpu)); } =20 static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_= vcpu *vcpu) @@ -438,17 +433,12 @@ static __always_inline bool kvm_vcpu_trap_il_is32bit(= const struct kvm_vcpu *vcpu =20 static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *v= cpu) { - return ESR_ELx_EC(kvm_vcpu_get_esr(vcpu)); + return esr_get_ec(kvm_vcpu_get_esr(vcpu)); } =20 static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_trap_get_class(vcpu) =3D=3D ESR_ELx_EC_IABT_LOW; -} - -static inline bool kvm_vcpu_trap_is_exec_fault(const struct kvm_vcpu *vcpu) -{ - return kvm_vcpu_trap_is_iabt(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu); + return esr_trap_is_iabt(kvm_vcpu_get_esr(vcpu)); } =20 static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *v= cpu) @@ -468,26 +458,9 @@ bool kvm_vcpu_trap_is_translation_fault(const struct k= vm_vcpu *vcpu) return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu)); } =20 -static inline -u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu) -{ - unsigned long esr =3D kvm_vcpu_get_esr(vcpu); - - BUG_ON(!esr_fsc_is_permission_fault(esr)); - return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL)); -} - static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu) { - switch (kvm_vcpu_trap_get_fault(vcpu)) { - case ESR_ELx_FSC_EXTABT: - case ESR_ELx_FSC_SEA_TTW(-1) ... ESR_ELx_FSC_SEA_TTW(3): - case ESR_ELx_FSC_SECC: - case ESR_ELx_FSC_SECC_TTW(-1) ... ESR_ELx_FSC_SECC_TTW(3): - return true; - default: - return false; - } + return esr_abt_is_sea(kvm_vcpu_get_esr(vcpu)); } =20 static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu) @@ -496,9 +469,9 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct k= vm_vcpu *vcpu) return ESR_ELx_SYS64_ISS_RT(esr); } =20 -static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu) +static inline bool esr_abt_is_write_fault(unsigned long esr) { - if (kvm_vcpu_abt_iss1tw(vcpu)) { + if (esr_abt_is_s1ptw(esr)) { /* * Only a permission fault on a S1PTW should be * considered as a write. Otherwise, page tables baked @@ -511,13 +484,18 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu= *vcpu) * first), then a permission fault to allow the flags * to be set. */ - return kvm_vcpu_trap_is_permission_fault(vcpu); + return esr_fsc_is_permission_fault(esr); } =20 - if (kvm_vcpu_trap_is_iabt(vcpu)) + if (esr_trap_is_iabt(esr)) return false; =20 - return kvm_vcpu_dabt_iswrite(vcpu); + return esr_dabt_is_write(esr); +} + +static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu) +{ + return esr_abt_is_write_fault(kvm_vcpu_get_esr(vcpu)); } =20 static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 74e7e7f7564c..d1a6e25c3095 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1605,10 +1605,35 @@ struct kvm_s2_fault_desc { unsigned long hva; }; =20 +static bool kvm_s2_fault_is_perm(const struct kvm_s2_fault_desc *s2fd) +{ + return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(s2fd->vcpu)); +} + +static bool kvm_s2_fault_is_exec(const struct kvm_s2_fault_desc *s2fd) +{ + return esr_abt_is_exec_fault(kvm_vcpu_get_esr(s2fd->vcpu)); +} + +static bool kvm_s2_fault_is_write(const struct kvm_s2_fault_desc *s2fd) +{ + return esr_abt_is_write_fault(kvm_vcpu_get_esr(s2fd->vcpu)); +} + +static u64 kvm_s2_perm_fault_granule(const struct kvm_s2_fault_desc *s2fd) +{ + u64 level; + + if (!kvm_s2_fault_is_perm(s2fd)) + return 0; + level =3D kvm_vcpu_get_esr(s2fd->vcpu) & ESR_ELx_FSC_LEVEL; + return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)); +} + static int gmem_abort(const struct kvm_s2_fault_desc *s2fd) { bool write_fault, exec_fault; - bool perm_fault =3D kvm_vcpu_trap_is_permission_fault(s2fd->vcpu); + bool perm_fault =3D kvm_s2_fault_is_perm(s2fd); enum kvm_pgtable_walk_flags flags =3D KVM_PGTABLE_WALK_SHARED; enum kvm_pgtable_prot prot =3D KVM_PGTABLE_PROT_R; struct kvm_pgtable *pgt =3D s2fd->vcpu->arch.hw_mmu->pgt; @@ -1632,8 +1657,8 @@ static int gmem_abort(const struct kvm_s2_fault_desc = *s2fd) else gfn =3D s2fd->fault_ipa >> PAGE_SHIFT; =20 - write_fault =3D kvm_is_write_fault(s2fd->vcpu); - exec_fault =3D kvm_vcpu_trap_is_exec_fault(s2fd->vcpu); + write_fault =3D kvm_s2_fault_is_write(s2fd); + exec_fault =3D kvm_s2_fault_is_exec(s2fd); =20 VM_WARN_ON_ONCE(write_fault && exec_fault); =20 @@ -1840,11 +1865,6 @@ static short kvm_s2_resolve_vma_size(const struct kv= m_s2_fault_desc *s2fd, return vma_shift; } =20 -static bool kvm_s2_fault_is_perm(const struct kvm_s2_fault_desc *s2fd) -{ - return kvm_vcpu_trap_is_permission_fault(s2fd->vcpu); -} - static int kvm_s2_fault_get_vma_info(const struct kvm_s2_fault_desc *s2fd, struct kvm_s2_fault_vma_info *s2vi) { @@ -1910,7 +1930,7 @@ static int kvm_s2_fault_pin_pfn(const struct kvm_s2_f= ault_desc *s2fd, return ret; =20 s2vi->pfn =3D __kvm_faultin_pfn(s2fd->memslot, get_canonical_gfn(s2fd, s2= vi), - kvm_is_write_fault(s2fd->vcpu) ? FOLL_WRITE : 0, + kvm_s2_fault_is_write(s2fd) ? FOLL_WRITE : 0, &s2vi->map_writable, &s2vi->page); if (unlikely(is_error_noslot_pfn(s2vi->pfn))) { if (s2vi->pfn =3D=3D KVM_PFN_ERR_HWPOISON) { @@ -1968,7 +1988,7 @@ static int kvm_s2_fault_compute_prot(const struct kvm= _s2_fault_desc *s2fd, { struct kvm *kvm =3D s2fd->vcpu->kvm; =20 - if (kvm_vcpu_trap_is_exec_fault(s2fd->vcpu) && s2vi->map_non_cacheable) + if (kvm_s2_fault_is_exec(s2fd) && s2vi->map_non_cacheable) return -ENOEXEC; =20 /* @@ -1986,13 +2006,13 @@ static int kvm_s2_fault_compute_prot(const struct k= vm_s2_fault_desc *s2fd, =20 if (s2vi->map_writable && (s2vi->device || !memslot_is_logging(s2fd->memslot) || - kvm_is_write_fault(s2fd->vcpu))) + kvm_s2_fault_is_write(s2fd))) *prot |=3D KVM_PGTABLE_PROT_W; =20 if (s2fd->nested) *prot =3D adjust_nested_fault_perms(s2fd->nested, *prot); =20 - if (kvm_vcpu_trap_is_exec_fault(s2fd->vcpu)) + if (kvm_s2_fault_is_exec(s2fd)) *prot |=3D KVM_PGTABLE_PROT_X; =20 if (s2vi->map_non_cacheable) @@ -2034,8 +2054,7 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault= _desc *s2fd, if (mmu_invalidate_retry(kvm, s2vi->mmu_seq)) goto out_unlock; =20 - perm_fault_granule =3D (kvm_s2_fault_is_perm(s2fd) ? - kvm_vcpu_trap_get_perm_fault_granule(s2fd->vcpu) : 0); + perm_fault_granule =3D kvm_s2_perm_fault_granule(s2fd); mapping_size =3D s2vi->vma_pagesize; pfn =3D s2vi->pfn; gfn =3D s2vi->gfn; @@ -2103,7 +2122,7 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault= _desc *s2fd, =20 static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd) { - bool perm_fault =3D kvm_vcpu_trap_is_permission_fault(s2fd->vcpu); + bool perm_fault =3D kvm_s2_fault_is_perm(s2fd); struct kvm_s2_fault_vma_info s2vi =3D {}; enum kvm_pgtable_prot prot; void *memcache; @@ -2250,7 +2269,7 @@ int kvm_handle_guest_sea(struct kvm_vcpu *vcpu) int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) { struct kvm_s2_trans nested_trans, *nested =3D NULL; - unsigned long esr; + unsigned long esr =3D kvm_vcpu_get_esr(vcpu); phys_addr_t fault_ipa; /* The address we faulted on */ phys_addr_t ipa; /* Always the IPA in the L1 guest phys space */ struct kvm_memory_slot *memslot; @@ -2259,11 +2278,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) gfn_t gfn; int ret, idx; =20 - if (kvm_vcpu_abt_issea(vcpu)) + if (esr_abt_is_sea(esr)) return kvm_handle_guest_sea(vcpu); =20 - esr =3D kvm_vcpu_get_esr(vcpu); - /* * The fault IPA should be reliable at this point as we're not dealing * with an SEA. @@ -2272,7 +2289,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) if (KVM_BUG_ON(ipa =3D=3D INVALID_GPA, vcpu->kvm)) return -EFAULT; =20 - is_iabt =3D kvm_vcpu_trap_is_iabt(vcpu); + is_iabt =3D esr_trap_is_iabt(esr); =20 if (esr_fsc_is_translation_fault(esr)) { /* Beyond sanitised PARange (which is the IPA limit) */ @@ -2289,7 +2306,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) } } =20 - trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_esr(vcpu), + trace_kvm_guest_fault(*vcpu_pc(vcpu), esr, kvm_vcpu_get_hfar(vcpu), fault_ipa); =20 /* Check the stage-2 fault is trans. fault or write fault */ @@ -2298,9 +2315,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) !esr_fsc_is_access_flag_fault(esr) && !esr_fsc_is_excl_atomic_fault(esr)) { kvm_err("Unsupported FSC: EC=3D%#x xFSC=3D%#lx ESR_EL2=3D%#lx\n", - kvm_vcpu_trap_get_class(vcpu), - (unsigned long)kvm_vcpu_trap_get_fault(vcpu), - (unsigned long)kvm_vcpu_get_esr(vcpu)); + esr_get_ec(esr), + (unsigned long)(esr & ESR_ELx_FSC), + (unsigned long)esr); return -EFAULT; } =20 @@ -2349,7 +2366,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) gfn =3D ipa >> PAGE_SHIFT; memslot =3D gfn_to_memslot(vcpu->kvm, gfn); hva =3D gfn_to_hva_memslot_prot(memslot, gfn, &writable); - write_fault =3D kvm_is_write_fault(vcpu); + write_fault =3D esr_abt_is_write_fault(esr); if (kvm_is_error_hva(hva) || (write_fault && !writable)) { /* * The guest has put either its instructions or its page-tables @@ -2362,7 +2379,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) goto out; } =20 - if (kvm_vcpu_abt_iss1tw(vcpu)) { + if (esr_abt_is_s1ptw(esr)) { ret =3D kvm_inject_sea_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); goto out_unlock; } @@ -2377,7 +2394,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) * So let's assume that the guest is just being * cautious, and skip the instruction. */ - if (kvm_is_error_hva(hva) && kvm_vcpu_dabt_is_cm(vcpu)) { + if (kvm_is_error_hva(hva) && esr_dabt_is_cm(esr)) { kvm_incr_pc(vcpu); ret =3D 1; goto out_unlock; @@ -2414,9 +2431,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) if (kvm_vm_is_protected(vcpu->kvm)) { ret =3D pkvm_mem_abort(&s2fd); } else { - VM_WARN_ON_ONCE(kvm_vcpu_trap_is_permission_fault(vcpu) && - !write_fault && - !kvm_vcpu_trap_is_exec_fault(vcpu)); + VM_WARN_ON_ONCE(kvm_s2_fault_is_perm(&s2fd) && !write_fault && + !kvm_s2_fault_is_exec(&s2fd)); =20 if (kvm_slot_has_gmem(memslot)) ret =3D gmem_abort(&s2fd); --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 97D4C463B96; Mon, 14 Sep 2026 12:26:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388818; cv=none; b=qNn5/aDae3aSjyBYC41sZ503KfHFHwFiMLqDv3iqKCVR/2dS5DJlnUkmN+O1LFmGb3Orn+mqAcY/QRr/j4J9lRkvLt7edIKNerleb54xfu5QUnuP2W47Xt/BWaif1bPlY01xA54eTFw8AE7nxVOiUUYUbA9st+lHKjrXtU3Pr18= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388818; c=relaxed/simple; bh=VZcSKR8yxRV7e2O4hOy2SU5uYNlmsrpgI1kclfEhfHw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G43JWwLz7Zhb/5VlBgm9IPp4zSRBmhK4wB02JUBVtvKNlQdAAfbl59W+OU2nLh0p6j4EGFyqbuCMQYIJ6HDfje2PhF1d5lW+jAQ34zsRHdS9+6FBQwX1oQXYC2p7JkwkqlU17YnfMY1NC4G4rn764/X7GIhNIxgrq7tGn+agrfM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lj8jBcZE; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lj8jBcZE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ABC381F00893; Mon, 14 Sep 2026 12:26:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388814; bh=2BN4nsRUF6et4huKV7sboPy7MNqNCFDoN6pq7KaBtvI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=lj8jBcZEcHBQyVpUtx8fvicJEMpA+vQtXGEQ3iVBQa+D72wsYCg1MISeemTEOmy0e ZohRt3EHQCuEb7yKQ0mhc88U8PMX3gJ7gdGN4cPowS0UQYptCgF3KIu9vvssp7vPzR 01wElEv7lBX985U22kVMTuzmafbqKlhDc8cGtWRKFaDc1/ZS5jyyXXMN1HP5B/3FQP /22RA8jOECnKwMKfiF5vdoZaMMI4fnnG8oKo20UqszI4034zqWpjlSrOQw/+j397cv L9ohyZ8clqAYU79KH9dXMgNnX+ZcKcS+ABQfZUM5Hi+IFIcKM3aKUIPyNpPaVPWbIp ZnsOu5xavM20w== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:14 +0100 Subject: [PATCH v2 03/13] KVM: arm64: Propagate and use esr in s2fd when handling guest aborts Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-3-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2889; i=ljs@kernel.org; h=from:subject:message-id; bh=VZcSKR8yxRV7e2O4hOy2SU5uYNlmsrpgI1kclfEhfHw=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP//ySLxMS5T/aLtwXP+LRQnb52Wregc/PWsc1x0Su ++Fse+PjlIWBjEuBlkxRZbnX8T3B4mEzeu84O8GM4eVCWQIAxenAEzk+z9GhqUrjgttTdz1W6OM pUdNaUq3s5vzFK5w2VKG8rbW/bPqghgZbm+fU9KlGXp64nddxc7i0CmvSvvb0q8Vn3pvMTVCrVu MBwA= X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 kvm_handle_guest_abort() establishes a kvm_s2_fault_desc data structure, s2fd, to store and propagate state to either pkvm_mem_abort(), gmem_abort() or user_mem_abort() handlers. Each of these, however, examines the Exception Syndrome Register (ESR) via s2fd->vcpu. Introduce an s2fd->esr field to abstract this and propagate it to callers. The value of this (beyond refactoring) is to be able to later generate faults with a synthetic esr, specifically to implement stage 2 page table pre-faulting. Abort handlers which use kvm_s2_fault_desc - gmem_abort() and user_mem_abort() - now only reference s2fd->esr and do not look it up in any other way, which makes it safe to pass a synthetic s2fd->esr value to these functions. No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/kvm/mmu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index d1a6e25c3095..8303121e3332 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1603,21 +1603,22 @@ struct kvm_s2_fault_desc { struct kvm_s2_trans *nested; struct kvm_memory_slot *memslot; unsigned long hva; + unsigned long esr; }; =20 static bool kvm_s2_fault_is_perm(const struct kvm_s2_fault_desc *s2fd) { - return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(s2fd->vcpu)); + return esr_fsc_is_permission_fault(s2fd->esr); } =20 static bool kvm_s2_fault_is_exec(const struct kvm_s2_fault_desc *s2fd) { - return esr_abt_is_exec_fault(kvm_vcpu_get_esr(s2fd->vcpu)); + return esr_abt_is_exec_fault(s2fd->esr); } =20 static bool kvm_s2_fault_is_write(const struct kvm_s2_fault_desc *s2fd) { - return esr_abt_is_write_fault(kvm_vcpu_get_esr(s2fd->vcpu)); + return esr_abt_is_write_fault(s2fd->esr); } =20 static u64 kvm_s2_perm_fault_granule(const struct kvm_s2_fault_desc *s2fd) @@ -1626,7 +1627,7 @@ static u64 kvm_s2_perm_fault_granule(const struct kvm= _s2_fault_desc *s2fd) =20 if (!kvm_s2_fault_is_perm(s2fd)) return 0; - level =3D kvm_vcpu_get_esr(s2fd->vcpu) & ESR_ELx_FSC_LEVEL; + level =3D s2fd->esr & ESR_ELx_FSC_LEVEL; return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)); } =20 @@ -1997,7 +1998,7 @@ static int kvm_s2_fault_compute_prot(const struct kvm= _s2_fault_desc *s2fd, * and trigger the exception here. Since the memslot is valid, inject * the fault back to the guest. */ - if (esr_fsc_is_excl_atomic_fault(kvm_vcpu_get_esr(s2fd->vcpu))) { + if (esr_fsc_is_excl_atomic_fault(s2fd->esr)) { kvm_inject_dabt_excl_atomic(s2fd->vcpu, kvm_vcpu_get_hfar(s2fd->vcpu)); return 1; } @@ -2426,6 +2427,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) .nested =3D nested, .memslot =3D memslot, .hva =3D hva, + .esr =3D esr, }; =20 if (kvm_vm_is_protected(vcpu->kvm)) { --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 6DD0B446058; Mon, 14 Sep 2026 12:27:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388822; cv=none; b=DmUN2tB3Y8BD6fyT1ceQElrs3ebz5bbfVKiHlGySC0jmtycGZQ54Ul5ETPQpIhieKIwaOTD8/EJYGBeY4szJSt3D7gBd1D1PofB2vtkGIOFSNY17pnaDxWvqv4HMFNY1KDoprVOaelyCmQWSOvdb5NqCwdEnd3gs375aA3Extbo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388822; c=relaxed/simple; bh=dG6C64QjhNHNdOgwg9m9mJcfl3nv/5lgtPr2u+2vsyE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DvDg9fhOjXg4Ha5H4shzwsWqI/w6L6orkHQMuKKG+jL20E9QG0kunXdysIicJVtGxbcBvQ6Q8YV4jRL7oZAMGZlX0xRfsEaAfEzOi6cxwQCvrjU2bMwTRMnZDGhlXWZc7ZFYqGiHCDaasQE/qH6dxLqJYWevs7V1KBSgEAoR5DQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=b8yHPw03; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="b8yHPw03" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 899831F000FF; Mon, 14 Sep 2026 12:26:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388819; bh=C4NpQb5XhJVGlGt5CTl/rUdz6rEZJtjDW0HpeqsCBQw=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=b8yHPw03mHxs/ro3lqxKEetFolYD0ty8BA68mqW2d5zb/aKhpnTcu028vS8Q8vke6 PBZ+E29kBe14CGJ06DU15BG+S2lsHMxta8WBgfYI42LLRgcvpiJ0/1a2FletnEY9Lq 94g70uHUquT+X09JP9YGXdjQ2g+US4o1ow6/7lggt/puQu2V2HRepTtSwg7bpbzsP0 ntccvKeWIT/0D2His1/PWxkGQ21TnXtq60uasaaFshrYHEviFKS5QhdYITMaOdCbFA J2Dh0QWqKQwPh1WMCho70dg8HjJZwrcEUlf9MkSw8eOykaeddF3bx87CZgD7UIEKEr hFpsMjZtqQSLA== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:15 +0100 Subject: [PATCH v2 04/13] KVM: arm64: Propagate and use mmu in s2fd when handling guest aborts Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-4-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3977; i=ljs@kernel.org; h=from:subject:message-id; bh=dG6C64QjhNHNdOgwg9m9mJcfl3nv/5lgtPr2u+2vsyE=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP//6qmgZi8tfPZ2A9beXxt2ZfDYiklHmpfwRHk2Om Yffq1UGdJSyMIhxMciKKbI8/yK+P0gkbF7nBX83mDmsTCBDGLg4BWAih9Yz/LP2l1Da9SKXqT3R e0PLptU1nXH/Kvgrk3Z5TuM+V3xwuy7DX7FNkvPW3dkSdK3mhIHzhpDr+ZVcbtI5+TqvLZla7t5 U5QcA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 kvm_handle_guest_abort() establishes a kvm_s2_fault_desc data structure, s2fd, to store and propagate state to either pkvm_mem_abort(), gmem_abort() or user_mem_abort() handlers. Each of these, however, examines the state of the stage 2 MMU via vcpu->arch.hw_mmu. Introduce an s2fd->mmu field to abstract this and propagate it to callers. Similar to adding the esr field, this allows injection of synthetic faults with the ultimate intention of implementing stage 2 page table pre-faulting. No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/kvm/mmu.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 8303121e3332..f402481e8a4e 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1604,6 +1604,7 @@ struct kvm_s2_fault_desc { struct kvm_memory_slot *memslot; unsigned long hva; unsigned long esr; + struct kvm_s2_mmu *mmu; }; =20 static bool kvm_s2_fault_is_perm(const struct kvm_s2_fault_desc *s2fd) @@ -1637,7 +1638,7 @@ static int gmem_abort(const struct kvm_s2_fault_desc = *s2fd) bool perm_fault =3D kvm_s2_fault_is_perm(s2fd); enum kvm_pgtable_walk_flags flags =3D KVM_PGTABLE_WALK_SHARED; enum kvm_pgtable_prot prot =3D KVM_PGTABLE_PROT_R; - struct kvm_pgtable *pgt =3D s2fd->vcpu->arch.hw_mmu->pgt; + struct kvm_pgtable *pgt =3D s2fd->mmu->pgt; unsigned long mmu_seq; struct page *page; struct kvm *kvm =3D s2fd->vcpu->kvm; @@ -1735,7 +1736,7 @@ static int pkvm_mem_abort(const struct kvm_s2_fault_d= esc *s2fd) { unsigned int flags =3D FOLL_HWPOISON | FOLL_LONGTERM | FOLL_WRITE; struct kvm_vcpu *vcpu =3D s2fd->vcpu; - struct kvm_pgtable *pgt =3D vcpu->arch.hw_mmu->pgt; + struct kvm_pgtable *pgt =3D s2fd->mmu->pgt; struct mm_struct *mm =3D current->mm; struct kvm *kvm =3D vcpu->kvm; void *hyp_memcache; @@ -2050,7 +2051,7 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault= _desc *s2fd, int ret; =20 kvm_fault_lock(kvm); - pgt =3D s2fd->vcpu->arch.hw_mmu->pgt; + pgt =3D s2fd->mmu->pgt; ret =3D -EAGAIN; if (mmu_invalidate_retry(kvm, s2vi->mmu_seq)) goto out_unlock; @@ -2271,6 +2272,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) { struct kvm_s2_trans nested_trans, *nested =3D NULL; unsigned long esr =3D kvm_vcpu_get_esr(vcpu); + struct kvm_s2_mmu *mmu =3D vcpu->arch.hw_mmu; phys_addr_t fault_ipa; /* The address we faulted on */ phys_addr_t ipa; /* Always the IPA in the L1 guest phys space */ struct kvm_memory_slot *memslot; @@ -2300,7 +2302,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) } =20 /* Falls between the IPA range and the PARange? */ - if (fault_ipa >=3D BIT_ULL(VTCR_EL2_IPA(vcpu->arch.hw_mmu->vtcr))) { + if (fault_ipa >=3D BIT_ULL(VTCR_EL2_IPA(mmu->vtcr))) { fault_ipa |=3D FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(vcpu)); =20 return kvm_inject_sea(vcpu, is_iabt, fault_ipa); @@ -2337,8 +2339,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) * nothing to walk and we treat it as a 1:1 before going through the * canonical translation. */ - if (kvm_is_nested_s2_mmu(vcpu->kvm,vcpu->arch.hw_mmu) && - vcpu->arch.hw_mmu->nested_stage2_enabled) { + if (kvm_is_nested_s2_mmu(vcpu->kvm, mmu) && + mmu->nested_stage2_enabled) { u32 esr; =20 ret =3D kvm_walk_nested_s2(vcpu, fault_ipa, &nested_trans); @@ -2413,7 +2415,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) } =20 /* Userspace should not be able to register out-of-bounds IPAs */ - VM_BUG_ON(ipa >=3D kvm_phys_size(vcpu->arch.hw_mmu)); + VM_BUG_ON(ipa >=3D kvm_phys_size(mmu)); =20 if (esr_fsc_is_access_flag_fault(esr)) { handle_access_fault(vcpu, fault_ipa); @@ -2428,6 +2430,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) .memslot =3D memslot, .hva =3D hva, .esr =3D esr, + .mmu =3D mmu, }; =20 if (kvm_vm_is_protected(vcpu->kvm)) { --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 4045D46AA79; Mon, 14 Sep 2026 12:27:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388828; cv=none; b=XlLKcIvbQfn8bzo+DDG2CpbgKgISBODjpBv23udAgM7q1/pCwCkFovzbWAPhpBnSblRM3DPyfxXylyBAWlVCwfVEv7zQmDrGAlnEQqEDdNJV2XpQyignbTk0xpgFbxT8NLVs2sxMhJU7FVdklACjPx3Cj8lU8PYhNr0RMG3PPG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388828; c=relaxed/simple; bh=7h5BNF2TyNFGKTZFDAT77YrYi9+yuhGSKydMX9EZVMo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LyAj+X7rcwuSoT6Sld/Q9opJq+RI6Qosgz6RIvuRkRk2qTj33L/VXWP58EsGfgUmuMKiJ2rdudN58ezXX3ivg3u+rsKK3obyjqMW1rNDY0SzQAe7WZfqGWoJfaphBYAx7+latOeOmh3UZsgHN2uydDFi4vWPeggqjO522x0PMmI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Y0IwcxuX; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Y0IwcxuX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 667981F00893; Mon, 14 Sep 2026 12:27:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388825; bh=kfg0Uz8+KztBDtg3H0+qNEem9pKDqqYVBa07KrFCXCA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Y0IwcxuX0w/WvGSBZT3ojW/ME7dow3oCVDawD0flWeh6jWWkI8QWODZUzZMmjwe/B 4VU4fHsHZc0zyXnmq868pX14HRYBiITiw8MW2ugWOITzNFdGYpjogtppY0ixIguo5U 3YNMESJ4llRoHzSJt6IwGjLIZTj81ZUdHosnMZavRsiYirgqHHmrnbdbZpBTbE+t0e cDfpNXMTZ8DEbCe2uA3r9EEIrXHVeNA3yurCq4oQqpnXcaI6fGuvvuPm7zcntOJkIr TXCADD8sujBUmxChcp5FBfa/WxOYkxnkVduYpNseGiDJqvEcxHPOaPa8AaMP9t2wlZ sWDZuCq9S6lyw== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:16 +0100 Subject: [PATCH v2 05/13] KVM: arm64: Propagate and use kvm_s2_fault_result on S2 fault Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-5-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4228; i=ljs@kernel.org; h=from:subject:message-id; bh=7h5BNF2TyNFGKTZFDAT77YrYi9+yuhGSKydMX9EZVMo=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/86OaVhwydvpoC2R3t2vPXcX80gaHMmc16puUTH3 fajd+1aO0pZGMS4GGTFFFmefxHfHyQSNq/zgr8bzBxWJpAhDFycAjAR192MDCsEvqkdEtT7Ncsi 0/fLOS+2ZEn/RaI7PWu62SaouqzvSGdkeNvM3+i0/vYDa6aQpUe5rqfc/O9u8jXcMyxswwJeZwN hTgA= X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 When stage 2 page tables fault the net result may either be that a page is mapped, an error occurred or the fault should be retried (-EAGAIN). When a fault succeeds it may be upgraded to a PMD size via transparent_hugepage_adjust(). In order to support KVM pre-faulting the outcome of the fault and the mapping size must be recorded. Track the mapping size via new kvm_s2_fault_result struct, which is threaded through gmem_abort(), user_mem_abort() and kvm_s2_fault_map(). PKVM and SEA aren't relevant to synthetic pre-faulting so neither kvm_inject_sea() nor pkvm_mem_abort() are altered. Actual hardware faulting doesn't require this information, so kvm_handle_guest_abort() simply passes NULL kvm_s2_fault_result to gmem_abort() and user_mem_abort(). A non-NULL result also tells the abort handlers that the caller is pre-faulting rather than a vcpu, in which case -EAGAIN is propagated to the caller to allow the pre-fault to be retried. No functional change intended. Suggested-by: Vincent Donnefort Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/kvm/mmu.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index f402481e8a4e..13541218cadb 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1607,6 +1607,10 @@ struct kvm_s2_fault_desc { struct kvm_s2_mmu *mmu; }; =20 +struct kvm_s2_fault_result { + unsigned long mapping_size; +}; + static bool kvm_s2_fault_is_perm(const struct kvm_s2_fault_desc *s2fd) { return esr_fsc_is_permission_fault(s2fd->esr); @@ -1632,7 +1636,8 @@ static u64 kvm_s2_perm_fault_granule(const struct kvm= _s2_fault_desc *s2fd) return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level)); } =20 -static int gmem_abort(const struct kvm_s2_fault_desc *s2fd) +static int gmem_abort(const struct kvm_s2_fault_desc *s2fd, + struct kvm_s2_fault_result *result) { bool write_fault, exec_fault; bool perm_fault =3D kvm_s2_fault_is_perm(s2fd); @@ -1714,7 +1719,13 @@ static int gmem_abort(const struct kvm_s2_fault_desc= *s2fd) if ((prot & KVM_PGTABLE_PROT_W) && !ret) mark_page_dirty_in_slot(kvm, s2fd->memslot, gfn); =20 - return ret !=3D -EAGAIN ? ret : 0; + if (ret =3D=3D -EAGAIN) + return result ? ret : 0; + + if (result && !ret) + result->mapping_size =3D PAGE_SIZE; + + return ret; } =20 struct kvm_s2_fault_vma_info { @@ -2038,7 +2049,8 @@ static int kvm_s2_fault_compute_prot(const struct kvm= _s2_fault_desc *s2fd, static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd, const struct kvm_s2_fault_vma_info *s2vi, enum kvm_pgtable_prot prot, - void *memcache) + void *memcache, + struct kvm_s2_fault_result *result) { enum kvm_pgtable_walk_flags flags =3D KVM_PGTABLE_WALK_SHARED; bool writable =3D prot & KVM_PGTABLE_PROT_W; @@ -2117,12 +2129,17 @@ static int kvm_s2_fault_map(const struct kvm_s2_fau= lt_desc *s2fd, mark_page_dirty_in_slot(kvm, s2fd->memslot, gpa_to_gfn(ipa)); } =20 - if (ret !=3D -EAGAIN) - return ret; - return 0; + if (ret =3D=3D -EAGAIN) + return result ? ret : 0; + + if (result && !ret) + result->mapping_size =3D mapping_size; + + return ret; } =20 -static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd) +static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd, + struct kvm_s2_fault_result *result) { bool perm_fault =3D kvm_s2_fault_is_perm(s2fd); struct kvm_s2_fault_vma_info s2vi =3D {}; @@ -2161,7 +2178,7 @@ static int user_mem_abort(const struct kvm_s2_fault_d= esc *s2fd) return ret; } =20 - return kvm_s2_fault_map(s2fd, &s2vi, prot, memcache); + return kvm_s2_fault_map(s2fd, &s2vi, prot, memcache, result); } =20 /* Resolve the access fault by making the page young again. */ @@ -2440,9 +2457,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) !kvm_s2_fault_is_exec(&s2fd)); =20 if (kvm_slot_has_gmem(memslot)) - ret =3D gmem_abort(&s2fd); + ret =3D gmem_abort(&s2fd, NULL); else - ret =3D user_mem_abort(&s2fd); + ret =3D user_mem_abort(&s2fd, NULL); } =20 if (ret =3D=3D 0) --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 1006B46D08B; Mon, 14 Sep 2026 12:27:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388833; cv=none; b=M9KBI29pFm8baXjjzuo7V9hkwLXgyJpVAFVhGfcjLdv/atGHBdKMFFhd0By8eaDuyAWikK4NXEioD9LVF+MJtbm2SiohmnUG76J7hIxbyV/Qh3EM5BBvOgZ1Lg7Q2e9XAs3vN41jB4LqDyNfAjsT63gl2U9j0le+k2MzTrBGWis= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388833; c=relaxed/simple; bh=Y4FlysXiT+xF7JlukrCtrhUE/JomIeYHyF5yaw00498=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fn83WaI4CoSPqZ4Jzs1q1VW3rrNkEfFQ1DriF83qYWRSvxejRIAXnUSe00Z1JmrkWuLYfHDDSdBxljQkQgVmj+CgrWLC+jxuPzm0PK0zuvmPzyukvbFYpnGaie67Zws5M0f+buQUDJrg8NtsUU6nUujD0EhpLxYUQCVRu8OV3ro= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BD0J6OC+; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BD0J6OC+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46B441F0089D; Mon, 14 Sep 2026 12:27:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388831; bh=iKvODBKPVjNkw+FyDfWvIqPPmR7jxIaTnYa7ga+H6Fg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=BD0J6OC+lga4CbFP4aSfvYa6SYSaAKYvgPlAAhSvC0RQdhWy3MFA3LYh/OVFwfjvR GQOA/NE4uAuWzSqCpT4H1D9nLxYeKTFKXuGfMZTUgmWeQkbay5w2f8zLRI33pyzLPf uAePava7AOMmjWZcuKXwb2ZLHV0Ns0Vdp6k1xbzuQenZGqPZ4AD0Olo0nFyzVaiM81 Ckm7xEOMJkyJEHi5jCsLST9ccJTHbr70FgrTc1Q8GG9ruJTXxjE5Xtc3AKc83GjWGO jxM1VYM0PWHF7JJeqMfR8xe8riXjAI68aw7QUbB/kgvE0VjnP8uWobo+PX/2LOAaDT CZRCIKWYr54dQ== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:17 +0100 Subject: [PATCH v2 06/13] KVM: arm64: Size the stage-2 memcache from the fault MMU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-6-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2249; i=ljs@kernel.org; h=from:subject:message-id; bh=Y4FlysXiT+xF7JlukrCtrhUE/JomIeYHyF5yaw00498=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/9a6DvvzsJ/B8rz3ocsCvnIcmyGyjkn6+Z/nVef/ nq77POn6R2lLAxiXAyyYoosz7+I7w8SCZvXecHfDWYOKxPIEAYuTgGYyLIbjAxT9s+Nf5IdfJw1 pfKYjJTy2bc80ZHikQce5WtXJ56zfcTH8IdT8dv6HPMaVsfjS9k+c1Te9fqSZPBsO+ehNY9LHfe 8Y2cHAA== X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 topup_mmu_memcache() sizes the page-table cache from vcpu->arch.hw_mmu, which is the MMU that faulted. Pass the target s2fd->mmu instead, so the mmu used can be controlled by the caller. For a guest abort this is vcpu->arch.hw_mmu, so this commit introduces no functional change in practice. However, it's necessary for a future change which introduces stage 2 pre-faulting which must always target the canonical MMU regardless of the vCPU's last-run context. No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/kvm/mmu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 13541218cadb..8c23fef4ecf8 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1554,9 +1554,9 @@ static void *get_mmu_memcache(struct kvm_vcpu *vcpu) return &vcpu->arch.pkvm_memcache; } =20 -static int topup_mmu_memcache(struct kvm_vcpu *vcpu, void *memcache) +static int topup_mmu_memcache(struct kvm_s2_mmu *mmu, void *memcache) { - int min_pages =3D kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu); + int min_pages =3D kvm_mmu_cache_min_pages(mmu); =20 if (!is_protected_kvm_enabled()) return kvm_mmu_topup_memory_cache(memcache, min_pages); @@ -1654,7 +1654,7 @@ static int gmem_abort(const struct kvm_s2_fault_desc = *s2fd, =20 if (!perm_fault) { memcache =3D get_mmu_memcache(s2fd->vcpu); - ret =3D topup_mmu_memcache(s2fd->vcpu, memcache); + ret =3D topup_mmu_memcache(s2fd->mmu, memcache); if (ret) return ret; } @@ -1755,7 +1755,7 @@ static int pkvm_mem_abort(const struct kvm_s2_fault_d= esc *s2fd) int ret; =20 hyp_memcache =3D get_mmu_memcache(vcpu); - ret =3D topup_mmu_memcache(vcpu, hyp_memcache); + ret =3D topup_mmu_memcache(s2fd->mmu, hyp_memcache); if (ret) return -ENOMEM; =20 @@ -2159,7 +2159,7 @@ static int user_mem_abort(const struct kvm_s2_fault_d= esc *s2fd, memcache =3D get_mmu_memcache(s2fd->vcpu); if (!perm_fault || memslot_is_logging(s2fd->memslot) || is_protected_kvm_enabled()) { - ret =3D topup_mmu_memcache(s2fd->vcpu, memcache); + ret =3D topup_mmu_memcache(s2fd->mmu, memcache); if (ret) return ret; } --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 2B3EE4483A2; Mon, 14 Sep 2026 12:27:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388840; cv=none; b=g/k0RW6oMz1aR5yBbxKqRPvqpudMMUVGsZGeKTHv11vBXKM0nJwwptBGLdCk+7bPGKYc8Mj3Tio/MAK6llmJ1wYr2iylxV/FD/ZKElB3Z5zKE6j1HABQAUuT3ctcjvto3ak2QXS2wHjGqGgDABqB35n8hYEEvhDZVmtC6y/GL50= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388840; c=relaxed/simple; bh=Hb4EU3ooaVPX0vORXtq1G56N+69ZYTRtU/gYDr/Xt9w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XN94sbCvYcmphxV2EguqRQ27R1nTdCQBQ/Nf0g+jPBieXkumZCXOuSORPE2agVUiMnuYseqx6sAQjgWsrVHw4BMi2sdHHYa1Id4iQvmfp/8koMr9PfMJdDk4pVfF6DONd4eizxRriM/HpKNDKtEEaqgFsqkZBn65rmNrRqs4HVY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VbA1+Er/; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VbA1+Er/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 211091F00898; Mon, 14 Sep 2026 12:27:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388837; bh=d44gE0/IL0gyA9lyN7r1jK3OuMoXRfrYJhQ+4wSHM8U=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=VbA1+Er/iWG/56cK3BppcKN06PLdqOGhz/rBvvOCk7lo05ELrzewdm7Kvn49pjlaK I+fVuw7agdYbnPzfh+enQ+6/sm54EhVrTdXveTDzJmm3n4y8A8R0lNjNuaW2by2Gfr 4K0rZeeJ59RRQhk1MUtQ0Fwcwh9t5pzZV86l0BiWwWxKhGAQnBWnBcqkZdeyuG1g2+ 0ge4jV+cSKVF17sako6EiAwrD4TeYvck5sZ0vWttdkN7Bl9gTVRPsDp97a77xhNAYL jSJYykGEcy4wI2Ea2ww7EO0HtpqVzFaWOTmHEidBVBiU7wE0+w27KsCTHyff0jzvjt 5aHDTpHYT6GkA== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:18 +0100 Subject: [PATCH v2 07/13] KVM: arm64: Propagate EHWPOISON in kvm_s2_fault_pin_pfn() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-7-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1982; i=ljs@kernel.org; h=from:subject:message-id; bh=Hb4EU3ooaVPX0vORXtq1G56N+69ZYTRtU/gYDr/Xt9w=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/9qbKIWcyhaOuTB7wW/pmysejLhhOHH7Jh70y/wt lxav/HgiY5SFgYxLgZZMUWW51/E9weJhM3rvODvBjOHlQlkCAMXpwBMJO0+w//Q/x4Ma0RVQ334 7rIXmNj/mKEeJuC4v35PmescCeWNKscZGaZWv5unp9nA0vN6bp3o1pvHdt8+rGDNwLv+XKpb5DV lVjYA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Currently kvm_s2_fault_pin_pfn() handles a poisoned page directly by sending a SIGBUS signal itself. This is an odd place to do it, the caller should decide what to do with errors, so move the handling to the sole caller, user_mem_abort(). This lays the foundation for stage 2 pre-faulting which, arising from a synthetic fault, should not send a signal. In order to do so, check to see if user_mem_abort()'s caller has set result - i.e. whether it wants to be informed about the outcome of the fault handling. If it does, then it is implied that it should handle the -EHWPOISON error itself. This is the case for pre-faulting. Otherwise this is real hardware, so send the signal. No functional change intended. Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/kvm/mmu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 8c23fef4ecf8..eae085a622ff 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1946,10 +1946,8 @@ static int kvm_s2_fault_pin_pfn(const struct kvm_s2_= fault_desc *s2fd, kvm_s2_fault_is_write(s2fd) ? FOLL_WRITE : 0, &s2vi->map_writable, &s2vi->page); if (unlikely(is_error_noslot_pfn(s2vi->pfn))) { - if (s2vi->pfn =3D=3D KVM_PFN_ERR_HWPOISON) { - kvm_send_hwpoison_signal(s2fd->hva, __ffs(s2vi->vma_pagesize)); - return 0; - } + if (s2vi->pfn =3D=3D KVM_PFN_ERR_HWPOISON) + return -EHWPOISON; return -EFAULT; } =20 @@ -2169,6 +2167,13 @@ static int user_mem_abort(const struct kvm_s2_fault_= desc *s2fd, * get block mapping for device MMIO region. */ ret =3D kvm_s2_fault_pin_pfn(s2fd, &s2vi); + if (ret =3D=3D -EHWPOISON) { + /* If result is specified, let the caller handle this. */ + if (result) + return -EHWPOISON; + kvm_send_hwpoison_signal(s2fd->hva, __ffs(s2vi.vma_pagesize)); + return 0; + } if (ret !=3D 1) return ret; =20 --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 2277C455623; Mon, 14 Sep 2026 12:27:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388846; cv=none; b=FIpVGWpGi5pnx7nMk0yZd034MEe4pdidx9JUVuEWw3xv8X9yiPIuwKj3+GL4zmiijf7A/wV6OmCLqs+uDpVOPjnpwtuIF26elgx/eyqFdlyY+YyQj6DAYS0lYArFI/vdUMujZn8CNSvsotTPrY0AIQYqyNE7pGJutZO9t3zVXeQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388846; c=relaxed/simple; bh=sxsR0neWhr2x3K2zdyfHuHOqlS6vpsw+7DVZOk50OYk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=p25NuqVgQHEGSrTUEsnqSZ4zTwFhPaSdxzuTuTGIhQKpPYOGe4DE+93oXyfNkSXzS7GycLn7qCpnnkFNzHpZxZRWIz/u72HYW7OkxzWvwUEnN5OqLdBNM3gm/PFWvFrn2+PxUDQHUzD61zauabW+MKCssst9DLGRDK3Bev11gsI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VT91QDfE; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VT91QDfE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 01CED1F000FF; Mon, 14 Sep 2026 12:27:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388843; bh=ephBT7Ms4ZBAJjep/I2F/htnPClPVQpebuoaPNEXZb4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=VT91QDfE2BE1TM7B+x0FJjzqg6aZFfbRzXR+MFJitGKNOFlD5wtaONuroPHf5lfyH nKtK3YzJ/wLUUh2SAL/Fh1zWB6PdbzQKxMSp37MzhNh4trxPcxvjSWzMa25jR7/8Wp ehfHY2lbbYt7SH+CRBpd3pp9xaRPDHJJeApbFQlh4j8gvbgTfxgCVMxVpqyxOorU9Y m3aAz3XvCt7WN8XMlJAsgQh1GAzwY6R8FqtleCqr1Mq6EcX2Xke6tPj5r8s3G3HH6O G7SBV/82HngjxUiRtGNJrfY927GwrG7aIwVpCwMFBekPSScMpGa7Rl3njZPSEkPTM4 8QgusD7c3TFmg== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:19 +0100 Subject: [PATCH v2 08/13] KVM: arm64: Pass walk flags to kvm_pgtable_get_leaf() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-8-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5556; i=ljs@kernel.org; h=from:subject:message-id; bh=gnm60rg2wPySPU/+erDKmBvXy87LcivmTZpZyB37QFA=; b=kA0DAAoWz53NioHifxQByyZiAGqn5/Wg7ynwQorQwEyvD9T3MBQbe8zX88kxmp7R9m9IVvqmG Yh1BAAWCgAdFiEE5/QXv1IUVp6J0E9Gz53NioHifxQFAmqn5/UACgkQz53NioHifxSgbwD+ITy+ jbun0GGJMR7jRBBSZrGP2hqcngvchJQ22FiEsGkA/R4yVLn0+fLOJ9IabHGooa3zm8+sWj5MNLl TsW2KbUIC X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 From: Jack Thomson Allow callers of kvm_pgtable_get_leaf() to specify the page-table walk flags, in preparation for performing walks under the MMU read lock. Reading a stage-2 leaf while only holding the read lock requires KVM_PGTABLE_WALK_SHARED: parallel faults (which also only hold the read lock) can unlink table pages and free them via RCU, so the walker must be inside an RCU read-side critical section, which the shared walk flag provides via kvm_pgtable_walk_begin(). All existing callers either hold the write lock, walk with interrupts disabled, or run at hyp where shared walks are rejected; they keep the current behaviour by passing no flags. No functional change intended. Signed-off-by: Jack Thomson Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/include/asm/kvm_pgtable.h | 5 ++++- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 10 +++++----- arch/arm64/kvm/hyp/pgtable.c | 5 +++-- arch/arm64/kvm/mmu.c | 2 +- arch/arm64/kvm/nested.c | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/= kvm_pgtable.h index 41a8687938eb..d0167f7dfbee 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -859,6 +859,8 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr,= u64 size, * @addr: Input address for the start of the walk. * @ptep: Pointer to storage for the retrieved PTE. * @level: Pointer to storage for the level of the retrieved PTE. + * @flags: Flags to control the page-table walk + * (see struct kvm_pgtable_visit_ctx). * * The offset of @addr within a page is ignored. * @@ -869,7 +871,8 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr,= u64 size, * Return: 0 on success, negative error code on failure. */ int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr, - kvm_pte_t *ptep, s8 *level); + kvm_pte_t *ptep, s8 *level, + enum kvm_pgtable_walk_flags flags); =20 /** * kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvh= e/mem_protect.c index 39aa8911f62c..23a57312b981 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -532,7 +532,7 @@ static int host_stage2_adjust_range(u64 addr, struct kv= m_mem_range *range) int ret; =20 hyp_assert_lock_held(&host_mmu.lock); - ret =3D kvm_pgtable_get_leaf(&host_mmu.pgt, addr, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&host_mmu.pgt, addr, &pte, &level, 0); if (ret) return ret; =20 @@ -910,7 +910,7 @@ static int get_valid_guest_pte(struct pkvm_hyp_vm *vm, = u64 ipa, kvm_pte_t *ptep, s8 level; int ret; =20 - ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0); if (ret) return ret; if (guest_pte_is_poisoned(pte)) @@ -959,7 +959,7 @@ int __pkvm_vcpu_in_poison_fault(struct pkvm_hyp_vcpu *h= yp_vcpu) ipa |=3D FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(&hyp_vcpu->vcpu)); =20 guest_lock_component(vm); - ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0); if (ret) goto unlock; =20 @@ -1315,7 +1315,7 @@ static int host_stage2_get_guest_info(phys_addr_t phy= s, struct pkvm_hyp_vm **vm, return -EPERM; } =20 - ret =3D kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, &level, 0); if (ret) return ret; =20 @@ -1544,7 +1544,7 @@ static int __check_host_shared_guest(struct pkvm_hyp_= vm *vm, u64 *__phys, u64 ip s8 level; int ret; =20 - ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0); if (ret) return ret; if (!kvm_pte_valid(pte)) diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index b74dd5ce1efd..347eec3957d6 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -298,12 +298,13 @@ static int leaf_walker(const struct kvm_pgtable_visit= _ctx *ctx, } =20 int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr, - kvm_pte_t *ptep, s8 *level) + kvm_pte_t *ptep, s8 *level, + enum kvm_pgtable_walk_flags flags) { struct leaf_walk_data data; struct kvm_pgtable_walker walker =3D { .cb =3D leaf_walker, - .flags =3D KVM_PGTABLE_WALK_LEAF, + .flags =3D flags | KVM_PGTABLE_WALK_LEAF, .arg =3D &data, }; int ret; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index eae085a622ff..9c922b498adb 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -866,7 +866,7 @@ static int get_user_mapping_size(struct kvm *kvm, u64 a= ddr) * IPI-ing threads). */ local_irq_save(flags); - ret =3D kvm_pgtable_get_leaf(&pgt, addr, &pte, &level); + ret =3D kvm_pgtable_get_leaf(&pgt, addr, &pte, &level, 0); local_irq_restore(flags); =20 if (ret) diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 17123f0b6dab..3488d5ad225b 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -654,7 +654,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu,= u64 addr) return 0; =20 tmp &=3D ~(sz - 1); - if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL)) + if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL, 0)) goto again; if (!(pte & PTE_VALID)) goto again; --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 C7832455623; Mon, 14 Sep 2026 12:27:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388851; cv=none; b=iax3ekfw6NRikpbCN2Uljg6rmlOaHI1uUdX46jfR/p7U88ljZfXhj0gV8KrfWKK6O4bIIFWwhZMYEyMQrqIo/7f4wHQEap7tiL1Pebl46ucuBMA58I1K7cxeqwWF5EdXaSLWisq8l1zuxImPmcNdyR0akursWfiur9quvoVBFSQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388851; c=relaxed/simple; bh=zGFS584HnUtx3DB3mxkwTl+niPKdC9PKA7LK2k9UJ98=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=e0zpfmRU3gUFOBKELvlBp7Jabav1UEHZqy2tTaoCu4TRZIFneUvHOFn2UrAF4/b9ICJU2nY5GJH6JIooZv77bzZxUpoR7eAjCkpwaNCEqOGIisfxli/20uRR3wRWwTFyG/srtxQxtvBlAx0ZV/lF69jhkQZtA24w0RIBTSphaCQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IN67ho5V; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IN67ho5V" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DA2761F00893; Mon, 14 Sep 2026 12:27:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388849; bh=uc+x321Bebrgu/kzizKcirXOM0C2dCttTdV9zeKiSgc=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=IN67ho5VaBAydk8qvmgod7tjfM46rHy+asK+Bv9GyqD7YCTT0S8RuaziBM1idGRSn JPzTZ/p4icHXsKqG88Va3EyQUp1eDwzfgR7NuzyrSPbYr2SHz7xcWLhGm48kwpObQz kVWLxoPcr3rGMLyGCfm/8ChtoCV7VnkWv/CKgLyy8rvy9oD4i6GWS3fyv6nN73qqda lDsoPh/62QRTl7rm1yD5ralj860Eew667WNyF1lsvzfLou3NalEUOC+259znGaUqVB kUAQ+aY7O4IIfozegfxVDrraoJx6HAUsRyK/+xp8+Z+w9/rdw6LYtlSOAllsXtcpDq IC2v88j2YomTA== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:20 +0100 Subject: [PATCH v2 09/13] KVM: arm64: Implement KVM_PRE_FAULT_MEMORY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-9-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7848; i=ljs@kernel.org; h=from:subject:message-id; bh=zGFS584HnUtx3DB3mxkwTl+niPKdC9PKA7LK2k9UJ98=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP//64Lfs1rOmp8vrKixKb/i1TTGu/9S7XiNCrj3Fy TBM77hCRykLgxgXg6yYIsvzL+L7g0TC5nVe8HeDmcPKBDKEgYtTACayt57hr0B4ZIMcT71Y7apH AVe72bkcHrM/rX4c/WeVl/VVd81LxowMzfo2Dl8l62r9q1eXHvYtevbF+OL0+E96jPmCioznVaZ yAgA= X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Implement KVM stage 2 page table pre-faulting for the arm64 architecture, with the core of the implementation in kvm_arch_vcpu_pre_fault_memory(). Pre-fault by first trying a page table walk under the MMU read lock then, if it fails, injecting a synthetic data abort at the page table level at which the page table walk failed. This is necessarily racey as reclaim might happen at any time. Successfully pre-faulting can therefore only guarantee that each GPA was observed to be mapped at least once. Protected KVM (pKVM) is not supported at all because pKVM creates VMs and vCPUs when first run, meaning any attempt to pre-fault prior to this cannot succeed. A retry mechanic is implemented when user_mem_abort() or gmem_abort() fail to map memory due to a benign failure where a hardware abort would not result in an error. An invalid memslot (i.e. a memslot with the KVM_MEMSLOT_INVALID flag set) results in the operation returning -EAGAIN without a retry mechanic, because an invalid memslot means the pre-fault operation raced with memslot reclaim, and since the SRCU lock is held, progress cannot be made, and the user must retry. This work is based with gratitude on Jack Thomson's original series, its previous revisions and the feedback they received. Link: https://patch.msgid.link/20260612162354.73378-1-jackabt.amazon@gmail.= com/ Signed-off-by: Lorenzo Stoakes (ARM) --- arch/arm64/include/asm/kvm_pkvm.h | 2 +- arch/arm64/kvm/Kconfig | 1 + arch/arm64/kvm/arm.c | 1 + arch/arm64/kvm/mmu.c | 141 ++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 144 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm= _pkvm.h index beea00e693a0..4d6e5765e9e5 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -44,9 +44,9 @@ static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, = long ext) case KVM_CAP_ARM_PTRAUTH_GENERIC: return true; case KVM_CAP_ARM_MTE: - return false; case KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE: case KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES: + case KVM_CAP_PRE_FAULT_MEMORY: return false; default: return !kvm || !kvm_vm_is_protected(kvm); diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 449154f9a485..71233068b7cb 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -37,6 +37,7 @@ menuconfig KVM select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS select KVM_GUEST_MEMFD + select KVM_GENERIC_PRE_FAULT_MEMORY help Support hosting virtualized guest machines. =20 diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index ccae82c1242b..58ac70f31d84 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -393,6 +393,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long = ext) case KVM_CAP_COUNTER_OFFSET: case KVM_CAP_ARM_WRITABLE_IMP_ID_REGS: case KVM_CAP_ARM_SEA_TO_USER: + case KVM_CAP_PRE_FAULT_MEMORY: r =3D 1; break; case KVM_CAP_SET_GUEST_DEBUG2: diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 9c922b498adb..17f1f6d36f2b 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -5,6 +5,7 @@ */ =20 #include +#include #include #include #include @@ -2835,3 +2836,143 @@ void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool w= as_enabled) =20 trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled); } + +/* + * Try to walk to the specified GPA in canonical mmu - if unmapped returns= 0, if + * mapped returns the granule size, otherwise returns an error. + */ +static long kvm_walk_s2(struct kvm_pgtable *pgt, + gpa_t gpa, s8 *level) +{ + struct kvm *kvm =3D kvm_s2_mmu_to_kvm(pgt->mmu); + kvm_pte_t pte; + long ret; + + guard(read_lock)(&kvm->mmu_lock); + + ret =3D kvm_pgtable_get_leaf(pgt, gpa, &pte, level, + KVM_PGTABLE_WALK_SHARED); + if (ret) + return ret; + /* Unpopulated, must fault. */ + if (!kvm_pte_valid(pte)) + return 0; + return kvm_granule_size(*level); +} + +/* Synthesised data abort at specified page table level. */ +#define PRE_FAULT_ESR(level) \ + ((ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT) | \ + ESR_ELx_IL | ESR_ELx_FSC_FAULT_L(level)) + +/* Retrieve either a read-only or a read/write hva. */ +static hva_t gfn_to_hva_memslot_read(struct kvm_memory_slot *slot, gfn_t g= fn) +{ + return gfn_to_hva_memslot_prot(slot, gfn, /*writable=3D*/NULL); +} + +static long __pre_fault_s2(struct kvm_s2_mmu *mmu, struct kvm_vcpu *vcpu, + gpa_t gpa, struct kvm_memory_slot *memslot, s8 level) +{ + const bool is_gmem =3D kvm_slot_has_gmem(memslot); + const gfn_t gfn =3D gpa_to_gfn(gpa); + const hva_t hva =3D is_gmem ? 0 : gfn_to_hva_memslot_read(memslot, gfn); + const struct kvm_s2_fault_desc s2fd =3D { + .vcpu =3D vcpu, + .fault_ipa =3D gpa, + .nested =3D NULL, + .memslot =3D memslot, + .hva =3D hva, + .esr =3D PRE_FAULT_ESR(level), + .mmu =3D mmu, + }; + struct kvm_s2_fault_result result =3D {}; + long ret; + + if (kvm_is_error_hva(hva)) + return -EFAULT; + + if (is_gmem) + ret =3D gmem_abort(&s2fd, &result); + else + ret =3D user_mem_abort(&s2fd, &result); + if (IS_ERR_VALUE(ret)) + return ret; + return result.mapping_size; +} + +static long pre_fault_s2(struct kvm_s2_mmu *mmu, struct kvm_vcpu *vcpu, + gpa_t gpa, struct kvm_memory_slot *memslot) +{ + s8 level; + long ret; + + /* Try a walk first. */ + ret =3D kvm_walk_s2(mmu->pgt, gpa, &level); + if (ret) + return ret; + /* OK, have to fault page in. */ + return __pre_fault_s2(mmu, vcpu, gpa, memslot, level); +} + +static unsigned long +pre_fault_bytes_consumed(gpa_t gpa, unsigned long granule_size, + unsigned long bytes_remaining) +{ + /* Granules are always a power-of-2. */ + const unsigned long granule_bytes_remaining =3D + granule_size - (gpa % granule_size); + + return min(granule_bytes_remaining, bytes_remaining); +} + +/* If you lose the race this many times, time to give up. */ +#define MAX_PRE_FAULT_RETRIES 3 + +/** + * kvm_arch_vcpu_pre_fault_memory - pre-fault stage-2 page tables for the + * specified GPA. + * @vcpu: The VCPU pointer + * @range: {gpa, size, flags} tuple + * + * The mapping performed is always best-effort - faulting in is necessarily + * racey. The ranges faulted in are canonical, nested page tables are igno= red. + * + * @range->gpa specifies the GPA to pre-fault, @range->size specifies how = many + * bytes remain to be pre-faulted and @range->flags is reserved and must b= e 0. + * + * Returns: the number of bytes the pre-fault consumed, or an error. + */ +long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range) +{ + struct kvm *kvm =3D vcpu->kvm; + const u64 bytes_remaining =3D range->size; + struct kvm_s2_mmu *mmu =3D &kvm->arch.mmu; /* Canonical. */ + struct kvm_memory_slot *memslot; + const gpa_t gpa =3D range->gpa; + int num_retries =3D 0; + long ret; + + /* + * pKVM is unsupported as their vCPUs are instantiated on first run and + * pre-faulting only running vCPUs would be inconsistent and confusing. + */ + if (is_protected_kvm_enabled()) + return -EOPNOTSUPP; + + memslot =3D gfn_to_memslot(kvm, gpa_to_gfn(gpa)); + if (!memslot) + return -ENOENT; + /* SRCU must be released for progress and only userland can do that. */ + if (memslot->flags & KVM_MEMSLOT_INVALID) + return -EAGAIN; + + do { + ret =3D pre_fault_s2(mmu, vcpu, gpa, memslot); + } while (ret =3D=3D -EAGAIN && num_retries++ < MAX_PRE_FAULT_RETRIES); + + if (IS_ERR_VALUE(ret)) + return ret; + return pre_fault_bytes_consumed(gpa, ret, bytes_remaining); +} --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 8ECDF455623; Mon, 14 Sep 2026 12:27:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388856; cv=none; b=iNNxxM7phIpOsByIz066kiSF61xqnZRlZ7PAtbkNJwazqjoJ3gVIDUDEAt+n9eVHKnLwMDSnFOWbxX5Uj4Ui4JoKiv0Kgsz+GtwfZ82h4YxYnASTP2+LEPwCvl6feavUs2Om50+3d3lXuF08SKrybQgFhTBHoiC9jiOwRdf1y9M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388856; c=relaxed/simple; bh=UMAm/iY38JK7kwFijNKO0oMBtghoFRe1xQSMWNQVt1w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=b+xH7Vz9+aKoFeecN8KczpBbz2ZyvRiRSKd/HR/RXDBzvgM+HDS8sKlMH/+iOHB87uA2Vgy9nvEfSOIEp1XGjBSroFVgIq8lPLs2z5L6lB7WUM3KiaBJXx6WAY11sl5+LzkpdS0d/zewlhE1vVgspfzwL/fvZ7WJS3Mcgh3kf+E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WEy2l5Fk; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="WEy2l5Fk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B54421F000FF; Mon, 14 Sep 2026 12:27:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388855; bh=Np9lRZngEX1/cke4zpiBmcslPtIquzm48zu2HawlS80=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=WEy2l5FkUgCswDMSJ1YTwDmZD1nzQj7T1h5LAqs0+0gjfsmxdZgWDlcZXd1eOsz3W b55osXjinmIkuFGUC4BWtsDxBsJ9JTmvJ7LtvCH4i78rCU2v5kjlcfV+7+fibIwQJx i21rjI7H4st+KYcuyQCpNHQq45V62Nm2nhD0ShUa3iWGS4DtmlJMsNIj3woCUQ6rTr dhmn5EUbPGI3RzxLe6hoxnZwyTQP1k2hPsU9/+WL3+WPN92HcFDoF9nhCIZcurMpt3 D1I0ejavTAAkK2XAAMgyyzwxPQtimgr4/a4nX/TlEMBeIbN5XLqoN/GgTWd9M7w3hL g3iMSt8ZSTzxw== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:21 +0100 Subject: [PATCH v2 10/13] Documentation: KVM: document arm64 KVM_PRE_FAULT_MEMORY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-10-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3340; i=ljs@kernel.org; h=from:subject:message-id; bh=UMAm/iY38JK7kwFijNKO0oMBtghoFRe1xQSMWNQVt1w=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/+2f+vjjNV9sZXahZfKRL90stYV7L/zKk9aViRPf 6ro5knrOkpZGMS4GGTFFFmefxHfHyQSNq/zgr8bzBxWJpAhDFycAjCRs/8Z/qd1Lbk3x1Tm8nPL gi/JC058c5X0/mO1kX/nrsDmys0pd5kY/kqEd+hem1Zy2DrJmKe+8Cf/nf23VW5tYZacHHAxvWZ eGzMA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Update the KVM API documentation to reflect the fact that arm64 now supports this functionality. Also document error values and arm64-specific behaviour. Signed-off-by: Lorenzo Stoakes (ARM) --- Documentation/virt/kvm/api.rst | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 4988c32df4bf..fb7f8baca970 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6485,7 +6485,7 @@ See KVM_SET_USER_MEMORY_REGION2 for additional detail= s. --------------------------- =20 :Capability: KVM_CAP_PRE_FAULT_MEMORY -:Architectures: none +:Architectures: x86, s390, arm64 :Type: vcpu ioctl :Parameters: struct kvm_pre_fault_memory (in/out) :Returns: 0 if at least one page is processed, < 0 on error @@ -6493,12 +6493,14 @@ See KVM_SET_USER_MEMORY_REGION2 for additional deta= ils. Errors: =20 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + EAGAIN A race occurred before progress was made, but a retry may suc= ceed. EINVAL The specified `gpa` and `size` were invalid (e.g. not page aligned, causes an overflow, or size is zero), or the VM is UCONTROL (s390). ENOENT The specified `gpa` is outside defined memslots. EINTR An unmasked signal is pending and no page was processed. EFAULT The parameter address was invalid. + EHWPOISON A poisoned host page was encountered. EOPNOTSUPP Mapping memory for a GPA is unsupported by the hypervisor, and/or for the current vCPU state/mode. EIO unexpected error conditions (also causes a WARN) @@ -6518,7 +6520,17 @@ Errors: KVM_PRE_FAULT_MEMORY populates KVM's stage-2 page tables used to map memory for the current vCPU state. KVM maps memory as if the vCPU generated a stage-2 read page fault, e.g. faults in memory as needed, but doesn't break -CoW. On x86, KVM does not mark any newly created stage-2 PTE as Accessed. +CoW. On arm64, KVM marks newly created stage-2 PTEs as Accessed, as it +does for any stage-2 fault, but leaves the Accessed state of existing PTEs +unchanged. On x86, KVM does not mark any newly created stage-2 PTE as +Accessed, and for s390 it is not applicable. + +On arm64, a GPA is interpreted as an IPA, and never interpreted as the IPA +of a nested guest. Pre-faulting only populates canonical stage 2 page +tables. + +The feature is not supported on arm64 if the protected KVM (pKVM) feature +is enabled. =20 In the case of confidential VM types where there is an initial set up of private guest memory before the guest is 'finalized'/measured, this ioctl @@ -6533,7 +6545,7 @@ When the ioctl returns, the input values are updated = to point to the remaining range. If `size` > 0 on return, the caller can just issue the ioctl again with the same `struct kvm_map_memory` argument. =20 -Shadow page tables cannot support this ioctl because they +On x86, shadow page tables cannot support this ioctl because they are indexed by virtual address or nested guest physical address. Calling this ioctl when the guest is using shadow page tables (for example because it is running a nested guest with nested page tables) --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 604D2470E8C; Mon, 14 Sep 2026 12:27:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388863; cv=none; b=p4k+UMV9jxzrv+lXLzLbg3K1VYnip8hR4UzfaheAAyJBSV/1pZsmYwJ2GTtzoDDHM6Puo8X9zYb8TTcy8pNvBIPjdWQSjYv6BOBY07p3/4gBINfMhagl6XPvtHnplW5BYc5PtjKCe/h2BRQjeEkKR/ud0CM17raBOaC4bWC/2rA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388863; c=relaxed/simple; bh=lju0lzTKzNyWSKs8GRO52l6iJlWI1BbQuWoQ53C5IBE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o/4qAoPSHE5EnklmHkrvmEG8uOUzDWI1Nn8ohiZLErj9YkLw5JTu0I9jjaV5OcNHbZRd5cQdjbXAIM6EMNnNC1uGG+UyWcYwiCxFTDGbnnF3G3KgPJhvEhLqbX14wwL3ZaSBzS4n2rC11CKPptJ2RA2Rwk3Purd16Z6tpxD8BhU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ie+StPTt; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ie+StPTt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 93C011F00893; Mon, 14 Sep 2026 12:27:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388861; bh=ONUv8GT7AVuvGju01vgoySPFvTxbOCj9Mi71RpZ8izg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ie+StPTtBIv3Ciy7sijRl5nzJHeTn5uylXDoVvlecy7G9HGj7G6siPKQGQboFc3vA nxp1iNScQ+mMos67Hhykm5ojwguOvIwasE9qzPhVy2kxCeXHdMkyaONAnuAPUo98Ci NNxFke+UjHiO1DdzEnftHveme3N3G7rou57YmqdaD1PUFoORtOzN9hIZ3NECMs30wH A+pJbEsc/iMz5siRQTGq5IaGhOHMbUQULYIAbS9wQqmGIoNlurIyJtgvj8QvPFh7Cp TF41hT3+YsWXrzL//wzjE0qWTbGv2slRT+HRYBkJRcDO2j4TphK0ZR7cXbXGupOKVw vKduC/vcqRFxw== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:22 +0100 Subject: [PATCH v2 11/13] KVM: selftests: Enable pre_fault_memory_test for arm64 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-11-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7583; i=ljs@kernel.org; h=from:subject:message-id; bh=PtJ+fDCz2VxcBAFjDOIHMBfVyg3lZYR9z7edtkLP/hI=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/+W31/ZocwXYa75UX+LgOujdeInP5tEyta+Sprqf rd94l63jlIWBjEuBlkxRZbnX8T3B4mEzeu84O8GM4eVCWQIAxenAEwkn5eRYaMq68aPuRW7Fy43 ydpXab7p8XcNPrX/fpyFGyMUlXujmxkZbibc2L4t8eOrjER7xesyETy1KSun2FTEtD3bfPXOqUs 8fAA= X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 From: Jack Thomson Enable the pre_fault_memory_test to run on arm64 by making it work with different guest page sizes and testing multiple guest configurations. Add an assert on the exit reason, comparing against UCALL_EXIT_REASON so the check is portable, as arm64 exits with KVM_EXIT_MMIO while x86 uses KVM_EXIT_IO. Signed-off-by: Jack Thomson [ljs: merge conflict resolution with commit c847704619da, commit message accuracy fixup] Signed-off-by: Lorenzo Stoakes (ARM) --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/pre_fault_memory_test.c | 117 +++++++++++++++++= ---- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 5f8d17ee5f67..66a9a4e62888 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -199,6 +199,7 @@ TEST_GEN_PROGS_arm64 +=3D guest_memfd_test TEST_GEN_PROGS_arm64 +=3D mmu_stress_test TEST_GEN_PROGS_arm64 +=3D rseq_test TEST_GEN_PROGS_arm64 +=3D steal_time +TEST_GEN_PROGS_arm64 +=3D pre_fault_memory_test =20 TEST_GEN_PROGS_s390 =3D $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_s390 +=3D s390/memop diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/te= sting/selftests/kvm/pre_fault_memory_test.c index a0fcae3cb7a8..ee77c51cc566 100644 --- a/tools/testing/selftests/kvm/pre_fault_memory_test.c +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c @@ -12,19 +12,29 @@ #include #include #include +#include =20 /* Arbitrarily chosen values */ -#define TEST_SIZE (SZ_2M + PAGE_SIZE) -#define TEST_NPAGES (TEST_SIZE / PAGE_SIZE) +#define TEST_BASE_SIZE SZ_2M #define TEST_SLOT 10 =20 +/* Storage of test info to share with guest code */ +struct test_config { + u64 page_size; + u64 test_size; + u64 test_num_pages; +}; + +static struct test_config test_config; + static void guest_code(u64 base_gva) { volatile u64 val __used; + struct test_config *config =3D &test_config; int i; =20 - for (i =3D 0; i < TEST_NPAGES; i++) { - u64 *src =3D (u64 *)(base_gva + i * PAGE_SIZE); + for (i =3D 0; i < config->test_num_pages; i++) { + u64 *src =3D (u64 *)(base_gva + i * config->page_size); =20 val =3D *src; } @@ -57,7 +67,7 @@ static void *delete_slot_worker(void *__data) cpu_relax(); =20 vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa, - TEST_SLOT, TEST_NPAGES, data->flags); + TEST_SLOT, test_config.test_num_pages, data->flags); =20 return NULL; } @@ -150,8 +160,8 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64= base_gpa, u64 offset, /* * Assert success if prefaulting the entire range should succeed, i.e. * complete with no bytes remaining. Otherwise prefaulting should have - * failed due to ENOENT (due to RET_PF_EMULATE for emulated MMIO when - * no memslot exists). + * failed due to ENOENT (no memslot exists for the GPA; on x86 this + * surfaces via RET_PF_EMULATE). */ if (!expected_left) TEST_ASSERT_VM_VCPU_IOCTL(!ret, KVM_PRE_FAULT_MEMORY, ret, vcpu->vm); @@ -160,39 +170,72 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u= 64 base_gpa, u64 offset, KVM_PRE_FAULT_MEMORY, ret, vcpu->vm); } =20 -static void __test_pre_fault_memory(unsigned long vm_type, bool private) +struct test_params { + unsigned long vm_type; + bool private; +}; + +static void __test_pre_fault_memory(enum vm_guest_mode guest_mode, void *a= rg) { - gpa_t gpa, gva, alignment, guest_page_size; + gpa_t gpa, gva, alignment, guest_page_size, host_page_size; + struct test_params *p =3D arg; const struct vm_shape shape =3D { - .mode =3D VM_MODE_DEFAULT, - .type =3D vm_type, + .mode =3D guest_mode, + .type =3D p->vm_type, }; struct kvm_vcpu *vcpu; + struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; =20 + pr_info("Testing guest mode: %s\n", vm_guest_mode_string(guest_mode)); + vm =3D vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code); =20 - alignment =3D guest_page_size =3D vm_guest_mode_params[VM_MODE_DEFAULT].p= age_size; - gpa =3D (vm->max_gfn - TEST_NPAGES) * guest_page_size; + guest_page_size =3D vm_guest_mode_params[guest_mode].page_size; + host_page_size =3D getpagesize(); + + test_config.page_size =3D guest_page_size; + test_config.test_size =3D align_up(TEST_BASE_SIZE + test_config.page_size, + host_page_size); + test_config.test_num_pages =3D vm_calc_num_guest_pages(vm->mode, test_con= fig.test_size); + + gpa =3D (vm->max_gfn - test_config.test_num_pages) * test_config.page_siz= e; alignment =3D SZ_2M; + alignment =3D max(alignment, host_page_size); gpa =3D align_down(gpa, alignment); gva =3D gpa & ((1ULL << (vm->va_bits - 1)) - 1); =20 - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa, TEST_SLOT, - TEST_NPAGES, private ? KVM_MEM_GUEST_MEMFD : 0); - virt_map(vm, gva, gpa, TEST_NPAGES); + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + gpa, TEST_SLOT, test_config.test_num_pages, + p->private ? KVM_MEM_GUEST_MEMFD : 0); + virt_map(vm, gva, gpa, test_config.test_num_pages); =20 - if (private) - vm_mem_set_private(vm, gpa, TEST_SIZE); + if (p->private) + vm_mem_set_private(vm, gpa, test_config.test_size); =20 - pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private); - pre_fault_memory(vcpu, gpa, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private); - pre_fault_memory(vcpu, gpa, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private); + pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private); + /* Retry the same range after the first prefault attempt. */ + pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private); + pre_fault_memory(vcpu, gpa, + test_config.test_size - host_page_size, + host_page_size * 2, host_page_size, p->private); + pre_fault_memory(vcpu, gpa, test_config.test_size, + host_page_size, host_page_size, p->private); =20 vcpu_args_set(vcpu, 1, gva); + + /* Export the shared variables to the guest. */ + sync_global_to_guest(vm, test_config); + vcpu_run(vcpu); =20 + run =3D vcpu->run; + TEST_ASSERT(run->exit_reason =3D=3D UCALL_EXIT_REASON, + "Wanted %s, got exit reason: %u (%s)", + exit_reason_str(UCALL_EXIT_REASON), + run->exit_reason, exit_reason_str(run->exit_reason)); + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: REPORT_GUEST_ASSERT(uc); @@ -209,16 +252,46 @@ static void __test_pre_fault_memory(unsigned long vm_= type, bool private) =20 static void test_pre_fault_memory(unsigned long vm_type, bool private) { + struct test_params p =3D { + .vm_type =3D vm_type, + .private =3D private, + }; + if (vm_type && !(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(vm_type))) { pr_info("Skipping tests for vm_type 0x%lx\n", vm_type); return; } =20 - __test_pre_fault_memory(vm_type, private); + for_each_guest_mode(__test_pre_fault_memory, &p); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-m mode]\n", name); + puts(""); + guest_modes_help(); + puts(""); } =20 int main(int argc, char *argv[]) { + int opt; + + guest_modes_append_default(); + + while ((opt =3D getopt(argc, argv, "hm:")) !=3D -1) { + switch (opt) { + case 'm': + guest_modes_cmdline(optarg); + break; + case 'h': + default: + help(argv[0]); + exit(0); + } + } + TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY)); =20 test_pre_fault_memory(0, false); --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 10F62470E8E; Mon, 14 Sep 2026 12:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388868; cv=none; b=JLsE5iYcJlJ8v39oq8ON7+HRwLpeYkxUD2u57uHeJZDKmw186N7GD21DbhY/s1cTcmztU9Y02+S3W4VnOW/xezIFkwrmgZARgCixaRZJFIrXBh0GKsLsq9tR9PRrYPG/Mkp/bIs8NZmYdqEsqYHj9bHP/I9L/TPk8zhR5kR1TR8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388868; c=relaxed/simple; bh=2mli7Z7Iv34/jPztedKMCf45PGYRXNpv3Rf35FR6iow=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nepcoqMSBpyXwH4Euj1KgM6yiQbsn73G34lQ48hlExODtSWHh4r9mU7DdxUAIXXh0xS4ZxFqRHXdcnBXI6BbUdiJt/g0lUeIiygHdlsrb1+aAdE1asrPBH5rLPNoEsg0uUX9mwzpUwYSPVurnn6PtVYlafrxUCzkZqnGE9G9vDs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Io6C9H8n; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Io6C9H8n" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 774451F00898; Mon, 14 Sep 2026 12:27:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388866; bh=cRk7lD7czZ0zVPvtZdVAKc/8RTbrtJAsMOSGvFeFLfA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Io6C9H8n9TBJSPWspiFAo4lj1AINIU5qLH1BKYRpxfVkGRoRYiRDWGsydFbA4hwOP gXA+w75D6VyzBIb0ctScuhgE10mfZMR4qKwro2zsNcDjD8IVexr8IphkqIfC3KTh3n a/F3aASjPhZvmvcTvfjj/8AyNCLIP8q+azBQndoVerdhMFnyjjO+K2/Ehn/frT2teC aNQalNRhW0YPgonsDXqQFmsDfWxAQMjHo0XBdlK9XQjK0xoT5avqe2oe+wAUbSsLb7 6FRmkna9r4nX1SvlgpM/HnxJWlk37ij7y+KRYzHFCo7vl6/ZASm3No4eoRECwRBEMC zvc4qQrLmvz/w== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:23 +0100 Subject: [PATCH v2 12/13] KVM: selftests: Add option for different backing in pre-fault tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-12-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6683; i=ljs@kernel.org; h=from:subject:message-id; bh=PO6VwHVzr1ywPi/wKPjgqxPqz8SXyRcry63dvjVJNh0=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP/8mKO3QFf99W7Ygx8yTbd163+edFzraVFBd8G3ep 7VXPdrsOkpZGMS4GGTFFFmefxHfHyQSNq/zgr8bzBxWJpAhDFycAjARyyKG/w6X1zl/X7F21o9o X5NtyWzZ9YInPhsvP8P3esqJAuZ/3xUZGQ50OxVw3X9wQj/VIOhEWKbjC72gd4HTnStZ3xtafxZ eygkA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 From: Jack Thomson Add a -s option to specify different memory backing types for the pre-fault tests (e.g. anonymous, hugetlb), allowing testing of the pre-fault functionality across different memory configurations. Signed-off-by: Jack Thomson Signed-off-by: Lorenzo Stoakes (ARM) --- .../testing/selftests/kvm/pre_fault_memory_test.c | 51 +++++++++++++++---= ---- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/te= sting/selftests/kvm/pre_fault_memory_test.c index ee77c51cc566..702c72bbfa96 100644 --- a/tools/testing/selftests/kvm/pre_fault_memory_test.c +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c @@ -46,6 +46,7 @@ struct slot_worker_data { struct kvm_vm *vm; gpa_t gpa; u32 flags; + enum vm_mem_backing_src_type mem_backing_src; bool worker_ready; bool prefault_ready; bool recreate_slot; @@ -66,14 +67,16 @@ static void *delete_slot_worker(void *__data) while (!READ_ONCE(data->recreate_slot)) cpu_relax(); =20 - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa, + vm_userspace_mem_region_add(vm, data->mem_backing_src, data->gpa, TEST_SLOT, test_config.test_num_pages, data->flags); =20 return NULL; } =20 static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offs= et, - u64 size, u64 expected_left, bool private) + u64 size, u64 expected_left, + enum vm_mem_backing_src_type mem_backing_src, + bool private) { struct kvm_pre_fault_memory range =3D { .gpa =3D base_gpa + offset, @@ -84,6 +87,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 b= ase_gpa, u64 offset, .vm =3D vcpu->vm, .gpa =3D base_gpa, .flags =3D private ? KVM_MEM_GUEST_MEMFD : 0, + .mem_backing_src =3D mem_backing_src, }; bool slot_recreated =3D false; pthread_t slot_worker; @@ -173,11 +177,13 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u= 64 base_gpa, u64 offset, struct test_params { unsigned long vm_type; bool private; + enum vm_mem_backing_src_type mem_backing_src; }; =20 static void __test_pre_fault_memory(enum vm_guest_mode guest_mode, void *a= rg) { gpa_t gpa, gva, alignment, guest_page_size, host_page_size; + gpa_t backing_src_pagesz, mem_page_size; struct test_params *p =3D arg; const struct vm_shape shape =3D { .mode =3D guest_mode, @@ -189,24 +195,28 @@ static void __test_pre_fault_memory(enum vm_guest_mod= e guest_mode, void *arg) struct ucall uc; =20 pr_info("Testing guest mode: %s\n", vm_guest_mode_string(guest_mode)); + pr_info("Testing memory backing src type: %s\n", + vm_mem_backing_src_alias(p->mem_backing_src)->name); =20 vm =3D vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code); =20 guest_page_size =3D vm_guest_mode_params[guest_mode].page_size; host_page_size =3D getpagesize(); + backing_src_pagesz =3D get_backing_src_pagesz(p->mem_backing_src); + mem_page_size =3D max(host_page_size, backing_src_pagesz); =20 test_config.page_size =3D guest_page_size; test_config.test_size =3D align_up(TEST_BASE_SIZE + test_config.page_size, - host_page_size); + mem_page_size); test_config.test_num_pages =3D vm_calc_num_guest_pages(vm->mode, test_con= fig.test_size); =20 gpa =3D (vm->max_gfn - test_config.test_num_pages) * test_config.page_siz= e; alignment =3D SZ_2M; - alignment =3D max(alignment, host_page_size); + alignment =3D max(alignment, mem_page_size); gpa =3D align_down(gpa, alignment); gva =3D gpa & ((1ULL << (vm->va_bits - 1)) - 1); =20 - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + vm_userspace_mem_region_add(vm, p->mem_backing_src, gpa, TEST_SLOT, test_config.test_num_pages, p->private ? KVM_MEM_GUEST_MEMFD : 0); virt_map(vm, gva, gpa, test_config.test_num_pages); @@ -214,14 +224,18 @@ static void __test_pre_fault_memory(enum vm_guest_mod= e guest_mode, void *arg) if (p->private) vm_mem_set_private(vm, gpa, test_config.test_size); =20 - pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private); + pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, + p->mem_backing_src, p->private); /* Retry the same range after the first prefault attempt. */ - pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, p->private); + pre_fault_memory(vcpu, gpa, 0, test_config.test_size, 0, + p->mem_backing_src, p->private); pre_fault_memory(vcpu, gpa, test_config.test_size - host_page_size, - host_page_size * 2, host_page_size, p->private); + host_page_size * 2, host_page_size, + p->mem_backing_src, p->private); pre_fault_memory(vcpu, gpa, test_config.test_size, - host_page_size, host_page_size, p->private); + host_page_size, host_page_size, + p->mem_backing_src, p->private); =20 vcpu_args_set(vcpu, 1, gva); =20 @@ -250,11 +264,13 @@ static void __test_pre_fault_memory(enum vm_guest_mod= e guest_mode, void *arg) kvm_vm_free(vm); } =20 -static void test_pre_fault_memory(unsigned long vm_type, bool private) +static void test_pre_fault_memory(unsigned long vm_type, enum vm_mem_backi= ng_src_type backing_src, + bool private) { struct test_params p =3D { .vm_type =3D vm_type, .private =3D private, + .mem_backing_src =3D backing_src, }; =20 if (vm_type && !(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(vm_type))) { @@ -268,23 +284,28 @@ static void test_pre_fault_memory(unsigned long vm_ty= pe, bool private) static void help(char *name) { puts(""); - printf("usage: %s [-h] [-m mode]\n", name); + printf("usage: %s [-h] [-m mode] [-s mem-type]\n", name); puts(""); guest_modes_help(); + backing_src_help("-s"); puts(""); } =20 int main(int argc, char *argv[]) { + enum vm_mem_backing_src_type backing =3D DEFAULT_VM_MEM_SRC; int opt; =20 guest_modes_append_default(); =20 - while ((opt =3D getopt(argc, argv, "hm:")) !=3D -1) { + while ((opt =3D getopt(argc, argv, "hm:s:")) !=3D -1) { switch (opt) { case 'm': guest_modes_cmdline(optarg); break; + case 's': + backing =3D parse_backing_src_type(optarg); + break; case 'h': default: help(argv[0]); @@ -294,10 +315,10 @@ int main(int argc, char *argv[]) =20 TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY)); =20 - test_pre_fault_memory(0, false); + test_pre_fault_memory(0, backing, false); #ifdef __x86_64__ - test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, false); - test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, true); + test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, backing, false); + test_pre_fault_memory(KVM_X86_SW_PROTECTED_VM, backing, true); #endif return 0; } --=20 2.55.0 From nobody Fri Sep 25 10:03:48 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 0F33B4718FA; Mon, 14 Sep 2026 12:27:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388874; cv=none; b=IdwHESI4ETDg4sqNqZPhOJ7HwZcFcVWWLYYtEsY5PGRxbM4AvTBHo+ZwEjxppotR4wNvZFCgf9c/yPvT6EInx+VB8ePWXyT3+o6028myMVf5hcefWUXxQ4m3rggI4UayJNcZTba73/gnXZm65bRTGVlCCil+RLSG3IDX2r16UmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789388874; c=relaxed/simple; bh=jWGri653x+FF39q+LmajuQGRo5SzD2ymgUKx4l9C5To=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qdIaXOXZRfsYNqeYNTULJXzwX+EZymTN2z5QN/z9r7uA9CEYXaO+0+UiMepKUnJOwgvTr7U3dcJehUejsADyu8PPI3xC+KsGWKsBICSi+2eTJ7f57GPj0+FRWTHbpzW+81CcwWg92gf7VtyDZcQHtb+M2/QKkHrbkDRaXg5R9tE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g4O+bSjA; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g4O+bSjA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 52A1A1F000FF; Mon, 14 Sep 2026 12:27:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789388872; bh=BMhGWlwfT+kVNUcgZl5xzinPFe97kBLDh0bd5vegWbI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=g4O+bSjAHjTi57+vAIDvU1ks+7o+rzYFjUbigrjCjg17nvqd1jGyDP1VtSVQxO4g3 iWMBQ/i3EEkRBwXOaeDTT4pefcZnQGoIMQJPBfjuxa3ea1CV2gGJMmaOsQfyvpjeR8 tUqDPxajomLAJnjey9V8wJyuV6Fpsf+U+ztKrhq+6lw83Ofn7SXsMCQ/frfrX2fL0+ SmBdw/QW/JGG6P8p+Zyonz7EODdmwlI0Lx5lKL3/osgipOt0wQTOemgbQKWzU7Y8QB wxEkxH693Zdw0DzOvJ5KJAkDCk85esyYwPt4Dd0wnxYD5ibhmDjeZOd5ISUHHznqzY LtCKLs/QHj60w== From: "Lorenzo Stoakes (ARM)" Date: Mon, 14 Sep 2026 13:26:24 +0100 Subject: [PATCH v2 13/13] KVM: selftests: Add nested pre-fault test for arm64 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260914-kvm-arm-prefault-v2-13-26fb47f74b73@kernel.org> References: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> In-Reply-To: <20260914-kvm-arm-prefault-v2-0-26fb47f74b73@kernel.org> To: Catalin Marinas , Will Deacon , Marc Zyngier , Oliver Upton , Fuad Tabba , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Paolo Bonzini , Jonathan Corbet Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, kvmarm@lists.linux.dev, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Jack Thomson , Jack Thomson , Alexandru Elisei , Vincent Donnefort , "Aneesh Kumar K.V" , Sean Christopherson , Claudio Imbrenda , Leo Soares Passos , "Lorenzo Stoakes (ARM)" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6315; i=ljs@kernel.org; h=from:subject:message-id; bh=jWGri653x+FF39q+LmajuQGRo5SzD2ymgUKx4l9C5To=; b=owGbwMvMwCV2fu7ZrsZH9SKMp9WSGLKWP//mfv35lTUVKdURlyISHZeIll25YXRhSnPj4e5+H uO0nmuqHaUsDGJcDLJiiizPv4jvDxIJm9d5wd8NZg4rE8gQBi5OAZhI1FGG//WhzxW2LovbErLl ys3M9UGqNv9q1Q+vrde4Liadd7zihRcjw+1iy8RZ/ke3f/TeuUtLKGVVP2PvgelHFezK/zK9qHx 3mgMA X-Developer-Key: i=ljs@kernel.org; a=openpgp; fpr=E7F417BF5214569E89D04F46CF9DCD8A81E27F14 Add an arm64 nested-virtualisation selftest for KVM_PRE_FAULT_MEMORY. The guest enters vEL2, sets up its EL2 translation configuration into the real EL1 registers then ERETs to vEL1 and exits to userspace so its vCPU last-run context is nested backed by a shadow stage 2 MMU. The test then asserts that pre-faulting ignores that and instead targets the canonical stage 2 page tables only. Userspace cannot observe a mistargeted pre-fault, so simply assert that the pre-faulting works correctly when the last-run context was nested. Based on a patch by Jack Thomson with gratitude. The test here is simplified and focused on what can be asserted. Link: https://lore.kernel.org/kvmarm/20260612162354.73378-6-jackabt.amazon@= gmail.com/ Signed-off-by: Lorenzo Stoakes (ARM) --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/arm64/nv_pre_fault_memory_test.c | 158 +++++++++++++++++= ++++ 2 files changed, 159 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 66a9a4e62888..1e0edd0f99f7 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -173,6 +173,7 @@ TEST_GEN_PROGS_arm64 +=3D arm64/debug-exceptions TEST_GEN_PROGS_arm64 +=3D arm64/hello_el2 TEST_GEN_PROGS_arm64 +=3D arm64/host_sve TEST_GEN_PROGS_arm64 +=3D arm64/hypercalls +TEST_GEN_PROGS_arm64 +=3D arm64/nv_pre_fault_memory_test TEST_GEN_PROGS_arm64 +=3D arm64/external_aborts TEST_GEN_PROGS_arm64 +=3D arm64/mmio_sign_ext TEST_GEN_PROGS_arm64 +=3D arm64/page_fault_test diff --git a/tools/testing/selftests/kvm/arm64/nv_pre_fault_memory_test.c b= /tools/testing/selftests/kvm/arm64/nv_pre_fault_memory_test.c new file mode 100644 index 000000000000..09c1db303856 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/nv_pre_fault_memory_test.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * nv_pre_fault_memory_test - Test KVM_PRE_FAULT_MEMORY on a vCPU whose + * last-run context is nested. + * + * The guest enters vEL2, sets up its EL2 translation configuration into t= he + * real EL1 registers then ERETs to vEL1 and exits to userspace so its vCPU + * last-run context is nested backed by a shadow stage 2 MMU. + * + * Assert that pre-faulting ignores that and targets the canonical stage-2 + * page tables only. + */ +#include "kvm_util.h" +#include "processor.h" +#include "test_util.h" +#include "ucall.h" + +#include +#include + +#define TEST_MEM_SLOT 10 +#define TEST_MEM_SIZE SZ_2M +#define TEST_MEM_GPA SZ_1G + +static void guest_el1_code(void) +{ + u64 offset; + + GUEST_ASSERT_EQ(get_current_el(), 1); + + /* Exit to userspace with the vEL1 (nested) context live. */ + GUEST_SYNC(1); + + /* + * Touch the prefaulted range. vstage-2 is disabled, so the shadow + * stage-2 is a 1:1 view of the canonical IPA space. + */ + for (offset =3D 0; offset < TEST_MEM_SIZE; offset +=3D SZ_4K) + READ_ONCE(*(u64 *)(TEST_MEM_GPA + offset)); + + GUEST_DONE(); +} + +static void guest_code(void) +{ + u64 sp; + + GUEST_ASSERT_EQ(get_current_el(), 2); + + /* + * Mirror the EL2 translation regime into the real EL1 registers so + * that vEL1 runs on the test's stage-1 page tables. With E2H=3D1, the + * _EL1 accessors read the EL2 registers, and the _EL12 accessors + * write the real EL1 registers. + */ + write_sysreg_s(read_sysreg(sctlr_el1), SYS_SCTLR_EL12); + write_sysreg_s(read_sysreg(tcr_el1), SYS_TCR_EL12); + write_sysreg_s(read_sysreg(ttbr0_el1), SYS_TTBR0_EL12); + write_sysreg_s(read_sysreg(mair_el1), SYS_MAIR_EL12); + write_sysreg_s(read_sysreg(cpacr_el1), SYS_CPACR_EL12); + + /* Run vEL1 on the same stack. */ + asm volatile("mov %0, sp" : "=3Dr"(sp)); + write_sysreg(sp, sp_el1); + + /* + * Drop TGE so that vEL1 is a nested context rather than host EL0. + * KVM backs it with a shadow stage-2 MMU even though vstage-2 is + * disabled (HCR_EL2.VM=3D0). + */ + write_sysreg(read_sysreg(hcr_el2) & ~HCR_EL2_TGE, hcr_el2); + isb(); + + write_sysreg(PSR_MODE_EL1h | PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | + PSR_D_BIT, spsr_el2); + write_sysreg((u64)guest_el1_code, elr_el2); + asm volatile("eret"); + + GUEST_ASSERT(false); +} + +static void pre_fault(struct kvm_vcpu *vcpu, u64 gpa, u64 size) +{ + struct kvm_pre_fault_memory range =3D { + .gpa =3D gpa, + .size =3D size, + }; + int ret; + + do { + ret =3D __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range); + } while ((!ret && range.size) || + (ret < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN))); + + TEST_ASSERT(!ret, "KVM_PRE_FAULT_MEMORY failed, ret: %d errno: %d", + ret, errno); + TEST_ASSERT_EQ(range.size, 0); +} + +int main(void) +{ + struct kvm_vcpu_init init; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + u64 npages; + + TEST_REQUIRE(test_supports_el2()); + TEST_REQUIRE(kvm_check_cap(KVM_CAP_PRE_FAULT_MEMORY)); + + vm =3D vm_create(1); + + kvm_get_default_vcpu_target(vm, &init); + init.features[0] |=3D BIT(KVM_ARM_VCPU_HAS_EL2); + vcpu =3D aarch64_vcpu_add(vm, 0, &init, guest_code); + kvm_arch_vm_finalize_vcpus(vm); + + npages =3D TEST_MEM_SIZE / vm->page_size; + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, TEST_MEM_GPA, + TEST_MEM_SLOT, npages, 0); + virt_map(vm, TEST_MEM_GPA, TEST_MEM_GPA, npages); + + /* Run the guest until it has ERET'd from vEL2 to vEL1. */ + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + TEST_ASSERT_EQ(uc.args[1], 1); + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); + } + + /* + * The vCPU's last-run context is vEL1, so its hw_mmu is a shadow + * stage-2 MMU. + * + * Pre-faulting must ignore that and populate the canonical stage-2. + */ + pre_fault(vcpu, TEST_MEM_GPA, TEST_MEM_SIZE); + + /* Resume at vEL1 and touch the prefaulted range. */ + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); + } + + kvm_vm_free(vm); + return 0; +} --=20 2.55.0