arm64: cpufeature: Rename BBML2_NOABORT as BBML3

- As bbml2_noabort is functionally equivalent to bbml3,
  rename cpu/system_supports_bbml2_noabort to
  cpu/system_supports_bbml3.
  The ARM64 capability name is also renamed accordingly.

- As BBML2_NOABORT or the equivalent BBML3 is the
  kernel requirement for setting up linear map with
  block/contpte mappings and not BBML2, replace all
  bbml2 references with bbml3.

FEAT_BBML3, is introduced as part of 2025 Architecture Extensions.
https://developer.arm.com/documentation/109697/2026_03/2025-Architecture-Extensions

No functional changes are introduced with this patch.

Reviewed-by: Gavin Shan <gshan@redhat.com>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Signed-off-by: Linu Cherian <linu.cherian@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
Linu Cherian 2026-07-23 10:10:32 +05:30 committed by Will Deacon
parent e4fa246243
commit 94104e3cfa
6 changed files with 50 additions and 67 deletions

View File

@ -878,11 +878,11 @@ static inline bool system_supports_pmuv3(void)
return cpus_have_final_cap(ARM64_HAS_PMUV3); return cpus_have_final_cap(ARM64_HAS_PMUV3);
} }
bool cpu_supports_bbml2_noabort(void); bool cpu_supports_bbml3(void);
static inline bool system_supports_bbml2_noabort(void) static inline bool system_supports_bbml3(void)
{ {
return alternative_has_cap_unlikely(ARM64_HAS_BBML2_NOABORT); return alternative_has_cap_unlikely(ARM64_HAS_BBML3);
} }
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);

View File

@ -2131,21 +2131,10 @@ static bool hvhe_possible(const struct arm64_cpu_capabilities *entry,
return arm64_test_sw_feature_override(ARM64_SW_FEATURE_OVERRIDE_HVHE); return arm64_test_sw_feature_override(ARM64_SW_FEATURE_OVERRIDE_HVHE);
} }
bool cpu_supports_bbml2_noabort(void) bool cpu_supports_bbml3(void)
{ {
/* /* CPUs that support BBML3 but dont advertise through ID_AA64MMFR2_EL1 */
* We want to allow usage of BBML2 in as wide a range of kernel contexts static const struct midr_range supports_bbml3_list[] = {
* as possible. This list is therefore an allow-list of known-good
* implementations that both support BBML2 and additionally, fulfill the
* extra constraint of never generating TLB conflict aborts when using
* the relaxed BBML2 semantics (such aborts make use of BBML2 in certain
* kernel contexts difficult to prove safe against recursive aborts).
*
* Note that implementations can only be considered "known-good" if their
* implementors attest to the fact that the implementation never raises
* TLB conflict aborts for BBML2 mapping granularity changes.
*/
static const struct midr_range supports_bbml2_noabort_list[] = {
MIDR_REV_RANGE(MIDR_CORTEX_X4, 0, 3, 0xf), MIDR_REV_RANGE(MIDR_CORTEX_X4, 0, 3, 0xf),
MIDR_REV_RANGE(MIDR_NEOVERSE_V3, 0, 2, 0xf), MIDR_REV_RANGE(MIDR_NEOVERSE_V3, 0, 2, 0xf),
MIDR_REV_RANGE(MIDR_NEOVERSE_V3AE, 0, 2, 0xf), MIDR_REV_RANGE(MIDR_NEOVERSE_V3AE, 0, 2, 0xf),
@ -2165,8 +2154,7 @@ bool cpu_supports_bbml2_noabort(void)
{} {}
}; };
/* Does our cpu guarantee to never raise TLB conflict aborts? */ if (!is_midr_in_range_list(supports_bbml3_list))
if (!is_midr_in_range_list(supports_bbml2_noabort_list))
return false; return false;
/* /*
@ -2177,9 +2165,9 @@ bool cpu_supports_bbml2_noabort(void)
return true; return true;
} }
static bool has_bbml2_noabort(const struct arm64_cpu_capabilities *caps, int scope) static bool has_bbml3(const struct arm64_cpu_capabilities *caps, int scope)
{ {
return cpu_supports_bbml2_noabort(); return cpu_supports_bbml3();
} }
static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused) static void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused)
@ -3072,10 +3060,10 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP) ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP)
}, },
{ {
.desc = "BBM Level 2 without TLB conflict abort", .desc = "BBM Level 3",
.capability = ARM64_HAS_BBML2_NOABORT, .capability = ARM64_HAS_BBML3,
.type = ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE, .type = ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE,
.matches = has_bbml2_noabort, .matches = has_bbml3,
}, },
{ {
.desc = "52-bit Virtual Addressing for KVM (LPA2)", .desc = "52-bit Virtual Addressing for KVM (LPA2)",

View File

@ -89,7 +89,7 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
} }
/* /*
* On eliding the __tlb_flush_range() under BBML2+noabort: * On eliding the __tlb_flush_range() under BBML3:
* *
* NOTE: Instead of using N=16 as the contiguous block length, we use * NOTE: Instead of using N=16 as the contiguous block length, we use
* N=4 for clarity. * N=4 for clarity.
@ -135,7 +135,7 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
* contiguous TLB entry, which is a micro-optimisation opportunity, * contiguous TLB entry, which is a micro-optimisation opportunity,
* but does not affect correctness. * but does not affect correctness.
* *
* In the BBML2 case, the change is avoiding the intermediate tlbi+dsb. * In the BBML3 case, the change is avoiding the intermediate tlbi+dsb.
* This means a few things, but notably other PEs will still "see" any * This means a few things, but notably other PEs will still "see" any
* stale cached TLB entries. This could lead to a "contiguous bit * stale cached TLB entries. This could lead to a "contiguous bit
* misprogramming" issue until the final tlbi+dsb of the changed page, * misprogramming" issue until the final tlbi+dsb of the changed page,
@ -158,21 +158,16 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
* are present, and a write is made to this address, do we fault or * are present, and a write is made to this address, do we fault or
* is the write permitted (via amalgamation)? * is the write permitted (via amalgamation)?
* *
* The relevant Arm ARM DDI 0487L.a requirements are RNGLXZ and RJQQTC, * With BBML3 implemented, no TLB conflict abort is raised and the OA,
* and together state that when BBML1 or BBML2 are implemented, either * access permissions and memory attributes produced is one of the cached
* a TLB conflict abort is raised (which we expressly forbid), or will * TLB entries, but never amalgamate.
* "produce an OA, access permissions, and memory attributes that are
* consistent with any of the programmed translation table values".
*
* That is to say, will either raise a TLB conflict, or produce one of
* the cached TLB entries, but never amalgamate.
* *
* Thus, as the page tables are only considered "consistent" after * Thus, as the page tables are only considered "consistent" after
* the final tlbi+dsb (which evicts both the single stale (RW,n) TLB * the final tlbi+dsb (which evicts both the single stale (RW,n) TLB
* entry as well as the new contiguous (RO,c) TLB entry), omitting the * entry as well as the new contiguous (RO,c) TLB entry), omitting the
* initial tlbi+dsb is correct. * initial tlbi+dsb is correct.
* *
* It is also important to note that at the end of the BBML2 folding * It is also important to note that at the end of the BBML3 folding
* case, we are still left with potentially all N TLB entries still * case, we are still left with potentially all N TLB entries still
* cached (the N-1 non-contiguous ptes, and the single contiguous * cached (the N-1 non-contiguous ptes, and the single contiguous
* block). However, over time, natural TLB pressure will cause the * block). However, over time, natural TLB pressure will cause the
@ -214,7 +209,7 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
* *
* |____| <--- tlbi + dsb * |____| <--- tlbi + dsb
* *
* For BBML2, we again remove the intermediate tlbi+dsb. Here, there * For BBML3, we again remove the intermediate tlbi+dsb. Here, there
* are no issues, as the final tlbi+dsb covering the changed page is * are no issues, as the final tlbi+dsb covering the changed page is
* guaranteed to remove the original large contiguous (RW,c) TLB entry, * guaranteed to remove the original large contiguous (RW,c) TLB entry,
* as well as the intermediate (RW,n) TLB entry; the next access will * as well as the intermediate (RW,n) TLB entry; the next access will
@ -224,7 +219,7 @@ static void contpte_convert(struct mm_struct *mm, unsigned long addr,
* regardless. * regardless.
*/ */
if (!system_supports_bbml2_noabort()) if (!system_supports_bbml3())
__flush_tlb_range(&vma, start_addr, addr, PAGE_SIZE, 3, __flush_tlb_range(&vma, start_addr, addr, PAGE_SIZE, 3,
TLBF_NOWALKCACHE); TLBF_NOWALKCACHE);

View File

@ -779,18 +779,18 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
static inline bool force_pte_mapping(void) static inline bool force_pte_mapping(void)
{ {
const bool bbml2 = system_capabilities_finalized() ? const bool bbml3 = system_capabilities_finalized() ?
system_supports_bbml2_noabort() : cpu_supports_bbml2_noabort(); system_supports_bbml3() : cpu_supports_bbml3();
if (debug_pagealloc_enabled()) if (debug_pagealloc_enabled())
return true; return true;
if (bbml2) if (bbml3)
return false; return false;
return rodata_full || arm64_kfence_can_set_direct_map() || is_realm_world(); return rodata_full || arm64_kfence_can_set_direct_map() || is_realm_world();
} }
static DEFINE_MUTEX(pgtable_split_lock); static DEFINE_MUTEX(pgtable_split_lock);
static bool linear_map_requires_bbml2; static bool linear_map_requires_bbml3;
int split_kernel_leaf_mapping(unsigned long start, unsigned long end) int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
{ {
@ -803,15 +803,15 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
* always pte-mapped), we must not go any further because taking the * always pte-mapped), we must not go any further because taking the
* mutex below may sleep. Do not call force_pte_mapping() here because * mutex below may sleep. Do not call force_pte_mapping() here because
* it could return a confusing result if called from a secondary cpu * it could return a confusing result if called from a secondary cpu
* prior to finalizing caps. Instead, linear_map_requires_bbml2 gives us * prior to finalizing caps. Instead, linear_map_requires_bbml3 gives us
* what we need. * what we need.
*/ */
if (!linear_map_requires_bbml2 || is_kfence_address((void *)start)) if (!linear_map_requires_bbml3 || is_kfence_address((void *)start))
return 0; return 0;
if (!system_supports_bbml2_noabort()) { if (!system_supports_bbml3()) {
/* /*
* !BBML2_NOABORT systems should not be trying to change * BBML3 systems should not be trying to change
* permissions on anything that is not pte-mapped in the first * permissions on anything that is not pte-mapped in the first
* place. Just return early and let the permission change code * place. Just return early and let the permission change code
* raise a warning if not already pte-mapped. * raise a warning if not already pte-mapped.
@ -828,8 +828,8 @@ int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
/* /*
* Boot-time: Started secondary cpus but don't know if they * Boot-time: Started secondary cpus but don't know if they
* support BBML2_NOABORT yet. Can't allow splitting in this * support BBML3 yet. Can't allow splitting in this window
* window in case they don't. * in case they don't.
*/ */
if (WARN_ON(num_online_cpus() > 1)) if (WARN_ON(num_online_cpus() > 1))
return -EBUSY; return -EBUSY;
@ -934,11 +934,11 @@ static int range_split_to_ptes(unsigned long start, unsigned long end, gfp_t gfp
return ret; return ret;
} }
u32 idmap_kpti_bbml2_flag; u32 idmap_kpti_bbml3_flag;
static void __init init_idmap_kpti_bbml2_flag(void) static void __init init_idmap_kpti_bbml3_flag(void)
{ {
WRITE_ONCE(idmap_kpti_bbml2_flag, 1); WRITE_ONCE(idmap_kpti_bbml3_flag, 1);
/* Must be visible to other CPUs before stop_machine() is called. */ /* Must be visible to other CPUs before stop_machine() is called. */
smp_mb(); smp_mb();
} }
@ -947,7 +947,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
{ {
/* /*
* Repainting the linear map must be done by CPU0 (the boot CPU) because * Repainting the linear map must be done by CPU0 (the boot CPU) because
* that's the only CPU that we know supports BBML2. The other CPUs will * that's the only CPU that we know supports BBML3. The other CPUs will
* be held in a waiting area with the idmap active. * be held in a waiting area with the idmap active.
*/ */
if (!smp_processor_id()) { if (!smp_processor_id()) {
@ -960,7 +960,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
/* /*
* Wait for all secondary CPUs to be put into the waiting area. * Wait for all secondary CPUs to be put into the waiting area.
*/ */
smp_cond_load_acquire(&idmap_kpti_bbml2_flag, VAL == num_online_cpus()); smp_cond_load_acquire(&idmap_kpti_bbml3_flag, VAL == num_online_cpus());
/* /*
* Walk all of the linear map [lstart, lend), except the kernel * Walk all of the linear map [lstart, lend), except the kernel
@ -979,7 +979,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
* Relies on dsb in flush_tlb_kernel_range() to avoid reordering * Relies on dsb in flush_tlb_kernel_range() to avoid reordering
* before any page table split operations. * before any page table split operations.
*/ */
WRITE_ONCE(idmap_kpti_bbml2_flag, 0); WRITE_ONCE(idmap_kpti_bbml3_flag, 0);
} else { } else {
typedef void (wait_split_fn)(void); typedef void (wait_split_fn)(void);
extern wait_split_fn wait_linear_map_split_to_ptes; extern wait_split_fn wait_linear_map_split_to_ptes;
@ -988,7 +988,7 @@ static int __init linear_map_split_to_ptes(void *__unused)
wait_fn = (void *)__pa_symbol(wait_linear_map_split_to_ptes); wait_fn = (void *)__pa_symbol(wait_linear_map_split_to_ptes);
/* /*
* At least one secondary CPU doesn't support BBML2 so cannot * At least one secondary CPU doesn't support BBML3 so cannot
* tolerate the size of the live mappings changing. So have the * tolerate the size of the live mappings changing. So have the
* secondary CPUs wait for the boot CPU to make the changes * secondary CPUs wait for the boot CPU to make the changes
* with the idmap active and init_mm inactive. * with the idmap active and init_mm inactive.
@ -1003,8 +1003,8 @@ static int __init linear_map_split_to_ptes(void *__unused)
void __init linear_map_maybe_split_to_ptes(void) void __init linear_map_maybe_split_to_ptes(void)
{ {
if (linear_map_requires_bbml2 && !system_supports_bbml2_noabort()) { if (linear_map_requires_bbml3 && !system_supports_bbml3()) {
init_idmap_kpti_bbml2_flag(); init_idmap_kpti_bbml3_flag();
stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask); stop_machine(linear_map_split_to_ptes, NULL, cpu_online_mask);
} }
} }
@ -1127,7 +1127,7 @@ bool arch_kfence_init_pool(void)
mutex_unlock(&pgtable_split_lock); mutex_unlock(&pgtable_split_lock);
/* /*
* Since the system supports bbml2_noabort, tlb invalidation is not * Since the system supports bbml3, tlb invalidation is not
* required here; the pgtable mappings have been split to pte but larger * required here; the pgtable mappings have been split to pte but larger
* entries may safely linger in the TLB. * entries may safely linger in the TLB.
*/ */
@ -1166,7 +1166,7 @@ static void __init map_mem(void)
arm64_kfence_map_pool(); arm64_kfence_map_pool();
linear_map_requires_bbml2 = !force_pte_mapping() && can_set_direct_map(); linear_map_requires_bbml3 = !force_pte_mapping() && can_set_direct_map();
if (force_pte_mapping()) if (force_pte_mapping())
flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
@ -1333,7 +1333,7 @@ void __init kpti_install_ng_mappings(void)
if (arm64_use_ng_mappings) if (arm64_use_ng_mappings)
return; return;
init_idmap_kpti_bbml2_flag(); init_idmap_kpti_bbml3_flag();
stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask); stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
} }
@ -1394,7 +1394,7 @@ void __pi_map_range(phys_addr_t *pte, u64 start, u64 end, phys_addr_t pa,
u64 va_offset); u64 va_offset);
static u8 idmap_ptes[IDMAP_LEVELS - 1][PAGE_SIZE] __aligned(PAGE_SIZE) __ro_after_init, static u8 idmap_ptes[IDMAP_LEVELS - 1][PAGE_SIZE] __aligned(PAGE_SIZE) __ro_after_init,
kpti_bbml2_ptes[IDMAP_LEVELS - 1][PAGE_SIZE] __aligned(PAGE_SIZE) __ro_after_init; kpti_bbml3_ptes[IDMAP_LEVELS - 1][PAGE_SIZE] __aligned(PAGE_SIZE) __ro_after_init;
static void __init create_idmap(void) static void __init create_idmap(void)
{ {
@ -1406,17 +1406,17 @@ static void __init create_idmap(void)
IDMAP_ROOT_LEVEL, (pte_t *)idmap_pg_dir, false, IDMAP_ROOT_LEVEL, (pte_t *)idmap_pg_dir, false,
__phys_to_virt(ptep) - ptep); __phys_to_virt(ptep) - ptep);
if (linear_map_requires_bbml2 || if (linear_map_requires_bbml3 ||
(IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && !arm64_use_ng_mappings)) { (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && !arm64_use_ng_mappings)) {
phys_addr_t pa = __pa_symbol(&idmap_kpti_bbml2_flag); phys_addr_t pa = __pa_symbol(&idmap_kpti_bbml3_flag);
/* /*
* The KPTI G-to-nG conversion code needs a read-write mapping * The KPTI G-to-nG conversion code needs a read-write mapping
* of its synchronization flag in the ID map. This is also used * of its synchronization flag in the ID map. This is also used
* when splitting the linear map to ptes if a secondary CPU * when splitting the linear map to ptes if a secondary CPU
* doesn't support bbml2. * doesn't support bbml3.
*/ */
ptep = __pa_symbol(kpti_bbml2_ptes); ptep = __pa_symbol(kpti_bbml3_ptes);
__pi_map_range(&ptep, pa, pa + sizeof(u32), pa, PAGE_KERNEL, __pi_map_range(&ptep, pa, pa + sizeof(u32), pa, PAGE_KERNEL,
IDMAP_ROOT_LEVEL, (pte_t *)idmap_pg_dir, false, IDMAP_ROOT_LEVEL, (pte_t *)idmap_pg_dir, false,
__phys_to_virt(ptep) - ptep); __phys_to_virt(ptep) - ptep);

View File

@ -287,7 +287,7 @@ SYM_TYPED_FUNC_START(idmap_kpti_install_ng_mappings)
mov x5, x3 // preserve temp_pte arg mov x5, x3 // preserve temp_pte arg
mrs swapper_ttb, ttbr1_el1 mrs swapper_ttb, ttbr1_el1
adr_l flag_ptr, idmap_kpti_bbml2_flag adr_l flag_ptr, idmap_kpti_bbml3_flag
cbnz cpu, __idmap_kpti_secondary cbnz cpu, __idmap_kpti_secondary
@ -445,7 +445,7 @@ SYM_TYPED_FUNC_START(wait_linear_map_split_to_ptes)
flag_ptr .req x4 flag_ptr .req x4
mrs swapper_ttb, ttbr1_el1 mrs swapper_ttb, ttbr1_el1
adr_l flag_ptr, idmap_kpti_bbml2_flag adr_l flag_ptr, idmap_kpti_bbml3_flag
__idmap_cpu_set_reserved_ttbr1 x16, x17 __idmap_cpu_set_reserved_ttbr1 x16, x17
scondary_cpu_wait: scondary_cpu_wait:

View File

@ -14,6 +14,7 @@ HAS_ADDRESS_AUTH_ARCH_QARMA5
HAS_ADDRESS_AUTH_IMP_DEF HAS_ADDRESS_AUTH_IMP_DEF
HAS_AMU_EXTN HAS_AMU_EXTN
HAS_ARMv8_4_TTL HAS_ARMv8_4_TTL
HAS_BBML3
HAS_CACHE_DIC HAS_CACHE_DIC
HAS_CACHE_IDC HAS_CACHE_IDC
HAS_CNP HAS_CNP
@ -51,7 +52,6 @@ HAS_LS64_V
HAS_LSUI HAS_LSUI
HAS_MOPS HAS_MOPS
HAS_NESTED_VIRT HAS_NESTED_VIRT
HAS_BBML2_NOABORT
HAS_PAN HAS_PAN
HAS_PMUV3 HAS_PMUV3
HAS_S1PIE HAS_S1PIE