From: Marc Zyngier <maz@kernel.org>
To: Wei-Lin Chang <weilin.chang@arm.com>
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 <pbonzini@redhat.com>,
Shuah Khan <shuah@kernel.org>, Oliver Upton <oupton@kernel.org>,
Joey Gouly <joey.gouly@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>
Subject: Re: [PATCH 3/3] KVM: arm64: selftests: Enable stage-2 in NV preparation functions
Date: Wed, 25 Mar 2026 09:18:20 +0000 [thread overview]
Message-ID: <86mrzw468z.wl-maz@kernel.org> (raw)
In-Reply-To: <20260325003620.2214766-4-weilin.chang@arm.com>
On Wed, 25 Mar 2026 00:36:20 +0000,
Wei-Lin Chang <weilin.chang@arm.com> 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 <weilin.chang@arm.com>
> ---
> .../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 <linux/sizes.h>
> +
> #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.
next prev parent reply other threads:[~2026-03-25 9:18 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-25 0:36 [PATCH 0/3] KVM: arm64: selftests: Basic nested guest support Wei-Lin Chang
2026-03-25 0:36 ` [PATCH 1/3] KVM: arm64: selftests: Add library functions for NV Wei-Lin Chang
2026-03-25 9:03 ` Marc Zyngier
2026-03-26 14:28 ` Wei-Lin Chang
2026-03-25 0:36 ` [PATCH 2/3] KVM: arm64: sefltests: Add basic NV selftest Wei-Lin Chang
2026-03-25 0:36 ` [PATCH 3/3] KVM: arm64: selftests: Enable stage-2 in NV preparation functions Wei-Lin Chang
2026-03-25 6:23 ` Itaru Kitayama
2026-03-26 21:34 ` Wei-Lin Chang
2026-03-25 9:18 ` Marc Zyngier [this message]
2026-03-26 21:16 ` Wei-Lin Chang
2026-03-25 8:00 ` [PATCH 0/3] KVM: arm64: selftests: Basic nested guest support Itaru Kitayama
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=86mrzw468z.wl-maz@kernel.org \
--to=maz@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=joey.gouly@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=oupton@kernel.org \
--cc=pbonzini@redhat.com \
--cc=shuah@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=weilin.chang@arm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox