|
| 1 | +From 3d499ba2dce4ac8716f2c9bb07f66f45d0555a19 Mon Sep 17 00:00:00 2001 |
| 2 | +From: The-going < [email protected]> |
| 3 | +Date: Fri, 12 Jul 2024 14:20:15 +0300 |
| 4 | +Subject: arm: patch: call 'patch_unmap' after flushing dcache and icache |
| 5 | + |
| 6 | +Problem: Linux kernel hangs in early boot on 32-bit ARM platform, |
| 7 | +when ftrace 4-byte "mcount" function call location for |
| 8 | +"_raw_spin_unlock_irqrestore" function straddles icache lines. |
| 9 | + |
| 10 | +1. The ftrace location for "_raw_spin_unlock_irqrestore" is NOT |
| 11 | + 4-byte aligned and 4 bytes at this location straddle the instruction |
| 12 | + cache line (0x20) boundaries. |
| 13 | + |
| 14 | +The problem is present for (cross-compiler) GCC 10, 11, 12. |
| 15 | +It does not happen when the kernel is compiled with GCC 9, |
| 16 | +even when condition (1) is satisfied. |
| 17 | + |
| 18 | +Detailed description: |
| 19 | +https://forum.armbian.com/topic/41339-linux-image-legacy-sunxi2451-kernel-6192-is-broken-stuck-at-starting-kernel/?do=findComment&comment=196528 |
| 20 | + |
| 21 | +Author: @mikhailai |
| 22 | +--- |
| 23 | + arch/arm/kernel/patch.c | 9 ++++++++- |
| 24 | + 1 file changed, 8 insertions(+), 1 deletion(-) |
| 25 | + |
| 26 | +diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c |
| 27 | +index e9e828b6bb30..ce0fd3aeb575 100644 |
| 28 | +--- a/arch/arm/kernel/patch.c |
| 29 | ++++ b/arch/arm/kernel/patch.c |
| 30 | +@@ -101,11 +101,18 @@ void __kprobes __patch_text_real(void *addr, unsigned int insn, bool remap) |
| 31 | + |
| 32 | + if (waddr != addr) { |
| 33 | + flush_kernel_vmap_range(waddr, twopage ? size / 2 : size); |
| 34 | +- patch_unmap(FIX_TEXT_POKE0, &flags); |
| 35 | + } |
| 36 | + |
| 37 | + flush_icache_range((uintptr_t)(addr), |
| 38 | + (uintptr_t)(addr) + size); |
| 39 | ++ |
| 40 | ++ /* Can only call 'patch_unmap' after flushing dcache and icache, |
| 41 | ++ * because it calls 'raw_spin_unlock_irqrestore', but that may |
| 42 | ++ * happen to be the very function we're currently patching |
| 43 | ++ * (as it happens during the ftrace init). |
| 44 | ++ */ |
| 45 | ++ if (waddr != addr) |
| 46 | ++ patch_unmap(FIX_TEXT_POKE0, &flags); |
| 47 | + } |
| 48 | + |
| 49 | + static int __kprobes patch_text_stop_machine(void *data) |
| 50 | +-- |
| 51 | +2.35.3 |
| 52 | + |
0 commit comments