Skip to content

Commit

Permalink
LoongArch: Use generic BUG() handler
Browse files Browse the repository at this point in the history
Inspired by commit 9fb7410("arm64/BUG: Use BRK instruction for
generic BUG traps"), do similar for LoongArch to use generic BUG()
handler.

This patch uses the BREAK software breakpoint instruction to generate
a trap instead, similarly to most other arches, with the generic BUG
code generating the dmesg boilerplate.

This allows bug metadata to be moved to a separate table and reduces
the amount of inline code at BUG() and WARN() sites. This also avoids
clobbering any registers before they can be dumped.

To mitigate the size of the bug table further, this patch makes use of
the existing infrastructure for encoding addresses within the bug table
as 32-bit relative pointers instead of absolute pointers.

(Note: this limits the max kernel size to 2GB.)

Before patch:
[ 3018.338013] lkdtm: Performing direct entry BUG
[ 3018.342445] Kernel bug detected[Rust-for-Linux#5]:
[ 3018.345992] CPU: 2 PID: 865 Comm: cat Tainted: G D 6.0.0-rc6+ Rust-for-Linux#35

After patch:
[  125.585985] lkdtm: Performing direct entry BUG
[  125.590433] ------------[ cut here ]------------
[  125.595020] kernel BUG at drivers/misc/lkdtm/bugs.c:78!
[  125.600211] Oops - BUG[Rust-for-Linux#1]:
[  125.602980] CPU: 3 PID: 410 Comm: cat Not tainted 6.0.0-rc6+ Rust-for-Linux#36

Out-of-line file/line data information obtained compared to before.

Signed-off-by: Youling Tang <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
  • Loading branch information
Youling Tang authored and chenhuacai committed Oct 12, 2022
1 parent dea2df3 commit 2d2c395
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 12 deletions.
8 changes: 8 additions & 0 deletions arch/loongarch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ config CPU_HAS_PREFETCH
bool
default y

config GENERIC_BUG
def_bool y
depends on BUG

config GENERIC_BUG_RELATIVE_POINTERS
def_bool y
depends on GENERIC_BUG

config GENERIC_CALIBRATE_DELAY
def_bool y

Expand Down
58 changes: 48 additions & 10 deletions arch/loongarch/include/asm/bug.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,59 @@
#ifndef __ASM_BUG_H
#define __ASM_BUG_H

#include <linux/compiler.h>
#include <asm/break.h>
#include <linux/stringify.h>

#ifndef CONFIG_DEBUG_BUGVERBOSE
#define _BUGVERBOSE_LOCATION(file, line)
#else
#define __BUGVERBOSE_LOCATION(file, line) \
.pushsection .rodata.str, "aMS", @progbits, 1; \
10002: .string file; \
.popsection; \
\
.long 10002b - .; \
.short line;
#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
#endif

#ifdef CONFIG_BUG
#ifndef CONFIG_GENERIC_BUG
#define __BUG_ENTRY(flags)
#else
#define __BUG_ENTRY(flags) \
.pushsection __bug_table, "aw"; \
.align 2; \
10000: .long 10001f - .; \
_BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
.short flags; \
.popsection; \
10001:
#endif

#include <asm/break.h>
#define ASM_BUG_FLAGS(flags) \
__BUG_ENTRY(flags) \
break BRK_BUG

static inline void __noreturn BUG(void)
{
__asm__ __volatile__("break %0" : : "i" (BRK_BUG));
unreachable();
}
#define ASM_BUG() ASM_BUG_FLAGS(0)

#define HAVE_ARCH_BUG
#define __BUG_FLAGS(flags) \
asm_inline volatile (__stringify(ASM_BUG_FLAGS(flags)));

#endif
#define __WARN_FLAGS(flags) \
do { \
instrumentation_begin(); \
__BUG_FLAGS(BUGFLAG_WARNING|(flags)); \
instrumentation_end(); \
} while (0)

#define BUG() \
do { \
instrumentation_begin(); \
__BUG_FLAGS(0); \
unreachable(); \
} while (0)

#define HAVE_ARCH_BUG

#include <asm-generic/bug.h>

Expand Down
4 changes: 4 additions & 0 deletions arch/loongarch/kernel/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <asm/addrspace.h>
#include <asm/asm.h>
#include <asm/asmmacro.h>
#include <asm/bug.h>
#include <asm/regdef.h>
#include <asm/loongarch.h>
#include <asm/stackframe.h>
Expand Down Expand Up @@ -85,6 +86,7 @@ SYM_CODE_START(kernel_entry) # kernel entry point
PTR_ADDI sp, sp, -4 * SZREG # init stack pointer

bl start_kernel
ASM_BUG()

SYM_CODE_END(kernel_entry)

Expand Down Expand Up @@ -116,6 +118,8 @@ SYM_CODE_START(smpboot_entry)
ld.d tp, t0, CPU_BOOT_TINFO

bl start_secondary
ASM_BUG()

SYM_CODE_END(smpboot_entry)

#endif /* CONFIG_SMP */
Expand Down
26 changes: 24 additions & 2 deletions arch/loongarch/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,29 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
irqentry_exit(regs, state);
}

#ifdef CONFIG_GENERIC_BUG
int is_valid_bugaddr(unsigned long addr)
{
return 1;
}
#endif /* CONFIG_GENERIC_BUG */

static void bug_handler(struct pt_regs *regs)
{
switch (report_bug(regs->csr_era, regs)) {
case BUG_TRAP_TYPE_BUG:
case BUG_TRAP_TYPE_NONE:
die_if_kernel("Oops - BUG", regs);
force_sig(SIGTRAP);
break;

case BUG_TRAP_TYPE_WARN:
/* Skip the BUG instruction and continue */
regs->csr_era += LOONGARCH_INSN_SIZE;
break;
}
}

asmlinkage void noinstr do_bp(struct pt_regs *regs)
{
bool user = user_mode(regs);
Expand Down Expand Up @@ -427,8 +450,7 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)

switch (bcode) {
case BRK_BUG:
die_if_kernel("Kernel bug detected", regs);
force_sig(SIGTRAP);
bug_handler(regs);
break;
case BRK_DIVZERO:
die_if_kernel("Break instruction in kernel code", regs);
Expand Down

0 comments on commit 2d2c395

Please sign in to comment.