[PATCH v2 6/6] KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
Fuad Tabba
tabba at google.com
Thu Dec 11 06:51:25 PST 2025
On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> wrote:
>
> Now that we potentially have two bits to deal with when setting
> execution permissions, make sure we correctly handle them when both
> when building the page tables and when reading back from them.
>
> Reported-by: Alexandru Elisei <alexandru.elisei at arm.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
Reviewed-by: Fuad Tabba <tabba at google.com>
/fuad
> ---
> arch/arm64/include/asm/kvm_pgtable.h | 12 +++---------
> arch/arm64/kvm/hyp/pgtable.c | 24 +++++++++++++++++++++---
> 2 files changed, 24 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
> index be68b89692065..095e6b73740a6 100644
> --- a/arch/arm64/include/asm/kvm_pgtable.h
> +++ b/arch/arm64/include/asm/kvm_pgtable.h
> @@ -87,15 +87,9 @@ typedef u64 kvm_pte_t;
>
> #define KVM_PTE_LEAF_ATTR_HI_SW GENMASK(58, 55)
>
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_UXN BIT(54)
> -#define __KVM_PTE_LEAF_ATTR_HI_S1_PXN BIT(53)
> -
> -#define KVM_PTE_LEAF_ATTR_HI_S1_XN \
> - ({ cpus_have_final_cap(ARM64_KVM_HVHE) ? \
> - (__KVM_PTE_LEAF_ATTR_HI_S1_UXN | \
> - __KVM_PTE_LEAF_ATTR_HI_S1_PXN) : \
> - __KVM_PTE_LEAF_ATTR_HI_S1_XN; })
> +#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_UXN BIT(54)
> +#define KVM_PTE_LEAF_ATTR_HI_S1_PXN BIT(53)
>
> #define KVM_PTE_LEAF_ATTR_HI_S2_XN GENMASK(54, 53)
>
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index e0bd6a0172729..97c0835d25590 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -342,6 +342,9 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
> if (!(prot & KVM_PGTABLE_PROT_R))
> return -EINVAL;
>
> + if (!cpus_have_final_cap(ARM64_KVM_HVHE))
> + prot &= ~KVM_PGTABLE_PROT_UX;
> +
> if (prot & KVM_PGTABLE_PROT_X) {
> if (prot & KVM_PGTABLE_PROT_W)
> return -EINVAL;
> @@ -351,8 +354,16 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
>
> if (system_supports_bti_kernel())
> attr |= KVM_PTE_LEAF_ATTR_HI_S1_GP;
> + }
> +
> + if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> + if (!(prot & KVM_PGTABLE_PROT_PX))
> + attr |= KVM_PTE_LEAF_ATTR_HI_S1_PXN;
> + if (!(prot & KVM_PGTABLE_PROT_UX))
> + attr |= KVM_PTE_LEAF_ATTR_HI_S1_UXN;
> } else {
> - attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
> + if (!(prot & KVM_PGTABLE_PROT_PX))
> + attr |= KVM_PTE_LEAF_ATTR_HI_S1_XN;
> }
>
> attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
> @@ -373,8 +384,15 @@ enum kvm_pgtable_prot kvm_pgtable_hyp_pte_prot(kvm_pte_t pte)
> if (!kvm_pte_valid(pte))
> return prot;
>
> - if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> - prot |= KVM_PGTABLE_PROT_X;
> + if (cpus_have_final_cap(ARM64_KVM_HVHE)) {
> + if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_PXN))
> + prot |= KVM_PGTABLE_PROT_PX;
> + if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_UXN))
> + prot |= KVM_PGTABLE_PROT_UX;
> + } else {
> + if (!(pte & KVM_PTE_LEAF_ATTR_HI_S1_XN))
> + prot |= KVM_PGTABLE_PROT_PX;
> + }
>
> ap = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S1_AP, pte);
> if (ap == KVM_PTE_LEAF_ATTR_LO_S1_AP_RO)
> --
> 2.47.3
>
More information about the linux-arm-kernel
mailing list