sh: Bring kgdb back from the dead.
This code has suffered quite a bit of bitrot, do some basic tidying to get it to a reasonably functional state again. This gets the basic support and the console working again. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
15700770ef
commit
fa5da2f7bd
|
@ -77,16 +77,17 @@ config 4KSTACKS
|
|||
on the VM subsystem for higher order allocations. This option
|
||||
will also use IRQ stacks to compensate for the reduced stackspace.
|
||||
|
||||
config KGDB
|
||||
config SH_KGDB
|
||||
bool "Include KGDB kernel debugger"
|
||||
select FRAME_POINTER
|
||||
select DEBUG_INFO
|
||||
help
|
||||
Include in-kernel hooks for kgdb, the Linux kernel source level
|
||||
debugger. See <http://kgdb.sourceforge.net/> for more information.
|
||||
Unless you are intending to debug the kernel, say N here.
|
||||
|
||||
menu "KGDB configuration options"
|
||||
depends on KGDB
|
||||
depends on SH_KGDB
|
||||
|
||||
config MORE_COMPILE_OPTIONS
|
||||
bool "Add any additional compile options"
|
||||
|
@ -109,16 +110,14 @@ config KGDB_THREAD
|
|||
|
||||
config SH_KGDB_CONSOLE
|
||||
bool "Console messages through GDB"
|
||||
depends on !SERIAL_SH_SCI_CONSOLE
|
||||
select SERIAL_CORE_CONSOLE
|
||||
default n
|
||||
|
||||
config KGDB_SYSRQ
|
||||
bool "Allow SysRq 'G' to enter KGDB"
|
||||
default y
|
||||
|
||||
config KGDB_KERNEL_ASSERTS
|
||||
bool "Include KGDB kernel assertions"
|
||||
default n
|
||||
|
||||
comment "Serial port setup"
|
||||
|
||||
config KGDB_DEFPORT
|
||||
|
@ -131,7 +130,7 @@ config KGDB_DEFBAUD
|
|||
|
||||
choice
|
||||
prompt "Parity"
|
||||
depends on KGDB
|
||||
depends on SH_KGDB
|
||||
default KGDB_DEFPARITY_N
|
||||
|
||||
config KGDB_DEFPARITY_N
|
||||
|
@ -147,7 +146,7 @@ endchoice
|
|||
|
||||
choice
|
||||
prompt "Data bits"
|
||||
depends on KGDB
|
||||
depends on SH_KGDB
|
||||
default KGDB_DEFBITS_8
|
||||
|
||||
config KGDB_DEFBITS_8
|
||||
|
|
|
@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
|
|||
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding
|
||||
|
||||
cflags-$(CONFIG_SH_DSP) += -Wa,-dsp
|
||||
cflags-$(CONFIG_SH_KGDB) += -g
|
||||
|
||||
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
|
||||
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
|
||||
|
|
|
@ -14,153 +14,6 @@
|
|||
#include <asm/se7751.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
void init_7751se_IRQ(void);
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
#include <asm/kgdb.h>
|
||||
static int kgdb_uart_setup(void);
|
||||
static struct kgdb_sermap kgdb_uart_sermap =
|
||||
{ "ttyS", 0, kgdb_uart_setup, NULL };
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize the board
|
||||
*/
|
||||
static void __init sh7751se_setup(char **cmdline_p)
|
||||
{
|
||||
/* Call init_smsc() replacement to set up SuperIO. */
|
||||
/* XXX: RTC setting comes here */
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
kgdb_register_sermap(&kgdb_uart_sermap);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Currently a hack (e.g. does not interact well w/serial.c, lots of *
|
||||
* hardcoded stuff) but may be useful if SCI/F needs debugging. *
|
||||
* Mostly copied from x86 code (see files asm-i386/kgdb_local.h and *
|
||||
* arch/i386/lib/kgdb_serial.c). *
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
#include <linux/types.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serialP.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#define COM1_PORT 0x3f8 /* Base I/O address */
|
||||
#define COM1_IRQ 4 /* IRQ not used yet */
|
||||
#define COM2_PORT 0x2f8 /* Base I/O address */
|
||||
#define COM2_IRQ 3 /* IRQ not used yet */
|
||||
|
||||
#define SB_CLOCK 1843200 /* Serial baud clock */
|
||||
#define SB_BASE (SB_CLOCK/16)
|
||||
#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
|
||||
|
||||
struct uart_port {
|
||||
int base;
|
||||
};
|
||||
#define UART_NPORTS 2
|
||||
struct uart_port uart_ports[] = {
|
||||
{ COM1_PORT },
|
||||
{ COM2_PORT },
|
||||
};
|
||||
struct uart_port *kgdb_uart_port;
|
||||
|
||||
#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg)
|
||||
#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg)
|
||||
|
||||
/* Basic read/write functions for the UART */
|
||||
#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
|
||||
static int kgdb_uart_getchar(void)
|
||||
{
|
||||
int lsr;
|
||||
int c = -1;
|
||||
|
||||
while (c == -1) {
|
||||
lsr = UART_IN(UART_LSR);
|
||||
if (lsr & UART_LSR_DR)
|
||||
c = UART_IN(UART_RX);
|
||||
if ((lsr & UART_LSR_RXCERR))
|
||||
c = -1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void kgdb_uart_putchar(int c)
|
||||
{
|
||||
while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
|
||||
;
|
||||
UART_OUT(UART_TX, c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize UART to configured/requested values.
|
||||
* (But we don't interrupts yet, or interact w/serial.c)
|
||||
*/
|
||||
static int kgdb_uart_setup(void)
|
||||
{
|
||||
int port;
|
||||
int lcr = 0;
|
||||
int bdiv = 0;
|
||||
|
||||
if (kgdb_portnum >= UART_NPORTS) {
|
||||
KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kgdb_uart_port = &uart_ports[kgdb_portnum];
|
||||
|
||||
/* Init sequence from gdb_hook_interrupt */
|
||||
UART_IN(UART_RX);
|
||||
UART_OUT(UART_IER, 0);
|
||||
|
||||
UART_IN(UART_RX); /* Serial driver comments say */
|
||||
UART_IN(UART_IIR); /* this clears interrupt regs */
|
||||
UART_IN(UART_MSR);
|
||||
|
||||
/* Figure basic LCR values */
|
||||
switch (kgdb_bits) {
|
||||
case '7':
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
default: case '8':
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
switch (kgdb_parity) {
|
||||
case 'O':
|
||||
lcr |= UART_LCR_PARITY;
|
||||
break;
|
||||
case 'E':
|
||||
lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* Figure the baud rate divisor */
|
||||
bdiv = (SB_BASE/kgdb_baud);
|
||||
|
||||
/* Set the baud rate and LCR values */
|
||||
UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
|
||||
UART_OUT(UART_DLL, (bdiv & 0xff));
|
||||
UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
|
||||
UART_OUT(UART_LCR, lcr);
|
||||
|
||||
/* Set the MCR */
|
||||
UART_OUT(UART_MCR, SB_MCR);
|
||||
|
||||
/* Turn off FIFOs for now */
|
||||
UART_OUT(UART_FCR, 0);
|
||||
|
||||
/* Setup complete: initialize function pointers */
|
||||
kgdb_getchar = kgdb_uart_getchar;
|
||||
kgdb_putchar = kgdb_uart_putchar;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SH_KGDB */
|
||||
|
||||
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
static struct resource heartbeat_resources[] = {
|
||||
|
@ -197,7 +50,6 @@ __initcall(se7751_devices_setup);
|
|||
*/
|
||||
struct sh_machine_vector mv_7751se __initmv = {
|
||||
.mv_name = "7751 SolutionEngine",
|
||||
.mv_setup = sh7751se_setup,
|
||||
.mv_nr_irqs = 72,
|
||||
|
||||
.mv_inb = sh7751se_inb,
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
* David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
|
||||
* Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>,
|
||||
* Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
|
||||
*
|
||||
*
|
||||
* This version by Henry Bell <henry.bell@st.com>
|
||||
* Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
|
||||
*
|
||||
* Contains low-level support for remote debug using GDB.
|
||||
*
|
||||
* Contains low-level support for remote debug using GDB.
|
||||
*
|
||||
* To enable debugger support, two things need to happen. A call to
|
||||
* set_debug_traps() is necessary in order to allow any breakpoints
|
||||
|
@ -48,7 +48,7 @@
|
|||
* k kill (Detach GDB)
|
||||
*
|
||||
* d Toggle debug flag
|
||||
* D Detach GDB
|
||||
* D Detach GDB
|
||||
*
|
||||
* Hct Set thread t for operations, OK or ENN
|
||||
* c = 'c' (step, cont), c = 'g' (other
|
||||
|
@ -58,7 +58,7 @@
|
|||
* qfThreadInfo Get list of current threads (first) m<id>
|
||||
* qsThreadInfo " " " " " (subsequent)
|
||||
* qOffsets Get section offsets Text=x;Data=y;Bss=z
|
||||
*
|
||||
*
|
||||
* TXX Find if thread XX is alive OK or ENN
|
||||
* ? What was the last sigval ? SNN (signal NN)
|
||||
* O Output to GDB console
|
||||
|
@ -74,7 +74,7 @@
|
|||
* '$' or '#'. If <data> starts with two characters followed by
|
||||
* ':', then the existing stubs interpret this as a sequence number.
|
||||
*
|
||||
* CSUM1 and CSUM2 are ascii hex representation of an 8-bit
|
||||
* CSUM1 and CSUM2 are ascii hex representation of an 8-bit
|
||||
* checksum of <data>, the most significant nibble is sent first.
|
||||
* the hex digits 0-9,a-f are used.
|
||||
*
|
||||
|
@ -86,8 +86,8 @@
|
|||
* Responses can be run-length encoded to save space. A '*' means that
|
||||
* the next character is an ASCII encoding giving a repeat count which
|
||||
* stands for that many repititions of the character preceding the '*'.
|
||||
* The encoding is n+29, yielding a printable character where n >=3
|
||||
* (which is where RLE starts to win). Don't use an n > 126.
|
||||
* The encoding is n+29, yielding a printable character where n >=3
|
||||
* (which is where RLE starts to win). Don't use an n > 126.
|
||||
*
|
||||
* So "0* " means the same as "0000".
|
||||
*/
|
||||
|
@ -100,12 +100,10 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#ifdef CONFIG_SH_KGDB_CONSOLE
|
||||
#include <linux/console.h>
|
||||
#endif
|
||||
|
||||
#include <linux/sysrq.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
@ -153,7 +151,6 @@ char kgdb_in_gdb_mode;
|
|||
char in_nmi; /* Set during NMI to prevent reentry */
|
||||
int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */
|
||||
int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */
|
||||
int kgdb_halt;
|
||||
|
||||
/* Exposed for user access */
|
||||
struct task_struct *kgdb_current;
|
||||
|
@ -328,7 +325,7 @@ static int hex_to_int(char **ptr, int *int_value)
|
|||
}
|
||||
|
||||
/* Copy the binary array pointed to by buf into mem. Fix $, #,
|
||||
and 0x7d escaped with 0x7d. Return a pointer to the character
|
||||
and 0x7d escaped with 0x7d. Return a pointer to the character
|
||||
after the last byte written. */
|
||||
static char *ebin_to_mem(const char *buf, char *mem, int count)
|
||||
{
|
||||
|
@ -452,7 +449,7 @@ static void get_packet(char *buffer, int buflen)
|
|||
/* Ack successful transfer */
|
||||
put_debug_char('+');
|
||||
|
||||
/* If a sequence char is present, reply
|
||||
/* If a sequence char is present, reply
|
||||
the sequence ID */
|
||||
if (buffer[2] == ':') {
|
||||
put_debug_char(buffer[0]);
|
||||
|
@ -759,7 +756,7 @@ static short *get_step_address(void)
|
|||
return (short *) addr;
|
||||
}
|
||||
|
||||
/* Set up a single-step. Replace the instruction immediately after the
|
||||
/* Set up a single-step. Replace the instruction immediately after the
|
||||
current instruction (i.e. next in the expected flow of control) with a
|
||||
trap instruction, so that returning will cause only a single instruction
|
||||
to be executed. Note that this model is slightly broken for instructions
|
||||
|
@ -1002,10 +999,8 @@ void set_thread_msg(void)
|
|||
char *ptr;
|
||||
|
||||
switch (in_buffer[1]) {
|
||||
|
||||
/* To select which thread for gG etc messages, i.e. supported */
|
||||
/* To select which thread for gG etc messages, i.e. supported */
|
||||
case 'g':
|
||||
|
||||
ptr = &in_buffer[2];
|
||||
hex_to_int(&ptr, &threadid);
|
||||
thread = get_thread(threadid);
|
||||
|
@ -1173,6 +1168,7 @@ static void query_msg(void)
|
|||
}
|
||||
#endif /* CONFIG_KGDB_THREAD */
|
||||
|
||||
#ifdef CONFIG_SH_KGDB_CONSOLE
|
||||
/*
|
||||
* Bring up the ports..
|
||||
*/
|
||||
|
@ -1185,6 +1181,9 @@ static int kgdb_serial_setup(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define kgdb_serial_setup() 0
|
||||
#endif
|
||||
|
||||
/* The command loop, read and act on requests */
|
||||
static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
||||
|
@ -1193,7 +1192,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
|||
|
||||
if (excep_code == NMI_VEC) {
|
||||
#ifndef CONFIG_KGDB_NMI
|
||||
KGDB_PRINTK("Ignoring unexpected NMI?\n");
|
||||
printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
|
||||
return;
|
||||
#else /* CONFIG_KGDB_NMI */
|
||||
if (!kgdb_enabled) {
|
||||
|
@ -1216,10 +1215,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
|||
/* Enter GDB mode (e.g. after detach) */
|
||||
if (!kgdb_in_gdb_mode) {
|
||||
/* Do serial setup, notify user, issue preemptive ack */
|
||||
kgdb_serial_setup();
|
||||
KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
|
||||
(kgdb_porttype ? kgdb_porttype->name : ""),
|
||||
kgdb_portnum, kgdb_baud);
|
||||
printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
|
||||
kgdb_in_gdb_mode = 1;
|
||||
put_debug_char('+');
|
||||
}
|
||||
|
@ -1233,21 +1229,18 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
|||
will later be replaced by its original one. Do NOT do this for
|
||||
trap 0xff, since that indicates a compiled-in breakpoint which
|
||||
will not be replaced (and we would retake the trap forever) */
|
||||
if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
|
||||
if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2)))
|
||||
trap_registers.pc -= 2;
|
||||
}
|
||||
|
||||
/* Undo any stepping we may have done */
|
||||
undo_single_step();
|
||||
|
||||
while (1) {
|
||||
|
||||
out_buffer[0] = 0;
|
||||
get_packet(in_buffer, BUFMAX);
|
||||
|
||||
/* Examine first char of buffer to see what we need to do */
|
||||
switch (in_buffer[0]) {
|
||||
|
||||
case '?': /* Send which signal we've received */
|
||||
send_signal_msg(sigval);
|
||||
break;
|
||||
|
@ -1323,11 +1316,8 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
|
|||
}
|
||||
|
||||
/* There has been an exception, most likely a breakpoint. */
|
||||
asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
static void handle_exception(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
int excep_code, vbr_val;
|
||||
int count;
|
||||
int trapa_value = ctrl_inl(TRA);
|
||||
|
@ -1355,7 +1345,7 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
|
|||
kgdb_trapa_val = trapa_value;
|
||||
|
||||
/* Act on the exception */
|
||||
kgdb_command_loop(excep_code >> 5, trapa_value);
|
||||
kgdb_command_loop(excep_code, trapa_value);
|
||||
|
||||
kgdb_current = NULL;
|
||||
|
||||
|
@ -1373,14 +1363,12 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
|
|||
asm("ldc %0, vbr": :"r"(vbr_val));
|
||||
}
|
||||
|
||||
/* Trigger a breakpoint by function */
|
||||
void breakpoint(void)
|
||||
asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7,
|
||||
struct pt_regs __regs)
|
||||
{
|
||||
if (!kgdb_enabled) {
|
||||
kgdb_enabled = 1;
|
||||
kgdb_init();
|
||||
}
|
||||
BREAKPOINT();
|
||||
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
|
||||
handle_exception(regs);
|
||||
}
|
||||
|
||||
/* Initialise the KGDB data structures and serial configuration */
|
||||
|
@ -1395,24 +1383,16 @@ int kgdb_init(void)
|
|||
kgdb_in_gdb_mode = 0;
|
||||
|
||||
if (kgdb_serial_setup() != 0) {
|
||||
KGDB_PRINTK("serial setup error\n");
|
||||
printk(KERN_NOTICE "KGDB: serial setup error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init ptr to exception handler */
|
||||
kgdb_debug_hook = kgdb_handle_exception;
|
||||
kgdb_debug_hook = handle_exception;
|
||||
kgdb_bus_err_hook = kgdb_handle_bus_error;
|
||||
|
||||
/* Enter kgdb now if requested, or just report init done */
|
||||
if (kgdb_halt) {
|
||||
kgdb_in_gdb_mode = 1;
|
||||
put_debug_char('+');
|
||||
breakpoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
KGDB_PRINTK("stub is initialized.\n");
|
||||
}
|
||||
printk(KERN_NOTICE "KGDB: stub is initialized.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1437,7 +1417,7 @@ static void kgdb_msg_write(const char *s, unsigned count)
|
|||
|
||||
/* Calculate how many this time */
|
||||
wcount = (count > MAXOUT) ? MAXOUT : count;
|
||||
|
||||
|
||||
/* Pack in hex chars */
|
||||
for (i = 0; i < wcount; i++)
|
||||
bufptr = pack_hex_byte(bufptr, s[i]);
|
||||
|
@ -1467,3 +1447,25 @@ void kgdb_console_write(struct console *co, const char *s, unsigned count)
|
|||
kgdb_msg_write(s, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KGDB_SYSRQ
|
||||
static void sysrq_handle_gdb(int key, struct tty_struct *tty)
|
||||
{
|
||||
printk("Entering GDB stub\n");
|
||||
breakpoint();
|
||||
}
|
||||
|
||||
static struct sysrq_key_op sysrq_gdb_op = {
|
||||
.handler = sysrq_handle_gdb,
|
||||
.help_msg = "Gdb",
|
||||
.action_msg = "GDB",
|
||||
};
|
||||
|
||||
static int gdb_register_sysrq(void)
|
||||
{
|
||||
printk("Registering GDB sysrq handler\n");
|
||||
register_sysrq_key('g', &sysrq_gdb_op);
|
||||
return 0;
|
||||
}
|
||||
module_init(gdb_register_sysrq);
|
||||
#endif
|
||||
|
|
|
@ -25,11 +25,8 @@
|
|||
#include <asm/setup.h>
|
||||
#include <asm/clock.h>
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
#include <asm/kgdb.h>
|
||||
static int kgdb_parse_options(char *options);
|
||||
#endif
|
||||
extern void * __rd_start, * __rd_end;
|
||||
|
||||
/*
|
||||
* Machine setup..
|
||||
*/
|
||||
|
@ -499,92 +496,3 @@ struct seq_operations cpuinfo_op = {
|
|||
.show = show_cpuinfo,
|
||||
};
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
/*
|
||||
* Parse command-line kgdb options. By default KGDB is enabled,
|
||||
* entered on error (or other action) using default serial info.
|
||||
* The command-line option can include a serial port specification
|
||||
* and an action to override default or configured behavior.
|
||||
*/
|
||||
struct kgdb_sermap kgdb_sci_sermap =
|
||||
{ "ttySC", 5, kgdb_sci_setup, NULL };
|
||||
|
||||
struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
|
||||
struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
|
||||
|
||||
void kgdb_register_sermap(struct kgdb_sermap *map)
|
||||
{
|
||||
struct kgdb_sermap *last;
|
||||
|
||||
for (last = kgdb_serlist; last->next; last = last->next)
|
||||
;
|
||||
last->next = map;
|
||||
if (!map->namelen) {
|
||||
map->namelen = strlen(map->name);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init kgdb_parse_options(char *options)
|
||||
{
|
||||
char c;
|
||||
int baud;
|
||||
|
||||
/* Check for port spec (or use default) */
|
||||
|
||||
/* Determine port type and instance */
|
||||
if (!memcmp(options, "tty", 3)) {
|
||||
struct kgdb_sermap *map = kgdb_serlist;
|
||||
|
||||
while (map && memcmp(options, map->name, map->namelen))
|
||||
map = map->next;
|
||||
|
||||
if (!map) {
|
||||
KGDB_PRINTK("unknown port spec in %s\n", options);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kgdb_porttype = map;
|
||||
kgdb_serial_setup = map->setup_fn;
|
||||
kgdb_portnum = options[map->namelen] - '0';
|
||||
options += map->namelen + 1;
|
||||
|
||||
options = (*options == ',') ? options+1 : options;
|
||||
|
||||
/* Read optional parameters (baud/parity/bits) */
|
||||
baud = simple_strtoul(options, &options, 10);
|
||||
if (baud != 0) {
|
||||
kgdb_baud = baud;
|
||||
|
||||
c = toupper(*options);
|
||||
if (c == 'E' || c == 'O' || c == 'N') {
|
||||
kgdb_parity = c;
|
||||
options++;
|
||||
}
|
||||
|
||||
c = *options;
|
||||
if (c == '7' || c == '8') {
|
||||
kgdb_bits = c;
|
||||
options++;
|
||||
}
|
||||
options = (*options == ',') ? options+1 : options;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for action specification */
|
||||
if (!memcmp(options, "halt", 4)) {
|
||||
kgdb_halt = 1;
|
||||
options += 4;
|
||||
} else if (!memcmp(options, "disabled", 8)) {
|
||||
kgdb_enabled = 0;
|
||||
options += 8;
|
||||
}
|
||||
|
||||
if (*options) {
|
||||
KGDB_PRINTK("ignored unknown options: %s\n", options);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
__setup("kgdb=", kgdb_parse_options);
|
||||
#endif /* CONFIG_SH_KGDB */
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/sh_bios.h>
|
||||
#include <asm/kgdb.h>
|
||||
|
@ -163,7 +164,7 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
|
|||
usegdb |= sh_bios_in_gdb_mode();
|
||||
#endif
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
|
||||
usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
|
||||
#endif
|
||||
|
||||
if (usegdb) {
|
||||
|
@ -204,7 +205,7 @@ static int kgdb_sci_getchar(void)
|
|||
int c;
|
||||
|
||||
/* Keep trying to read a character, this could be neater */
|
||||
while ((c = get_char(kgdb_sci_port)) < 0)
|
||||
while ((c = get_char(&kgdb_sci_port->port)) < 0)
|
||||
cpu_relax();
|
||||
|
||||
return c;
|
||||
|
@ -212,7 +213,7 @@ static int kgdb_sci_getchar(void)
|
|||
|
||||
static inline void kgdb_sci_putchar(int c)
|
||||
{
|
||||
put_char(kgdb_sci_port, c);
|
||||
put_char(&kgdb_sci_port->port, c);
|
||||
}
|
||||
#endif /* CONFIG_SH_KGDB */
|
||||
|
||||
|
@ -738,7 +739,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
|
|||
|
||||
#ifdef CONFIG_SH_KGDB
|
||||
/* Break into the debugger if a break is detected */
|
||||
BREAKPOINT();
|
||||
breakpoint();
|
||||
#endif
|
||||
|
||||
sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
|
||||
|
@ -971,7 +972,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
{
|
||||
struct sci_port *s = &sci_ports[port->line];
|
||||
unsigned int status, baud, smr_val;
|
||||
unsigned long flags;
|
||||
int t;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
|
||||
|
@ -989,12 +989,10 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
#else
|
||||
t = SCBRR_VALUE(baud);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
do {
|
||||
status = sci_in(port, SCxSR);
|
||||
} while (!(status & SCxSR_TEND(port)));
|
||||
|
@ -1038,8 +1036,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
if ((termios->c_cflag & CREAD) != 0)
|
||||
sci_start_rx(port,0);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *sci_type(struct uart_port *port)
|
||||
|
@ -1220,8 +1216,6 @@ static int __init serial_console_setup(struct console *co, char *options)
|
|||
if (!port->membase || !port->mapbase)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
port->type = serial_console_port->type;
|
||||
|
||||
if (port->flags & UPF_IOREMAP)
|
||||
|
@ -1247,7 +1241,7 @@ static struct console serial_console = {
|
|||
.device = uart_console_device,
|
||||
.write = serial_console_write,
|
||||
.setup = serial_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &sci_uart_driver,
|
||||
};
|
||||
|
@ -1292,11 +1286,23 @@ int __init kgdb_console_setup(struct console *co, char *options)
|
|||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
if (co->index != kgdb_portnum)
|
||||
co->index = kgdb_portnum;
|
||||
|
||||
kgdb_sci_port = &sci_ports[co->index];
|
||||
port = &kgdb_sci_port->port;
|
||||
|
||||
/*
|
||||
* Also need to check port->type, we don't actually have any
|
||||
* UPIO_PORT ports, but uart_report_port() handily misreports
|
||||
* it anyways if we don't have a port available by the time this is
|
||||
* called.
|
||||
*/
|
||||
if (!port->type)
|
||||
return -ENODEV;
|
||||
if (!port->membase || !port->mapbase)
|
||||
return -ENODEV;
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
|
@ -1311,11 +1317,12 @@ int __init kgdb_console_setup(struct console *co, char *options)
|
|||
|
||||
#ifdef CONFIG_SH_KGDB_CONSOLE
|
||||
static struct console kgdb_console = {
|
||||
.name = "ttySC",
|
||||
.write = kgdb_console_write,
|
||||
.setup = kgdb_console_setup,
|
||||
.flags = CON_PRINTBUFFER | CON_ENABLED,
|
||||
.index = -1,
|
||||
.name = "ttySC",
|
||||
.device = uart_console_device,
|
||||
.write = kgdb_console_write,
|
||||
.setup = kgdb_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &sci_uart_driver,
|
||||
};
|
||||
|
||||
|
@ -1386,6 +1393,12 @@ static int __devinit sci_probe(struct platform_device *dev)
|
|||
uart_add_one_port(&sci_uart_driver, &sciport->port);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
|
||||
kgdb_sci_port = &sci_ports[kgdb_portnum];
|
||||
kgdb_getchar = kgdb_sci_getchar;
|
||||
kgdb_putchar = kgdb_sci_putchar;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
|
||||
dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define __KGDB_H
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
struct console;
|
||||
|
||||
|
@ -45,35 +46,21 @@ extern int kgdb_portnum;
|
|||
extern int kgdb_baud;
|
||||
extern char kgdb_parity;
|
||||
extern char kgdb_bits;
|
||||
extern int kgdb_console_setup(struct console *, char *);
|
||||
|
||||
/* Init and interface stuff */
|
||||
extern int kgdb_init(void);
|
||||
extern int (*kgdb_serial_setup)(void);
|
||||
extern int (*kgdb_getchar)(void);
|
||||
extern void (*kgdb_putchar)(int);
|
||||
|
||||
struct kgdb_sermap {
|
||||
char *name;
|
||||
int namelen;
|
||||
int (*setup_fn)(struct console *, char *);
|
||||
struct kgdb_sermap *next;
|
||||
};
|
||||
extern void kgdb_register_sermap(struct kgdb_sermap *map);
|
||||
extern struct kgdb_sermap *kgdb_porttype;
|
||||
|
||||
/* Trap functions */
|
||||
typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
|
||||
typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
|
||||
typedef void (kgdb_bus_error_hook_t)(void);
|
||||
extern kgdb_debug_hook_t *kgdb_debug_hook;
|
||||
extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
|
||||
|
||||
extern void breakpoint(void);
|
||||
|
||||
/* Console */
|
||||
struct console;
|
||||
void kgdb_console_write(struct console *co, const char *s, unsigned count);
|
||||
void kgdb_console_init(void);
|
||||
extern int kgdb_console_setup(struct console *, char *);
|
||||
|
||||
/* Prototypes for jmp fns */
|
||||
#define _JBLEN 9
|
||||
|
@ -81,11 +68,8 @@ typedef int jmp_buf[_JBLEN];
|
|||
extern void longjmp(jmp_buf __jmpb, int __retval);
|
||||
extern int setjmp(jmp_buf __jmpb);
|
||||
|
||||
/* Variadic macro to print our own message to the console */
|
||||
#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
|
||||
|
||||
/* Forced breakpoint */
|
||||
#define BREAKPOINT() \
|
||||
#define breakpoint() \
|
||||
do { \
|
||||
if (kgdb_enabled) \
|
||||
__asm__ __volatile__("trapa #0x3c"); \
|
||||
|
@ -95,7 +79,6 @@ do { \
|
|||
#if defined(CONFIG_CPU_SH4)
|
||||
#define kgdb_flush_icache_range(start, end) \
|
||||
{ \
|
||||
extern void __flush_purge_region(void *, int); \
|
||||
__flush_purge_region((void*)(start), (int)(end) - (int)(start));\
|
||||
flush_icache_range((start), (end)); \
|
||||
}
|
||||
|
@ -103,31 +86,6 @@ do { \
|
|||
#define kgdb_flush_icache_range(start, end) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Kernel assert macros */
|
||||
#ifdef CONFIG_KGDB_KERNEL_ASSERTS
|
||||
|
||||
/* Predefined conditions */
|
||||
#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
|
||||
#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
|
||||
#define KA_VALID_KPTR(ptr) (!(ptr) || \
|
||||
((void *)(ptr) >= (void *)PAGE_OFFSET && \
|
||||
(void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
|
||||
#define KA_VALID_PTRORERR(errptr) \
|
||||
(KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
|
||||
#define KA_HELD_GKL() (current->lock_depth >= 0)
|
||||
|
||||
/* The actual assert */
|
||||
#define KGDB_ASSERT(condition, message) do { \
|
||||
if (!(condition) && (kgdb_enabled)) { \
|
||||
KGDB_PRINTK("Assertion failed at %s:%d: %s\n", \
|
||||
__FILE__, __LINE__, message);\
|
||||
BREAKPOINT(); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define KGDB_ASSERT(condition, message)
|
||||
#endif
|
||||
|
||||
/* Taken from sh-stub.c of GDB 4.18 */
|
||||
static const char hexchars[] = "0123456789abcdef";
|
||||
|
||||
|
@ -142,5 +100,4 @@ static inline char lowhex(const int x)
|
|||
{
|
||||
return hexchars[x & 0xf];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -65,6 +65,8 @@
|
|||
|
||||
#define IRQ_79C973 13
|
||||
|
||||
void init_7751se_IRQ(void);
|
||||
|
||||
#define __IO_PREFIX sh7751se
|
||||
#include <asm/io_generic.h>
|
||||
|
||||
|
|
Loading…
Reference in New Issue