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

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

authored by

Christophe Leroy and committed by
Michael Ellerman
1e688dd2 db87a719

+71 -25
+1 -1
arch/powerpc/include/asm/book3s/64/kup.h
··· 90 90 /* Prevent access to userspace using any key values */ 91 91 LOAD_REG_IMMEDIATE(\gpr2, AMR_KUAP_BLOCKED) 92 92 999: tdne \gpr1, \gpr2 93 - EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE) 93 + EMIT_WARN_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE) 94 94 END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_BOOK3S_KUAP, 67) 95 95 #endif 96 96 .endm
+45 -9
arch/powerpc/include/asm/bug.h
··· 4 4 #ifdef __KERNEL__ 5 5 6 6 #include <asm/asm-compat.h> 7 + #include <asm/extable.h> 7 8 8 9 #ifdef CONFIG_BUG 9 10 ··· 30 29 .previous 31 30 .endm 32 31 #endif /* verbose */ 32 + 33 + .macro EMIT_WARN_ENTRY addr,file,line,flags 34 + EX_TABLE(\addr,\addr+4) 35 + EMIT_BUG_ENTRY \addr,\file,\line,\flags 36 + .endm 33 37 34 38 #else /* !__ASSEMBLY__ */ 35 39 /* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and ··· 64 58 "i" (sizeof(struct bug_entry)), \ 65 59 ##__VA_ARGS__) 66 60 61 + #define WARN_ENTRY(insn, flags, label, ...) \ 62 + asm_volatile_goto( \ 63 + "1: " insn "\n" \ 64 + EX_TABLE(1b, %l[label]) \ 65 + _EMIT_BUG_ENTRY \ 66 + : : "i" (__FILE__), "i" (__LINE__), \ 67 + "i" (flags), \ 68 + "i" (sizeof(struct bug_entry)), \ 69 + ##__VA_ARGS__ : : label) 70 + 67 71 /* 68 72 * BUG_ON() and WARN_ON() do their best to cooperate with compile-time 69 73 * optimisations. However depending on the complexity of the condition ··· 86 70 } while (0) 87 71 #define HAVE_ARCH_BUG 88 72 89 - #define __WARN_FLAGS(flags) BUG_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags)) 73 + #define __WARN_FLAGS(flags) do { \ 74 + __label__ __label_warn_on; \ 75 + \ 76 + WARN_ENTRY("twi 31, 0, 0", BUGFLAG_WARNING | (flags), __label_warn_on); \ 77 + unreachable(); \ 78 + \ 79 + __label_warn_on: \ 80 + break; \ 81 + } while (0) 90 82 91 83 #ifdef CONFIG_PPC64 92 84 #define BUG_ON(x) do { \ ··· 107 83 } while (0) 108 84 109 85 #define WARN_ON(x) ({ \ 110 - int __ret_warn_on = !!(x); \ 111 - if (__builtin_constant_p(__ret_warn_on)) { \ 112 - if (__ret_warn_on) \ 86 + bool __ret_warn_on = false; \ 87 + do { \ 88 + if (__builtin_constant_p((x))) { \ 89 + if (!(x)) \ 90 + break; \ 113 91 __WARN(); \ 114 - } else { \ 115 - BUG_ENTRY(PPC_TLNEI " %4, 0", \ 116 - BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN), \ 117 - "r" (__ret_warn_on)); \ 118 - } \ 92 + __ret_warn_on = true; \ 93 + } else { \ 94 + __label__ __label_warn_on; \ 95 + \ 96 + WARN_ENTRY(PPC_TLNEI " %4, 0", \ 97 + BUGFLAG_WARNING | BUGFLAG_TAINT(TAINT_WARN), \ 98 + __label_warn_on, "r" (x)); \ 99 + break; \ 100 + __label_warn_on: \ 101 + __ret_warn_on = true; \ 102 + } \ 103 + } while (0); \ 119 104 unlikely(__ret_warn_on); \ 120 105 }) 121 106 ··· 137 104 #ifdef __ASSEMBLY__ 138 105 .macro EMIT_BUG_ENTRY addr,file,line,flags 139 106 .endm 107 + .macro EMIT_WARN_ENTRY addr,file,line,flags 108 + .endm 140 109 #else /* !__ASSEMBLY__ */ 141 110 #define _EMIT_BUG_ENTRY 111 + #define _EMIT_WARN_ENTRY 142 112 #endif 143 113 #endif /* CONFIG_BUG */ 144 114
+14
arch/powerpc/include/asm/extable.h
··· 17 17 18 18 #define ARCH_HAS_RELATIVE_EXTABLE 19 19 20 + #ifndef __ASSEMBLY__ 21 + 20 22 struct exception_table_entry { 21 23 int insn; 22 24 int fixup; ··· 28 26 { 29 27 return (unsigned long)&x->fixup + x->fixup; 30 28 } 29 + 30 + #endif 31 + 32 + /* 33 + * Helper macro for exception table entries 34 + */ 35 + #define EX_TABLE(_fault, _target) \ 36 + stringify_in_c(.section __ex_table,"a";)\ 37 + stringify_in_c(.balign 4;) \ 38 + stringify_in_c(.long (_fault) - . ;) \ 39 + stringify_in_c(.long (_target) - . ;) \ 40 + stringify_in_c(.previous) 31 41 32 42 #endif
+1 -10
arch/powerpc/include/asm/ppc_asm.h
··· 10 10 #include <asm/ppc-opcode.h> 11 11 #include <asm/firmware.h> 12 12 #include <asm/feature-fixups.h> 13 + #include <asm/extable.h> 13 14 14 15 #ifdef __ASSEMBLY__ 15 16 ··· 752 751 #endif /* !CONFIG_PPC_BOOK3E */ 753 752 754 753 #endif /* __ASSEMBLY__ */ 755 - 756 - /* 757 - * Helper macro for exception table entries 758 - */ 759 - #define EX_TABLE(_fault, _target) \ 760 - stringify_in_c(.section __ex_table,"a";)\ 761 - stringify_in_c(.balign 4;) \ 762 - stringify_in_c(.long (_fault) - . ;) \ 763 - stringify_in_c(.long (_target) - . ;) \ 764 - stringify_in_c(.previous) 765 754 766 755 #define SOFT_MASK_TABLE(_start, _end) \ 767 756 stringify_in_c(.section __soft_mask_table,"a";)\
+1 -1
arch/powerpc/kernel/entry_64.S
··· 309 309 */ 310 310 lbz r0,PACAIRQSOFTMASK(r13) 311 311 1: tdeqi r0,IRQS_ENABLED 312 - EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING 312 + EMIT_WARN_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING 313 313 #endif 314 314 315 315 /* Hard-disable interrupts */
+1 -1
arch/powerpc/kernel/misc_32.S
··· 237 237 addi r3,r3,-4 238 238 239 239 0: twnei r5, 0 /* WARN if r3 is not cache aligned */ 240 - EMIT_BUG_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING 240 + EMIT_WARN_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING 241 241 242 242 addi r4,r4,-4 243 243
+7 -2
arch/powerpc/kernel/traps.c
··· 1477 1477 1478 1478 if (!(regs->msr & MSR_PR) && /* not user-mode */ 1479 1479 report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) { 1480 - regs_add_return_ip(regs, 4); 1481 - return; 1480 + const struct exception_table_entry *entry; 1481 + 1482 + entry = search_exception_tables(bugaddr); 1483 + if (entry) { 1484 + regs_set_return_ip(regs, extable_fixup(entry) + regs->nip - bugaddr); 1485 + return; 1486 + } 1482 1487 } 1483 1488 _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); 1484 1489 return;
+1 -1
scripts/mod/modpost.c
··· 931 931 ".kprobes.text", ".cpuidle.text", ".noinstr.text" 932 932 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ 933 933 ".fixup", ".entry.text", ".exception.text", ".text.*", \ 934 - ".coldtext" 934 + ".coldtext", ".softirqentry.text" 935 935 936 936 #define INIT_SECTIONS ".init.*" 937 937 #define MEM_INIT_SECTIONS ".meminit.*"