diff options
36 files changed, 3223 insertions, 3624 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 49590f8fe98..d211fdb2458 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -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 diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 6a2c57a2fe7..2e3a149ea0e 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -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 diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 59700aaaae9..6e03a2a7863 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -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 diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 484c83d23ee..57d1bbdd0bd 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -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 */ diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index b7f1e81c8ff..8bec05fa579 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.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 diff --git a/arch/sparc/kernel/kgdb.c b/arch/sparc/kernel/kgdb.c new file mode 100644 index 00000000000..757805ce02e --- /dev/null +++ b/arch/sparc/kernel/kgdb.c @@ -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 }, +}; diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c deleted file mode 100644 index e84f815e690..00000000000 --- a/arch/sparc/kernel/sparc-stub.c +++ /dev/null @@ -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 -} diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 0def48158c7..dfde77ff084 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -335,37 +335,6 @@ void smp4d_cross_call_irq(void) ccall_info.processors_out[i] = 1; } -static int smp4d_stop_cpu_sender; - -static void smp4d_stop_cpu(void) -{ - int me = hard_smp4d_processor_id(); - - if (me != smp4d_stop_cpu_sender) - while(1) barrier(); -} - -/* Cross calls, in order to work efficiently and atomically do all - * the message passing work themselves, only stopcpu and reschedule - * messages come through here. - */ -void smp4d_message_pass(int target, int msg, unsigned long data, int wait) -{ - int me = hard_smp4d_processor_id(); - - SMP_PRINTK(("smp4d_message_pass %d %d %08lx %d\n", target, msg, data, wait)); - if (msg == MSG_STOP_CPU && target == MSG_ALL_BUT_SELF) { - unsigned long flags; - static DEFINE_SPINLOCK(stop_cpu_lock); - spin_lock_irqsave(&stop_cpu_lock, flags); - smp4d_stop_cpu_sender = me; - smp4d_cross_call((smpfunc_t)smp4d_stop_cpu, 0, 0, 0, 0, 0); - spin_unlock_irqrestore(&stop_cpu_lock, flags); - } - printk("Yeeee, trying to send SMP msg(%d) to %d on cpu %d\n", msg, target, me); - panic("Bogon SMP message pass."); -} - void smp4d_percpu_timer_interrupt(struct pt_regs *regs) { struct pt_regs *old_regs; @@ -439,7 +408,6 @@ void __init sun4d_init_smp(void) BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id); BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); for (i = 0; i < NR_CPUS; i++) { diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 0b940726716..ffb875aacb7 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -34,8 +34,6 @@ #include "irq.h" -#define IRQ_RESCHEDULE 13 -#define IRQ_STOP_CPU 14 #define IRQ_CROSS_CALL 15 extern ctxd_t *srmmu_ctx_table_phys; @@ -232,48 +230,6 @@ void smp4m_irq_rotate(int cpu) set_irq_udt(next); } -/* Cross calls, in order to work efficiently and atomically do all - * the message passing work themselves, only stopcpu and reschedule - * messages come through here. - */ -void smp4m_message_pass(int target, int msg, unsigned long data, int wait) -{ - static unsigned long smp_cpu_in_msg[NR_CPUS]; - cpumask_t mask; - int me = smp_processor_id(); - int irq, i; - - if(msg == MSG_RESCHEDULE) { - irq = IRQ_RESCHEDULE; - - if(smp_cpu_in_msg[me]) - return; - } else if(msg == MSG_STOP_CPU) { - irq = IRQ_STOP_CPU; - } else { - goto barf; - } - - smp_cpu_in_msg[me]++; - if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) { - mask = cpu_online_map; - if(target == MSG_ALL_BUT_SELF) - cpu_clear(me, mask); - for(i = 0; i < 4; i++) { - if (cpu_isset(i, mask)) - set_cpu_int(i, irq); - } - } else { - set_cpu_int(target, irq); - } - smp_cpu_in_msg[me]--; - - return; -barf: - printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me); - panic("Bogon SMP message pass."); -} - static struct smp_funcall { smpfunc_t func; unsigned long arg1; @@ -413,6 +369,5 @@ void __init sun4m_init_smp(void) BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4m_blackbox_id); BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM); } diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index edbe71e3fab..eb36f3b746b 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -13,6 +13,7 @@ config SPARC64 default y select HAVE_IDE select HAVE_LMB + select HAVE_ARCH_KGDB config GENERIC_TIME bool diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 2bd0340b743..ec4f5ebb1ca 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -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 diff --git a/arch/sparc64/kernel/cherrs.S b/arch/sparc64/kernel/cherrs.S new file mode 100644 index 00000000000..89afebd7eca --- /dev/null +++ b/arch/sparc64/kernel/cherrs.S @@ -0,0 +1,579 @@ + /* These get patched into the trap table at boot time + * once we know we have a cheetah processor. + */ + .globl cheetah_fecc_trap_vector + .type cheetah_fecc_trap_vector,#function +cheetah_fecc_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 0, %g1 + .size cheetah_fecc_trap_vector,.-cheetah_fecc_trap_vector + + .globl cheetah_fecc_trap_vector_tl1 + .type cheetah_fecc_trap_vector_tl1,#function +cheetah_fecc_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_DC | DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_fast_ecc), %g2 + jmpl %g2 + %lo(cheetah_fast_ecc), %g0 + mov 1, %g1 + .size cheetah_fecc_trap_vector_tl1,.-cheetah_fecc_trap_vector_tl1 + + .globl cheetah_cee_trap_vector + .type cheetah_cee_trap_vector,#function +cheetah_cee_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 0, %g1 + .size cheetah_cee_trap_vector,.-cheetah_cee_trap_vector + + .globl cheetah_cee_trap_vector_tl1 + .type cheetah_cee_trap_vector_tl1,#function +cheetah_cee_trap_vector_tl1: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + andn %g1, DCU_IC, %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + sethi %hi(cheetah_cee), %g2 + jmpl %g2 + %lo(cheetah_cee), %g0 + mov 1, %g1 + .size cheetah_cee_trap_vector_tl1,.-cheetah_cee_trap_vector_tl1 + + .globl cheetah_deferred_trap_vector + .type cheetah_deferred_trap_vector,#function +cheetah_deferred_trap_vector: + membar #Sync + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 0, %g1 + .size cheetah_deferred_trap_vector,.-cheetah_deferred_trap_vector + + .globl cheetah_deferred_trap_vector_tl1 + .type cheetah_deferred_trap_vector_tl1,#function +cheetah_deferred_trap_vector_tl1: + membar #Sync; + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; + andn %g1, DCU_DC | DCU_IC, %g1; + stxa %g1, [%g0] ASI_DCU_CONTROL_REG; + membar #Sync; + sethi %hi(cheetah_deferred_trap), %g2 + jmpl %g2 + %lo(cheetah_deferred_trap), %g0 + mov 1, %g1 + .size cheetah_deferred_trap_vector_tl1,.-cheetah_deferred_trap_vector_tl1 + + /* Cheetah+ specific traps. These are for the new I/D cache parity + * error traps. The first argument to cheetah_plus_parity_handler + * is encoded as follows: + * + * Bit0: 0=dcache,1=icache + * Bit1: 0=recoverable,1=unrecoverable + */ + .globl cheetah_plus_dcpe_trap_vector + .type cheetah_plus_dcpe_trap_vector,#function +cheetah_plus_dcpe_trap_vector: + membar #Sync + sethi %hi(do_cheetah_plus_data_parity), %g7 + jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0 + nop + nop + nop + nop + nop + .size cheetah_plus_dcpe_trap_vector,.-cheetah_plus_dcpe_trap_vector + + .type do_cheetah_plus_data_parity,#function +do_cheetah_plus_data_parity: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov 0x0, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 + ba,a,pt %xcc, rtrap_irq + .size do_cheetah_plus_data_parity,.-do_cheetah_plus_data_parity + + .globl cheetah_plus_dcpe_trap_vector_tl1 + .type cheetah_plus_dcpe_trap_vector_tl1,#function +cheetah_plus_dcpe_trap_vector_tl1: + membar #Sync + wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate + sethi %hi(do_dcpe_tl1), %g3 + jmpl %g3 + %lo(do_dcpe_tl1), %g0 + nop + nop + nop + nop + .size cheetah_plus_dcpe_trap_vector_tl1,.-cheetah_plus_dcpe_trap_vector_tl1 + + .globl cheetah_plus_icpe_trap_vector + .type cheetah_plus_icpe_trap_vector,#function +cheetah_plus_icpe_trap_vector: + membar #Sync + sethi %hi(do_cheetah_plus_insn_parity), %g7 + jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0 + nop + nop + nop + nop + nop + .size cheetah_plus_icpe_trap_vector,.-cheetah_plus_icpe_trap_vector + + .type do_cheetah_plus_insn_parity,#function +do_cheetah_plus_insn_parity: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov 0x1, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 + ba,a,pt %xcc, rtrap_irq + .size do_cheetah_plus_insn_parity,.-do_cheetah_plus_insn_parity + + .globl cheetah_plus_icpe_trap_vector_tl1 + .type cheetah_plus_icpe_trap_vector_tl1,#function +cheetah_plus_icpe_trap_vector_tl1: + membar #Sync + wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate + sethi %hi(do_icpe_tl1), %g3 + jmpl %g3 + %lo(do_icpe_tl1), %g0 + nop + nop + nop + nop + .size cheetah_plus_icpe_trap_vector_tl1,.-cheetah_plus_icpe_trap_vector_tl1 + + /* If we take one of these traps when tl >= 1, then we + * jump to interrupt globals. If some trap level above us + * was also using interrupt globals, we cannot recover. + * We may use all interrupt global registers except %g6. + */ + .globl do_dcpe_tl1 + .type do_dcpe_tl1,#function +do_dcpe_tl1: + rdpr %tl, %g1 ! Save original trap level + mov 1, %g2 ! Setup TSTATE checking loop + sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit +1: wrpr %g2, %tl ! Set trap level to check + rdpr %tstate, %g4 ! Read TSTATE for this level + andcc %g4, %g3, %g0 ! Interrupt globals in use? + bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable + wrpr %g1, %tl ! Restore original trap level + add %g2, 1, %g2 ! Next trap level + cmp %g2, %g1 ! Hit them all yet? + ble,pt %icc, 1b ! Not yet + nop + wrpr %g1, %tl ! Restore original trap level +do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ + sethi %hi(dcache_parity_tl1_occurred), %g2 + lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1 + add %g1, 1, %g1 + stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)] + /* Reset D-cache parity */ + sethi %hi(1 << 16), %g1 ! D-cache size + mov (1 << 5), %g2 ! D-cache line size + sub %g1, %g2, %g1 ! Move down 1 cacheline +1: srl %g1, 14, %g3 ! Compute UTAG + membar #Sync + stxa %g3, [%g1] ASI_DCACHE_UTAG + membar #Sync + sub %g2, 8, %g3 ! 64-bit data word within line +2: membar #Sync + stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA + membar #Sync + subcc %g3, 8, %g3 ! Next 64-bit data word + bge,pt %icc, 2b + nop + subcc %g1, %g2, %g1 ! Next cacheline + bge,pt %icc, 1b + nop + ba,pt %xcc, dcpe_icpe_tl1_common + nop + +do_dcpe_tl1_fatal: + sethi %hi(1f), %g7 + ba,pt %xcc, etraptl1 +1: or %g7, %lo(1b), %g7 + mov 0x2, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 + ba,pt %xcc, rtrap + nop + .size do_dcpe_tl1,.-do_dcpe_tl1 + + .globl do_icpe_tl1 + .type do_icpe_tl1,#function +do_icpe_tl1: + rdpr %tl, %g1 ! Save original trap level + mov 1, %g2 ! Setup TSTATE checking loop + sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit +1: wrpr %g2, %tl ! Set trap level to check + rdpr %tstate, %g4 ! Read TSTATE for this level + andcc %g4, %g3, %g0 ! Interrupt globals in use? + bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable + wrpr %g1, %tl ! Restore original trap level + add %g2, 1, %g2 ! Next trap level + cmp %g2, %g1 ! Hit them all yet? + ble,pt %icc, 1b ! Not yet + nop + wrpr %g1, %tl ! Restore original trap level +do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ + sethi %hi(icache_parity_tl1_occurred), %g2 + lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1 + add %g1, 1, %g1 + stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)] + /* Flush I-cache */ + sethi %hi(1 << 15), %g1 ! I-cache size + mov (1 << 5), %g2 ! I-cache line size + sub %g1, %g2, %g1 +1: or %g1, (2 << 3), %g3 + stxa %g0, [%g3] ASI_IC_TAG + membar #Sync + subcc %g1, %g2, %g1 + bge,pt %icc, 1b + nop + ba,pt %xcc, dcpe_icpe_tl1_common + nop + +do_icpe_tl1_fatal: + sethi %hi(1f), %g7 + ba,pt %xcc, etraptl1 +1: or %g7, %lo(1b), %g7 + mov 0x3, %o0 + call cheetah_plus_parity_error + add %sp, PTREGS_OFF, %o1 + ba,pt %xcc, rtrap + nop + .size do_icpe_tl1,.-do_icpe_tl1 + + .type dcpe_icpe_tl1_common,#function +dcpe_icpe_tl1_common: + /* Flush D-cache, re-enable D/I caches in DCU and finally + * retry the trapping instruction. + */ + sethi %hi(1 << 16), %g1 ! D-cache size + mov (1 << 5), %g2 ! D-cache line size + sub %g1, %g2, %g1 +1: stxa %g0, [%g1] ASI_DCACHE_TAG + membar #Sync + subcc %g1, %g2, %g1 + bge,pt %icc, 1b + nop + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + or %g1, (DCU_DC | DCU_IC), %g1 + stxa %g1, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + retry + .size dcpe_icpe_tl1_common,.-dcpe_icpe_tl1_common + + /* Capture I/D/E-cache state into per-cpu error scoreboard. + * + * %g1: (TL>=0) ? 1 : 0 + * %g2: scratch + * %g3: scratch + * %g4: AFSR + * %g5: AFAR + * %g6: unused, will have current thread ptr after etrap + * %g7: scratch + */ + .type __cheetah_log_error,#function +__cheetah_log_error: + /* Put "TL1" software bit into AFSR. */ + and %g1, 0x1, %g1 + sllx %g1, 63, %g2 + or %g4, %g2, %g4 + + /* Get log entry pointer for this cpu at this trap level. */ + BRANCH_IF_JALAPENO(g2,g3,50f) + ldxa [%g0] ASI_SAFARI_CONFIG, %g2 + srlx %g2, 17, %g2 + ba,pt %xcc, 60f + and %g2, 0x3ff, %g2 + +50: ldxa [%g0] ASI_JBUS_CONFIG, %g2 + srlx %g2, 17, %g2 + and %g2, 0x1f, %g2 + +60: sllx %g2, 9, %g2 + sethi %hi(cheetah_error_log), %g3 + ldx [%g3 + %lo(cheetah_error_log)], %g3 + brz,pn %g3, 80f + nop + + add %g3, %g2, %g3 + sllx %g1, 8, %g1 + add %g3, %g1, %g1 + + /* %g1 holds pointer to the top of the logging scoreboard */ + ldx [%g1 + 0x0], %g7 + cmp %g7, -1 + bne,pn %xcc, 80f + nop + + stx %g4, [%g1 + 0x0] + stx %g5, [%g1 + 0x8] + add %g1, 0x10, %g1 + + /* %g1 now points to D-cache logging area */ + set 0x3ff8, %g2 /* DC_addr mask */ + and %g5, %g2, %g2 /* DC_addr bits of AFAR */ + srlx %g5, 12, %g3 + or %g3, 1, %g3 /* PHYS tag + valid */ + +10: ldxa [%g2] ASI_DCACHE_TAG, %g7 + cmp %g3, %g7 /* TAG match? */ + bne,pt %xcc, 13f + nop + + /* Yep, what we want, capture state. */ + stx %g2, [%g1 + 0x20] + stx %g7, [%g1 + 0x28] + + /* A membar Sync is required before and after utag access. */ + membar #Sync + ldxa [%g2] ASI_DCACHE_UTAG, %g7 + membar #Sync + stx %g7, [%g1 + 0x30] + ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7 + stx %g7, [%g1 + 0x38] + clr %g3 + +12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7 + stx %g7, [%g1] + add %g3, (1 << 5), %g3 + cmp %g3, (4 << 5) + bl,pt %xcc, 12b + add %g1, 0x8, %g1 + + ba,pt %xcc, 20f + add %g1, 0x20, %g1 + +13: sethi %hi(1 << 14), %g7 + add %g2, %g7, %g2 + srlx %g2, 14, %g7 + cmp %g7, 4 + bl,pt %xcc, 10b + nop + + add %g1, 0x40, %g1 + + /* %g1 now points to I-cache logging area */ +20: set 0x1fe0, %g2 /* IC_addr mask */ + and %g5, %g2, %g2 /* IC_addr bits of AFAR */ + sllx %g2, 1, %g2 /* IC_addr[13:6]==VA[12:5] */ + srlx %g5, (13 - 8), %g3 /* Make PTAG */ + andn %g3, 0xff, %g3 /* Mask off undefined bits */ + +21: ldxa [%g2] ASI_IC_TAG, %g7 + andn %g7, 0xff, %g7 + cmp %g3, %g7 + bne,pt %xcc, 23f + nop + + /* Yep, what we want, capture state. */ + stx %g2, [%g1 + 0x40] + stx %g7, [%g1 + 0x48] + add %g2, (1 << 3), %g2 + ldxa [%g2] ASI_IC_TAG, %g7 + add %g2, (1 << 3), %g2 + stx %g7, [%g1 + 0x50] + ldxa [%g2] ASI_IC_TAG, %g7 + add %g2, (1 << 3), %g2 + stx %g7, [%g1 + 0x60] + ldxa [%g2] ASI_IC_TAG, %g7 + stx %g7, [%g1 + 0x68] + sub %g2, (3 << 3), %g2 + ldxa [%g2] ASI_IC_STAG, %g7 + stx %g7, [%g1 + 0x58] + clr %g3 + srlx %g2, 2, %g2 + +22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7 + stx %g7, [%g1] + add %g3, (1 << 3), %g3 + cmp %g3, (8 << 3) + bl,pt %xcc, 22b + add %g1, 0x8, %g1 + + ba,pt %xcc, 30f + add %g1, 0x30, %g1 + +23: sethi %hi(1 << 14), %g7 + add %g2, %g7, %g2 + srlx %g2, 14, %g7 + cmp %g7, 4 + bl,pt %xcc, 21b + nop + + add %g1, 0x70, %g1 + + /* %g1 now points to E-cache logging area */ +30: andn %g5, (32 - 1), %g2 + stx %g2, [%g1 + 0x20] + ldxa [%g2] ASI_EC_TAG_DATA, %g7 + stx %g7, [%g1 + 0x28] + ldxa [%g2] ASI_EC_R, %g0 + clr %g3 + +31: ldxa [%g3] ASI_EC_DATA, %g7 + stx %g7, [%g1 + %g3] + add %g3, 0x8, %g3 + cmp %g3, 0x20 + + bl,pt %xcc, 31b + nop +80: + rdpr %tt, %g2 + cmp %g2, 0x70 + be c_fast_ecc + cmp %g2, 0x63 + be c_cee + nop + ba,pt %xcc, c_deferred + .size __cheetah_log_error,.-__cheetah_log_error + + /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc + * in the trap table. That code has done a memory barrier + * and has disabled both the I-cache and D-cache in the DCU + * control register. The I-cache is disabled so that we may + * capture the corrupted cache line, and the D-cache is disabled + * because corrupt data may have been placed there and we don't + * want to reference it. + * + * %g1 is one if this trap occurred at %tl >= 1. + * + * Next, we turn off error reporting so that we don't recurse. + */ + .globl cheetah_fast_ecc + .type cheetah_fast_ecc,#function +cheetah_fast_ecc: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + ba,pt %xcc, __cheetah_log_error + nop + .size cheetah_fast_ecc,.-cheetah_fast_ecc + + .type c_fast_ecc,#function +c_fast_ecc: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov %l4, %o1 + mov %l5, %o2 + call cheetah_fecc_handler + add %sp, PTREGS_OFF, %o0 + ba,a,pt %xcc, rtrap_irq + .size c_fast_ecc,.-c_fast_ecc + + /* Our caller has disabled I-cache and performed membar Sync. */ + .globl cheetah_cee + .type cheetah_cee,#function +cheetah_cee: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + ba,pt %xcc, __cheetah_log_error + nop + .size cheetah_cee,.-cheetah_cee + + .type c_cee,#function +c_cee: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov %l4, %o1 + mov %l5, %o2 + call cheetah_cee_handler + add %sp, PTREGS_OFF, %o0 + ba,a,pt %xcc, rtrap_irq + .size c_cee,.-c_cee + + /* Our caller has disabled I-cache+D-cache and performed membar Sync. */ + .globl cheetah_deferred_trap + .type cheetah_deferred_trap,#function +cheetah_deferred_trap: + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 + andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 + stxa %g2, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Fetch and clear AFSR/AFAR */ + ldxa [%g0] ASI_AFSR, %g4 + ldxa [%g0] ASI_AFAR, %g5 + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + ba,pt %xcc, __cheetah_log_error + nop + .size cheetah_deferred_trap,.-cheetah_deferred_trap + + .type c_deferred,#function +c_deferred: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov %l4, %o1 + mov %l5, %o2 + call cheetah_deferred_handler + add %sp, PTREGS_OFF, %o0 + ba,a,pt %xcc, rtrap_irq + .size c_deferred,.-c_deferred diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S deleted file mode 100644 index fd06e937ae1..00000000000 --- a/arch/sparc64/kernel/entry.S +++ /dev/null @@ -1,2575 +0,0 @@ -/* $Id: entry.S,v 1.144 2002/02/09 19:49:30 davem Exp $ - * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. - * - * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include <linux/errno.h> - -#include <asm/head.h> -#include <asm/asi.h> -#include <asm/smp.h> -#include <asm/ptrace.h> -#include <asm/page.h> -#include <asm/signal.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/visasm.h> -#include <asm/estate.h> -#include <asm/auxio.h> -#include <asm/sfafsr.h> -#include <asm/pil.h> -#include <asm/unistd.h> - -#define curptr g6 - - .text - .align 32 - - /* This is trivial with the new code... */ - .globl do_fpdis -do_fpdis: - sethi %hi(TSTATE_PEF), %g4 - rdpr %tstate, %g5 - andcc %g5, %g4, %g0 - be,pt %xcc, 1f - nop - rd %fprs, %g5 - andcc %g5, FPRS_FEF, %g0 - be,pt %xcc, 1f - nop - - /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */ - sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - add %g0, %g0, %g0 - ba,a,pt %xcc, rtrap - -1: TRAP_LOAD_THREAD_REG(%g6, %g1) - ldub [%g6 + TI_FPSAVED], %g5 - wr %g0, FPRS_FEF, %fprs - andcc %g5, FPRS_FEF, %g0 - be,a,pt %icc, 1f - clr %g7 - ldx [%g6 + TI_GSR], %g7 -1: andcc %g5, FPRS_DL, %g0 - bne,pn %icc, 2f - fzero %f0 - andcc %g5, FPRS_DU, %g0 - bne,pn %icc, 1f - fzero %f2 - faddd %f0, %f2, %f4 - fmuld %f0, %f2, %f6 - faddd %f0, %f2, %f8 - fmuld %f0, %f2, %f10 - faddd %f0, %f2, %f12 - fmuld %f0, %f2, %f14 - faddd %f0, %f2, %f16 - fmuld %f0, %f2, %f18 - faddd %f0, %f2, %f20 - fmuld %f0, %f2, %f22 - faddd %f0, %f2, %f24 - fmuld %f0, %f2, %f26 - faddd %f0, %f2, %f28 - fmuld %f0, %f2, %f30 - faddd %f0, %f2, %f32 - fmuld %f0, %f2, %f34 - faddd %f0, %f2, %f36 - fmuld %f0, %f2, %f38 - faddd %f0, %f2, %f40 - fmuld %f0, %f2, %f42 - faddd %f0, %f2, %f44 - fmuld %f0, %f2, %f46 - faddd %f0, %f2, %f48 - fmuld %f0, %f2, %f50 - faddd %f0, %f2, %f52 - fmuld %f0, %f2, %f54 - faddd %f0, %f2, %f56 - fmuld %f0, %f2, %f58 - b,pt %xcc, fpdis_exit2 - faddd %f0, %f2, %f60 -1: mov SECONDARY_CONTEXT, %g3 - add %g6, TI_FPREGS + 0x80, %g1 - faddd %f0, %f2, %f4 - fmuld %f0, %f2, %f6 - -661: ldxa [%g3] ASI_DMMU, %g5 - .section .sun4v_1insn_patch, "ax" - .word 661b - ldxa [%g3] ASI_MMU, %g5 - .previous - - sethi %hi(sparc64_kern_sec_context), %g2 - ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 - -661: stxa %g2, [%g3] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g2, [%g3] ASI_MMU - .previous - - membar #Sync - add %g6, TI_FPREGS + 0xc0, %g2 - faddd %f0, %f2, %f8 - fmuld %f0, %f2, %f10 - membar #Sync - ldda [%g1] ASI_BLK_S, %f32 - ldda [%g2] ASI_BLK_S, %f48 - membar #Sync - faddd %f0, %f2, %f12 - fmuld %f0, %f2, %f14 - faddd %f0, %f2, %f16 - fmuld %f0, %f2, %f18 - faddd %f0, %f2, %f20 - fmuld %f0, %f2, %f22 - faddd %f0, %f2, %f24 - fmuld %f0, %f2, %f26 - faddd %f0, %f2, %f28 - fmuld %f0, %f2, %f30 - b,pt %xcc, fpdis_exit - nop -2: andcc %g5, FPRS_DU, %g0 - bne,pt %icc, 3f - fzero %f32 - mov SECONDARY_CONTEXT, %g3 - fzero %f34 - -661: ldxa [%g3] ASI_DMMU, %g5 - .section .sun4v_1insn_patch, "ax" - .word 661b - ldxa [%g3] ASI_MMU, %g5 - .previous - - add %g6, TI_FPREGS, %g1 - sethi %hi(sparc64_kern_sec_context), %g2 - ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 - -661: stxa %g2, [%g3] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g2, [%g3] ASI_MMU - .previous - - membar #Sync - add %g6, TI_FPREGS + 0x40, %g2 - faddd %f32, %f34, %f36 - fmuld %f32, %f34, %f38 - membar #Sync - ldda [%g1] ASI_BLK_S, %f0 - ldda [%g2] ASI_BLK_S, %f16 - membar #Sync - faddd %f32, %f34, %f40 - fmuld %f32, %f34, %f42 - faddd %f32, %f34, %f44 - fmuld %f32, %f34, %f46 - faddd %f32, %f34, %f48 - fmuld %f32, %f34, %f50 - faddd %f32, %f34, %f52 - fmuld %f32, %f34, %f54 - faddd %f32, %f34, %f56 - fmuld %f32, %f34, %f58 - faddd %f32, %f34, %f60 - fmuld %f32, %f34, %f62 - ba,pt %xcc, fpdis_exit - nop -3: mov SECONDARY_CONTEXT, %g3 - add %g6, TI_FPREGS, %g1 - -661: ldxa [%g3] ASI_DMMU, %g5 - .section .sun4v_1insn_patch, "ax" - .word 661b - ldxa [%g3] ASI_MMU, %g5 - .previous - - sethi %hi(sparc64_kern_sec_context), %g2 - ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 - -661: stxa %g2, [%g3] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g2, [%g3] ASI_MMU - .previous - - membar #Sync - mov 0x40, %g2 - membar #Sync - ldda [%g1] ASI_BLK_S, %f0 - ldda [%g1 + %g2] ASI_BLK_S, %f16 - add %g1, 0x80, %g1 - ldda [%g1] ASI_BLK_S, %f32 - ldda [%g1 + %g2] ASI_BLK_S, %f48 - membar #Sync -fpdis_exit: - -661: stxa %g5, [%g3] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g5, [%g3] ASI_MMU - .previous - - membar #Sync -fpdis_exit2: - wr %g7, 0, %gsr - ldx [%g6 + TI_XFSR], %fsr - rdpr %tstate, %g3 - or %g3, %g4, %g3 ! anal... - wrpr %g3, %tstate - wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits - retry - - .align 32 -fp_other_bounce: - call do_fpother - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl do_fpother_check_fitos - .align 32 -do_fpother_check_fitos: - TRAP_LOAD_THREAD_REG(%g6, %g1) - sethi %hi(fp_other_bounce - 4), %g7 - or %g7, %lo(fp_other_bounce - 4), %g7 - - /* NOTE: Need to preserve %g7 until we fully commit - * to the fitos fixup. - */ - stx %fsr, [%g6 + TI_XFSR] - rdpr %tstate, %g3 - andcc %g3, TSTATE_PRIV, %g0 - bne,pn %xcc, do_fptrap_after_fsr - nop - ldx [%g6 + TI_XFSR], %g3 - srlx %g3, 14, %g1 - and %g1, 7, %g1 - cmp %g1, 2 ! Unfinished FP-OP - bne,pn %xcc, do_fptrap_after_fsr - sethi %hi(1 << 23), %g1 ! Inexact - andcc %g3, %g1, %g0 - bne,pn %xcc, do_fptrap_after_fsr - rdpr %tpc, %g1 - lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail -#define FITOS_MASK 0xc1f83fe0 -#define FITOS_COMPARE 0x81a01880 - sethi %hi(FITOS_MASK), %g1 - or %g1, %lo(FITOS_MASK), %g1 - and %g3, %g1, %g1 - sethi %hi(FITOS_COMPARE), %g2 - or %g2, %lo(FITOS_COMPARE), %g2 - cmp %g1, %g2 - bne,pn %xcc, do_fptrap_after_fsr - nop - std %f62, [%g6 + TI_FPREGS + (62 * 4)] - sethi %hi(fitos_table_1), %g1 - and %g3, 0x1f, %g2 - or %g1, %lo(fitos_table_1), %g1 - sllx %g2, 2, %g2 - jmpl %g1 + %g2, %g0 - ba,pt %xcc, fitos_emul_continue - -fitos_table_1: - fitod %f0, %f62 - fitod %f1, %f62 - fitod %f2, %f62 - fitod %f3, %f62 - fitod %f4, %f62 - fitod %f5, %f62 - fitod %f6, %f62 - fitod %f7, %f62 - fitod %f8, %f62 - fitod %f9, %f62 - fitod %f10, %f62 - fitod %f11, %f62 - fitod %f12, %f62 - fitod %f13, %f62 - fitod %f14, %f62 - fitod %f15, %f62 - fitod %f16, %f62 - fitod %f17, %f62 - fitod %f18, %f62 - fitod %f19, %f62 - fitod %f20, %f62 - fitod %f21, %f62 - fitod %f22, %f62 - fitod %f23, %f62 - fitod %f24, %f62 - fitod %f25, %f62 - fitod %f26, %f62 - fitod %f27, %f62 - fitod %f28, %f62 - fitod %f29, %f62 - fitod %f30, %f62 - fitod %f31, %f62 - -fitos_emul_continue: - sethi %hi(fitos_table_2), %g1 - srl %g3, 25, %g2 - or %g1, %lo(fitos_table_2), %g1 - and %g2, 0x1f, %g2 - sllx %g2, 2, %g2 - jmpl %g1 + %g2, %g0 - ba,pt %xcc, fitos_emul_fini - -fitos_table_2: - fdtos %f62, %f0 - fdtos %f62, %f1 - fdtos %f62, %f2 - fdtos %f62, %f3 - fdtos %f62, %f4 - fdtos %f62, %f5 - fdtos %f62, %f6 - fdtos %f62, %f7 - fdtos %f62, %f8 - fdtos %f62, %f9 - fdtos %f62, %f10 - fdtos %f62, %f11 - fdtos %f62, %f12 - fdtos %f62, %f13 - fdtos %f62, %f14 - fdtos %f62, %f15 - fdtos %f62, %f16 - fdtos %f62, %f17 - fdtos %f62, %f18 - fdtos %f62, %f19 - fdtos %f62, %f20 - fdtos %f62, %f21 - fdtos %f62, %f22 - fdtos %f62, %f23 - fdtos %f62, %f24 - fdtos %f62, %f25 - fdtos %f62, %f26 - fdtos %f62, %f27 - fdtos %f62, %f28 - fdtos %f62, %f29 - fdtos %f62, %f30 - fdtos %f62, %f31 - -fitos_emul_fini: - ldd [%g6 + TI_FPREGS + (62 * 4)], %f62 - done - - .globl do_fptrap - .align 32 -do_fptrap: - TRAP_LOAD_THREAD_REG(%g6, %g1) - stx %fsr, [%g6 + TI_XFSR] -do_fptrap_after_fsr: - ldub [%g6 + TI_FPSAVED], %g3 - rd %fprs, %g1 - or %g3, %g1, %g3 - stb %g3, [%g6 + TI_FPSAVED] - rd %gsr, %g3 - stx %g3, [%g6 + TI_GSR] - mov SECONDARY_CONTEXT, %g3 - -661: ldxa [%g3] ASI_DMMU, %g5 - .section .sun4v_1insn_patch, "ax" - .word 661b - ldxa [%g3] ASI_MMU, %g5 - .previous - - sethi %hi(sparc64_kern_sec_context), %g2 - ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 - -661: stxa %g2, [%g3] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g2, [%g3] ASI_MMU - .previous - - membar #Sync - add %g6, TI_FPREGS, %g2 - andcc %g1, FPRS_DL, %g0 - be,pn %icc, 4f - mov 0x40, %g3 - stda %f0, [%g2] ASI_BLK_S - stda %f16, [%g2 + %g3] ASI_BLK_S - andcc %g1, FPRS_DU, %g0 - be,pn %icc, 5f -4: add %g2, 128, %g2 - stda %f32, [%g2] ASI_BLK_S - stda %f48, [%g2 + %g3] ASI_BLK_S -5: mov SECONDARY_CONTEXT, %g1 - membar #Sync - -661: stxa %g5, [%g1] ASI_DMMU - .section .sun4v_1insn_patch, "ax" - .word 661b - stxa %g5, [%g1] ASI_MMU - .previous - - membar #Sync - ba,pt %xcc, etrap - wr %g0, 0, %fprs - - /* The registers for cross calls will be: - * - * DATA 0: [low 32-bits] Address of function to call, jmp to this - * [high 32-bits] MMU Context Argument 0, place in %g5 - * DATA 1: Address Argument 1, place in %g1 - * DATA 2: Address Argument 2, place in %g7 - * - * With this method we can do most of the cross-call tlb/cache - * flushing very quickly. - */ - .text - .align 32 - .globl do_ivec -do_ivec: - mov 0x40, %g3 - ldxa [%g3 + %g0] ASI_INTR_R, %g3 - sethi %hi(KERNBASE), %g4 - cmp %g3, %g4 - bgeu,pn %xcc, do_ivec_xcall - srlx %g3, 32, %g5 - stxa %g0, [%g0] ASI_INTR_RECEIVE - membar #Sync - - sethi %hi(ivector_table_pa), %g2 - ldx [%g2 + %lo(ivector_table_pa)], %g2 - sllx %g3, 4, %g3 - add %g2, %g3, %g3 - - TRAP_LOAD_IRQ_WORK_PA(%g6, %g1) - - ldx [%g6], %g5 - stxa %g5, [%g3] ASI_PHYS_USE_EC - stx %g3, [%g6] - wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint - retry -do_ivec_xcall: - mov 0x50, %g1 - ldxa [%g1 + %g0] ASI_INTR_R, %g1 - srl %g3, 0, %g3 - - mov 0x60, %g7 - ldxa [%g7 + %g0] ASI_INTR_R, %g7 - stxa %g0, [%g0] ASI_INTR_RECEIVE - membar #Sync - ba,pt %xcc, 1f - nop - - .align 32 -1: jmpl %g3, %g0 - nop - - .globl getcc, setcc -getcc: - ldx [%o0 + PT_V9_TSTATE], %o1 - srlx %o1, 32, %o1 - and %o1, 0xf, %o1 - retl - stx %o1, [%o0 + PT_V9_G1] -setcc: - ldx [%o0 + PT_V9_TSTATE], %o1 - ldx [%o0 + PT_V9_G1], %o2 - or %g0, %ulo(TSTATE_ICC), %o3 - sllx %o3, 32, %o3 - andn %o1, %o3, %o1 - sllx %o2, 32, %o2 - and %o2, %o3, %o2 - or %o1, %o2, %o1 - retl - stx %o1, [%o0 + PT_V9_TSTATE] - - .globl utrap_trap -utrap_trap: /* %g3=handler,%g4=level */ - TRAP_LOAD_THREAD_REG(%g6, %g1) - ldx [%g6 + TI_UTRAPS], %g1 - brnz,pt %g1, invoke_utrap - nop - - ba,pt %xcc, etrap - rd %pc, %g7 - mov %l4, %o1 - call bad_trap - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - -invoke_utrap: - sllx %g3, 3, %g3 - ldx [%g1 + %g3], %g1 - save %sp, -128, %sp - rdpr %tstate, %l6 - rdpr %cwp, %l7 - andn %l6, TSTATE_CWP, %l6 - wrpr %l6, %l7, %tstate - rdpr %tpc, %l6 - rdpr %tnpc, %l7 - wrpr %g1, 0, %tnpc - done - - /* We need to carefully read the error status, ACK - * the errors, prevent recursive traps, and pass the - * information on to C code for logging. - * - * We pass the AFAR in as-is, and we encode the status - * information as described in asm-sparc64/sfafsr.h - */ - .globl __spitfire_access_error -__spitfire_access_error: - /* Disable ESTATE error reporting so that we do not - * take recursive traps and RED state the processor. - */ - stxa %g0, [%g0] ASI_ESTATE_ERROR_EN - membar #Sync - - mov UDBE_UE, %g1 - ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR - - /* __spitfire_cee_trap branches here with AFSR in %g4 and - * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the - * ESTATE Error Enable register. - */ -__spitfire_cee_trap_continue: - ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR - - rdpr %tt, %g3 - and %g3, 0x1ff, %g3 ! Paranoia - sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 - or %g4, %g3, %g4 - rdpr %tl, %g3 - cmp %g3, 1 - mov 1, %g3 - bleu %xcc, 1f - sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 - - or %g4, %g3, %g4 - - /* Read in the UDB error register state, clearing the - * sticky error bits as-needed. We only clear them if - * the UE bit is set. Likewise, __spitfire_cee_trap - * below will only do so if the CE bit is set. - * - * NOTE: UltraSparc-I/II have high and low UDB error - * registers, corresponding to the two UDB units - * present on those chips. UltraSparc-IIi only - * has a single UDB, called "SDB" in the manual. - * For IIi the upper UDB register always reads - * as zero so for our purposes things will just - * work with the checks below. - */ -1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 - and %g3, 0x3ff, %g7 ! Paranoia - sllx %g7, SFSTAT_UDBH_SHIFT, %g7 - or %g4, %g7, %g4 - andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE - be,pn %xcc, 1f - nop - stxa %g3, [%g0] ASI_UDB_ERROR_W - membar #Sync - -1: mov 0x18, %g3 - ldxa [%g3] ASI_UDBL_ERROR_R, %g3 - and %g3, 0x3ff, %g7 ! Paranoia - sllx %g7, SFSTAT_UDBL_SHIFT, %g7 - or %g4, %g7, %g4 - andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE - be,pn %xcc, 1f - nop - mov 0x18, %g7 - stxa %g3, [%g7] ASI_UDB_ERROR_W - membar #Sync - -1: /* Ok, now that we've latched the error state, - * clear the sticky bits in the AFSR. - */ - stxa %g4, [%g0] ASI_AFSR - membar #Sync - - rdpr %tl, %g2 - cmp %g2, 1 - rdpr %pil, %g2 - bleu,pt %xcc, 1f - wrpr %g0, 15, %pil - - ba,pt %xcc, etraptl1 - rd %pc, %g7 - - ba,pt %xcc, 2f - nop - -1: ba,pt %xcc, etrap_irq - rd %pc, %g7 - -2: -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov %l4, %o1 - mov %l5, %o2 - call spitfire_access_error - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - /* This is the trap handler entry point for ECC correctable - * errors. They are corrected, but we listen for the trap - * so that the event can be logged. - * - * Disrupting errors are either: - * 1) single-bit ECC errors during UDB reads to system - * memory - * 2) data parity errors during write-back events - * - * As far as I can make out from the manual, the CEE trap - * is only for correctable errors during memory read - * accesses by the front-end of the processor. - * - * The code below is only for trap level 1 CEE events, - * as it is the only situation where we can safely record - * and log. For trap level >1 we just clear the CE bit - * in the AFSR and return. - * - * This is just like __spiftire_access_error above, but it - * specifically handles correctable errors. If an - * uncorrectable error is indicated in the AFSR we - * will branch directly above to __spitfire_access_error - * to handle it instead. Uncorrectable therefore takes - * priority over correctable, and the error logging - * C code will notice this case by inspecting the - * trap type. - */ - .globl __spitfire_cee_trap -__spitfire_cee_trap: - ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR - mov 1, %g3 - sllx %g3, SFAFSR_UE_SHIFT, %g3 - andcc %g4, %g3, %g0 ! Check for UE - bne,pn %xcc, __spitfire_access_error - nop - - /* Ok, in this case we only have a correctable error. - * Indicate we only wish to capture that state in register - * %g1, and we only disable CE error reporting unlike UE - * handling which disables all errors. - */ - ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 - andn %g3, ESTATE_ERR_CE, %g3 - stxa %g3, [%g0] ASI_ESTATE_ERROR_EN - membar #Sync - - /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ - ba,pt %xcc, __spitfire_cee_trap_continue - mov UDBE_CE, %g1 - - .globl __spitfire_data_access_exception - .globl __spitfire_data_access_exception_tl1 -__spitfire_data_access_exception_tl1: - rdpr %pstate, %g4 - wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate - mov TLB_SFSR, %g3 - mov DMMU_SFAR, %g5 - ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR - ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR - stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit - membar #Sync - rdpr %tt, %g3 - cmp %g3, 0x80 ! first win spill/fill trap - blu,pn %xcc, 1f - cmp %g3, 0xff ! last win spill/fill trap - bgu,pn %xcc, 1f - nop - ba,pt %xcc, winfix_dax - rdpr %tpc, %g3 -1: sethi %hi(109f), %g7 - ba,pt %xcc, etraptl1 -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call spitfire_data_access_exception_tl1 - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - -__spitfire_data_access_exception: - rdpr %pstate, %g4 - wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate - mov TLB_SFSR, %g3 - mov DMMU_SFAR, %g5 - ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR - ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR - stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit - membar #Sync - sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call spitfire_data_access_exception - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl __spitfire_insn_access_exception - .globl __spitfire_insn_access_exception_tl1 -__spitfire_insn_access_exception_tl1: - rdpr %pstate, %g4 - wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate - mov TLB_SFSR, %g3 - ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR - rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC - stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit - membar #Sync - sethi %hi(109f), %g7 - ba,pt %xcc, etraptl1 -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call spitfire_insn_access_exception_tl1 - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - -__spitfire_insn_access_exception: - rdpr %pstate, %g4 - wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate - mov TLB_SFSR, %g3 - ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR - rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC - stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit - membar #Sync - sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call spitfire_insn_access_exception - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - /* These get patched into the trap table at boot time - * once we know we have a cheetah processor. - */ - .globl cheetah_fecc_trap_vector, cheetah_fecc_trap_vector_tl1 -cheetah_fecc_trap_vector: - membar #Sync - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 - andn %g1, DCU_DC | DCU_IC, %g1 - stxa %g1, [%g0] ASI_DCU_CONTROL_REG - membar #Sync - sethi %hi(cheetah_fast_ecc), %g2 - jmpl %g2 + %lo(cheetah_fast_ecc), %g0 - mov 0, %g1 -cheetah_fecc_trap_vector_tl1: - membar #Sync - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 - andn %g1, DCU_DC | DCU_IC, %g1 - stxa %g1, [%g0] ASI_DCU_CONTROL_REG - membar #Sync - sethi %hi(cheetah_fast_ecc), %g2 - jmpl %g2 + %lo(cheetah_fast_ecc), %g0 - mov 1, %g1 - .globl cheetah_cee_trap_vector, cheetah_cee_trap_vector_tl1 -cheetah_cee_trap_vector: - membar #Sync - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 - andn %g1, DCU_IC, %g1 - stxa %g1, [%g0] ASI_DCU_CONTROL_REG - membar #Sync - sethi %hi(cheetah_cee), %g2 - jmpl %g2 + %lo(cheetah_cee), %g0 - mov 0, %g1 -cheetah_cee_trap_vector_tl1: - membar #Sync - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 - andn %g1, DCU_IC, %g1 - stxa %g1, [%g0] ASI_DCU_CONTROL_REG - membar #Sync - sethi %hi(cheetah_cee), %g2 - jmpl %g2 + %lo(cheetah_cee), %g0 - mov 1, %g1 - .globl cheetah_deferred_trap_vector, cheetah_deferred_trap_vector_tl1 -cheetah_deferred_trap_vector: - membar #Sync - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; - andn %g1, DCU_DC | DCU_IC, %g1; - stxa %g1, [%g0] ASI_DCU_CONTROL_REG; - membar #Sync; - sethi %hi(cheetah_deferred_trap), %g2 - jmpl %g2 + %lo(cheetah_deferred_trap), %g0 - mov 0, %g1 -cheetah_deferred_trap_vector_tl1: - membar #Sync; - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1; - andn %g1, DCU_DC | DCU_IC, %g1; - stxa %g1, [%g0] ASI_DCU_CONTROL_REG; - membar #Sync; - sethi %hi(cheetah_deferred_trap), %g2 - jmpl %g2 + %lo(cheetah_deferred_trap), %g0 - mov 1, %g1 - - /* Cheetah+ specific traps. These are for the new I/D cache parity - * error traps. The first argument to cheetah_plus_parity_handler - * is encoded as follows: - * - * Bit0: 0=dcache,1=icache - * Bit1: 0=recoverable,1=unrecoverable - */ - .globl cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1 -cheetah_plus_dcpe_trap_vector: - membar #Sync - sethi %hi(do_cheetah_plus_data_parity), %g7 - jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0 - nop - nop - nop - nop - nop - -do_cheetah_plus_data_parity: - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov 0x0, %o0 - call cheetah_plus_parity_error - add %sp, PTREGS_OFF, %o1 - ba,a,pt %xcc, rtrap_irq - -cheetah_plus_dcpe_trap_vector_tl1: - membar #Sync - wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate - sethi %hi(do_dcpe_tl1), %g3 - jmpl %g3 + %lo(do_dcpe_tl1), %g0 - nop - nop - nop - nop - - .globl cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1 -cheetah_plus_icpe_trap_vector: - membar #Sync - sethi %hi(do_cheetah_plus_insn_parity), %g7 - jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0 - nop - nop - nop - nop - nop - -do_cheetah_plus_insn_parity: - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov 0x1, %o0 - call cheetah_plus_parity_error - add %sp, PTREGS_OFF, %o1 - ba,a,pt %xcc, rtrap_irq - -cheetah_plus_icpe_trap_vector_tl1: - membar #Sync - wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate - sethi %hi(do_icpe_tl1), %g3 - jmpl %g3 + %lo(do_icpe_tl1), %g0 - nop - nop - nop - nop - - /* If we take one of these traps when tl >= 1, then we - * jump to interrupt globals. If some trap level above us - * was also using interrupt globals, we cannot recover. - * We may use all interrupt global registers except %g6. - */ - .globl do_dcpe_tl1, do_icpe_tl1 -do_dcpe_tl1: - rdpr %tl, %g1 ! Save original trap level - mov 1, %g2 ! Setup TSTATE checking loop - sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit -1: wrpr %g2, %tl ! Set trap level to check - rdpr %tstate, %g4 ! Read TSTATE for this level - andcc %g4, %g3, %g0 ! Interrupt globals in use? - bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable - wrpr %g1, %tl ! Restore original trap level - add %g2, 1, %g2 ! Next trap level - cmp %g2, %g1 ! Hit them all yet? - ble,pt %icc, 1b ! Not yet - nop - wrpr %g1, %tl ! Restore original trap level -do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ - sethi %hi(dcache_parity_tl1_occurred), %g2 - lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1 - add %g1, 1, %g1 - stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)] - /* Reset D-cache parity */ - sethi %hi(1 << 16), %g1 ! D-cache size - mov (1 << 5), %g2 ! D-cache line size - sub %g1, %g2, %g1 ! Move down 1 cacheline -1: srl %g1, 14, %g3 ! Compute UTAG - membar #Sync - stxa %g3, [%g1] ASI_DCACHE_UTAG - membar #Sync - sub %g2, 8, %g3 ! 64-bit data word within line -2: membar #Sync - stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA - membar #Sync - subcc %g3, 8, %g3 ! Next 64-bit data word - bge,pt %icc, 2b - nop - subcc %g1, %g2, %g1 ! Next cacheline - bge,pt %icc, 1b - nop - ba,pt %xcc, dcpe_icpe_tl1_common - nop - -do_dcpe_tl1_fatal: - sethi %hi(1f), %g7 - ba,pt %xcc, etraptl1 -1: or %g7, %lo(1b), %g7 - mov 0x2, %o0 - call cheetah_plus_parity_error - add %sp, PTREGS_OFF, %o1 - ba,pt %xcc, rtrap - nop - -do_icpe_tl1: - rdpr %tl, %g1 ! Save original trap level - mov 1, %g2 ! Setup TSTATE checking loop - sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit -1: wrpr %g2, %tl ! Set trap level to check - rdpr %tstate, %g4 ! Read TSTATE for this level - andcc %g4, %g3, %g0 ! Interrupt globals in use? - bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable - wrpr %g1, %tl ! Restore original trap level - add %g2, 1, %g2 ! Next trap level - cmp %g2, %g1 ! Hit them all yet? - ble,pt %icc, 1b ! Not yet - nop - wrpr %g1, %tl ! Restore original trap level -do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */ - sethi %hi(icache_parity_tl1_occurred), %g2 - lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1 - add %g1, 1, %g1 - stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)] - /* Flush I-cache */ - sethi %hi(1 << 15), %g1 ! I-cache size - mov (1 << 5), %g2 ! I-cache line size - sub %g1, %g2, %g1 -1: or %g1, (2 << 3), %g3 - stxa %g0, [%g3] ASI_IC_TAG - membar #Sync - subcc %g1, %g2, %g1 - bge,pt %icc, 1b - nop - ba,pt %xcc, dcpe_icpe_tl1_common - nop - -do_icpe_tl1_fatal: - sethi %hi(1f), %g7 - ba,pt %xcc, etraptl1 -1: or %g7, %lo(1b), %g7 - mov 0x3, %o0 - call cheetah_plus_parity_error - add %sp, PTREGS_OFF, %o1 - ba,pt %xcc, rtrap - nop - -dcpe_icpe_tl1_common: - /* Flush D-cache, re-enable D/I caches in DCU and finally - * retry the trapping instruction. - */ - sethi %hi(1 << 16), %g1 ! D-cache size - mov (1 << 5), %g2 ! D-cache line size - sub %g1, %g2, %g1 -1: stxa %g0, [%g1] ASI_DCACHE_TAG - membar #Sync - subcc %g1, %g2, %g1 - bge,pt %icc, 1b - nop - ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 - or %g1, (DCU_DC | DCU_IC), %g1 - stxa %g1, [%g0] ASI_DCU_CONTROL_REG - membar #Sync - retry - - /* Capture I/D/E-cache state into per-cpu error scoreboard. - * - * %g1: (TL>=0) ? 1 : 0 - * %g2: scratch - * %g3: scratch - * %g4: AFSR - * %g5: AFAR - * %g6: unused, will have current thread ptr after etrap - * %g7: scratch - */ -__cheetah_log_error: - /* Put "TL1" software bit into AFSR. */ - and %g1, 0x1, %g1 - sllx %g1, 63, %g2 - or %g4, %g2, %g4 - - /* Get log entry pointer for this cpu at this trap level. */ - BRANCH_IF_JALAPENO(g2,g3,50f) - ldxa [%g0] ASI_SAFARI_CONFIG, %g2 - srlx %g2, 17, %g2 - ba,pt %xcc, 60f - and %g2, 0x3ff, %g2 - -50: ldxa [%g0] ASI_JBUS_CONFIG, %g2 - srlx %g2, 17, %g2 - and %g2, 0x1f, %g2 - -60: sllx %g2, 9, %g2 - sethi %hi(cheetah_error_log), %g3 - ldx [%g3 + %lo(cheetah_error_log)], %g3 - brz,pn %g3, 80f - nop - - add %g3, %g2, %g3 - sllx %g1, 8, %g1 - add %g3, %g1, %g1 - - /* %g1 holds pointer to the top of the logging scoreboard */ - ldx [%g1 + 0x0], %g7 - cmp %g7, -1 - bne,pn %xcc, 80f - nop - - stx %g4, [%g1 + 0x0] - stx %g5, [%g1 + 0x8] - add %g1, 0x10, %g1 - - /* %g1 now points to D-cache logging area */ - set 0x3ff8, %g2 /* DC_addr mask */ - and %g5, %g2, %g2 /* DC_addr bits of AFAR */ - srlx %g5, 12, %g3 - or %g3, 1, %g3 /* PHYS tag + valid */ - -10: ldxa [%g2] ASI_DCACHE_TAG, %g7 - cmp %g3, %g7 /* TAG match? */ - bne,pt %xcc, 13f - nop - - /* Yep, what we want, capture state. */ - stx %g2, [%g1 + 0x20] - stx %g7, [%g1 + 0x28] - - /* A membar Sync is required before and after utag access. */ - membar #Sync - ldxa [%g2] ASI_DCACHE_UTAG, %g7 - membar #Sync - stx %g7, [%g1 + 0x30] - ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7 - stx %g7, [%g1 + 0x38] - clr %g3 - -12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7 - stx %g7, [%g1] - add %g3, (1 << 5), %g3 - cmp %g3, (4 << 5) - bl,pt %xcc, 12b - add %g1, 0x8, %g1 - - ba,pt %xcc, 20f - add %g1, 0x20, %g1 - -13: sethi %hi(1 << 14), %g7 - add %g2, %g7, %g2 - srlx %g2, 14, %g7 - cmp %g7, 4 - bl,pt %xcc, 10b - nop - - add %g1, 0x40, %g1 - - /* %g1 now points to I-cache logging area */ -20: set 0x1fe0, %g2 /* IC_addr mask */ - and %g5, %g2, %g2 /* IC_addr bits of AFAR */ - sllx %g2, 1, %g2 /* IC_addr[13:6]==VA[12:5] */ - srlx %g5, (13 - 8), %g3 /* Make PTAG */ - andn %g3, 0xff, %g3 /* Mask off undefined bits */ - -21: ldxa [%g2] ASI_IC_TAG, %g7 - andn %g7, 0xff, %g7 - cmp %g3, %g7 - bne,pt %xcc, 23f - nop - - /* Yep, what we want, capture state. */ - stx %g2, [%g1 + 0x40] - stx %g7, [%g1 + 0x48] - add %g2, (1 << 3), %g2 - ldxa [%g2] ASI_IC_TAG, %g7 - add %g2, (1 << 3), %g2 - stx %g7, [%g1 + 0x50] - ldxa [%g2] ASI_IC_TAG, %g7 - add %g2, (1 << 3), %g2 - stx %g7, [%g1 + 0x60] - ldxa [%g2] ASI_IC_TAG, %g7 - stx %g7, [%g1 + 0x68] - sub %g2, (3 << 3), %g2 - ldxa [%g2] ASI_IC_STAG, %g7 - stx %g7, [%g1 + 0x58] - clr %g3 - srlx %g2, 2, %g2 - -22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7 - stx %g7, [%g1] - add %g3, (1 << 3), %g3 - cmp %g3, (8 << 3) - bl,pt %xcc, 22b - add %g1, 0x8, %g1 - - ba,pt %xcc, 30f - add %g1, 0x30, %g1 - -23: sethi %hi(1 << 14), %g7 - add %g2, %g7, %g2 - srlx %g2, 14, %g7 - cmp %g7, 4 - bl,pt %xcc, 21b - nop - - add %g1, 0x70, %g1 - - /* %g1 now points to E-cache logging area */ -30: andn %g5, (32 - 1), %g2 - stx %g2, [%g1 + 0x20] - ldxa [%g2] ASI_EC_TAG_DATA, %g7 - stx %g7, [%g1 + 0x28] - ldxa [%g2] ASI_EC_R, %g0 - clr %g3 - -31: ldxa [%g3] ASI_EC_DATA, %g7 - stx %g7, [%g1 + %g3] - add %g3, 0x8, %g3 - cmp %g3, 0x20 - - bl,pt %xcc, 31b - nop -80: - rdpr %tt, %g2 - cmp %g2, 0x70 - be c_fast_ecc - cmp %g2, 0x63 - be c_cee - nop - ba,pt %xcc, c_deferred - - /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc - * in the trap table. That code has done a memory barrier - * and has disabled both the I-cache and D-cache in the DCU - * control register. The I-cache is disabled so that we may - * capture the corrupted cache line, and the D-cache is disabled - * because corrupt data may have been placed there and we don't - * want to reference it. - * - * %g1 is one if this trap occurred at %tl >= 1. - * - * Next, we turn off error reporting so that we don't recurse. - */ - .globl cheetah_fast_ecc -cheetah_fast_ecc: - ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 - andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 - stxa %g2, [%g0] ASI_ESTATE_ERROR_EN - membar #Sync - - /* Fetch and clear AFSR/AFAR */ - ldxa [%g0] ASI_AFSR, %g4 - ldxa [%g0] ASI_AFAR, %g5 - stxa %g4, [%g0] ASI_AFSR - membar #Sync - - ba,pt %xcc, __cheetah_log_error - nop - -c_fast_ecc: - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov %l4, %o1 - mov %l5, %o2 - call cheetah_fecc_handler - add %sp, PTREGS_OFF, %o0 - ba,a,pt %xcc, rtrap_irq - - /* Our caller has disabled I-cache and performed membar Sync. */ - .globl cheetah_cee -cheetah_cee: - ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 - andn %g2, ESTATE_ERROR_CEEN, %g2 - stxa %g2, [%g0] ASI_ESTATE_ERROR_EN - membar #Sync - - /* Fetch and clear AFSR/AFAR */ - ldxa [%g0] ASI_AFSR, %g4 - ldxa [%g0] ASI_AFAR, %g5 - stxa %g4, [%g0] ASI_AFSR - membar #Sync - - ba,pt %xcc, __cheetah_log_error - nop - -c_cee: - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov %l4, %o1 - mov %l5, %o2 - call cheetah_cee_handler - add %sp, PTREGS_OFF, %o0 - ba,a,pt %xcc, rtrap_irq - - /* Our caller has disabled I-cache+D-cache and performed membar Sync. */ - .globl cheetah_deferred_trap -cheetah_deferred_trap: - ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2 - andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2 - stxa %g2, [%g0] ASI_ESTATE_ERROR_EN - membar #Sync - - /* Fetch and clear AFSR/AFAR */ - ldxa [%g0] ASI_AFSR, %g4 - ldxa [%g0] ASI_AFAR, %g5 - stxa %g4, [%g0] ASI_AFSR - membar #Sync - - ba,pt %xcc, __cheetah_log_error - nop - -c_deferred: - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - mov %l4, %o1 - mov %l5, %o2 - call cheetah_deferred_handler - add %sp, PTREGS_OFF, %o0 - ba,a,pt %xcc, rtrap_irq - - .globl __do_privact -__do_privact: - mov TLB_SFSR, %g3 - stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit - membar #Sync - sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - call do_privact - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl do_mna -do_mna: - rdpr %tl, %g3 - cmp %g3, 1 - - /* Setup %g4/%g5 now as they are used in the - * winfixup code. - */ - mov TLB_SFSR, %g3 - mov DMMU_SFAR, %g4 - ldxa [%g4] ASI_DMMU, %g4 - ldxa [%g3] ASI_DMMU, %g5 - stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit - membar #Sync - bgu,pn %icc, winfix_mna - rdpr %tpc, %g3 - -1: sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call mem_address_unaligned - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl do_lddfmna -do_lddfmna: - sethi %hi(109f), %g7 - mov TLB_SFSR, %g4 - ldxa [%g4] ASI_DMMU, %g5 - stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit - membar #Sync - mov DMMU_SFAR, %g4 - ldxa [%g4] ASI_DMMU, %g4 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call handle_lddfmna - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl do_stdfmna -do_stdfmna: - sethi %hi(109f), %g7 - mov TLB_SFSR, %g4 - ldxa [%g4] ASI_DMMU, %g5 - stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit - membar #Sync - mov DMMU_SFAR, %g4 - ldxa [%g4] ASI_DMMU, %g4 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - mov %l4, %o1 - mov %l5, %o2 - call handle_stdfmna - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - .globl breakpoint_trap -breakpoint_trap: - call sparc_breakpoint - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap - nop - - /* SunOS's execv() call only specifies the argv argument, the - * environment settings are the same as the calling processes. - */ - .globl sunos_execv -sys_execve: - sethi %hi(sparc_execve), %g1 - ba,pt %xcc, execve_merge - or %g1, %lo(sparc_execve), %g1 -#ifdef CONFIG_COMPAT - .globl sys_execve -sunos_execv: - stx %g0, [%sp + PTREGS_OFF + PT_V9_I2] - .globl sys32_execve -sys32_execve: - sethi %hi(sparc32_execve), %g1 - or %g1, %lo(sparc32_execve), %g1 -#endif -execve_merge: - flushw - jmpl %g1, %g0 - add %sp, PTREGS_OFF, %o0 - - .globl sys_pipe, sys_sigpause, sys_nis_syscall - .globl sys_rt_sigreturn - .globl sys_ptrace - .globl sys_sigaltstack - .align 32 -sys_pipe: ba,pt %xcc, sparc_pipe - add %sp, PTREGS_OFF, %o0 -sys_nis_syscall:ba,pt %xcc, c_sys_nis_syscall - add %sp, PTREGS_OFF, %o0 -sys_memory_ordering: - ba,pt %xcc, sparc_memory_ordering - add %sp, PTREGS_OFF, %o1 -sys_sigaltstack:ba,pt %xcc, do_sigaltstack - add %i6, STACK_BIAS, %o2 -#ifdef CONFIG_COMPAT - .globl sys32_sigstack -sys32_sigstack: ba,pt %xcc, do_sys32_sigstack - mov %i6, %o2 - .globl sys32_sigaltstack -sys32_sigaltstack: - ba,pt %xcc, do_sys32_sigaltstack - mov %i6, %o2 -#endif - .align 32 -#ifdef CONFIG_COMPAT - .globl sys32_sigreturn -sys32_sigreturn: - add %sp, PTREGS_OFF, %o0 - call do_sigreturn32 - add %o7, 1f-.-4, %o7 - nop -#endif -sys_rt_sigreturn: - add %sp, PTREGS_OFF, %o0 - call do_rt_sigreturn - add %o7, 1f-.-4, %o7 - nop -#ifdef CONFIG_COMPAT - .globl sys32_rt_sigreturn -sys32_rt_sigreturn: - add %sp, PTREGS_OFF, %o0 - call do_rt_sigreturn32 - add %o7, 1f-.-4, %o7 - nop -#endif - .align 32 -1: ldx [%curptr + TI_FLAGS], %l5 - andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 - be,pt %icc, rtrap - nop - add %sp, PTREGS_OFF, %o0 - call syscall_trace - mov 1, %o1 - - ba,pt %xcc, rtrap - nop - - /* This is how fork() was meant to be done, 8 instruction entry. - * - * I questioned the following code briefly, let me clear things - * up so you must not reason on it like I did. - * - * Know the fork_kpsr etc. we use in the sparc32 port? We don't - * need it here because the only piece of window state we copy to - * the child is the CWP register. Even if the parent sleeps, - * we are safe because we stuck it into pt_regs of the parent - * so it will not change. - * - * XXX This raises the question, whether we can do the same on - * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The - * XXX answer is yes. We stick fork_kpsr in UREG_G0 and - * XXX fork_kwim in UREG_G1 (global registers are considered - * XXX volatile across a system call in the sparc ABI I think - * XXX if it isn't we can use regs->y instead, anyone who depends - * XXX upon the Y register being preserved across a fork deserves - * XXX to lose). - * - * In fact we should take advantage of that fact for other things - * during system calls... - */ - .globl sys_fork, sys_vfork, sys_clone, sparc_exit - .globl ret_from_syscall - .align 32 -sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */ - sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 - or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 - ba,pt %xcc, sys_clone -sys_fork: clr %o1 - mov SIGCHLD, %o0 -sys_clone: flushw - movrz %o1, %fp, %o1 - mov 0, %o3 - ba,pt %xcc, sparc_do_fork - add %sp, PTREGS_OFF, %o2 -ret_from_syscall: - /* Clear current_thread_info()->new_child, and - * check performance counter stuff too. - */ - stb %g0, [%g6 + TI_NEW_CHILD] - ldx [%g6 + TI_FLAGS], %l0 - call schedule_tail - mov %g7, %o0 - andcc %l0, _TIF_PERFCTR, %g0 - be,pt %icc, 1f - nop - ldx [%g6 + TI_PCR], %o7 - wr %g0, %o7, %pcr - - /* Blackbird errata workaround. See commentary in - * smp.c:smp_percpu_timer_interrupt() for more - * information. - */ - ba,pt %xcc, 99f - nop - .align 64 -99: wr %g0, %g0, %pic - rd %pic, %g0 - -1: b,pt %xcc, ret_sys_call - ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 -sparc_exit: rdpr %pstate, %g2 - wrpr %g2, PSTATE_IE, %pstate - rdpr %otherwin, %g1 - rdpr %cansave, %g3 - add %g3, %g1, %g3 - wrpr %g3, 0x0, %cansave - wrpr %g0, 0x0, %otherwin - wrpr %g2, 0x0, %pstate - ba,pt %xcc, sys_exit - stb %g0, [%g6 + TI_WSAVED] - -linux_sparc_ni_syscall: - sethi %hi(sys_ni_syscall), %l7 - b,pt %xcc, 4f - or %l7, %lo(sys_ni_syscall), %l7 - -linux_syscall_trace32: - add %sp, PTREGS_OFF, %o0 - call syscall_trace - clr %o1 - srl %i0, 0, %o0 - srl %i4, 0, %o4 - srl %i1, 0, %o1 - srl %i2, 0, %o2 - b,pt %xcc, 2f - srl %i3, 0, %o3 - -linux_syscall_trace: - add %sp, PTREGS_OFF, %o0 - call syscall_trace - clr %o1 - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov %i3, %o3 - b,pt %xcc, 2f - mov %i4, %o4 - - - /* Linux 32-bit system calls enter here... */ - .align 32 - .globl linux_sparc_syscall32 -linux_sparc_syscall32: - /* Direct access to user regs, much faster. */ - cmp %g1, NR_SYSCALLS ! IEU1 Group - bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI - srl %i0, 0, %o0 ! IEU0 - sll %g1, 2, %l4 ! IEU0 Group - srl %i4, 0, %o4 ! IEU1 - lduw [%l7 + %l4], %l7 ! Load - srl %i1, 0, %o1 ! IEU0 Group - ldx [%curptr + TI_FLAGS], %l0 ! Load - - srl %i5, 0, %o5 ! IEU1 - srl %i2, 0, %o2 ! IEU0 Group - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 - bne,pn %icc, linux_syscall_trace32 ! CTI - mov %i0, %l5 ! IEU1 - call %l7 ! CTI Group brk forced - srl %i3, 0, %o3 ! IEU0 - ba,a,pt %xcc, 3f - - /* Linux native system calls enter here... */ - .align 32 - .globl linux_sparc_syscall -linux_sparc_syscall: - /* Direct access to user regs, much faster. */ - cmp %g1, NR_SYSCALLS ! IEU1 Group - bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI - mov %i0, %o0 ! IEU0 - sll %g1, 2, %l4 ! IEU0 Group - mov %i1, %o1 ! IEU1 - lduw [%l7 + %l4], %l7 ! Load -4: mov %i2, %o2 ! IEU0 Group - ldx [%curptr + TI_FLAGS], %l0 ! Load - - mov %i3, %o3 ! IEU1 - mov %i4, %o4 ! IEU0 Group - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 - bne,pn %icc, linux_syscall_trace ! CTI Group - mov %i0, %l5 ! IEU0 -2: call %l7 ! CTI Group brk forced - mov %i5, %o5 ! IEU0 - nop - -3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] -ret_sys_call: - ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 - ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc - sra %o0, 0, %o0 - mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 - sllx %g2, 32, %g2 - - /* Check if force_successful_syscall_return() - * was invoked. - */ - ldub [%curptr + TI_SYS_NOERROR], %l2 - brnz,a,pn %l2, 80f - stb %g0, [%curptr + TI_SYS_NOERROR] - - cmp %o0, -ERESTART_RESTARTBLOCK - bgeu,pn %xcc, 1f - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 -80: - /* System call success, clear Carry condition code. */ - andn %g3, %g2, %g3 - stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - add %l1, 0x4, %l2 ! npc = npc+4 - stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] - ba,pt %xcc, rtrap - stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] - -1: - /* System call failure, set Carry condition code. - * Also, get abs(errno) to return to the process. - */ - andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 - sub %g0, %o0, %o0 - or %g3, %g2, %g3 - stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] - stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] - bne,pn %icc, linux_syscall_trace2 - add %l1, 0x4, %l2 ! npc = npc+4 - stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] - - b,pt %xcc, rtrap - stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] -linux_syscall_trace2: - add %sp, PTREGS_OFF, %o0 - call syscall_trace - mov 1, %o1 - stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] - ba,pt %xcc, rtrap - stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] - - .align 32 - .globl __flushw_user -__flushw_user: - rdpr %otherwin, %g1 - brz,pn %g1, 2f - clr %g2 -1: save %sp, -128, %sp - rdpr %otherwin, %g1 - brnz,pt %g1, 1b - add %g2, 1, %g2 -1: sub %g2, 1, %g2 - brnz,pt %g2, 1b - restore %g0, %g0, %g0 -2: retl - nop - - /* Flush %fp and %i7 to the stack for all register - * windows active inside of the cpu. This allows - * show_stack_trace() to avoid using an expensive - * 'flushw'. - */ - .globl stack_trace_flush - .type stack_trace_flush,#function -stack_trace_flush: - rdpr %pstate, %o0 - wrpr %o0, PSTATE_IE, %pstate - - rdpr %cwp, %g1 - rdpr %canrestore, %g2 - sub %g1, 1, %g3 - -1: brz,pn %g2, 2f - sub %g2, 1, %g2 - wrpr %g3, %cwp - stx %fp, [%sp + STACK_BIAS + RW_V9_I6] - stx %i7, [%sp + STACK_BIAS + RW_V9_I7] - ba,pt %xcc, 1b - sub %g3, 1, %g3 - -2: wrpr %g1, %cwp - wrpr %o0, %pstate - - retl - nop - .size stack_trace_flush,.-stack_trace_flush - -#ifdef CONFIG_SMP - .globl hard_smp_processor_id -hard_smp_processor_id: -#endif - .globl real_hard_smp_processor_id -real_hard_smp_processor_id: - __GET_CPUID(%o0) - retl - nop - - /* %o0: devhandle - * %o1: devino - * - * returns %o0: sysino - */ - .globl sun4v_devino_to_sysino - .type sun4v_devino_to_sysino,#function -sun4v_devino_to_sysino: - mov HV_FAST_INTR_DEVINO2SYSINO, %o5 - ta HV_FAST_TRAP - retl - mov %o1, %o0 - .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino - - /* %o0: sysino - * - * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) - */ - .globl sun4v_intr_getenabled - .type sun4v_intr_getenabled,#function -sun4v_intr_getenabled: - mov HV_FAST_INTR_GETENABLED, %o5 - ta HV_FAST_TRAP - retl - mov %o1, %o0 - .size sun4v_intr_getenabled, .-sun4v_intr_getenabled - - /* %o0: sysino - * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) - */ - .globl sun4v_intr_setenabled - .type sun4v_intr_setenabled,#function -sun4v_intr_setenabled: - mov HV_FAST_INTR_SETENABLED, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_intr_setenabled, .-sun4v_intr_setenabled - - /* %o0: sysino - * - * returns %o0: intr_state (HV_INTR_STATE_*) - */ - .globl sun4v_intr_getstate - .type sun4v_intr_getstate,#function -sun4v_intr_getstate: - mov HV_FAST_INTR_GETSTATE, %o5 - ta HV_FAST_TRAP - retl - mov %o1, %o0 - .size sun4v_intr_getstate, .-sun4v_intr_getstate - - /* %o0: sysino - * %o1: intr_state (HV_INTR_STATE_*) - */ - .globl sun4v_intr_setstate - .type sun4v_intr_setstate,#function -sun4v_intr_setstate: - mov HV_FAST_INTR_SETSTATE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_intr_setstate, .-sun4v_intr_setstate - - /* %o0: sysino - * - * returns %o0: cpuid - */ - .globl sun4v_intr_gettarget - .type sun4v_intr_gettarget,#function -sun4v_intr_gettarget: - mov HV_FAST_INTR_GETTARGET, %o5 - ta HV_FAST_TRAP - retl - mov %o1, %o0 - .size sun4v_intr_gettarget, .-sun4v_intr_gettarget - - /* %o0: sysino - * %o1: cpuid - */ - .globl sun4v_intr_settarget - .type sun4v_intr_settarget,#function -sun4v_intr_settarget: - mov HV_FAST_INTR_SETTARGET, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_intr_settarget, .-sun4v_intr_settarget - - /* %o0: cpuid - * %o1: pc - * %o2: rtba - * %o3: arg0 - * - * returns %o0: status - */ - .globl sun4v_cpu_start - .type sun4v_cpu_start,#function -sun4v_cpu_start: - mov HV_FAST_CPU_START, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_cpu_start, .-sun4v_cpu_start - - /* %o0: cpuid - * - * returns %o0: status - */ - .globl sun4v_cpu_stop - .type sun4v_cpu_stop,#function -sun4v_cpu_stop: - mov HV_FAST_CPU_STOP, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_cpu_stop, .-sun4v_cpu_stop - - /* returns %o0: status */ - .globl sun4v_cpu_yield - .type sun4v_cpu_yield, #function -sun4v_cpu_yield: - mov HV_FAST_CPU_YIELD, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_cpu_yield, .-sun4v_cpu_yield - - /* %o0: type - * %o1: queue paddr - * %o2: num queue entries - * - * returns %o0: status - */ - .globl sun4v_cpu_qconf - .type sun4v_cpu_qconf,#function -sun4v_cpu_qconf: - mov HV_FAST_CPU_QCONF, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_cpu_qconf, .-sun4v_cpu_qconf - - /* %o0: num cpus in cpu list - * %o1: cpu list paddr - * %o2: mondo block paddr - * - * returns %o0: status - */ - .globl sun4v_cpu_mondo_send - .type sun4v_cpu_mondo_send,#function -sun4v_cpu_mondo_send: - mov HV_FAST_CPU_MONDO_SEND, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send - - /* %o0: CPU ID - * - * returns %o0: -status if status non-zero, else - * %o0: cpu state as HV_CPU_STATE_* - */ - .globl sun4v_cpu_state - .type sun4v_cpu_state,#function -sun4v_cpu_state: - mov HV_FAST_CPU_STATE, %o5 - ta HV_FAST_TRAP - brnz,pn %o0, 1f - sub %g0, %o0, %o0 - mov %o1, %o0 -1: retl - nop - .size sun4v_cpu_state, .-sun4v_cpu_state - - /* %o0: virtual address - * %o1: must be zero - * %o2: TTE - * %o3: HV_MMU_* flags - * - * returns %o0: status - */ - .globl sun4v_mmu_map_perm_addr - .type sun4v_mmu_map_perm_addr,#function -sun4v_mmu_map_perm_addr: - mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr - - /* %o0: number of TSB descriptions - * %o1: TSB descriptions real address - * - * returns %o0: status - */ - .globl sun4v_mmu_tsb_ctx0 - .type sun4v_mmu_tsb_ctx0,#function -sun4v_mmu_tsb_ctx0: - mov HV_FAST_MMU_TSB_CTX0, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0 - - /* %o0: API group number - * %o1: pointer to unsigned long major number storage - * %o2: pointer to unsigned long minor number storage - * - * returns %o0: status - */ - .globl sun4v_get_version - .type sun4v_get_version,#function -sun4v_get_version: - mov HV_CORE_GET_VER, %o5 - mov %o1, %o3 - mov %o2, %o4 - ta HV_CORE_TRAP - stx %o1, [%o3] - retl - stx %o2, [%o4] - .size sun4v_get_version, .-sun4v_get_version - - /* %o0: API group number - * %o1: desired major number - * %o2: desired minor number - * %o3: pointer to unsigned long actual minor number storage - * - * returns %o0: status - */ - .globl sun4v_set_version - .type sun4v_set_version,#function -sun4v_set_version: - mov HV_CORE_SET_VER, %o5 - mov %o3, %o4 - ta HV_CORE_TRAP - retl - stx %o1, [%o4] - .size sun4v_set_version, .-sun4v_set_version - - /* %o0: pointer to unsigned long time - * - * returns %o0: status - */ - .globl sun4v_tod_get - .type sun4v_tod_get,#function -sun4v_tod_get: - mov %o0, %o4 - mov HV_FAST_TOD_GET, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_tod_get, .-sun4v_tod_get - - /* %o0: time - * - * returns %o0: status - */ - .globl sun4v_tod_set - .type sun4v_tod_set,#function -sun4v_tod_set: - mov HV_FAST_TOD_SET, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_tod_set, .-sun4v_tod_set - - /* %o0: pointer to unsigned long status - * - * returns %o0: signed character - */ - .globl sun4v_con_getchar - .type sun4v_con_getchar,#function -sun4v_con_getchar: - mov %o0, %o4 - mov HV_FAST_CONS_GETCHAR, %o5 - clr %o0 - clr %o1 - ta HV_FAST_TRAP - stx %o0, [%o4] - retl - sra %o1, 0, %o0 - .size sun4v_con_getchar, .-sun4v_con_getchar - - /* %o0: signed long character - * - * returns %o0: status - */ - .globl sun4v_con_putchar - .type sun4v_con_putchar,#function -sun4v_con_putchar: - mov HV_FAST_CONS_PUTCHAR, %o5 - ta HV_FAST_TRAP - retl - sra %o0, 0, %o0 - .size sun4v_con_putchar, .-sun4v_con_putchar - - /* %o0: buffer real address - * %o1: buffer size - * %o2: pointer to unsigned long bytes_read - * - * returns %o0: status - */ - .globl sun4v_con_read - .type sun4v_con_read,#function -sun4v_con_read: - mov %o2, %o4 - mov HV_FAST_CONS_READ, %o5 - ta HV_FAST_TRAP - brnz %o0, 1f - cmp %o1, -1 /* break */ - be,a,pn %icc, 1f - mov %o1, %o0 - cmp %o1, -2 /* hup */ - be,a,pn %icc, 1f - mov %o1, %o0 - stx %o1, [%o4] -1: retl - nop - .size sun4v_con_read, .-sun4v_con_read - - /* %o0: buffer real address - * %o1: buffer size - * %o2: pointer to unsigned long bytes_written - * - * returns %o0: status - */ - .globl sun4v_con_write - .type sun4v_con_write,#function -sun4v_con_write: - mov %o2, %o4 - mov HV_FAST_CONS_WRITE, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_con_write, .-sun4v_con_write - - /* %o0: soft state - * %o1: address of description string - * - * returns %o0: status - */ - .globl sun4v_mach_set_soft_state - .type sun4v_mach_set_soft_state,#function -sun4v_mach_set_soft_state: - mov HV_FAST_MACH_SET_SOFT_STATE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state - - /* %o0: exit code - * - * Does not return. - */ - .globl sun4v_mach_exit - .type sun4v_mach_exit,#function -sun4v_mach_exit: - mov HV_FAST_MACH_EXIT, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_mach_exit, .-sun4v_mach_exit - - /* %o0: buffer real address - * %o1: buffer length - * %o2: pointer to unsigned long real_buf_len - * - * returns %o0: status - */ - .globl sun4v_mach_desc - .type sun4v_mach_desc,#function -sun4v_mach_desc: - mov %o2, %o4 - mov HV_FAST_MACH_DESC, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_mach_desc, .-sun4v_mach_desc - - /* %o0: new timeout in milliseconds - * %o1: pointer to unsigned long orig_timeout - * - * returns %o0: status - */ - .globl sun4v_mach_set_watchdog - .type sun4v_mach_set_watchdog,#function -sun4v_mach_set_watchdog: - mov %o1, %o4 - mov HV_FAST_MACH_SET_WATCHDOG, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog - - /* No inputs and does not return. */ - .globl sun4v_mach_sir - .type sun4v_mach_sir,#function -sun4v_mach_sir: - mov %o1, %o4 - mov HV_FAST_MACH_SIR, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_mach_sir, .-sun4v_mach_sir - - /* %o0: channel - * %o1: ra - * %o2: num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_tx_qconf - .type sun4v_ldc_tx_qconf,#function -sun4v_ldc_tx_qconf: - mov HV_FAST_LDC_TX_QCONF, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf - - /* %o0: channel - * %o1: pointer to unsigned long ra - * %o2: pointer to unsigned long num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_tx_qinfo - .type sun4v_ldc_tx_qinfo,#function -sun4v_ldc_tx_qinfo: - mov %o1, %g1 - mov %o2, %g2 - mov HV_FAST_LDC_TX_QINFO, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - retl - nop - .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo - - /* %o0: channel - * %o1: pointer to unsigned long head_off - * %o2: pointer to unsigned long tail_off - * %o2: pointer to unsigned long chan_state - * - * returns %o0: status - */ - .globl sun4v_ldc_tx_get_state - .type sun4v_ldc_tx_get_state,#function -sun4v_ldc_tx_get_state: - mov %o1, %g1 - mov %o2, %g2 - mov %o3, %g3 - mov HV_FAST_LDC_TX_GET_STATE, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - stx %o3, [%g3] - retl - nop - .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state - - /* %o0: channel - * %o1: tail_off - * - * returns %o0: status - */ - .globl sun4v_ldc_tx_set_qtail - .type sun4v_ldc_tx_set_qtail,#function -sun4v_ldc_tx_set_qtail: - mov HV_FAST_LDC_TX_SET_QTAIL, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail - - /* %o0: channel - * %o1: ra - * %o2: num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_rx_qconf - .type sun4v_ldc_rx_qconf,#function -sun4v_ldc_rx_qconf: - mov HV_FAST_LDC_RX_QCONF, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf - - /* %o0: channel - * %o1: pointer to unsigned long ra - * %o2: pointer to unsigned long num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_rx_qinfo - .type sun4v_ldc_rx_qinfo,#function -sun4v_ldc_rx_qinfo: - mov %o1, %g1 - mov %o2, %g2 - mov HV_FAST_LDC_RX_QINFO, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - retl - nop - .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo - - /* %o0: channel - * %o1: pointer to unsigned long head_off - * %o2: pointer to unsigned long tail_off - * %o2: pointer to unsigned long chan_state - * - * returns %o0: status - */ - .globl sun4v_ldc_rx_get_state - .type sun4v_ldc_rx_get_state,#function -sun4v_ldc_rx_get_state: - mov %o1, %g1 - mov %o2, %g2 - mov %o3, %g3 - mov HV_FAST_LDC_RX_GET_STATE, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - stx %o3, [%g3] - retl - nop - .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state - - /* %o0: channel - * %o1: head_off - * - * returns %o0: status - */ - .globl sun4v_ldc_rx_set_qhead - .type sun4v_ldc_rx_set_qhead,#function -sun4v_ldc_rx_set_qhead: - mov HV_FAST_LDC_RX_SET_QHEAD, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead - - /* %o0: channel - * %o1: ra - * %o2: num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_set_map_table - .type sun4v_ldc_set_map_table,#function -sun4v_ldc_set_map_table: - mov HV_FAST_LDC_SET_MAP_TABLE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table - - /* %o0: channel - * %o1: pointer to unsigned long ra - * %o2: pointer to unsigned long num_entries - * - * returns %o0: status - */ - .globl sun4v_ldc_get_map_table - .type sun4v_ldc_get_map_table,#function -sun4v_ldc_get_map_table: - mov %o1, %g1 - mov %o2, %g2 - mov HV_FAST_LDC_GET_MAP_TABLE, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - retl - nop - .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table - - /* %o0: channel - * %o1: dir_code - * %o2: tgt_raddr - * %o3: lcl_raddr - * %o4: len - * %o5: pointer to unsigned long actual_len - * - * returns %o0: status - */ - .globl sun4v_ldc_copy - .type sun4v_ldc_copy,#function -sun4v_ldc_copy: - mov %o5, %g1 - mov HV_FAST_LDC_COPY, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - retl - nop - .size sun4v_ldc_copy, .-sun4v_ldc_copy - - /* %o0: channel - * %o1: cookie - * %o2: pointer to unsigned long ra - * %o3: pointer to unsigned long perm - * - * returns %o0: status - */ - .globl sun4v_ldc_mapin - .type sun4v_ldc_mapin,#function -sun4v_ldc_mapin: - mov %o2, %g1 - mov %o3, %g2 - mov HV_FAST_LDC_MAPIN, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - stx %o2, [%g2] - retl - nop - .size sun4v_ldc_mapin, .-sun4v_ldc_mapin - - /* %o0: ra - * - * returns %o0: status - */ - .globl sun4v_ldc_unmap - .type sun4v_ldc_unmap,#function -sun4v_ldc_unmap: - mov HV_FAST_LDC_UNMAP, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_unmap, .-sun4v_ldc_unmap - - /* %o0: channel - * %o1: cookie - * %o2: mte_cookie - * - * returns %o0: status - */ - .globl sun4v_ldc_revoke - .type sun4v_ldc_revoke,#function -sun4v_ldc_revoke: - mov HV_FAST_LDC_REVOKE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ldc_revoke, .-sun4v_ldc_revoke - - /* %o0: device handle - * %o1: device INO - * %o2: pointer to unsigned long cookie - * - * returns %o0: status - */ - .globl sun4v_vintr_get_cookie - .type sun4v_vintr_get_cookie,#function -sun4v_vintr_get_cookie: - mov %o2, %g1 - mov HV_FAST_VINTR_GET_COOKIE, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - retl - nop - .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie - - /* %o0: device handle - * %o1: device INO - * %o2: cookie - * - * returns %o0: status - */ - .globl sun4v_vintr_set_cookie - .type sun4v_vintr_set_cookie,#function -sun4v_vintr_set_cookie: - mov HV_FAST_VINTR_SET_COOKIE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie - - /* %o0: device handle - * %o1: device INO - * %o2: pointer to unsigned long valid_state - * - * returns %o0: status - */ - .globl sun4v_vintr_get_valid - .type sun4v_vintr_get_valid,#function -sun4v_vintr_get_valid: - mov %o2, %g1 - mov HV_FAST_VINTR_GET_VALID, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - retl - nop - .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid - - /* %o0: device handle - * %o1: device INO - * %o2: valid_state - * - * returns %o0: status - */ - .globl sun4v_vintr_set_valid - .type sun4v_vintr_set_valid,#function -sun4v_vintr_set_valid: - mov HV_FAST_VINTR_SET_VALID, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid - - /* %o0: device handle - * %o1: device INO - * %o2: pointer to unsigned long state - * - * returns %o0: status - */ - .globl sun4v_vintr_get_state - .type sun4v_vintr_get_state,#function -sun4v_vintr_get_state: - mov %o2, %g1 - mov HV_FAST_VINTR_GET_STATE, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - retl - nop - .size sun4v_vintr_get_state, .-sun4v_vintr_get_state - - /* %o0: device handle - * %o1: device INO - * %o2: state - * - * returns %o0: status - */ - .globl sun4v_vintr_set_state - .type sun4v_vintr_set_state,#function -sun4v_vintr_set_state: - mov HV_FAST_VINTR_SET_STATE, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_vintr_set_state, .-sun4v_vintr_set_state - - /* %o0: device handle - * %o1: device INO - * %o2: pointer to unsigned long cpuid - * - * returns %o0: status - */ - .globl sun4v_vintr_get_target - .type sun4v_vintr_get_target,#function -sun4v_vintr_get_target: - mov %o2, %g1 - mov HV_FAST_VINTR_GET_TARGET, %o5 - ta HV_FAST_TRAP - stx %o1, [%g1] - retl - nop - .size sun4v_vintr_get_target, .-sun4v_vintr_get_target - - /* %o0: device handle - * %o1: device INO - * %o2: cpuid - * - * returns %o0: status - */ - .globl sun4v_vintr_set_target - .type sun4v_vintr_set_target,#function -sun4v_vintr_set_target: - mov HV_FAST_VINTR_SET_TARGET, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_vintr_set_target, .-sun4v_vintr_set_target - - /* %o0: NCS sub-function - * %o1: sub-function arg real-address - * %o2: sub-function arg size - * - * returns %o0: status - */ - .globl sun4v_ncs_request - .type sun4v_ncs_request,#function -sun4v_ncs_request: - mov HV_FAST_NCS_REQUEST, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_ncs_request, .-sun4v_ncs_request - - .globl sun4v_svc_send - .type sun4v_svc_send,#function -sun4v_svc_send: - save %sp, -192, %sp - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov HV_FAST_SVC_SEND, %o5 - ta HV_FAST_TRAP - stx %o1, [%i3] - ret - restore - .size sun4v_svc_send, .-sun4v_svc_send - - .globl sun4v_svc_recv - .type sun4v_svc_recv,#function -sun4v_svc_recv: - save %sp, -192, %sp - mov %i0, %o0 - mov %i1, %o1 - mov %i2, %o2 - mov HV_FAST_SVC_RECV, %o5 - ta HV_FAST_TRAP - stx %o1, [%i3] - ret - restore - .size sun4v_svc_recv, .-sun4v_svc_recv - - .globl sun4v_svc_getstatus - .type sun4v_svc_getstatus,#function -sun4v_svc_getstatus: - mov HV_FAST_SVC_GETSTATUS, %o5 - mov %o1, %o4 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_svc_getstatus, .-sun4v_svc_getstatus - - .globl sun4v_svc_setstatus - .type sun4v_svc_setstatus,#function -sun4v_svc_setstatus: - mov HV_FAST_SVC_SETSTATUS, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_svc_setstatus, .-sun4v_svc_setstatus - - .globl sun4v_svc_clrstatus - .type sun4v_svc_clrstatus,#function -sun4v_svc_clrstatus: - mov HV_FAST_SVC_CLRSTATUS, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus - - .globl sun4v_mmustat_conf - .type sun4v_mmustat_conf,#function -sun4v_mmustat_conf: - mov %o1, %o4 - mov HV_FAST_MMUSTAT_CONF, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_mmustat_conf, .-sun4v_mmustat_conf - - .globl sun4v_mmustat_info - .type sun4v_mmustat_info,#function -sun4v_mmustat_info: - mov %o0, %o4 - mov HV_FAST_MMUSTAT_INFO, %o5 - ta HV_FAST_TRAP - stx %o1, [%o4] - retl - nop - .size sun4v_mmustat_info, .-sun4v_mmustat_info - - .globl sun4v_mmu_demap_all - .type sun4v_mmu_demap_all,#function -sun4v_mmu_demap_all: - clr %o0 - clr %o1 - mov HV_MMU_ALL, %o2 - mov HV_FAST_MMU_DEMAP_ALL, %o5 - ta HV_FAST_TRAP - retl - nop - .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all diff --git a/arch/sparc64/kernel/fpu_traps.S b/arch/sparc64/kernel/fpu_traps.S new file mode 100644 index 00000000000..a6864826a4b --- /dev/null +++ b/arch/sparc64/kernel/fpu_traps.S @@ -0,0 +1,384 @@ + /* This is trivial with the new code... */ + .globl do_fpdis + .type do_fpdis,#function +do_fpdis: + sethi %hi(TSTATE_PEF), %g4 + rdpr %tstate, %g5 + andcc %g5, %g4, %g0 + be,pt %xcc, 1f + nop + rd %fprs, %g5 + andcc %g5, FPRS_FEF, %g0 + be,pt %xcc, 1f + nop + + /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */ + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + add %g0, %g0, %g0 + ba,a,pt %xcc, rtrap + +1: TRAP_LOAD_THREAD_REG(%g6, %g1) + ldub [%g6 + TI_FPSAVED], %g5 + wr %g0, FPRS_FEF, %fprs + andcc %g5, FPRS_FEF, %g0 + be,a,pt %icc, 1f + clr %g7 + ldx [%g6 + TI_GSR], %g7 +1: andcc %g5, FPRS_DL, %g0 + bne,pn %icc, 2f + fzero %f0 + andcc %g5, FPRS_DU, %g0 + bne,pn %icc, 1f + fzero %f2 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 + faddd %f0, %f2, %f32 + fmuld %f0, %f2, %f34 + faddd %f0, %f2, %f36 + fmuld %f0, %f2, %f38 + faddd %f0, %f2, %f40 + fmuld %f0, %f2, %f42 + faddd %f0, %f2, %f44 + fmuld %f0, %f2, %f46 + faddd %f0, %f2, %f48 + fmuld %f0, %f2, %f50 + faddd %f0, %f2, %f52 + fmuld %f0, %f2, %f54 + faddd %f0, %f2, %f56 + fmuld %f0, %f2, %f58 + b,pt %xcc, fpdis_exit2 + faddd %f0, %f2, %f60 +1: mov SECONDARY_CONTEXT, %g3 + add %g6, TI_FPREGS + 0x80, %g1 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + +661: ldxa [%g3] ASI_DMMU, %g5 + .section .sun4v_1insn_patch, "ax" + .word 661b + ldxa [%g3] ASI_MMU, %g5 + .previous + + sethi %hi(sparc64_kern_sec_context), %g2 + ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 + +661: stxa %g2, [%g3] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g2, [%g3] ASI_MMU + .previous + + membar #Sync + add %g6, TI_FPREGS + 0xc0, %g2 + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + membar #Sync + ldda [%g1] ASI_BLK_S, %f32 + ldda [%g2] ASI_BLK_S, %f48 + membar #Sync + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 + b,pt %xcc, fpdis_exit + nop +2: andcc %g5, FPRS_DU, %g0 + bne,pt %icc, 3f + fzero %f32 + mov SECONDARY_CONTEXT, %g3 + fzero %f34 + +661: ldxa [%g3] ASI_DMMU, %g5 + .section .sun4v_1insn_patch, "ax" + .word 661b + ldxa [%g3] ASI_MMU, %g5 + .previous + + add %g6, TI_FPREGS, %g1 + sethi %hi(sparc64_kern_sec_context), %g2 + ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 + +661: stxa %g2, [%g3] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g2, [%g3] ASI_MMU + .previous + + membar #Sync + add %g6, TI_FPREGS + 0x40, %g2 + faddd %f32, %f34, %f36 + fmuld %f32, %f34, %f38 + membar #Sync + ldda [%g1] ASI_BLK_S, %f0 + ldda [%g2] ASI_BLK_S, %f16 + membar #Sync + faddd %f32, %f34, %f40 + fmuld %f32, %f34, %f42 + faddd %f32, %f34, %f44 + fmuld %f32, %f34, %f46 + faddd %f32, %f34, %f48 + fmuld %f32, %f34, %f50 + faddd %f32, %f34, %f52 + fmuld %f32, %f34, %f54 + faddd %f32, %f34, %f56 + fmuld %f32, %f34, %f58 + faddd %f32, %f34, %f60 + fmuld %f32, %f34, %f62 + ba,pt %xcc, fpdis_exit + nop +3: mov SECONDARY_CONTEXT, %g3 + add %g6, TI_FPREGS, %g1 + +661: ldxa [%g3] ASI_DMMU, %g5 + .section .sun4v_1insn_patch, "ax" + .word 661b + ldxa [%g3] ASI_MMU, %g5 + .previous + + sethi %hi(sparc64_kern_sec_context), %g2 + ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 + +661: stxa %g2, [%g3] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g2, [%g3] ASI_MMU + .previous + + membar #Sync + mov 0x40, %g2 + membar #Sync + ldda [%g1] ASI_BLK_S, %f0 + ldda [%g1 + %g2] ASI_BLK_S, %f16 + add %g1, 0x80, %g1 + ldda [%g1] ASI_BLK_S, %f32 + ldda [%g1 + %g2] ASI_BLK_S, %f48 + membar #Sync +fpdis_exit: + +661: stxa %g5, [%g3] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g5, [%g3] ASI_MMU + .previous + + membar #Sync +fpdis_exit2: + wr %g7, 0, %gsr + ldx [%g6 + TI_XFSR], %fsr + rdpr %tstate, %g3 + or %g3, %g4, %g3 ! anal... + wrpr %g3, %tstate + wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits + retry + .size do_fpdis,.-do_fpdis + + .align 32 + .type fp_other_bounce,#function +fp_other_bounce: + call do_fpother + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size fp_other_bounce,.-fp_other_bounce + + .align 32 + .globl do_fpother_check_fitos + .type do_fpother_check_fitos,#function +do_fpother_check_fitos: + TRAP_LOAD_THREAD_REG(%g6, %g1) + sethi %hi(fp_other_bounce - 4), %g7 + or %g7, %lo(fp_other_bounce - 4), %g7 + + /* NOTE: Need to preserve %g7 until we fully commit + * to the fitos fixup. + */ + stx %fsr, [%g6 + TI_XFSR] + rdpr %tstate, %g3 + andcc %g3, TSTATE_PRIV, %g0 + bne,pn %xcc, do_fptrap_after_fsr + nop + ldx [%g6 + TI_XFSR], %g3 + srlx %g3, 14, %g1 + and %g1, 7, %g1 + cmp %g1, 2 ! Unfinished FP-OP + bne,pn %xcc, do_fptrap_after_fsr + sethi %hi(1 << 23), %g1 ! Inexact + andcc %g3, %g1, %g0 + bne,pn %xcc, do_fptrap_after_fsr + rdpr %tpc, %g1 + lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail +#define FITOS_MASK 0xc1f83fe0 +#define FITOS_COMPARE 0x81a01880 + sethi %hi(FITOS_MASK), %g1 + or %g1, %lo(FITOS_MASK), %g1 + and %g3, %g1, %g1 + sethi %hi(FITOS_COMPARE), %g2 + or %g2, %lo(FITOS_COMPARE), %g2 + cmp %g1, %g2 + bne,pn %xcc, do_fptrap_after_fsr + nop + std %f62, [%g6 + TI_FPREGS + (62 * 4)] + sethi %hi(fitos_table_1), %g1 + and %g3, 0x1f, %g2 + or %g1, %lo(fitos_table_1), %g1 + sllx %g2, 2, %g2 + jmpl %g1 + %g2, %g0 + ba,pt %xcc, fitos_emul_continue + +fitos_table_1: + fitod %f0, %f62 + fitod %f1, %f62 + fitod %f2, %f62 + fitod %f3, %f62 + fitod %f4, %f62 + fitod %f5, %f62 + fitod %f6, %f62 + fitod %f7, %f62 + fitod %f8, %f62 + fitod %f9, %f62 + fitod %f10, %f62 + fitod %f11, %f62 + fitod %f12, %f62 + fitod %f13, %f62 + fitod %f14, %f62 + fitod %f15, %f62 + fitod %f16, %f62 + fitod %f17, %f62 + fitod %f18, %f62 + fitod %f19, %f62 + fitod %f20, %f62 + fitod %f21, %f62 + fitod %f22, %f62 + fitod %f23, %f62 + fitod %f24, %f62 + fitod %f25, %f62 + fitod %f26, %f62 + fitod %f27, %f62 + fitod %f28, %f62 + fitod %f29, %f62 + fitod %f30, %f62 + fitod %f31, %f62 + +fitos_emul_continue: + sethi %hi(fitos_table_2), %g1 + srl %g3, 25, %g2 + or %g1, %lo(fitos_table_2), %g1 + and %g2, 0x1f, %g2 + sllx %g2, 2, %g2 + jmpl %g1 + %g2, %g0 + ba,pt %xcc, fitos_emul_fini + +fitos_table_2: + fdtos %f62, %f0 + fdtos %f62, %f1 + fdtos %f62, %f2 + fdtos %f62, %f3 + fdtos %f62, %f4 + fdtos %f62, %f5 + fdtos %f62, %f6 + fdtos %f62, %f7 + fdtos %f62, %f8 + fdtos %f62, %f9 + fdtos %f62, %f10 + fdtos %f62, %f11 + fdtos %f62, %f12 + fdtos %f62, %f13 + fdtos %f62, %f14 + fdtos %f62, %f15 + fdtos %f62, %f16 + fdtos %f62, %f17 + fdtos %f62, %f18 + fdtos %f62, %f19 + fdtos %f62, %f20 + fdtos %f62, %f21 + fdtos %f62, %f22 + fdtos %f62, %f23 + fdtos %f62, %f24 + fdtos %f62, %f25 + fdtos %f62, %f26 + fdtos %f62, %f27 + fdtos %f62, %f28 + fdtos %f62, %f29 + fdtos %f62, %f30 + fdtos %f62, %f31 + +fitos_emul_fini: + ldd [%g6 + TI_FPREGS + (62 * 4)], %f62 + done + .size do_fpother_check_fitos,.-do_fpother_check_fitos + + .align 32 + .globl do_fptrap + .type do_fptrap,#function +do_fptrap: + TRAP_LOAD_THREAD_REG(%g6, %g1) + stx %fsr, [%g6 + TI_XFSR] +do_fptrap_after_fsr: + ldub [%g6 + TI_FPSAVED], %g3 + rd %fprs, %g1 + or %g3, %g1, %g3 + stb %g3, [%g6 + TI_FPSAVED] + rd %gsr, %g3 + stx %g3, [%g6 + TI_GSR] + mov SECONDARY_CONTEXT, %g3 + +661: ldxa [%g3] ASI_DMMU, %g5 + .section .sun4v_1insn_patch, "ax" + .word 661b + ldxa [%g3] ASI_MMU, %g5 + .previous + + sethi %hi(sparc64_kern_sec_context), %g2 + ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2 + +661: stxa %g2, [%g3] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g2, [%g3] ASI_MMU + .previous + + membar #Sync + add %g6, TI_FPREGS, %g2 + andcc %g1, FPRS_DL, %g0 + be,pn %icc, 4f + mov 0x40, %g3 + stda %f0, [%g2] ASI_BLK_S + stda %f16, [%g2 + %g3] ASI_BLK_S + andcc %g1, FPRS_DU, %g0 + be,pn %icc, 5f +4: add %g2, 128, %g2 + stda %f32, [%g2] ASI_BLK_S + stda %f48, [%g2 + %g3] ASI_BLK_S +5: mov SECONDARY_CONTEXT, %g1 + membar #Sync + +661: stxa %g5, [%g1] ASI_DMMU + .section .sun4v_1insn_patch, "ax" + .word 661b + stxa %g5, [%g1] ASI_MMU + .previous + + membar #Sync + ba,pt %xcc, etrap + wr %g0, 0, %fprs + .size do_fptrap,.-do_fptrap diff --git a/arch/sparc64/kernel/getsetcc.S b/arch/sparc64/kernel/getsetcc.S new file mode 100644 index 00000000000..a14d272d206 --- /dev/null +++ b/arch/sparc64/kernel/getsetcc.S @@ -0,0 +1,24 @@ + .globl getcc + .type getcc,#function +getcc: + ldx [%o0 + PT_V9_TSTATE], %o1 + srlx %o1, 32, %o1 + and %o1, 0xf, %o1 + retl + stx %o1, [%o0 + PT_V9_G1] + .size getcc,.-getcc + + .globl setcc + .type setcc,#function +setcc: + ldx [%o0 + PT_V9_TSTATE], %o1 + ldx [%o0 + PT_V9_G1], %o2 + or %g0, %ulo(TSTATE_ICC), %o3 + sllx %o3, 32, %o3 + andn %o1, %o3, %o1 + sllx %o2, 32, %o2 + and %o2, %o3, %o2 + or %o1, %o2, %o1 + retl + stx %o1, [%o0 + PT_V9_TSTATE] + .size setcc,.-setcc diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 34f8ff57c56..c9afef093d5 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -27,6 +27,10 @@ #include <asm/ttable.h> #include <asm/mmu.h> #include <asm/cpudata.h> +#include <asm/pil.h> +#include <asm/estate.h> +#include <asm/sfafsr.h> +#include <asm/unistd.h> /* This section from from _start to sparc64_boot_end should fit into * 0x0000000000404000 to 0x0000000000408000. @@ -823,7 +827,16 @@ sparc64_boot_end: #include "etrap.S" #include "rtrap.S" #include "winfixup.S" -#include "entry.S" +#include "fpu_traps.S" +#include "ivec.S" +#include "getsetcc.S" +#include "utrap.S" +#include "spiterrs.S" +#include "cherrs.S" +#include "misctrap.S" +#include "syscalls.S" +#include "helpers.S" +#include "hvcalls.S" #include "sun4v_tlb_miss.S" #include "sun4v_ivec.S" #include "ktlb.S" diff --git a/arch/sparc64/kernel/helpers.S b/arch/sparc64/kernel/helpers.S new file mode 100644 index 00000000000..314dd0c9fc5 --- /dev/null +++ b/arch/sparc64/kernel/helpers.S @@ -0,0 +1,63 @@ + .align 32 + .globl __flushw_user + .type __flushw_user,#function +__flushw_user: + rdpr %otherwin, %g1 + brz,pn %g1, 2f + clr %g2 +1: save %sp, -128, %sp + rdpr %otherwin, %g1 + brnz,pt %g1, 1b + add %g2, 1, %g2 +1: sub %g2, 1, %g2 + brnz,pt %g2, 1b + restore %g0, %g0, %g0 +2: retl + nop + .size __flushw_user,.-__flushw_user + + /* Flush %fp and %i7 to the stack for all register + * windows active inside of the cpu. This allows + * show_stack_trace() to avoid using an expensive + * 'flushw'. + */ + .globl stack_trace_flush + .type stack_trace_flush,#function +stack_trace_flush: + rdpr %pstate, %o0 + wrpr %o0, PSTATE_IE, %pstate + + rdpr %cwp, %g1 + rdpr %canrestore, %g2 + sub %g1, 1, %g3 + +1: brz,pn %g2, 2f + sub %g2, 1, %g2 + wrpr %g3, %cwp + stx %fp, [%sp + STACK_BIAS + RW_V9_I6] + stx %i7, [%sp + STACK_BIAS + RW_V9_I7] + ba,pt %xcc, 1b + sub %g3, 1, %g3 + +2: wrpr %g1, %cwp + wrpr %o0, %pstate + + retl + nop + .size stack_trace_flush,.-stack_trace_flush + +#ifdef CONFIG_SMP + .globl hard_smp_processor_id + .type hard_smp_processor_id,#function +hard_smp_processor_id: +#endif + .globl real_hard_smp_processor_id + .type real_hard_smp_processor_id,#function +real_hard_smp_processor_id: + __GET_CPUID(%o0) + retl + nop +#ifdef CONFIG_SMP + .size hard_smp_processor_id,.-hard_smp_processor_id +#endif + .size real_hard_smp_processor_id,.-real_hard_smp_processor_id diff --git a/arch/sparc64/kernel/hvcalls.S b/arch/sparc64/kernel/hvcalls.S new file mode 100644 index 00000000000..a2810f3ac70 --- /dev/null +++ b/arch/sparc64/kernel/hvcalls.S @@ -0,0 +1,886 @@ + /* %o0: devhandle + * %o1: devino + * + * returns %o0: sysino + */ + .globl sun4v_devino_to_sysino + .type sun4v_devino_to_sysino,#function +sun4v_devino_to_sysino: + mov HV_FAST_INTR_DEVINO2SYSINO, %o5 + ta HV_FAST_TRAP + retl + mov %o1, %o0 + .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino + + /* %o0: sysino + * + * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) + */ + .globl sun4v_intr_getenabled + .type sun4v_intr_getenabled,#function +sun4v_intr_getenabled: + mov HV_FAST_INTR_GETENABLED, %o5 + ta HV_FAST_TRAP + retl + mov %o1, %o0 + .size sun4v_intr_getenabled, .-sun4v_intr_getenabled + + /* %o0: sysino + * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) + */ + .globl sun4v_intr_setenabled + .type sun4v_intr_setenabled,#function +sun4v_intr_setenabled: + mov HV_FAST_INTR_SETENABLED, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_intr_setenabled, .-sun4v_intr_setenabled + + /* %o0: sysino + * + * returns %o0: intr_state (HV_INTR_STATE_*) + */ + .globl sun4v_intr_getstate + .type sun4v_intr_getstate,#function +sun4v_intr_getstate: + mov HV_FAST_INTR_GETSTATE, %o5 + ta HV_FAST_TRAP + retl + mov %o1, %o0 + .size sun4v_intr_getstate, .-sun4v_intr_getstate + + /* %o0: sysino + * %o1: intr_state (HV_INTR_STATE_*) + */ + .globl sun4v_intr_setstate + .type sun4v_intr_setstate,#function +sun4v_intr_setstate: + mov HV_FAST_INTR_SETSTATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_intr_setstate, .-sun4v_intr_setstate + + /* %o0: sysino + * + * returns %o0: cpuid + */ + .globl sun4v_intr_gettarget + .type sun4v_intr_gettarget,#function +sun4v_intr_gettarget: + mov HV_FAST_INTR_GETTARGET, %o5 + ta HV_FAST_TRAP + retl + mov %o1, %o0 + .size sun4v_intr_gettarget, .-sun4v_intr_gettarget + + /* %o0: sysino + * %o1: cpuid + */ + .globl sun4v_intr_settarget + .type sun4v_intr_settarget,#function +sun4v_intr_settarget: + mov HV_FAST_INTR_SETTARGET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_intr_settarget, .-sun4v_intr_settarget + + /* %o0: cpuid + * %o1: pc + * %o2: rtba + * %o3: arg0 + * + * returns %o0: status + */ + .globl sun4v_cpu_start + .type sun4v_cpu_start,#function +sun4v_cpu_start: + mov HV_FAST_CPU_START, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_start, .-sun4v_cpu_start + + /* %o0: cpuid + * + * returns %o0: status + */ + .globl sun4v_cpu_stop + .type sun4v_cpu_stop,#function +sun4v_cpu_stop: + mov HV_FAST_CPU_STOP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_stop, .-sun4v_cpu_stop + + /* returns %o0: status */ + .globl sun4v_cpu_yield + .type sun4v_cpu_yield, #function +sun4v_cpu_yield: + mov HV_FAST_CPU_YIELD, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_yield, .-sun4v_cpu_yield + + /* %o0: type + * %o1: queue paddr + * %o2: num queue entries + * + * returns %o0: status + */ + .globl sun4v_cpu_qconf + .type sun4v_cpu_qconf,#function +sun4v_cpu_qconf: + mov HV_FAST_CPU_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_qconf, .-sun4v_cpu_qconf + + /* %o0: num cpus in cpu list + * %o1: cpu list paddr + * %o2: mondo block paddr + * + * returns %o0: status + */ + .globl sun4v_cpu_mondo_send + .type sun4v_cpu_mondo_send,#function +sun4v_cpu_mondo_send: + mov HV_FAST_CPU_MONDO_SEND, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send + + /* %o0: CPU ID + * + * returns %o0: -status if status non-zero, else + * %o0: cpu state as HV_CPU_STATE_* + */ + .globl sun4v_cpu_state + .type sun4v_cpu_state,#function +sun4v_cpu_state: + mov HV_FAST_CPU_STATE, %o5 + ta HV_FAST_TRAP + brnz,pn %o0, 1f + sub %g0, %o0, %o0 + mov %o1, %o0 +1: retl + nop + .size sun4v_cpu_state, .-sun4v_cpu_state + + /* %o0: virtual address + * %o1: must be zero + * %o2: TTE + * %o3: HV_MMU_* flags + * + * returns %o0: status + */ + .globl sun4v_mmu_map_perm_addr + .type sun4v_mmu_map_perm_addr,#function +sun4v_mmu_map_perm_addr: + mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr + + /* %o0: number of TSB descriptions + * %o1: TSB descriptions real address + * + * returns %o0: status + */ + .globl sun4v_mmu_tsb_ctx0 + .type sun4v_mmu_tsb_ctx0,#function +sun4v_mmu_tsb_ctx0: + mov HV_FAST_MMU_TSB_CTX0, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0 + + /* %o0: API group number + * %o1: pointer to unsigned long major number storage + * %o2: pointer to unsigned long minor number storage + * + * returns %o0: status + */ + .globl sun4v_get_version + .type sun4v_get_version,#function +sun4v_get_version: + mov HV_CORE_GET_VER, %o5 + mov %o1, %o3 + mov %o2, %o4 + ta HV_CORE_TRAP + stx %o1, [%o3] + retl + stx %o2, [%o4] + .size sun4v_get_version, .-sun4v_get_version + + /* %o0: API group number + * %o1: desired major number + * %o2: desired minor number + * %o3: pointer to unsigned long actual minor number storage + * + * returns %o0: status + */ + .globl sun4v_set_version + .type sun4v_set_version,#function +sun4v_set_version: + mov HV_CORE_SET_VER, %o5 + mov %o3, %o4 + ta HV_CORE_TRAP + retl + stx %o1, [%o4] + .size sun4v_set_version, .-sun4v_set_version + + /* %o0: pointer to unsigned long time + * + * returns %o0: status + */ + .globl sun4v_tod_get + .type sun4v_tod_get,#function +sun4v_tod_get: + mov %o0, %o4 + mov HV_FAST_TOD_GET, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_tod_get, .-sun4v_tod_get + + /* %o0: time + * + * returns %o0: status + */ + .globl sun4v_tod_set + .type sun4v_tod_set,#function +sun4v_tod_set: + mov HV_FAST_TOD_SET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_tod_set, .-sun4v_tod_set + + /* %o0: pointer to unsigned long status + * + * returns %o0: signed character + */ + .globl sun4v_con_getchar + .type sun4v_con_getchar,#function +sun4v_con_getchar: + mov %o0, %o4 + mov HV_FAST_CONS_GETCHAR, %o5 + clr %o0 + clr %o1 + ta HV_FAST_TRAP + stx %o0, [%o4] + retl + sra %o1, 0, %o0 + .size sun4v_con_getchar, .-sun4v_con_getchar + + /* %o0: signed long character + * + * returns %o0: status + */ + .globl sun4v_con_putchar + .type sun4v_con_putchar,#function +sun4v_con_putchar: + mov HV_FAST_CONS_PUTCHAR, %o5 + ta HV_FAST_TRAP + retl + sra %o0, 0, %o0 + .size sun4v_con_putchar, .-sun4v_con_putchar + + /* %o0: buffer real address + * %o1: buffer size + * %o2: pointer to unsigned long bytes_read + * + * returns %o0: status + */ + .globl sun4v_con_read + .type sun4v_con_read,#function +sun4v_con_read: + mov %o2, %o4 + mov HV_FAST_CONS_READ, %o5 + ta HV_FAST_TRAP + brnz %o0, 1f + cmp %o1, -1 /* break */ + be,a,pn %icc, 1f + mov %o1, %o0 + cmp %o1, -2 /* hup */ + be,a,pn %icc, 1f + mov %o1, %o0 + stx %o1, [%o4] +1: retl + nop + .size sun4v_con_read, .-sun4v_con_read + + /* %o0: buffer real address + * %o1: buffer size + * %o2: pointer to unsigned long bytes_written + * + * returns %o0: status + */ + .globl sun4v_con_write + .type sun4v_con_write,#function +sun4v_con_write: + mov %o2, %o4 + mov HV_FAST_CONS_WRITE, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_con_write, .-sun4v_con_write + + /* %o0: soft state + * %o1: address of description string + * + * returns %o0: status + */ + .globl sun4v_mach_set_soft_state + .type sun4v_mach_set_soft_state,#function +sun4v_mach_set_soft_state: + mov HV_FAST_MACH_SET_SOFT_STATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state + + /* %o0: exit code + * + * Does not return. + */ + .globl sun4v_mach_exit + .type sun4v_mach_exit,#function +sun4v_mach_exit: + mov HV_FAST_MACH_EXIT, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mach_exit, .-sun4v_mach_exit + + /* %o0: buffer real address + * %o1: buffer length + * %o2: pointer to unsigned long real_buf_len + * + * returns %o0: status + */ + .globl sun4v_mach_desc + .type sun4v_mach_desc,#function +sun4v_mach_desc: + mov %o2, %o4 + mov HV_FAST_MACH_DESC, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_desc, .-sun4v_mach_desc + + /* %o0: new timeout in milliseconds + * %o1: pointer to unsigned long orig_timeout + * + * returns %o0: status + */ + .globl sun4v_mach_set_watchdog + .type sun4v_mach_set_watchdog,#function +sun4v_mach_set_watchdog: + mov %o1, %o4 + mov HV_FAST_MACH_SET_WATCHDOG, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog + + /* No inputs and does not return. */ + .globl sun4v_mach_sir + .type sun4v_mach_sir,#function +sun4v_mach_sir: + mov %o1, %o4 + mov HV_FAST_MACH_SIR, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_sir, .-sun4v_mach_sir + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qconf + .type sun4v_ldc_tx_qconf,#function +sun4v_ldc_tx_qconf: + mov HV_FAST_LDC_TX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qinfo + .type sun4v_ldc_tx_qinfo,#function +sun4v_ldc_tx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_TX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_get_state + .type sun4v_ldc_tx_get_state,#function +sun4v_ldc_tx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_TX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state + + /* %o0: channel + * %o1: tail_off + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_set_qtail + .type sun4v_ldc_tx_set_qtail,#function +sun4v_ldc_tx_set_qtail: + mov HV_FAST_LDC_TX_SET_QTAIL, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qconf + .type sun4v_ldc_rx_qconf,#function +sun4v_ldc_rx_qconf: + mov HV_FAST_LDC_RX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qinfo + .type sun4v_ldc_rx_qinfo,#function +sun4v_ldc_rx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_RX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_get_state + .type sun4v_ldc_rx_get_state,#function +sun4v_ldc_rx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_RX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state + + /* %o0: channel + * %o1: head_off + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_set_qhead + .type sun4v_ldc_rx_set_qhead,#function +sun4v_ldc_rx_set_qhead: + mov HV_FAST_LDC_RX_SET_QHEAD, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_set_map_table + .type sun4v_ldc_set_map_table,#function +sun4v_ldc_set_map_table: + mov HV_FAST_LDC_SET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_get_map_table + .type sun4v_ldc_get_map_table,#function +sun4v_ldc_get_map_table: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_GET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table + + /* %o0: channel + * %o1: dir_code + * %o2: tgt_raddr + * %o3: lcl_raddr + * %o4: len + * %o5: pointer to unsigned long actual_len + * + * returns %o0: status + */ + .globl sun4v_ldc_copy + .type sun4v_ldc_copy,#function +sun4v_ldc_copy: + mov %o5, %g1 + mov HV_FAST_LDC_COPY, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_ldc_copy, .-sun4v_ldc_copy + + /* %o0: channel + * %o1: cookie + * %o2: pointer to unsigned long ra + * %o3: pointer to unsigned long perm + * + * returns %o0: status + */ + .globl sun4v_ldc_mapin + .type sun4v_ldc_mapin,#function +sun4v_ldc_mapin: + mov %o2, %g1 + mov %o3, %g2 + mov HV_FAST_LDC_MAPIN, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_mapin, .-sun4v_ldc_mapin + + /* %o0: ra + * + * returns %o0: status + */ + .globl sun4v_ldc_unmap + .type sun4v_ldc_unmap,#function +sun4v_ldc_unmap: + mov HV_FAST_LDC_UNMAP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_unmap, .-sun4v_ldc_unmap + + /* %o0: channel + * %o1: cookie + * %o2: mte_cookie + * + * returns %o0: status + */ + .globl sun4v_ldc_revoke + .type sun4v_ldc_revoke,#function +sun4v_ldc_revoke: + mov HV_FAST_LDC_REVOKE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_revoke, .-sun4v_ldc_revoke + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_get_cookie + .type sun4v_vintr_get_cookie,#function +sun4v_vintr_get_cookie: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_COOKIE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_set_cookie + .type sun4v_vintr_set_cookie,#function +sun4v_vintr_set_cookie: + mov HV_FAST_VINTR_SET_COOKIE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_valid + .type sun4v_vintr_get_valid,#function +sun4v_vintr_get_valid: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_VALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid + + /* %o0: device handle + * %o1: device INO + * %o2: valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_valid + .type sun4v_vintr_set_valid,#function +sun4v_vintr_set_valid: + mov HV_FAST_VINTR_SET_VALID, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_state + .type sun4v_vintr_get_state,#function +sun4v_vintr_get_state: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_state, .-sun4v_vintr_get_state + + /* %o0: device handle + * %o1: device INO + * %o2: state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_state + .type sun4v_vintr_set_state,#function +sun4v_vintr_set_state: + mov HV_FAST_VINTR_SET_STATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_state, .-sun4v_vintr_set_state + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_get_target + .type sun4v_vintr_get_target,#function +sun4v_vintr_get_target: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_TARGET, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_target, .-sun4v_vintr_get_target + + /* %o0: device handle + * %o1: device INO + * %o2: cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_set_target + .type sun4v_vintr_set_target,#function +sun4v_vintr_set_target: + mov HV_FAST_VINTR_SET_TARGET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_target, .-sun4v_vintr_set_target + + /* %o0: NCS sub-function + * %o1: sub-function arg real-address + * %o2: sub-function arg size + * + * returns %o0: status + */ + .globl sun4v_ncs_request + .type sun4v_ncs_request,#function +sun4v_ncs_request: + mov HV_FAST_NCS_REQUEST, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ncs_request, .-sun4v_ncs_request + + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov HV_FAST_SVC_SEND, %o5 + ta HV_FAST_TRAP + stx %o1, [%i3] + ret + restore + .size sun4v_svc_send, .-sun4v_svc_send + + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov HV_FAST_SVC_RECV, %o5 + ta HV_FAST_TRAP + stx %o1, [%i3] + ret + restore + .size sun4v_svc_recv, .-sun4v_svc_recv + + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: + mov HV_FAST_SVC_GETSTATUS, %o5 + mov %o1, %o4 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus + + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: + mov HV_FAST_SVC_SETSTATUS, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus + + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: + mov HV_FAST_SVC_CLRSTATUS, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus + + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: + mov %o1, %o4 + mov HV_FAST_MMUSTAT_CONF, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf + + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: + mov %o0, %o4 + mov HV_FAST_MMUSTAT_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_info, .-sun4v_mmustat_info + + .globl sun4v_mmu_demap_all + .type sun4v_mmu_demap_all,#function +sun4v_mmu_demap_all: + clr %o0 + clr %o1 + mov HV_MMU_ALL, %o2 + mov HV_FAST_MMU_DEMAP_ALL, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all diff --git a/arch/sparc64/kernel/ivec.S b/arch/sparc64/kernel/ivec.S new file mode 100644 index 00000000000..d29f92ebca5 --- /dev/null +++ b/arch/sparc64/kernel/ivec.S @@ -0,0 +1,51 @@ + /* The registers for cross calls will be: + * + * DATA 0: [low 32-bits] Address of function to call, jmp to this + * [high 32-bits] MMU Context Argument 0, place in %g5 + * DATA 1: Address Argument 1, place in %g1 + * DATA 2: Address Argument 2, place in %g7 + * + * With this method we can do most of the cross-call tlb/cache + * flushing very quickly. + */ + .align 32 + .globl do_ivec + .type do_ivec,#function +do_ivec: + mov 0x40, %g3 + ldxa [%g3 + %g0] ASI_INTR_R, %g3 + sethi %hi(KERNBASE), %g4 + cmp %g3, %g4 + bgeu,pn %xcc, do_ivec_xcall + srlx %g3, 32, %g5 + stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync + + sethi %hi(ivector_table_pa), %g2 + ldx [%g2 + %lo(ivector_table_pa)], %g2 + sllx %g3, 4, %g3 + add %g2, %g3, %g3 + + TRAP_LOAD_IRQ_WORK_PA(%g6, %g1) + + ldx [%g6], %g5 + stxa %g5, [%g3] ASI_PHYS_USE_EC + stx %g3, [%g6] + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint + retry +do_ivec_xcall: + mov 0x50, %g1 + ldxa [%g1 + %g0] ASI_INTR_R, %g1 + srl %g3, 0, %g3 + + mov 0x60, %g7 + ldxa [%g7 + %g0] ASI_INTR_R, %g7 + stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync + ba,pt %xcc, 1f + nop + + .align 32 +1: jmpl %g3, %g0 + nop + .size do_ivec,.-do_ivec diff --git a/arch/sparc64/kernel/kgdb.c b/arch/sparc64/kernel/kgdb.c new file mode 100644 index 00000000000..fefbe6dc51b --- /dev/null +++ b/arch/sparc64/kernel/kgdb.c @@ -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 }, +}; diff --git a/arch/sparc64/kernel/misctrap.S b/arch/sparc64/kernel/misctrap.S new file mode 100644 index 00000000000..753b4f031bf --- /dev/null +++ b/arch/sparc64/kernel/misctrap.S @@ -0,0 +1,97 @@ +#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 + stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + call do_privact + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __do_privact,.-__do_privact + + .type do_mna,#function +do_mna: + rdpr %tl, %g3 + cmp %g3, 1 + + /* Setup %g4/%g5 now as they are used in the + * winfixup code. + */ + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g4 + ldxa [%g4] ASI_DMMU, %g4 + ldxa [%g3] ASI_DMMU, %g5 + stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit + membar #Sync + bgu,pn %icc, winfix_mna + rdpr %tpc, %g3 + +1: sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call mem_address_unaligned + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size do_mna,.-do_mna + + .type do_lddfmna,#function +do_lddfmna: + sethi %hi(109f), %g7 + mov TLB_SFSR, %g4 + ldxa [%g4] ASI_DMMU, %g5 + stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit + membar #Sync + mov DMMU_SFAR, %g4 + ldxa [%g4] ASI_DMMU, %g4 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_lddfmna + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size do_lddfmna,.-do_lddfmna + + .type do_stdfmna,#function +do_stdfmna: + sethi %hi(109f), %g7 + mov TLB_SFSR, %g4 + ldxa [%g4] ASI_DMMU, %g5 + stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit + membar #Sync + mov DMMU_SFAR, %g4 + ldxa [%g4] ASI_DMMU, %g4 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call handle_stdfmna + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size do_stdfmna,.-do_stdfmna + + .type breakpoint_trap,#function +breakpoint_trap: + call sparc_breakpoint + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size breakpoint_trap,.-breakpoint_trap diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 409dd71f273..3aba47624df 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -38,7 +38,6 @@ #include <asm/pgtable.h> #include <asm/oplib.h> #include <asm/uaccess.h> -#include <asm/timer.h> #include <asm/starfire.h> #include <asm/tlb.h> #include <asm/sections.h> @@ -910,6 +909,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 +1081,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); diff --git a/arch/sparc64/kernel/spiterrs.S b/arch/sparc64/kernel/spiterrs.S new file mode 100644 index 00000000000..ef902c6f8e3 --- /dev/null +++ b/arch/sparc64/kernel/spiterrs.S @@ -0,0 +1,245 @@ + /* We need to carefully read the error status, ACK the errors, + * prevent recursive traps, and pass the information on to C + * code for logging. + * + * We pass the AFAR in as-is, and we encode the status + * information as described in asm-sparc64/sfafsr.h + */ + .type __spitfire_access_error,#function +__spitfire_access_error: + /* Disable ESTATE error reporting so that we do not take + * recursive traps and RED state the processor. + */ + stxa %g0, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + mov UDBE_UE, %g1 + ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR + + /* __spitfire_cee_trap branches here with AFSR in %g4 and + * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the ESTATE + * Error Enable register. + */ +__spitfire_cee_trap_continue: + ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR + + rdpr %tt, %g3 + and %g3, 0x1ff, %g3 ! Paranoia + sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 + or %g4, %g3, %g4 + rdpr %tl, %g3 + cmp %g3, 1 + mov 1, %g3 + bleu %xcc, 1f + sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 + + or %g4, %g3, %g4 + + /* Read in the UDB error register state, clearing the sticky + * error bits as-needed. We only clear them if the UE bit is + * set. Likewise, __spitfire_cee_trap below will only do so + * if the CE bit is set. + * + * NOTE: UltraSparc-I/II have high and low UDB error + * registers, corresponding to the two UDB units + * present on those chips. UltraSparc-IIi only + * has a single UDB, called "SDB" in the manual. + * For IIi the upper UDB register always reads + * as zero so for our purposes things will just + * work with the checks below. + */ +1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 + and %g3, 0x3ff, %g7 ! Paranoia + sllx %g7, SFSTAT_UDBH_SHIFT, %g7 + or %g4, %g7, %g4 + andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE + be,pn %xcc, 1f + nop + stxa %g3, [%g0] ASI_UDB_ERROR_W + membar #Sync + +1: mov 0x18, %g3 + ldxa [%g3] ASI_UDBL_ERROR_R, %g3 + and %g3, 0x3ff, %g7 ! Paranoia + sllx %g7, SFSTAT_UDBL_SHIFT, %g7 + or %g4, %g7, %g4 + andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE + be,pn %xcc, 1f + nop + mov 0x18, %g7 + stxa %g3, [%g7] ASI_UDB_ERROR_W + membar #Sync + +1: /* Ok, now that we've latched the error state, clear the + * sticky bits in the AFSR. + */ + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + rdpr %tl, %g2 + cmp %g2, 1 + rdpr %pil, %g2 + bleu,pt %xcc, 1f + wrpr %g0, 15, %pil + + ba,pt %xcc, etraptl1 + rd %pc, %g7 + + ba,pt %xcc, 2f + nop + +1: ba,pt %xcc, etrap_irq + rd %pc, %g7 + +2: +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif + mov %l4, %o1 + mov %l5, %o2 + call spitfire_access_error + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __spitfire_access_error,.-__spitfire_access_error + + /* This is the trap handler entry point for ECC correctable + * errors. They are corrected, but we listen for the trap so + * that the event can be logged. + * + * Disrupting errors are either: + * 1) single-bit ECC errors during UDB reads to system + * memory + * 2) data parity errors during write-back events + * + * As far as I can make out from the manual, the CEE trap is + * only for correctable errors during memory read accesses by + * the front-end of the processor. + * + * The code below is only for trap level 1 CEE events, as it + * is the only situation where we can safely record and log. + * For trap level >1 we just clear the CE bit in the AFSR and + * return. + * + * This is just like __spiftire_access_error above, but it + * specifically handles correctable errors. If an + * uncorrectable error is indicated in the AFSR we will branch + * directly above to __spitfire_access_error to handle it + * instead. Uncorrectable therefore takes priority over + * correctable, and the error logging C code will notice this + * case by inspecting the trap type. + */ + .type __spitfire_cee_trap,#function +__spitfire_cee_trap: + ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR + mov 1, %g3 + sllx %g3, SFAFSR_UE_SHIFT, %g3 + andcc %g4, %g3, %g0 ! Check for UE + bne,pn %xcc, __spitfire_access_error + nop + + /* Ok, in this case we only have a correctable error. + * Indicate we only wish to capture that state in register + * %g1, and we only disable CE error reporting unlike UE + * handling which disables all errors. + */ + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 + andn %g3, ESTATE_ERR_CE, %g3 + stxa %g3, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ + ba,pt %xcc, __spitfire_cee_trap_continue + mov UDBE_CE, %g1 + .size __spitfire_cee_trap,.-__spitfire_cee_trap + + .type __spitfire_data_access_exception_tl1,#function +__spitfire_data_access_exception_tl1: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit + membar #Sync + rdpr %tt, %g3 + cmp %g3, 0x80 ! first win spill/fill trap + blu,pn %xcc, 1f + cmp %g3, 0xff ! last win spill/fill trap + bgu,pn %xcc, 1f + nop + ba,pt %xcc, winfix_dax + rdpr %tpc, %g3 +1: sethi %hi(109f), %g7 + ba,pt %xcc, etraptl1 +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_data_access_exception_tl1 + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1 + + .type __spitfire_data_access_exception,#function +__spitfire_data_access_exception: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_data_access_exception + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __spitfire_data_access_exception,.-__spitfire_data_access_exception + + .type __spitfire_insn_access_exception_tl1,#function +__spitfire_insn_access_exception_tl1: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR + rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC + stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etraptl1 +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_insn_access_exception_tl1 + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1 + + .type __spitfire_insn_access_exception,#function +__spitfire_insn_access_exception: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR + rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC + stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_insn_access_exception + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception diff --git a/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S new file mode 100644 index 00000000000..db19ed67acf --- /dev/null +++ b/arch/sparc64/kernel/syscalls.S @@ -0,0 +1,279 @@ + /* SunOS's execv() call only specifies the argv argument, the + * environment settings are the same as the calling processes. + */ +sys_execve: + sethi %hi(sparc_execve), %g1 + ba,pt %xcc, execve_merge + or %g1, %lo(sparc_execve), %g1 + +#ifdef CONFIG_COMPAT +sunos_execv: + stx %g0, [%sp + PTREGS_OFF + PT_V9_I2] +sys32_execve: + sethi %hi(sparc32_execve), %g1 + or %g1, %lo(sparc32_execve), %g1 +#endif + +execve_merge: + flushw + jmpl %g1, %g0 + add %sp, PTREGS_OFF, %o0 + + .align 32 +sys_pipe: + ba,pt %xcc, sparc_pipe + add %sp, PTREGS_OFF, %o0 +sys_nis_syscall: + ba,pt %xcc, c_sys_nis_syscall + add %sp, PTREGS_OFF, %o0 +sys_memory_ordering: + ba,pt %xcc, sparc_memory_ordering + add %sp, PTREGS_OFF, %o1 +sys_sigaltstack: + ba,pt %xcc, do_sigaltstack + add %i6, STACK_BIAS, %o2 +#ifdef CONFIG_COMPAT +sys32_sigstack: + ba,pt %xcc, do_sys32_sigstack + mov %i6, %o2 +sys32_sigaltstack: + ba,pt %xcc, do_sys32_sigaltstack + mov %i6, %o2 +#endif + .align 32 +#ifdef CONFIG_COMPAT +sys32_sigreturn: + add %sp, PTREGS_OFF, %o0 + call do_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +#endif +sys_rt_sigreturn: + add %sp, PTREGS_OFF, %o0 + call do_rt_sigreturn + add %o7, 1f-.-4, %o7 + nop +#ifdef CONFIG_COMPAT +sys32_rt_sigreturn: + add %sp, PTREGS_OFF, %o0 + call do_rt_sigreturn32 + add %o7, 1f-.-4, %o7 + nop +#endif + .align 32 +1: ldx [%g6 + TI_FLAGS], %l5 + andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 + be,pt %icc, rtrap + nop + add %sp, PTREGS_OFF, %o0 + call syscall_trace + mov 1, %o1 + ba,pt %xcc, rtrap + nop + + /* This is how fork() was meant to be done, 8 instruction entry. + * + * I questioned the following code briefly, let me clear things + * up so you must not reason on it like I did. + * + * Know the fork_kpsr etc. we use in the sparc32 port? We don't + * need it here because the only piece of window state we copy to + * the child is the CWP register. Even if the parent sleeps, + * we are safe because we stuck it into pt_regs of the parent + * so it will not change. + * + * XXX This raises the question, whether we can do the same on + * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The + * XXX answer is yes. We stick fork_kpsr in UREG_G0 and + * XXX fork_kwim in UREG_G1 (global registers are considered + * XXX volatile across a system call in the sparc ABI I think + * XXX if it isn't we can use regs->y instead, anyone who depends + * XXX upon the Y register being preserved across a fork deserves + * XXX to lose). + * + * In fact we should take advantage of that fact for other things + * during system calls... + */ + .align 32 +sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */ + sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 + or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 + ba,pt %xcc, sys_clone +sys_fork: + clr %o1 + mov SIGCHLD, %o0 +sys_clone: + flushw + movrz %o1, %fp, %o1 + mov 0, %o3 + ba,pt %xcc, sparc_do_fork + add %sp, PTREGS_OFF, %o2 + + .globl ret_from_syscall +ret_from_syscall: + /* Clear current_thread_info()->new_child, and + * check performance counter stuff too. + */ + stb %g0, [%g6 + TI_NEW_CHILD] + ldx [%g6 + TI_FLAGS], %l0 + call schedule_tail + mov %g7, %o0 + andcc %l0, _TIF_PERFCTR, %g0 + be,pt %icc, 1f + nop + ldx [%g6 + TI_PCR], %o7 + wr %g0, %o7, %pcr + + /* Blackbird errata workaround. See commentary in + * smp.c:smp_percpu_timer_interrupt() for more + * information. + */ + ba,pt %xcc, 99f + nop + + .align 64 +99: wr %g0, %g0, %pic + rd %pic, %g0 + +1: ba,pt %xcc, ret_sys_call + ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 + + .globl sparc_exit + .type sparc_exit,#function +sparc_exit: + rdpr %pstate, %g2 + wrpr %g2, PSTATE_IE, %pstate + rdpr %otherwin, %g1 + rdpr %cansave, %g3 + add %g3, %g1, %g3 + wrpr %g3, 0x0, %cansave + wrpr %g0, 0x0, %otherwin + wrpr %g2, 0x0, %pstate + ba,pt %xcc, sys_exit + stb %g0, [%g6 + TI_WSAVED] + .size sparc_exit,.-sparc_exit + +linux_sparc_ni_syscall: + sethi %hi(sys_ni_syscall), %l7 + ba,pt %xcc, 4f + or %l7, %lo(sys_ni_syscall), %l7 + +linux_syscall_trace32: + add %sp, PTREGS_OFF, %o0 + call syscall_trace + clr %o1 + srl %i0, 0, %o0 + srl %i4, 0, %o4 + srl %i1, 0, %o1 + srl %i2, 0, %o2 + ba,pt %xcc, 2f + srl %i3, 0, %o3 + +linux_syscall_trace: + add %sp, PTREGS_OFF, %o0 + call syscall_trace + clr %o1 + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + b,pt %xcc, 2f + mov %i4, %o4 + + + /* Linux 32-bit system calls enter here... */ + .align 32 + .globl linux_sparc_syscall32 +linux_sparc_syscall32: + /* Direct access to user regs, much faster. */ + cmp %g1, NR_SYSCALLS ! IEU1 Group + bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI + srl %i0, 0, %o0 ! IEU0 + sll %g1, 2, %l4 ! IEU0 Group + srl %i4, 0, %o4 ! IEU1 + lduw [%l7 + %l4], %l7 ! Load + srl %i1, 0, %o1 ! IEU0 Group + ldx [%g6 + TI_FLAGS], %l0 ! Load + + srl %i5, 0, %o5 ! IEU1 + srl %i2, 0, %o2 ! IEU0 Group + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 + bne,pn %icc, linux_syscall_trace32 ! CTI + mov %i0, %l5 ! IEU1 + call %l7 ! CTI Group brk forced + srl %i3, 0, %o3 ! IEU0 + ba,a,pt %xcc, 3f + + /* Linux native system calls enter here... */ + .align 32 + .globl linux_sparc_syscall +linux_sparc_syscall: + /* Direct access to user regs, much faster. */ + cmp %g1, NR_SYSCALLS ! IEU1 Group + bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI + mov %i0, %o0 ! IEU0 + sll %g1, 2, %l4 ! IEU0 Group + mov %i1, %o1 ! IEU1 + lduw [%l7 + %l4], %l7 ! Load +4: mov %i2, %o2 ! IEU0 Group + ldx [%g6 + TI_FLAGS], %l0 ! Load + + mov %i3, %o3 ! IEU1 + mov %i4, %o4 ! IEU0 Group + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 + bne,pn %icc, linux_syscall_trace ! CTI Group + mov %i0, %l5 ! IEU0 +2: call %l7 ! CTI Group brk forced + mov %i5, %o5 ! IEU0 + nop + +3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] +ret_sys_call: + ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 + ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc + sra %o0, 0, %o0 + mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 + sllx %g2, 32, %g2 + + /* Check if force_successful_syscall_return() + * was invoked. + */ + ldub [%g6 + TI_SYS_NOERROR], %l2 + brnz,a,pn %l2, 80f + stb %g0, [%g6 + TI_SYS_NOERROR] + + cmp %o0, -ERESTART_RESTARTBLOCK + bgeu,pn %xcc, 1f + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 +80: + /* System call success, clear Carry condition code. */ + andn %g3, %g2, %g3 + stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] + bne,pn %icc, linux_syscall_trace2 + add %l1, 0x4, %l2 ! npc = npc+4 + stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] + ba,pt %xcc, rtrap + stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] + +1: + /* System call failure, set Carry condition code. + * Also, get abs(errno) to return to the process. + */ + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 + sub %g0, %o0, %o0 + or %g3, %g2, %g3 + stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] + stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE] + bne,pn %icc, linux_syscall_trace2 + add %l1, 0x4, %l2 ! npc = npc+4 + stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] + + b,pt %xcc, rtrap + stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] +linux_syscall_trace2: + add %sp, PTREGS_OFF, %o0 + call syscall_trace + mov 1, %o1 + stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] + ba,pt %xcc, rtrap + stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index b0de4c00b11..450053af039 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -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) diff --git a/arch/sparc64/kernel/utrap.S b/arch/sparc64/kernel/utrap.S new file mode 100644 index 00000000000..b7f0f3f3a90 --- /dev/null +++ b/arch/sparc64/kernel/utrap.S @@ -0,0 +1,29 @@ + .globl utrap_trap + .type utrap_trap,#function +utrap_trap: /* %g3=handler,%g4=level */ + TRAP_LOAD_THREAD_REG(%g6, %g1) + ldx [%g6 + TI_UTRAPS], %g1 + brnz,pt %g1, invoke_utrap + nop + + ba,pt %xcc, etrap + rd %pc, %g7 + mov %l4, %o1 + call bad_trap + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop + +invoke_utrap: + sllx %g3, 3, %g3 + ldx [%g1 + %g3], %g1 + save %sp, -128, %sp + rdpr %tstate, %l6 + rdpr %cwp, %l7 + andn %l6, TSTATE_CWP, %l6 + wrpr %l6, %l7, %tstate + rdpr %tpc, %l6 + rdpr %tnpc, %l7 + wrpr %g1, 0, %tnpc + done + .size utrap_trap,.-utrap_trap diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index e686a67561a..796e005dad8 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -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 */ diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 6d6286c4eea..30a1af857c7 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -132,7 +132,7 @@ static int send_ack; static int final_ack; static int hw_break_val; static int hw_break_val2; -#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) +#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) static int arch_needs_sstep_emulation = 1; #else static int arch_needs_sstep_emulation; diff --git a/include/asm-sparc/head.h b/include/asm-sparc/head.h index fcdba511633..e6532c3e09c 100644 --- a/include/asm-sparc/head.h +++ b/include/asm-sparc/head.h @@ -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; diff --git a/include/asm-sparc/kgdb.h b/include/asm-sparc/kgdb.h index d120adfb429..b6ef301d05b 100644 --- a/include/asm-sparc/kgdb.h +++ b/include/asm-sparc/kgdb.h @@ -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); - -/* 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 */ diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index b3f492208fd..e6d56159972 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -51,13 +51,11 @@ void smp_bogo(struct seq_file *); void smp_info(struct seq_file *); BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) -BTFIXUPDEF_CALL(void, smp_message_pass, int, int, unsigned long, int) BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void) BTFIXUPDEF_BLACKBOX(hard_smp_processor_id) BTFIXUPDEF_BLACKBOX(load_current) #define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5) -#define smp_message_pass(target,msg,data,wait) BTFIXUP_CALL(smp_message_pass)(target,msg,data,wait) static inline void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); } static inline void xc1(smpfunc_t func, unsigned long arg1) diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 4e08210cd4c..b4b024445fc 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.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. diff --git a/include/asm-sparc64/kgdb.h b/include/asm-sparc64/kgdb.h new file mode 100644 index 00000000000..aa6532fd3a1 --- /dev/null +++ b/include/asm-sparc64/kgdb.h @@ -0,0 +1 @@ +#include <asm-sparc/kgdb.h> diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h index 72927749aeb..2f5d126f716 100644 --- a/include/asm-sparc64/pil.h +++ b/include/asm-sparc64/pil.h @@ -19,11 +19,4 @@ #define PIL_SMP_CTX_NEW_VERSION 4 #define PIL_DEVICE_IRQ 5 -#ifndef __ASSEMBLY__ -#define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \ - (PIL) == PIL_SMP_RECEIVE_SIGNAL || \ - (PIL) == PIL_SMP_CAPTURE || \ - (PIL) == PIL_SMP_CTX_NEW_VERSION) -#endif - #endif /* !(_SPARC64_PIL_H) */ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index 53eae091a17..6897ac31be4 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.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)), \ diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index d3cc4eff39a..1b55538b944 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -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; \ |