Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Mark Brown <broonie@kernel.org>
To: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
	 Fuad Tabba <fuad.tabba@linux.dev>,
	Joey Gouly <joey.gouly@arm.com>,
	 Steffen Eiden <seiden@linux.ibm.com>,
	 Suzuki K Poulose <suzuki.poulose@arm.com>,
	 Zenghui Yu <yuzenghui@huawei.com>,
	 Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	 Mark Rutland <mark.rutland@arm.com>
Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	 linux-kernel@vger.kernel.org, Mark Brown <broonie@kernel.org>
Subject: [PATCH 2/2] KVM: arm64: Enable S1PIE for nVHE and hVHE
Date: Fri, 04 Sep 2026 00:14:42 +0100	[thread overview]
Message-ID: <20260904-kvm-arm64-nvhe-pie-v1-2-29d59f245e6c@kernel.org> (raw)
In-Reply-To: <20260904-kvm-arm64-nvhe-pie-v1-0-29d59f245e6c@kernel.org>

When FEAT_S1PIE (stage 1 permission indirection) is supported we
currently enable and use it in the hypervisor when running in VHE mode
but not when running in nVHE or hVHE mode.  While systems with
FEAT_S1PIE would normally use VHE users can configure them for nVHE or
hVHE, for example in order to run protected guests.  Enable FEAT_S1PIE
with nVHE and hVHE.

AP[1] is one of the bits used to encode the indirected permissions.
Since for hVHE this is always 0 and for nVHE it is always 1 we only
configure the subset of indirected permissions that the system is
expected to use.

With permission indirection read only permissions must be encoded in the
bits used by PIE, set DBM for read only mappings.  Only do this when
using S1PIE, the hypervisor does not otherwise use DBM and if we were
actually using DBM it would be for writable mappings.

This should have no practical impact other than causing any unexpected
encodings to map to no permissions instead of their default meanings.
It will mean that the configuration is closer to that in VHE mode, and
will be required for future work enabling features like D128 and GCS
which are only available via indirection.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/include/asm/kvm_asm.h     |  1 +
 arch/arm64/include/asm/kvm_pgtable.h | 26 ++++++++++++++++++++++++++
 arch/arm64/kernel/asm-offsets.c      |  1 +
 arch/arm64/kvm/arm.c                 |  8 ++++++++
 arch/arm64/kvm/hyp/nvhe/hyp-init.S   |  6 ++++++
 arch/arm64/kvm/hyp/pgtable.c         |  7 +++++++
 6 files changed, 49 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index eb796436d6eb..bc587be33703 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -207,6 +207,7 @@ extern void *__vhe_undefined_symbol;
 
 struct kvm_nvhe_init_params {
 	unsigned long mair_el2;
+	unsigned long pir_el2;
 	unsigned long tcr_el2;
 	unsigned long tcr2_el2;
 	unsigned long tpidr_el2;
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 41a8687938eb..7c5c87c6745e 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -93,6 +93,7 @@ typedef u64 kvm_pte_t;
 
 #define KVM_PTE_LEAF_ATTR_HI_S2_XN	GENMASK(54, 53)
 
+#define KVM_PTE_LEAF_ATTR_HI_S1_DBM	BIT(51)
 #define KVM_PTE_LEAF_ATTR_HI_S1_GP	BIT(50)
 
 #define KVM_PTE_LEAF_ATTR_S2_PERMS	(KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
@@ -297,6 +298,31 @@ enum kvm_pgtable_prot {
 #define PAGE_HYP_RO		(KVM_PGTABLE_PROT_R)
 #define PAGE_HYP_DEVICE		(PAGE_HYP | KVM_PGTABLE_PROT_DEVICE)
 
+/*
+ * Permission indirection configuration for the nVHE hypervisor when we
+ * have FEAT_S1PIE. Like the host kernel we configure a mapping
+ * equivalent to the non-PIE meanings of the bits so the page table
+ * manipulation code does not need to account for PIE.
+ *
+ * Since nVHE and hVHE fix AP[1] as 1 or 0 respectively we define
+ * separate PIE mappings for each. These mappings are minimal with
+ * only things used from the hypervisor. Write permission is
+ * controlled via DBM.
+ */
+
+#define KVM_HYP_PIR_IDX(uxn, pxn, dbm, ap1) (((uxn) << 3) | ((pxn) << 2) | \
+					     ((dbm) << 1) | (ap1))
+
+#define KVM_NVHE_PIR_EL2        (					\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(0, 0, 0, 1), PIE_RX)	|	\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(1, 0, 0, 1), PIE_RW)	|	\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(1, 0, 1, 1), PIE_R))
+
+#define KVM_HVHE_PIR_EL2        (					\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(0, 0, 0, 0), PIE_RX)	|	\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(1, 1, 1, 0), PIE_R)	|	\
+       PIRx_ELx_PERM_PREP(KVM_HYP_PIR_IDX(1, 1, 0, 0), PIE_RW))
+
 typedef bool (*kvm_pgtable_force_pte_cb_t)(u64 addr, u64 end,
 					   enum kvm_pgtable_prot prot);
 
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index baffe58015d6..fab949435aae 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -117,6 +117,7 @@ int main(void)
   DEFINE(HOST_CONTEXT_VCPU,	offsetof(struct kvm_cpu_context, __hyp_running_vcpu));
   DEFINE(HOST_DATA_CONTEXT,	offsetof(struct kvm_host_data, host_ctxt));
   DEFINE(NVHE_INIT_MAIR_EL2,	offsetof(struct kvm_nvhe_init_params, mair_el2));
+  DEFINE(NVHE_INIT_PIR_EL2,	offsetof(struct kvm_nvhe_init_params, pir_el2));
   DEFINE(NVHE_INIT_TCR_EL2,	offsetof(struct kvm_nvhe_init_params, tcr_el2));
   DEFINE(NVHE_INIT_TCR2_EL2,	offsetof(struct kvm_nvhe_init_params, tcr2_el2));
   DEFINE(NVHE_INIT_TPIDR_EL2,	offsetof(struct kvm_nvhe_init_params, tpidr_el2));
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 88eb0459ad4b..9232b4581723 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2187,6 +2187,14 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
 	params->tcr_el2 = tcr;
 
 	tcr2 = 0;
+	if (cpus_have_final_cap(ARM64_HAS_S1PIE)) {
+		if (cpus_have_final_cap(ARM64_KVM_HVHE))
+			params->pir_el2 = KVM_HVHE_PIR_EL2;
+		else
+			params->pir_el2 = KVM_NVHE_PIR_EL2;
+
+		tcr2 |= TCR2_EL2_PIE;
+	}
 	params->tcr2_el2 = tcr2;
 
 	params->pgd_pa = kvm_mmu_get_httbr();
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index a39de9c20d27..20f926276688 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -140,6 +140,12 @@ alternative_else_nop_endif
 	ldr	x1, [x0, #NVHE_INIT_TCR_EL2]
 	msr	tcr_el2, x1
 
+alternative_if ARM64_HAS_S1PIE
+	ldr	x1, [x0, #NVHE_INIT_PIR_EL2]
+	msr	REG_PIR_EL2, x1
+	msr	REG_PIRE0_EL2, xzr
+alternative_else_nop_endif
+
 alternative_if ARM64_HAS_TCR2
 	ldr	x1, [x0, #NVHE_INIT_TCR2_EL2]
 	msr	REG_TCR2_EL2, x1
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index b74dd5ce1efd..fd6854913549 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -349,6 +349,13 @@ 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;
+	} else if (cpus_have_final_cap(ARM64_HAS_S1PIE) &&
+		   !(prot & KVM_PGTABLE_PROT_W)) {
+		/*
+		 * When using S1PIE for nVHE set DBM for read only
+		 * mappings since AP[2] is ineffective.
+		 */
+		attr |= KVM_PTE_LEAF_ATTR_HI_S1_DBM;
 	}
 
 	if (cpus_have_final_cap(ARM64_KVM_HVHE)) {

-- 
2.47.3



  parent reply	other threads:[~2026-09-03 23:16 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03 23:14 [PATCH 0/2] KVM: arm64: Enable S1PIE for nVHE and hVHE Mark Brown
2026-09-03 23:14 ` [PATCH 1/2] KVM: arm64: Initialise TCR2_EL2 for nVHE mode Mark Brown
2026-09-04  7:32   ` Marc Zyngier
2026-09-04 11:35     ` Mark Brown
2026-09-04 13:13       ` Marc Zyngier
2026-09-03 23:14 ` Mark Brown [this message]
2026-09-04  7:25   ` [PATCH 2/2] KVM: arm64: Enable S1PIE for nVHE and hVHE Marc Zyngier
2026-09-04 10:33     ` Mark Brown
2026-09-04 11:29       ` Will Deacon
2026-09-04 11:48         ` Mark Brown
2026-09-04 12:20           ` Fuad Tabba
2026-09-04 13:38             ` Mark Brown
2026-09-04 13:57               ` Marc Zyngier
2026-09-04 17:40                 ` Mark Brown
2026-09-04 13:41             ` Will Deacon
2026-09-04 14:13               ` Alexandru Elisei
2026-09-04 13:23           ` Marc Zyngier
2026-09-04 13:53             ` Mark Brown

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=20260904-kvm-arm64-nvhe-pie-v1-2-29d59f245e6c@kernel.org \
    --to=broonie@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=fuad.tabba@linux.dev \
    --cc=joey.gouly@arm.com \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=oupton@kernel.org \
    --cc=seiden@linux.ibm.com \
    --cc=suzuki.poulose@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