git: 5bcd16cced3b - main - arm64: Use the new sys handler for ID regs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 12 May 2025 12:50:27 UTC
The branch main has been updated by andrew:
URL: https://cgit.FreeBSD.org/src/commit/?id=5bcd16cced3b57d16e5c0973641c31acba4e1f64
commit 5bcd16cced3b57d16e5c0973641c31acba4e1f64
Author: Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-05-12 11:07:09 +0000
Commit: Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-05-12 11:07:09 +0000
arm64: Use the new sys handler for ID regs
Switch to the new sys instruction handling for the ID registers.
Reviewed by: harry.moulton_arm.com
Sponsored by: Arm Ltd
Differential Revision: https://reviews.freebsd.org/D50211
---
sys/arm64/arm64/identcpu.c | 75 ++++++++++++++++++++++++----------------------
1 file changed, 39 insertions(+), 36 deletions(-)
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index c4eaaaafc279..508ea0d472d3 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -2384,48 +2384,49 @@ user_ctr_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
return (1);
}
-static int
-user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
- uint32_t esr)
+static bool
+user_idreg_handler(uint64_t esr, struct trapframe *frame)
{
uint64_t value;
- int CRm, Op2, i, reg;
+ int reg;
- if ((insn & MRS_MASK) != MRS_VALUE)
- return (0);
+ if (ESR_ELx_EXCEPTION(esr) != EXCP_MSR)
+ return (false);
+
+ /* Only support reading from ID registers */
+ if ((esr & ISS_MSR_DIR) == 0)
+ return (false);
/*
- * We only emulate Op0 == 3, Op1 == 0, CRn == 0, CRm == {0, 4-7}.
- * These are in the EL1 CPU identification space.
- * CRm == 0 holds MIDR_EL1, MPIDR_EL1, and REVID_EL1.
- * CRm == {4-7} holds the ID_AA64 registers.
+ * This only handles the ID register space and a few registers that
+ * are safe to pass through to userspace.
*
- * For full details see the ARMv8 ARM (ARM DDI 0487C.a)
- * Table D9-2 System instruction encodings for non-Debug System
- * register accesses.
+ * These registers are all in the space op0 == 3, op1 == 0,
+ * CRn == 0. We support the following CRm:
+ * - CRm == 0: midr_el1, mpidr_el1, and revidr_el1.
+ * - CRm in {4-7}: sanitized ID registers.
+ *
+ * Registers in the ID register space (CRm in {4-7}) are all
+ * read-only and have either defined fields, or are read as
+ * zero (RAZ). For these we return 0 for any unknown register.
*/
- if (mrs_Op0(insn) != 3 || mrs_Op1(insn) != 0 || mrs_CRn(insn) != 0)
- return (0);
-
- CRm = mrs_CRm(insn);
- if (CRm > 7 || (CRm < 4 && CRm != 0))
- return (0);
+ if (ISS_MSR_OP0(esr) != 3 || ISS_MSR_OP1(esr) != 0 ||
+ ISS_MSR_CRn(esr) != 0)
+ return (false);
- Op2 = mrs_Op2(insn);
value = 0;
-
- for (i = 0; i < nitems(user_regs); i++) {
- if (user_regs[i].CRm == CRm && user_regs[i].Op2 == Op2) {
- if (SV_CURPROC_ABI() == SV_ABI_FREEBSD)
- value = CPU_DESC_FIELD(user_cpu_desc, i);
- else
- value = CPU_DESC_FIELD(l_user_cpu_desc, i);
- break;
+ if (ISS_MSR_CRm(esr) >= 4 && ISS_MSR_CRm(esr) <= 7) {
+ for (int i = 0; i < nitems(user_regs); i++) {
+ if (user_regs[i].iss == (esr & ISS_MSR_REG_MASK)) {
+ if (SV_CURPROC_ABI() == SV_ABI_FREEBSD)
+ value = CPU_DESC_FIELD(user_cpu_desc, i);
+ else
+ value = CPU_DESC_FIELD(l_user_cpu_desc, i);
+ break;
+ }
}
- }
-
- if (CRm == 0) {
- switch (Op2) {
+ } else if (ISS_MSR_CRm(esr) == 0) {
+ switch (ISS_MSR_OP2(esr)) {
case 0:
value = READ_SPECIALREG(midr_el1);
break;
@@ -2436,8 +2437,10 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
value = READ_SPECIALREG(revidr_el1);
break;
default:
- return (0);
+ return (false);
}
+ } else {
+ return (false);
}
/*
@@ -2446,7 +2449,7 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
*/
frame->tf_elr += INSN_SIZE;
- reg = MRS_REGISTER(insn);
+ reg = ISS_MSR_Rt(esr);
/* If reg is 31 then write to xzr, i.e. do nothing */
if (reg == 31)
return (1);
@@ -2456,7 +2459,7 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
else if (reg == 30)
frame->tf_lr = value;
- return (1);
+ return (true);
}
/*
@@ -2795,7 +2798,7 @@ identify_cpu_sysinit(void *dummy __unused)
#endif
install_undef_handler(user_ctr_handler);
- install_undef_handler(user_mrs_handler);
+ install_sys_handler(user_idreg_handler);
}
SYSINIT(identify_cpu, SI_SUB_CPU, SI_ORDER_MIDDLE, identify_cpu_sysinit, NULL);