From 10e267234cc0133bc9ed26bc34eb09de90c248c0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Nov 2006 13:38:57 -0800 Subject: [SPARC64]: Add irqtrace/stacktrace/lockdep support. Signed-off-by: David S. Miller diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index d391d11..d41f66a 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -26,6 +26,14 @@ config MMU bool default y +config STACKTRACE_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + config TIME_INTERPOLATION bool default y diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug index afe0a77..1f130f3 100644 --- a/arch/sparc64/Kconfig.debug +++ b/arch/sparc64/Kconfig.debug @@ -1,5 +1,9 @@ menu "Kernel hacking" +config TRACE_IRQFLAGS_SUPPORT + bool + default y + source "lib/Kconfig.debug" config DEBUG_STACK_USAGE diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index e1eabeb..eff0c01 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -14,6 +14,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ pci_psycho.o pci_sabre.o pci_schizo.o \ pci_sun4v.o pci_sun4v_asm.o diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 6f28bec..c15a3ed 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -597,7 +597,12 @@ __spitfire_cee_trap_continue: 1: ba,pt %xcc, etrap_irq rd %pc, %g7 -2: mov %l4, %o1 +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 @@ -824,6 +829,10 @@ do_cheetah_plus_data_parity: 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 @@ -855,6 +864,10 @@ do_cheetah_plus_insn_parity: 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 @@ -1183,6 +1196,10 @@ c_fast_ecc: 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 @@ -1211,6 +1228,10 @@ c_cee: 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 @@ -1239,6 +1260,10 @@ c_deferred: 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 diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index c8e9dc9..03ffaf8 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -489,6 +489,14 @@ tlb_fixup_done: call __bzero sub %o1, %o0, %o1 +#ifdef CONFIG_LOCKDEP + /* We have this call this super early, as even prom_init can grab + * spinlocks and thus call into the lockdep code. + */ + call lockdep_init + nop +#endif + mov %l6, %o1 ! OpenPROM stack call prom_init mov %l7, %o0 ! OpenPROM cif handler diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 3522cd6..079d18a 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -165,14 +165,26 @@ rtrap: __handle_softirq_continue: rtrap_xcall: sethi %hi(0xf << 20), %l4 - andcc %l1, TSTATE_PRIV, %l3 and %l1, %l4, %l4 + andn %l1, %l4, %l1 + srl %l4, 20, %l4 +#ifdef CONFIG_TRACE_IRQFLAGS + brnz,pn %l4, rtrap_no_irq_enable + nop + call trace_hardirqs_on + nop + wrpr %l4, %pil +rtrap_no_irq_enable: +#endif + andcc %l1, TSTATE_PRIV, %l3 bne,pn %icc, to_kernel - andn %l1, %l4, %l1 + nop /* We must hold IRQs off and atomically test schedule+signal * state, then hold them off all the way back to userspace. - * If we are returning to kernel, none of this matters. + * If we are returning to kernel, none of this matters. Note + * that we are disabling interrupts via PSTATE_IE, not using + * %pil. * * If we do not do this, there is a window where we would do * the tests, later the signal/resched event arrives but we do @@ -256,7 +268,6 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 ld [%sp + PTREGS_OFF + PT_V9_Y], %o3 wr %o3, %g0, %y - srl %l4, 20, %l4 wrpr %l4, 0x0, %pil wrpr %g0, 0x1, %tl wrpr %l1, %g0, %tstate @@ -374,8 +385,8 @@ to_kernel: ldx [%g6 + TI_FLAGS], %l5 andcc %l5, _TIF_NEED_RESCHED, %g0 be,pt %xcc, kern_fpucheck - srl %l4, 20, %l5 - cmp %l5, 0 + nop + cmp %l4, 0 bne,pn %xcc, kern_fpucheck sethi %hi(PREEMPT_ACTIVE), %l6 stw %l6, [%g6 + TI_PRE_COUNT] diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c new file mode 100644 index 0000000..c4d15f2 --- /dev/null +++ b/arch/sparc64/kernel/stacktrace.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + unsigned long ksp, fp, thread_base; + struct thread_info *tp; + + if (!task) + task = current; + tp = task_thread_info(task); + if (task == current) { + flushw_all(); + __asm__ __volatile__( + "mov %%fp, %0" + : "=r" (ksp) + ); + } else + ksp = tp->ksp; + + fp = ksp + STACK_BIAS; + thread_base = (unsigned long) tp; + do { + struct reg_window *rw; + + /* Bogus frame pointer? */ + if (fp < (thread_base + sizeof(struct thread_info)) || + fp >= (thread_base + THREAD_SIZE)) + break; + + rw = (struct reg_window *) fp; + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = rw->ins[7]; + + fp = rw->ins[6] + STACK_BIAS; + } while (trace->nr_entries < trace->max_entries); +} diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index 49703c3..405855d 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -190,7 +190,10 @@ sun4v_res_mondo: mov %g1, %g4 ba,pt %xcc, etrap_irq rd %pc, %g7 - +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif /* Log the event. */ add %sp, PTREGS_OFF, %o0 call sun4v_resum_error @@ -216,7 +219,10 @@ sun4v_res_mondo_queue_full: wrpr %g0, 15, %pil ba,pt %xcc, etrap_irq rd %pc, %g7 - +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif call sun4v_resum_overflow add %sp, PTREGS_OFF, %o0 @@ -295,7 +301,10 @@ sun4v_nonres_mondo: mov %g1, %g4 ba,pt %xcc, etrap_irq rd %pc, %g7 - +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif /* Log the event. */ add %sp, PTREGS_OFF, %o0 call sun4v_nonresum_error @@ -321,7 +330,10 @@ sun4v_nonres_mondo_queue_full: wrpr %g0, 15, %pil ba,pt %xcc, etrap_irq rd %pc, %g7 - +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif call sun4v_nonresum_overflow add %sp, PTREGS_OFF, %o0 diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index d70b60a..737c269 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -477,6 +477,10 @@ xcall_sync_tick: sethi %hi(109f), %g7 b,pt %xcc, etrap_irq 109: or %g7, %lo(109b), %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif call smp_synchronize_tick_client nop clr %l6 @@ -508,6 +512,10 @@ xcall_report_regs: sethi %hi(109f), %g7 b,pt %xcc, etrap_irq 109: or %g7, %lo(109b), %g7 +#ifdef CONFIG_TRACE_IRQFLAGS + call trace_hardirqs_off + nop +#endif call __show_regs add %sp, PTREGS_OFF, %o0 clr %l6 diff --git a/include/asm-sparc64/irqflags.h b/include/asm-sparc64/irqflags.h new file mode 100644 index 0000000..024fc54 --- /dev/null +++ b/include/asm-sparc64/irqflags.h @@ -0,0 +1,89 @@ +/* + * include/asm-sparc64/irqflags.h + * + * IRQ flags handling + * + * This file gets included from lowlevel asm headers too, to provide + * wrapped versions of the local_irq_*() APIs, based on the + * raw_local_irq_*() functions from the lowlevel headers. + */ +#ifndef _ASM_IRQFLAGS_H +#define _ASM_IRQFLAGS_H + +#ifndef __ASSEMBLY__ + +static inline unsigned long __raw_local_save_flags(void) +{ + unsigned long flags; + + __asm__ __volatile__( + "rdpr %%pil, %0" + : "=r" (flags) + ); + + return flags; +} + +#define raw_local_save_flags(flags) \ + do { (flags) = __raw_local_save_flags(); } while (0) + +static inline void raw_local_irq_restore(unsigned long flags) +{ + __asm__ __volatile__( + "wrpr %0, %%pil" + : /* no output */ + : "r" (flags) + : "memory" + ); +} + +static inline void raw_local_irq_disable(void) +{ + __asm__ __volatile__( + "wrpr 15, %%pil" + : /* no outputs */ + : /* no inputs */ + : "memory" + ); +} + +static inline void raw_local_irq_enable(void) +{ + __asm__ __volatile__( + "wrpr 0, %%pil" + : /* no outputs */ + : /* no inputs */ + : "memory" + ); +} + +static inline int raw_irqs_disabled_flags(unsigned long flags) +{ + return (flags > 0); +} + +static inline int raw_irqs_disabled(void) +{ + unsigned long flags = __raw_local_save_flags(); + + return raw_irqs_disabled_flags(flags); +} + +/* + * For spinlocks, etc: + */ +static inline unsigned long __raw_local_irq_save(void) +{ + unsigned long flags = __raw_local_save_flags(); + + raw_local_irq_disable(); + + return flags; +} + +#define raw_local_irq_save(flags) \ + do { (flags) = __raw_local_irq_save(); } while (0) + +#endif /* (__ASSEMBLY__) */ + +#endif /* !(_ASM_IRQFLAGS_H) */ diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h index cef5e82..1294b7c 100644 --- a/include/asm-sparc64/rwsem.h +++ b/include/asm-sparc64/rwsem.h @@ -23,20 +23,33 @@ struct rw_semaphore { signed int count; spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ -{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) } +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) -static __inline__ void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ +do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ +} while (0) extern void __down_read(struct rw_semaphore *sem); extern int __down_read_trylock(struct rw_semaphore *sem); @@ -46,6 +59,11 @@ extern void __up_read(struct rw_semaphore *sem); extern void __up_write(struct rw_semaphore *sem); extern void __downgrade_write(struct rw_semaphore *sem); +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) +{ + __down_write(sem); +} + static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) { return atomic_add_return(delta, (atomic_t *)(&sem->count)); diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index a8b7432..32281ac 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -7,6 +7,9 @@ #include #ifndef __ASSEMBLY__ + +#include + /* * Sparc (general) CPU types */ @@ -72,52 +75,6 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ #endif -#define setipl(__new_ipl) \ - __asm__ __volatile__("wrpr %0, %%pil" : : "r" (__new_ipl) : "memory") - -#define local_irq_disable() \ - __asm__ __volatile__("wrpr 15, %%pil" : : : "memory") - -#define local_irq_enable() \ - __asm__ __volatile__("wrpr 0, %%pil" : : : "memory") - -#define getipl() \ -({ unsigned long retval; __asm__ __volatile__("rdpr %%pil, %0" : "=r" (retval)); retval; }) - -#define swap_pil(__new_pil) \ -({ unsigned long retval; \ - __asm__ __volatile__("rdpr %%pil, %0\n\t" \ - "wrpr %1, %%pil" \ - : "=&r" (retval) \ - : "r" (__new_pil) \ - : "memory"); \ - retval; \ -}) - -#define read_pil_and_cli() \ -({ unsigned long retval; \ - __asm__ __volatile__("rdpr %%pil, %0\n\t" \ - "wrpr 15, %%pil" \ - : "=r" (retval) \ - : : "memory"); \ - retval; \ -}) - -#define local_save_flags(flags) ((flags) = getipl()) -#define local_irq_save(flags) ((flags) = read_pil_and_cli()) -#define local_irq_restore(flags) setipl((flags)) - -/* On sparc64 IRQ flags are the PIL register. A value of zero - * means all interrupt levels are enabled, any other value means - * only IRQ levels greater than that value will be received. - * Consequently this means that the lowest IRQ level is one. - */ -#define irqs_disabled() \ -({ unsigned long flags; \ - local_save_flags(flags);\ - (flags > 0); \ -}) - #define nop() __asm__ __volatile__ ("nop") #define read_barrier_depends() do { } while(0) diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index f235260..c2a16e1 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -137,10 +137,49 @@ #endif #define BREAKPOINT_TRAP TRAP(breakpoint_trap) +#ifdef CONFIG_TRACE_IRQFLAGS + +#define TRAP_IRQ(routine, level) \ + rdpr %pil, %g2; \ + wrpr %g0, 15, %pil; \ + sethi %hi(1f-4), %g7; \ + ba,pt %xcc, etrap_irq; \ + or %g7, %lo(1f-4), %g7; \ + nop; \ + nop; \ + nop; \ + .subsection 2; \ +1: call trace_hardirqs_off; \ + nop; \ + mov level, %o0; \ + call routine; \ + add %sp, PTREGS_OFF, %o1; \ + ba,a,pt %xcc, rtrap_irq; \ + .previous; + +#define TICK_SMP_IRQ \ + rdpr %pil, %g2; \ + wrpr %g0, 15, %pil; \ + sethi %hi(1f-4), %g7; \ + ba,pt %xcc, etrap_irq; \ + or %g7, %lo(1f-4), %g7; \ + nop; \ + nop; \ + nop; \ + .subsection 2; \ +1: call trace_hardirqs_off; \ + nop; \ + call smp_percpu_timer_interrupt; \ + add %sp, PTREGS_OFF, %o0; \ + ba,a,pt %xcc, rtrap_irq; \ + .previous; + +#else + #define TRAP_IRQ(routine, level) \ rdpr %pil, %g2; \ wrpr %g0, 15, %pil; \ - b,pt %xcc, etrap_irq; \ + ba,pt %xcc, etrap_irq; \ rd %pc, %g7; \ mov level, %o0; \ call routine; \ @@ -151,12 +190,14 @@ rdpr %pil, %g2; \ wrpr %g0, 15, %pil; \ sethi %hi(109f), %g7; \ - b,pt %xcc, etrap_irq; \ + ba,pt %xcc, etrap_irq; \ 109: or %g7, %lo(109b), %g7; \ call smp_percpu_timer_interrupt; \ add %sp, PTREGS_OFF, %o0; \ ba,a,pt %xcc, rtrap_irq; +#endif + #define TRAP_IVEC TRAP_NOSAVE(do_ivec) #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl) -- cgit v0.10.2 From 042cf50cfd0bc3e1769d8287465eb522e8a08ba6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Nov 2006 13:40:11 -0800 Subject: [SPARC64]: Update defconfig. Signed-off-by: David S. Miller diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 2f4612f..18a1861 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,12 +1,14 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19-rc2 -# Tue Oct 17 19:29:20 2006 +# Linux kernel version: 2.6.19-rc6 +# Thu Nov 16 13:39:41 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y CONFIG_64BIT=y CONFIG_MMU=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y CONFIG_TIME_INTERPOLATION=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_AUDIT_ARCH=y @@ -48,7 +50,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SYSCTL=y # CONFIG_EMBEDDED is not set CONFIG_UID16=y -# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -145,7 +147,6 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y -# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set CONFIG_SUN_OPENPROMFS=m CONFIG_SPARC32_COMPAT=y @@ -219,7 +220,6 @@ CONFIG_INET6_XFRM_MODE_BEET=m # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set CONFIG_IPV6_SIT=m CONFIG_IPV6_TUNNEL=m -# CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set @@ -1119,6 +1119,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_KAWETH is not set # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET_MII is not set # CONFIG_USB_USBNET is not set # CONFIG_USB_MON is not set @@ -1373,6 +1374,7 @@ CONFIG_KPROBES=y # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_PRINTK_TIME=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y @@ -1387,6 +1389,8 @@ CONFIG_SCHEDSTATS=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set @@ -1420,7 +1424,7 @@ CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_HASH=y -CONFIG_CRYPTO_MANAGER=m +CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=y -- cgit v0.10.2 From 6e7726e16fb5e8f1169dbfcb75e321ac871af827 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 19 Nov 2006 14:38:25 -0800 Subject: [SPARC64]: Call do_mathemu on illegal instruction traps too. To add this logic, put the VIS instruction check at the vis_emul() call site instead of inside of vis_emul(). Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index fe1796c..ec7a601 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2261,8 +2261,12 @@ void die_if_kernel(char *str, struct pt_regs *regs) do_exit(SIGSEGV); } +#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19)) +#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19)) + extern int handle_popc(u32 insn, struct pt_regs *regs); extern int handle_ldf_stq(u32 insn, struct pt_regs *regs); +extern int vis_emul(struct pt_regs *, unsigned int); void do_illegal_instruction(struct pt_regs *regs) { @@ -2287,10 +2291,18 @@ void do_illegal_instruction(struct pt_regs *regs) if (handle_ldf_stq(insn, regs)) return; } else if (tlb_type == hypervisor) { - extern int vis_emul(struct pt_regs *, unsigned int); + if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) { + if (!vis_emul(regs, insn)) + return; + } else { + struct fpustate *f = FPUSTATE; - if (!vis_emul(regs, insn)) - return; + /* XXX maybe verify XFSR bits like + * XXX do_fpother() does? + */ + if (do_mathemu(regs, f)) + return; + } } } info.si_signo = SIGILL; diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c index 84fedaa..c3fd647 100644 --- a/arch/sparc64/kernel/visemul.c +++ b/arch/sparc64/kernel/visemul.c @@ -128,9 +128,6 @@ /* 001001100 - Permute bytes as specified by GSR.MASK */ #define BSHUFFLE_OPF 0x04c -#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19)) -#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19)) - #define VIS_OPF_SHIFT 5 #define VIS_OPF_MASK (0x1ff << VIS_OPF_SHIFT) @@ -810,9 +807,6 @@ int vis_emul(struct pt_regs *regs, unsigned int insn) if (get_user(insn, (u32 __user *) pc)) return -EFAULT; - if ((insn & VIS_OPCODE_MASK) != VIS_OPCODE_VAL) - return -EINVAL; - opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT; switch (opf) { default: -- cgit v0.10.2 From c449c38b5df1fad556ea210deb6cff3b27323e49 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 28 Nov 2006 20:18:05 -0800 Subject: [SPARC64]: Unaligned accesses to userspace are hard errors. Userspace is forbidden from making unaligned loads and stores. So if we get an unaligned trap due to a {get,put}_user(), signal a fault and run the exception handler. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index a9b7652..bc18d48 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -243,7 +243,7 @@ static inline int ok_for_kernel(unsigned int insn) return !floating_point_load_or_store_p(insn); } -static void kernel_mna_trap_fault(void) +static void kernel_mna_trap_fault(int fixup_tstate_asi) { struct pt_regs *regs = current_thread_info()->kern_una_regs; unsigned int insn = current_thread_info()->kern_una_insn; @@ -274,18 +274,15 @@ static void kernel_mna_trap_fault(void) regs->tpc = entry->fixup; regs->tnpc = regs->tpc + 4; - regs->tstate &= ~TSTATE_ASI; - regs->tstate |= (ASI_AIUS << 24UL); + if (fixup_tstate_asi) { + regs->tstate &= ~TSTATE_ASI; + regs->tstate |= (ASI_AIUS << 24UL); + } } -asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) +static void log_unaligned(struct pt_regs *regs) { static unsigned long count, last_time; - enum direction dir = decode_direction(insn); - int size = decode_access_size(insn); - - current_thread_info()->kern_una_regs = regs; - current_thread_info()->kern_una_insn = insn; if (jiffies - last_time > 5 * HZ) count = 0; @@ -295,6 +292,28 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) printk("Kernel unaligned access at TPC[%lx] ", regs->tpc); print_symbol("%s\n", regs->tpc); } +} + +asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) +{ + enum direction dir = decode_direction(insn); + int size = decode_access_size(insn); + int orig_asi, asi; + + current_thread_info()->kern_una_regs = regs; + current_thread_info()->kern_una_insn = insn; + + orig_asi = asi = decode_asi(insn, regs); + + /* If this is a {get,put}_user() on an unaligned userspace pointer, + * just signal a fault and do not log the event. + */ + if (asi == ASI_AIUS) { + kernel_mna_trap_fault(0); + return; + } + + log_unaligned(regs); if (!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel " @@ -302,10 +321,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) unaligned_panic("Kernel does fpu/atomic " "unaligned load/store.", regs); - kernel_mna_trap_fault(); + kernel_mna_trap_fault(0); } else { unsigned long addr, *reg_addr; - int orig_asi, asi, err; + int err; addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); @@ -315,7 +334,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); #endif - orig_asi = asi = decode_asi(insn, regs); switch (asi) { case ASI_NL: case ASI_AIUPL: @@ -365,7 +383,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) /* Not reached... */ } if (unlikely(err)) - kernel_mna_trap_fault(); + kernel_mna_trap_fault(1); else advance(regs); } -- cgit v0.10.2 From a2c1e064c45f5126625121f58afa423e13c55efc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 29 Nov 2006 21:16:21 -0800 Subject: [SPARC64]: Run ctrl-alt-del action for sun4v powerdown request. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index ec7a601..ad67784 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -10,7 +10,7 @@ */ #include -#include /* for jiffies */ +#include #include #include #include @@ -1873,6 +1873,16 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset) put_cpu(); + if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) { + /* If err_type is 0x4, it's a powerdown request. Do + * not do the usual resumable error log because that + * makes it look like some abnormal error. + */ + printk(KERN_INFO "Power down request...\n"); + kill_cad_pid(SIGINT, 1); + return; + } + sun4v_log_error(regs, &local_copy, cpu, KERN_ERR "RESUMABLE ERROR", &sun4v_resum_oflow_cnt); -- cgit v0.10.2 From c80892d150a872b18cedfbf789211bfbebfc67ce Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Thu, 30 Nov 2006 17:07:04 -0800 Subject: [SPARC]: Replace kmalloc+memset with kzalloc Replace kmalloc+memset with kzalloc Signed-off-by: Yan Burman Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 54d51b4..cbbc988 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -317,9 +317,8 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0) goto err_nopages; - if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) + if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) goto err_nomem; - memset((char*)res, 0, sizeof(struct resource)); if (allocate_resource(&_sparc_dvma, res, len_total, _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { @@ -589,12 +588,11 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) return NULL; } - if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { + if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { free_pages(va, order); printk("pci_alloc_consistent: no core\n"); return NULL; } - memset((char*)res, 0, sizeof(struct resource)); if (allocate_resource(&_sparc_dvma, res, len_total, _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 46200c4..dab6169 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -793,10 +793,9 @@ struct of_device* of_platform_device_create(struct device_node *np, { struct of_device *dev; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - memset(dev, 0, sizeof(*dev)); dev->dev.parent = parent; dev->dev.bus = bus; diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index d4f9da8..b8bd53a 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -545,8 +545,7 @@ void __init sun4d_init_sbi_irq(void) nsbi = 0; for_each_sbus(sbus) nsbi++; - sbus_actions = (struct sbus_action *)kmalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); - memset (sbus_actions, 0, (nsbi * 8 * 4 * sizeof(struct sbus_action))); + sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); for_each_sbus(sbus) { #ifdef CONFIG_SMP extern unsigned char boot_cpu_id; diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 2bb1309..0070620 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -41,9 +41,8 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) struct linux_prom_registers iommu_promregs[PROMREG_MAX]; struct resource r; - iounit = kmalloc(sizeof(struct iounit_struct), GFP_ATOMIC); + iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); - memset(iounit, 0, sizeof(*iounit)); iounit->limit[0] = IOUNIT_BMAP1_START; iounit->limit[1] = IOUNIT_BMAP2_START; iounit->limit[2] = IOUNIT_BMAPM_START; -- cgit v0.10.2 From d4accd60d23f3c8a576fd08b727f88096f42d445 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 30 Nov 2006 17:11:26 -0800 Subject: [SPARC]: Check kzalloc() return value in SUN4D irq/iommu init. Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index b8bd53a..cf1b8ba 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -546,6 +546,10 @@ void __init sun4d_init_sbi_irq(void) for_each_sbus(sbus) nsbi++; sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); + if (!sbus_actions) { + prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); + prom_halt(); + } for_each_sbus(sbus) { #ifdef CONFIG_SMP extern unsigned char boot_cpu_id; diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 0070620..4ccda77 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -22,6 +22,7 @@ #include #include #include +#include /* #define IOUNIT_DEBUG */ #ifdef IOUNIT_DEBUG @@ -42,6 +43,10 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus) struct resource r; iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC); + if (!iounit) { + prom_printf("SUN4D: Cannot alloc iounit, halting.\n"); + prom_halt(); + } iounit->limit[0] = IOUNIT_BMAP1_START; iounit->limit[1] = IOUNIT_BMAP2_START; -- cgit v0.10.2 From 982c2064d9a8b51404088d132489a25e2db807fd Mon Sep 17 00:00:00 2001 From: Yan Burman Date: Thu, 30 Nov 2006 17:13:09 -0800 Subject: [SPARC64]: Replace kmalloc+memset with kzalloc Replace kmalloc+memset with kzalloc Signed-off-by: Yan Burman Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 259f37e..9699abe 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c @@ -341,7 +341,7 @@ static void fetch_decode_regs(struct mctrl_info *mp) static int init_one_mctrl(struct device_node *dp) { - struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL); + struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL); int portid = of_getintprop_default(dp, "portid", -1); struct linux_prom64_registers *regs; void *pval; @@ -349,7 +349,6 @@ static int init_one_mctrl(struct device_node *dp) if (!mp) return -1; - memset(mp, 0, sizeof(*mp)); if (portid == -1) goto fail; diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index f028e68..ad1c4f5 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -72,14 +72,12 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) struct linux_prom_registers *regs; struct sparc_isa_device *isa_dev; - isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); + isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { fatal_err("cannot allocate child isa_dev"); prom_halt(); } - memset(isa_dev, 0, sizeof(*isa_dev)); - /* Link it in to parent. */ isa_dev->next = parent_isa_dev->child; parent_isa_dev->child = isa_dev; @@ -104,14 +102,12 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) struct linux_prom_registers *regs; struct sparc_isa_device *isa_dev; - isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); + isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL); if (!isa_dev) { printk(KERN_DEBUG "ISA: cannot allocate isa_dev"); return; } - memset(isa_dev, 0, sizeof(*isa_dev)); - isa_dev->ofdev.node = dp; isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; isa_dev->ofdev.dev.bus = &isa_bus_type; @@ -180,14 +176,12 @@ void __init isa_init(void) pbm = pdev_cookie->pbm; dp = pdev_cookie->prom_node; - isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL); + isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL); if (!isa_br) { printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge"); return; } - memset(isa_br, 0, sizeof(*isa_br)); - isa_br->ofdev.node = dp; isa_br->ofdev.dev.parent = &pdev->dev; isa_br->ofdev.dev.bus = &isa_bus_type; diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 8cc14fc..cec0ece 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -1007,10 +1007,9 @@ struct of_device* of_platform_device_create(struct device_node *np, { struct of_device *dev; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; - memset(dev, 0, sizeof(*dev)); dev->dev.parent = parent; dev->dev.bus = bus; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 03ad4c0..6b04794 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -798,7 +798,7 @@ static struct pci_ops pci_sun4v_ops = { static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm) { - struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); + struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { prom_printf("%s: Critical allocation failure.\n", pbm->name); @@ -806,7 +806,6 @@ static void pbm_scan_bus(struct pci_controller_info *p, } /* All we care about is the PBM. */ - memset(cookie, 0, sizeof(*cookie)); cookie->pbm = pbm; pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); @@ -1048,12 +1047,11 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) /* Allocate and initialize the free area map. */ sz = num_tsb_entries / 8; sz = (sz + 7UL) & ~7UL; - iommu->arena.map = kmalloc(sz, GFP_KERNEL); + iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); prom_halt(); } - memset(iommu->arena.map, 0, sz); iommu->arena.limit = num_tsb_entries; sz = probe_existing_entries(pbm, iommu); @@ -1164,24 +1162,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) per_cpu(pci_iommu_batch, i).pglist = (u64 *) page; } - p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) goto fatal_memory_error; - memset(p, 0, sizeof(*p)); - - iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; - memset(iommu, 0, sizeof(*iommu)); p->pbm_A.iommu = iommu; - iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); + iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) goto fatal_memory_error; - memset(iommu, 0, sizeof(*iommu)); p->pbm_B.iommu = iommu; p->next = pci_controller_root; -- cgit v0.10.2 From 35bca36cf7b20a73a89f87aab34b1b4dfff6bf08 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 1 Dec 2006 20:18:40 -0800 Subject: [SPARC{32,64}]: Propagate ptrace_traceme() return value. ptrace_traceme() consolidation made ret = ptrace_traceme(); dead write. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 1baf13e..003f8ee 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -289,7 +289,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); - pt_succ_return(regs, 0); + if (ret < 0) + pt_error_return(regs, -ret); + else + pt_succ_return(regs, 0); goto out; } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index d31975e..81111a1 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -202,7 +202,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs) #endif if (request == PTRACE_TRACEME) { ret = ptrace_traceme(); - pt_succ_return(regs, 0); + if (ret < 0) + pt_error_return(regs, -ret); + else + pt_succ_return(regs, 0); goto out; } -- cgit v0.10.2 From 5ff42459af99427a393e3b576a77a900d43e730a Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 1 Dec 2006 20:19:59 -0800 Subject: [SPARC64]: dma remove extra brackets Signed-off-by: Mariusz Kozlowski Signed-off-by: David S. Miller diff --git a/include/asm-sparc64/dma.h b/include/asm-sparc64/dma.h index 27f6597..93e5a06 100644 --- a/include/asm-sparc64/dma.h +++ b/include/asm-sparc64/dma.h @@ -152,9 +152,9 @@ extern void dvma_init(struct sbus_bus *); #define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL)) /* Yes, I hack a lot of elisp in my spare time... */ -#define DMA_ERROR_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR)) -#define DMA_IRQ_P(regs) (((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))) -#define DMA_WRITE_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE)) +#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR)) +#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) +#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE)) #define DMA_OFF(__regs) \ do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \ tmp &= ~DMA_ENABLE; \ -- cgit v0.10.2 From 2f149228bb30ea08bfde740178f832d5c9081005 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 9 Dec 2006 15:41:53 -0800 Subject: [SPARC64]: Update defconfig. Signed-off-by: David S. Miller diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 18a1861..0f0d38f 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19-rc6 -# Thu Nov 16 13:39:41 2006 +# Linux kernel version: 2.6.19 +# Sat Dec 9 15:41:30 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -11,16 +11,19 @@ CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_TIME_INTERPOLATION=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_AUDIT_ARCH=y CONFIG_SPARC64_PAGE_SIZE_8KB=y # CONFIG_SPARC64_PAGE_SIZE_64KB is not set # CONFIG_SPARC64_PAGE_SIZE_512KB is not set # CONFIG_SPARC64_PAGE_SIZE_4MB is not set CONFIG_SECCOMP=y -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y +CONFIG_HZ_100=y +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set -CONFIG_HZ=250 +CONFIG_HZ=100 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -44,6 +47,7 @@ CONFIG_POSIX_MQUEUE=y # CONFIG_UTS_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +CONFIG_SYSFS_DEPRECATED=y CONFIG_RELAY=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -147,6 +151,7 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_MULTITHREAD_PROBE is not set # CONFIG_PCI_DEBUG is not set CONFIG_SUN_OPENPROMFS=m CONFIG_SPARC32_COMPAT=y @@ -204,6 +209,7 @@ CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_CUBIC=y CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y @@ -238,6 +244,8 @@ CONFIG_IP_DCCP_CCID2=m # CONFIG_IP_DCCP_CCID2_DEBUG is not set CONFIG_IP_DCCP_CCID3=m CONFIG_IP_DCCP_TFRC_LIB=m +# CONFIG_IP_DCCP_CCID3_DEBUG is not set +CONFIG_IP_DCCP_CCID3_RTO=100 # # DCCP Kernel Hacking @@ -405,6 +413,7 @@ CONFIG_IDEDMA_AUTO=y # CONFIG_RAID_ATTRS=m CONFIG_SCSI=y +# CONFIG_SCSI_TGT is not set CONFIG_SCSI_NETLINK=y CONFIG_SCSI_PROC_FS=y @@ -425,6 +434,7 @@ CONFIG_CHR_DEV_SG=m CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set # # SCSI Transports @@ -468,6 +478,7 @@ CONFIG_ISCSI_TCP=m # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_SUNESP is not set +# CONFIG_SCSI_SRP is not set # # Serial ATA (prod) and Parallel ATA (experimental) drivers @@ -598,6 +609,7 @@ CONFIG_BNX2=m # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set # # Token Ring devices @@ -724,10 +736,6 @@ CONFIG_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set @@ -1039,6 +1047,11 @@ CONFIG_SND_SUN_CS4231=m # CONFIG_SOUND_PRIME is not set # +# HID Devices +# +CONFIG_HID=y + +# # USB support # CONFIG_USB_ARCH_HAS_HCD=y @@ -1053,6 +1066,7 @@ CONFIG_USB=y CONFIG_USB_DEVICEFS=y # CONFIG_USB_BANDWIDTH is not set # CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_MULTITHREAD_PROBE is not set # CONFIG_USB_OTG is not set # @@ -1089,8 +1103,7 @@ CONFIG_USB_UHCI_HCD=m # USB Input Devices # CONFIG_USB_HID=y -CONFIG_USB_HIDINPUT=y -# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_USB_HID_POWERBOOK is not set # CONFIG_HID_FF is not set CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set @@ -1365,6 +1378,11 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_UTF8 is not set # +# Distributed Lock Manager +# +# CONFIG_DLM is not set + +# # Instrumentation Support # CONFIG_PROFILING=y @@ -1426,6 +1444,7 @@ CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_MD5=y @@ -1434,8 +1453,10 @@ CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_GF128MUL=m CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_TWOFISH=m @@ -1460,6 +1481,7 @@ CONFIG_CRYPTO_TEST=m # # Library routines # +CONFIG_BITREVERSE=y CONFIG_CRC_CCITT=m CONFIG_CRC16=m CONFIG_CRC32=y -- cgit v0.10.2 From f0882589666440d573f657cb3a1d5f66f3caa157 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 10 Dec 2006 02:42:03 -0800 Subject: [SPARC64]: Fix several kprobes bugs. - relbranch_fixup(), for non-branches, would end up setting regs->tnpc incorrectly, in fact it would set it equal to regs->tpc which would cause that instruction to execute twice Also, if this is not a PC-relative branch, we should just leave regs->tnpc as-is. This covers cases like 'jmpl' which branch to absolute values. - To be absolutely %100 safe, we need to flush the instruction cache for all assignments to kprobe->ainsn.insn[], including cases like add_aggr_kprobe() - prev_kprobe's status field needs to be 'unsigned long' to match the type of the value it is saving - jprobes were totally broken: = jprobe_return() can run in the stack frame of the jprobe handler, or in an even deeper stack frame, thus we'll be in the wrong register window than the one from the original probe state. So unwind using 'restore' instructions, if necessary, right before we do the jprobe_return() breakpoint trap. = There is no reason to save/restore the register window saved at %sp at jprobe trigger time. Those registers cannot be modified by the jprobe handler. Also, this code was saving and restoring "sizeof (struct sparc_stackf)" bytes. Depending upon the caller, this could clobber unrelated stack frame pieces if there is only a basic 128-byte register window stored on the stack, without the argument save area. So just saving and restoring struct pt_regs is sufficient. = Kill the "jprobe_saved_esp", totally unused. Also, delete "jprobe_saved_regs_location", with the stack frame unwind now done explicitly by jprobe_return(), this check is superfluous. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index 8e75ed7..ae221f0 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c @@ -45,7 +45,11 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); int __kprobes arch_prepare_kprobe(struct kprobe *p) { p->ainsn.insn[0] = *p->addr; + flushi(&p->ainsn.insn[0]); + p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2; + flushi(&p->ainsn.insn[1]); + p->opcode = *p->addr; return 0; } @@ -185,16 +189,19 @@ no_kprobe: /* If INSN is a relative control transfer instruction, * return the corrected branch destination value. * - * The original INSN location was REAL_PC, it actually - * executed at PC and produced destination address NPC. + * regs->tpc and regs->tnpc still hold the values of the + * program counters at the time of trap due to the execution + * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1] + * */ -static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc, - unsigned long pc, - unsigned long npc) +static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p, + struct pt_regs *regs) { + unsigned long real_pc = (unsigned long) p->addr; + /* Branch not taken, no mods necessary. */ - if (npc == pc + 0x4UL) - return real_pc + 0x4UL; + if (regs->tnpc == regs->tpc + 0x4UL) + return real_pc + 0x8UL; /* The three cases are call, branch w/prediction, * and traditional branch. @@ -202,14 +209,21 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc, if ((insn & 0xc0000000) == 0x40000000 || (insn & 0xc1c00000) == 0x00400000 || (insn & 0xc1c00000) == 0x00800000) { + unsigned long ainsn_addr; + + ainsn_addr = (unsigned long) &p->ainsn.insn[0]; + /* The instruction did all the work for us * already, just apply the offset to the correct * instruction location. */ - return (real_pc + (npc - pc)); + return (real_pc + (regs->tnpc - ainsn_addr)); } - return real_pc + 0x4UL; + /* It is jmpl or some other absolute PC modification instruction, + * leave NPC as-is. + */ + return regs->tnpc; } /* If INSN is an instruction which writes it's PC location @@ -220,12 +234,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn, { unsigned long *slot = NULL; - /* Simplest cast is call, which always uses %o7 */ + /* Simplest case is 'call', which always uses %o7 */ if ((insn & 0xc0000000) == 0x40000000) { slot = ®s->u_regs[UREG_I7]; } - /* Jmpl encodes the register inside of the opcode */ + /* 'jmpl' encodes the register inside of the opcode */ if ((insn & 0xc1f80000) == 0x81c00000) { unsigned long rd = ((insn >> 25) & 0x1f); @@ -247,11 +261,11 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn, /* * Called after single-stepping. p->addr is the address of the - * instruction whose first byte has been replaced by the breakpoint + * instruction which has been replaced by the breakpoint * instruction. To avoid the SMP problems that can occur when we * temporarily put back the original opcode to single-step, we * single-stepped a copy of the instruction. The address of this - * copy is p->ainsn.insn. + * copy is &p->ainsn.insn[0]. * * This function prepares to return from the post-single-step * breakpoint trap. @@ -261,11 +275,11 @@ static void __kprobes resume_execution(struct kprobe *p, { u32 insn = p->ainsn.insn[0]; + regs->tnpc = relbranch_fixup(insn, p, regs); + + /* This assignment must occur after relbranch_fixup() */ regs->tpc = kcb->kprobe_orig_tnpc; - regs->tnpc = relbranch_fixup(insn, - (unsigned long) p->addr, - (unsigned long) &p->ainsn.insn[0], - regs->tnpc); + retpc_fixup(regs, insn, (unsigned long) p->addr); regs->tstate = ((regs->tstate & ~TSTATE_PIL) | @@ -430,17 +444,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) struct jprobe *jp = container_of(p, struct jprobe, kp); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - kcb->jprobe_saved_regs_location = regs; memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs)); - /* Save a whole stack frame, this gets arguments - * pushed onto the stack after using up all the - * arg registers. - */ - memcpy(&(kcb->jprobe_saved_stack), - (char *) (regs->u_regs[UREG_FP] + STACK_BIAS), - sizeof(kcb->jprobe_saved_stack)); - regs->tpc = (unsigned long) jp->entry; regs->tnpc = ((unsigned long) jp->entry) + 0x4UL; regs->tstate |= TSTATE_PIL; @@ -450,10 +455,19 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) void __kprobes jprobe_return(void) { - __asm__ __volatile__( - ".globl jprobe_return_trap_instruction\n" + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + register unsigned long orig_fp asm("g1"); + + orig_fp = kcb->jprobe_saved_regs.u_regs[UREG_FP]; + __asm__ __volatile__("\n" +"1: cmp %%sp, %0\n\t" + "blu,a,pt %%xcc, 1b\n\t" + " restore\n\t" + ".globl jprobe_return_trap_instruction\n" "jprobe_return_trap_instruction:\n\t" - "ta 0x70"); + "ta 0x70" + : /* no outputs */ + : "r" (orig_fp)); } extern void jprobe_return_trap_instruction(void); @@ -466,26 +480,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); if (addr == (u32 *) jprobe_return_trap_instruction) { - if (kcb->jprobe_saved_regs_location != regs) { - printk("JPROBE: Current regs (%p) does not match " - "saved regs (%p).\n", - regs, kcb->jprobe_saved_regs_location); - printk("JPROBE: Saved registers\n"); - __show_regs(kcb->jprobe_saved_regs_location); - printk("JPROBE: Current registers\n"); - __show_regs(regs); - BUG(); - } - /* Restore old register state. Do pt_regs - * first so that UREG_FP is the original one for - * the stack frame restore. - */ memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs)); - - memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS), - &(kcb->jprobe_saved_stack), - sizeof(kcb->jprobe_saved_stack)); - preempt_enable_no_resched(); return 1; } diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index c9f5c34..becc38f 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h @@ -13,7 +13,11 @@ typedef u32 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define arch_remove_kprobe(p) do {} while (0) #define ARCH_INACTIVE_KPROBE_COUNT 0 -#define flush_insn_slot(p) do { } while (0) + +#define flush_insn_slot(p) \ +do { flushi(&(p)->ainsn.insn[0]); \ + flushi(&(p)->ainsn.insn[1]); \ +} while (0) /* Architecture specific copy of original instruction*/ struct arch_specific_insn { @@ -23,7 +27,7 @@ struct arch_specific_insn { struct prev_kprobe { struct kprobe *kp; - unsigned int status; + unsigned long status; unsigned long orig_tnpc; unsigned long orig_tstate_pil; }; @@ -33,10 +37,7 @@ struct kprobe_ctlblk { unsigned long kprobe_status; unsigned long kprobe_orig_tnpc; unsigned long kprobe_orig_tstate_pil; - long *jprobe_saved_esp; struct pt_regs jprobe_saved_regs; - struct pt_regs *jprobe_saved_regs_location; - struct sparc_stackf jprobe_saved_stack; struct prev_kprobe prev_kprobe; }; -- cgit v0.10.2