Blackfin: kgdb: punt dead code
[safe/jmp/linux-2.6] / arch / blackfin / kernel / kgdb.c
index a1f9641..f1036b6 100644 (file)
@@ -1,32 +1,9 @@
 /*
- * File:         arch/blackfin/kernel/kgdb.c
- * Based on:
- * Author:       Sonic Zhang
+ * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces
  *
- * Created:
- * Description:
+ * Copyright 2005-2008 Analog Devices Inc.
  *
- * Rev:          $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
- *
- * Modified:
- *               Copyright 2005-2006 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/string.h>
 #include <linux/kgdb.h>
 #include <linux/console.h>
 #include <linux/init.h>
-#include <linux/debugger.h>
 #include <linux/errno.h>
 #include <linux/irq.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/blackfin.h>
+#include <asm/dma.h>
 
-/* Put the error code here just in case the user cares.  */
-int gdb_bf533errcode;
-/* Likewise, the vector number here (since GDB only gets the signal
-   number through the usual means, and that's not very specific).  */
-int gdb_bf533vector = -1;
-
-#if KGDB_MAX_NO_CPUS != 8
-#error change the definition of slavecpulocks
-#endif
-
-void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
        gdb_regs[BFIN_R0] = regs->r0;
        gdb_regs[BFIN_R1] = regs->r1;
@@ -123,7 +91,7 @@ void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
  * Extracts ebp, esp and eip values understandable by gdb from the values
  * saved by switch_to.
  * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
- * prior to entering switch_to is 8 greater then the value that is saved.
+ * prior to entering switch_to is 8 greater than the value that is saved.
  * If switch_to changes, change following code appropriately.
  */
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
@@ -133,7 +101,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
        gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
 }
 
-void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
        regs->r0 = gdb_regs[BFIN_R0];
        regs->r1 = gdb_regs[BFIN_R1];
@@ -199,177 +167,206 @@ struct hw_breakpoint {
        unsigned int dataacc:2;
        unsigned short count;
        unsigned int addr;
-} breakinfo[HW_BREAKPOINT_NUM];
+} breakinfo[HW_WATCHPOINT_NUM];
 
-int kgdb_arch_init(void)
-{
-       debugger_step = 0;
-
-       kgdb_remove_all_hw_break();
-       return 0;
-}
-
-int kgdb_set_hw_break(unsigned long addr)
+int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-               if (!breakinfo[breakno].occupied) {
+       int bfin_type;
+       int dataacc = 0;
+
+       switch (type) {
+       case BP_HARDWARE_BREAKPOINT:
+               bfin_type = TYPE_INST_WATCHPOINT;
+               break;
+       case BP_WRITE_WATCHPOINT:
+               dataacc = 1;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       case BP_READ_WATCHPOINT:
+               dataacc = 2;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       case BP_ACCESS_WATCHPOINT:
+               dataacc = 3;
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       default:
+               return -ENOSPC;
+       }
+
+       /* Becasue hardware data watchpoint impelemented in current
+        * Blackfin can not trigger an exception event as the hardware
+        * instrction watchpoint does, we ignaore all data watch point here.
+        * They can be turned on easily after future blackfin design
+        * supports this feature.
+        */
+       for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+               if (bfin_type == breakinfo[breakno].type
+                       && !breakinfo[breakno].occupied) {
                        breakinfo[breakno].occupied = 1;
+                       breakinfo[breakno].skip = 0;
                        breakinfo[breakno].enabled = 1;
-                       breakinfo[breakno].type = 1;
                        breakinfo[breakno].addr = addr;
+                       breakinfo[breakno].dataacc = dataacc;
+                       breakinfo[breakno].count = 0;
                        return 0;
                }
 
        return -ENOSPC;
 }
 
-int kgdb_remove_hw_break(unsigned long addr)
+int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type)
 {
        int breakno;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
-               if (breakinfo[breakno].addr == addr)
-                       memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
+       int bfin_type;
+
+       switch (type) {
+       case BP_HARDWARE_BREAKPOINT:
+               bfin_type = TYPE_INST_WATCHPOINT;
+               break;
+       case BP_WRITE_WATCHPOINT:
+       case BP_READ_WATCHPOINT:
+       case BP_ACCESS_WATCHPOINT:
+               bfin_type = TYPE_DATA_WATCHPOINT;
+               break;
+       default:
+               return 0;
+       }
+       for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+               if (bfin_type == breakinfo[breakno].type
+                       && breakinfo[breakno].occupied
+                       && breakinfo[breakno].addr == addr) {
+                       breakinfo[breakno].occupied = 0;
+                       breakinfo[breakno].enabled = 0;
+               }
 
        return 0;
 }
 
-void kgdb_remove_all_hw_break(void)
+void bfin_remove_all_hw_break(void)
 {
-       memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
-}
+       int breakno;
 
-/*
-void kgdb_show_info(void)
-{
-       printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
-               bfin_read_WPIA0(), bfin_read_WPIACNT0(),
-               bfin_read_WPIACTL(), bfin_read_WPSTAT());
+       memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM);
+
+       for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++)
+               breakinfo[breakno].type = TYPE_INST_WATCHPOINT;
+       for (; breakno < HW_WATCHPOINT_NUM; breakno++)
+               breakinfo[breakno].type = TYPE_DATA_WATCHPOINT;
 }
-*/
 
-void kgdb_correct_hw_break(void)
+void bfin_correct_hw_break(void)
 {
        int breakno;
-       int correctit;
-       uint32_t wpdactl = bfin_read_WPDACTL();
+       unsigned int wpiactl = 0;
+       unsigned int wpdactl = 0;
+       int enable_wp = 0;
+
+       for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++)
+               if (breakinfo[breakno].enabled) {
+                       enable_wp = 1;
 
-       correctit = 0;
-       for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
-               if (breakinfo[breakno].type == 1) {
                        switch (breakno) {
                        case 0:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN01|EMUSW0);
-                                       wpdactl |= WPIAEN0|WPICNTEN0;
-                                       bfin_write_WPIA0(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT0(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN0;
-                               }
+                               wpiactl |= WPIAEN0|WPICNTEN0;
+                               bfin_write_WPIA0(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT0(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 1:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN01|EMUSW1);
-                                       wpdactl |= WPIAEN1|WPICNTEN1;
-                                       bfin_write_WPIA1(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT1(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN1;
-                               }
+                               wpiactl |= WPIAEN1|WPICNTEN1;
+                               bfin_write_WPIA1(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT1(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 2:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN23|EMUSW2);
-                                       wpdactl |= WPIAEN2|WPICNTEN2;
-                                       bfin_write_WPIA2(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT2(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN2;
-                               }
+                               wpiactl |= WPIAEN2|WPICNTEN2;
+                               bfin_write_WPIA2(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT2(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
-
                        case 3:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN23|EMUSW3);
-                                       wpdactl |= WPIAEN3|WPICNTEN3;
-                                       bfin_write_WPIA3(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT3(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN3;
-                               }
+                               wpiactl |= WPIAEN3|WPICNTEN3;
+                               bfin_write_WPIA3(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT3(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        case 4:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN45|EMUSW4);
-                                       wpdactl |= WPIAEN4|WPICNTEN4;
-                                       bfin_write_WPIA4(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT4(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN4;
-                               }
+                               wpiactl |= WPIAEN4|WPICNTEN4;
+                               bfin_write_WPIA4(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT4(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        case 5:
-                               if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
-                                       correctit = 1;
-                                       wpdactl &= ~(WPIREN45|EMUSW5);
-                                       wpdactl |= WPIAEN5|WPICNTEN5;
-                                       bfin_write_WPIA5(breakinfo[breakno].addr);
-                                       bfin_write_WPIACNT5(breakinfo[breakno].skip);
-                               } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
-                                       correctit = 1;
-                                       wpdactl &= ~WPIAEN5;
-                               }
+                               wpiactl |= WPIAEN5|WPICNTEN5;
+                               bfin_write_WPIA5(breakinfo[breakno].addr);
+                               bfin_write_WPIACNT5(breakinfo[breakno].count
+                                       + breakinfo->skip);
+                               break;
+                       case 6:
+                               wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0;
+                               wpdactl |= breakinfo[breakno].dataacc
+                                       << WPDACC0_OFFSET;
+                               bfin_write_WPDA0(breakinfo[breakno].addr);
+                               bfin_write_WPDACNT0(breakinfo[breakno].count
+                                       + breakinfo->skip);
+                               break;
+                       case 7:
+                               wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1;
+                               wpdactl |= breakinfo[breakno].dataacc
+                                       << WPDACC1_OFFSET;
+                               bfin_write_WPDA1(breakinfo[breakno].addr);
+                               bfin_write_WPDACNT1(breakinfo[breakno].count
+                                       + breakinfo->skip);
                                break;
                        }
                }
-       }
-       if (correctit) {
-               wpdactl &= ~WPAND;
-               wpdactl |= WPPWR;
-               /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
+
+       /* Should enable WPPWR bit first before set any other
+        * WPIACTL and WPDACTL bits */
+       if (enable_wp) {
+               bfin_write_WPIACTL(WPPWR);
+               CSYNC();
+               bfin_write_WPIACTL(wpiactl|WPPWR);
                bfin_write_WPDACTL(wpdactl);
                CSYNC();
-               /*kgdb_show_info();*/
        }
 }
 
 void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
        /* Disable hardware debugging while we are in kgdb */
-       bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
+       bfin_write_WPIACTL(0);
+       bfin_write_WPDACTL(0);
        CSYNC();
 }
 
-void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+#ifdef CONFIG_SMP
+void kgdb_passive_cpu_callback(void *info)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
 {
-       /* Master processor is completely in the debugger */
-       gdb_bf533vector = eVector;
-       gdb_bf533errcode = err_code;
+       smp_call_function(kgdb_passive_cpu_callback, NULL, 0);
 }
 
-int kgdb_arch_handle_exception(int exceptionVector, int signo,
+void kgdb_roundup_cpu(int cpu, unsigned long flags)
+{
+       smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0);
+}
+#endif
+
+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)
+                              struct pt_regs *regs)
 {
        long addr;
-       long breakno;
        char *ptr;
        int newPC;
-       int wp_status;
        int i;
 
        switch (remcom_in_buffer[0]) {
@@ -385,44 +382,29 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
                /* try to read optional parameter, pc unchanged if no parm */
                ptr = &remcom_in_buffer[1];
                if (kgdb_hex2long(&ptr, &addr)) {
-                       linux_regs->retx = addr;
+                       regs->retx = addr;
                }
-               newPC = linux_regs->retx;
+               newPC = regs->retx;
 
                /* clear the trace bit */
-               linux_regs->syscfg &= 0xfffffffe;
+               regs->syscfg &= 0xfffffffe;
 
                /* set the trace bit if we're stepping */
                if (remcom_in_buffer[0] == 's') {
-                       linux_regs->syscfg |= 0x1;
-                       debugger_step = linux_regs->ipend;
-                       debugger_step >>= 6;
-                       for (i = 10; i > 0; i--, debugger_step >>= 1)
-                               if (debugger_step & 1)
+                       regs->syscfg |= 0x1;
+                       kgdb_single_step = regs->ipend;
+                       kgdb_single_step >>= 6;
+                       for (i = 10; i > 0; i--, kgdb_single_step >>= 1)
+                               if (kgdb_single_step & 1)
                                        break;
                        /* i indicate event priority of current stopped instruction
                         * user space instruction is 0, IVG15 is 1, IVTMR is 10.
-                        * debugger_step > 0 means in single step mode
+                        * kgdb_single_step > 0 means in single step mode
                         */
-                       debugger_step = i + 1;
-               } else {
-                       debugger_step = 0;
+                       kgdb_single_step = i + 1;
                }
 
-               wp_status = bfin_read_WPSTAT();
-               CSYNC();
-
-               if (exceptionVector == VEC_WATCH) {
-                       for (breakno = 0; breakno < 6; ++breakno) {
-                               if (wp_status & (1 << breakno)) {
-                                       breakinfo->skip = 1;
-                                       break;
-                               }
-                       }
-               }
-               kgdb_correct_hw_break();
-
-               bfin_write_WPSTAT(0);
+               bfin_correct_hw_break();
 
                return 0;
        }                       /* switch */
@@ -431,5 +413,245 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo,
 
 struct kgdb_arch arch_kgdb_ops = {
        .gdb_bpt_instr = {0xa1},
+#ifdef CONFIG_SMP
+       .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP,
+#else
        .flags = KGDB_HW_BREAKPOINT,
+#endif
+       .set_hw_breakpoint = bfin_set_hw_break,
+       .remove_hw_breakpoint = bfin_remove_hw_break,
+       .remove_all_hw_break = bfin_remove_all_hw_break,
+       .correct_hw_break = bfin_correct_hw_break,
 };
+
+static int hex(char ch)
+{
+       if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       if ((ch >= 'A') && (ch <= 'F'))
+               return ch - 'A' + 10;
+       return -1;
+}
+
+static int validate_memory_access_address(unsigned long addr, int size)
+{
+       if (size < 0 || addr == 0)
+               return -EFAULT;
+       return bfin_mem_access_type(addr, size);
+}
+
+static int bfin_probe_kernel_read(char *dst, char *src, int size)
+{
+       unsigned long lsrc = (unsigned long)src;
+       int mem_type;
+
+       mem_type = validate_memory_access_address(lsrc, size);
+       if (mem_type < 0)
+               return mem_type;
+
+       if (lsrc >= SYSMMR_BASE) {
+               if (size == 2 && lsrc % 2 == 0) {
+                       u16 mmr = bfin_read16(src);
+                       memcpy(dst, &mmr, sizeof(mmr));
+                       return 0;
+               } else if (size == 4 && lsrc % 4 == 0) {
+                       u32 mmr = bfin_read32(src);
+                       memcpy(dst, &mmr, sizeof(mmr));
+                       return 0;
+               }
+       } else {
+               switch (mem_type) {
+                       case BFIN_MEM_ACCESS_CORE:
+                       case BFIN_MEM_ACCESS_CORE_ONLY:
+                               return probe_kernel_read(dst, src, size);
+                       /* XXX: should support IDMA here with SMP */
+                       case BFIN_MEM_ACCESS_DMA:
+                               if (dma_memcpy(dst, src, size))
+                                       return 0;
+                               break;
+                       case BFIN_MEM_ACCESS_ITEST:
+                               if (isram_memcpy(dst, src, size))
+                                       return 0;
+                               break;
+               }
+       }
+
+       return -EFAULT;
+}
+
+static int bfin_probe_kernel_write(char *dst, char *src, int size)
+{
+       unsigned long ldst = (unsigned long)dst;
+       int mem_type;
+
+       mem_type = validate_memory_access_address(ldst, size);
+       if (mem_type < 0)
+               return mem_type;
+
+       if (ldst >= SYSMMR_BASE) {
+               if (size == 2 && ldst % 2 == 0) {
+                       u16 mmr;
+                       memcpy(&mmr, src, sizeof(mmr));
+                       bfin_write16(dst, mmr);
+                       return 0;
+               } else if (size == 4 && ldst % 4 == 0) {
+                       u32 mmr;
+                       memcpy(&mmr, src, sizeof(mmr));
+                       bfin_write32(dst, mmr);
+                       return 0;
+               }
+       } else {
+               switch (mem_type) {
+                       case BFIN_MEM_ACCESS_CORE:
+                       case BFIN_MEM_ACCESS_CORE_ONLY:
+                               return probe_kernel_write(dst, src, size);
+                       /* XXX: should support IDMA here with SMP */
+                       case BFIN_MEM_ACCESS_DMA:
+                               if (dma_memcpy(dst, src, size))
+                                       return 0;
+                               break;
+                       case BFIN_MEM_ACCESS_ITEST:
+                               if (isram_memcpy(dst, src, size))
+                                       return 0;
+                               break;
+               }
+       }
+
+       return -EFAULT;
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null). May return an error.
+ */
+int kgdb_mem2hex(char *mem, char *buf, int count)
+{
+       char *tmp;
+       int err;
+
+       /*
+        * We use the upper half of buf as an intermediate buffer for the
+        * raw memory copy.  Hex conversion will work against this one.
+        */
+       tmp = buf + count;
+
+       err = bfin_probe_kernel_read(tmp, mem, count);
+       if (!err) {
+               while (count > 0) {
+                       buf = pack_hex_byte(buf, *tmp);
+                       tmp++;
+                       count--;
+               }
+
+               *buf = 0;
+       }
+
+       return err;
+}
+
+/*
+ * Copy the binary array pointed to by buf into mem.  Fix $, #, and
+ * 0x7d escaped with 0x7d.  Return a pointer to the character after
+ * the last byte written.
+ */
+int kgdb_ebin2mem(char *buf, char *mem, int count)
+{
+       char *tmp_old, *tmp_new;
+       int size;
+
+       tmp_old = tmp_new = buf;
+
+       for (size = 0; size < count; ++size) {
+               if (*tmp_old == 0x7d)
+                       *tmp_new = *(++tmp_old) ^ 0x20;
+               else
+                       *tmp_new = *tmp_old;
+               tmp_new++;
+               tmp_old++;
+       }
+
+       return bfin_probe_kernel_write(mem, buf, count);
+}
+
+/*
+ * Convert the hex array pointed to by buf into binary to be placed in mem.
+ * Return a pointer to the character AFTER the last byte written.
+ * May return an error.
+ */
+int kgdb_hex2mem(char *buf, char *mem, int count)
+{
+       char *tmp_raw, *tmp_hex;
+
+       /*
+        * We use the upper half of buf as an intermediate buffer for the
+        * raw memory that is converted from hex.
+        */
+       tmp_raw = buf + count * 2;
+
+       tmp_hex = tmp_raw - 1;
+       while (tmp_hex >= buf) {
+               tmp_raw--;
+               *tmp_raw = hex(*tmp_hex--);
+               *tmp_raw |= hex(*tmp_hex--) << 4;
+       }
+
+       return bfin_probe_kernel_write(mem, tmp_raw, count);
+}
+
+#define IN_MEM(addr, size, l1_addr, l1_size) \
+({ \
+       unsigned long __addr = (unsigned long)(addr); \
+       (l1_size && __addr >= l1_addr && __addr + (size) <= l1_addr + l1_size); \
+})
+#define ASYNC_BANK_SIZE \
+       (ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
+        ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE)
+
+int kgdb_validate_break_address(unsigned long addr)
+{
+       int cpu = raw_smp_processor_id();
+
+       if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end)
+               return 0;
+       if (IN_MEM(addr, BREAK_INSTR_SIZE, ASYNC_BANK0_BASE, ASYNC_BANK_SIZE))
+               return 0;
+       if (cpu == 0 && IN_MEM(addr, BREAK_INSTR_SIZE, L1_CODE_START, L1_CODE_LENGTH))
+               return 0;
+#ifdef CONFIG_SMP
+       else if (cpu == 1 && IN_MEM(addr, BREAK_INSTR_SIZE, COREB_L1_CODE_START, L1_CODE_LENGTH))
+               return 0;
+#endif
+       if (IN_MEM(addr, BREAK_INSTR_SIZE, L2_START, L2_LENGTH))
+               return 0;
+
+       return -EFAULT;
+}
+
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+       int err = bfin_probe_kernel_read(saved_instr, (char *)addr,
+                                        BREAK_INSTR_SIZE);
+       if (err)
+               return err;
+       return bfin_probe_kernel_write((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
+                                      BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+       return bfin_probe_kernel_write((char *)addr, bundle, BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_init(void)
+{
+       kgdb_single_step = 0;
+
+       bfin_remove_all_hw_break();
+       return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}