Skip to contentSkip to conversation

KVM: arm64: Support FEAT_LS64_ACCDATA in guests

PATCH Applied Fuad Tabba 6 participants 17 messages Oct 25 – Nov 3

Subsystems (5)
Documentation KVM Kselftest arm64 +1 more subsystems
lore
Share & tools
lore

Fuad Tabba

author reviewer
#0 lore raw

v2 cover KVM: arm64: Support FEAT_LS64_ACCDATA in guests

Hi folks,

Changes since v1 [1]:
- Support FEAT_LS64_ACCDATA in guests instead of capping ID_AA64ISAR1_EL1.LS64 at LS64_V. A saved VM keeps its level, so restore no longer has to accept older kernels' levels, and v1's set_id_regs patch goes. (Marc)
- Add an arm64.nols64 option. (Marc)
- Retitled the series to match.

On a host with FEAT_LS64_ACCDATA, KVM advertises ST64BV0 and ACCDATA_EL1 to guests but doesn't support either. A guest's ST64BV0 hits the WARN in handle_other(), and every guest on a CPU shares ACCDATA_EL1.

Patches 2 and 3 are Marc's from 2024 [2], rebased. I changed patch 3 to switch ACCDATA_EL1 for guests only, and only when the new ARM64_HAS_LS64_ACCDATA capability is set, for the reasons in its note. Patch 4 sets HCRX_EL2.EnAS0. Patch 1 adds arm64.nols64 to disable LS64 on a host whose firmware leaves SCR_EL3.ADEn clear. It comes first so that the option exists in every commit that switches ACCDATA_EL1. All five carry Cc: stable. The get-reg-list patch carries it because the test fails on a host with the feature once patch 2 is in.

Tested on the FVP with arm_v8_7_accelerator_support_level at 3 (LS64_ACCDATA) in VHE, nVHE and protected mode, and at 4 (LS64WB) in VHE, with cpuidle.off=1 so that idle doesn't reset ACCDATA_EL1 between VMs. In my reproducer, one VM writes ACCDATA_EL1 and the next VM on the same CPU reads it. Unpatched, it reads the first VM's value and ST64BV0 hits the WARN. Patched, the second VM reads 0 and ST64BV0 doesn't trap.

Based on Linux 7.3-rc3 (fd73f4a665989).

Cheers,
/fuad

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/

Fuad Tabba (3):
arm64: Add override for ID_AA64ISAR1_EL1.LS64
KVM: arm64: Enable ST64BV0 for guests with FEAT_LS64_ACCDATA
KVM: arm64: selftests: Add ACCDATA_EL1 to get-reg-list

Marc Zyngier (2):
KVM: arm64: Add ACCDATA_EL1 to the sysreg array
KVM: arm64: Add context-switch of ACCDATA_EL1

 .../admin-guide/kernel-parameters.txt         |  3 +++
 arch/arm64/include/asm/kvm_emulate.h          |  3 +++
 arch/arm64/include/asm/kvm_host.h             |  3 +++
 arch/arm64/kernel/cpufeature.c                |  7 ++++++
 arch/arm64/kernel/pi/idreg-override.c         |  2 ++
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h    | 23 +++++++++++++++++++
 arch/arm64/kvm/sys_regs.c                     | 12 +++++++++-
 arch/arm64/tools/cpucaps                      |  1 +
 .../selftests/kvm/arm64/get-reg-list.c        |  2 ++
 9 files changed, 55 insertions(+), 1 deletion(-)

base-commit: fd73f4a6659897191fa0d40695fe370925dd3780

Signature · 1 line
2.47.3
author reviewer
#1 lore raw

PATCH v2 1/5 arm64: Add override for ID_AA64ISAR1_EL1.LS64

Accesses to ACCDATA_EL1, which FEAT_LS64_ACCDATA adds, trap to EL3 unless firmware sets SCR_EL3.ADEn. Once KVM context-switches the register for its guests, a host whose firmware leaves the bit clear can't run them.

Add an override for ID_AA64ISAR1_EL1.LS64, with an arm64.nols64 alias, so that the feature can be disabled on such a host and for its guests. id_aa64isar1.ls64=2 disables only FEAT_LS64_ACCDATA and above.

---
 Documentation/admin-guide/kernel-parameters.txt | 3 +++
 arch/arm64/kernel/pi/idreg-override.c           | 2 ++
 2 files changed, 5 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +3 -0
index 33cd30996e47e..ef690cf6c3664 100644
@@ -571,6 +571,9 @@ Kernel parameters
 	arm64.nohaft	[ARM64] Unconditionally disable Hardware managed Access
 			Flag for Table descriptors support
 
+	arm64.nols64	[ARM64] Unconditionally disable 64-byte Load/Store
+			instructions support
+
 	arm64.nomops	[ARM64] Unconditionally disable Memory Copy and Memory
 			Set instructions support
 
arch/arm64/kernel/pi/idreg-override.c +2 -0
index 274bc72ba98d0..0c7f293779c1f 100644
@@ -174,6 +174,7 @@ static const struct ftr_set_desc isar1 __prel64_initconst = {
 	.name		= "id_aa64isar1",
 	.override	= &id_aa64isar1_override,
 	.fields		= {
+		FIELD("ls64", ID_AA64ISAR1_EL1_LS64_SHIFT, NULL),
 		FIELD("gpi", ID_AA64ISAR1_EL1_GPI_SHIFT, NULL),
 		FIELD("gpa", ID_AA64ISAR1_EL1_GPA_SHIFT, NULL),
 		FIELD("api", ID_AA64ISAR1_EL1_API_SHIFT, NULL),
@@ -253,6 +254,7 @@ static const struct {
 	  "id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 "
 	  "id_aa64isar1.api=0 id_aa64isar1.apa=0 "
 	  "id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0"	   },
+	{ "arm64.nols64",		"id_aa64isar1.ls64=0" },
 	{ "arm64.nomops",		"id_aa64isar2.mops=0" },
 	{ "arm64.nomte",		"id_aa64pfr1.mte=0" },
 	{ "nokaslr",			"arm64_sw.nokaslr=1" },
Signature · 1 line
2.47.3
maintainer Acked-by on v2 1/5
#2 lore raw

Re: [PATCH v2 1/5] arm64: Add override for ID_AA64ISAR1_EL1.LS64

Quoted 11 lines · Fuad Tabba

Accesses to ACCDATA_EL1, which FEAT_LS64_ACCDATA adds, trap to EL3 unless firmware sets SCR_EL3.ADEn. Once KVM context-switches the register for its guests, a host whose firmware leaves the bit clear can't run them.

Add an override for ID_AA64ISAR1_EL1.LS64, with an arm64.nols64 alias, so that the feature can be disabled on such a host and for its guests. id_aa64isar1.ls64=2 disables only FEAT_LS64_ACCDATA and above.

However, does this need a plain cc stable? I assume you want it to go in with patch 3 but that one only goes as far as 7.0. Same cc stable in patch 2 which you may want to limit (or add both as dependencies to the cc stable in patch 3 when committing).

Signature · 1 line
Catalin
author reviewer
#3 lore raw

Re: [PATCH v2 1/5] arm64: Add override for ID_AA64ISAR1_EL1.LS64

Hi Catalin,

On Thu, 29 Oct 2026 21:14:18 +0000, Catalin Marinas <[email protected]> wrote:
[...]

Quoted 4 lines

However, does this need a plain cc stable? I assume you want it to go in with patch 3 but that one only goes as far as 7.0. Same cc stable in patch 2 which you may want to limit (or add both as dependencies to the cc stable in patch 3 when committing).

No, it doesn't. Patches 1, 2 and 5 are only there for patches 3 and 4, so none of them need to go further back than 7.0.

Marc, Oliver, could the tag on all five patches become "Cc:
[email protected] # 7.0.x" when you apply them? I'll respin if that's easier.

Thanks!
/fuad

author reviewer
#4 lore raw

PATCH v2 2/5 KVM: arm64: Add ACCDATA_EL1 to the sysreg array

In reply to Fuad Tabba

From: Marc Zyngier <[email protected]>

Make ACCDATA_EL1 a first-class citizen, and add it to the sysreg array. Visibility is conditioned on the feature being enabled.

---
 arch/arm64/include/asm/kvm_host.h |  3 +++
 arch/arm64/kvm/sys_regs.c         | 12 +++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kvm_host.h +3 -0
index 27fe0cd5b2d7a..5b1cd1f502b7d 100644
@@ -498,6 +498,9 @@ enum vcpu_sysreg {
 	GCR_EL1,	/* Tag Control Register */
 	TFSRE0_EL1,	/* Tag Fault Status Register (EL0) */
 
+	/* Random stuff */
+	ACCDATA_EL1,	/* Accelerator Data */
+
 	POR_EL0,	/* Permission Overlay Register 0 (EL0) */
 
 	/* FP/SIMD/SVE */
arch/arm64/kvm/sys_regs.c +11 -1
index 44aae52c473d7..40f8be41da3a4 100644
@@ -2914,6 +2914,15 @@ static unsigned int sve_el2_visibility(const struct kvm_vcpu *vcpu,
 	return __el2_visibility(vcpu, rd, sve_visibility);
 }
 
+static unsigned int accdata_visibility(const struct kvm_vcpu *vcpu,
+				       const struct sys_reg_desc *rd)
+{
+	if (kvm_has_feat(vcpu->kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA))
+		return 0;
+
+	return REG_HIDDEN;
+}
+
 static unsigned int vncr_el2_visibility(const struct kvm_vcpu *vcpu,
 					const struct sys_reg_desc *rd)
 {
@@ -3601,7 +3610,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
 	{ SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
 
-	{ SYS_DESC(SYS_ACCDATA_EL1), undef_access },
+	{ SYS_DESC(SYS_ACCDATA_EL1), undef_access, reset_val, ACCDATA_EL1, 0,
+	  .visibility = accdata_visibility},
 
 	{ SYS_DESC(SYS_SCXTNUM_EL1), undef_access },
 
Signature · 1 line
2.47.3
Reviewed-by on v2 2/5
#5 lore raw

Re: [PATCH v2 2/5] KVM: arm64: Add ACCDATA_EL1 to the sysreg array

Quoted 5 lines · Fuad Tabba

From: Marc Zyngier <[email protected]>

Make ACCDATA_EL1 a first-class citizen, and add it to the sysreg array. Visibility is conditioned on the feature being enabled.

Hi Tabba,

LGTM.

Quoted 57 lines
---
 arch/arm64/include/asm/kvm_host.h |  3 +++
 arch/arm64/kvm/sys_regs.c         | 12 +++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kvm_host.h +3 -0
index 27fe0cd5b2d7a..5b1cd1f502b7d 100644
@@ -498,6 +498,9 @@ enum vcpu_sysreg {
 	GCR_EL1,	/* Tag Control Register */
 	TFSRE0_EL1,	/* Tag Fault Status Register (EL0) */
 
+	/* Random stuff */
+	ACCDATA_EL1,	/* Accelerator Data */
+
 	POR_EL0,	/* Permission Overlay Register 0 (EL0) */
 
 	/* FP/SIMD/SVE */
arch/arm64/kvm/sys_regs.c +11 -2
index 44aae52c473d7..40f8be41da3a4 100644
@@ -2914,6 +2914,15 @@ static unsigned int sve_el2_visibility(const struct kvm_vcpu *vcpu,
 	return __el2_visibility(vcpu, rd, sve_visibility);
 }
 
+static unsigned int accdata_visibility(const struct kvm_vcpu *vcpu,
+				       const struct sys_reg_desc *rd)
+{
+	if (kvm_has_feat(vcpu->kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA))
+		return 0;
+
+	return REG_HIDDEN;
+}
+
 static unsigned int vncr_el2_visibility(const struct kvm_vcpu *vcpu,
 					const struct sys_reg_desc *rd)
 {
@@ -3601,7 +3610,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
 	{ SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
 
-	{ SYS_DESC(SYS_ACCDATA_EL1), undef_access },
+	{ SYS_DESC(SYS_ACCDATA_EL1), undef_access, reset_val, ACCDATA_EL1, 0,
+	  .visibility = accdata_visibility},
 
 	{ SYS_DESC(SYS_SCXTNUM_EL1), undef_access },
 
--

2.47.3

author reviewer
#6 lore raw

PATCH v2 3/5 KVM: arm64: Add context-switch of ACCDATA_EL1

In reply to Fuad Tabba

From: Marc Zyngier <[email protected]>

Add ACCDATA_EL1 save/restore as part of the EL0 context. This is conditioned on the guest's view of ID_AA64ISAR1_EL1.LS64 reporting that this register is supported.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")

[Fuad: rebased; switch ACCDATA_EL1 for guests only, as the host never
uses it; gate it on a new ARM64_HAS_LS64_ACCDATA capability, since in pKVM the host controls a non-protected guest's ID registers, and an EL2 access to ACCDATA_EL1 on a CPU without the feature is UNDEFINED]

---
 arch/arm64/kernel/cpufeature.c             |  7 +++++++
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 23 ++++++++++++++++++++++
 arch/arm64/tools/cpucaps                   |  1 +
 3 files changed, 31 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
index 32102c3912fa7..b5720c56eebc9 100644
@@ -3225,6 +3225,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.cpu_enable = cpu_enable_ls64_v,
 		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_V)
 	},
+	{
+		.desc = "LS64_ACCDATA",
+		.capability = ARM64_HAS_LS64_ACCDATA,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA)
+	},
 #ifdef CONFIG_ARM64_LSUI
 	{
 		.desc = "Unprivileged Load Store Instructions (LSUI)",
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +23 -0
index c382848d31947..4a008c8a696ba 100644
@@ -17,6 +17,7 @@
 #include <asm/kvm_mmu.h>
 
 static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt);
 
 static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
 {
@@ -67,6 +68,13 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
 	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+
+	/*
+	 * Despite the appearances, ACCDATA_EL1 is part of the EL0
+	 * context, as it can only be used using ST64BV0.
+	 */
+	if (ctxt_has_accdata(ctxt))
+		ctxt_sys_reg(ctxt, ACCDATA_EL1)	= read_sysreg_s(SYS_ACCDATA_EL1);
 }
 
 static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
@@ -131,6 +139,18 @@ static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt)
 	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
 }
 
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	/* The host never uses ACCDATA_EL1 */
+	if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) || !ctxt_is_guest(ctxt))
+		return false;
+
+	vcpu = ctxt_to_vcpu(ctxt);
+	return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA);
+}
+
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, SCTLR_EL1)	= read_sysreg_el1(SYS_SCTLR);
@@ -210,6 +230,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),	tpidr_el0);
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),	tpidrro_el0);
+
+	if (ctxt_has_accdata(ctxt))
+		write_sysreg_s(ctxt_sys_reg(ctxt, ACCDATA_EL1), SYS_ACCDATA_EL1);
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
arch/arm64/tools/cpucaps +1 -0
index 2775ba3359cfe..f01719bbd6037 100644
@@ -49,6 +49,7 @@ HAS_LPA2
 HAS_LSE_ATOMICS
 HAS_LS64
 HAS_LS64_V
+HAS_LS64_ACCDATA
 HAS_LSUI
 HAS_MOPS
 HAS_NESTED_VIRT
Signature · 1 line
2.47.3
#7 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

Hi Fuad

Quoted 69 lines · Fuad Tabba

From: Marc Zyngier <[email protected]>

Add ACCDATA_EL1 save/restore as part of the EL0 context. This is conditioned on the guest's view of ID_AA64ISAR1_EL1.LS64 reporting that this register is supported.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")

[Fuad: rebased; switch ACCDATA_EL1 for guests only, as the host never
uses it; gate it on a new ARM64_HAS_LS64_ACCDATA capability, since in pKVM the host controls a non-protected guest's ID registers, and an EL2 access to ACCDATA_EL1 on a CPU without the feature is UNDEFINED]

---
  arch/arm64/kernel/cpufeature.c             |  7 +++++++
  arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 23 ++++++++++++++++++++++
  arch/arm64/tools/cpucaps                   |  1 +
  3 files changed, 31 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
index 32102c3912fa7..b5720c56eebc9 100644
@@ -3225,6 +3225,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
  		.cpu_enable = cpu_enable_ls64_v,
  		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_V)
  	},
+	{
+		.desc = "LS64_ACCDATA",
+		.capability = ARM64_HAS_LS64_ACCDATA,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA)
+	},
  #ifdef CONFIG_ARM64_LSUI
  	{
  		.desc = "Unprivileged Load Store Instructions (LSUI)",
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +8 -0
index c382848d31947..4a008c8a696ba 100644
@@ -17,6 +17,7 @@
  #include <asm/kvm_mmu.h>
 
  static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt);
 
  static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
  {
@@ -67,6 +68,13 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
  {
  	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
  	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+
+	/*
+	 * Despite the appearances, ACCDATA_EL1 is part of the EL0
+	 * context, as it can only be used using ST64BV0.
+	 */
+	if (ctxt_has_accdata(ctxt))
+		ctxt_sys_reg(ctxt, ACCDATA_EL1)	= read_sysreg_s(SYS_ACCDATA_EL1);
  }
 
  static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
@@ -131,6 +139,18 @@ static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt)
  	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
  }
 

arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt) · line 151

Quoted 10 lines
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +10 -0
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	/* The host never uses ACCDATA_EL1 */
+	if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) || !ctxt_is_guest(ctxt))
+		return false;
+
+	vcpu = ctxt_to_vcpu(ctxt);
+	return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA);

minor nit: Aligning with the other kvm_has_feat() usecsaes, should we wrap this under kvm_has_accdata() (with moving the cpus_have_final_cap() to the wrapper ?)

Otherwise looks good to me.

Suzuki

Quoted 27 lines
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +5 -0
+}
+
  static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
  {
  	ctxt_sys_reg(ctxt, SCTLR_EL1)	= read_sysreg_el1(SYS_SCTLR);
@@ -210,6 +230,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
  {
  	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),	tpidr_el0);
  	write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),	tpidrro_el0);
+
+	if (ctxt_has_accdata(ctxt))
+		write_sysreg_s(ctxt_sys_reg(ctxt, ACCDATA_EL1), SYS_ACCDATA_EL1);
  }
 
  static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
arch/arm64/tools/cpucaps +1 -0
index 2775ba3359cfe..f01719bbd6037 100644
@@ -49,6 +49,7 @@ HAS_LPA2
  HAS_LSE_ATOMICS
  HAS_LS64
  HAS_LS64_V
+HAS_LS64_ACCDATA
  HAS_LSUI
  HAS_MOPS
  HAS_NESTED_VIRT
author reviewer
#8 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

On Mon, 26 Oct 2026 at 15:41, Suzuki K Poulose <[email protected]> wrote:
[...]

Quoted 6 lines
Quoted 6 lines
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +6 -0
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+     struct kvm_vcpu *vcpu;
+
+     /* The host never uses ACCDATA_EL1 */
+     if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) || !ctxt_is_guest(ctxt))
Quoted 8 lines

arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt) · line 151

Quoted 4 lines
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +4 -0
+             return false;
+
+     vcpu = ctxt_to_vcpu(ctxt);
+     return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA);

minor nit: Aligning with the other kvm_has_feat() usecsaes, should we wrap this under kvm_has_accdata() (with moving the cpus_have_final_cap() to the wrapper ?)

Thanks Suzuki. I'll do this change if I respin.

Cheers,
/fuad

#9 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

In reply to Fuad Tabba

Review

Quoted 11 lines · Fuad Tabba
(quoted diff) +6 -0
 	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
 }
 
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	/* The host never uses ACCDATA_EL1 */
+	if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) || 

!ctxt_is_guest(ctxt))

(quoted diff) +1 -0
+		return false;

Maybe add a wrapper for this as we have for other features?

In my patch I've converted the check to use this one now:

arch/arm64/include/asm/cpufeature.h +5 -0
@@ -909,6 +909,11 @@ static inline bool system_supports_bbml3(void)
        return alternative_has_cap_unlikely(ARM64_HAS_BBML3);
 }
 
+static inline bool system_supports_ls64_accdata(void)
+{
+       return cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA);
+}
+
 int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
 

which makes sense to add in your patch first.

I think we'll also want a HWCAP3_LS64_ACCDATA exported to userspace, but we can keep that separate.

Arnd

author reviewer
#10 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

Quoted 5 lines · Arnd Bergmann
Quoted 3 lines · Fuad Tabba
      return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));

}

Quoted 10 lines
Quoted 8 lines
(quoted diff) +6 -0
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+     struct kvm_vcpu *vcpu;
+
+     /* The host never uses ACCDATA_EL1 */
+     if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) ||

!ctxt_is_guest(ctxt))
+ return false;

Maybe add a wrapper for this as we have for other features?

Thanks Arnd. Makes sense, I'll do this if I respin.

Cheers,
/fuad

maintainer Acked-by on v2 3/5
#11 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

In reply to Fuad Tabba
Quoted 10 lines · Fuad Tabba

From: Marc Zyngier <[email protected]>

Add ACCDATA_EL1 save/restore as part of the EL0 context. This is conditioned on the guest's view of ID_AA64ISAR1_EL1.LS64 reporting that this register is supported.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")
Quoted 5 lines

[Fuad: rebased; switch ACCDATA_EL1 for guests only, as the host never
uses it; gate it on a new ARM64_HAS_LS64_ACCDATA capability, since in pKVM the host controls a non-protected guest's ID registers, and an EL2 access to ACCDATA_EL1 on a CPU without the feature is UNDEFINED]

Reviewed-by on v2 3/5
#12 lore raw

Re: [PATCH v2 3/5] KVM: arm64: Add context-switch of ACCDATA_EL1

In reply to Fuad Tabba
Quoted 10 lines · Fuad Tabba

From: Marc Zyngier <[email protected]>

Add ACCDATA_EL1 save/restore as part of the EL0 context. This is conditioned on the guest's view of ID_AA64ISAR1_EL1.LS64 reporting that this register is supported.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")
Quoted 5 lines

[Fuad: rebased; switch ACCDATA_EL1 for guests only, as the host never
uses it; gate it on a new ARM64_HAS_LS64_ACCDATA capability, since in pKVM the host controls a non-protected guest's ID registers, and an EL2 access to ACCDATA_EL1 on a CPU without the feature is UNDEFINED]

Quoted 94 lines
---
 arch/arm64/kernel/cpufeature.c             |  7 +++++++
 arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 23 ++++++++++++++++++++++
 arch/arm64/tools/cpucaps                   |  1 +
 3 files changed, 31 insertions(+)
arch/arm64/kernel/cpufeature.c +7 -0
index 32102c3912fa7..b5720c56eebc9 100644
@@ -3225,6 +3225,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.cpu_enable = cpu_enable_ls64_v,
 		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_V)
 	},
+	{
+		.desc = "LS64_ACCDATA",
+		.capability = ARM64_HAS_LS64_ACCDATA,
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA)
+	},
 #ifdef CONFIG_ARM64_LSUI
 	{
 		.desc = "Unprivileged Load Store Instructions (LSUI)",
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +23 -0
index c382848d31947..4a008c8a696ba 100644
@@ -17,6 +17,7 @@
 #include <asm/kvm_mmu.h>
 
 static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt);
 
 static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt)
 {
@@ -67,6 +68,13 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, TPIDR_EL0)	= read_sysreg(tpidr_el0);
 	ctxt_sys_reg(ctxt, TPIDRRO_EL0)	= read_sysreg(tpidrro_el0);
+
+	/*
+	 * Despite the appearances, ACCDATA_EL1 is part of the EL0
+	 * context, as it can only be used using ST64BV0.
+	 */
+	if (ctxt_has_accdata(ctxt))
+		ctxt_sys_reg(ctxt, ACCDATA_EL1)	= read_sysreg_s(SYS_ACCDATA_EL1);
 }
 
 static inline bool ctxt_has_mte(struct kvm_cpu_context *ctxt)
@@ -131,6 +139,18 @@ static inline bool ctxt_has_sctlr2(struct kvm_cpu_context *ctxt)
 	return kvm_has_sctlr2(kern_hyp_va(vcpu->kvm));
 }
 
+static inline bool ctxt_has_accdata(struct kvm_cpu_context *ctxt)
+{
+	struct kvm_vcpu *vcpu;
+
+	/* The host never uses ACCDATA_EL1 */
+	if (!cpus_have_final_cap(ARM64_HAS_LS64_ACCDATA) || !ctxt_is_guest(ctxt))
+		return false;
+
+	vcpu = ctxt_to_vcpu(ctxt);
+	return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA);
+}
+
 static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
 	ctxt_sys_reg(ctxt, SCTLR_EL1)	= read_sysreg_el1(SYS_SCTLR);
@@ -210,6 +230,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 {
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0),	tpidr_el0);
 	write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0),	tpidrro_el0);
+
+	if (ctxt_has_accdata(ctxt))
+		write_sysreg_s(ctxt_sys_reg(ctxt, ACCDATA_EL1), SYS_ACCDATA_EL1);
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
arch/arm64/tools/cpucaps +1 -1
index 2775ba3359cfe..f01719bbd6037 100644
@@ -49,6 +49,7 @@ HAS_LPA2
 HAS_LSE_ATOMICS
 HAS_LS64
 HAS_LS64_V
+HAS_LS64_ACCDATA
 HAS_LSUI
 HAS_MOPS
 HAS_NESTED_VIRT
--

2.47.3

author reviewer
#13 lore raw

PATCH v2 4/5 KVM: arm64: Enable ST64BV0 for guests with FEAT_LS64_ACCDATA

In reply to Fuad Tabba

Since commit 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}"), a guest sees the host's ID_AA64ISAR1_EL1.LS64, but KVM only enables the FEAT_LS64 and FEAT_LS64_V instructions in HCRX_EL2. On a host with FEAT_LS64_ACCDATA, a guest's ST64BV0 therefore traps and hits the WARN_ON_ONCE() in handle_other().

Set HCRX_EL2.EnAS0 when the guest has FEAT_LS64_ACCDATA, now that ACCDATA_EL1 is context-switched.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")
---
 arch/arm64/include/asm/kvm_emulate.h | 3 +++
 1 file changed, 3 insertions(+)
arch/arm64/include/asm/kvm_emulate.h +3 -0
index a3c1928bdf743..d07f72082531c 100644
@@ -712,6 +712,9 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
 		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_V))
 			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnASR;
 
+		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA))
+			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnAS0;
+
 		/*
 		 * NV3 is a host-specific extension, and we always use
 		 * it when present and that the guest uses NV. It may
Signature · 1 line
2.47.3
Reviewed-by on v2 4/5
#14 lore raw

Re: [PATCH v2 4/5] KVM: arm64: Enable ST64BV0 for guests with FEAT_LS64_ACCDATA

Quoted 6 lines · Fuad Tabba

Since commit 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}"), a guest sees the host's ID_AA64ISAR1_EL1.LS64, but KVM only enables the FEAT_LS64 and FEAT_LS64_V instructions in HCRX_EL2. On a host with FEAT_LS64_ACCDATA, a guest's ST64BV0 therefore traps and hits the WARN_ON_ONCE() in handle_other().

Quoted 6 lines

Set HCRX_EL2.EnAS0 when the guest has FEAT_LS64_ACCDATA, now that ACCDATA_EL1 is context-switched.

Fixes 58ce78667a641 ("arm64: Add support for FEAT_{LS64, LS64_V}")

lgtm.

Quoted 21 lines
---
 arch/arm64/include/asm/kvm_emulate.h | 3 +++
 1 file changed, 3 insertions(+)
arch/arm64/include/asm/kvm_emulate.h +3 -1
index a3c1928bdf743..d07f72082531c 100644
@@ -712,6 +712,9 @@ static inline void vcpu_set_hcrx(struct kvm_vcpu *vcpu)
 		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_V))
 			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnASR;
 
+		if (kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA))
+			vcpu->arch.hcrx_el2 |= HCRX_EL2_EnAS0;
+
 		/*
 		 * NV3 is a host-specific extension, and we always use
 		 * it when present and that the guest uses NV. It may
--

2.47.3

author reviewer
#15 lore raw

PATCH v2 5/5 KVM: arm64: selftests: Add ACCDATA_EL1 to get-reg-list

In reply to Fuad Tabba

KVM exposes ACCDATA_EL1 to userspace when the guest has FEAT_LS64_ACCDATA. Add it to get-reg-list, conditioned on ID_AA64ISAR1_EL1.LS64, so that the test still passes on hosts that implement the feature.

---
 tools/testing/selftests/kvm/arm64/get-reg-list.c | 2 ++
 1 file changed, 2 insertions(+)
tools/testing/selftests/kvm/arm64/get-reg-list.c +2 -0
index 533994687b5d8..912590f9b0c2b 100644
@@ -49,6 +49,7 @@ static struct feature_id_reg feat_id_regs[] = {
 	REG_FEAT(POR_EL1,	ID_AA64MMFR3_EL1, S1POE, IMP),
 	REG_FEAT(POR_EL0,	ID_AA64MMFR3_EL1, S1POE, IMP),
 	REG_FEAT(POR_EL2,	ID_AA64MMFR3_EL1, S1POE, IMP),
+	REG_FEAT(ACCDATA_EL1,	ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA),
 	REG_FEAT(HCRX_EL2,	ID_AA64MMFR1_EL1, HCX, IMP),
 	REG_FEAT(HFGRTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
 	REG_FEAT(HFGWTR_EL2,	ID_AA64MMFR0_EL1, FGT, IMP),
@@ -517,6 +518,7 @@ static __u64 base_regs[] = {
 	ARM64_SYS_REG(3, 0, 12, 1, 1),	/* DISR_EL1 */
 	ARM64_SYS_REG(3, 0, 13, 0, 1),	/* CONTEXTIDR_EL1 */
 	ARM64_SYS_REG(3, 0, 13, 0, 4),	/* TPIDR_EL1 */
+	ARM64_SYS_REG(3, 0, 13, 0, 5),	/* ACCDATA_EL1 */
 	ARM64_SYS_REG(3, 0, 14, 1, 0),	/* CNTKCTL_EL1 */
 	ARM64_SYS_REG(3, 2, 0, 0, 0),	/* CSSELR_EL1 */
 	ARM64_SYS_REG(3, 3, 10, 2, 4),	/* POR_EL0 */
Signature · 1 line
2.47.3
maintainer Applied
#16 lore raw
In reply to Fuad Tabba
Quoted 9 lines · Fuad Tabba

Changes since v1 [1]:
- Support FEAT_LS64_ACCDATA in guests instead of capping ID_AA64ISAR1_EL1.LS64 at LS64_V. A saved VM keeps its level, so restore no longer has to accept older kernels' levels, and v1's set_id_regs patch goes. (Marc)
- Add an arm64.nols64 option. (Marc)
- Retitled the series to match.

[...]

Applied to fixes, thanks!

[1/5] arm64: Add override for ID_AA64ISAR1_EL1.LS64

      commit: 699edee85fb9f4403b5bc939f3f84374f841b33b
[2/5] KVM: arm64: Add ACCDATA_EL1 to the sysreg array
      commit: 8b5bcf2e799c24906b813f4a63081e68721a026b
[3/5] KVM: arm64: Add context-switch of ACCDATA_EL1
      commit: c122ea1564b41326d8c09c64005d38ec2fa6dd8f
[4/5] KVM: arm64: Enable ST64BV0 for guests with FEAT_LS64_ACCDATA
      commit: e2412d6a90a4b39e3fc464eeab8637a7f4eccc10
[5/5] KVM: arm64: selftests: Add ACCDATA_EL1 to get-reg-list
      commit: b7bb9e9425dd7772cba9ac4392e982f541cccfac

Cheers,

	M.
Signature · 1 line
Without deviation from the norm, progress is not possible.