linux/arch/arm64/kernel/kgdb.c
<<
>>
Prefs
   1/*
   2 * AArch64 KGDB support
   3 *
   4 * Based on arch/arm/kernel/kgdb.c
   5 *
   6 * Copyright (C) 2013 Cavium Inc.
   7 * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include <linux/irq.h>
  23#include <linux/kdebug.h>
  24#include <linux/kgdb.h>
  25#include <asm/traps.h>
  26
  27struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
  28        { "x0", 8, offsetof(struct pt_regs, regs[0])},
  29        { "x1", 8, offsetof(struct pt_regs, regs[1])},
  30        { "x2", 8, offsetof(struct pt_regs, regs[2])},
  31        { "x3", 8, offsetof(struct pt_regs, regs[3])},
  32        { "x4", 8, offsetof(struct pt_regs, regs[4])},
  33        { "x5", 8, offsetof(struct pt_regs, regs[5])},
  34        { "x6", 8, offsetof(struct pt_regs, regs[6])},
  35        { "x7", 8, offsetof(struct pt_regs, regs[7])},
  36        { "x8", 8, offsetof(struct pt_regs, regs[8])},
  37        { "x9", 8, offsetof(struct pt_regs, regs[9])},
  38        { "x10", 8, offsetof(struct pt_regs, regs[10])},
  39        { "x11", 8, offsetof(struct pt_regs, regs[11])},
  40        { "x12", 8, offsetof(struct pt_regs, regs[12])},
  41        { "x13", 8, offsetof(struct pt_regs, regs[13])},
  42        { "x14", 8, offsetof(struct pt_regs, regs[14])},
  43        { "x15", 8, offsetof(struct pt_regs, regs[15])},
  44        { "x16", 8, offsetof(struct pt_regs, regs[16])},
  45        { "x17", 8, offsetof(struct pt_regs, regs[17])},
  46        { "x18", 8, offsetof(struct pt_regs, regs[18])},
  47        { "x19", 8, offsetof(struct pt_regs, regs[19])},
  48        { "x20", 8, offsetof(struct pt_regs, regs[20])},
  49        { "x21", 8, offsetof(struct pt_regs, regs[21])},
  50        { "x22", 8, offsetof(struct pt_regs, regs[22])},
  51        { "x23", 8, offsetof(struct pt_regs, regs[23])},
  52        { "x24", 8, offsetof(struct pt_regs, regs[24])},
  53        { "x25", 8, offsetof(struct pt_regs, regs[25])},
  54        { "x26", 8, offsetof(struct pt_regs, regs[26])},
  55        { "x27", 8, offsetof(struct pt_regs, regs[27])},
  56        { "x28", 8, offsetof(struct pt_regs, regs[28])},
  57        { "x29", 8, offsetof(struct pt_regs, regs[29])},
  58        { "x30", 8, offsetof(struct pt_regs, regs[30])},
  59        { "sp", 8, offsetof(struct pt_regs, sp)},
  60        { "pc", 8, offsetof(struct pt_regs, pc)},
  61        { "pstate", 8, offsetof(struct pt_regs, pstate)},
  62        { "v0", 16, -1 },
  63        { "v1", 16, -1 },
  64        { "v2", 16, -1 },
  65        { "v3", 16, -1 },
  66        { "v4", 16, -1 },
  67        { "v5", 16, -1 },
  68        { "v6", 16, -1 },
  69        { "v7", 16, -1 },
  70        { "v8", 16, -1 },
  71        { "v9", 16, -1 },
  72        { "v10", 16, -1 },
  73        { "v11", 16, -1 },
  74        { "v12", 16, -1 },
  75        { "v13", 16, -1 },
  76        { "v14", 16, -1 },
  77        { "v15", 16, -1 },
  78        { "v16", 16, -1 },
  79        { "v17", 16, -1 },
  80        { "v18", 16, -1 },
  81        { "v19", 16, -1 },
  82        { "v20", 16, -1 },
  83        { "v21", 16, -1 },
  84        { "v22", 16, -1 },
  85        { "v23", 16, -1 },
  86        { "v24", 16, -1 },
  87        { "v25", 16, -1 },
  88        { "v26", 16, -1 },
  89        { "v27", 16, -1 },
  90        { "v28", 16, -1 },
  91        { "v29", 16, -1 },
  92        { "v30", 16, -1 },
  93        { "v31", 16, -1 },
  94        { "fpsr", 4, -1 },
  95        { "fpcr", 4, -1 },
  96};
  97
  98char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
  99{
 100        if (regno >= DBG_MAX_REG_NUM || regno < 0)
 101                return NULL;
 102
 103        if (dbg_reg_def[regno].offset != -1)
 104                memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
 105                       dbg_reg_def[regno].size);
 106        else
 107                memset(mem, 0, dbg_reg_def[regno].size);
 108        return dbg_reg_def[regno].name;
 109}
 110
 111int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
 112{
 113        if (regno >= DBG_MAX_REG_NUM || regno < 0)
 114                return -EINVAL;
 115
 116        if (dbg_reg_def[regno].offset != -1)
 117                memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
 118                       dbg_reg_def[regno].size);
 119        return 0;
 120}
 121
 122void
 123sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
 124{
 125        struct pt_regs *thread_regs;
 126
 127        /* Initialize to zero */
 128        memset((char *)gdb_regs, 0, NUMREGBYTES);
 129        thread_regs = task_pt_regs(task);
 130        memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES);
 131}
 132
 133void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
 134{
 135        regs->pc = pc;
 136}
 137
 138static int compiled_break;
 139
 140static void kgdb_arch_update_addr(struct pt_regs *regs,
 141                                char *remcom_in_buffer)
 142{
 143        unsigned long addr;
 144        char *ptr;
 145
 146        ptr = &remcom_in_buffer[1];
 147        if (kgdb_hex2long(&ptr, &addr))
 148                kgdb_arch_set_pc(regs, addr);
 149        else if (compiled_break == 1)
 150                kgdb_arch_set_pc(regs, regs->pc + 4);
 151
 152        compiled_break = 0;
 153}
 154
 155int kgdb_arch_handle_exception(int exception_vector, int signo,
 156                               int err_code, char *remcom_in_buffer,
 157                               char *remcom_out_buffer,
 158                               struct pt_regs *linux_regs)
 159{
 160        int err;
 161
 162        switch (remcom_in_buffer[0]) {
 163        case 'D':
 164        case 'k':
 165                /*
 166                 * Packet D (Detach), k (kill). No special handling
 167                 * is required here. Handle same as c packet.
 168                 */
 169        case 'c':
 170                /*
 171                 * Packet c (Continue) to continue executing.
 172                 * Set pc to required address.
 173                 * Try to read optional parameter and set pc.
 174                 * If this was a compiled breakpoint, we need to move
 175                 * to the next instruction else we will just breakpoint
 176                 * over and over again.
 177                 */
 178                kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
 179                atomic_set(&kgdb_cpu_doing_single_step, -1);
 180                kgdb_single_step =  0;
 181
 182                /*
 183                 * Received continue command, disable single step
 184                 */
 185                if (kernel_active_single_step())
 186                        kernel_disable_single_step();
 187
 188                err = 0;
 189                break;
 190        case 's':
 191                /*
 192                 * Update step address value with address passed
 193                 * with step packet.
 194                 * On debug exception return PC is copied to ELR
 195                 * So just update PC.
 196                 * If no step address is passed, resume from the address
 197                 * pointed by PC. Do not update PC
 198                 */
 199                kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
 200                atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
 201                kgdb_single_step =  1;
 202
 203                /*
 204                 * Enable single step handling
 205                 */
 206                if (!kernel_active_single_step())
 207                        kernel_enable_single_step(linux_regs);
 208                err = 0;
 209                break;
 210        default:
 211                err = -1;
 212        }
 213        return err;
 214}
 215
 216static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
 217{
 218        kgdb_handle_exception(1, SIGTRAP, 0, regs);
 219        return 0;
 220}
 221
 222static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
 223{
 224        compiled_break = 1;
 225        kgdb_handle_exception(1, SIGTRAP, 0, regs);
 226
 227        return 0;
 228}
 229
 230static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 231{
 232        kgdb_handle_exception(1, SIGTRAP, 0, regs);
 233        return 0;
 234}
 235
 236static struct break_hook kgdb_brkpt_hook = {
 237        .esr_mask       = 0xffffffff,
 238        .esr_val        = (u32)ESR_ELx_VAL_BRK64(KGDB_DYN_DBG_BRK_IMM),
 239        .fn             = kgdb_brk_fn
 240};
 241
 242static struct break_hook kgdb_compiled_brkpt_hook = {
 243        .esr_mask       = 0xffffffff,
 244        .esr_val        = (u32)ESR_ELx_VAL_BRK64(KGDB_COMPILED_DBG_BRK_IMM),
 245        .fn             = kgdb_compiled_brk_fn
 246};
 247
 248static struct step_hook kgdb_step_hook = {
 249        .fn             = kgdb_step_brk_fn
 250};
 251
 252static void kgdb_call_nmi_hook(void *ignored)
 253{
 254        kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 255}
 256
 257void kgdb_roundup_cpus(unsigned long flags)
 258{
 259        local_irq_enable();
 260        smp_call_function(kgdb_call_nmi_hook, NULL, 0);
 261        local_irq_disable();
 262}
 263
 264static int __kgdb_notify(struct die_args *args, unsigned long cmd)
 265{
 266        struct pt_regs *regs = args->regs;
 267
 268        if (kgdb_handle_exception(1, args->signr, cmd, regs))
 269                return NOTIFY_DONE;
 270        return NOTIFY_STOP;
 271}
 272
 273static int
 274kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
 275{
 276        unsigned long flags;
 277        int ret;
 278
 279        local_irq_save(flags);
 280        ret = __kgdb_notify(ptr, cmd);
 281        local_irq_restore(flags);
 282
 283        return ret;
 284}
 285
 286static struct notifier_block kgdb_notifier = {
 287        .notifier_call  = kgdb_notify,
 288        /*
 289         * Want to be lowest priority
 290         */
 291        .priority       = -INT_MAX,
 292};
 293
 294/*
 295 * kgdb_arch_init - Perform any architecture specific initialization.
 296 * This function will handle the initialization of any architecture
 297 * specific callbacks.
 298 */
 299int kgdb_arch_init(void)
 300{
 301        int ret = register_die_notifier(&kgdb_notifier);
 302
 303        if (ret != 0)
 304                return ret;
 305
 306        register_break_hook(&kgdb_brkpt_hook);
 307        register_break_hook(&kgdb_compiled_brkpt_hook);
 308        register_step_hook(&kgdb_step_hook);
 309        return 0;
 310}
 311
 312/*
 313 * kgdb_arch_exit - Perform any architecture specific uninitalization.
 314 * This function will handle the uninitalization of any architecture
 315 * specific callbacks, for dynamic registration and unregistration.
 316 */
 317void kgdb_arch_exit(void)
 318{
 319        unregister_break_hook(&kgdb_brkpt_hook);
 320        unregister_break_hook(&kgdb_compiled_brkpt_hook);
 321        unregister_step_hook(&kgdb_step_hook);
 322        unregister_die_notifier(&kgdb_notifier);
 323}
 324
 325/*
 326 * ARM instructions are always in LE.
 327 * Break instruction is encoded in LE format
 328 */
 329struct kgdb_arch arch_kgdb_ops = {
 330        .gdb_bpt_instr = {
 331                KGDB_DYN_BRK_INS_BYTE(0),
 332                KGDB_DYN_BRK_INS_BYTE(1),
 333                KGDB_DYN_BRK_INS_BYTE(2),
 334                KGDB_DYN_BRK_INS_BYTE(3),
 335        }
 336};
 337