Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Catalin Marinas:

- Revert the moving of the jump labels initialisation before
setup_machine_fdt(). The bug was fixed in drivers/char/random.c.

- Ftrace fixes: branch range check and consistent handling of PLTs.

- Clean rather than invalidate FROM_DEVICE buffers at start of DMA
transfer (safer if such buffer is mapped in user space). A cache
invalidation is done already at the end of the transfer.

- A couple of clean-ups (unexport symbol, remove unused label).

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer
arm64/cpufeature: Unexport set_cpu_feature()
arm64: ftrace: remove redundant label
arm64: ftrace: consistently handle PLTs.
arm64: ftrace: fix branch range checks
Revert "arm64: Initialize jump labels before setup_machine_fdt()"

+76 -86
-1
arch/arm64/kernel/cpufeature.c
··· 3101 3101 WARN_ON(num >= MAX_CPU_FEATURES); 3102 3102 elf_hwcap |= BIT(num); 3103 3103 } 3104 - EXPORT_SYMBOL_GPL(cpu_set_feature); 3105 3104 3106 3105 bool cpu_have_feature(unsigned int num) 3107 3106 {
-1
arch/arm64/kernel/entry-ftrace.S
··· 102 102 * x19-x29 per the AAPCS, and we created frame records upon entry, so we need 103 103 * to restore x0-x8, x29, and x30. 104 104 */ 105 - ftrace_common_return: 106 105 /* Restore function arguments */ 107 106 ldp x0, x1, [sp] 108 107 ldp x2, x3, [sp, #S_X2]
+71 -76
arch/arm64/kernel/ftrace.c
··· 78 78 } 79 79 80 80 /* 81 + * Find the address the callsite must branch to in order to reach '*addr'. 82 + * 83 + * Due to the limited range of 'BL' instructions, modules may be placed too far 84 + * away to branch directly and must use a PLT. 85 + * 86 + * Returns true when '*addr' contains a reachable target address, or has been 87 + * modified to contain a PLT address. Returns false otherwise. 88 + */ 89 + static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, 90 + struct module *mod, 91 + unsigned long *addr) 92 + { 93 + unsigned long pc = rec->ip; 94 + long offset = (long)*addr - (long)pc; 95 + struct plt_entry *plt; 96 + 97 + /* 98 + * When the target is within range of the 'BL' instruction, use 'addr' 99 + * as-is and branch to that directly. 100 + */ 101 + if (offset >= -SZ_128M && offset < SZ_128M) 102 + return true; 103 + 104 + /* 105 + * When the target is outside of the range of a 'BL' instruction, we 106 + * must use a PLT to reach it. We can only place PLTs for modules, and 107 + * only when module PLT support is built-in. 108 + */ 109 + if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 110 + return false; 111 + 112 + /* 113 + * 'mod' is only set at module load time, but if we end up 114 + * dealing with an out-of-range condition, we can assume it 115 + * is due to a module being loaded far away from the kernel. 116 + * 117 + * NOTE: __module_text_address() must be called with preemption 118 + * disabled, but we can rely on ftrace_lock to ensure that 'mod' 119 + * retains its validity throughout the remainder of this code. 120 + */ 121 + if (!mod) { 122 + preempt_disable(); 123 + mod = __module_text_address(pc); 124 + preempt_enable(); 125 + } 126 + 127 + if (WARN_ON(!mod)) 128 + return false; 129 + 130 + plt = get_ftrace_plt(mod, *addr); 131 + if (!plt) { 132 + pr_err("ftrace: no module PLT for %ps\n", (void *)*addr); 133 + return false; 134 + } 135 + 136 + *addr = (unsigned long)plt; 137 + return true; 138 + } 139 + 140 + /* 81 141 * Turn on the call to ftrace_caller() in instrumented function 82 142 */ 83 143 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 84 144 { 85 145 unsigned long pc = rec->ip; 86 146 u32 old, new; 87 - long offset = (long)pc - (long)addr; 88 147 89 - if (offset < -SZ_128M || offset >= SZ_128M) { 90 - struct module *mod; 91 - struct plt_entry *plt; 92 - 93 - if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 94 - return -EINVAL; 95 - 96 - /* 97 - * On kernels that support module PLTs, the offset between the 98 - * branch instruction and its target may legally exceed the 99 - * range of an ordinary relative 'bl' opcode. In this case, we 100 - * need to branch via a trampoline in the module. 101 - * 102 - * NOTE: __module_text_address() must be called with preemption 103 - * disabled, but we can rely on ftrace_lock to ensure that 'mod' 104 - * retains its validity throughout the remainder of this code. 105 - */ 106 - preempt_disable(); 107 - mod = __module_text_address(pc); 108 - preempt_enable(); 109 - 110 - if (WARN_ON(!mod)) 111 - return -EINVAL; 112 - 113 - plt = get_ftrace_plt(mod, addr); 114 - if (!plt) { 115 - pr_err("ftrace: no module PLT for %ps\n", (void *)addr); 116 - return -EINVAL; 117 - } 118 - 119 - addr = (unsigned long)plt; 120 - } 148 + if (!ftrace_find_callable_addr(rec, NULL, &addr)) 149 + return -EINVAL; 121 150 122 151 old = aarch64_insn_gen_nop(); 123 152 new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK); ··· 160 131 { 161 132 unsigned long pc = rec->ip; 162 133 u32 old, new; 134 + 135 + if (!ftrace_find_callable_addr(rec, NULL, &old_addr)) 136 + return -EINVAL; 137 + if (!ftrace_find_callable_addr(rec, NULL, &addr)) 138 + return -EINVAL; 163 139 164 140 old = aarch64_insn_gen_branch_imm(pc, old_addr, 165 141 AARCH64_INSN_BRANCH_LINK); ··· 215 181 unsigned long addr) 216 182 { 217 183 unsigned long pc = rec->ip; 218 - bool validate = true; 219 184 u32 old = 0, new; 220 - long offset = (long)pc - (long)addr; 221 185 222 - if (offset < -SZ_128M || offset >= SZ_128M) { 223 - u32 replaced; 186 + if (!ftrace_find_callable_addr(rec, mod, &addr)) 187 + return -EINVAL; 224 188 225 - if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) 226 - return -EINVAL; 227 - 228 - /* 229 - * 'mod' is only set at module load time, but if we end up 230 - * dealing with an out-of-range condition, we can assume it 231 - * is due to a module being loaded far away from the kernel. 232 - */ 233 - if (!mod) { 234 - preempt_disable(); 235 - mod = __module_text_address(pc); 236 - preempt_enable(); 237 - 238 - if (WARN_ON(!mod)) 239 - return -EINVAL; 240 - } 241 - 242 - /* 243 - * The instruction we are about to patch may be a branch and 244 - * link instruction that was redirected via a PLT entry. In 245 - * this case, the normal validation will fail, but we can at 246 - * least check that we are dealing with a branch and link 247 - * instruction that points into the right module. 248 - */ 249 - if (aarch64_insn_read((void *)pc, &replaced)) 250 - return -EFAULT; 251 - 252 - if (!aarch64_insn_is_bl(replaced) || 253 - !within_module(pc + aarch64_get_branch_offset(replaced), 254 - mod)) 255 - return -EINVAL; 256 - 257 - validate = false; 258 - } else { 259 - old = aarch64_insn_gen_branch_imm(pc, addr, 260 - AARCH64_INSN_BRANCH_LINK); 261 - } 262 - 189 + old = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK); 263 190 new = aarch64_insn_gen_nop(); 264 191 265 - return ftrace_modify_code(pc, old, new, validate); 192 + return ftrace_modify_code(pc, old, new, true); 266 193 } 267 194 268 195 void arch_ftrace_update_code(int command)
+5 -6
arch/arm64/kernel/setup.c
··· 303 303 early_fixmap_init(); 304 304 early_ioremap_init(); 305 305 306 - /* 307 - * Initialise the static keys early as they may be enabled by the 308 - * cpufeature code, early parameters, and DT setup. 309 - */ 310 - jump_label_init(); 311 - 312 306 setup_machine_fdt(__fdt_pointer); 313 307 308 + /* 309 + * Initialise the static keys early as they may be enabled by the 310 + * cpufeature code and early parameters. 311 + */ 312 + jump_label_init(); 314 313 parse_early_param(); 315 314 316 315 /*
-2
arch/arm64/mm/cache.S
··· 218 218 */ 219 219 SYM_FUNC_START(__pi___dma_map_area) 220 220 add x1, x0, x1 221 - cmp w2, #DMA_FROM_DEVICE 222 - b.eq __pi_dcache_inval_poc 223 221 b __pi_dcache_clean_poc 224 222 SYM_FUNC_END(__pi___dma_map_area) 225 223 SYM_FUNC_ALIAS(__dma_map_area, __pi___dma_map_area)