summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2025-12-10 20:30:24 +0300
committerMarc Zyngier <maz@kernel.org>2026-01-15 13:58:21 +0300
commit80cbfd7174f31010982f065e8ae73bf337992105 (patch)
tree1726812723c46d248876817508797c09853e9188
parent9d2de51825598fc8e76f596c16368362753d8021 (diff)
downloadlinux-80cbfd7174f31010982f065e8ae73bf337992105.tar.xz
KVM: arm64: Honor UX/PX attributes for EL2 S1 mappings
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@arm.com> Reviewed-by: Fuad Tabba <tabba@google.com> Reviewed-by: Joey Gouly <joey.gouly@arm.com> Tested-by: Fuad Tabba <tabba@google.com> Link: https://patch.msgid.link/20251210173024.561160-7-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
-rw-r--r--arch/arm64/include/asm/kvm_pgtable.h12
-rw-r--r--arch/arm64/kvm/hyp/pgtable.c24
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 c0ad262a8289..56bd08be9630 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 a99a7d6e7d0c..13e34d66b6a7 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)