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

ARM: fixup SMP alternatives in modules

With certain configurations, we inline the unlock functions in modules,
which results in SMP alternatives being created in modules. We need to
fix those up when loading a module to prevent undefined instruction
faults.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

+48 -14
+27 -13
arch/arm/kernel/head.S
··· 391 391 392 392 393 393 #ifdef CONFIG_SMP_ON_UP 394 + __INIT 394 395 __fixup_smp: 395 396 and r3, r9, #0x000f0000 @ architecture version 396 397 teq r3, #0x000f0000 @ CPU ID supported? ··· 416 415 sub r3, r0, r3 417 416 add r4, r4, r3 418 417 add r5, r5, r3 419 - 2: cmp r4, r5 420 - movhs pc, lr 421 - ldmia r4!, {r0, r6} 422 - ARM( str r6, [r0, r3] ) 423 - THUMB( add r0, r0, r3 ) 424 - #ifdef __ARMEB__ 425 - THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. 426 - #endif 427 - THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords 428 - THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. 429 - THUMB( strh r6, [r0] ) 430 - b 2b 418 + b __do_fixup_smp_on_up 431 419 ENDPROC(__fixup_smp) 432 420 433 421 .align ··· 430 440 ALT_SMP(.long 1) 431 441 ALT_UP(.long 0) 432 442 .popsection 433 - 434 443 #endif 444 + 445 + .text 446 + __do_fixup_smp_on_up: 447 + cmp r4, r5 448 + movhs pc, lr 449 + ldmia r4!, {r0, r6} 450 + ARM( str r6, [r0, r3] ) 451 + THUMB( add r0, r0, r3 ) 452 + #ifdef __ARMEB__ 453 + THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. 454 + #endif 455 + THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords 456 + THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. 457 + THUMB( strh r6, [r0] ) 458 + b __do_fixup_smp_on_up 459 + ENDPROC(__do_fixup_smp_on_up) 460 + 461 + ENTRY(fixup_smp) 462 + stmfd sp!, {r4 - r6, lr} 463 + mov r4, r0 464 + add r5, r0, r1 465 + mov r3, #0 466 + bl __do_fixup_smp_on_up 467 + ldmfd sp!, {r4 - r6, pc} 468 + ENDPROC(fixup_smp) 435 469 436 470 #include "head-common.S"
+21 -1
arch/arm/kernel/module.c
··· 22 22 23 23 #include <asm/pgtable.h> 24 24 #include <asm/sections.h> 25 + #include <asm/smp_plat.h> 25 26 #include <asm/unwind.h> 26 27 27 28 #ifdef CONFIG_XIP_KERNEL ··· 269 268 const Elf_Shdr *txt_sec; 270 269 }; 271 270 271 + static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, 272 + const Elf_Shdr *sechdrs, const char *name) 273 + { 274 + const Elf_Shdr *s, *se; 275 + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 276 + 277 + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) 278 + if (strcmp(name, secstrs + s->sh_name) == 0) 279 + return s; 280 + 281 + return NULL; 282 + } 283 + 284 + extern void fixup_smp(const void *, unsigned long); 285 + 272 286 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, 273 287 struct module *mod) 274 288 { 289 + const Elf_Shdr * __maybe_unused s = NULL; 275 290 #ifdef CONFIG_ARM_UNWIND 276 291 const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 277 - const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum; 292 + const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; 278 293 struct mod_unwind_map maps[ARM_SEC_MAX]; 279 294 int i; 280 295 ··· 332 315 maps[i].txt_sec->sh_addr, 333 316 maps[i].txt_sec->sh_size); 334 317 #endif 318 + s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); 319 + if (s && !is_smp()) 320 + fixup_smp((void *)s->sh_addr, s->sh_size); 335 321 return 0; 336 322 } 337 323