linux/arch/nios2/kernel/kgdb.c
<<
>>
Prefs
   1/*
   2 * Nios2 KGDB support
   3 *
   4 * Copyright (C) 2015 Altera Corporation
   5 * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
   6 *
   7 * Based on the code posted by Kazuyasu on the Altera Forum at:
   8 * http://www.alteraforum.com/forum/showpost.php?p=77003&postcount=20
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 *
  23 */
  24#include <linux/ptrace.h>
  25#include <linux/kgdb.h>
  26#include <linux/kdebug.h>
  27#include <linux/io.h>
  28
  29static int wait_for_remote_debugger;
  30
  31struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
  32{
  33        { "zero", GDB_SIZEOF_REG, -1 },
  34        { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, r1) },
  35        { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r2) },
  36        { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r3) },
  37        { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r4) },
  38        { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r5) },
  39        { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r6) },
  40        { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r7) },
  41        { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r8) },
  42        { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r9) },
  43        { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10) },
  44        { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11) },
  45        { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12) },
  46        { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13) },
  47        { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14) },
  48        { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15) },
  49        { "r16", GDB_SIZEOF_REG, -1 },
  50        { "r17", GDB_SIZEOF_REG, -1 },
  51        { "r18", GDB_SIZEOF_REG, -1 },
  52        { "r19", GDB_SIZEOF_REG, -1 },
  53        { "r20", GDB_SIZEOF_REG, -1 },
  54        { "r21", GDB_SIZEOF_REG, -1 },
  55        { "r22", GDB_SIZEOF_REG, -1 },
  56        { "r23", GDB_SIZEOF_REG, -1 },
  57        { "et", GDB_SIZEOF_REG, -1 },
  58        { "bt", GDB_SIZEOF_REG, -1 },
  59        { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp) },
  60        { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) },
  61        { "fp", GDB_SIZEOF_REG, offsetof(struct pt_regs, fp) },
  62        { "ea", GDB_SIZEOF_REG, -1 },
  63        { "ba", GDB_SIZEOF_REG, -1 },
  64        { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, ra) },
  65        { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, ea) },
  66        { "status", GDB_SIZEOF_REG, -1 },
  67        { "estatus", GDB_SIZEOF_REG, offsetof(struct pt_regs, estatus) },
  68        { "bstatus", GDB_SIZEOF_REG, -1 },
  69        { "ienable", GDB_SIZEOF_REG, -1 },
  70        { "ipending", GDB_SIZEOF_REG, -1},
  71        { "cpuid", GDB_SIZEOF_REG, -1 },
  72        { "ctl6", GDB_SIZEOF_REG, -1 },
  73        { "exception", GDB_SIZEOF_REG, -1 },
  74        { "pteaddr", GDB_SIZEOF_REG, -1 },
  75        { "tlbacc", GDB_SIZEOF_REG, -1 },
  76        { "tlbmisc", GDB_SIZEOF_REG, -1 },
  77        { "eccinj", GDB_SIZEOF_REG, -1 },
  78        { "badaddr", GDB_SIZEOF_REG, -1 },
  79        { "config", GDB_SIZEOF_REG, -1 },
  80        { "mpubase", GDB_SIZEOF_REG, -1 },
  81        { "mpuacc", GDB_SIZEOF_REG, -1 },
  82};
  83
  84char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
  85{
  86        if (regno >= DBG_MAX_REG_NUM || regno < 0)
  87                return NULL;
  88
  89        if (dbg_reg_def[regno].offset != -1)
  90                memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
  91                       dbg_reg_def[regno].size);
  92        else
  93                memset(mem, 0, dbg_reg_def[regno].size);
  94
  95        return dbg_reg_def[regno].name;
  96}
  97
  98int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
  99{
 100        if (regno >= DBG_MAX_REG_NUM || regno < 0)
 101                return -EINVAL;
 102
 103        if (dbg_reg_def[regno].offset != -1)
 104                memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
 105                       dbg_reg_def[regno].size);
 106
 107        return 0;
 108}
 109
 110void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 111{
 112        memset((char *)gdb_regs, 0, NUMREGBYTES);
 113        gdb_regs[GDB_SP] = p->thread.kregs->sp;
 114        gdb_regs[GDB_PC] = p->thread.kregs->ea;
 115}
 116
 117void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
 118{
 119        regs->ea = pc;
 120}
 121
 122int kgdb_arch_handle_exception(int vector, int signo, int err_code,
 123                                char *remcom_in_buffer, char *remcom_out_buffer,
 124                                struct pt_regs *regs)
 125{
 126        char *ptr;
 127        unsigned long addr;
 128
 129        switch (remcom_in_buffer[0]) {
 130        case 's':
 131        case 'c':
 132                /* handle the optional parameters */
 133                ptr = &remcom_in_buffer[1];
 134                if (kgdb_hex2long(&ptr, &addr))
 135                        regs->ea = addr;
 136
 137                return 0;
 138        }
 139
 140        return -1; /* this means that we do not want to exit from the handler */
 141}
 142
 143asmlinkage void kgdb_breakpoint_c(struct pt_regs *regs)
 144{
 145        /*
 146         * The breakpoint entry code has moved the PC on by 4 bytes, so we must
 147         * move it back.  This could be done on the host but we do it here
 148         */
 149        if (!wait_for_remote_debugger)
 150                regs->ea -= 4;
 151        else    /* pass the first trap 30 code */
 152                wait_for_remote_debugger = 0;
 153
 154        kgdb_handle_exception(30, SIGTRAP, 0, regs);
 155}
 156
 157int kgdb_arch_init(void)
 158{
 159        wait_for_remote_debugger = 1;
 160        return 0;
 161}
 162
 163void kgdb_arch_exit(void)
 164{
 165        /* Nothing to do */
 166}
 167
 168struct kgdb_arch arch_kgdb_ops = {
 169        /* Breakpoint instruction: trap 30 */
 170        .gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 },
 171};
 172