mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 13:44:15 +08:00
powerpc/bug: Provide better flexibility to WARN_ON/__WARN_FLAGS() with asm goto
Using asm goto in __WARN_FLAGS() and WARN_ON() allows more flexibility to GCC. For that add an entry to the exception table so that program_check_exception() knowns where to resume execution after a WARNING. Here are two exemples. The first one is done on PPC32 (which benefits from the previous patch), the second is on PPC64. unsigned long test(struct pt_regs *regs) { int ret; WARN_ON(regs->msr & MSR_PR); return regs->gpr[3]; } unsigned long test9w(unsigned long a, unsigned long b) { if (WARN_ON(!b)) return 0; return a / b; } Before the patch: 000003a8 <test>: 3a8: 81 23 00 84 lwz r9,132(r3) 3ac: 71 29 40 00 andi. r9,r9,16384 3b0: 40 82 00 0c bne 3bc <test+0x14> 3b4: 80 63 00 0c lwz r3,12(r3) 3b8: 4e 80 00 20 blr 3bc: 0f e0 00 00 twui r0,0 3c0: 80 63 00 0c lwz r3,12(r3) 3c4: 4e 80 00 20 blr 0000000000000bf0 <.test9w>: bf0: 7c 89 00 74 cntlzd r9,r4 bf4: 79 29 d1 82 rldicl r9,r9,58,6 bf8: 0b 09 00 00 tdnei r9,0 bfc: 2c 24 00 00 cmpdi r4,0 c00: 41 82 00 0c beq c0c <.test9w+0x1c> c04: 7c 63 23 92 divdu r3,r3,r4 c08: 4e 80 00 20 blr c0c: 38 60 00 00 li r3,0 c10: 4e 80 00 20 blr After the patch: 000003a8 <test>: 3a8: 81 23 00 84 lwz r9,132(r3) 3ac: 71 29 40 00 andi. r9,r9,16384 3b0: 40 82 00 0c bne 3bc <test+0x14> 3b4: 80 63 00 0c lwz r3,12(r3) 3b8: 4e 80 00 20 blr 3bc: 0f e0 00 00 twui r0,0 0000000000000c50 <.test9w>: c50: 7c 89 00 74 cntlzd r9,r4 c54: 79 29 d1 82 rldicl r9,r9,58,6 c58: 0b 09 00 00 tdnei r9,0 c5c: 7c 63 23 92 divdu r3,r3,r4 c60: 4e 80 00 20 blr c70: 38 60 00 00 li r3,0 c74: 4e 80 00 20 blr In the first exemple, we see GCC doesn't need to duplicate what happens after the trap. In the second exemple, we see that GCC doesn't need to emit a test and a branch in the likely path in addition to the trap. We've got some WARN_ON() in .softirqentry.text section so it needs to be added in the OTHER_TEXT_SECTIONS in modpost.c Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/389962b1b702e3c78d169e59bcfac56282889173.1618331882.git.christophe.leroy@csgroup.eu
This commit is contained in:
parent
db87a71992
commit
1e688dd2a3
@ -90,7 +90,7 @@
|
||||
/* Prevent access to userspace using any key values */
|
||||
LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED)
|
||||
999: tdne \gpr1, \gpr2
|
||||
EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
EMIT_WARN_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
|
||||
END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_BOOK3S_KUAP, 67)
|
||||
#endif
|
||||
.endm
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <asm/asm-compat.h>
|
||||
#include <asm/extable.h>
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
|
||||
@ -30,6 +31,11 @@
|
||||
.endm
|
||||
#endif /* verbose */
|
||||
|
||||
.macro EMIT_WARN_ENTRY addr,file,line,flags
|
||||
EX_TABLE(\addr,\addr+4)
|
||||
EMIT_BUG_ENTRY \addr,\file,\line,\flags
|
||||
.endm
|
||||
|
||||
#else /* !__ASSEMBLY__ */
|
||||
/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
|
||||
sizeof(struct bug_entry), respectively */
|
||||
@ -58,6 +64,16 @@
|
||||
"i" (sizeof(struct bug_entry)), \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define WARN_ENTRY(insn, flags, label, ...) \
|
||||
asm_volatile_goto( \
|
||||
"1: " insn "\n" \
|
||||
EX_TABLE(1b, %l[label]) \
|
||||
_EMIT_BUG_ENTRY \
|
||||
: : "i" (__FILE__), "i" (__LINE__), \
|
||||
"i" (flags), \
|
||||
"i" (sizeof(struct bug_entry)), \
|
||||
##__VA_ARGS__ : : label)
|
||||
|
||||
/*
|
||||
* BUG_ON() and WARN_ON() do their best to cooperate with compile-time
|
||||
* optimisations. However depending on the complexity of the condition
|
||||
@ -70,7 +86,15 @@
|
||||
} while (0)
|
||||
#define HAVE_ARCH_BUG
|
||||
|
||||
#define __WARN_FLAGS(flags) BUG_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags))
|
||||
#define __WARN_FLAGS(flags) do { \
|
||||
__label__ __label_warn_on; \
|
||||
\
|
||||
WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \
|
||||
unreachable(); \
|
||||
\
|
||||
__label_warn_on: \
|
||||
break; \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
#define BUG_ON(x) do { \
|
||||
@ -83,15 +107,24 @@
|
||||
} while (0)
|
||||
|
||||
#define WARN_ON(x) ({ \
|
||||
int __ret_warn_on = !!(x); \
|
||||
if (__builtin_constant_p(__ret_warn_on)) { \
|
||||
if (__ret_warn_on) \
|
||||
bool __ret_warn_on = false; \
|
||||
do { \
|
||||
if (__builtin_constant_p((x))) { \
|
||||
if (!(x)) \
|
||||
break; \
|
||||
__WARN(); \
|
||||
__ret_warn_on = true; \
|
||||
} else { \
|
||||
BUG_ENTRY(PPC_TLNEI " %4, 0", \
|
||||
__label__ __label_warn_on; \
|
||||
\
|
||||
WARN_ENTRY(PPC_TLNEI " %4, 0", \
|
||||
BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN), \
|
||||
"r" (__ret_warn_on)); \
|
||||
__label_warn_on, "r" (x)); \
|
||||
break; \
|
||||
__label_warn_on: \
|
||||
__ret_warn_on = true; \
|
||||
} \
|
||||
} while (0); \
|
||||
unlikely(__ret_warn_on); \
|
||||
})
|
||||
|
||||
@ -104,8 +137,11 @@
|
||||
#ifdef __ASSEMBLY__
|
||||
.macro EMIT_BUG_ENTRY addr,file,line,flags
|
||||
.endm
|
||||
.macro EMIT_WARN_ENTRY addr,file,line,flags
|
||||
.endm
|
||||
#else /* !__ASSEMBLY__ */
|
||||
#define _EMIT_BUG_ENTRY
|
||||
#define _EMIT_WARN_ENTRY
|
||||
#endif
|
||||
#endif /* CONFIG_BUG */
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#define ARCH_HAS_RELATIVE_EXTABLE
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct exception_table_entry {
|
||||
int insn;
|
||||
int fixup;
|
||||
@ -28,3 +30,15 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper macro for exception table entries
|
||||
*/
|
||||
#define EX_TABLE(_fault, _target) \
|
||||
stringify_in_c(.section __ex_table,"a";)\
|
||||
stringify_in_c(.balign 4;) \
|
||||
stringify_in_c(.long (_fault) - . ;) \
|
||||
stringify_in_c(.long (_target) - . ;) \
|
||||
stringify_in_c(.previous)
|
||||
|
||||
#endif
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <asm/ppc-opcode.h>
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/feature-fixups.h>
|
||||
#include <asm/extable.h>
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
@ -752,16 +753,6 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
* Helper macro for exception table entries
|
||||
*/
|
||||
#define EX_TABLE(_fault, _target) \
|
||||
stringify_in_c(.section __ex_table,"a";)\
|
||||
stringify_in_c(.balign 4;) \
|
||||
stringify_in_c(.long (_fault) - . ;) \
|
||||
stringify_in_c(.long (_target) - . ;) \
|
||||
stringify_in_c(.previous)
|
||||
|
||||
#define SOFT_MASK_TABLE(_start, _end) \
|
||||
stringify_in_c(.section __soft_mask_table,"a";)\
|
||||
stringify_in_c(.balign 8;) \
|
||||
|
@ -309,7 +309,7 @@ _GLOBAL(enter_rtas)
|
||||
*/
|
||||
lbz r0,PACAIRQSOFTMASK(r13)
|
||||
1: tdeqi r0,IRQS_ENABLED
|
||||
EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
|
||||
EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING
|
||||
#endif
|
||||
|
||||
/* Hard-disable interrupts */
|
||||
|
@ -237,7 +237,7 @@ _GLOBAL(copy_page)
|
||||
addi r3,r3,-4
|
||||
|
||||
0: twnei r5, 0 /* WARN if r3 is not cache aligned */
|
||||
EMIT_BUG_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
|
||||
EMIT_WARN_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
|
||||
|
||||
addi r4,r4,-4
|
||||
|
||||
|
@ -1477,9 +1477,14 @@ static void do_program_check(struct pt_regs *regs)
|
||||
|
||||
if (!(regs->msr & MSR_PR) && /* not user-mode */
|
||||
report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
|
||||
regs_add_return_ip(regs, 4);
|
||||
const struct exception_table_entry *entry;
|
||||
|
||||
entry = search_exception_tables(bugaddr);
|
||||
if (entry) {
|
||||
regs_set_return_ip(regs, extable_fixup(entry) + regs->nip - bugaddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
|
||||
return;
|
||||
}
|
||||
|
@ -931,7 +931,7 @@ static void check_section(const char *modname, struct elf_info *elf,
|
||||
".kprobes.text", ".cpuidle.text", ".noinstr.text"
|
||||
#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
|
||||
".fixup", ".entry.text", ".exception.text", ".text.*", \
|
||||
".coldtext"
|
||||
".coldtext", ".softirqentry.text"
|
||||
|
||||
#define INIT_SECTIONS ".init.*"
|
||||
#define MEM_INIT_SECTIONS ".meminit.*"
|
||||
|
1
tools/testing/selftests/powerpc/primitives/asm/extable.h
Symbolic link
1
tools/testing/selftests/powerpc/primitives/asm/extable.h
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../../arch/powerpc/include/asm/extable.h
|
Loading…
Reference in New Issue
Block a user