/*
* arch/mips/kernel/gdb-stub.c
*
* Originally written by Glenn Engel, Lake Stevens Instrument Division
*
* Contributed by HP Systems
*
* Modified for SPARC by Stu Grossman, Cygnus Support.
*
* Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
* Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
*
* Copyright (C) 1995 Andreas Busse
*
* Copyright (C) 2003 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*/
/*
* To enable debugger support, two things need to happen. One, a
* call to set_debug_traps() is necessary in order to allow any breakpoints
* or error conditions to be properly intercepted and reported to gdb.
* Two, a breakpoint needs to be generated to begin communication. This
* is most easily accomplished by a call to breakpoint(). Breakpoint()
* simulates a breakpoint by executing a BREAK instruction.
*
*
* The following gdb commands are supported:
*
* command function Return value
*
* g return the value of the CPU registers hex data or ENN
* G set the value of the CPU registers OK or ENN
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
*
* c Resume at current address SNN ( signal NN)
* cAA..AA Continue at address AA..AA SNN
*
* s Step one instruction SNN
* sAA..AA Step one instruction from AA..AA SNN
*
* k kill
*
* ? What was the last sigval ? SNN (signal NN)
*
* bBB..BB Set baud rate to BB..BB OK or BNN, then sets
* baud rate
*
* All commands and responses are sent with a packet which includes a
* checksum. A packet consists of
*
* $<packet info>#<checksum>.
*
* where
* <packet info> :: <characters representing the command or response>
* <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
*
* When a packet is received, it is first acknowledged with either '+' or '-'.
* '+' indicates a successful transfer. '-' indicates a failed transfer.
*
* Example:
*
* Host: Reply:
* $m0,10#2a +$00010203040506070809101112131415#42
*
*
* ==============
* MORE EXAMPLES:
* ==============
*
* For reference -- the following are the steps that one
* company took (RidgeRun Inc) to get remote gdb debugging
* going. In this scenario the host machine was a PC and the
* target platform was a Galileo EVB64120A MIPS evaluation
* board.
*
* Step 1:
* First download gdb-5.0.tar.gz from the internet.
* and then build/install the package.
*
* Example:
* $ tar zxf gdb-5.0.tar.gz
* $ cd gdb-5.0
* $ ./configure --target=mips-linux-elf
* $ make
* $ install
* $ which mips-linux-elf-gdb
* /usr/local/bin/mips-linux-elf-gdb
*
* Step 2:
* Configure linux for remote debugging and build it.
*
* Example:
* $ cd ~/linux
* $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
* $ make
*
* Step 3:
* Download the kernel to the remote target and start
* the kernel running. It will promptly halt and wait
* for the host gdb session to connect. It does this
* since the "Kernel Hacking" option has defined
* CONFIG_KGDB which in turn enables your calls
* to:
* set_debug_traps();
* breakpoint();
*
* Step 4:
* Start the gdb session on the host.
*
* Example:
* $ mips-linux-elf-gdb vmlinux
* (gdb) set remotebaud 115200
* (gdb) target remote /dev/ttyS1
* ...at this point you are connected to
* the remote target and can use gdb
* in the normal fasion. Setting
* breakpoints, single stepping,
* printing variables, etc.
*/
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/reboot.h>
#include <asm/asm.h>
#include <asm/cacheflush.h>
#include <asm/mipsregs.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/gdb-stub.h>
#include <asm/inst.h>
#include <asm/smp.h>
/*
* external low-level support routines
*/
extern int putDebugChar(char c); /* write a single character */
extern char getDebugChar(void); /* read and return a single char */
extern void trap_low(void);
/*
* breakpoint and test functions
*/
extern void breakpoint(void);
extern void breakinst(void);
extern void async_breakpoint(void);
extern void async_breakinst(void);
extern void adel(void);
/*
* local prototypes
*/
static void getpacket(char *buffer);
static void putpacket(char *buffer);
static int computeSignal(int tt);
static int hex(unsigned char ch);
static int hexToInt(char **ptr, int *intValue);
static int hexToLong(char **ptr, long *longValue);
static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
void handle_exception(struct gdb_regs *regs);
int kgdb_enabled;
/*
* spin locks for smp case
*/
static DEFINE_SPINLOCK(kgdb_lock);
static raw_spinlock_t kgdb_cpulock[NR_CPUS] = {
[0 ... NR_CPUS-1] = __RAW_SPIN_LOCK_UNLOCKED,
};
/*
* BUFMAX defines the maximum number of characters in inbound/outbound buffers
* at least NUMREGBYTES*2 are needed for register packets
*/
#define BUFMAX 2048
static char input_buffer[BUFMAX];
static char output_buffer[BUFMAX];
static int initialized; /* !0 means we've been initialized */
static int kgdb_started;
static const char hexchars[]="0123456789abcdef";
/* Used to prevent crashes in memory access. Note that they'll crash anyway if
we haven't set up fault handlers yet... */
int kgdb_read_byte(unsigned char *address,