config RWSEM_XCHGADD_ALGORITHM
        def_bool y
 
+config GENERIC_BUG
+       def_bool y
+       depends on BUG
+
+config GENERIC_BUG_RELATIVE_POINTERS
+       def_bool y
+       depends on GENERIC_BUG
+
 config GENERIC_HWEIGHT
        def_bool y
 
 
--- /dev/null
+/*
+ * Copyright (C) 2015  ARM Limited
+ * Author: Dave Martin <Dave.Martin@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ARCH_ARM64_ASM_BUG_H
+#define _ARCH_ARM64_ASM_BUG_H
+
+#include <asm/debug-monitors.h>
+
+#ifdef CONFIG_GENERIC_BUG
+#define HAVE_ARCH_BUG
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
+#define __BUGVERBOSE_LOCATION(file, line)                              \
+               ".pushsection .rodata.str,\"aMS\",@progbits,1\n"        \
+       "2:     .string \"" file "\"\n\t"                               \
+               ".popsection\n\t"                                       \
+                                                                       \
+               ".long 2b - 0b\n\t"                                     \
+               ".short " #line "\n\t"
+#else
+#define _BUGVERBOSE_LOCATION(file, line)
+#endif
+
+#define _BUG_FLAGS(flags) __BUG_FLAGS(flags)
+
+#define __BUG_FLAGS(flags) asm volatile (              \
+               ".pushsection __bug_table,\"a\"\n\t"    \
+               ".align 2\n\t"                          \
+       "0:     .long 1f - 0b\n\t"                      \
+_BUGVERBOSE_LOCATION(__FILE__, __LINE__)               \
+               ".short " #flags "\n\t"                 \
+               ".popsection\n"                         \
+                                                       \
+       "1:     brk %[imm]"                             \
+               :: [imm] "i" (BUG_BRK_IMM)              \
+)
+
+#define BUG() do {                             \
+       _BUG_FLAGS(0);                          \
+       unreachable();                          \
+} while (0)
+
+#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint))
+
+#endif /* ! CONFIG_GENERIC_BUG */
+
+#include <asm-generic/bug.h>
+
+#endif /* ! _ARCH_ARM64_ASM_BUG_H */
 
  * 0x100: for triggering a fault on purpose (reserved)
  * 0x400: for dynamic BRK instruction
  * 0x401: for compile time BRK instruction
+ * 0x800: kernel-mode BUG() and WARN() traps
  */
 #define FAULT_BRK_IMM                  0x100
 #define KGDB_DYN_DBG_BRK_IMM           0x400
 #define KGDB_COMPILED_DBG_BRK_IMM      0x401
+#define BUG_BRK_IMM                    0x800
 
 /*
  * BRK instruction encoding
 
  * 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>
 #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>
        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);
 }
 
        arm64_notify_die("Oops - SP/PC alignment exception", regs, &info, esr);
 }
 
-static struct fault_info debug_fault_info[] = {
+int __init early_brk64(unsigned long addr, unsigned int esr,
+                      struct pt_regs *regs);
+
+/*
+ * __refdata because early_brk64 is __init, but the reference to it is
+ * clobbered at arch_initcall time.
+ * See traps.c and debug-monitors.c:debug_traps_init().
+ */
+static struct fault_info __refdata debug_fault_info[] = {
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware breakpoint"   },
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware single-step"  },
        { do_bad,       SIGTRAP,        TRAP_HWBKPT,    "hardware watchpoint"   },
        { do_bad,       SIGBUS,         0,              "unknown 3"             },
        { do_bad,       SIGTRAP,        TRAP_BRKPT,     "aarch32 BKPT"          },
        { do_bad,       SIGTRAP,        0,              "aarch32 vector catch"  },
-       { do_bad,       SIGTRAP,        TRAP_BRKPT,     "aarch64 BRK"           },
+       { early_brk64,  SIGTRAP,        TRAP_BRKPT,     "aarch64 BRK"           },
        { do_bad,       SIGBUS,         0,              "unknown 7"             },
 };