From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C5323502A4; Wed, 25 Mar 2026 09:18:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774430303; cv=none; b=CCYplBmCacgPkiDkqViv7Xttn9uFChhrgOHqZql86n+B7PMZ0mm9HodLhD+Guhle9FlSd6BAZh13dH8m/69IqP8gHfUie1974vYFUpy0vPUNJSdcrfihBQtXaGJrMpcW7uRmUz29wcoLy6/r4lnm5TzKDmBRDArGmq5wDoht7go= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774430303; c=relaxed/simple; bh=0i4abdRDleJm92gWlAzYDCiaX3cyuhdf9fdZTk6kWlI=; h=Date:Message-ID:From:To:Cc:Subject:In-Reply-To:References: MIME-Version:Content-Type; b=M2Ri5iFBz8TZptumPpjb+kw/Ndf8q/LAjIYfCQfIP5jplDsZHYgj2D8TAkaWvIHahjBGugg4/g3fa44gpcV/hUBEbgQQr4S+Hc6DO31GoJ6RJGsrTpg8fckT0vmeNBJBVsJiqUzchw8eiExAMXqjXyPdxvg1IGjCMkTZB8eF2+8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=C8bgt+aS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="C8bgt+aS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD2D2C4CEF7; Wed, 25 Mar 2026 09:18:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774430302; bh=0i4abdRDleJm92gWlAzYDCiaX3cyuhdf9fdZTk6kWlI=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=C8bgt+aSaIBXurlz5x1xUUO0IvckVpM/oUBKrmOjwTSFa4Upl8Rl75127DwiSs34h ilQByYAjum0+9FBVmUCpYMER9HvMEMj/l8TuZEKFeEvLGtYiLyGpO/NvGeCtrk3lvK nBQ0de7bobdfILJK6idX5Qtsugmm5AdRNqsRjxdrov8goDeBdeAGQ7eT/KOc+914Gb Zm1uGMp1Qw3j7yTt8OY22nB+2l5bfvNPhGo5TVkka6vulOSM15QpPydA+D9BqAk2F/ prdYYlP1tIgNzVPXy5Pk7N/UXjdOSYvj39EaUT1aYBH8FWOmFlIZywZjxG6jFxWFyZ ErPTweqjgwY0Q== Received: from sofa.misterjones.org ([185.219.108.64] helo=goblin-girl.misterjones.org) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1w5KNY-00000005U8U-2Vxu; Wed, 25 Mar 2026 09:18:20 +0000 Date: Wed, 25 Mar 2026 09:18:20 +0000 Message-ID: <86mrzw468z.wl-maz@kernel.org> From: Marc Zyngier To: Wei-Lin Chang Cc: kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, Paolo Bonzini , Shuah Khan , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon Subject: Re: [PATCH 3/3] KVM: arm64: selftests: Enable stage-2 in NV preparation functions In-Reply-To: <20260325003620.2214766-4-weilin.chang@arm.com> References: <20260325003620.2214766-1-weilin.chang@arm.com> <20260325003620.2214766-4-weilin.chang@arm.com> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM-LB/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL-LB/10.8 EasyPG/1.0.0 Emacs/30.1 (aarch64-unknown-linux-gnu) MULE/6.0 (HANACHIRUSATO) Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: weilin.chang@arm.com, kvm@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, pbonzini@redhat.com, shuah@kernel.org, oupton@kernel.org, joey.gouly@arm.com, suzuki.poulose@arm.com, yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false On Wed, 25 Mar 2026 00:36:20 +0000, Wei-Lin Chang wrote: > > Introduce library functions for setting up guest stage-2 page tables, > then use that to give L2 an identity mapped stage-2 and enable it. > > The translation and stage-2 page table built is simple, start level 0, > 4 levels, 4KB granules, normal cachable, 48-bit IA, 40-bit OA. That's a no go. The most common NV-capable out there can realistically only do 16kB at S2, and is limited to 36bit IPA. We can't really afford to say "too bad" and leave the main development platform behind. > > The nested page table code is adapted from lib/x86/vmx.c. I guess this starting point is the main issue. > > Signed-off-by: Wei-Lin Chang > --- > .../selftests/kvm/include/arm64/nested.h | 7 ++ > .../selftests/kvm/include/arm64/processor.h | 9 ++ > .../testing/selftests/kvm/lib/arm64/nested.c | 97 ++++++++++++++++++- > 3 files changed, 111 insertions(+), 2 deletions(-) > > diff --git a/tools/testing/selftests/kvm/include/arm64/nested.h b/tools/testing/selftests/kvm/include/arm64/nested.h > index 739ff2ee0161..0be10a775e48 100644 > --- a/tools/testing/selftests/kvm/include/arm64/nested.h > +++ b/tools/testing/selftests/kvm/include/arm64/nested.h > @@ -6,6 +6,13 @@ > #ifndef SELFTEST_KVM_NESTED_H > #define SELFTEST_KVM_NESTED_H > > +uint64_t get_l1_vtcr(void); > + > +void nested_map(struct kvm_vm *vm, vm_paddr_t guest_pgd, > + uint64_t nested_paddr, uint64_t paddr, uint64_t size); > +void nested_map_memslot(struct kvm_vm *vm, vm_paddr_t guest_pgd, > + uint32_t memslot); > + > void prepare_l2_stack(struct kvm_vm *vm, struct kvm_vcpu *vcpu); > void prepare_hyp_state(struct kvm_vm *vm, struct kvm_vcpu *vcpu); > void prepare_eret_destination(struct kvm_vm *vm, struct kvm_vcpu *vcpu, void *l2_pc); > diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h > index ac97a1c436fc..5de2e932d95a 100644 > --- a/tools/testing/selftests/kvm/include/arm64/processor.h > +++ b/tools/testing/selftests/kvm/include/arm64/processor.h > @@ -104,6 +104,15 @@ > #define TCR_HA (UL(1) << 39) > #define TCR_DS (UL(1) << 59) > > +/* VTCR_EL2 specific flags */ > +#define VTCR_EL2_T0SZ_BITS(x) ((UL(64) - (x)) << VTCR_EL2_T0SZ_SHIFT) > + > +#define VTCR_EL2_SL0_LV0_4K (UL(2) << VTCR_EL2_SL0_SHIFT) > +#define VTCR_EL2_SL0_LV1_4K (UL(1) << VTCR_EL2_SL0_SHIFT) > +#define VTCR_EL2_SL0_LV2_4K (UL(0) << VTCR_EL2_SL0_SHIFT) > + > +#define VTCR_EL2_PS_40_BITS (UL(2) << VTCR_EL2_PS_SHIFT) > + > /* > * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). > */ > diff --git a/tools/testing/selftests/kvm/lib/arm64/nested.c b/tools/testing/selftests/kvm/lib/arm64/nested.c > index 111d02f44cfe..910f8cd30f96 100644 > --- a/tools/testing/selftests/kvm/lib/arm64/nested.c > +++ b/tools/testing/selftests/kvm/lib/arm64/nested.c > @@ -1,8 +1,11 @@ > // SPDX-License-Identifier: GPL-2.0 > /* > - * ARM64 Nested virtualization helpers > + * ARM64 Nested virtualization helpers, nested page table code adapted from > + * ../x86/vmx.c. > */ > > +#include > + > #include "kvm_util.h" > #include "nested.h" > #include "processor.h" > @@ -18,6 +21,87 @@ static void hvc_handler(struct ex_regs *regs) > regs->pc = (u64)after_hvc; > } > > +uint64_t get_l1_vtcr(void) > +{ > + return VTCR_EL2_PS_40_BITS | VTCR_EL2_TG0_4K | VTCR_EL2_ORGN0_WBWA | > + VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LV0_4K | VTCR_EL2_T0SZ_BITS(48); Irk. See above. > +} > + > +static void __nested_pg_map(struct kvm_vm *vm, uint64_t guest_pgd, > + uint64_t nested_paddr, uint64_t paddr, uint64_t flags) > +{ > + uint8_t attr_idx = flags & (PTE_ATTRINDX_MASK >> PTE_ATTRINDX_SHIFT); > + uint64_t pg_attr; > + uint64_t *ptep; > + > + TEST_ASSERT((nested_paddr % vm->page_size) == 0, > + "L2 IPA not on page boundary,\n" > + " nested_paddr: 0x%lx vm->page_size: 0x%x", nested_paddr, vm->page_size); > + TEST_ASSERT((paddr % vm->page_size) == 0, > + "Guest physical address not on page boundary,\n" > + " paddr: 0x%lx vm->page_size: 0x%x", paddr, vm->page_size); > + TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn, > + "Physical address beyond maximum supported,\n" > + " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", > + paddr, vm->max_gfn, vm->page_size); > + > + ptep = addr_gpa2hva(vm, guest_pgd) + ((nested_paddr >> 39) & 0x1ffu) * 8; > + if (!*ptep) > + *ptep = (vm_alloc_page_table(vm) & GENMASK(47, 12)) | PGD_TYPE_TABLE | PTE_VALID; > + ptep = addr_gpa2hva(vm, *ptep & GENMASK(47, 12)) + ((nested_paddr >> 30) & 0x1ffu) * 8; > + if (!*ptep) > + *ptep = (vm_alloc_page_table(vm) & GENMASK(47, 12)) | PUD_TYPE_TABLE | PTE_VALID; > + ptep = addr_gpa2hva(vm, *ptep & GENMASK(47, 12)) + ((nested_paddr >> 21) & 0x1ffu) * 8; > + if (!*ptep) > + *ptep = (vm_alloc_page_table(vm) & GENMASK(47, 12)) | PMD_TYPE_TABLE | PTE_VALID; > + ptep = addr_gpa2hva(vm, *ptep & GENMASK(47, 12)) + ((nested_paddr >> 12) & 0x1ffu) * 8; > + > + pg_attr = PTE_AF | PTE_ATTRINDX(attr_idx) | PTE_TYPE_PAGE | PTE_VALID; > + pg_attr |= PTE_SHARED; > + > + *ptep = (paddr & GENMASK(47, 12)) | pg_attr; Please use named constants, and write a page table generator that is independent of page, IA and OA sizes, as advertised to the guest. Thanks, M. -- Without deviation from the norm, progress is not possible.