Skip to content

Commit 0a285df

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: Avoid cpus_have_const_cap() for ARM64_WORKAROUND_843419
In count_plts() and is_forbidden_offset_for_adrp() we use cpus_have_const_cap() to check for ARM64_WORKAROUND_843419, but this is not necessary and cpus_have_final_cap() would be preferable. For historical reasons, cpus_have_const_cap() is more complicated than it needs to be. Before cpucaps are finalized, it will perform a bitmap test of the system_cpucaps bitmap, and once cpucaps are finalized it will use an alternative branch. This used to be necessary to handle some race conditions in the window between cpucap detection and the subsequent patching of alternatives and static branches, where different branches could be out-of-sync with one another (or w.r.t. alternative sequences). Now that we use alternative branches instead of static branches, these are all patched atomically w.r.t. one another, and there are only a handful of cases that need special care in the window between cpucap detection and alternative patching. Due to the above, it would be nice to remove cpus_have_const_cap(), and migrate callers over to alternative_has_cap_*(), cpus_have_final_cap(), or cpus_have_cap() depending on when their requirements. This will remove redundant instructions and improve code generation, and will make it easier to determine how each callsite will behave before, during, and after alternative patching. It's not possible to load a module in the window between detecting the ARM64_WORKAROUND_843419 cpucap and patching alternatives. The module VA range limits are initialized much later in module_init_limits() which is a subsys_initcall, and module loading cannot happen before this. Hence it's not necessary for count_plts() or is_forbidden_offset_for_adrp() to use cpus_have_const_cap(). This patch replaces the use of cpus_have_const_cap() with cpus_have_final_cap() which will avoid generating code to test the system_cpucaps bitmap and should be better for all subsequent calls at runtime. Using cpus_have_final_cap() clearly documents that we do not expect this code to run before cpucaps are finalized, and will make it easier to spot issues if code is changed in future to allow modules to be loaded earlier. The ARM64_WORKAROUND_843419 cpucap is added to cpucap_is_possible() so that code can be elided entirely when this is not possible, and redundant IS_ENABLED() checks are removed. Signed-off-by: Mark Rutland <[email protected]> Cc: Ard Biesheuvel <[email protected]> Cc: Suzuki K Poulose <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Catalin Marinas <[email protected]>
1 parent c2ef5f1 commit 0a285df

File tree

3 files changed

+6
-6
lines changed

3 files changed

+6
-6
lines changed

arch/arm64/include/asm/cpucaps.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ cpucap_is_possible(const unsigned int cap)
4444
return IS_ENABLED(CONFIG_ARM64_TLB_RANGE);
4545
case ARM64_UNMAP_KERNEL_AT_EL0:
4646
return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0);
47+
case ARM64_WORKAROUND_843419:
48+
return IS_ENABLED(CONFIG_ARM64_ERRATUM_843419);
4749
case ARM64_WORKAROUND_2658417:
4850
return IS_ENABLED(CONFIG_ARM64_ERRATUM_2658417);
4951
}

arch/arm64/include/asm/module.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ struct plt_entry {
4444

4545
static inline bool is_forbidden_offset_for_adrp(void *place)
4646
{
47-
return IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) &&
48-
cpus_have_const_cap(ARM64_WORKAROUND_843419) &&
47+
return cpus_have_final_cap(ARM64_WORKAROUND_843419) &&
4948
((u64)place & 0xfff) >= 0xff8;
5049
}
5150

arch/arm64/kernel/module-plts.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,7 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
203203
break;
204204
case R_AARCH64_ADR_PREL_PG_HI21_NC:
205205
case R_AARCH64_ADR_PREL_PG_HI21:
206-
if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) ||
207-
!cpus_have_const_cap(ARM64_WORKAROUND_843419))
206+
if (!cpus_have_final_cap(ARM64_WORKAROUND_843419))
208207
break;
209208

210209
/*
@@ -239,13 +238,13 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
239238
}
240239
}
241240

242-
if (IS_ENABLED(CONFIG_ARM64_ERRATUM_843419) &&
243-
cpus_have_const_cap(ARM64_WORKAROUND_843419))
241+
if (cpus_have_final_cap(ARM64_WORKAROUND_843419)) {
244242
/*
245243
* Add some slack so we can skip PLT slots that may trigger
246244
* the erratum due to the placement of the ADRP instruction.
247245
*/
248246
ret += DIV_ROUND_UP(ret, (SZ_4K / sizeof(struct plt_entry)));
247+
}
249248

250249
return ret;
251250
}

0 commit comments

Comments
 (0)