Commit e2fdd7fd authored by David S. Miller's avatar David S. Miller

sparc: Add kgdb support.

Current limitations:

1) On SMP single stepping has some fundamental issues,
   shared with other sw single-step architectures such
   as mips and arm.

2) On 32-bit sparc we don't support SMP kgdb yet.  That
   requires some reworking of the IPI mechanisms and
   infrastructure on that platform.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4d7ffa49
......@@ -68,6 +68,7 @@ config SPARC
default y
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_ARCH_KGDB if !SMP
# Identify this as a Sparc32 build
config SPARC32
......
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.25
# Sun Apr 20 01:49:51 2008
# Tue Apr 29 01:28:58 2008
#
CONFIG_MMU=y
CONFIG_HIGHMEM=y
......@@ -217,12 +217,7 @@ CONFIG_IPV6_TUNNEL=m
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
CONFIG_IP_SCTP=m
# CONFIG_SCTP_DBG_MSG is not set
CONFIG_SCTP_DBG_OBJCNT=y
# CONFIG_SCTP_HMAC_NONE is not set
# CONFIG_SCTP_HMAC_SHA1 is not set
CONFIG_SCTP_HMAC_MD5=y
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
......@@ -245,9 +240,7 @@ CONFIG_NET_PKTGEN=m
# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_AF_RXRPC=m
# CONFIG_AF_RXRPC_DEBUG is not set
# CONFIG_RXKAD is not set
# CONFIG_AF_RXRPC is not set
#
# Wireless
......@@ -390,7 +383,7 @@ CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=m
# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
......@@ -544,6 +537,7 @@ CONFIG_SERIAL_SUNSU_CONSOLE=y
# CONFIG_SERIAL_SUNSAB is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_CONSOLE_POLL=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
......@@ -595,6 +589,7 @@ CONFIG_SSB_POSSIBLE=y
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
# CONFIG_HTC_PASIC3 is not set
#
# Multimedia devices
......@@ -645,10 +640,6 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_NEW_LEDS is not set
# CONFIG_INFINIBAND is not set
# CONFIG_RTC_CLASS is not set
#
# Userspace I/O
#
# CONFIG_UIO is not set
#
......@@ -680,16 +671,12 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
CONFIG_XFS_FS=m
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_QUOTACTL=y
CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
# CONFIG_FUSE_FS is not set
......@@ -725,11 +712,9 @@ CONFIG_SYSFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
CONFIG_BEFS_FS=m
# CONFIG_BEFS_DEBUG is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
......@@ -744,7 +729,6 @@ CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
......@@ -755,16 +739,10 @@ CONFIG_SUNRPC_GSS=m
CONFIG_RPCSEC_GSS_KRB5=m
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
CONFIG_CIFS=m
# CONFIG_CIFS_STATS is not set
# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_XATTR is not set
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_EXPERIMENTAL is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
CONFIG_AFS_FS=m
# CONFIG_AFS_DEBUG is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
......@@ -821,6 +799,7 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_ENABLE_WARN_DEPRECATED is not set
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
......@@ -842,70 +821,105 @@ CONFIG_DETECT_SOFTLOCKUP=y
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
CONFIG_FRAME_POINTER=y
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_SAMPLES is not set
CONFIG_KGDB=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_TESTS=y
# CONFIG_KGDB_TESTS_ON_BOOT is not set
# CONFIG_DEBUG_STACK_USAGE is not set
#
# Security options
#
CONFIG_KEYS=y
# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_BLKCIPHER=y
# CONFIG_CRYPTO_SEQIV is not set
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_NULL=m
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_AUTHENC=y
# CONFIG_CRYPTO_TEST is not set
#
# Authenticated Encryption with Associated Data
#
# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_GCM is not set
# CONFIG_CRYPTO_SEQIV is not set
#
# Block modes
#
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_CTS is not set
CONFIG_CRYPTO_ECB=m
# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_XTS is not set
#
# Hash modes
#
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_XCBC is not set
CONFIG_CRYPTO_NULL=m
#
# Digest
#
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_XTS is not set
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_GCM is not set
# CONFIG_CRYPTO_CCM is not set
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_SERPENT=m
# CONFIG_CRYPTO_WP512 is not set
#
# Ciphers
#
CONFIG_CRYPTO_AES=m
# CONFIG_CRYPTO_ANUBIS is not set
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_BLOWFISH=m
# CONFIG_CRYPTO_CAMELLIA is not set
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
# CONFIG_CRYPTO_TEA is not set
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_SALSA20 is not set
# CONFIG_CRYPTO_SEED is not set
CONFIG_CRYPTO_SERPENT=m
# CONFIG_CRYPTO_TEA is not set
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
#
# Compression
#
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
CONFIG_CRYPTO_AUTHENC=y
# CONFIG_CRYPTO_LZO is not set
# CONFIG_CRYPTO_HW is not set
......@@ -913,6 +927,7 @@ CONFIG_CRYPTO_AUTHENC=y
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_GENERIC_FIND_FIRST_BIT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
......
......@@ -25,3 +25,4 @@ obj-$(CONFIG_PCI) += ebus.o
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
obj-$(CONFIG_SPARC_LED) += led.o
obj-$(CONFIG_KGDB) += kgdb.o
......@@ -12,7 +12,6 @@
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/smp.h>
#include <asm/kgdb.h>
#include <asm/contregs.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
......@@ -45,91 +44,20 @@
_SV; _SV; _SV; _SV; _SV; _SV; _SV; \
_RS; _RS; _RS; _RS; _RS; _RS; _RS;
/* First, KGDB low level things. This is a rewrite
* of the routines found in the sparc-stub.c asm() statement
* from the gdb distribution. This is also dual-purpose
* as a software trap for userlevel programs.
*/
.data
.align 4
in_trap_handler:
.word 0
.text
.align 4
#if 0 /* kgdb is dropped from 2.5.33 */
! This function is called when any SPARC trap (except window overflow or
! underflow) occurs. It makes sure that the invalid register window is still
! available before jumping into C code. It will also restore the world if you
! return from handle_exception.
.globl trap_low
trap_low:
rd %wim, %l3
SAVE_ALL
sethi %hi(in_trap_handler), %l4
ld [%lo(in_trap_handler) + %l4], %l5
inc %l5
st %l5, [%lo(in_trap_handler) + %l4]
/* Make sure kgdb sees the same state we just saved. */
LOAD_PT_GLOBALS(sp)
LOAD_PT_INS(sp)
ld [%sp + STACKFRAME_SZ + PT_Y], %l4
ld [%sp + STACKFRAME_SZ + PT_WIM], %l3
ld [%sp + STACKFRAME_SZ + PT_PSR], %l0
ld [%sp + STACKFRAME_SZ + PT_PC], %l1
ld [%sp + STACKFRAME_SZ + PT_NPC], %l2
rd %tbr, %l5 /* Never changes... */
/* Make kgdb exception frame. */
sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
! + hidden arg + arg spill
! + doubleword alignment
! + registers[72] local var
SAVE_KGDB_GLOBALS(sp)
SAVE_KGDB_INS(sp)
SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
/* We are increasing PIL, so two writes. */
or %l0, PSR_PIL, %l0
wr %l0, 0, %psr
WRITE_PAUSE
wr %l0, PSR_ET, %psr
WRITE_PAUSE
call handle_exception
add %sp, STACKFRAME_SZ, %o0 ! Pass address of registers
/* Load new kgdb register set. */
LOAD_KGDB_GLOBALS(sp)
LOAD_KGDB_INS(sp)
LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
wr %l4, 0x0, %y
sethi %hi(in_trap_handler), %l4
ld [%lo(in_trap_handler) + %l4], %l5
dec %l5
st %l5, [%lo(in_trap_handler) + %l4]
add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame.
/* Now take what kgdb did and place it into the pt_regs
* frame which SparcLinux RESTORE_ALL understands.,
*/
STORE_PT_INS(sp)
STORE_PT_GLOBALS(sp)
STORE_PT_YREG(sp, g2)
STORE_PT_PRIV(sp, l0, l1, l2)
RESTORE_ALL
#ifdef CONFIG_KGDB
.align 4
.globl arch_kgdb_breakpoint
.type arch_kgdb_breakpoint,#function
arch_kgdb_breakpoint:
ta 0x7d
retl
nop
.size arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
#endif
#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
.text
.align 4
.globl floppy_hardint
floppy_hardint:
......@@ -1596,6 +1524,23 @@ breakpoint_trap:
RESTORE_ALL
#ifdef CONFIG_KGDB
.align 4
.globl kgdb_trap_low
.type kgdb_trap_low,#function
kgdb_trap_low:
rd %wim,%l3
SAVE_ALL
wr %l0, PSR_ET, %psr
WRITE_PAUSE
call kgdb_trap
add %sp, STACKFRAME_SZ, %o0
RESTORE_ALL
.size kgdb_trap_low,.-kgdb_trap_low
#endif
.align 4
.globl __handle_exception, flush_patch_exception
__handle_exception:
......@@ -1698,4 +1643,22 @@ pcic_nmi_trap_patch:
#endif /* CONFIG_PCI */
.globl flushw_all
flushw_all:
save %sp, -0x40, %sp
save %sp, -0x40, %sp
save %sp, -0x40, %sp
save %sp, -0x40, %sp
save %sp, -0x40, %sp
save %sp, -0x40, %sp
save %sp, -0x40, %sp
restore
restore
restore
restore
restore
restore
ret
restore
/* End of entry.S */
......@@ -191,7 +191,8 @@ t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xe
t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd)
t_badfc:BAD_TRAP(0xfc)
t_kgdb: KGDB_TRAP(0xfd)
dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */
dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */
......@@ -267,7 +268,7 @@ trapbase_cpu1:
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
trapbase_cpu2:
BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
......@@ -335,7 +336,7 @@ trapbase_cpu2:
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
trapbase_cpu3:
BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
......@@ -403,7 +404,7 @@ trapbase_cpu3:
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
#endif
.align PAGE_SIZE
......
/* kgdb.c: KGDB support for 32-bit sparc.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kgdb.h>
#include <linux/kdebug.h>
#include <asm/kdebug.h>
#include <asm/ptrace.h>
#include <asm/irq.h>
extern unsigned long trapbase;
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
struct reg_window *win;
int i;
gdb_regs[GDB_G0] = 0;
for (i = 0; i < 15; i++)
gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
win = (struct reg_window *) regs->u_regs[UREG_FP];
for (i = 0; i < 8; i++)
gdb_regs[GDB_L0 + i] = win->locals[i];
for (i = 0; i < 8; i++)
gdb_regs[GDB_I0 + i] = win->ins[i];
for (i = GDB_F0; i <= GDB_F31; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_Y] = regs->y;
gdb_regs[GDB_PSR] = regs->psr;
gdb_regs[GDB_WIM] = 0;
gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
gdb_regs[GDB_PC] = regs->pc;
gdb_regs[GDB_NPC] = regs->npc;
gdb_regs[GDB_FSR] = 0;
gdb_regs[GDB_CSR] = 0;
}
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
{
struct thread_info *t = task_thread_info(p);
struct reg_window *win;
int i;
for (i = GDB_G0; i < GDB_G6; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_G6] = (unsigned long) t;
gdb_regs[GDB_G7] = 0;
for (i = GDB_O0; i < GDB_SP; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_SP] = t->ksp;
gdb_regs[GDB_O7] = 0;
win = (struct reg_window *) t->ksp;
for (i = 0; i < 8; i++)
gdb_regs[GDB_L0 + i] = win->locals[i];
for (i = 0; i < 8; i++)
gdb_regs[GDB_I0 + i] = win->ins[i];
for (i = GDB_F0; i <= GDB_F31; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_Y] = 0;
gdb_regs[GDB_PSR] = t->kpsr;
gdb_regs[GDB_WIM] = t->kwim;
gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
gdb_regs[GDB_PC] = t->kpc;
gdb_regs[GDB_NPC] = t->kpc + 4;
gdb_regs[GDB_FSR] = 0;
gdb_regs[GDB_CSR] = 0;
}
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
struct reg_window *win;
int i;
for (i = 0; i < 15; i++)
regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
/* If the PSR register is changing, we have to preserve
* the CWP field, otherwise window save/restore explodes.
*/
if (regs->psr != gdb_regs[GDB_PSR]) {
unsigned long cwp = regs->psr & PSR_CWP;
regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp;
}
regs->pc = gdb_regs[GDB_PC];
regs->npc = gdb_regs[GDB_NPC];
regs->y = gdb_regs[GDB_Y];
win = (struct reg_window *) regs->u_regs[UREG_FP];
for (i = 0; i < 8; i++)
win->locals[i] = gdb_regs[GDB_L0 + i];
for (i = 0; i < 8; i++)
win->ins[i] = gdb_regs[GDB_I0 + i];
}
int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
char *remcomInBuffer, char *remcomOutBuffer,
struct pt_regs *linux_regs)
{
unsigned long addr;
char *ptr;
switch (remcomInBuffer[0]) {
case 'c':
/* try to read optional parameter, pc unchanged if no parm */
ptr = &remcomInBuffer[1];
if (kgdb_hex2long(&ptr, &addr)) {
linux_regs->pc = addr;
linux_regs->npc = addr + 4;
}
/* fallthru */
case 'D':
case 'k':
if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) {
linux_regs->pc = linux_regs->npc;
linux_regs->npc += 4;
}
return 0;
}
return -1;
}
extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
asmlinkage void kgdb_trap(struct pt_regs *regs)
{
unsigned long flags;
if (user_mode(regs)) {
do_hw_interrupt(regs, 0xfd);
return;
}
flushw_all();
local_irq_save(flags);
kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
local_irq_restore(flags);
}
int kgdb_arch_init(void)
{
return 0;
}
void kgdb_arch_exit(void)
{
}
struct kgdb_arch arch_kgdb_ops = {
/* Breakpoint instruction: ta 0x7d */
.gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x7d },
};
This diff is collapsed.
......@@ -13,6 +13,7 @@ config SPARC64
default y
select HAVE_IDE
select HAVE_LMB
select HAVE_ARCH_KGDB
config GENERIC_TIME
bool
......
......@@ -29,3 +29,4 @@ obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o
obj-y += $(obj-yy)
obj-$(CONFIG_KGDB) += kgdb.o
/* kgdb.c: KGDB support for 64-bit sparc.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kgdb.h>
#include <linux/kdebug.h>
#include <asm/kdebug.h>
#include <asm/ptrace.h>
#include <asm/irq.h>
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
struct reg_window *win;
int i;
gdb_regs[GDB_G0] = 0;
for (i = 0; i < 15; i++)
gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
for (i = 0; i < 8; i++)
gdb_regs[GDB_L0 + i] = win->locals[i];
for (i = 0; i < 8; i++)
gdb_regs[GDB_I0 + i] = win->ins[i];
for (i = GDB_F0; i <= GDB_F62; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_PC] = regs->tpc;
gdb_regs[GDB_NPC] = regs->tnpc;
gdb_regs[GDB_STATE] = regs->tstate;
gdb_regs[GDB_FSR] = 0;
gdb_regs[GDB_FPRS] = 0;
gdb_regs[GDB_Y] = regs->y;
}
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
{
struct thread_info *t = task_thread_info(p);
extern unsigned int switch_to_pc;
extern unsigned int ret_from_syscall;
struct reg_window *win;
unsigned long pc, cwp;
int i;
for (i = GDB_G0; i < GDB_G6; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_G6] = (unsigned long) t;
gdb_regs[GDB_G7] = (unsigned long) p;
for (i = GDB_O0; i < GDB_SP; i++)
gdb_regs[i] = 0;
gdb_regs[GDB_SP] = t->ksp;
gdb_regs[GDB_O7] = 0;
win = (struct reg_window *) (t->ksp + STACK_BIAS);
for (i = 0; i < 8; i++)
gdb_regs[GDB_L0 + i] = win->locals[i];
for (i = 0; i < 8; i++)
gdb_regs[GDB_I0 + i] = win->ins[i];
for (i = GDB_F0; i <= GDB_F62; i++)
gdb_regs[i] = 0;
if (t->new_child)
pc = (unsigned long) &ret_from_syscall;
else
pc = (unsigned long) &switch_to_pc;
gdb_regs[GDB_PC] = pc;
gdb_regs[GDB_NPC] = pc + 4;
cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
gdb_regs[GDB_FSR] = 0;
gdb_regs[GDB_FPRS] = 0;
gdb_regs[GDB_Y] = 0;
}
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
struct reg_window *win;
int i;
for (i = 0; i < 15; i++)
regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
/* If the TSTATE register is changing, we have to preserve
* the CWP field, otherwise window save/restore explodes.
*/
if (regs->tstate != gdb_regs[GDB_STATE]) {
unsigned long cwp = regs->tstate & TSTATE_CWP;
regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
}
regs->tpc = gdb_regs[GDB_PC];
regs->tnpc = gdb_regs[GDB_NPC];
regs->y = gdb_regs[GDB_Y];
win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
for (i = 0; i < 8; i++)
win->locals[i] = gdb_regs[GDB_L0 + i];
for (i = 0; i < 8; i++)
win->ins[i] = gdb_regs[GDB_I0 + i];
}
#ifdef CONFIG_SMP
void smp_kgdb_capture_client(struct pt_regs *regs)
{
unsigned long flags;
__asm__ __volatile__("rdpr %%pstate, %0\n\t"
"wrpr %0, %1, %%pstate"
: "=r" (flags)
: "i" (PSTATE_IE));
flushw_all();
if (atomic_read(&kgdb_active) != -1)
kgdb_nmicallback(raw_smp_processor_id(), regs);
__asm__ __volatile__("wrpr %0, 0, %%pstate"
: : "r" (flags));
}
#endif
int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
char *remcomInBuffer, char *remcomOutBuffer,
struct pt_regs *linux_regs)
{
unsigned long addr;
char *ptr;
switch (remcomInBuffer[0]) {
case 'c':
/* try to read optional parameter, pc unchanged if no parm */
ptr = &remcomInBuffer[1];
if (kgdb_hex2long(&ptr, &addr)) {
linux_regs->tpc = addr;
linux_regs->tnpc = addr + 4;
}
/* fallthru */
case 'D':
case 'k':
if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
linux_regs->tpc = linux_regs->tnpc;
linux_regs->tnpc += 4;
}
return 0;
}
return -1;
}
asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
{
unsigned long flags;
if (user_mode(regs)) {
bad_trap(regs, trap_level);
return;
}
flushw_all();
local_irq_save(flags);
kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
local_irq_restore(flags);
}
int kgdb_arch_init(void)
{
return 0;
}
void kgdb_arch_exit(void)
{
}
struct kgdb_arch arch_kgdb_ops = {
/* Breakpoint instruction: ta 0x72 */
.gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 },
};
#ifdef CONFIG_KGDB
.globl arch_kgdb_breakpoint
.type arch_kgdb_breakpoint,#function
arch_kgdb_breakpoint:
ta 0x72
retl
nop
.size arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
#endif
.type __do_privact,#function
__do_privact:
mov TLB_SFSR, %g3
......
......@@ -910,6 +910,9 @@ extern unsigned long xcall_flush_tlb_kernel_range;
extern unsigned long xcall_report_regs;
extern unsigned long xcall_receive_signal;
extern unsigned long xcall_new_mmu_context_version;
#ifdef CONFIG_KGDB
extern unsigned long xcall_kgdb_capture;
#endif
#ifdef DCACHE_ALIASING_POSSIBLE
extern unsigned long xcall_flush_dcache_page_cheetah;
......@@ -1079,6 +1082,13 @@ void smp_new_mmu_context_version(void)
smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
}
#ifdef CONFIG_KGDB
void kgdb_roundup_cpus(unsigned long flags)
{
smp_cross_call(&xcall_kgdb_capture, 0, 0, 0);
}
#endif
void smp_report_regs(void)
{
smp_cross_call(&xcall_report_regs, 0, 0, 0);
......
......@@ -153,7 +153,7 @@ tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168)
tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c)
tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context)
tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172)
tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) KGDB_TRAP(0x172)
tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
......
......@@ -676,6 +676,33 @@ xcall_new_mmu_context_version:
wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
retry
#ifdef CONFIG_KGDB
.globl xcall_kgdb_capture
xcall_kgdb_capture:
661: rdpr %pstate, %g2
wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
.section .sun4v_2insn_patch, "ax"
.word 661b
nop
nop
.previous
rdpr %pil, %g2
wrpr %g0, 15, %pil
sethi %hi(109f), %g7
ba,pt %xcc, etrap_irq
109: or %g7, %lo(109b), %g7
#ifdef CONFIG_TRACE_IRQFLAGS
call trace_hardirqs_off
nop
#endif
call smp_kgdb_capture_client
add %sp, PTREGS_OFF, %o0
/* Has to be a non-v9 branch due to the large distance. */
ba rtrap_xcall
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
#endif
#endif /* CONFIG_SMP */
......
......@@ -52,6 +52,17 @@
nop; \
nop;
#ifdef CONFIG_KGDB
#define KGDB_TRAP(num) \
b kgdb_trap_low; \
rd %psr,%l0; \
nop; \
nop;
#else
#define KGDB_TRAP(num) \
BAD_TRAP(num)
#endif
/* The Get Condition Codes software trap for userland. */
#define GETCC_TRAP \
b getcc_trap_handler; mov %psr, %l0; nop; nop;
......
/* $Id: kgdb.h,v 1.8 1998/01/07 06:33:44 baccala Exp $
* kgdb.h: Defines and declarations for serial line source level
* remote debugging of the Linux kernel using gdb.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#ifndef _SPARC_KGDB_H
#define _SPARC_KGDB_H
#ifndef __ASSEMBLY__
/* To init the kgdb engine. */
extern void set_debug_traps(void);
/* To enter the debugger explicitly. */
extern void breakpoint(void);
/* For convenience we define the format of a kgdb trap breakpoint
* frame here also.
*/
struct kgdb_frame {
unsigned long globals[8];
unsigned long outs[8];
unsigned long locals[8];
unsigned long ins[8];
unsigned long fpregs[32];
unsigned long y;
unsigned long psr;
unsigned long wim;
unsigned long tbr;
unsigned long pc;
unsigned long npc;
unsigned long fpsr;
unsigned long cpsr;
#ifdef CONFIG_SPARC32
#define BUFMAX 2048
#else
#define BUFMAX 4096
#endif
enum regnames {
GDB_G0, GDB_G1, GDB_G2, GDB_G3, GDB_G4, GDB_G5, GDB_G6, GDB_G7,
GDB_O0, GDB_O1, GDB_O2, GDB_O3, GDB_O4, GDB_O5, GDB_SP, GDB_O7,
GDB_L0, GDB_L1, GDB_L2, GDB_L3, GDB_L4, GDB_L5, GDB_L6, GDB_L7,
GDB_I0, GDB_I1, GDB_I2, GDB_I3, GDB_I4, GDB_I5, GDB_FP, GDB_I7,
GDB_F0,
GDB_F31 = GDB_F0 + 31,
#ifdef CONFIG_SPARC32
GDB_Y, GDB_PSR, GDB_WIM, GDB_TBR, GDB_PC, GDB_NPC,
GDB_FSR, GDB_CSR,
#else
GDB_F32 = GDB_F0 + 32,
GDB_F62 = GDB_F32 + 15,
GDB_PC, GDB_NPC, GDB_STATE, GDB_FSR, GDB_FPRS, GDB_Y,
#endif
};
#endif /* !(__ASSEMBLY__) */
/* Macros for assembly usage of the kgdb breakpoint frame. */
#define KGDB_G0 0x000
#define KGDB_G1 0x004
#define KGDB_G2 0x008
#define KGDB_G4 0x010
#define KGDB_G6 0x018
#define KGDB_I0 0x020
#define KGDB_I2 0x028
#define KGDB_I4 0x030
#define KGDB_I6 0x038
#define KGDB_Y 0x100
#define KGDB_PSR 0x104
#define KGDB_WIM 0x108
#define KGDB_TBR 0x10c
#define KGDB_PC 0x110
#define KGDB_NPC 0x114
#define SAVE_KGDB_GLOBALS(reg) \
std %g0, [%reg + STACKFRAME_SZ + KGDB_G0]; \
std %g2, [%reg + STACKFRAME_SZ + KGDB_G2]; \
std %g4, [%reg + STACKFRAME_SZ + KGDB_G4]; \
std %g6, [%reg + STACKFRAME_SZ + KGDB_G6];
#define SAVE_KGDB_INS(reg) \
std %i0, [%reg + STACKFRAME_SZ + KGDB_I0]; \
std %i2, [%reg + STACKFRAME_SZ + KGDB_I2]; \
std %i4, [%reg + STACKFRAME_SZ + KGDB_I4]; \
std %i6, [%reg + STACKFRAME_SZ + KGDB_I6];
#define SAVE_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
st %reg_y, [%reg + STACKFRAME_SZ + KGDB_Y]; \
st %reg_psr, [%reg + STACKFRAME_SZ + KGDB_PSR]; \
st %reg_wim, [%reg + STACKFRAME_SZ + KGDB_WIM]; \
st %reg_tbr, [%reg + STACKFRAME_SZ + KGDB_TBR]; \
st %reg_pc, [%reg + STACKFRAME_SZ + KGDB_PC]; \
st %reg_npc, [%reg + STACKFRAME_SZ + KGDB_NPC];
#define LOAD_KGDB_GLOBALS(reg) \
ld [%reg + STACKFRAME_SZ + KGDB_G1], %g1; \
ldd [%reg + STACKFRAME_SZ + KGDB_G2], %g2; \
ldd [%reg + STACKFRAME_SZ + KGDB_G4], %g4; \
ldd [%reg + STACKFRAME_SZ + KGDB_G6], %g6;
#ifdef CONFIG_SPARC32
#define NUMREGBYTES ((GDB_CSR + 1) * 4)
#else
#define NUMREGBYTES ((GDB_Y + 1) * 8)
#endif
#define LOAD_KGDB_INS(reg) \
ldd [%reg + STACKFRAME_SZ + KGDB_I0], %i0; \
ldd [%reg + STACKFRAME_SZ + KGDB_I2], %i2; \
ldd [%reg + STACKFRAME_SZ + KGDB_I4], %i4; \
ldd [%reg + STACKFRAME_SZ + KGDB_I6], %i6;
extern void arch_kgdb_breakpoint(void);
#define LOAD_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
ld [%reg + STACKFRAME_SZ + KGDB_Y], %reg_y; \
ld [%reg + STACKFRAME_SZ + KGDB_PSR], %reg_psr; \
ld [%reg + STACKFRAME_SZ + KGDB_WIM], %reg_wim; \
ld [%reg + STACKFRAME_SZ + KGDB_TBR], %reg_tbr; \
ld [%reg + STACKFRAME_SZ + KGDB_PC], %reg_pc; \
ld [%reg + STACKFRAME_SZ + KGDB_NPC], %reg_npc;
#define BREAK_INSTR_SIZE 4
#define CACHE_FLUSH_IS_SAFE 1
#endif /* !(_SPARC_KGDB_H) */
#endif /* _SPARC_KGDB_H */
......@@ -94,6 +94,8 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
} while(0)
#endif
extern void flushw_all(void);
/*
* Flush windows so that the VM switch which follows
* would not pull the stack from under us.
......
#include <asm-sparc/kgdb.h>
......@@ -180,12 +180,13 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
"ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
"ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
"ldx [%%g6 + %9], %%g4\n\t" \
"brz,pt %%o7, 1f\n\t" \
"brz,pt %%o7, switch_to_pc\n\t" \
" mov %%g7, %0\n\t" \
"sethi %%hi(ret_from_syscall), %%g1\n\t" \
"jmpl %%g1 + %%lo(ret_from_syscall), %%g0\n\t" \
" nop\n\t" \
"1:\n\t" \
".globl switch_to_pc\n\t" \
"switch_to_pc:\n\t" \
: "=&r" (last), "=r" (current), "=r" (current_thread_info_reg), \
"=r" (__local_per_cpu_offset) \
: "0" (task_thread_info(next)), \
......
......@@ -175,6 +175,12 @@
#define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
#endif
#ifdef CONFIG_KGDB
#define KGDB_TRAP(lvl) TRAP_IRQ(kgdb_trap, lvl)
#else
#define KGDB_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
#endif
#define SUN4V_ITSB_MISS \
ldxa [%g0] ASI_SCRATCHPAD, %g2; \
ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4; \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment