2005-09-26 10:04:21 +04:00
/*
* Copyright ( C ) 1995 - 1996 Gary Thomas ( gdt @ linuxppc . org )
2010-04-08 09:38:22 +04:00
* Copyright 2007 - 2010 Freescale Semiconductor , Inc .
2005-09-26 10:04:21 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* Modified by Cort Dougan ( cort @ cs . nmt . edu )
* and Paul Mackerras ( paulus @ samba . org )
*/
/*
* This file handles the architecture - dependent parts of hardware exceptions
*/
# include <linux/errno.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/stddef.h>
# include <linux/unistd.h>
2005-10-06 07:27:05 +04:00
# include <linux/ptrace.h>
2005-09-26 10:04:21 +04:00
# include <linux/user.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/module.h>
2005-10-06 07:27:05 +04:00
# include <linux/prctl.h>
2005-09-26 10:04:21 +04:00
# include <linux/delay.h>
# include <linux/kprobes.h>
2005-12-04 10:39:43 +03:00
# include <linux/kexec.h>
2006-06-25 16:47:08 +04:00
# include <linux/backlight.h>
2006-12-08 14:30:41 +03:00
# include <linux/bug.h>
2007-05-08 11:27:03 +04:00
# include <linux/kdebug.h>
2009-05-18 06:10:05 +04:00
# include <linux/debugfs.h>
2011-06-04 09:36:54 +04:00
# include <linux/ratelimit.h>
2005-09-26 10:04:21 +04:00
2009-05-18 06:10:05 +04:00
# include <asm/emulated_ops.h>
2005-09-26 10:04:21 +04:00
# include <asm/pgtable.h>
# include <asm/uaccess.h>
# include <asm/system.h>
# include <asm/io.h>
2005-10-10 16:37:57 +04:00
# include <asm/machdep.h>
# include <asm/rtas.h>
2005-10-19 08:53:32 +04:00
# include <asm/pmc.h>
2005-10-01 12:43:42 +04:00
# ifdef CONFIG_PPC32
2005-09-26 10:04:21 +04:00
# include <asm/reg.h>
2005-10-10 16:37:57 +04:00
# endif
2005-09-26 10:04:21 +04:00
# ifdef CONFIG_PMAC_BACKLIGHT
# include <asm/backlight.h>
# endif
2005-10-01 12:43:42 +04:00
# ifdef CONFIG_PPC64
2005-10-10 16:37:57 +04:00
# include <asm/firmware.h>
2005-10-01 12:43:42 +04:00
# include <asm/processor.h>
# endif
2006-06-24 02:29:34 +04:00
# include <asm/kexec.h>
2009-02-10 23:10:44 +03:00
# include <asm/ppc-opcode.h>
2010-11-18 09:57:32 +03:00
# include <asm/rio.h>
2005-10-01 12:43:42 +04:00
2008-01-31 06:34:47 +03:00
# if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
2010-01-12 03:50:14 +03:00
int ( * __debugger ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_ipi ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_bpt ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_sstep ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_iabr_match ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_dabr_match ) ( struct pt_regs * regs ) __read_mostly ;
int ( * __debugger_fault_handler ) ( struct pt_regs * regs ) __read_mostly ;
2005-09-26 10:04:21 +04:00
EXPORT_SYMBOL ( __debugger ) ;
EXPORT_SYMBOL ( __debugger_ipi ) ;
EXPORT_SYMBOL ( __debugger_bpt ) ;
EXPORT_SYMBOL ( __debugger_sstep ) ;
EXPORT_SYMBOL ( __debugger_iabr_match ) ;
EXPORT_SYMBOL ( __debugger_dabr_match ) ;
EXPORT_SYMBOL ( __debugger_fault_handler ) ;
# endif
/*
* Trap & Exception support
*/
2007-03-21 04:38:12 +03:00
# ifdef CONFIG_PMAC_BACKLIGHT
static void pmac_backlight_unblank ( void )
{
mutex_lock ( & pmac_backlight_mutex ) ;
if ( pmac_backlight ) {
struct backlight_properties * props ;
props = & pmac_backlight - > props ;
props - > brightness = props - > max_brightness ;
props - > power = FB_BLANK_UNBLANK ;
backlight_update_status ( pmac_backlight ) ;
}
mutex_unlock ( & pmac_backlight_mutex ) ;
}
# else
static inline void pmac_backlight_unblank ( void ) { }
# endif
2005-09-26 10:04:21 +04:00
int die ( const char * str , struct pt_regs * regs , long err )
{
2007-03-21 04:38:13 +03:00
static struct {
2010-02-18 05:22:31 +03:00
raw_spinlock_t lock ;
2007-03-21 04:38:13 +03:00
u32 lock_owner ;
int lock_owner_depth ;
} die = {
2010-02-18 05:22:31 +03:00
. lock = __RAW_SPIN_LOCK_UNLOCKED ( die . lock ) ,
2007-03-21 04:38:13 +03:00
. lock_owner = - 1 ,
. lock_owner_depth = 0
} ;
2006-06-24 02:29:34 +04:00
static int die_counter ;
2007-03-21 04:38:13 +03:00
unsigned long flags ;
2005-09-26 10:04:21 +04:00
if ( debugger ( regs ) )
return 1 ;
2007-03-21 04:38:11 +03:00
oops_enter ( ) ;
2007-03-21 04:38:13 +03:00
if ( die . lock_owner ! = raw_smp_processor_id ( ) ) {
console_verbose ( ) ;
2010-02-18 05:22:31 +03:00
raw_spin_lock_irqsave ( & die . lock , flags ) ;
2007-03-21 04:38:13 +03:00
die . lock_owner = smp_processor_id ( ) ;
die . lock_owner_depth = 0 ;
bust_spinlocks ( 1 ) ;
if ( machine_is ( powermac ) )
pmac_backlight_unblank ( ) ;
} else {
local_save_flags ( flags ) ;
}
2006-06-25 16:47:08 +04:00
2007-03-21 04:38:13 +03:00
if ( + + die . lock_owner_depth < 3 ) {
printk ( " Oops: %s, sig: %ld [#%d] \n " , str , err , + + die_counter ) ;
2005-09-26 10:04:21 +04:00
# ifdef CONFIG_PREEMPT
2007-03-21 04:38:13 +03:00
printk ( " PREEMPT " ) ;
2005-09-26 10:04:21 +04:00
# endif
# ifdef CONFIG_SMP
2007-03-21 04:38:13 +03:00
printk ( " SMP NR_CPUS=%d " , NR_CPUS ) ;
2005-09-26 10:04:21 +04:00
# endif
# ifdef CONFIG_DEBUG_PAGEALLOC
2007-03-21 04:38:13 +03:00
printk ( " DEBUG_PAGEALLOC " ) ;
2005-09-26 10:04:21 +04:00
# endif
# ifdef CONFIG_NUMA
2007-03-21 04:38:13 +03:00
printk ( " NUMA " ) ;
2005-09-26 10:04:21 +04:00
# endif
2007-03-21 04:38:14 +03:00
printk ( " %s \n " , ppc_md . name ? ppc_md . name : " " ) ;
2007-03-21 04:38:13 +03:00
2010-02-07 17:44:16 +03:00
if ( notify_die ( DIE_OOPS , str , regs , err , 255 ,
SIGSEGV ) = = NOTIFY_STOP )
return 1 ;
2007-03-21 04:38:13 +03:00
print_modules ( ) ;
show_regs ( regs ) ;
} else {
printk ( " Recursive die() failure, output suppressed \n " ) ;
}
2006-03-28 16:15:54 +04:00
2005-09-26 10:04:21 +04:00
bust_spinlocks ( 0 ) ;
2007-03-21 04:38:13 +03:00
die . lock_owner = - 1 ;
2007-07-17 15:03:42 +04:00
add_taint ( TAINT_DIE ) ;
2011-11-30 04:23:09 +04:00
oops_exit ( ) ;
printk ( " \n " ) ;
2010-02-18 05:22:31 +03:00
raw_spin_unlock_irqrestore ( & die . lock , flags ) ;
2005-12-04 10:39:43 +03:00
2011-11-30 04:23:10 +04:00
/*
* A system reset ( 0x100 ) is a request to dump , so we always send
* it through the crashdump code .
*/
if ( kexec_should_crash ( current ) | | ( TRAP ( regs ) = = 0x100 ) ) {
2005-12-04 10:39:43 +03:00
crash_kexec ( regs ) ;
2011-11-30 04:23:10 +04:00
/*
* We aren ' t the primary crash CPU . We need to send it
* to a holding pattern to avoid it ending up in the panic
* code .
*/
crash_kexec_secondary ( regs ) ;
}
2005-09-26 10:04:21 +04:00
2011-11-30 04:23:09 +04:00
/*
* While our oops output is serialised by a spinlock , output
* from panic ( ) called below can race and corrupt it . If we
* know we are going to panic , delay for 1 second so we have a
* chance to get clean backtraces from all CPUs that are oopsing .
*/
if ( in_interrupt ( ) | | panic_on_oops | | ! current - > pid | |
is_global_init ( current ) ) {
mdelay ( MSEC_PER_SEC ) ;
}
2005-09-26 10:04:21 +04:00
if ( in_interrupt ( ) )
panic ( " Fatal exception in interrupt " ) ;
2006-07-30 14:03:34 +04:00
if ( panic_on_oops )
2006-08-14 10:24:22 +04:00
panic ( " Fatal exception " ) ;
2006-07-30 14:03:34 +04:00
2005-09-26 10:04:21 +04:00
do_exit ( err ) ;
return 0 ;
}
2009-12-16 03:47:18 +03:00
void user_single_step_siginfo ( struct task_struct * tsk ,
struct pt_regs * regs , siginfo_t * info )
{
memset ( info , 0 , sizeof ( * info ) ) ;
info - > si_signo = SIGTRAP ;
info - > si_code = TRAP_TRACE ;
info - > si_addr = ( void __user * ) regs - > nip ;
}
2005-09-26 10:04:21 +04:00
void _exception ( int signr , struct pt_regs * regs , int code , unsigned long addr )
{
siginfo_t info ;
2007-10-12 04:20:07 +04:00
const char fmt32 [ ] = KERN_INFO " %s[%d]: unhandled signal %d " \
" at %08lx nip %08lx lr %08lx code %x \n " ;
const char fmt64 [ ] = KERN_INFO " %s[%d]: unhandled signal %d " \
" at %016lx nip %016lx lr %016lx code %x \n " ;
2005-09-26 10:04:21 +04:00
if ( ! user_mode ( regs ) ) {
if ( die ( " Exception in kernel mode " , regs , signr ) )
return ;
2007-10-12 04:20:07 +04:00
} else if ( show_unhandled_signals & &
2011-06-04 09:36:54 +04:00
unhandled_signal ( current , signr ) ) {
printk_ratelimited ( regs - > msr & MSR_64BIT ? fmt64 : fmt32 ,
current - > comm , current - > pid , signr ,
addr , regs - > nip , regs - > link , code ) ;
}
2005-09-26 10:04:21 +04:00
memset ( & info , 0 , sizeof ( info ) ) ;
info . si_signo = signr ;
info . si_code = code ;
info . si_addr = ( void __user * ) addr ;
force_sig_info ( signr , & info , current ) ;
}
# ifdef CONFIG_PPC64
void system_reset_exception ( struct pt_regs * regs )
{
/* See if any machine dependent calls */
2006-01-04 22:55:53 +03:00
if ( ppc_md . system_reset_exception ) {
if ( ppc_md . system_reset_exception ( regs ) )
return ;
}
2005-09-26 10:04:21 +04:00
2005-10-06 07:27:05 +04:00
die ( " System Reset " , regs , SIGABRT ) ;
2005-09-26 10:04:21 +04:00
/* Must die if the interrupt is not recoverable */
if ( ! ( regs - > msr & MSR_RI ) )
panic ( " Unrecoverable System Reset " ) ;
/* What should we do here? We could issue a shutdown or hard reset. */
}
# endif
/*
* I / O accesses can cause machine checks on powermacs .
* Check if the NIP corresponds to the address of a sync
* instruction for which there is an entry in the exception
* table .
* Note that the 601 only takes a machine check on TEA
* ( transfer error ack ) signal assertion , and does not
* set any of the top 16 bits of SRR1 .
* - - paulus .
*/
static inline int check_io_access ( struct pt_regs * regs )
{
2006-11-13 01:27:39 +03:00
# ifdef CONFIG_PPC32
2005-09-26 10:04:21 +04:00
unsigned long msr = regs - > msr ;
const struct exception_table_entry * entry ;
unsigned int * nip = ( unsigned int * ) regs - > nip ;
if ( ( ( msr & 0xffff0000 ) = = 0 | | ( msr & ( 0x80000 | 0x40000 ) ) )
& & ( entry = search_exception_tables ( regs - > nip ) ) ! = NULL ) {
/*
* Check that it ' s a sync instruction , or somewhere
* in the twi ; isync ; nop sequence that inb / inw / inl uses .
* As the address is in the exception table
* we should be able to read the instr there .
* For the debug message , we look at the preceding
* load or store .
*/
if ( * nip = = 0x60000000 ) /* nop */
nip - = 2 ;
else if ( * nip = = 0x4c00012c ) /* isync */
- - nip ;
if ( * nip = = 0x7c0004ac | | ( * nip > > 26 ) = = 3 ) {
/* sync or twi */
unsigned int rb ;
- - nip ;
rb = ( * nip > > 11 ) & 0x1f ;
printk ( KERN_DEBUG " %s bad port %lx at %p \n " ,
( * nip & 0x100 ) ? " OUT to " : " IN from " ,
regs - > gpr [ rb ] - _IO_BASE , nip ) ;
regs - > msr | = MSR_RI ;
regs - > nip = entry - > fixup ;
return 1 ;
}
}
2006-11-13 01:27:39 +03:00
# endif /* CONFIG_PPC32 */
2005-09-26 10:04:21 +04:00
return 0 ;
}
2010-02-08 14:50:57 +03:00
# ifdef CONFIG_PPC_ADV_DEBUG_REGS
2005-09-26 10:04:21 +04:00
/* On 4xx, the reason for the machine check or program exception
is in the ESR . */
# define get_reason(regs) ((regs)->dsisr)
# ifndef CONFIG_FSL_BOOKE
# define get_mc_reason(regs) ((regs)->dsisr)
# else
2010-04-08 09:38:22 +04:00
# define get_mc_reason(regs) (mfspr(SPRN_MCSR))
2005-09-26 10:04:21 +04:00
# endif
# define REASON_FP ESR_FP
# define REASON_ILLEGAL (ESR_PIL | ESR_PUO)
# define REASON_PRIVILEGED ESR_PPR
# define REASON_TRAP ESR_PTR
/* single-step stuff */
# define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC)
# define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC)
# else
/* On non-4xx, the reason for the machine check or program
exception is in the MSR . */
# define get_reason(regs) ((regs)->msr)
# define get_mc_reason(regs) ((regs)->msr)
# define REASON_FP 0x100000
# define REASON_ILLEGAL 0x80000
# define REASON_PRIVILEGED 0x40000
# define REASON_TRAP 0x20000
# define single_stepping(regs) ((regs)->msr & MSR_SE)
# define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
# endif
2007-12-21 07:39:21 +03:00
# if defined(CONFIG_4xx)
int machine_check_4xx ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
2006-03-31 07:11:15 +04:00
unsigned long reason = get_mc_reason ( regs ) ;
2005-09-26 10:04:21 +04:00
if ( reason & ESR_IMCP ) {
printk ( " Instruction " ) ;
mtspr ( SPRN_ESR , reason & ~ ESR_IMCP ) ;
} else
printk ( " Data " ) ;
printk ( " machine check in kernel mode. \n " ) ;
2007-12-21 07:39:21 +03:00
return 0 ;
}
int machine_check_440A ( struct pt_regs * regs )
{
unsigned long reason = get_mc_reason ( regs ) ;
2005-09-26 10:04:21 +04:00
printk ( " Machine check in kernel mode. \n " ) ;
if ( reason & ESR_IMCP ) {
printk ( " Instruction Synchronous Machine Check exception \n " ) ;
mtspr ( SPRN_ESR , reason & ~ ESR_IMCP ) ;
}
else {
u32 mcsr = mfspr ( SPRN_MCSR ) ;
if ( mcsr & MCSR_IB )
printk ( " Instruction Read PLB Error \n " ) ;
if ( mcsr & MCSR_DRB )
printk ( " Data Read PLB Error \n " ) ;
if ( mcsr & MCSR_DWB )
printk ( " Data Write PLB Error \n " ) ;
if ( mcsr & MCSR_TLBP )
printk ( " TLB Parity Error \n " ) ;
if ( mcsr & MCSR_ICP ) {
flush_instruction_cache ( ) ;
printk ( " I-Cache Parity Error \n " ) ;
}
if ( mcsr & MCSR_DCSP )
printk ( " D-Cache Search Parity Error \n " ) ;
if ( mcsr & MCSR_DCFP )
printk ( " D-Cache Flush Parity Error \n " ) ;
if ( mcsr & MCSR_IMPE )
printk ( " Machine Check exception is imprecise \n " ) ;
/* Clear MCSR */
mtspr ( SPRN_MCSR , mcsr ) ;
}
2007-12-21 07:39:21 +03:00
return 0 ;
}
2010-03-05 06:43:18 +03:00
int machine_check_47x ( struct pt_regs * regs )
{
unsigned long reason = get_mc_reason ( regs ) ;
u32 mcsr ;
printk ( KERN_ERR " Machine check in kernel mode. \n " ) ;
if ( reason & ESR_IMCP ) {
printk ( KERN_ERR
" Instruction Synchronous Machine Check exception \n " ) ;
mtspr ( SPRN_ESR , reason & ~ ESR_IMCP ) ;
return 0 ;
}
mcsr = mfspr ( SPRN_MCSR ) ;
if ( mcsr & MCSR_IB )
printk ( KERN_ERR " Instruction Read PLB Error \n " ) ;
if ( mcsr & MCSR_DRB )
printk ( KERN_ERR " Data Read PLB Error \n " ) ;
if ( mcsr & MCSR_DWB )
printk ( KERN_ERR " Data Write PLB Error \n " ) ;
if ( mcsr & MCSR_TLBP )
printk ( KERN_ERR " TLB Parity Error \n " ) ;
if ( mcsr & MCSR_ICP ) {
flush_instruction_cache ( ) ;
printk ( KERN_ERR " I-Cache Parity Error \n " ) ;
}
if ( mcsr & MCSR_DCSP )
printk ( KERN_ERR " D-Cache Search Parity Error \n " ) ;
if ( mcsr & PPC47x_MCSR_GPR )
printk ( KERN_ERR " GPR Parity Error \n " ) ;
if ( mcsr & PPC47x_MCSR_FPR )
printk ( KERN_ERR " FPR Parity Error \n " ) ;
if ( mcsr & PPC47x_MCSR_IPR )
printk ( KERN_ERR " Machine Check exception is imprecise \n " ) ;
/* Clear MCSR */
mtspr ( SPRN_MCSR , mcsr ) ;
return 0 ;
}
2007-12-21 07:39:21 +03:00
# elif defined(CONFIG_E500)
2010-04-08 09:38:22 +04:00
int machine_check_e500mc ( struct pt_regs * regs )
{
unsigned long mcsr = mfspr ( SPRN_MCSR ) ;
unsigned long reason = mcsr ;
int recoverable = 1 ;
2011-06-16 23:09:17 +04:00
if ( reason & MCSR_LD ) {
2010-11-18 09:57:32 +03:00
recoverable = fsl_rio_mcheck_exception ( regs ) ;
if ( recoverable = = 1 )
goto silent_out ;
}
2010-04-08 09:38:22 +04:00
printk ( " Machine check in kernel mode. \n " ) ;
printk ( " Caused by (from MCSR=%lx): " , reason ) ;
if ( reason & MCSR_MCP )
printk ( " Machine Check Signal \n " ) ;
if ( reason & MCSR_ICPERR ) {
printk ( " Instruction Cache Parity Error \n " ) ;
/*
* This is recoverable by invalidating the i - cache .
*/
mtspr ( SPRN_L1CSR1 , mfspr ( SPRN_L1CSR1 ) | L1CSR1_ICFI ) ;
while ( mfspr ( SPRN_L1CSR1 ) & L1CSR1_ICFI )
;
/*
* This will generally be accompanied by an instruction
* fetch error report - - only treat MCSR_IF as fatal
* if it wasn ' t due to an L1 parity error .
*/
reason & = ~ MCSR_IF ;
}
if ( reason & MCSR_DCPERR_MC ) {
printk ( " Data Cache Parity Error \n " ) ;
2011-08-27 15:14:23 +04:00
/*
* In write shadow mode we auto - recover from the error , but it
* may still get logged and cause a machine check . We should
* only treat the non - write shadow case as non - recoverable .
*/
if ( ! ( mfspr ( SPRN_L1CSR2 ) & L1CSR2_DCWS ) )
recoverable = 0 ;
2010-04-08 09:38:22 +04:00
}
if ( reason & MCSR_L2MMU_MHIT ) {
printk ( " Hit on multiple TLB entries \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_NMI )
printk ( " Non-maskable interrupt \n " ) ;
if ( reason & MCSR_IF ) {
printk ( " Instruction Fetch Error Report \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_LD ) {
printk ( " Load Error Report \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_ST ) {
printk ( " Store Error Report \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_LDG ) {
printk ( " Guarded Load Error Report \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_TLBSYNC )
printk ( " Simultaneous tlbsync operations \n " ) ;
if ( reason & MCSR_BSL2_ERR ) {
printk ( " Level 2 Cache Error \n " ) ;
recoverable = 0 ;
}
if ( reason & MCSR_MAV ) {
u64 addr ;
addr = mfspr ( SPRN_MCAR ) ;
addr | = ( u64 ) mfspr ( SPRN_MCARU ) < < 32 ;
printk ( " Machine Check %s Address: %#llx \n " ,
reason & MCSR_MEA ? " Effective " : " Physical " , addr ) ;
}
2010-11-18 09:57:32 +03:00
silent_out :
2010-04-08 09:38:22 +04:00
mtspr ( SPRN_MCSR , mcsr ) ;
return mfspr ( SPRN_MCSR ) = = 0 & & recoverable ;
}
2007-12-21 07:39:21 +03:00
int machine_check_e500 ( struct pt_regs * regs )
{
unsigned long reason = get_mc_reason ( regs ) ;
2010-11-18 09:57:32 +03:00
if ( reason & MCSR_BUS_RBERR ) {
if ( fsl_rio_mcheck_exception ( regs ) )
return 1 ;
}
2005-09-26 10:04:21 +04:00
printk ( " Machine check in kernel mode. \n " ) ;
printk ( " Caused by (from MCSR=%lx): " , reason ) ;
if ( reason & MCSR_MCP )
printk ( " Machine Check Signal \n " ) ;
if ( reason & MCSR_ICPERR )
printk ( " Instruction Cache Parity Error \n " ) ;
if ( reason & MCSR_DCP_PERR )
printk ( " Data Cache Push Parity Error \n " ) ;
if ( reason & MCSR_DCPERR )
printk ( " Data Cache Parity Error \n " ) ;
if ( reason & MCSR_BUS_IAERR )
printk ( " Bus - Instruction Address Error \n " ) ;
if ( reason & MCSR_BUS_RAERR )
printk ( " Bus - Read Address Error \n " ) ;
if ( reason & MCSR_BUS_WAERR )
printk ( " Bus - Write Address Error \n " ) ;
if ( reason & MCSR_BUS_IBERR )
printk ( " Bus - Instruction Data Error \n " ) ;
if ( reason & MCSR_BUS_RBERR )
printk ( " Bus - Read Data Bus Error \n " ) ;
if ( reason & MCSR_BUS_WBERR )
printk ( " Bus - Read Data Bus Error \n " ) ;
if ( reason & MCSR_BUS_IPERR )
printk ( " Bus - Instruction Parity Error \n " ) ;
if ( reason & MCSR_BUS_RPERR )
printk ( " Bus - Read Parity Error \n " ) ;
2007-12-21 07:39:21 +03:00
return 0 ;
}
2010-10-08 17:32:11 +04:00
int machine_check_generic ( struct pt_regs * regs )
{
return 0 ;
}
2007-12-21 07:39:21 +03:00
# elif defined(CONFIG_E200)
int machine_check_e200 ( struct pt_regs * regs )
{
unsigned long reason = get_mc_reason ( regs ) ;
2005-09-26 10:04:21 +04:00
printk ( " Machine check in kernel mode. \n " ) ;
printk ( " Caused by (from MCSR=%lx): " , reason ) ;
if ( reason & MCSR_MCP )
printk ( " Machine Check Signal \n " ) ;
if ( reason & MCSR_CP_PERR )
printk ( " Cache Push Parity Error \n " ) ;
if ( reason & MCSR_CPERR )
printk ( " Cache Parity Error \n " ) ;
if ( reason & MCSR_EXCP_ERR )
printk ( " ISI, ITLB, or Bus Error on first instruction fetch for an exception handler \n " ) ;
if ( reason & MCSR_BUS_IRERR )
printk ( " Bus - Read Bus Error on instruction fetch \n " ) ;
if ( reason & MCSR_BUS_DRERR )
printk ( " Bus - Read Bus Error on data load \n " ) ;
if ( reason & MCSR_BUS_WRERR )
printk ( " Bus - Write Bus Error on buffered store or cache line push \n " ) ;
2007-12-21 07:39:21 +03:00
return 0 ;
}
# else
int machine_check_generic ( struct pt_regs * regs )
{
unsigned long reason = get_mc_reason ( regs ) ;
2005-09-26 10:04:21 +04:00
printk ( " Machine check in kernel mode. \n " ) ;
printk ( " Caused by (from SRR1=%lx): " , reason ) ;
switch ( reason & 0x601F0000 ) {
case 0x80000 :
printk ( " Machine check signal \n " ) ;
break ;
case 0 : /* for 601 */
case 0x40000 :
case 0x140000 : /* 7450 MSS error and TEA */
printk ( " Transfer error ack signal \n " ) ;
break ;
case 0x20000 :
printk ( " Data parity error signal \n " ) ;
break ;
case 0x10000 :
printk ( " Address parity error signal \n " ) ;
break ;
case 0x20000000 :
printk ( " L1 Data Cache error \n " ) ;
break ;
case 0x40000000 :
printk ( " L1 Instruction Cache error \n " ) ;
break ;
case 0x00100000 :
printk ( " L2 data cache parity error \n " ) ;
break ;
default :
printk ( " Unknown values in msr \n " ) ;
}
2007-09-20 23:11:20 +04:00
return 0 ;
}
2007-12-21 07:39:21 +03:00
# endif /* everything else */
2007-09-20 23:11:20 +04:00
void machine_check_exception ( struct pt_regs * regs )
{
int recover = 0 ;
2010-01-31 23:34:06 +03:00
__get_cpu_var ( irq_stat ) . mce_exceptions + + ;
2007-12-21 07:39:21 +03:00
/* See if any machine dependent calls. In theory, we would want
* to call the CPU first , and call the ppc_md . one if the CPU
* one returns a positive number . However there is existing code
* that assumes the board gets a first chance , so let ' s keep it
* that way for now and fix things later . - - BenH .
*/
2007-09-20 23:11:20 +04:00
if ( ppc_md . machine_check_exception )
recover = ppc_md . machine_check_exception ( regs ) ;
2007-12-21 07:39:21 +03:00
else if ( cur_cpu_spec - > machine_check )
recover = cur_cpu_spec - > machine_check ( regs ) ;
2007-09-20 23:11:20 +04:00
2007-12-21 07:39:21 +03:00
if ( recover > 0 )
2007-09-20 23:11:20 +04:00
return ;
# if defined(CONFIG_8xx) && defined(CONFIG_PCI)
2007-12-21 07:39:21 +03:00
/* the qspan pci read routines can cause machine checks -- Cort
*
* yuck ! ! ! that totally needs to go away ! There are better ways
* to deal with that than having a wart in the mcheck handler .
* - - BenH
*/
2007-09-20 23:11:20 +04:00
bad_page_fault ( regs , regs - > dar , SIGBUS ) ;
return ;
# endif
2011-01-11 22:45:31 +03:00
if ( debugger_fault_handler ( regs ) )
2007-09-20 23:11:20 +04:00
return ;
if ( check_io_access ( regs ) )
return ;
2005-10-06 07:27:05 +04:00
die ( " Machine check " , regs , SIGBUS ) ;
2005-09-26 10:04:21 +04:00
/* Must die if the interrupt is not recoverable */
if ( ! ( regs - > msr & MSR_RI ) )
panic ( " Unrecoverable Machine check " ) ;
}
void SMIException ( struct pt_regs * regs )
{
die ( " System Management Interrupt " , regs , SIGABRT ) ;
}
2005-10-01 12:43:42 +04:00
void unknown_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
printk ( " Bad trap at PC: %lx, SR: %lx, vector=%lx \n " ,
regs - > nip , regs - > msr , regs - > trap ) ;
_exception ( SIGTRAP , regs , 0 , 0 ) ;
}
2005-10-01 12:43:42 +04:00
void instruction_breakpoint_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
if ( notify_die ( DIE_IABR_MATCH , " iabr_match " , regs , 5 ,
5 , SIGTRAP ) = = NOTIFY_STOP )
return ;
if ( debugger_iabr_match ( regs ) )
return ;
_exception ( SIGTRAP , regs , TRAP_BRKPT , regs - > nip ) ;
}
void RunModeException ( struct pt_regs * regs )
{
_exception ( SIGTRAP , regs , 0 , 0 ) ;
}
2005-10-06 07:27:05 +04:00
void __kprobes single_step_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
2010-06-15 10:05:31 +04:00
clear_single_step ( regs ) ;
2005-09-26 10:04:21 +04:00
if ( notify_die ( DIE_SSTEP , " single_step " , regs , 5 ,
5 , SIGTRAP ) = = NOTIFY_STOP )
return ;
if ( debugger_sstep ( regs ) )
return ;
_exception ( SIGTRAP , regs , TRAP_TRACE , regs - > nip ) ;
}
/*
* After we have successfully emulated an instruction , we have to
* check if the instruction was being single - stepped , and if so ,
* pretend we got a single - step exception . This was pointed out
* by Kumar Gala . - - paulus
*/
2005-10-06 07:27:05 +04:00
static void emulate_single_step ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
2010-06-15 10:05:31 +04:00
if ( single_stepping ( regs ) )
single_step_exception ( regs ) ;
2005-09-26 10:04:21 +04:00
}
2007-02-07 10:47:59 +03:00
static inline int __parse_fpscr ( unsigned long fpscr )
2005-10-01 12:43:42 +04:00
{
2007-02-07 10:47:59 +03:00
int ret = 0 ;
2005-10-01 12:43:42 +04:00
/* Invalid operation */
if ( ( fpscr & FPSCR_VE ) & & ( fpscr & FPSCR_VX ) )
2007-02-07 10:47:59 +03:00
ret = FPE_FLTINV ;
2005-10-01 12:43:42 +04:00
/* Overflow */
else if ( ( fpscr & FPSCR_OE ) & & ( fpscr & FPSCR_OX ) )
2007-02-07 10:47:59 +03:00
ret = FPE_FLTOVF ;
2005-10-01 12:43:42 +04:00
/* Underflow */
else if ( ( fpscr & FPSCR_UE ) & & ( fpscr & FPSCR_UX ) )
2007-02-07 10:47:59 +03:00
ret = FPE_FLTUND ;
2005-10-01 12:43:42 +04:00
/* Divide by zero */
else if ( ( fpscr & FPSCR_ZE ) & & ( fpscr & FPSCR_ZX ) )
2007-02-07 10:47:59 +03:00
ret = FPE_FLTDIV ;
2005-10-01 12:43:42 +04:00
/* Inexact result */
else if ( ( fpscr & FPSCR_XE ) & & ( fpscr & FPSCR_XX ) )
2007-02-07 10:47:59 +03:00
ret = FPE_FLTRES ;
return ret ;
}
static void parse_fpe ( struct pt_regs * regs )
{
int code = 0 ;
flush_fp_to_thread ( current ) ;
code = __parse_fpscr ( current - > thread . fpscr . val ) ;
2005-10-01 12:43:42 +04:00
_exception ( SIGFPE , regs , code , regs - > nip ) ;
}
/*
* Illegal instruction emulation support . Originally written to
2005-09-26 10:04:21 +04:00
* provide the PVR to user applications using the mfspr rd , PVR .
* Return non - zero if we can ' t emulate , or - EFAULT if the associated
* memory access caused an access fault . Return zero on success .
*
* There are a couple of ways to do this , either " decode " the instruction
* or directly match lots of bits . In this case , matching lots of
* bits is faster and easier .
2005-10-10 16:37:57 +04:00
*
2005-09-26 10:04:21 +04:00
*/
static int emulate_string_inst ( struct pt_regs * regs , u32 instword )
{
u8 rT = ( instword > > 21 ) & 0x1f ;
u8 rA = ( instword > > 16 ) & 0x1f ;
u8 NB_RB = ( instword > > 11 ) & 0x1f ;
u32 num_bytes ;
unsigned long EA ;
int pos = 0 ;
/* Early out if we are an invalid form of lswx */
2009-02-10 23:10:44 +03:00
if ( ( instword & PPC_INST_STRING_MASK ) = = PPC_INST_LSWX )
2005-09-26 10:04:21 +04:00
if ( ( rT = = rA ) | | ( rT = = NB_RB ) )
return - EINVAL ;
EA = ( rA = = 0 ) ? 0 : regs - > gpr [ rA ] ;
2009-02-10 23:10:44 +03:00
switch ( instword & PPC_INST_STRING_MASK ) {
case PPC_INST_LSWX :
case PPC_INST_STSWX :
2005-09-26 10:04:21 +04:00
EA + = NB_RB ;
num_bytes = regs - > xer & 0x7f ;
break ;
2009-02-10 23:10:44 +03:00
case PPC_INST_LSWI :
case PPC_INST_STSWI :
2005-09-26 10:04:21 +04:00
num_bytes = ( NB_RB = = 0 ) ? 32 : NB_RB ;
break ;
default :
return - EINVAL ;
}
while ( num_bytes ! = 0 )
{
u8 val ;
u32 shift = 8 * ( 3 - ( pos & 0x3 ) ) ;
2009-02-10 23:10:44 +03:00
switch ( ( instword & PPC_INST_STRING_MASK ) ) {
case PPC_INST_LSWX :
case PPC_INST_LSWI :
2005-09-26 10:04:21 +04:00
if ( get_user ( val , ( u8 __user * ) EA ) )
return - EFAULT ;
/* first time updating this reg,
* zero it out */
if ( pos = = 0 )
regs - > gpr [ rT ] = 0 ;
regs - > gpr [ rT ] | = val < < shift ;
break ;
2009-02-10 23:10:44 +03:00
case PPC_INST_STSWI :
case PPC_INST_STSWX :
2005-09-26 10:04:21 +04:00
val = regs - > gpr [ rT ] > > shift ;
if ( put_user ( val , ( u8 __user * ) EA ) )
return - EFAULT ;
break ;
}
/* move EA to next address */
EA + = 1 ;
num_bytes - - ;
/* manage our position within the register */
if ( + + pos = = 4 ) {
pos = 0 ;
if ( + + rT = = 32 )
rT = 0 ;
}
}
return 0 ;
}
2006-08-30 22:11:38 +04:00
static int emulate_popcntb_inst ( struct pt_regs * regs , u32 instword )
{
u32 ra , rs ;
unsigned long tmp ;
ra = ( instword > > 16 ) & 0x1f ;
rs = ( instword > > 21 ) & 0x1f ;
tmp = regs - > gpr [ rs ] ;
tmp = tmp - ( ( tmp > > 1 ) & 0x5555555555555555ULL ) ;
tmp = ( tmp & 0x3333333333333333ULL ) + ( ( tmp > > 2 ) & 0x3333333333333333ULL ) ;
tmp = ( tmp + ( tmp > > 4 ) ) & 0x0f0f0f0f0f0f0f0fULL ;
regs - > gpr [ ra ] = tmp ;
return 0 ;
}
2007-11-20 06:35:29 +03:00
static int emulate_isel ( struct pt_regs * regs , u32 instword )
{
u8 rT = ( instword > > 21 ) & 0x1f ;
u8 rA = ( instword > > 16 ) & 0x1f ;
u8 rB = ( instword > > 11 ) & 0x1f ;
u8 BC = ( instword > > 6 ) & 0x1f ;
u8 bit ;
unsigned long tmp ;
tmp = ( rA = = 0 ) ? 0 : regs - > gpr [ rA ] ;
bit = ( regs - > ccr > > ( 31 - BC ) ) & 0x1 ;
regs - > gpr [ rT ] = bit ? tmp : regs - > gpr [ rB ] ;
return 0 ;
}
2005-09-26 10:04:21 +04:00
static int emulate_instruction ( struct pt_regs * regs )
{
u32 instword ;
u32 rd ;
2006-06-07 10:14:40 +04:00
if ( ! user_mode ( regs ) | | ( regs - > msr & MSR_LE ) )
2005-09-26 10:04:21 +04:00
return - EINVAL ;
CHECK_FULL_REGS ( regs ) ;
if ( get_user ( instword , ( u32 __user * ) ( regs - > nip ) ) )
return - EFAULT ;
/* Emulate the mfspr rD, PVR. */
2009-02-10 23:10:44 +03:00
if ( ( instword & PPC_INST_MFSPR_PVR_MASK ) = = PPC_INST_MFSPR_PVR ) {
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( mfpvr , regs ) ;
2005-09-26 10:04:21 +04:00
rd = ( instword > > 21 ) & 0x1f ;
regs - > gpr [ rd ] = mfspr ( SPRN_PVR ) ;
return 0 ;
}
/* Emulating the dcba insn is just a no-op. */
2009-05-18 06:10:05 +04:00
if ( ( instword & PPC_INST_DCBA_MASK ) = = PPC_INST_DCBA ) {
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( dcba , regs ) ;
2005-09-26 10:04:21 +04:00
return 0 ;
2009-05-18 06:10:05 +04:00
}
2005-09-26 10:04:21 +04:00
/* Emulate the mcrxr insn. */
2009-02-10 23:10:44 +03:00
if ( ( instword & PPC_INST_MCRXR_MASK ) = = PPC_INST_MCRXR ) {
2005-10-10 16:37:57 +04:00
int shift = ( instword > > 21 ) & 0x1c ;
2005-09-26 10:04:21 +04:00
unsigned long msk = 0xf0000000UL > > shift ;
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( mcrxr , regs ) ;
2005-09-26 10:04:21 +04:00
regs - > ccr = ( regs - > ccr & ~ msk ) | ( ( regs - > xer > > shift ) & msk ) ;
regs - > xer & = ~ 0xf0000000UL ;
return 0 ;
}
/* Emulate load/store string insn. */
2009-05-18 06:10:05 +04:00
if ( ( instword & PPC_INST_STRING_GEN_MASK ) = = PPC_INST_STRING ) {
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( string , regs ) ;
2005-09-26 10:04:21 +04:00
return emulate_string_inst ( regs , instword ) ;
2009-05-18 06:10:05 +04:00
}
2005-09-26 10:04:21 +04:00
2006-08-30 22:11:38 +04:00
/* Emulate the popcntb (Population Count Bytes) instruction. */
2009-02-10 23:10:44 +03:00
if ( ( instword & PPC_INST_POPCNTB_MASK ) = = PPC_INST_POPCNTB ) {
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( popcntb , regs ) ;
2006-08-30 22:11:38 +04:00
return emulate_popcntb_inst ( regs , instword ) ;
}
2007-11-20 06:35:29 +03:00
/* Emulate isel (Integer Select) instruction */
2009-02-10 23:10:44 +03:00
if ( ( instword & PPC_INST_ISEL_MASK ) = = PPC_INST_ISEL ) {
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( isel , regs ) ;
2007-11-20 06:35:29 +03:00
return emulate_isel ( regs , instword ) ;
}
2011-03-02 18:18:48 +03:00
# ifdef CONFIG_PPC64
/* Emulate the mfspr rD, DSCR. */
if ( ( ( instword & PPC_INST_MFSPR_DSCR_MASK ) = = PPC_INST_MFSPR_DSCR ) & &
cpu_has_feature ( CPU_FTR_DSCR ) ) {
PPC_WARN_EMULATED ( mfdscr , regs ) ;
rd = ( instword > > 21 ) & 0x1f ;
regs - > gpr [ rd ] = mfspr ( SPRN_DSCR ) ;
return 0 ;
}
/* Emulate the mtspr DSCR, rD. */
if ( ( ( instword & PPC_INST_MTSPR_DSCR_MASK ) = = PPC_INST_MTSPR_DSCR ) & &
cpu_has_feature ( CPU_FTR_DSCR ) ) {
PPC_WARN_EMULATED ( mtdscr , regs ) ;
rd = ( instword > > 21 ) & 0x1f ;
mtspr ( SPRN_DSCR , regs - > gpr [ rd ] ) ;
current - > thread . dscr_inherit = 1 ;
return 0 ;
}
# endif
2005-09-26 10:04:21 +04:00
return - EINVAL ;
}
2006-12-08 14:30:41 +03:00
int is_valid_bugaddr ( unsigned long addr )
2005-09-26 10:04:21 +04:00
{
2006-12-08 14:30:41 +03:00
return is_kernel_addr ( addr ) ;
2005-09-26 10:04:21 +04:00
}
2005-10-06 07:27:05 +04:00
void __kprobes program_check_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
unsigned int reason = get_reason ( regs ) ;
extern int do_mathemu ( struct pt_regs * regs ) ;
2006-12-08 11:43:30 +03:00
/* We can now get here via a FP Unavailable exception if the core
2007-02-07 10:13:32 +03:00
* has no FPU , in that case the reason flags will be 0 */
2005-09-26 10:04:21 +04:00
2005-10-01 12:43:42 +04:00
if ( reason & REASON_FP ) {
/* IEEE FP exception */
parse_fpe ( regs ) ;
2005-10-06 07:27:05 +04:00
return ;
}
if ( reason & REASON_TRAP ) {
2010-05-21 06:04:25 +04:00
/* Debugger is first in line to stop recursive faults in
* rcu_lock , notify_die , or atomic_notifier_call_chain */
if ( debugger_bpt ( regs ) )
return ;
2005-09-26 10:04:21 +04:00
/* trap exception */
2005-10-01 12:43:42 +04:00
if ( notify_die ( DIE_BPT , " breakpoint " , regs , 5 , 5 , SIGTRAP )
= = NOTIFY_STOP )
return ;
2006-12-08 14:30:41 +03:00
if ( ! ( regs - > msr & MSR_PR ) & & /* not user-mode */
2007-07-16 10:41:39 +04:00
report_bug ( regs - > nip , regs ) = = BUG_TRAP_TYPE_WARN ) {
2005-09-26 10:04:21 +04:00
regs - > nip + = 4 ;
return ;
}
2005-10-06 07:27:05 +04:00
_exception ( SIGTRAP , regs , TRAP_BRKPT , regs - > nip ) ;
return ;
}
2006-03-03 09:11:40 +03:00
local_irq_enable ( ) ;
2007-02-07 10:13:32 +03:00
# ifdef CONFIG_MATH_EMULATION
/* (reason & REASON_ILLEGAL) would be the obvious thing here,
* but there seems to be a hardware bug on the 405 GP ( RevD )
* that means ESR is sometimes set incorrectly - either to
* ESR_DST ( ! ? ) or 0. In the process of chasing this with the
* hardware people - not sure if it can happen on any illegal
* instruction or only on FP instructions , whether there is a
2011-03-31 05:57:33 +04:00
* pattern to occurrences etc . - dgibson 31 / Mar / 2003 */
2007-02-07 10:47:59 +03:00
switch ( do_mathemu ( regs ) ) {
case 0 :
2007-02-07 10:13:32 +03:00
emulate_single_step ( regs ) ;
return ;
2007-02-07 10:47:59 +03:00
case 1 : {
int code = 0 ;
code = __parse_fpscr ( current - > thread . fpscr . val ) ;
_exception ( SIGFPE , regs , code , regs - > nip ) ;
return ;
}
case - EFAULT :
_exception ( SIGSEGV , regs , SEGV_MAPERR , regs - > nip ) ;
return ;
2007-02-07 10:13:32 +03:00
}
2007-02-07 10:47:59 +03:00
/* fall through on any other errors */
2007-02-07 10:13:32 +03:00
# endif /* CONFIG_MATH_EMULATION */
2005-10-06 07:27:05 +04:00
/* Try to emulate it if we should. */
if ( reason & ( REASON_ILLEGAL | REASON_PRIVILEGED ) ) {
2005-09-26 10:04:21 +04:00
switch ( emulate_instruction ( regs ) ) {
case 0 :
regs - > nip + = 4 ;
emulate_single_step ( regs ) ;
2005-10-06 07:27:05 +04:00
return ;
2005-09-26 10:04:21 +04:00
case - EFAULT :
_exception ( SIGSEGV , regs , SEGV_MAPERR , regs - > nip ) ;
2005-10-06 07:27:05 +04:00
return ;
2005-09-26 10:04:21 +04:00
}
}
2005-10-06 07:27:05 +04:00
if ( reason & REASON_PRIVILEGED )
_exception ( SIGILL , regs , ILL_PRVOPC , regs - > nip ) ;
else
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
2005-09-26 10:04:21 +04:00
}
2005-10-01 12:43:42 +04:00
void alignment_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
2006-11-01 07:11:39 +03:00
int sig , code , fixed = 0 ;
2005-09-26 10:04:21 +04:00
2006-06-07 10:15:39 +04:00
/* we don't implement logging of alignment exceptions */
if ( ! ( current - > thread . align_ctl & PR_UNALIGN_SIGBUS ) )
fixed = fix_alignment ( regs ) ;
2005-09-26 10:04:21 +04:00
if ( fixed = = 1 ) {
regs - > nip + = 4 ; /* skip over emulated instruction */
emulate_single_step ( regs ) ;
return ;
}
2005-10-01 12:43:42 +04:00
/* Operand address was bad */
2005-09-26 10:04:21 +04:00
if ( fixed = = - EFAULT ) {
2006-11-01 07:11:39 +03:00
sig = SIGSEGV ;
code = SEGV_ACCERR ;
} else {
sig = SIGBUS ;
code = BUS_ADRALN ;
2005-09-26 10:04:21 +04:00
}
2006-11-01 07:11:39 +03:00
if ( user_mode ( regs ) )
_exception ( sig , regs , code , regs - > dar ) ;
else
bad_page_fault ( regs , regs - > dar , sig ) ;
2005-09-26 10:04:21 +04:00
}
void StackOverflow ( struct pt_regs * regs )
{
printk ( KERN_CRIT " Kernel stack overflow in process %p, r1=%lx \n " ,
current , regs - > gpr [ 1 ] ) ;
debugger ( regs ) ;
show_regs ( regs ) ;
panic ( " kernel stack overflow " ) ;
}
void nonrecoverable_exception ( struct pt_regs * regs )
{
printk ( KERN_ERR " Non-recoverable exception at PC=%lx MSR=%lx \n " ,
regs - > nip , regs - > msr ) ;
debugger ( regs ) ;
die ( " nonrecoverable exception " , regs , SIGKILL ) ;
}
void trace_syscall ( struct pt_regs * regs )
{
printk ( " Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s \n " ,
2007-10-19 10:40:41 +04:00
current , task_pid_nr ( current ) , regs - > nip , regs - > link , regs - > gpr [ 0 ] ,
2005-09-26 10:04:21 +04:00
regs - > ccr & 0x10000000 ? " Error= " : " " , regs - > gpr [ 3 ] , print_tainted ( ) ) ;
}
2005-10-01 12:43:42 +04:00
void kernel_fp_unavailable_exception ( struct pt_regs * regs )
{
printk ( KERN_EMERG " Unrecoverable FP Unavailable Exception "
" %lx at %lx \n " , regs - > trap , regs - > nip ) ;
die ( " Unrecoverable FP Unavailable Exception " , regs , SIGABRT ) ;
}
void altivec_unavailable_exception ( struct pt_regs * regs )
{
if ( user_mode ( regs ) ) {
/* A user program has executed an altivec instruction,
but this kernel doesn ' t support altivec . */
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
return ;
}
2006-10-13 05:41:00 +04:00
2005-10-01 12:43:42 +04:00
printk ( KERN_EMERG " Unrecoverable VMX/Altivec Unavailable Exception "
" %lx at %lx \n " , regs - > trap , regs - > nip ) ;
die ( " Unrecoverable VMX/Altivec Unavailable Exception " , regs , SIGABRT ) ;
}
2008-06-25 08:07:18 +04:00
void vsx_unavailable_exception ( struct pt_regs * regs )
{
if ( user_mode ( regs ) ) {
/* A user program has executed an vsx instruction,
but this kernel doesn ' t support vsx . */
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
return ;
}
printk ( KERN_EMERG " Unrecoverable VSX Unavailable Exception "
" %lx at %lx \n " , regs - > trap , regs - > nip ) ;
die ( " Unrecoverable VSX Unavailable Exception " , regs , SIGABRT ) ;
}
2005-10-01 12:43:42 +04:00
void performance_monitor_exception ( struct pt_regs * regs )
{
2010-01-31 23:34:06 +03:00
__get_cpu_var ( irq_stat ) . pmu_irqs + + ;
2005-10-01 12:43:42 +04:00
perf_irq ( regs ) ;
}
2005-10-06 07:27:05 +04:00
# ifdef CONFIG_8xx
2005-09-26 10:04:21 +04:00
void SoftwareEmulation ( struct pt_regs * regs )
{
extern int do_mathemu ( struct pt_regs * ) ;
extern int Soft_emulate_8xx ( struct pt_regs * ) ;
2007-09-19 00:29:35 +04:00
# if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_8XX_MINIMAL_FPEMU)
2005-09-26 10:04:21 +04:00
int errcode ;
2007-09-19 00:29:35 +04:00
# endif
2005-09-26 10:04:21 +04:00
CHECK_FULL_REGS ( regs ) ;
if ( ! user_mode ( regs ) ) {
debugger ( regs ) ;
die ( " Kernel Mode Software FPU Emulation " , regs , SIGFPE ) ;
}
# ifdef CONFIG_MATH_EMULATION
errcode = do_mathemu ( regs ) ;
2009-05-18 06:10:05 +04:00
if ( errcode > = 0 )
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( math , regs ) ;
2007-02-07 10:47:59 +03:00
switch ( errcode ) {
case 0 :
emulate_single_step ( regs ) ;
return ;
case 1 : {
int code = 0 ;
code = __parse_fpscr ( current - > thread . fpscr . val ) ;
_exception ( SIGFPE , regs , code , regs - > nip ) ;
return ;
}
case - EFAULT :
_exception ( SIGSEGV , regs , SEGV_MAPERR , regs - > nip ) ;
return ;
default :
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
return ;
}
2007-09-19 00:29:35 +04:00
# elif defined(CONFIG_8XX_MINIMAL_FPEMU)
2005-09-26 10:04:21 +04:00
errcode = Soft_emulate_8xx ( regs ) ;
2009-05-18 06:10:05 +04:00
if ( errcode > = 0 )
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( 8 xx , regs ) ;
2009-05-18 06:10:05 +04:00
2007-02-07 10:47:59 +03:00
switch ( errcode ) {
case 0 :
2005-09-26 10:04:21 +04:00
emulate_single_step ( regs ) ;
2007-02-07 10:47:59 +03:00
return ;
case 1 :
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
return ;
case - EFAULT :
_exception ( SIGSEGV , regs , SEGV_MAPERR , regs - > nip ) ;
return ;
}
2007-09-19 00:29:35 +04:00
# else
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
2007-02-07 10:47:59 +03:00
# endif
2005-09-26 10:04:21 +04:00
}
2005-10-06 07:27:05 +04:00
# endif /* CONFIG_8xx */
2005-09-26 10:04:21 +04:00
2010-02-08 14:50:57 +03:00
# ifdef CONFIG_PPC_ADV_DEBUG_REGS
2010-02-08 14:51:18 +03:00
static void handle_debug ( struct pt_regs * regs , unsigned long debug_status )
{
int changed = 0 ;
/*
* Determine the cause of the debug event , clear the
* event flags and send a trap to the handler . Torez
*/
if ( debug_status & ( DBSR_DAC1R | DBSR_DAC1W ) ) {
dbcr_dac ( current ) & = ~ ( DBCR_DAC1R | DBCR_DAC1W ) ;
# ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
current - > thread . dbcr2 & = ~ DBCR2_DAC12MODE ;
# endif
do_send_trap ( regs , mfspr ( SPRN_DAC1 ) , debug_status , TRAP_HWBKPT ,
5 ) ;
changed | = 0x01 ;
} else if ( debug_status & ( DBSR_DAC2R | DBSR_DAC2W ) ) {
dbcr_dac ( current ) & = ~ ( DBCR_DAC2R | DBCR_DAC2W ) ;
do_send_trap ( regs , mfspr ( SPRN_DAC2 ) , debug_status , TRAP_HWBKPT ,
6 ) ;
changed | = 0x01 ;
} else if ( debug_status & DBSR_IAC1 ) {
current - > thread . dbcr0 & = ~ DBCR0_IAC1 ;
dbcr_iac_range ( current ) & = ~ DBCR_IAC12MODE ;
do_send_trap ( regs , mfspr ( SPRN_IAC1 ) , debug_status , TRAP_HWBKPT ,
1 ) ;
changed | = 0x01 ;
} else if ( debug_status & DBSR_IAC2 ) {
current - > thread . dbcr0 & = ~ DBCR0_IAC2 ;
do_send_trap ( regs , mfspr ( SPRN_IAC2 ) , debug_status , TRAP_HWBKPT ,
2 ) ;
changed | = 0x01 ;
} else if ( debug_status & DBSR_IAC3 ) {
current - > thread . dbcr0 & = ~ DBCR0_IAC3 ;
dbcr_iac_range ( current ) & = ~ DBCR_IAC34MODE ;
do_send_trap ( regs , mfspr ( SPRN_IAC3 ) , debug_status , TRAP_HWBKPT ,
3 ) ;
changed | = 0x01 ;
} else if ( debug_status & DBSR_IAC4 ) {
current - > thread . dbcr0 & = ~ DBCR0_IAC4 ;
do_send_trap ( regs , mfspr ( SPRN_IAC4 ) , debug_status , TRAP_HWBKPT ,
4 ) ;
changed | = 0x01 ;
}
/*
* At the point this routine was called , the MSR ( DE ) was turned off .
* Check all other debug flags and see if that bit needs to be turned
* back on or not .
*/
if ( DBCR_ACTIVE_EVENTS ( current - > thread . dbcr0 , current - > thread . dbcr1 ) )
regs - > msr | = MSR_DE ;
else
/* Make sure the IDM flag is off */
current - > thread . dbcr0 & = ~ DBCR0_IDM ;
if ( changed & 0x01 )
mtspr ( SPRN_DBCR0 , current - > thread . dbcr0 ) ;
}
2005-09-26 10:04:21 +04:00
2008-06-26 11:01:37 +04:00
void __kprobes DebugException ( struct pt_regs * regs , unsigned long debug_status )
2005-09-26 10:04:21 +04:00
{
2010-02-08 14:51:18 +03:00
current - > thread . dbsr = debug_status ;
2009-05-29 01:26:38 +04:00
/* Hack alert: On BookE, Branch Taken stops on the branch itself, while
* on server , it stops on the target of the branch . In order to simulate
* the server behaviour , we thus restart right away with a single step
* instead of stopping here when hitting a BT
*/
if ( debug_status & DBSR_BT ) {
regs - > msr & = ~ MSR_DE ;
/* Disable BT */
mtspr ( SPRN_DBCR0 , mfspr ( SPRN_DBCR0 ) & ~ DBCR0_BT ) ;
/* Clear the BT event */
mtspr ( SPRN_DBSR , DBSR_BT ) ;
/* Do the single step trick only when coming from userspace */
if ( user_mode ( regs ) ) {
current - > thread . dbcr0 & = ~ DBCR0_BT ;
current - > thread . dbcr0 | = DBCR0_IDM | DBCR0_IC ;
regs - > msr | = MSR_DE ;
return ;
}
if ( notify_die ( DIE_SSTEP , " block_step " , regs , 5 ,
5 , SIGTRAP ) = = NOTIFY_STOP ) {
return ;
}
if ( debugger_sstep ( regs ) )
return ;
} else if ( debug_status & DBSR_IC ) { /* Instruction complete */
2005-09-26 10:04:21 +04:00
regs - > msr & = ~ MSR_DE ;
2008-06-26 11:01:37 +04:00
/* Disable instruction completion */
mtspr ( SPRN_DBCR0 , mfspr ( SPRN_DBCR0 ) & ~ DBCR0_IC ) ;
/* Clear the instruction completion event */
mtspr ( SPRN_DBSR , DBSR_IC ) ;
if ( notify_die ( DIE_SSTEP , " single_step " , regs , 5 ,
5 , SIGTRAP ) = = NOTIFY_STOP ) {
return ;
}
if ( debugger_sstep ( regs ) )
return ;
2008-07-23 20:10:41 +04:00
if ( user_mode ( regs ) ) {
2010-02-08 14:51:18 +03:00
current - > thread . dbcr0 & = ~ DBCR0_IC ;
if ( DBCR_ACTIVE_EVENTS ( current - > thread . dbcr0 ,
current - > thread . dbcr1 ) )
regs - > msr | = MSR_DE ;
else
/* Make sure the IDM bit is off */
current - > thread . dbcr0 & = ~ DBCR0_IDM ;
2008-07-23 20:10:41 +04:00
}
2010-02-08 14:51:18 +03:00
_exception ( SIGTRAP , regs , TRAP_TRACE , regs - > nip ) ;
} else
handle_debug ( regs , debug_status ) ;
2005-09-26 10:04:21 +04:00
}
2010-02-08 14:50:57 +03:00
# endif /* CONFIG_PPC_ADV_DEBUG_REGS */
2005-09-26 10:04:21 +04:00
# if !defined(CONFIG_TAU_INT)
void TAUException ( struct pt_regs * regs )
{
printk ( " TAU trap at PC: %lx, MSR: %lx, vector=%lx %s \n " ,
regs - > nip , regs - > msr , regs - > trap , print_tainted ( ) ) ;
}
# endif /* CONFIG_INT_TAU */
# ifdef CONFIG_ALTIVEC
2005-10-01 12:43:42 +04:00
void altivec_assist_exception ( struct pt_regs * regs )
2005-09-26 10:04:21 +04:00
{
int err ;
if ( ! user_mode ( regs ) ) {
printk ( KERN_EMERG " VMX/Altivec assist exception in kernel mode "
" at %lx \n " , regs - > nip ) ;
2005-10-06 07:27:05 +04:00
die ( " Kernel VMX/Altivec assist exception " , regs , SIGILL ) ;
2005-09-26 10:04:21 +04:00
}
2005-10-01 12:43:42 +04:00
flush_altivec_to_thread ( current ) ;
2009-10-27 21:46:55 +03:00
PPC_WARN_EMULATED ( altivec , regs ) ;
2005-09-26 10:04:21 +04:00
err = emulate_altivec ( regs ) ;
if ( err = = 0 ) {
regs - > nip + = 4 ; /* skip emulated instruction */
emulate_single_step ( regs ) ;
return ;
}
if ( err = = - EFAULT ) {
/* got an error reading the instruction */
_exception ( SIGSEGV , regs , SEGV_ACCERR , regs - > nip ) ;
} else {
/* didn't recognize the instruction */
/* XXX quick hack for now: set the non-Java bit in the VSCR */
2011-06-04 09:36:54 +04:00
printk_ratelimited ( KERN_ERR " Unrecognized altivec instruction "
" in %s at %lx \n " , current - > comm , regs - > nip ) ;
2005-09-26 10:04:21 +04:00
current - > thread . vscr . u [ 3 ] | = 0x10000 ;
}
}
# endif /* CONFIG_ALTIVEC */
2008-06-25 08:07:18 +04:00
# ifdef CONFIG_VSX
void vsx_assist_exception ( struct pt_regs * regs )
{
if ( ! user_mode ( regs ) ) {
printk ( KERN_EMERG " VSX assist exception in kernel mode "
" at %lx \n " , regs - > nip ) ;
die ( " Kernel VSX assist exception " , regs , SIGILL ) ;
}
flush_vsx_to_thread ( current ) ;
printk ( KERN_INFO " VSX assist not supported at %lx \n " , regs - > nip ) ;
_exception ( SIGILL , regs , ILL_ILLOPC , regs - > nip ) ;
}
# endif /* CONFIG_VSX */
2005-09-26 10:04:21 +04:00
# ifdef CONFIG_FSL_BOOKE
void CacheLockingException ( struct pt_regs * regs , unsigned long address ,
unsigned long error_code )
{
/* We treat cache locking instructions from the user
* as priv ops , in the future we could try to do
* something smarter
*/
if ( error_code & ( ESR_DLK | ESR_ILK ) )
_exception ( SIGILL , regs , ILL_PRVOPC , regs - > nip ) ;
return ;
}
# endif /* CONFIG_FSL_BOOKE */
# ifdef CONFIG_SPE
void SPEFloatingPointException ( struct pt_regs * regs )
{
2008-10-28 06:50:21 +03:00
extern int do_spe_mathemu ( struct pt_regs * regs ) ;
2005-09-26 10:04:21 +04:00
unsigned long spefscr ;
int fpexc_mode ;
int code = 0 ;
2008-10-28 06:50:21 +03:00
int err ;
2011-06-15 03:34:25 +04:00
flush_spe_to_thread ( current ) ;
2005-09-26 10:04:21 +04:00
spefscr = current - > thread . spefscr ;
fpexc_mode = current - > thread . fpexc_mode ;
if ( ( spefscr & SPEFSCR_FOVF ) & & ( fpexc_mode & PR_FP_EXC_OVF ) ) {
code = FPE_FLTOVF ;
}
else if ( ( spefscr & SPEFSCR_FUNF ) & & ( fpexc_mode & PR_FP_EXC_UND ) ) {
code = FPE_FLTUND ;
}
else if ( ( spefscr & SPEFSCR_FDBZ ) & & ( fpexc_mode & PR_FP_EXC_DIV ) )
code = FPE_FLTDIV ;
else if ( ( spefscr & SPEFSCR_FINV ) & & ( fpexc_mode & PR_FP_EXC_INV ) ) {
code = FPE_FLTINV ;
}
else if ( ( spefscr & ( SPEFSCR_FG | SPEFSCR_FX ) ) & & ( fpexc_mode & PR_FP_EXC_RES ) )
code = FPE_FLTRES ;
2008-10-28 06:50:21 +03:00
err = do_spe_mathemu ( regs ) ;
if ( err = = 0 ) {
regs - > nip + = 4 ; /* skip emulated instruction */
emulate_single_step ( regs ) ;
return ;
}
if ( err = = - EFAULT ) {
/* got an error reading the instruction */
_exception ( SIGSEGV , regs , SEGV_ACCERR , regs - > nip ) ;
} else if ( err = = - EINVAL ) {
/* didn't recognize the instruction */
printk ( KERN_ERR " unrecognized spe instruction "
" in %s at %lx \n " , current - > comm , regs - > nip ) ;
} else {
_exception ( SIGFPE , regs , code , regs - > nip ) ;
}
2005-09-26 10:04:21 +04:00
return ;
}
2008-10-28 06:50:21 +03:00
void SPEFloatingPointRoundException ( struct pt_regs * regs )
{
extern int speround_handler ( struct pt_regs * regs ) ;
int err ;
preempt_disable ( ) ;
if ( regs - > msr & MSR_SPE )
giveup_spe ( current ) ;
preempt_enable ( ) ;
regs - > nip - = 4 ;
err = speround_handler ( regs ) ;
if ( err = = 0 ) {
regs - > nip + = 4 ; /* skip emulated instruction */
emulate_single_step ( regs ) ;
return ;
}
if ( err = = - EFAULT ) {
/* got an error reading the instruction */
_exception ( SIGSEGV , regs , SEGV_ACCERR , regs - > nip ) ;
} else if ( err = = - EINVAL ) {
/* didn't recognize the instruction */
printk ( KERN_ERR " unrecognized spe instruction "
" in %s at %lx \n " , current - > comm , regs - > nip ) ;
} else {
_exception ( SIGFPE , regs , 0 , regs - > nip ) ;
return ;
}
}
2005-09-26 10:04:21 +04:00
# endif
2005-10-01 12:43:42 +04:00
/*
* We enter here if we get an unrecoverable exception , that is , one
* that happened at a point where the RI ( recoverable interrupt ) bit
* in the MSR is 0. This indicates that SRR0 / 1 are live , and that
* we therefore lost state by taking this exception .
*/
void unrecoverable_exception ( struct pt_regs * regs )
{
printk ( KERN_EMERG " Unrecoverable exception %lx at %lx \n " ,
regs - > trap , regs - > nip ) ;
die ( " Unrecoverable exception " , regs , SIGABRT ) ;
}
2005-09-26 10:04:21 +04:00
# ifdef CONFIG_BOOKE_WDT
/*
* Default handler for a Watchdog exception ,
* spins until a reboot occurs
*/
void __attribute__ ( ( weak ) ) WatchdogHandler ( struct pt_regs * regs )
{
/* Generic WatchdogHandler, implement your own */
mtspr ( SPRN_TCR , mfspr ( SPRN_TCR ) & ( ~ TCR_WIE ) ) ;
return ;
}
void WatchdogException ( struct pt_regs * regs )
{
printk ( KERN_EMERG " PowerPC Book-E Watchdog Exception \n " ) ;
WatchdogHandler ( regs ) ;
}
# endif
2005-10-01 12:43:42 +04:00
/*
* We enter here if we discover during exception entry that we are
* running in supervisor mode with a userspace value in the stack pointer .
*/
void kernel_bad_stack ( struct pt_regs * regs )
{
printk ( KERN_EMERG " Bad kernel stack pointer %lx at %lx \n " ,
regs - > gpr [ 1 ] , regs - > nip ) ;
die ( " Bad kernel stack pointer " , regs , SIGABRT ) ;
}
2005-09-26 10:04:21 +04:00
void __init trap_init ( void )
{
}
2009-05-18 06:10:05 +04:00
# ifdef CONFIG_PPC_EMULATED_STATS
# define WARN_EMULATED_SETUP(type) .type = { .name = #type }
struct ppc_emulated ppc_emulated = {
# ifdef CONFIG_ALTIVEC
WARN_EMULATED_SETUP ( altivec ) ,
# endif
WARN_EMULATED_SETUP ( dcba ) ,
WARN_EMULATED_SETUP ( dcbz ) ,
WARN_EMULATED_SETUP ( fp_pair ) ,
WARN_EMULATED_SETUP ( isel ) ,
WARN_EMULATED_SETUP ( mcrxr ) ,
WARN_EMULATED_SETUP ( mfpvr ) ,
WARN_EMULATED_SETUP ( multiple ) ,
WARN_EMULATED_SETUP ( popcntb ) ,
WARN_EMULATED_SETUP ( spe ) ,
WARN_EMULATED_SETUP ( string ) ,
WARN_EMULATED_SETUP ( unaligned ) ,
# ifdef CONFIG_MATH_EMULATION
WARN_EMULATED_SETUP ( math ) ,
# elif defined(CONFIG_8XX_MINIMAL_FPEMU)
WARN_EMULATED_SETUP ( 8 xx ) ,
# endif
# ifdef CONFIG_VSX
WARN_EMULATED_SETUP ( vsx ) ,
# endif
2011-03-02 18:18:48 +03:00
# ifdef CONFIG_PPC64
WARN_EMULATED_SETUP ( mfdscr ) ,
WARN_EMULATED_SETUP ( mtdscr ) ,
# endif
2009-05-18 06:10:05 +04:00
} ;
u32 ppc_warn_emulated ;
void ppc_warn_emulated_print ( const char * type )
{
2011-06-04 09:36:54 +04:00
pr_warn_ratelimited ( " %s used emulated %s instruction \n " , current - > comm ,
type ) ;
2009-05-18 06:10:05 +04:00
}
static int __init ppc_warn_emulated_init ( void )
{
struct dentry * dir , * d ;
unsigned int i ;
struct ppc_emulated_entry * entries = ( void * ) & ppc_emulated ;
if ( ! powerpc_debugfs_root )
return - ENODEV ;
dir = debugfs_create_dir ( " emulated_instructions " ,
powerpc_debugfs_root ) ;
if ( ! dir )
return - ENOMEM ;
d = debugfs_create_u32 ( " do_warn " , S_IRUGO | S_IWUSR , dir ,
& ppc_warn_emulated ) ;
if ( ! d )
goto fail ;
for ( i = 0 ; i < sizeof ( ppc_emulated ) / sizeof ( * entries ) ; i + + ) {
d = debugfs_create_u32 ( entries [ i ] . name , S_IRUGO | S_IWUSR , dir ,
( u32 * ) & entries [ i ] . val . counter ) ;
if ( ! d )
goto fail ;
}
return 0 ;
fail :
debugfs_remove_recursive ( dir ) ;
return - ENOMEM ;
}
device_initcall ( ppc_warn_emulated_init ) ;
# endif /* CONFIG_PPC_EMULATED_STATS */