linux/arch/arc/kernel/kgdb.c
<<
>>
Prefs
   1/*
   2 * kgdb support for ARC
   3 *
   4 * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/kgdb.h>
  12#include <linux/sched.h>
  13#include <linux/sched/task_stack.h>
  14#include <asm/disasm.h>
  15#include <asm/cacheflush.h>
  16
  17static void to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
  18                        struct callee_regs *cregs)
  19{
  20        int regno;
  21
  22        for (regno = 0; regno <= 26; regno++)
  23                gdb_regs[_R0 + regno] = get_reg(regno, kernel_regs, cregs);
  24
  25        for (regno = 27; regno < GDB_MAX_REGS; regno++)
  26                gdb_regs[regno] = 0;
  27
  28        gdb_regs[_FP]           = kernel_regs->fp;
  29        gdb_regs[__SP]          = kernel_regs->sp;
  30        gdb_regs[_BLINK]        = kernel_regs->blink;
  31        gdb_regs[_RET]          = kernel_regs->ret;
  32        gdb_regs[_STATUS32]     = kernel_regs->status32;
  33        gdb_regs[_LP_COUNT]     = kernel_regs->lp_count;
  34        gdb_regs[_LP_END]       = kernel_regs->lp_end;
  35        gdb_regs[_LP_START]     = kernel_regs->lp_start;
  36        gdb_regs[_BTA]          = kernel_regs->bta;
  37        gdb_regs[_STOP_PC]      = kernel_regs->ret;
  38}
  39
  40static void from_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
  41                        struct callee_regs *cregs)
  42{
  43        int regno;
  44
  45        for (regno = 0; regno <= 26; regno++)
  46                set_reg(regno, gdb_regs[regno + _R0], kernel_regs, cregs);
  47
  48        kernel_regs->fp         = gdb_regs[_FP];
  49        kernel_regs->sp         = gdb_regs[__SP];
  50        kernel_regs->blink      = gdb_regs[_BLINK];
  51        kernel_regs->ret        = gdb_regs[_RET];
  52        kernel_regs->status32   = gdb_regs[_STATUS32];
  53        kernel_regs->lp_count   = gdb_regs[_LP_COUNT];
  54        kernel_regs->lp_end     = gdb_regs[_LP_END];
  55        kernel_regs->lp_start   = gdb_regs[_LP_START];
  56        kernel_regs->bta        = gdb_regs[_BTA];
  57}
  58
  59
  60void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
  61{
  62        to_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  63                current->thread.callee_reg);
  64}
  65
  66void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
  67{
  68        from_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  69                current->thread.callee_reg);
  70}
  71
  72void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
  73                                 struct task_struct *task)
  74{
  75        if (task)
  76                to_gdb_regs(gdb_regs, task_pt_regs(task),
  77                        (struct callee_regs *) task->thread.callee_reg);
  78}
  79
  80struct single_step_data_t {
  81        uint16_t opcode[2];
  82        unsigned long address[2];
  83        int is_branch;
  84        int armed;
  85} single_step_data;
  86
  87static void undo_single_step(struct pt_regs *regs)
  88{
  89        if (single_step_data.armed) {
  90                int i;
  91
  92                for (i = 0; i < (single_step_data.is_branch ? 2 : 1); i++) {
  93                        memcpy((void *) single_step_data.address[i],
  94                                &single_step_data.opcode[i],
  95                                BREAK_INSTR_SIZE);
  96
  97                        flush_icache_range(single_step_data.address[i],
  98                                single_step_data.address[i] +
  99                                BREAK_INSTR_SIZE);
 100                }
 101                single_step_data.armed = 0;
 102        }
 103}
 104
 105static void place_trap(unsigned long address, void *save)
 106{
 107        memcpy(save, (void *) address, BREAK_INSTR_SIZE);
 108        memcpy((void *) address, &arch_kgdb_ops.gdb_bpt_instr,
 109                BREAK_INSTR_SIZE);
 110        flush_icache_range(address, address + BREAK_INSTR_SIZE);
 111}
 112
 113static void do_single_step(struct pt_regs *regs)
 114{
 115        single_step_data.is_branch = disasm_next_pc((unsigned long)
 116                regs->ret, regs, (struct callee_regs *)
 117                current->thread.callee_reg,
 118                &single_step_data.address[0],
 119                &single_step_data.address[1]);
 120
 121        place_trap(single_step_data.address[0], &single_step_data.opcode[0]);
 122
 123        if (single_step_data.is_branch) {
 124                place_trap(single_step_data.address[1],
 125                        &single_step_data.opcode[1]);
 126        }
 127
 128        single_step_data.armed++;
 129}
 130
 131int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
 132                               char *remcomInBuffer, char *remcomOutBuffer,
 133                               struct pt_regs *regs)
 134{
 135        unsigned long addr;
 136        char *ptr;
 137
 138        undo_single_step(regs);
 139
 140        switch (remcomInBuffer[0]) {
 141        case 's':
 142        case 'c':
 143                ptr = &remcomInBuffer[1];
 144                if (kgdb_hex2long(&ptr, &addr))
 145                        regs->ret = addr;
 146
 147        case 'D':
 148        case 'k':
 149                atomic_set(&kgdb_cpu_doing_single_step, -1);
 150
 151                if (remcomInBuffer[0] == 's') {
 152                        do_single_step(regs);
 153                        atomic_set(&kgdb_cpu_doing_single_step,
 154                                   smp_processor_id());
 155                }
 156
 157                return 0;
 158        }
 159        return -1;
 160}
 161
 162int kgdb_arch_init(void)
 163{
 164        single_step_data.armed = 0;
 165        return 0;
 166}
 167
 168void kgdb_trap(struct pt_regs *regs)
 169{
 170        /* trap_s 3 is used for breakpoints that overwrite existing
 171         * instructions, while trap_s 4 is used for compiled breakpoints.
 172         *
 173         * with trap_s 3 breakpoints the original instruction needs to be
 174         * restored and continuation needs to start at the location of the
 175         * breakpoint.
 176         *
 177         * with trap_s 4 (compiled) breakpoints, continuation needs to
 178         * start after the breakpoint.
 179         */
 180        if (regs->ecr_param == 3)
 181                instruction_pointer(regs) -= BREAK_INSTR_SIZE;
 182
 183        kgdb_handle_exception(1, SIGTRAP, 0, regs);
 184}
 185
 186void kgdb_arch_exit(void)
 187{
 188}
 189
 190void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 191{
 192        instruction_pointer(regs) = ip;
 193}
 194
 195static void kgdb_call_nmi_hook(void *ignored)
 196{
 197        kgdb_nmicallback(raw_smp_processor_id(), NULL);
 198}
 199
 200void kgdb_roundup_cpus(unsigned long flags)
 201{
 202        local_irq_enable();
 203        smp_call_function(kgdb_call_nmi_hook, NULL, 0);
 204        local_irq_disable();
 205}
 206
 207struct kgdb_arch arch_kgdb_ops = {
 208        /* breakpoint instruction: TRAP_S 0x3 */
 209#ifdef CONFIG_CPU_BIG_ENDIAN
 210        .gdb_bpt_instr          = {0x78, 0x7e},
 211#else
 212        .gdb_bpt_instr          = {0x7e, 0x78},
 213#endif
 214};
 215