Skip to content

Commit 3913809

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: alternatives: make clean_dcache_range_nopatch() noinstr-safe
When patching kernel alternatives, we need to be careful not to execute kernel code which is itself subject to patching. In general, if code is executed after the instructions in memory have been patched but prior to the cache maintenance and barriers completing, it could lead to UNPREDICTABLE results. As our regular cache maintenance routines are patched with alternatives, we have a clean_dcache_range_nopatch() function which is *intended* to avoid patchable code and therefore supposed to be safe in the middle of patching alternatives. Unfortunately, it's not marked as 'noinstr', and so can be instrumented with patchable code. Additionally, it calls read_sanitised_ftr_reg() (which may be instrumented with patchable code) to find the sanitized value of CTR_EL0.DminLine, and is therefore not safe to call during patching. Luckily, since commit: 675b056 ("arm64: cpufeature: expose arm64_ftr_reg struct for CTR_EL0") ... we can read the sanitised CTR_EL0 value directly, and avoid the call to read_sanitised_ftr_reg(). This patch marks clean_dcache_range_nopatch() as noinstr, and has it read the sanitized CTR_EL0 value directly, avoiding the issues above. As a bonus, this is also an optimization. As read_sanitised_ftr_reg() performs a binary search to find the CTR_EL0 value, reading the value directly avoids this binary search per applied alternative, avoiding some unnecessary work. Signed-off-by: Mark Rutland <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 615af00 commit 3913809

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

arch/arm64/kernel/alternative.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ static noinstr void patch_alternative(struct alt_instr *alt,
121121
* accidentally call into the cache.S code, which is patched by us at
122122
* runtime.
123123
*/
124-
static void clean_dcache_range_nopatch(u64 start, u64 end)
124+
static noinstr void clean_dcache_range_nopatch(u64 start, u64 end)
125125
{
126126
u64 cur, d_size, ctr_el0;
127127

128-
ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0);
128+
ctr_el0 = arm64_ftr_reg_ctrel0.sys_val;
129129
d_size = 4 << cpuid_feature_extract_unsigned_field(ctr_el0,
130130
CTR_EL0_DminLine_SHIFT);
131131
cur = start & ~(d_size - 1);

0 commit comments

Comments
 (0)