lkml.org 
[lkml]   [2011]   [Aug]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch v2 31/35] Hexagon: kgdb support files
    Signed-off-by: Linas Vepstas <linas@codeaurora.org>

    ---
    arch/hexagon/include/asm/kgdb.h | 39 ++++++
    arch/hexagon/kernel/kgdb.c | 241 ++++++++++++++++++++++++++++++++++++++++
    2 files changed, 280 insertions(+)

    Index: linux-hexagon-kernel/arch/hexagon/include/asm/kgdb.h
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-hexagon-kernel/arch/hexagon/include/asm/kgdb.h 2011-08-25 19:24:03.628025356 -0500
    @@ -0,0 +1,39 @@
    +/*
    + * arch/hexagon/include/asm/kgdb.h - Hexagon KGDB Support
    + *
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only 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, write to the Free Software
    + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    + * 02110-1301, USA.
    + */
    +
    +#ifndef __HEXAGON_KGDB_H__
    +#define __HEXAGON_KGDB_H__
    +
    +#define BREAK_INSTR_SIZE 4
    +#define CACHE_FLUSH_IS_SAFE 1
    +#define BUFMAX ((NUMREGBYTES * 2) + 512)
    +
    +static inline void arch_kgdb_breakpoint(void)
    +{
    + asm("trap0(#0xDB)");
    +}
    +
    +/* Registers:
    + * 32 gpr + sa0/1 + lc0/1 + m0/1 + gp + ugp + pred + pc = 42 total.
    + */
    +#define NUMREGBYTES (42*4)
    +#define DBG_MAX_REG_NUM 42
    +
    +#endif /* __HEXAGON_KGDB_H__ */
    Index: linux-hexagon-kernel/arch/hexagon/kernel/kgdb.c
    ===================================================================
    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-hexagon-kernel/arch/hexagon/kernel/kgdb.c 2011-08-27 20:20:07.085494269 -0500
    @@ -0,0 +1,241 @@
    +/*
    + * arch/hexagon/kernel/kgdb.c - Hexagon KGDB Support
    + *
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only 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, write to the Free Software
    + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    + * 02110-1301, USA.
    + */
    +
    +#include <linux/kdebug.h>
    +#include <linux/kgdb.h>
    +
    +/* All registers are 4 bytes, for now */
    +#define GDB_SIZEOF_REG 4
    +
    +/* The register names are used during printing of the regs;
    + * Keep these at three letters to pretty-print. */
    +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
    + { " r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, r00)},
    + { " r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, r01)},
    + { " r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r02)},
    + { " r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r03)},
    + { " r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r04)},
    + { " r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r05)},
    + { " r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r06)},
    + { " r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r07)},
    + { " r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r08)},
    + { " r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r09)},
    + { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10)},
    + { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11)},
    + { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12)},
    + { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13)},
    + { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14)},
    + { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15)},
    + { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, r16)},
    + { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, r17)},
    + { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, r18)},
    + { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, r19)},
    + { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, r20)},
    + { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, r21)},
    + { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, r22)},
    + { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, r23)},
    + { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, r24)},
    + { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, r25)},
    + { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, r26)},
    + { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, r27)},
    + { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, r28)},
    + { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, r29)},
    + { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, r30)},
    + { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, r31)},
    +
    + { "usr", GDB_SIZEOF_REG, offsetof(struct pt_regs, usr)},
    + { "preds", GDB_SIZEOF_REG, offsetof(struct pt_regs, preds)},
    + { " m0", GDB_SIZEOF_REG, offsetof(struct pt_regs, m0)},
    + { " m1", GDB_SIZEOF_REG, offsetof(struct pt_regs, m1)},
    + { "sa0", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa0)},
    + { "sa1", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa1)},
    + { "lc0", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc0)},
    + { "lc1", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc1)},
    + { " gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)},
    + { "ugp", GDB_SIZEOF_REG, offsetof(struct pt_regs, ugp)},
    +};
    +
    +struct kgdb_arch arch_kgdb_ops = {
    + /* trap0(#0xDB) 0x0cdb0054 */
    + .gdb_bpt_instr = {0x54, 0x00, 0xdb, 0x0c},
    +};
    +
    +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
    +{
    + if (regno >= DBG_MAX_REG_NUM || regno < 0)
    + return NULL;
    +
    + *((unsigned long *) mem) = *((unsigned long *) ((void *)regs +
    + dbg_reg_def[regno].offset));
    +
    + return dbg_reg_def[regno].name;
    +}
    +
    +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
    +{
    + if (regno >= DBG_MAX_REG_NUM || regno < 0)
    + return -EINVAL;
    +
    + *((unsigned long *) ((void *)regs + dbg_reg_def[regno].offset)) =
    + *((unsigned long *) mem);
    +
    + return 0;
    +}
    +
    +void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
    +{
    + instruction_pointer(regs) = pc;
    +}
    +
    +#ifdef CONFIG_SMP
    +
    +/**
    + * kgdb_roundup_cpus - Get other CPUs into a holding pattern
    + * @flags: Current IRQ state
    + *
    + * On SMP systems, we need to get the attention of the other CPUs
    + * and get them be in a known state. This should do what is needed
    + * to get the other CPUs to call kgdb_wait(). Note that on some arches,
    + * the NMI approach is not used for rounding up all the CPUs. For example,
    + * in case of MIPS, smp_call_function() is used to roundup CPUs. In
    + * this case, we have to make sure that interrupts are enabled before
    + * calling smp_call_function(). The argument to this function is
    + * the flags that will be used when restoring the interrupts. There is
    + * local_irq_save() call before kgdb_roundup_cpus().
    + *
    + * On non-SMP systems, this is not called.
    + */
    +
    +static void hexagon_kgdb_nmi_hook(void *ignored)
    +{
    + kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
    +}
    +
    +void kgdb_roundup_cpus(unsigned long flags)
    +{
    + smp_call_function(hexagon_kgdb_nmi_hook, NULL, 0);
    +}
    +#endif
    +
    +
    +/* Not yet working */
    +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
    + struct task_struct *task)
    +{
    + struct pt_regs *thread_regs;
    +
    + if (task == NULL)
    + return;
    +
    + /* Initialize to zero */
    + memset(gdb_regs, 0, NUMREGBYTES);
    +
    + /* Otherwise, we have only some registers from switch_to() */
    + thread_regs = task_pt_regs(task);
    + gdb_regs[0] = thread_regs->r00;
    +}
    +
    +/**
    + * kgdb_arch_handle_exception - Handle architecture specific GDB packets.
    + * @vector: The error vector of the exception that happened.
    + * @signo: The signal number of the exception that happened.
    + * @err_code: The error code of the exception that happened.
    + * @remcom_in_buffer: The buffer of the packet we have read.
    + * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into.
    + * @regs: The &struct pt_regs of the current process.
    + *
    + * This function MUST handle the 'c' and 's' command packets,
    + * as well packets to set / remove a hardware breakpoint, if used.
    + * If there are additional packets which the hardware needs to handle,
    + * they are handled here. The code should return -1 if it wants to
    + * process more packets, and a %0 or %1 if it wants to exit from the
    + * kgdb callback.
    + *
    + * Not yet working.
    + */
    +int kgdb_arch_handle_exception(int vector, int signo, int err_code,
    + char *remcom_in_buffer, char *remcom_out_buffer,
    + struct pt_regs *linux_regs)
    +{
    + switch (remcom_in_buffer[0]) {
    + case 's':
    + case 'c':
    + return 0;
    + }
    + /* Stay in the debugger. */
    + return -1;
    +}
    +
    +static int __kgdb_notify(struct die_args *args, unsigned long cmd)
    +{
    + struct pt_regs *regs = args->regs;
    +#if 0
    + ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr, args->err,
    + regs);
    + if (ret)
    + return NOTIFY_DONE;
    +#endif
    + return NOTIFY_STOP;
    +}
    +
    +static int
    +kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
    +{
    + unsigned long flags;
    + int ret;
    +
    + local_irq_save(flags);
    + ret = __kgdb_notify(ptr, cmd);
    + local_irq_restore(flags);
    +
    + return ret;
    +}
    +
    +static struct notifier_block kgdb_notifier = {
    + .notifier_call = kgdb_notify,
    +
    + /*
    + * Lowest-prio notifier priority, we want to be notified last:
    + */
    + .priority = -INT_MAX,
    +};
    +
    +/**
    + * kgdb_arch_init - Perform any architecture specific initalization.
    + *
    + * This function will handle the initalization of any architecture
    + * specific callbacks.
    + */
    +int kgdb_arch_init(void)
    +{
    + return register_die_notifier(&kgdb_notifier);
    +}
    +
    +/**
    + * kgdb_arch_exit - Perform any architecture specific uninitalization.
    + *
    + * This function will handle the uninitalization of any architecture
    + * specific callbacks, for dynamic registration and unregistration.
    + */
    +void kgdb_arch_exit(void)
    +{
    + unregister_die_notifier(&kgdb_notifier);
    +}
    +
    --

    Sent by an employee of the Qualcomm Innovation Center, Inc.
    The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.



    \
     
     \ /
      Last update: 2011-08-30 21:35    [W:0.050 / U:60.940 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site