Hi Itaru,

The usual subject prefix in the tree is "KVM: arm64: selftests:", for
this patch and the next one.

On Tue, 25 Aug 2026 at 22:18, Itaru Kitayama <[email protected]> wrote:
>
> Add p4d_index() for when 5-level paging required, i.e., V52 guest mode
> IDs. With the index helper function, _virt_pg_map() handles 5-level

Only VM_MODE_P52V52_4K has five levels. The 16K and 64K V52 modes get
four and three, so this is for the 4K granule rather than for V52
modes as a class.

...

>  u64 *virt_get_pte_hva_at_level(struct kvm_vm *vm, gva_t gva, int level)
>  {
> +       int start_level = 4 - vm->mmu.pgtable_levels;
>         u64 *ptep;
>
> +       TEST_ASSERT(level >= start_level && level <= 3,
> +                   "Invalid translation level %d, valid range is %d-3",
> +                   level, start_level);
> +
>         if (!vm->mmu.pgd_created)
>                 goto unmapped_gva;
>
>         ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, gva) * 8;
>         if (!ptep)
>                 goto unmapped_gva;
> -       if (level == 0)
> +       /*
> +        * Stage-1 translation starts at level -1 for a five-level page
> +        * table, and at levels 0, 1, or 2 for four-, three-, or two-level
> +        * page tables, respectively.
> +        */
> +       if (level == start_level)


This changes what level means for the existing three-level modes:
level 0 used to return the top-level entry and now trips the assert,
level 1 used to return the leaf and now returns the top level. No
caller in tree asks for either of those two levels, and the new
numbering matches the architecture.

...

> @@ -321,12 +356,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct 
> kvm_vcpu_init *init)
>         case VM_MODE_PXXVYY_4K:
>                 TEST_FAIL("AArch64 does not support 4K sized pages "
>                           "with ANY-bit physical address ranges");
> +       case VM_MODE_P52V52_64K:

These VM_MODE_ enumerators arrive in patch 2, so this patch does not
build on its own:

  lib/arm64/processor.c:359:7: error: use of undeclared identifier
'VM_MODE_P52V52_64K'; did you mean 'VM_MODE_P52V48_64K'?
  lib/arm64/processor.c:360:7: error: duplicate case value 'VM_MODE_P52V48_64K'

There are other build errors from the same cause. Could you move the
enum values and their vm_guest_mode_string()/vm_guest_mode_params[]
entries into this patch, or a new one altogether?

>         case VM_MODE_P52V48_64K:
>         case VM_MODE_P48V48_64K:
>         case VM_MODE_P40V48_64K:
>         case VM_MODE_P36V48_64K:
>                 tcr_el1 |= TCR_TG0_64K;
>                 break;
> +       case VM_MODE_P52V52_16K:
>         case VM_MODE_P52V48_16K:
>         case VM_MODE_P48V48_16K:
>         case VM_MODE_P40V48_16K:
> @@ -334,6 +371,7 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct 
> kvm_vcpu_init *init)
>         case VM_MODE_P36V47_16K:
>                 tcr_el1 |= TCR_TG0_16K;
>                 break;
> +       case VM_MODE_P52V52_4K:
>         case VM_MODE_P52V48_4K:
>         case VM_MODE_P48V48_4K:
>         case VM_MODE_P40V48_4K:
> @@ -348,6 +386,9 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct 
> kvm_vcpu_init *init)
>
>         /* Configure output size */
>         switch (vm->mode) {
> +       case VM_MODE_P52V52_4K:
> +       case VM_MODE_P52V52_16K:
> +       case VM_MODE_P52V52_64K:
>         case VM_MODE_P52V48_4K:
>         case VM_MODE_P52V48_16K:
>         case VM_MODE_P52V48_64K:
> @@ -578,6 +619,42 @@ static u32 max_ipa_for_page_size(u32 vm_ipa, u32 gran,
>                 return min(vm_ipa, 48U);
>  }
>
> +u32 aarch64_get_supported_va_size(void)

This repeats aarch64_get_supported_page_sizes() below it and builds a
second probe VM one line after the first. Could it take a u32 *va
out-param, so both ID registers come off the one vCPU?

VARange is the 52-bit VA indicator for the 64K granule only, so a bare
52 or 48 reads as granule-independent. The caller in patch 2 only uses
it for 64K, so nothing is wrong today.

Cheers,
/fuad


> +{
> +       struct kvm_vcpu_init preferred_init = {};
> +       int kvm_fd, vm_fd, vcpu_fd, err;
> +       u64 val;
> +       u32 va_range;
> +       struct kvm_one_reg reg = {
> +               .id     = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR2_EL1),
> +               .addr   = (u64)&val,
> +       };
> +
> +       kvm_fd = open_kvm_dev_path_or_exit();
> +       vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL);
> +       TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd));
> +
> +       vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
> +       TEST_ASSERT(vcpu_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu_fd));
> +
> +       err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
> +       TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_PREFERRED_TARGET, err));
> +
> +       err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init);
> +       TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_VCPU_INIT, err));
> +
> +       err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
> +       TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, err));
> +
> +       va_range = FIELD_GET(ID_AA64MMFR2_EL1_VARange, val);
> +
> +       close(vcpu_fd);
> +       close(vm_fd);
> +       close(kvm_fd);
> +
> +       return va_range >= ID_AA64MMFR2_EL1_VARange_52 ? 52 : 48;
> +}
> +
>  void aarch64_get_supported_page_sizes(u32 ipa, u32 *ipa4k,
>                                       u32 *ipa16k, u32 *ipa64k)
>  {
>
> --
> 2.43.0
>

Reply via email to