]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
arm64: Handle BRBE booting requirements
authorAnshuman Khandual <anshuman.khandual@arm.com>
Wed, 11 Jun 2025 18:01:12 +0000 (13:01 -0500)
committerWill Deacon <will@kernel.org>
Tue, 8 Jul 2025 15:11:27 +0000 (16:11 +0100)
To use the Branch Record Buffer Extension (BRBE), some configuration is
necessary at EL3 and EL2. This patch documents the requirements and adds
the initial EL2 setup code, which largely consists of configuring the
fine-grained traps and initializing a couple of BRBE control registers.

Before this patch, __init_el2_fgt() would initialize HDFGRTR_EL2 and
HDFGWTR_EL2 with the same value, relying on the read/write trap controls
for a register occupying the same bit position in either register. The
'nBRBIDR' trap control only exists in bit 59 of HDFGRTR_EL2, while bit
59 of HDFGWTR_EL2 is RES0, and so this assumption no longer holds.

To handle HDFGRTR_EL2 and HDFGWTR_EL2 having (slightly) different bit
layouts, __init_el2_fgt() is changed to accumulate the HDFGRTR_EL2 and
HDFGWTR_EL2 control bits separately. While making this change the
open-coded value (1 << 62) is replaced with
HDFG{R,W}TR_EL2_nPMSNEVFR_EL1_MASK.

The BRBCR_EL1 and BRBCR_EL2 registers are unusual and require special
initialisation: even though they are subject to E2H renaming, both have
an effect regardless of HCR_EL2.TGE, even when running at EL2. So we
must initialize BRBCR_EL2 in case we run in nVHE mode. This is handled
in __init_el2_brbe() with a comment to explain the situation.

Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Reviewed-by: Leo Yan <leo.yan@arm.com>
Tested-by: James Clark <james.clark@linaro.org>
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
[Mark: rewrite commit message, fix typo in comment]
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Co-developed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
tested-by: Adam Young <admiyo@os.amperecomputing.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/20250611-arm-brbe-v19-v23-2-e7775563036e@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
Documentation/arch/arm64/booting.rst
arch/arm64/include/asm/el2_setup.h

index dee7b6de864fcfe739bb526c5510972c079bcbce..fbdc4b071755e61330618ab2a532b04f63ef9e12 100644 (file)
@@ -388,6 +388,27 @@ Before jumping into the kernel, the following conditions must be met:
 
     - SMCR_EL2.EZT0 (bit 30) must be initialised to 0b1.
 
+  For CPUs with the Branch Record Buffer Extension (FEAT_BRBE):
+
+  - If EL3 is present:
+
+    - MDCR_EL3.SBRBE (bits 33:32) must be initialised to 0b01 or 0b11.
+
+  - If the kernel is entered at EL1 and EL2 is present:
+
+    - BRBCR_EL2.CC (bit 3) must be initialised to 0b1.
+    - BRBCR_EL2.MPRED (bit 4) must be initialised to 0b1.
+
+    - HDFGRTR_EL2.nBRBDATA (bit 61) must be initialised to 0b1.
+    - HDFGRTR_EL2.nBRBCTL  (bit 60) must be initialised to 0b1.
+    - HDFGRTR_EL2.nBRBIDR  (bit 59) must be initialised to 0b1.
+
+    - HDFGWTR_EL2.nBRBDATA (bit 61) must be initialised to 0b1.
+    - HDFGWTR_EL2.nBRBCTL  (bit 60) must be initialised to 0b1.
+
+    - HFGITR_EL2.nBRBIALL (bit 56) must be initialised to 0b1.
+    - HFGITR_EL2.nBRBINJ  (bit 55) must be initialised to 0b1.
+
   For CPUs with the Performance Monitors Extension (FEAT_PMUv3p9):
 
  - If EL3 is present:
index ba5df0df02a467c800e262094b5c9e7f5911e760..de8a57f728c5a4ddf578e9b15d19cc0d836a652c 100644 (file)
 .Lskip_set_cptr_\@:
 .endm
 
+/*
+ * Configure BRBE to permit recording cycle counts and branch mispredicts.
+ *
+ * At any EL, to record cycle counts BRBE requires that both BRBCR_EL2.CC=1 and
+ * BRBCR_EL1.CC=1.
+ *
+ * At any EL, to record branch mispredicts BRBE requires that both
+ * BRBCR_EL2.MPRED=1 and BRBCR_EL1.MPRED=1.
+ *
+ * Set {CC,MPRED} in BRBCR_EL2 in case nVHE mode is used and we are
+ * executing in EL1.
+ */
+.macro __init_el2_brbe
+       mrs     x1, id_aa64dfr0_el1
+       ubfx    x1, x1, #ID_AA64DFR0_EL1_BRBE_SHIFT, #4
+       cbz     x1, .Lskip_brbe_\@
+
+       mov_q   x0, BRBCR_ELx_CC | BRBCR_ELx_MPRED
+       msr_s   SYS_BRBCR_EL2, x0
+.Lskip_brbe_\@:
+.endm
+
 /* Disable any fine grained traps */
 .macro __init_el2_fgt
        mrs     x1, id_aa64mmfr0_el1
        cbz     x1, .Lskip_fgt_\@
 
        mov     x0, xzr
+       mov     x2, xzr
        mrs     x1, id_aa64dfr0_el1
        ubfx    x1, x1, #ID_AA64DFR0_EL1_PMSVer_SHIFT, #4
        cmp     x1, #3
        b.lt    .Lskip_spe_fgt_\@
        /* Disable PMSNEVFR_EL1 read and write traps */
-       orr     x0, x0, #(1 << 62)
+       orr     x0, x0, #HDFGRTR_EL2_nPMSNEVFR_EL1_MASK
+       orr     x2, x2, #HDFGWTR_EL2_nPMSNEVFR_EL1_MASK
 
 .Lskip_spe_fgt_\@:
+       mrs     x1, id_aa64dfr0_el1
+       ubfx    x1, x1, #ID_AA64DFR0_EL1_BRBE_SHIFT, #4
+       cbz     x1, .Lskip_brbe_fgt_\@
+
+       /*
+        * Disable read traps for the following registers
+        *
+        * [BRBSRC|BRBTGT|RBINF]_EL1
+        * [BRBSRCINJ|BRBTGTINJ|BRBINFINJ|BRBTS]_EL1
+        */
+       orr     x0, x0, #HDFGRTR_EL2_nBRBDATA_MASK
+
+       /*
+        * Disable write traps for the following registers
+        *
+        * [BRBSRCINJ|BRBTGTINJ|BRBINFINJ|BRBTS]_EL1
+        */
+       orr     x2, x2, #HDFGWTR_EL2_nBRBDATA_MASK
+
+       /* Disable read and write traps for [BRBCR|BRBFCR]_EL1 */
+       orr     x0, x0, #HDFGRTR_EL2_nBRBCTL_MASK
+       orr     x2, x2, #HDFGWTR_EL2_nBRBCTL_MASK
+
+       /* Disable read traps for BRBIDR_EL1 */
+       orr     x0, x0, #HDFGRTR_EL2_nBRBIDR_MASK
+
+.Lskip_brbe_fgt_\@:
 
 .Lset_debug_fgt_\@:
        msr_s   SYS_HDFGRTR_EL2, x0
-       msr_s   SYS_HDFGWTR_EL2, x0
+       msr_s   SYS_HDFGWTR_EL2, x2
 
        mov     x0, xzr
+       mov     x2, xzr
+
+       mrs     x1, id_aa64dfr0_el1
+       ubfx    x1, x1, #ID_AA64DFR0_EL1_BRBE_SHIFT, #4
+       cbz     x1, .Lskip_brbe_insn_fgt_\@
+
+       /* Disable traps for BRBIALL instruction */
+       orr     x2, x2, #HFGITR_EL2_nBRBIALL_MASK
+
+       /* Disable traps for BRBINJ instruction */
+       orr     x2, x2, #HFGITR_EL2_nBRBINJ_MASK
+
+.Lskip_brbe_insn_fgt_\@:
        mrs     x1, id_aa64pfr1_el1
        ubfx    x1, x1, #ID_AA64PFR1_EL1_SME_SHIFT, #4
        cbz     x1, .Lskip_sme_fgt_\@
 .Lset_fgt_\@:
        msr_s   SYS_HFGRTR_EL2, x0
        msr_s   SYS_HFGWTR_EL2, x0
-       msr_s   SYS_HFGITR_EL2, xzr
+       msr_s   SYS_HFGITR_EL2, x2
 
        mrs     x1, id_aa64pfr0_el1             // AMU traps UNDEF without AMU
        ubfx    x1, x1, #ID_AA64PFR0_EL1_AMU_SHIFT, #4
        __init_el2_hcrx
        __init_el2_timers
        __init_el2_debug
+       __init_el2_brbe
        __init_el2_lor
        __init_el2_stage2
        __init_el2_gicv3