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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4d7ffa4990
commit
e2fdd7fd99
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# 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
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
.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
|
||||
.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
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/* 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 },
|
||||
};
|
|
@ -1,724 +0,0 @@
|
|||
/* $Id: sparc-stub.c,v 1.28 2001/10/30 04:54:21 davem Exp $
|
||||
* sparc-stub.c: KGDB support for the Linux kernel.
|
||||
*
|
||||
* Modifications to run under Linux
|
||||
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
|
||||
*
|
||||
* This file originally came from the gdb sources, and the
|
||||
* copyright notices have been retained below.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
THIS SOFTWARE IS NOT COPYRIGHTED
|
||||
|
||||
HP offers the following for use in the public domain. HP makes no
|
||||
warranty with regard to the software or its performance and the
|
||||
user accepts the software "AS IS" with all faults.
|
||||
|
||||
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
|
||||
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
|
||||
*
|
||||
* Module name: remcom.c $
|
||||
* Revision: 1.34 $
|
||||
* Date: 91/03/09 12:29:49 $
|
||||
* Contributor: Lake Stevens Instrument Division$
|
||||
*
|
||||
* Description: low level support for gdb debugger. $
|
||||
*
|
||||
* Considerations: only works on target hardware $
|
||||
*
|
||||
* Written by: Glenn Engel $
|
||||
* ModuleState: Experimental $
|
||||
*
|
||||
* NOTES: See Below $
|
||||
*
|
||||
* Modified for SPARC by Stu Grossman, Cygnus Support.
|
||||
*
|
||||
* This code has been extensively tested on the Fujitsu SPARClite demo board.
|
||||
*
|
||||
* To enable debugger support, two things need to happen. One, a
|
||||
* call to set_debug_traps() is necessary in order to allow any breakpoints
|
||||
* or error conditions to be properly intercepted and reported to gdb.
|
||||
* Two, a breakpoint needs to be generated to begin communication. This
|
||||
* is most easily accomplished by a call to breakpoint(). Breakpoint()
|
||||
* simulates a breakpoint by executing a trap #1.
|
||||
*
|
||||
*************
|
||||
*
|
||||
* The following gdb commands are supported:
|
||||
*
|
||||
* command function Return value
|
||||
*
|
||||
* g return the value of the CPU registers hex data or ENN
|
||||
* G set the value of the CPU registers OK or ENN
|
||||
*
|
||||
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
|
||||
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
|
||||
*
|
||||
* c Resume at current address SNN ( signal NN)
|
||||
* cAA..AA Continue at address AA..AA SNN
|
||||
*
|
||||
* s Step one instruction SNN
|
||||
* sAA..AA Step one instruction from AA..AA SNN
|
||||
*
|
||||
* k kill
|
||||
*
|
||||
* ? What was the last sigval ? SNN (signal NN)
|
||||
*
|
||||
* bBB..BB Set baud rate to BB..BB OK or BNN, then sets
|
||||
* baud rate
|
||||
*
|
||||
* All commands and responses are sent with a packet which includes a
|
||||
* checksum. A packet consists of
|
||||
*
|
||||
* $<packet info>#<checksum>.
|
||||
*
|
||||
* where
|
||||
* <packet info> :: <characters representing the command or response>
|
||||
* <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
|
||||
*
|
||||
* When a packet is received, it is first acknowledged with either '+' or '-'.
|
||||
* '+' indicates a successful transfer. '-' indicates a failed transfer.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Host: Reply:
|
||||
* $m0,10#2a +$00010203040506070809101112131415#42
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/head.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/vac-ops.h>
|
||||
#include <asm/kgdb.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* external low-level support routines
|
||||
*/
|
||||
|
||||
extern void putDebugChar(char); /* write a single character */
|
||||
extern char getDebugChar(void); /* read and return a single char */
|
||||
|
||||
/*
|
||||
* BUFMAX defines the maximum number of characters in inbound/outbound buffers
|
||||
* at least NUMREGBYTES*2 are needed for register packets
|
||||
*/
|
||||
#define BUFMAX 2048
|
||||
|
||||
static int initialized; /* !0 means we've been initialized */
|
||||
|
||||
static const char hexchars[]="0123456789abcdef";
|
||||
|
||||
#define NUMREGS 72
|
||||
|
||||
/* Number of bytes of registers. */
|
||||
#define NUMREGBYTES (NUMREGS * 4)
|
||||
enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
|
||||
O0, O1, O2, O3, O4, O5, SP, O7,
|
||||
L0, L1, L2, L3, L4, L5, L6, L7,
|
||||
I0, I1, I2, I3, I4, I5, FP, I7,
|
||||
|
||||
F0, F1, F2, F3, F4, F5, F6, F7,
|
||||
F8, F9, F10, F11, F12, F13, F14, F15,
|
||||
F16, F17, F18, F19, F20, F21, F22, F23,
|
||||
F24, F25, F26, F27, F28, F29, F30, F31,
|
||||
Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
|
||||
|
||||
|
||||
extern void trap_low(void); /* In arch/sparc/kernel/entry.S */
|
||||
|
||||
unsigned long get_sun4cpte(unsigned long addr)
|
||||
{
|
||||
unsigned long entry;
|
||||
|
||||
__asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" :
|
||||
"=r" (entry) :
|
||||
"r" (addr), "i" (ASI_PTE));
|
||||
return entry;
|
||||
}
|
||||
|
||||
unsigned long get_sun4csegmap(unsigned long addr)
|
||||
{
|
||||
unsigned long entry;
|
||||
|
||||
__asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
|
||||
"=r" (entry) :
|
||||
"r" (addr), "i" (ASI_SEGMAP));
|
||||
return entry;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Have to sort this out. This cannot be done after initialization. */
|
||||
static void flush_cache_all_nop(void) {}
|
||||
#endif
|
||||
|
||||
/* Place where we save old trap entries for restoration */
|
||||
struct tt_entry kgdb_savettable[256];
|
||||
typedef void (*trapfunc_t)(void);
|
||||
|
||||
/* Helper routine for manipulation of kgdb_savettable */
|
||||
static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest)
|
||||
{
|
||||
dest->inst_one = src->inst_one;
|
||||
dest->inst_two = src->inst_two;
|
||||
dest->inst_three = src->inst_three;
|
||||
dest->inst_four = src->inst_four;
|
||||
}
|
||||
|
||||
/* Initialize the kgdb_savettable so that debugging can commence */
|
||||
static void eh_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i < 256; i++)
|
||||
copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]);
|
||||
}
|
||||
|
||||
/* Install an exception handler for kgdb */
|
||||
static void exceptionHandler(int tnum, trapfunc_t trap_entry)
|
||||
{
|
||||
unsigned long te_addr = (unsigned long) trap_entry;
|
||||
|
||||
/* Make new vector */
|
||||
sparc_ttable[tnum].inst_one =
|
||||
SPARC_BRANCH((unsigned long) te_addr,
|
||||
(unsigned long) &sparc_ttable[tnum].inst_one);
|
||||
sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0;
|
||||
sparc_ttable[tnum].inst_three = SPARC_NOP;
|
||||
sparc_ttable[tnum].inst_four = SPARC_NOP;
|
||||
}
|
||||
|
||||
/* Convert ch from a hex digit to an int */
|
||||
static int
|
||||
hex(unsigned char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch-'a'+10;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch-'0';
|
||||
if (ch >= 'A' && ch <= 'F')
|
||||
return ch-'A'+10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* scan for the sequence $<data>#<checksum> */
|
||||
static void
|
||||
getpacket(char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
unsigned char xmitcsum;
|
||||
int i;
|
||||
int count;
|
||||
unsigned char ch;
|
||||
|
||||
do {
|
||||
/* wait around for the start character, ignore all other characters */
|
||||
while ((ch = (getDebugChar() & 0x7f)) != '$') ;
|
||||
|
||||
checksum = 0;
|
||||
xmitcsum = -1;
|
||||
|
||||
count = 0;
|
||||
|
||||
/* now, read until a # or end of buffer is found */
|
||||
while (count < BUFMAX) {
|
||||
ch = getDebugChar() & 0x7f;
|
||||
if (ch == '#')
|
||||
break;
|
||||
checksum = checksum + ch;
|
||||
buffer[count] = ch;
|
||||
count = count + 1;
|
||||
}
|
||||
|
||||
if (count >= BUFMAX)
|
||||
continue;
|
||||
|
||||
buffer[count] = 0;
|
||||
|
||||
if (ch == '#') {
|
||||
xmitcsum = hex(getDebugChar() & 0x7f) << 4;
|
||||
xmitcsum |= hex(getDebugChar() & 0x7f);
|
||||
if (checksum != xmitcsum)
|
||||
putDebugChar('-'); /* failed checksum */
|
||||
else {
|
||||
putDebugChar('+'); /* successful transfer */
|
||||
/* if a sequence char is present, reply the ID */
|
||||
if (buffer[2] == ':') {
|
||||
putDebugChar(buffer[0]);
|
||||
putDebugChar(buffer[1]);
|
||||
/* remove sequence chars from buffer */
|
||||
count = strlen(buffer);
|
||||
for (i=3; i <= count; i++)
|
||||
buffer[i-3] = buffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (checksum != xmitcsum);
|
||||
}
|
||||
|
||||
/* send the packet in buffer. */
|
||||
|
||||
static void
|
||||
putpacket(unsigned char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
unsigned char ch, recv;
|
||||
|
||||
/* $<packet info>#<checksum>. */
|
||||
do {
|
||||
putDebugChar('$');
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
|
||||
while ((ch = buffer[count])) {
|
||||
putDebugChar(ch);
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
putDebugChar('#');
|
||||
putDebugChar(hexchars[checksum >> 4]);
|
||||
putDebugChar(hexchars[checksum & 0xf]);
|
||||
recv = getDebugChar();
|
||||
} while ((recv & 0x7f) != '+');
|
||||
}
|
||||
|
||||
static char remcomInBuffer[BUFMAX];
|
||||
static char remcomOutBuffer[BUFMAX];
|
||||
|
||||
/* Convert the memory pointed to by mem into hex, placing result in buf.
|
||||
* Return a pointer to the last char put in buf (null), in case of mem fault,
|
||||
* return 0.
|
||||
*/
|
||||
|
||||
static unsigned char *
|
||||
mem2hex(char *mem, char *buf, int count)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
while (count-- > 0) {
|
||||
/* This assembler code is basically: ch = *mem++;
|
||||
* except that we use the SPARC/Linux exception table
|
||||
* mechanism (see how "fixup" works in kernel_mna_trap_fault)
|
||||
* to arrange for a "return 0" upon a memory fault
|
||||
*/
|
||||
__asm__(
|
||||
"\n1:\n\t"
|
||||
"ldub [%0], %1\n\t"
|
||||
"inc %0\n\t"
|
||||
".section .fixup,#alloc,#execinstr\n\t"
|
||||
".align 4\n"
|
||||
"2:\n\t"
|
||||
"retl\n\t"
|
||||
" mov 0, %%o0\n\t"
|
||||
".section __ex_table, #alloc\n\t"
|
||||
".align 4\n\t"
|
||||
".word 1b, 2b\n\t"
|
||||
".text\n"
|
||||
: "=r" (mem), "=r" (ch) : "0" (mem));
|
||||
*buf++ = hexchars[ch >> 4];
|
||||
*buf++ = hexchars[ch & 0xf];
|
||||
}
|
||||
|
||||
*buf = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* convert the hex array pointed to by buf into binary to be placed in mem
|
||||
* return a pointer to the character AFTER the last byte written.
|
||||
*/
|
||||
static char *
|
||||
hex2mem(char *buf, char *mem, int count)
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
for (i=0; i<count; i++) {
|
||||
|
||||
ch = hex(*buf++) << 4;
|
||||
ch |= hex(*buf++);
|
||||
/* Assembler code is *mem++ = ch; with return 0 on fault */
|
||||
__asm__(
|
||||
"\n1:\n\t"
|
||||
"stb %1, [%0]\n\t"
|
||||
"inc %0\n\t"
|
||||
".section .fixup,#alloc,#execinstr\n\t"
|
||||
".align 4\n"
|
||||
"2:\n\t"
|
||||
"retl\n\t"
|
||||
" mov 0, %%o0\n\t"
|
||||
".section __ex_table, #alloc\n\t"
|
||||
".align 4\n\t"
|
||||
".word 1b, 2b\n\t"
|
||||
".text\n"
|
||||
: "=r" (mem) : "r" (ch) , "0" (mem));
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* This table contains the mapping between SPARC hardware trap types, and
|
||||
signals, which are primarily what GDB understands. It also indicates
|
||||
which hardware traps we need to commandeer when initializing the stub. */
|
||||
|
||||
static struct hard_trap_info
|
||||
{
|
||||
unsigned char tt; /* Trap type code for SPARC */
|
||||
unsigned char signo; /* Signal that we map this trap into */
|
||||
} hard_trap_info[] = {
|
||||
{SP_TRAP_SBPT, SIGTRAP}, /* ta 1 - Linux/KGDB software breakpoint */
|
||||
{0, 0} /* Must be last */
|
||||
};
|
||||
|
||||
/* Set up exception handlers for tracing and breakpoints */
|
||||
|
||||
void
|
||||
set_debug_traps(void)
|
||||
{
|
||||
struct hard_trap_info *ht;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
#if 0
|
||||
/* Have to sort this out. This cannot be done after initialization. */
|
||||
BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
|
||||
#endif
|
||||
|
||||
/* Initialize our copy of the Linux Sparc trap table */
|
||||
eh_init();
|
||||
|
||||
for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
|
||||
/* Only if it doesn't destroy our fault handlers */
|
||||
if((ht->tt != SP_TRAP_TFLT) &&
|
||||
(ht->tt != SP_TRAP_DFLT))
|
||||
exceptionHandler(ht->tt, trap_low);
|
||||
}
|
||||
|
||||
/* In case GDB is started before us, ack any packets (presumably
|
||||
* "$?#xx") sitting there.
|
||||
*
|
||||
* I've found this code causes more problems than it solves,
|
||||
* so that's why it's commented out. GDB seems to work fine
|
||||
* now starting either before or after the kernel -bwb
|
||||
*/
|
||||
#if 0
|
||||
while((c = getDebugChar()) != '$');
|
||||
while((c = getDebugChar()) != '#');
|
||||
c = getDebugChar(); /* eat first csum byte */
|
||||
c = getDebugChar(); /* eat second csum byte */
|
||||
putDebugChar('+'); /* ack it */
|
||||
#endif
|
||||
|
||||
initialized = 1; /* connect! */
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* Convert the SPARC hardware trap type code to a unix signal number. */
|
||||
|
||||
static int
|
||||
computeSignal(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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* While we find nice hex chars, build an int.
|
||||
* Return number of chars processed.
|
||||
*/
|
||||
|
||||
static int
|
||||
hexToInt(char **ptr, int *intValue)
|
||||
{
|
||||
int numChars = 0;
|
||||
int hexValue;
|
||||
|
||||
*intValue = 0;
|
||||
|
||||
while (**ptr) {
|
||||
hexValue = hex(**ptr);
|
||||
if (hexValue < 0)
|
||||
break;
|
||||
|
||||
*intValue = (*intValue << 4) | hexValue;
|
||||
numChars ++;
|
||||
|
||||
(*ptr)++;
|
||||
}
|
||||
|
||||
return (numChars);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does all command processing for interfacing to gdb. It
|
||||
* returns 1 if you should skip the instruction at the trap address, 0
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
extern void breakinst(void);
|
||||
|
||||
void
|
||||
handle_exception (unsigned long *registers)
|
||||
{
|
||||
int tt; /* Trap type */
|
||||
int sigval;
|
||||
int addr;
|
||||
int length;
|
||||
char *ptr;
|
||||
unsigned long *sp;
|
||||
|
||||
/* First, we must force all of the windows to be spilled out */
|
||||
|
||||
asm("save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"save %sp, -64, %sp\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t"
|
||||
"restore\n\t");
|
||||
|
||||
lock_kernel();
|
||||
if (registers[PC] == (unsigned long)breakinst) {
|
||||
/* Skip over breakpoint trap insn */
|
||||
registers[PC] = registers[NPC];
|
||||
registers[NPC] += 4;
|
||||
}
|
||||
|
||||
sp = (unsigned long *)registers[SP];
|
||||
|
||||
tt = (registers[TBR] >> 4) & 0xff;
|
||||
|
||||
/* reply to host that an exception has occurred */
|
||||
sigval = computeSignal(tt);
|
||||
ptr = remcomOutBuffer;
|
||||
|
||||
*ptr++ = 'T';
|
||||
*ptr++ = hexchars[sigval >> 4];
|
||||
*ptr++ = hexchars[sigval & 0xf];
|
||||
|
||||
*ptr++ = hexchars[PC >> 4];
|
||||
*ptr++ = hexchars[PC & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[PC], ptr, 4);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[FP >> 4];
|
||||
*ptr++ = hexchars[FP & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[SP >> 4];
|
||||
*ptr++ = hexchars[SP & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)&sp, ptr, 4);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[NPC >> 4];
|
||||
*ptr++ = hexchars[NPC & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[NPC], ptr, 4);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = hexchars[O7 >> 4];
|
||||
*ptr++ = hexchars[O7 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((char *)®isters[O7], ptr, 4);
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = 0;
|
||||
|
||||
putpacket(remcomOutBuffer);
|
||||
|
||||
/* XXX We may want to add some features dealing with poking the
|
||||
* XXX page tables, the real ones on the srmmu, and what is currently
|
||||
* XXX loaded in the sun4/sun4c tlb at this point in time. But this
|
||||
* XXX also required hacking to the gdb sources directly...
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
remcomOutBuffer[0] = 0;
|
||||
|
||||
getpacket(remcomInBuffer);
|
||||
switch (remcomInBuffer[0]) {
|
||||
case '?':
|
||||
remcomOutBuffer[0] = 'S';
|
||||
remcomOutBuffer[1] = hexchars[sigval >> 4];
|
||||
remcomOutBuffer[2] = hexchars[sigval & 0xf];
|
||||
remcomOutBuffer[3] = 0;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
/* toggle debug flag */
|
||||
break;
|
||||
|
||||
case 'g': /* return the value of the CPU registers */
|
||||
{
|
||||
ptr = remcomOutBuffer;
|
||||
/* G & O regs */
|
||||
ptr = mem2hex((char *)registers, ptr, 16 * 4);
|
||||
/* L & I regs */
|
||||
ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4);
|
||||
/* Floating point */
|
||||
memset(ptr, '0', 32 * 8);
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
mem2hex((char *)®isters[Y], (ptr + 32 * 4 * 2), (8 * 4));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'G': /* set the value of the CPU registers - return OK */
|
||||
{
|
||||
unsigned long *newsp, psr;
|
||||
|
||||
psr = registers[PSR];
|
||||
|
||||
ptr = &remcomInBuffer[1];
|
||||
/* G & O regs */
|
||||
hex2mem(ptr, (char *)registers, 16 * 4);
|
||||
/* L & I regs */
|
||||
hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4);
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], 8 * 4);
|
||||
|
||||
/* See if the stack pointer has moved. If so,
|
||||
* then copy the saved locals and ins to the
|
||||
* new location. This keeps the window
|
||||
* overflow and underflow routines happy.
|
||||
*/
|
||||
|
||||
newsp = (unsigned long *)registers[SP];
|
||||
if (sp != newsp)
|
||||
sp = memcpy(newsp, sp, 16 * 4);
|
||||
|
||||
/* Don't allow CWP to be modified. */
|
||||
|
||||
if (psr != registers[PSR])
|
||||
registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
|
||||
|
||||
strcpy(remcomOutBuffer,"OK");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||||
/* Try to read %x,%x. */
|
||||
|
||||
ptr = &remcomInBuffer[1];
|
||||
|
||||
if (hexToInt(&ptr, &addr)
|
||||
&& *ptr++ == ','
|
||||
&& hexToInt(&ptr, &length)) {
|
||||
if (mem2hex((char *)addr, remcomOutBuffer, length))
|
||||
break;
|
||||
|
||||
strcpy (remcomOutBuffer, "E03");
|
||||
} else {
|
||||
strcpy(remcomOutBuffer,"E01");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
||||
/* Try to read '%x,%x:'. */
|
||||
|
||||
ptr = &remcomInBuffer[1];
|
||||
|
||||
if (hexToInt(&ptr, &addr)
|
||||
&& *ptr++ == ','
|
||||
&& hexToInt(&ptr, &length)
|
||||
&& *ptr++ == ':') {
|
||||
if (hex2mem(ptr, (char *)addr, length)) {
|
||||
strcpy(remcomOutBuffer, "OK");
|
||||
} else {
|
||||
strcpy(remcomOutBuffer, "E03");
|
||||
}
|
||||
} else {
|
||||
strcpy(remcomOutBuffer, "E02");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c': /* cAA..AA Continue at address AA..AA(optional) */
|
||||
/* try to read optional parameter, pc unchanged if no parm */
|
||||
|
||||
ptr = &remcomInBuffer[1];
|
||||
if (hexToInt(&ptr, &addr)) {
|
||||
registers[PC] = addr;
|
||||
registers[NPC] = addr + 4;
|
||||
}
|
||||
|
||||
/* Need to flush the instruction cache here, as we may have deposited a
|
||||
* breakpoint, and the icache probably has no way of knowing that a data ref to
|
||||
* some location may have changed something that is in the instruction cache.
|
||||
*/
|
||||
flush_cache_all();
|
||||
unlock_kernel();
|
||||
return;
|
||||
|
||||
/* kill the program */
|
||||
case 'k' : /* do nothing */
|
||||
break;
|
||||
case 'r': /* Reset */
|
||||
asm ("call 0\n\t"
|
||||
"nop\n\t");
|
||||
break;
|
||||
} /* switch */
|
||||
|
||||
/* reply to the request */
|
||||
putpacket(remcomOutBuffer);
|
||||
} /* while(1) */
|
||||
}
|
||||
|
||||
/* This function will generate a breakpoint exception. It is used at the
|
||||
beginning of a program to sync up with a debugger and can be used
|
||||
otherwise as a quick means to stop program execution and "break" into
|
||||
the debugger. */
|
||||
|
||||
void
|
||||
breakpoint(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
/* Again, watch those c-prefixes for ELF kernels */
|
||||
#if defined(__svr4__) || defined(__ELF__)
|
||||
asm(".globl breakinst\n"
|
||||
"breakinst:\n\t"
|
||||
"ta 1\n");
|
||||
#else
|
||||
asm(".globl _breakinst\n"
|
||||
"_breakinst:\n\t"
|
||||
"ta 1\n");
|
||||
#endif
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/* 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 },
|
||||
};
|
|
@ -1,3 +1,13 @@
|
|||
#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;
|
||||
|
|
|
@ -1,94 +1,38 @@
|
|||
/* $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);
|
||||
#ifdef CONFIG_SPARC32
|
||||
#define BUFMAX 2048
|
||||
#else
|
||||
#define BUFMAX 4096
|
||||
#endif
|
||||
|
||||
/* 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;
|
||||
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
|
||||
#ifdef CONFIG_SPARC32
|
||||
#define NUMREGBYTES ((GDB_CSR + 1) * 4)
|
||||
#else
|
||||
#define NUMREGBYTES ((GDB_Y + 1) * 8)
|
||||
#endif
|
||||
|
||||
#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];
|
||||
extern void arch_kgdb_breakpoint(void);
|
||||
|
||||
#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 BREAK_INSTR_SIZE 4
|
||||
#define CACHE_FLUSH_IS_SAFE 1
|
||||
|
||||
#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;
|
||||
|
||||
#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;
|
||||
|
||||
#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;
|
||||
|
||||
#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.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#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; \
|
||||
|
|
Loading…
Reference in New Issue