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

ARM: Correct BUG() assembly to ensure it is endian-agnostic

Currently BUG() uses .word or .hword to create the necessary illegal
instructions. However if we are building BE8 then these get swapped
by the linker into different illegal instructions in the text. This
means that the BUG() macro does not get trapped properly.

Change to using <asm/opcodes.h> to provide the necessary ARM instruction
building as we cannot rely on gcc/gas having the `.inst` instructions
which where added to try and resolve this issue (reported by Dave Martin
<Dave.Martin@arm.com>).

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Reviewed-by: Dave Martin <Dave.Martin@arm.com>

Ben Dooks 63328070 3460743e

+11 -7
+6 -4
arch/arm/include/asm/bug.h
··· 2 2 #define _ASMARM_BUG_H 3 3 4 4 #include <linux/linkage.h> 5 + #include <linux/types.h> 6 + #include <asm/opcodes.h> 5 7 6 8 #ifdef CONFIG_BUG 7 9 ··· 14 12 */ 15 13 #ifdef CONFIG_THUMB2_KERNEL 16 14 #define BUG_INSTR_VALUE 0xde02 17 - #define BUG_INSTR_TYPE ".hword " 15 + #define BUG_INSTR(__value) __inst_thumb16(__value) 18 16 #else 19 17 #define BUG_INSTR_VALUE 0xe7f001f2 20 - #define BUG_INSTR_TYPE ".word " 18 + #define BUG_INSTR(__value) __inst_arm(__value) 21 19 #endif 22 20 23 21 ··· 35 33 36 34 #define __BUG(__file, __line, __value) \ 37 35 do { \ 38 - asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \ 36 + asm volatile("1:\t" BUG_INSTR(__value) "\n" \ 39 37 ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \ 40 38 "2:\t.asciz " #__file "\n" \ 41 39 ".popsection\n" \ ··· 50 48 51 49 #define __BUG(__file, __line, __value) \ 52 50 do { \ 53 - asm volatile(BUG_INSTR_TYPE #__value); \ 51 + asm volatile(BUG_INSTR(__value) "\n"); \ 54 52 unreachable(); \ 55 53 } while (0) 56 54 #endif /* CONFIG_DEBUG_BUGVERBOSE */
+5 -3
arch/arm/kernel/traps.c
··· 342 342 int is_valid_bugaddr(unsigned long pc) 343 343 { 344 344 #ifdef CONFIG_THUMB2_KERNEL 345 - unsigned short bkpt; 345 + u16 bkpt; 346 + u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE); 346 347 #else 347 - unsigned long bkpt; 348 + u32 bkpt; 349 + u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE); 348 350 #endif 349 351 350 352 if (probe_kernel_address((unsigned *)pc, bkpt)) 351 353 return 0; 352 354 353 - return bkpt == BUG_INSTR_VALUE; 355 + return bkpt == insn; 354 356 } 355 357 356 358 #endif