diff options
author | Dave P Martin <Dave.Martin@arm.com> | 2015-07-24 16:37:48 +0100 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2015-07-27 11:08:42 +0100 |
commit | 9fb7410f955f7a62c1f882ca8f9ffd4525907e28 (patch) | |
tree | 1a3da5d5b35c0cff97fea27331cdd25e7bd58c58 /arch/arm64/kernel/traps.c | |
parent | d7a33f4fbd12ca0a32a24cc46c0d02b47f6b54d1 (diff) | |
download | op-kernel-dev-9fb7410f955f7a62c1f882ca8f9ffd4525907e28.zip op-kernel-dev-9fb7410f955f7a62c1f882ca8f9ffd4525907e28.tar.gz |
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.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 1ea920c..824ba5a 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -17,6 +17,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/bug.h> #include <linux/signal.h> #include <linux/personality.h> #include <linux/kallsyms.h> @@ -32,8 +33,10 @@ #include <linux/syscalls.h> #include <asm/atomic.h> +#include <asm/bug.h> #include <asm/debug-monitors.h> #include <asm/esr.h> +#include <asm/insn.h> #include <asm/traps.h> #include <asm/stacktrace.h> #include <asm/exception.h> @@ -466,7 +469,61 @@ void __pgd_error(const char *file, int line, unsigned long val) pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val); } +/* GENERIC_BUG traps */ + +int is_valid_bugaddr(unsigned long addr) +{ + /* + * bug_handler() only called for BRK #BUG_BRK_IMM. + * So the answer is trivial -- any spurious instances with no + * bug table entry will be rejected by report_bug() and passed + * back to the debug-monitors code and handled as a fatal + * unexpected debug exception. + */ + return 1; +} + +static int bug_handler(struct pt_regs *regs, unsigned int esr) +{ + if (user_mode(regs)) + return DBG_HOOK_ERROR; + + switch (report_bug(regs->pc, regs)) { + case BUG_TRAP_TYPE_BUG: + die("Oops - BUG", regs, 0); + break; + + case BUG_TRAP_TYPE_WARN: + break; + + default: + /* unknown/unrecognised bug trap type */ + return DBG_HOOK_ERROR; + } + + /* If thread survives, skip over the BUG instruction and continue: */ + regs->pc += AARCH64_INSN_SIZE; /* skip BRK and resume */ + return DBG_HOOK_HANDLED; +} + +static struct break_hook bug_break_hook = { + .esr_val = 0xf2000000 | BUG_BRK_IMM, + .esr_mask = 0xffffffff, + .fn = bug_handler, +}; + +/* + * Initial handler for AArch64 BRK exceptions + * This handler only used until debug_traps_init(). + */ +int __init early_brk64(unsigned long addr, unsigned int esr, + struct pt_regs *regs) +{ + return bug_handler(regs, esr) != DBG_HOOK_HANDLED; +} + +/* This registration must happen early, before debug_traps_init(). */ void __init trap_init(void) { - return; + register_break_hook(&bug_break_hook); } |