aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/traps.c
diff options
context:
space:
mode:
authorDave P Martin <Dave.Martin@arm.com>2015-07-24 11:37:48 -0400
committerWill Deacon <will.deacon@arm.com>2015-07-27 06:08:42 -0400
commit9fb7410f955f7a62c1f882ca8f9ffd4525907e28 (patch)
tree1a3da5d5b35c0cff97fea27331cdd25e7bd58c58 /arch/arm64/kernel/traps.c
parentd7a33f4fbd12ca0a32a24cc46c0d02b47f6b54d1 (diff)
arm64/BUG: Use BRK instruction for generic BUG traps
Currently, the minimal default BUG() implementation from asm- generic is used for arm64. This patch uses the BRK 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 offsets instead of absolute pointers. (Note that this limits the kernel size to 2GB.) Traps are registered at arch_initcall time for aarch64, but BUG has minimal real dependencies and it is desirable to be able to generate bug splats as early as possible. This patch redirects all debug exceptions caused by BRK directly to bug_handler() until the full debug exception support has been initialised. Signed-off-by: Dave Martin <Dave.Martin@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r--arch/arm64/kernel/traps.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 1ea920cbd66d..824ba5ac6361 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -17,6 +17,7 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20#include <linux/bug.h>
20#include <linux/signal.h> 21#include <linux/signal.h>
21#include <linux/personality.h> 22#include <linux/personality.h>
22#include <linux/kallsyms.h> 23#include <linux/kallsyms.h>
@@ -32,8 +33,10 @@
32#include <linux/syscalls.h> 33#include <linux/syscalls.h>
33 34
34#include <asm/atomic.h> 35#include <asm/atomic.h>
36#include <asm/bug.h>
35#include <asm/debug-monitors.h> 37#include <asm/debug-monitors.h>
36#include <asm/esr.h> 38#include <asm/esr.h>
39#include <asm/insn.h>
37#include <asm/traps.h> 40#include <asm/traps.h>
38#include <asm/stacktrace.h> 41#include <asm/stacktrace.h>
39#include <asm/exception.h> 42#include <asm/exception.h>
@@ -466,7 +469,61 @@ void __pgd_error(const char *file, int line, unsigned long val)
466 pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val); 469 pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
467} 470}
468 471
472/* GENERIC_BUG traps */
473
474int is_valid_bugaddr(unsigned long addr)
475{
476 /*
477 * bug_handler() only called for BRK #BUG_BRK_IMM.
478 * So the answer is trivial -- any spurious instances with no
479 * bug table entry will be rejected by report_bug() and passed
480 * back to the debug-monitors code and handled as a fatal
481 * unexpected debug exception.
482 */
483 return 1;
484}
485
486static int bug_handler(struct pt_regs *regs, unsigned int esr)
487{
488 if (user_mode(regs))
489 return DBG_HOOK_ERROR;
490
491 switch (report_bug(regs->pc, regs)) {
492 case BUG_TRAP_TYPE_BUG:
493 die("Oops - BUG", regs, 0);
494 break;
495
496 case BUG_TRAP_TYPE_WARN:
497 break;
498
499 default:
500 /* unknown/unrecognised bug trap type */
501 return DBG_HOOK_ERROR;
502 }
503
504 /* If thread survives, skip over the BUG instruction and continue: */
505 regs->pc += AARCH64_INSN_SIZE; /* skip BRK and resume */
506 return DBG_HOOK_HANDLED;
507}
508
509static struct break_hook bug_break_hook = {
510 .esr_val = 0xf2000000 | BUG_BRK_IMM,
511 .esr_mask = 0xffffffff,
512 .fn = bug_handler,
513};
514
515/*
516 * Initial handler for AArch64 BRK exceptions
517 * This handler only used until debug_traps_init().
518 */
519int __init early_brk64(unsigned long addr, unsigned int esr,
520 struct pt_regs *regs)
521{
522 return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
523}
524
525/* This registration must happen early, before debug_traps_init(). */
469void __init trap_init(void) 526void __init trap_init(void)
470{ 527{
471 return; 528 register_break_hook(&bug_break_hook);
472} 529}