Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: kgdb: kgdboc console poll hooks for mpsc uart kgdb: kgdboc console poll hooks for cpm uart kgdb, powerpc: arch specific powerpc kgdb support kgdb: support for ARCH=arm kgdb: remove unused HAVE_ARCH_KGDB_SHADOW_INFO config variable
This commit is contained in:
commit
0f6e38a638
|
@ -12,6 +12,7 @@ config ARM
|
|||
select RTC_LIB
|
||||
select SYS_SUPPORTS_APM_EMULATION
|
||||
select HAVE_OPROFILE
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_KPROBES if (!XIP_KERNEL)
|
||||
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||
select HAVE_FTRACE if (!XIP_KERNEL)
|
||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
|
|||
obj-$(CONFIG_ATAGS_PROC) += atags.o
|
||||
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
|
||||
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
|
||||
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
|
||||
AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* arch/arm/kernel/kgdb.c
|
||||
*
|
||||
* ARM KGDB support
|
||||
*
|
||||
* Copyright (c) 2002-2004 MontaVista Software, Inc
|
||||
* Copyright (c) 2008 Wind River Systems, Inc.
|
||||
*
|
||||
* Authors: George Davis <davis_g@mvista.com>
|
||||
* Deepak Saxena <dsaxena@plexity.net>
|
||||
*/
|
||||
#include <linux/kgdb.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
/* Make a local copy of the registers passed into the handler (bletch) */
|
||||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
|
||||
{
|
||||
int regno;
|
||||
|
||||
/* Initialize all to zero. */
|
||||
for (regno = 0; regno < GDB_MAX_REGS; regno++)
|
||||
gdb_regs[regno] = 0;
|
||||
|
||||
gdb_regs[_R0] = kernel_regs->ARM_r0;
|
||||
gdb_regs[_R1] = kernel_regs->ARM_r1;
|
||||
gdb_regs[_R2] = kernel_regs->ARM_r2;
|
||||
gdb_regs[_R3] = kernel_regs->ARM_r3;
|
||||
gdb_regs[_R4] = kernel_regs->ARM_r4;
|
||||
gdb_regs[_R5] = kernel_regs->ARM_r5;
|
||||
gdb_regs[_R6] = kernel_regs->ARM_r6;
|
||||
gdb_regs[_R7] = kernel_regs->ARM_r7;
|
||||
gdb_regs[_R8] = kernel_regs->ARM_r8;
|
||||
gdb_regs[_R9] = kernel_regs->ARM_r9;
|
||||
gdb_regs[_R10] = kernel_regs->ARM_r10;
|
||||
gdb_regs[_FP] = kernel_regs->ARM_fp;
|
||||
gdb_regs[_IP] = kernel_regs->ARM_ip;
|
||||
gdb_regs[_SPT] = kernel_regs->ARM_sp;
|
||||
gdb_regs[_LR] = kernel_regs->ARM_lr;
|
||||
gdb_regs[_PC] = kernel_regs->ARM_pc;
|
||||
gdb_regs[_CPSR] = kernel_regs->ARM_cpsr;
|
||||
}
|
||||
|
||||
/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
|
||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
|
||||
{
|
||||
kernel_regs->ARM_r0 = gdb_regs[_R0];
|
||||
kernel_regs->ARM_r1 = gdb_regs[_R1];
|
||||
kernel_regs->ARM_r2 = gdb_regs[_R2];
|
||||
kernel_regs->ARM_r3 = gdb_regs[_R3];
|
||||
kernel_regs->ARM_r4 = gdb_regs[_R4];
|
||||
kernel_regs->ARM_r5 = gdb_regs[_R5];
|
||||
kernel_regs->ARM_r6 = gdb_regs[_R6];
|
||||
kernel_regs->ARM_r7 = gdb_regs[_R7];
|
||||
kernel_regs->ARM_r8 = gdb_regs[_R8];
|
||||
kernel_regs->ARM_r9 = gdb_regs[_R9];
|
||||
kernel_regs->ARM_r10 = gdb_regs[_R10];
|
||||
kernel_regs->ARM_fp = gdb_regs[_FP];
|
||||
kernel_regs->ARM_ip = gdb_regs[_IP];
|
||||
kernel_regs->ARM_sp = gdb_regs[_SPT];
|
||||
kernel_regs->ARM_lr = gdb_regs[_LR];
|
||||
kernel_regs->ARM_pc = gdb_regs[_PC];
|
||||
kernel_regs->ARM_cpsr = gdb_regs[_CPSR];
|
||||
}
|
||||
|
||||
void
|
||||
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
|
||||
{
|
||||
struct pt_regs *thread_regs;
|
||||
int regno;
|
||||
|
||||
/* Just making sure... */
|
||||
if (task == NULL)
|
||||
return;
|
||||
|
||||
/* Initialize to zero */
|
||||
for (regno = 0; regno < GDB_MAX_REGS; regno++)
|
||||
gdb_regs[regno] = 0;
|
||||
|
||||
/* Otherwise, we have only some registers from switch_to() */
|
||||
thread_regs = task_pt_regs(task);
|
||||
gdb_regs[_R0] = thread_regs->ARM_r0;
|
||||
gdb_regs[_R1] = thread_regs->ARM_r1;
|
||||
gdb_regs[_R2] = thread_regs->ARM_r2;
|
||||
gdb_regs[_R3] = thread_regs->ARM_r3;
|
||||
gdb_regs[_R4] = thread_regs->ARM_r4;
|
||||
gdb_regs[_R5] = thread_regs->ARM_r5;
|
||||
gdb_regs[_R6] = thread_regs->ARM_r6;
|
||||
gdb_regs[_R7] = thread_regs->ARM_r7;
|
||||
gdb_regs[_R8] = thread_regs->ARM_r8;
|
||||
gdb_regs[_R9] = thread_regs->ARM_r9;
|
||||
gdb_regs[_R10] = thread_regs->ARM_r10;
|
||||
gdb_regs[_FP] = thread_regs->ARM_fp;
|
||||
gdb_regs[_IP] = thread_regs->ARM_ip;
|
||||
gdb_regs[_SPT] = thread_regs->ARM_sp;
|
||||
gdb_regs[_LR] = thread_regs->ARM_lr;
|
||||
gdb_regs[_PC] = thread_regs->ARM_pc;
|
||||
gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
|
||||
}
|
||||
|
||||
static int compiled_break;
|
||||
|
||||
int kgdb_arch_handle_exception(int exception_vector, int signo,
|
||||
int err_code, char *remcom_in_buffer,
|
||||
char *remcom_out_buffer,
|
||||
struct pt_regs *linux_regs)
|
||||
{
|
||||
unsigned long addr;
|
||||
char *ptr;
|
||||
|
||||
switch (remcom_in_buffer[0]) {
|
||||
case 'D':
|
||||
case 'k':
|
||||
case 'c':
|
||||
kgdb_contthread = NULL;
|
||||
|
||||
/*
|
||||
* Try to read optional parameter, pc unchanged if no parm.
|
||||
* If this was a compiled breakpoint, we need to move
|
||||
* to the next instruction or we will just breakpoint
|
||||
* over and over again.
|
||||
*/
|
||||
ptr = &remcom_in_buffer[1];
|
||||
if (kgdb_hex2long(&ptr, &addr))
|
||||
linux_regs->ARM_pc = addr;
|
||||
else if (compiled_break == 1)
|
||||
linux_regs->ARM_pc += 4;
|
||||
|
||||
compiled_break = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
|
||||
{
|
||||
kgdb_handle_exception(1, SIGTRAP, 0, regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
|
||||
{
|
||||
compiled_break = 1;
|
||||
kgdb_handle_exception(1, SIGTRAP, 0, regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct undef_hook kgdb_brkpt_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KGDB_BREAKINST,
|
||||
.fn = kgdb_brk_fn
|
||||
};
|
||||
|
||||
static struct undef_hook kgdb_compiled_brkpt_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KGDB_COMPILED_BREAK,
|
||||
.fn = kgdb_compiled_brk_fn
|
||||
};
|
||||
|
||||
/**
|
||||
* kgdb_arch_init - Perform any architecture specific initalization.
|
||||
*
|
||||
* This function will handle the initalization of any architecture
|
||||
* specific callbacks.
|
||||
*/
|
||||
int kgdb_arch_init(void)
|
||||
{
|
||||
register_undef_hook(&kgdb_brkpt_hook);
|
||||
register_undef_hook(&kgdb_compiled_brkpt_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_undef_hook(&kgdb_brkpt_hook);
|
||||
unregister_undef_hook(&kgdb_compiled_brkpt_hook);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register our undef instruction hooks with ARM undef core.
|
||||
* We regsiter a hook specifically looking for the KGB break inst
|
||||
* and we handle the normal undef case within the do_undefinstr
|
||||
* handler.
|
||||
*/
|
||||
struct kgdb_arch arch_kgdb_ops = {
|
||||
#ifndef __ARMEB__
|
||||
.gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
|
||||
#else /* ! __ARMEB__ */
|
||||
.gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe}
|
||||
#endif
|
||||
};
|
|
@ -36,6 +36,7 @@
|
|||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "atags.h"
|
||||
|
@ -853,6 +854,7 @@ void __init setup_arch(char **cmdline_p)
|
|||
conswitchp = &dummy_con;
|
||||
#endif
|
||||
#endif
|
||||
early_trap_init();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -707,6 +707,11 @@ void abort(void)
|
|||
EXPORT_SYMBOL(abort);
|
||||
|
||||
void __init trap_init(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void __init early_trap_init(void)
|
||||
{
|
||||
unsigned long vectors = CONFIG_VECTORS_BASE;
|
||||
extern char __stubs_start[], __stubs_end[];
|
||||
|
|
|
@ -112,6 +112,7 @@ config PPC
|
|||
select HAVE_FTRACE
|
||||
select HAVE_IDE
|
||||
select HAVE_KPROBES
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_LMB
|
||||
select HAVE_DMA_ATTRS if PPC64
|
||||
|
|
|
@ -41,22 +41,6 @@ config HCALL_STATS
|
|||
This option will add a small amount of overhead to all hypervisor
|
||||
calls.
|
||||
|
||||
config DEBUGGER
|
||||
bool "Enable debugger hooks"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Include in-kernel hooks for kernel debuggers. Unless you are
|
||||
intending to debug the kernel, say N here.
|
||||
|
||||
config KGDB
|
||||
bool "Include kgdb kernel debugger"
|
||||
depends on DEBUGGER && (BROKEN || PPC_GEN550 || 4xx)
|
||||
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.
|
||||
|
||||
config CODE_PATCHING_SELFTEST
|
||||
bool "Run self-tests of the code-patching code."
|
||||
depends on DEBUG_KERNEL
|
||||
|
@ -67,36 +51,9 @@ config FTR_FIXUP_SELFTEST
|
|||
depends on DEBUG_KERNEL
|
||||
default n
|
||||
|
||||
choice
|
||||
prompt "Serial Port"
|
||||
depends on KGDB
|
||||
default KGDB_TTYS1
|
||||
|
||||
config KGDB_TTYS0
|
||||
bool "ttyS0"
|
||||
|
||||
config KGDB_TTYS1
|
||||
bool "ttyS1"
|
||||
|
||||
config KGDB_TTYS2
|
||||
bool "ttyS2"
|
||||
|
||||
config KGDB_TTYS3
|
||||
bool "ttyS3"
|
||||
|
||||
endchoice
|
||||
|
||||
config KGDB_CONSOLE
|
||||
bool "Enable serial console thru kgdb port"
|
||||
depends on KGDB && 8xx || CPM2
|
||||
help
|
||||
If you enable this, all serial console messages will be sent
|
||||
over the gdb stub.
|
||||
If unsure, say N.
|
||||
|
||||
config XMON
|
||||
bool "Include xmon kernel debugger"
|
||||
depends on DEBUGGER
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Include in-kernel hooks for the xmon kernel monitor/debugger.
|
||||
Unless you are intending to debug the kernel, say N here.
|
||||
|
@ -126,6 +83,11 @@ config XMON_DISASSEMBLY
|
|||
to say Y here, unless you're building for a memory-constrained
|
||||
system.
|
||||
|
||||
config DEBUGGER
|
||||
bool
|
||||
depends on KGDB || XMON
|
||||
default y
|
||||
|
||||
config IRQSTACKS
|
||||
bool "Use separate kernel stacks when processing interrupts"
|
||||
help
|
||||
|
|
|
@ -74,6 +74,7 @@ obj-y += time.o prom.o traps.o setup-common.o \
|
|||
misc_$(CONFIG_WORD_SIZE).o
|
||||
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
|
||||
obj-$(CONFIG_PPC64) += dma_64.o iommu.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
|
||||
obj-$(CONFIG_MODULES) += ppc_ksyms.o
|
||||
obj-$(CONFIG_BOOTX_TEXT) += btext.o
|
||||
|
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* PowerPC backend to the KGDB stub.
|
||||
*
|
||||
* 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
|
||||
* Copyright (C) 2003 Timesys Corporation.
|
||||
* Copyright (C) 2004-2006 MontaVista Software, Inc.
|
||||
* PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
|
||||
* PPC32 support restored by Vitaly Wool <vwool@ru.mvista.com> and
|
||||
* Sergei Shtylyov <sshtylyov@ru.mvista.com>
|
||||
* Copyright (C) 2007-2008 Wind River Systems, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program as licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
/*
|
||||
* This table contains the mapping between PowerPC hardware trap types, and
|
||||
* signals, which are primarily what GDB understands. GDB and the kernel
|
||||
* don't always agree on values, so we use constants taken from gdb-6.2.
|
||||
*/
|
||||
static struct hard_trap_info
|
||||
{
|
||||
unsigned int tt; /* Trap type code for powerpc */
|
||||
unsigned char signo; /* Signal that we map this trap into */
|
||||
} hard_trap_info[] = {
|
||||
{ 0x0100, 0x02 /* SIGINT */ }, /* system reset */
|
||||
{ 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */
|
||||
{ 0x0300, 0x0b /* SIGSEGV */ }, /* data access */
|
||||
{ 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */
|
||||
{ 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */
|
||||
{ 0x0600, 0x0a /* SIGBUS */ }, /* alignment */
|
||||
{ 0x0700, 0x05 /* SIGTRAP */ }, /* program check */
|
||||
{ 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */
|
||||
{ 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */
|
||||
{ 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */
|
||||
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
|
||||
{ 0x2002, 0x05 /* SIGTRAP */ }, /* debug */
|
||||
#if defined(CONFIG_FSL_BOOKE)
|
||||
{ 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */
|
||||
{ 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */
|
||||
{ 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */
|
||||
{ 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */
|
||||
{ 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */
|
||||
{ 0x2060, 0x0e /* SIGILL */ }, /* performace monitor */
|
||||
{ 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */
|
||||
{ 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */
|
||||
{ 0x3200, 0x02 /* SIGINT */ }, /* watchdog */
|
||||
#else /* ! CONFIG_FSL_BOOKE */
|
||||
{ 0x1000, 0x0e /* SIGALRM */ }, /* prog interval timer */
|
||||
{ 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */
|
||||
{ 0x1020, 0x02 /* SIGINT */ }, /* watchdog */
|
||||
{ 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */
|
||||
{ 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */
|
||||
#endif
|
||||
#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */
|
||||
{ 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */
|
||||
#if defined(CONFIG_8xx)
|
||||
{ 0x1000, 0x04 /* SIGILL */ }, /* software emulation */
|
||||
#else /* ! CONFIG_8xx */
|
||||
{ 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */
|
||||
{ 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */
|
||||
{ 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */
|
||||
#if defined(CONFIG_PPC64)
|
||||
{ 0x1200, 0x05 /* SIGILL */ }, /* system error */
|
||||
{ 0x1500, 0x04 /* SIGILL */ }, /* soft patch */
|
||||
{ 0x1600, 0x04 /* SIGILL */ }, /* maintenance */
|
||||
{ 0x1700, 0x08 /* SIGFPE */ }, /* altivec assist */
|
||||
{ 0x1800, 0x04 /* SIGILL */ }, /* thermal */
|
||||
#else /* ! CONFIG_PPC64 */
|
||||
{ 0x1400, 0x02 /* SIGINT */ }, /* SMI */
|
||||
{ 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */
|
||||
{ 0x1700, 0x04 /* SIGILL */ }, /* TAU */
|
||||
{ 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
{ 0x0000, 0x00 } /* Must be last */
|
||||
};
|
||||
|
||||
static int computeSignal(unsigned int tt)
|
||||
{
|
||||
struct hard_trap_info *ht;
|
||||
|
||||
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
|
||||
if (ht->tt == tt)
|
||||
return ht->signo;
|
||||
|
||||
return SIGHUP; /* default for things we don't know about */
|
||||
}
|
||||
|
||||
static int kgdb_call_nmi_hook(struct pt_regs *regs)
|
||||
{
|
||||
kgdb_nmicallback(raw_smp_processor_id(), regs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void kgdb_roundup_cpus(unsigned long flags)
|
||||
{
|
||||
smp_send_debugger_break(MSG_ALL_BUT_SELF);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* KGDB functions to use existing PowerPC64 hooks. */
|
||||
static int kgdb_debugger(struct pt_regs *regs)
|
||||
{
|
||||
return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs);
|
||||
}
|
||||
|
||||
static int kgdb_handle_breakpoint(struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs))
|
||||
return 0;
|
||||
|
||||
if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0)
|
||||
return 0;
|
||||
|
||||
if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
|
||||
regs->nip += 4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kgdb_singlestep(struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *thread_info, *exception_thread_info;
|
||||
|
||||
if (user_mode(regs))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* On Book E and perhaps other processsors, singlestep is handled on
|
||||
* the critical exception stack. This causes current_thread_info()
|
||||
* to fail, since it it locates the thread_info by masking off
|
||||
* the low bits of the current stack pointer. We work around
|
||||
* this issue by copying the thread_info from the kernel stack
|
||||
* before calling kgdb_handle_exception, and copying it back
|
||||
* afterwards. On most processors the copy is avoided since
|
||||
* exception_thread_info == thread_info.
|
||||
*/
|
||||
thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1));
|
||||
exception_thread_info = current_thread_info();
|
||||
|
||||
if (thread_info != exception_thread_info)
|
||||
memcpy(exception_thread_info, thread_info, sizeof *thread_info);
|
||||
|
||||
kgdb_handle_exception(0, SIGTRAP, 0, regs);
|
||||
|
||||
if (thread_info != exception_thread_info)
|
||||
memcpy(thread_info, exception_thread_info, sizeof *thread_info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kgdb_iabr_match(struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs))
|
||||
return 0;
|
||||
|
||||
if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kgdb_dabr_match(struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs))
|
||||
return 0;
|
||||
|
||||
if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PACK64(ptr, src) do { *(ptr++) = (src); } while (0)
|
||||
|
||||
#define PACK32(ptr, src) do { \
|
||||
u32 *ptr32; \
|
||||
ptr32 = (u32 *)ptr; \
|
||||
*(ptr32++) = (src); \
|
||||
ptr = (unsigned long *)ptr32; \
|
||||
} while (0)
|
||||
|
||||
|
||||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long *ptr = gdb_regs;
|
||||
int reg;
|
||||
|
||||
memset(gdb_regs, 0, NUMREGBYTES);
|
||||
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
PACK64(ptr, regs->gpr[reg]);
|
||||
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
#ifdef CONFIG_SPE
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
PACK64(ptr, current->thread.evr[reg]);
|
||||
#else
|
||||
ptr += 32;
|
||||
#endif
|
||||
#else
|
||||
/* fp registers not used by kernel, leave zero */
|
||||
ptr += 32 * 8 / sizeof(long);
|
||||
#endif
|
||||
|
||||
PACK64(ptr, regs->nip);
|
||||
PACK64(ptr, regs->msr);
|
||||
PACK32(ptr, regs->ccr);
|
||||
PACK64(ptr, regs->link);
|
||||
PACK64(ptr, regs->ctr);
|
||||
PACK32(ptr, regs->xer);
|
||||
|
||||
BUG_ON((unsigned long)ptr >
|
||||
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
|
||||
}
|
||||
|
||||
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||||
{
|
||||
struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
|
||||
STACK_FRAME_OVERHEAD);
|
||||
unsigned long *ptr = gdb_regs;
|
||||
int reg;
|
||||
|
||||
memset(gdb_regs, 0, NUMREGBYTES);
|
||||
|
||||
/* Regs GPR0-2 */
|
||||
for (reg = 0; reg < 3; reg++)
|
||||
PACK64(ptr, regs->gpr[reg]);
|
||||
|
||||
/* Regs GPR3-13 are caller saved, not in regs->gpr[] */
|
||||
ptr += 11;
|
||||
|
||||
/* Regs GPR14-31 */
|
||||
for (reg = 14; reg < 32; reg++)
|
||||
PACK64(ptr, regs->gpr[reg]);
|
||||
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
#ifdef CONFIG_SPE
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
PACK64(ptr, p->thread.evr[reg]);
|
||||
#else
|
||||
ptr += 32;
|
||||
#endif
|
||||
#else
|
||||
/* fp registers not used by kernel, leave zero */
|
||||
ptr += 32 * 8 / sizeof(long);
|
||||
#endif
|
||||
|
||||
PACK64(ptr, regs->nip);
|
||||
PACK64(ptr, regs->msr);
|
||||
PACK32(ptr, regs->ccr);
|
||||
PACK64(ptr, regs->link);
|
||||
PACK64(ptr, regs->ctr);
|
||||
PACK32(ptr, regs->xer);
|
||||
|
||||
BUG_ON((unsigned long)ptr >
|
||||
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
|
||||
}
|
||||
|
||||
#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0)
|
||||
|
||||
#define UNPACK32(dest, ptr) do { \
|
||||
u32 *ptr32; \
|
||||
ptr32 = (u32 *)ptr; \
|
||||
dest = *(ptr32++); \
|
||||
ptr = (unsigned long *)ptr32; \
|
||||
} while (0)
|
||||
|
||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long *ptr = gdb_regs;
|
||||
int reg;
|
||||
#ifdef CONFIG_SPE
|
||||
union {
|
||||
u32 v32[2];
|
||||
u64 v64;
|
||||
} acc;
|
||||
#endif
|
||||
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
UNPACK64(regs->gpr[reg], ptr);
|
||||
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
#ifdef CONFIG_SPE
|
||||
for (reg = 0; reg < 32; reg++)
|
||||
UNPACK64(current->thread.evr[reg], ptr);
|
||||
#else
|
||||
ptr += 32;
|
||||
#endif
|
||||
#else
|
||||
/* fp registers not used by kernel, leave zero */
|
||||
ptr += 32 * 8 / sizeof(int);
|
||||
#endif
|
||||
|
||||
UNPACK64(regs->nip, ptr);
|
||||
UNPACK64(regs->msr, ptr);
|
||||
UNPACK32(regs->ccr, ptr);
|
||||
UNPACK64(regs->link, ptr);
|
||||
UNPACK64(regs->ctr, ptr);
|
||||
UNPACK32(regs->xer, ptr);
|
||||
|
||||
BUG_ON((unsigned long)ptr >
|
||||
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does PowerPC specific procesing for interfacing to gdb.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
char *ptr = &remcom_in_buffer[1];
|
||||
unsigned long addr;
|
||||
|
||||
switch (remcom_in_buffer[0]) {
|
||||
/*
|
||||
* sAA..AA Step one instruction from AA..AA
|
||||
* This will return an error to gdb ..
|
||||
*/
|
||||
case 's':
|
||||
case 'c':
|
||||
/* handle the optional parameter */
|
||||
if (kgdb_hex2long(&ptr, &addr))
|
||||
linux_regs->nip = addr;
|
||||
|
||||
atomic_set(&kgdb_cpu_doing_single_step, -1);
|
||||
/* set the trace bit if we're stepping */
|
||||
if (remcom_in_buffer[0] == 's') {
|
||||
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
|
||||
mtspr(SPRN_DBCR0,
|
||||
mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
|
||||
linux_regs->msr |= MSR_DE;
|
||||
#else
|
||||
linux_regs->msr |= MSR_SE;
|
||||
#endif
|
||||
kgdb_single_step = 1;
|
||||
if (kgdb_contthread)
|
||||
atomic_set(&kgdb_cpu_doing_single_step,
|
||||
raw_smp_processor_id());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Global data
|
||||
*/
|
||||
struct kgdb_arch arch_kgdb_ops = {
|
||||
.gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08},
|
||||
};
|
||||
|
||||
static int kgdb_not_implemented(struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *old__debugger_ipi;
|
||||
static void *old__debugger;
|
||||
static void *old__debugger_bpt;
|
||||
static void *old__debugger_sstep;
|
||||
static void *old__debugger_iabr_match;
|
||||
static void *old__debugger_dabr_match;
|
||||
static void *old__debugger_fault_handler;
|
||||
|
||||
int kgdb_arch_init(void)
|
||||
{
|
||||
old__debugger_ipi = __debugger_ipi;
|
||||
old__debugger = __debugger;
|
||||
old__debugger_bpt = __debugger_bpt;
|
||||
old__debugger_sstep = __debugger_sstep;
|
||||
old__debugger_iabr_match = __debugger_iabr_match;
|
||||
old__debugger_dabr_match = __debugger_dabr_match;
|
||||
old__debugger_fault_handler = __debugger_fault_handler;
|
||||
|
||||
__debugger_ipi = kgdb_call_nmi_hook;
|
||||
__debugger = kgdb_debugger;
|
||||
__debugger_bpt = kgdb_handle_breakpoint;
|
||||
__debugger_sstep = kgdb_singlestep;
|
||||
__debugger_iabr_match = kgdb_iabr_match;
|
||||
__debugger_dabr_match = kgdb_dabr_match;
|
||||
__debugger_fault_handler = kgdb_not_implemented;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgdb_arch_exit(void)
|
||||
{
|
||||
__debugger_ipi = old__debugger_ipi;
|
||||
__debugger = old__debugger;
|
||||
__debugger_bpt = old__debugger_bpt;
|
||||
__debugger_sstep = old__debugger_sstep;
|
||||
__debugger_iabr_match = old__debugger_iabr_match;
|
||||
__debugger_dabr_match = old__debugger_dabr_match;
|
||||
__debugger_fault_handler = old__debugger_fault_handler;
|
||||
}
|
|
@ -43,10 +43,6 @@
|
|||
|
||||
#define DBG(fmt...)
|
||||
|
||||
#if defined CONFIG_KGDB
|
||||
#include <asm/kgdb.h>
|
||||
#endif
|
||||
|
||||
extern void bootx_init(unsigned long r4, unsigned long phys);
|
||||
|
||||
int boot_cpuid;
|
||||
|
@ -302,18 +298,6 @@ void __init setup_arch(char **cmdline_p)
|
|||
|
||||
xmon_setup();
|
||||
|
||||
#if defined(CONFIG_KGDB)
|
||||
if (ppc_md.kgdb_map_scc)
|
||||
ppc_md.kgdb_map_scc();
|
||||
set_debug_traps();
|
||||
if (strstr(cmd_line, "gdb")) {
|
||||
if (ppc_md.progress)
|
||||
ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
|
||||
printk("kgdb breakpoint activated\n");
|
||||
breakpoint();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set cache line size based on type of cpu as a default.
|
||||
* Systems with OF can look in the properties on the cpu node(s)
|
||||
|
|
|
@ -97,8 +97,6 @@ extern struct machdep_calls pmac_md;
|
|||
int sccdbg;
|
||||
#endif
|
||||
|
||||
extern void zs_kgdb_hook(int tty_num);
|
||||
|
||||
sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
|
||||
EXPORT_SYMBOL(sys_ctrler);
|
||||
|
||||
|
@ -329,10 +327,6 @@ static void __init pmac_setup_arch(void)
|
|||
l2cr_init();
|
||||
#endif /* CONFIG_PPC32 */
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
zs_kgdb_hook(0);
|
||||
#endif
|
||||
|
||||
find_via_cuda();
|
||||
find_via_pmu();
|
||||
smu_init();
|
||||
|
|
|
@ -201,6 +201,10 @@ static void cpm_uart_int_tx(struct uart_port *port)
|
|||
cpm_uart_tx_pump(port);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int serial_polled;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Receive characters
|
||||
*/
|
||||
|
@ -222,6 +226,12 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
|||
*/
|
||||
bdp = pinfo->rx_cur;
|
||||
for (;;) {
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (unlikely(serial_polled)) {
|
||||
serial_polled = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* get status */
|
||||
status = in_be16(&bdp->cbd_sc);
|
||||
/* If this one is empty, return happy */
|
||||
|
@ -253,7 +263,12 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
|||
goto handle_error;
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
continue;
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (unlikely(serial_polled)) {
|
||||
serial_polled = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
error_return:
|
||||
tty_insert_flip_char(tty, ch, flg);
|
||||
|
||||
|
@ -865,6 +880,80 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
|
|||
cpm_uart_request_port(port);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/* Serial polling routines for writing and reading from the uart while
|
||||
* in an interrupt or debug context.
|
||||
*/
|
||||
|
||||
#define GDB_BUF_SIZE 512 /* power of 2, please */
|
||||
|
||||
static char poll_buf[GDB_BUF_SIZE];
|
||||
static char *pollp;
|
||||
static int poll_chars;
|
||||
|
||||
static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
|
||||
{
|
||||
u_char c, *cp;
|
||||
volatile cbd_t *bdp;
|
||||
int i;
|
||||
|
||||
/* Get the address of the host memory buffer.
|
||||
*/
|
||||
bdp = pinfo->rx_cur;
|
||||
while (bdp->cbd_sc & BD_SC_EMPTY)
|
||||
;
|
||||
|
||||
/* If the buffer address is in the CPM DPRAM, don't
|
||||
* convert it.
|
||||
*/
|
||||
cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
|
||||
|
||||
if (obuf) {
|
||||
i = c = bdp->cbd_datlen;
|
||||
while (i-- > 0)
|
||||
*obuf++ = *cp++;
|
||||
} else
|
||||
c = *cp;
|
||||
bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
|
||||
bdp->cbd_sc |= BD_SC_EMPTY;
|
||||
|
||||
if (bdp->cbd_sc & BD_SC_WRAP)
|
||||
bdp = pinfo->rx_bd_base;
|
||||
else
|
||||
bdp++;
|
||||
pinfo->rx_cur = (cbd_t *)bdp;
|
||||
|
||||
return (int)c;
|
||||
}
|
||||
|
||||
static int cpm_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
|
||||
if (!serial_polled) {
|
||||
serial_polled = 1;
|
||||
poll_chars = 0;
|
||||
}
|
||||
if (poll_chars <= 0) {
|
||||
poll_chars = poll_wait_key(poll_buf, pinfo);
|
||||
pollp = poll_buf;
|
||||
}
|
||||
poll_chars--;
|
||||
return *pollp++;
|
||||
}
|
||||
|
||||
static void cpm_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
static char ch[2];
|
||||
|
||||
ch[0] = (char)c;
|
||||
cpm_uart_early_write(pinfo->port.line, ch, 1);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static struct uart_ops cpm_uart_pops = {
|
||||
.tx_empty = cpm_uart_tx_empty,
|
||||
.set_mctrl = cpm_uart_set_mctrl,
|
||||
|
@ -882,6 +971,10 @@ static struct uart_ops cpm_uart_pops = {
|
|||
.request_port = cpm_uart_request_port,
|
||||
.config_port = cpm_uart_config_port,
|
||||
.verify_port = cpm_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = cpm_get_poll_char,
|
||||
.poll_put_char = cpm_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct uart_cpm_port cpm_uart_ports[UART_NR];
|
||||
|
|
|
@ -921,6 +921,10 @@ static int mpsc_make_ready(struct mpsc_port_info *pi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int serial_polled;
|
||||
#endif
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
*
|
||||
|
@ -956,7 +960,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
|
|||
while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
|
||||
& SDMA_DESC_CMDSTAT_O)) {
|
||||
bytes_in = be16_to_cpu(rxre->bytecnt);
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (unlikely(serial_polled)) {
|
||||
serial_polled = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* Following use of tty struct directly is deprecated */
|
||||
if (unlikely(tty_buffer_request_room(tty, bytes_in)
|
||||
< bytes_in)) {
|
||||
|
@ -1017,6 +1026,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
|
|||
if (uart_handle_sysrq_char(&pi->port, *bp)) {
|
||||
bp++;
|
||||
bytes_in--;
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (unlikely(serial_polled)) {
|
||||
serial_polled = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
goto next_frame;
|
||||
}
|
||||
|
||||
|
@ -1519,6 +1534,133 @@ static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
|
||||
return rc;
|
||||
}
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/* Serial polling routines for writing and reading from the uart while
|
||||
* in an interrupt or debug context.
|
||||
*/
|
||||
|
||||
static char poll_buf[2048];
|
||||
static int poll_ptr;
|
||||
static int poll_cnt;
|
||||
static void mpsc_put_poll_char(struct uart_port *port,
|
||||
unsigned char c);
|
||||
|
||||
static int mpsc_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_rx_desc *rxre;
|
||||
u32 cmdstat, bytes_in, i;
|
||||
u8 *bp;
|
||||
|
||||
if (!serial_polled)
|
||||
serial_polled = 1;
|
||||
|
||||
pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
|
||||
|
||||
if (poll_cnt) {
|
||||
poll_cnt--;
|
||||
return poll_buf[poll_ptr++];
|
||||
}
|
||||
poll_ptr = 0;
|
||||
poll_cnt = 0;
|
||||
|
||||
while (poll_cnt == 0) {
|
||||
rxre = (struct mpsc_rx_desc *)(pi->rxr +
|
||||
(pi->rxr_posn*MPSC_RXRE_SIZE));
|
||||
dma_cache_sync(pi->port.dev, (void *)rxre,
|
||||
MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
|
||||
invalidate_dcache_range((ulong)rxre,
|
||||
(ulong)rxre + MPSC_RXRE_SIZE);
|
||||
#endif
|
||||
/*
|
||||
* Loop through Rx descriptors handling ones that have
|
||||
* been completed.
|
||||
*/
|
||||
while (poll_cnt == 0 &&
|
||||
!((cmdstat = be32_to_cpu(rxre->cmdstat)) &
|
||||
SDMA_DESC_CMDSTAT_O)){
|
||||
bytes_in = be16_to_cpu(rxre->bytecnt);
|
||||
bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
|
||||
dma_cache_sync(pi->port.dev, (void *) bp,
|
||||
MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
|
||||
invalidate_dcache_range((ulong)bp,
|
||||
(ulong)bp + MPSC_RXBE_SIZE);
|
||||
#endif
|
||||
if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
|
||||
SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
|
||||
!(cmdstat & pi->port.ignore_status_mask)) {
|
||||
poll_buf[poll_cnt] = *bp;
|
||||
poll_cnt++;
|
||||
} else {
|
||||
for (i = 0; i < bytes_in; i++) {
|
||||
poll_buf[poll_cnt] = *bp++;
|
||||
poll_cnt++;
|
||||
}
|
||||
pi->port.icount.rx += bytes_in;
|
||||
}
|
||||
rxre->bytecnt = cpu_to_be16(0);
|
||||
wmb();
|
||||
rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
|
||||
SDMA_DESC_CMDSTAT_EI |
|
||||
SDMA_DESC_CMDSTAT_F |
|
||||
SDMA_DESC_CMDSTAT_L);
|
||||
wmb();
|
||||
dma_cache_sync(pi->port.dev, (void *)rxre,
|
||||
MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
|
||||
flush_dcache_range((ulong)rxre,
|
||||
(ulong)rxre + MPSC_RXRE_SIZE);
|
||||
#endif
|
||||
|
||||
/* Advance to next descriptor */
|
||||
pi->rxr_posn = (pi->rxr_posn + 1) &
|
||||
(MPSC_RXR_ENTRIES - 1);
|
||||
rxre = (struct mpsc_rx_desc *)(pi->rxr +
|
||||
(pi->rxr_posn * MPSC_RXRE_SIZE));
|
||||
dma_cache_sync(pi->port.dev, (void *)rxre,
|
||||
MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
|
||||
invalidate_dcache_range((ulong)rxre,
|
||||
(ulong)rxre + MPSC_RXRE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Restart rx engine, if its stopped */
|
||||
if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
|
||||
mpsc_start_rx(pi);
|
||||
}
|
||||
if (poll_cnt) {
|
||||
poll_cnt--;
|
||||
return poll_buf[poll_ptr++];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void mpsc_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
u32 data;
|
||||
|
||||
data = readl(pi->mpsc_base + MPSC_MPCR);
|
||||
writeb(c, pi->mpsc_base + MPSC_CHR_1);
|
||||
mb();
|
||||
data = readl(pi->mpsc_base + MPSC_CHR_2);
|
||||
data |= MPSC_CHR_2_TTCS;
|
||||
writel(data, pi->mpsc_base + MPSC_CHR_2);
|
||||
mb();
|
||||
|
||||
while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct uart_ops mpsc_pops = {
|
||||
.tx_empty = mpsc_tx_empty,
|
||||
|
@ -1537,6 +1679,10 @@ static struct uart_ops mpsc_pops = {
|
|||
.request_port = mpsc_request_port,
|
||||
.config_port = mpsc_config_port,
|
||||
.verify_port = mpsc_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = mpsc_get_poll_char,
|
||||
.poll_put_char = mpsc_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* ARM KGDB support
|
||||
*
|
||||
* Author: Deepak Saxena <dsaxena@mvista.com>
|
||||
*
|
||||
* Copyright (C) 2002 MontaVista Software Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ARM_KGDB_H__
|
||||
#define __ARM_KGDB_H__
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
/*
|
||||
* GDB assumes that we're a user process being debugged, so
|
||||
* it will send us an SWI command to write into memory as the
|
||||
* debug trap. When an SWI occurs, the next instruction addr is
|
||||
* placed into R14_svc before jumping to the vector trap.
|
||||
* This doesn't work for kernel debugging as we are already in SVC
|
||||
* we would loose the kernel's LR, which is a bad thing. This
|
||||
* is bad thing.
|
||||
*
|
||||
* By doing this as an undefined instruction trap, we force a mode
|
||||
* switch from SVC to UND mode, allowing us to save full kernel state.
|
||||
*
|
||||
* We also define a KGDB_COMPILED_BREAK which can be used to compile
|
||||
* in breakpoints. This is important for things like sysrq-G and for
|
||||
* the initial breakpoint from trap_init().
|
||||
*
|
||||
* Note to ARM HW designers: Add real trap support like SH && PPC to
|
||||
* make our lives much much simpler. :)
|
||||
*/
|
||||
#define BREAK_INSTR_SIZE 4
|
||||
#define GDB_BREAKINST 0xef9f0001
|
||||
#define KGDB_BREAKINST 0xe7ffdefe
|
||||
#define KGDB_COMPILED_BREAK 0xe7ffdeff
|
||||
#define CACHE_FLUSH_IS_SAFE 1
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
static inline void arch_kgdb_breakpoint(void)
|
||||
{
|
||||
asm(".word 0xe7ffdeff");
|
||||
}
|
||||
|
||||
extern void kgdb_handle_bus_error(void);
|
||||
extern int kgdb_fault_expected;
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
* From Kevin Hilman:
|
||||
*
|
||||
* gdb is expecting the following registers layout.
|
||||
*
|
||||
* r0-r15: 1 long word each
|
||||
* f0-f7: unused, 3 long words each !!
|
||||
* fps: unused, 1 long word
|
||||
* cpsr: 1 long word
|
||||
*
|
||||
* Even though f0-f7 and fps are not used, they need to be
|
||||
* present in the registers sent for correct processing in
|
||||
* the host-side gdb.
|
||||
*
|
||||
* In particular, it is crucial that CPSR is in the right place,
|
||||
* otherwise gdb will not be able to correctly interpret stepping over
|
||||
* conditional branches.
|
||||
*/
|
||||
#define _GP_REGS 16
|
||||
#define _FP_REGS 8
|
||||
#define _EXTRA_REGS 2
|
||||
#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
|
||||
|
||||
#define KGDB_MAX_NO_CPUS 1
|
||||
#define BUFMAX 400
|
||||
#define NUMREGBYTES (GDB_MAX_REGS << 2)
|
||||
#define NUMCRITREGBYTES (32 << 2)
|
||||
|
||||
#define _R0 0
|
||||
#define _R1 1
|
||||
#define _R2 2
|
||||
#define _R3 3
|
||||
#define _R4 4
|
||||
#define _R5 5
|
||||
#define _R6 6
|
||||
#define _R7 7
|
||||
#define _R8 8
|
||||
#define _R9 9
|
||||
#define _R10 10
|
||||
#define _FP 11
|
||||
#define _IP 12
|
||||
#define _SPT 13
|
||||
#define _LR 14
|
||||
#define _PC 15
|
||||
#define _CPSR (GDB_MAX_REGS - 1)
|
||||
|
||||
/*
|
||||
* So that we can denote the end of a frame for tracing,
|
||||
* in the simple case:
|
||||
*/
|
||||
#define CFI_END_FRAME(func) __CFI_END_FRAME(_PC, _SPT, func)
|
||||
|
||||
#endif /* __ASM_KGDB_H__ */
|
|
@ -24,4 +24,6 @@ static inline int in_exception_text(unsigned long ptr)
|
|||
ptr < (unsigned long)&__exception_text_end;
|
||||
}
|
||||
|
||||
extern void __init early_trap_init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,57 +1,65 @@
|
|||
/*
|
||||
* kgdb.h: Defines and declarations for serial line source level
|
||||
* remote debugging of the Linux kernel using gdb.
|
||||
* include/asm-powerpc/kgdb.h
|
||||
*
|
||||
* The PowerPC (32/64) specific defines / externs for KGDB. Based on
|
||||
* the previous 32bit and 64bit specific files, which had the following
|
||||
* copyrights:
|
||||
*
|
||||
* PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
|
||||
* PPC Mods (C) 2004 Tom Rini (trini@mvista.com)
|
||||
* PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com)
|
||||
* PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
|
||||
* Author: Tom Rini <trini@kernel.crashing.org>
|
||||
*
|
||||
* 2006 (c) MontaVista Software, Inc. This file is licensed under
|
||||
* the terms of the GNU General Public License version 2. This program
|
||||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
#ifndef _PPC_KGDB_H
|
||||
#define _PPC_KGDB_H
|
||||
#ifndef __POWERPC_KGDB_H__
|
||||
#define __POWERPC_KGDB_H__
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* Things specific to the gen550 backend. */
|
||||
struct uart_port;
|
||||
|
||||
extern void gen550_progress(char *, unsigned short);
|
||||
extern void gen550_kgdb_map_scc(void);
|
||||
extern void gen550_init(int, struct uart_port *);
|
||||
|
||||
/* Things specific to the pmac backend. */
|
||||
extern void zs_kgdb_hook(int tty_num);
|
||||
|
||||
/* To init the kgdb engine. (called by serial hook)*/
|
||||
extern void set_debug_traps(void);
|
||||
|
||||
/* To enter the debugger explicitly. */
|
||||
extern void breakpoint(void);
|
||||
|
||||
/* For taking exceptions
|
||||
* these are defined in traps.c
|
||||
*/
|
||||
extern int (*debugger)(struct pt_regs *regs);
|
||||
extern int (*debugger_bpt)(struct pt_regs *regs);
|
||||
extern int (*debugger_sstep)(struct pt_regs *regs);
|
||||
extern int (*debugger_iabr_match)(struct pt_regs *regs);
|
||||
extern int (*debugger_dabr_match)(struct pt_regs *regs);
|
||||
extern void (*debugger_fault_handler)(struct pt_regs *regs);
|
||||
|
||||
/* What we bring to the party */
|
||||
int kgdb_bpt(struct pt_regs *regs);
|
||||
int kgdb_sstep(struct pt_regs *regs);
|
||||
void kgdb(struct pt_regs *regs);
|
||||
int kgdb_iabr_match(struct pt_regs *regs);
|
||||
int kgdb_dabr_match(struct pt_regs *regs);
|
||||
#define BREAK_INSTR_SIZE 4
|
||||
#define BUFMAX ((NUMREGBYTES * 2) + 512)
|
||||
#define OUTBUFMAX ((NUMREGBYTES * 2) + 512)
|
||||
static inline void arch_kgdb_breakpoint(void)
|
||||
{
|
||||
asm(".long 0x7d821008"); /* twge r2, r2 */
|
||||
}
|
||||
#define CACHE_FLUSH_IS_SAFE 1
|
||||
|
||||
/* The number bytes of registers we have to save depends on a few
|
||||
* things. For 64bit we default to not including vector registers and
|
||||
* vector state registers. */
|
||||
#ifdef CONFIG_PPC64
|
||||
/*
|
||||
* external low-level support routines (ie macserial.c)
|
||||
* 64 bit (8 byte) registers:
|
||||
* 32 gpr, 32 fpr, nip, msr, link, ctr
|
||||
* 32 bit (4 byte) registers:
|
||||
* ccr, xer, fpscr
|
||||
*/
|
||||
extern void kgdb_interruptible(int); /* control interrupts from serial */
|
||||
extern void putDebugChar(char); /* write a single character */
|
||||
extern char getDebugChar(void); /* read and return a single char */
|
||||
|
||||
#define NUMREGBYTES ((68 * 8) + (3 * 4))
|
||||
#define NUMCRITREGBYTES 184
|
||||
#else /* CONFIG_PPC32 */
|
||||
/* On non-E500 family PPC32 we determine the size by picking the last
|
||||
* register we need, but on E500 we skip sections so we list what we
|
||||
* need to store, and add it up. */
|
||||
#ifndef CONFIG_E500
|
||||
#define MAXREG (PT_FPSCR+1)
|
||||
#else
|
||||
/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/
|
||||
#define MAXREG ((32*2)+6+2+1)
|
||||
#endif
|
||||
#define NUMREGBYTES (MAXREG * sizeof(int))
|
||||
/* CR/LR, R1, R2, R13-R31 inclusive. */
|
||||
#define NUMCRITREGBYTES (23 * sizeof(int))
|
||||
#endif /* 32/64 */
|
||||
#endif /* !(__ASSEMBLY__) */
|
||||
#endif /* !(_PPC_KGDB_H) */
|
||||
#endif /* !__POWERPC_KGDB_H__ */
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
config HAVE_ARCH_KGDB_SHADOW_INFO
|
||||
bool
|
||||
|
||||
config HAVE_ARCH_KGDB
|
||||
bool
|
||||
|
||||
|
|
Loading…
Reference in New Issue