mirror of
https://github.com/torvalds/linux.git
synced 2024-12-25 12:21:37 +00:00
a4a5a7379e
On old ARM chips, unaligned accesses to memory are not trapped and fixed. On module load, symbols are relocated, and the relocation of __bug_table symbols is done on a u32 basis. Yet the section is not aligned to a multiple of 4 address, but to a multiple of 2. This triggers an Oops on pxa architecture, where address 0xbf0021ea is the first relocation in the __bug_table section : apply_relocate(): pxa3xx_nand: section 13 reloc 0 sym '' Unable to handle kernel paging request at virtual address bf0021ea pgd = e1cd0000 [bf0021ea] *pgd=c1cce851, *pte=c1cde04f, *ppte=c1cde01f Internal error: Oops: 23 [#1] ARM Modules linked in: CPU: 0 PID: 606 Comm: insmod Not tainted 4.2.0-rc8-next-20150828-cm-x300+ #887 Hardware name: CM-X300 module task: e1c68700 ti: e1c3e000 task.ti: e1c3e000 PC is at apply_relocate+0x2f4/0x3d4 LR is at 0xbf0021ea pc : [<c000e7c8>] lr : [<bf0021ea>] psr: 80000013 sp : e1c3fe30 ip : 60000013 fp : e49e8c60 r10: e49e8fa8 r9 : 00000000 r8 : e49e7c58 r7 : e49e8c38 r6 : e49e8a58 r5 : e49e8920 r4 : e49e8918 r3 : bf0021ea r2 : bf007034 r1 : 00000000 r0 : bf000000 Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 0000397f Table: c1cd0018 DAC: 00000051 Process insmod (pid: 606, stack limit = 0xe1c3e198) [<c000e7c8>] (apply_relocate) from [<c005ce5c>] (load_module+0x1248/0x1f5c) [<c005ce5c>] (load_module) from [<c005dc54>] (SyS_init_module+0xe4/0x170) [<c005dc54>] (SyS_init_module) from [<c000a420>] (ret_fast_syscall+0x0/0x38) Fix this by ensuring entries in __bug_table are all aligned to at least of multiple of 4. This transforms a module section __bug_table as : - [12] __bug_table PROGBITS 00000000 002232 000018 00 A 0 0 1 + [12] __bug_table PROGBITS 00000000 002232 000018 00 A 0 0 4 Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Reviewed-by: Dave Martin <Dave.Martin@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
94 lines
2.5 KiB
C
94 lines
2.5 KiB
C
#ifndef _ASMARM_BUG_H
|
|
#define _ASMARM_BUG_H
|
|
|
|
#include <linux/linkage.h>
|
|
#include <linux/types.h>
|
|
#include <asm/opcodes.h>
|
|
|
|
#ifdef CONFIG_BUG
|
|
|
|
/*
|
|
* Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
|
|
* We need to be careful not to conflict with those used by other modules and
|
|
* the register_undef_hook() system.
|
|
*/
|
|
#ifdef CONFIG_THUMB2_KERNEL
|
|
#define BUG_INSTR_VALUE 0xde02
|
|
#define BUG_INSTR(__value) __inst_thumb16(__value)
|
|
#else
|
|
#define BUG_INSTR_VALUE 0xe7f001f2
|
|
#define BUG_INSTR(__value) __inst_arm(__value)
|
|
#endif
|
|
|
|
|
|
#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
|
|
#define _BUG(file, line, value) __BUG(file, line, value)
|
|
|
|
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
|
|
|
/*
|
|
* The extra indirection is to ensure that the __FILE__ string comes through
|
|
* OK. Many version of gcc do not support the asm %c parameter which would be
|
|
* preferable to this unpleasantness. We use mergeable string sections to
|
|
* avoid multiple copies of the string appearing in the kernel image.
|
|
*/
|
|
|
|
#define __BUG(__file, __line, __value) \
|
|
do { \
|
|
asm volatile("1:\t" BUG_INSTR(__value) "\n" \
|
|
".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
|
|
"2:\t.asciz " #__file "\n" \
|
|
".popsection\n" \
|
|
".pushsection __bug_table,\"a\"\n" \
|
|
".align 2\n" \
|
|
"3:\t.word 1b, 2b\n" \
|
|
"\t.hword " #__line ", 0\n" \
|
|
".popsection"); \
|
|
unreachable(); \
|
|
} while (0)
|
|
|
|
#else /* not CONFIG_DEBUG_BUGVERBOSE */
|
|
|
|
#define __BUG(__file, __line, __value) \
|
|
do { \
|
|
asm volatile(BUG_INSTR(__value) "\n"); \
|
|
unreachable(); \
|
|
} while (0)
|
|
#endif /* CONFIG_DEBUG_BUGVERBOSE */
|
|
|
|
#define HAVE_ARCH_BUG
|
|
#endif /* CONFIG_BUG */
|
|
|
|
#include <asm-generic/bug.h>
|
|
|
|
struct pt_regs;
|
|
void die(const char *msg, struct pt_regs *regs, int err);
|
|
|
|
struct siginfo;
|
|
void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
|
|
unsigned long err, unsigned long trap);
|
|
|
|
#ifdef CONFIG_ARM_LPAE
|
|
#define FAULT_CODE_ALIGNMENT 33
|
|
#define FAULT_CODE_DEBUG 34
|
|
#else
|
|
#define FAULT_CODE_ALIGNMENT 1
|
|
#define FAULT_CODE_DEBUG 2
|
|
#endif
|
|
|
|
void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
|
|
struct pt_regs *),
|
|
int sig, int code, const char *name);
|
|
|
|
void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
|
|
struct pt_regs *),
|
|
int sig, int code, const char *name);
|
|
|
|
extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
|
|
|
|
struct mm_struct;
|
|
extern void show_pte(struct mm_struct *mm, unsigned long addr);
|
|
extern void __show_regs(struct pt_regs *);
|
|
|
|
#endif
|