2005-04-16 15:20:36 -07:00
/*
* S390 version
2012-07-20 11:15:04 +02:00
* Copyright IBM Corp . 1999
2005-04-16 15:20:36 -07:00
* Author ( s ) : Hartmut Penner ( hp @ de . ibm . com ) ,
* Martin Schwidefsky ( schwidefsky @ de . ibm . com )
*
* Derived from " include/asm-i386/processor.h "
* Copyright ( C ) 1994 , Linus Torvalds
*/
# ifndef __ASM_S390_PROCESSOR_H
# define __ASM_S390_PROCESSOR_H
2008-12-25 13:39:16 +01:00
# include <linux/linkage.h>
2012-03-28 18:30:02 +01:00
# include <linux/irqflags.h>
2009-09-11 10:29:04 +02:00
# include <asm/cpu.h>
2009-04-14 15:36:16 +02:00
# include <asm/page.h>
2005-04-16 15:20:36 -07:00
# include <asm/ptrace.h>
2009-04-14 15:36:16 +02:00
# include <asm/setup.h>
2012-07-31 10:52:05 +02:00
# include <asm/runtime_instr.h>
2005-04-16 15:20:36 -07:00
/*
* Default implementation of macro that returns current
* instruction pointer ( " program counter " ) .
*/
2006-09-28 16:56:43 +02:00
# define current_text_addr() ({ void *pc; asm("basr %0,0" : "=a" (pc)); pc; })
2005-04-16 15:20:36 -07:00
2009-09-11 10:29:04 +02:00
static inline void get_cpu_id ( struct cpuid * ptr )
2007-02-21 10:55:18 +01:00
{
2010-02-26 22:37:31 +01:00
asm volatile ( " stidp %0 " : " =Q " ( * ptr ) ) ;
2007-02-21 10:55:18 +01:00
}
2007-02-05 21:18:31 +01:00
extern void s390_adjust_jiffies ( void ) ;
2011-10-30 15:17:13 +01:00
extern const struct seq_operations cpuinfo_op ;
extern int sysctl_ieee_emulation_warnings ;
2005-04-16 15:20:36 -07:00
/*
2009-03-18 13:27:36 +01:00
* User space process size : 2 GB for 31 bit , 4 TB or 8 PT for 64 bit .
2005-04-16 15:20:36 -07:00
*/
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2005-04-16 15:20:36 -07:00
2008-02-09 18:24:36 +01:00
# define TASK_SIZE (1UL << 31)
# define TASK_UNMAPPED_BASE (1UL << 30)
2005-04-16 15:20:36 -07:00
2012-05-23 16:24:51 +02:00
# else /* CONFIG_64BIT */
2005-04-16 15:20:36 -07:00
2009-03-18 13:27:36 +01:00
# define TASK_SIZE_OF(tsk) ((tsk)->mm->context.asce_limit)
2008-02-09 18:24:36 +01:00
# define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \
( 1UL < < 30 ) : ( 1UL < < 41 ) )
# define TASK_SIZE TASK_SIZE_OF(current)
2005-04-16 15:20:36 -07:00
2012-05-23 16:24:51 +02:00
# endif /* CONFIG_64BIT */
2005-04-16 15:20:36 -07:00
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2008-02-09 18:24:36 +01:00
# define STACK_TOP (1UL << 31)
2008-02-09 18:24:37 +01:00
# define STACK_TOP_MAX (1UL << 31)
2012-05-23 16:24:51 +02:00
# else /* CONFIG_64BIT */
2008-02-09 18:24:37 +01:00
# define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42))
# define STACK_TOP_MAX (1UL << 42)
2012-05-23 16:24:51 +02:00
# endif /* CONFIG_64BIT */
2008-02-08 04:19:26 -08:00
2005-04-16 15:20:36 -07:00
# define HAVE_ARCH_PICK_MMAP_LAYOUT
typedef struct {
__u32 ar4 ;
} mm_segment_t ;
/*
* Thread structure
*/
struct thread_struct {
s390_fp_regs fp_regs ;
unsigned int acrs [ NUM_ACRS ] ;
unsigned long ksp ; /* kernel stack pointer */
mm_segment_t mm_segment ;
2011-07-24 10:48:20 +02:00
unsigned long gmap_addr ; /* address of last gmap fault. */
2011-01-05 12:48:10 +01:00
struct per_regs per_user ; /* User specified PER registers */
struct per_event per_event ; /* Cause of the last PER trap */
2012-07-31 11:03:04 +02:00
unsigned long per_flags ; /* Flags to control debug behavior */
2005-04-16 15:20:36 -07:00
/* pfault_wait is used to block the process on a pfault event */
unsigned long pfault_wait ;
2011-05-23 10:24:34 +02:00
struct list_head list ;
2012-07-31 10:52:05 +02:00
/* cpu runtime instrumentation */
struct runtime_instr_cb * ri_cb ;
int ri_signum ;
2012-07-31 11:03:04 +02:00
# ifdef CONFIG_64BIT
unsigned char trap_tdb [ 256 ] ; /* Transaction abort diagnose block */
# endif
2005-04-16 15:20:36 -07:00
} ;
2012-07-31 11:03:04 +02:00
# define PER_FLAG_NO_TE 1UL /* Flag to disable transactions. */
2005-04-16 15:20:36 -07:00
typedef struct thread_struct thread_struct ;
/*
* Stack layout of a C stack frame .
*/
# ifndef __PACK_STACK
struct stack_frame {
unsigned long back_chain ;
unsigned long empty1 [ 5 ] ;
unsigned long gprs [ 10 ] ;
unsigned int empty2 [ 8 ] ;
} ;
# else
struct stack_frame {
unsigned long empty1 [ 5 ] ;
unsigned int empty2 [ 8 ] ;
unsigned long gprs [ 10 ] ;
unsigned long back_chain ;
} ;
# endif
# define ARCH_MIN_TASKALIGN 8
2007-10-22 12:52:45 +02:00
# define INIT_THREAD { \
. ksp = sizeof ( init_stack ) + ( unsigned long ) & init_stack , \
}
2005-04-16 15:20:36 -07:00
/*
* Do necessary setup to start up a new thread .
*/
2011-10-30 15:16:50 +01:00
# define start_thread(regs, new_psw, new_stackp) do { \
regs - > psw . mask = psw_user_bits | PSW_MASK_EA | PSW_MASK_BA ; \
regs - > psw . addr = new_psw | PSW_ADDR_AMODE ; \
regs - > gprs [ 15 ] = new_stackp ; \
2008-07-14 09:58:54 +02:00
} while ( 0 )
2011-10-30 15:16:50 +01:00
# define start_thread31(regs, new_psw, new_stackp) do { \
regs - > psw . mask = psw_user_bits | PSW_MASK_BA ; \
regs - > psw . addr = new_psw | PSW_ADDR_AMODE ; \
regs - > gprs [ 15 ] = new_stackp ; \
2012-07-26 08:53:06 +02:00
__tlb_flush_mm ( current - > mm ) ; \
2011-10-30 15:16:50 +01:00
crst_table_downgrade ( current - > mm , 1UL < < 31 ) ; \
2012-07-26 08:53:06 +02:00
update_mm ( current - > mm , current ) ; \
2005-04-16 15:20:36 -07:00
} while ( 0 )
/* Forward declaration, a strange C thing */
struct task_struct ;
struct mm_struct ;
2008-02-08 04:18:33 -08:00
struct seq_file ;
2005-04-16 15:20:36 -07:00
2012-08-29 14:12:20 +02:00
# ifdef CONFIG_64BIT
extern void show_cacheinfo ( struct seq_file * m ) ;
# else
static inline void show_cacheinfo ( struct seq_file * m ) { }
# endif
2005-04-16 15:20:36 -07:00
/* Free all resources held by a thread. */
extern void release_thread ( struct task_struct * ) ;
extern int kernel_thread ( int ( * fn ) ( void * ) , void * arg , unsigned long flags ) ;
/*
* Return saved PC of a blocked thread .
*/
extern unsigned long thread_saved_pc ( struct task_struct * t ) ;
[S390] Improved oops output.
This patch adds two improvements to the oops output. First it adds an
additional line after the PSW which decodes the different fields of it.
Second a disassembler is added that decodes the instructions surrounding
the faulting PSW. The output of a test oops now looks like this:
kernel BUG at init/main.c:419
illegal operation: 0001 [#1]
CPU: 0 Not tainted
Process swapper (pid: 0, task: 0000000000464968, ksp: 00000000004be000)
Krnl PSW : 0700000180000000 00000000000120b6 (rest_init+0x36/0x38)
R:0 T:1 IO:1 EX:1 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 EA:3
Krnl GPRS: 0000000000000003 00000000004ba017 0000000000000022 0000000000000001
000000000003a5f6 0000000000000000 00000000004be6a8 0000000000000000
0000000000000000 00000000004b8200 0000000000003a50 0000000000008000
0000000000516368 000000000033d008 00000000000120b2 00000000004bdee0
Krnl Code: 00000000000120a6: e3e0f0980024 stg %r14,152(%r15)
00000000000120ac: c0e500014296 brasl %r14,3a5d8
00000000000120b2: a7f40001 brc 15,120b4
>00000000000120b6: 0707 bcr 0,%r7
00000000000120b8: eb7ff0500024 stmg %r7,%r15,80(%r15)
00000000000120be: c0d000195825 larl %r13,33d108
00000000000120c4: a7f13f00 tmll %r15,16128
00000000000120c8: a7840001 brc 8,120ca
Call Trace:
([<00000000000120b2>] rest_init+0x32/0x38)
[<00000000004be614>] start_kernel+0x37c/0x410
[<0000000000012020>] _ehead+0x20/0x80
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
2007-04-27 16:01:41 +02:00
extern void show_code ( struct pt_regs * regs ) ;
2012-07-31 16:23:59 +02:00
extern void print_fn_code ( unsigned char * code , unsigned long len ) ;
2005-04-16 15:20:36 -07:00
unsigned long get_wchan ( struct task_struct * p ) ;
2006-01-12 01:05:49 -08:00
# define task_pt_regs(tsk) ((struct pt_regs *) \
2006-01-12 01:05:50 -08:00
( task_stack_page ( tsk ) + THREAD_SIZE ) - 1 )
2006-01-12 01:05:49 -08:00
# define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr)
# define KSTK_ESP(tsk) (task_pt_regs(tsk)->gprs[15])
2005-04-16 15:20:36 -07:00
2012-03-28 18:30:02 +01:00
static inline unsigned short stap ( void )
{
unsigned short cpu_address ;
asm volatile ( " stap %0 " : " =m " ( cpu_address ) ) ;
return cpu_address ;
}
2005-04-16 15:20:36 -07:00
/*
* Give up the time slice of the virtual PU .
*/
2006-07-12 16:39:58 +02:00
static inline void cpu_relax ( void )
{
if ( MACHINE_HAS_DIAG44 )
2007-02-05 21:17:20 +01:00
asm volatile ( " diag 0,0,68 " ) ;
barrier ( ) ;
2006-07-12 16:39:58 +02:00
}
2005-04-16 15:20:36 -07:00
2007-06-19 13:10:06 +02:00
static inline void psw_set_key ( unsigned int key )
{
asm volatile ( " spka 0(%0) " : : " d " (key)) ;
}
2005-06-25 14:55:30 -07:00
/*
* Set PSW to specified value .
*/
static inline void __load_psw ( psw_t psw )
{
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2010-02-26 22:37:31 +01:00
asm volatile ( " lpsw %0 " : : " Q " ( psw ) : " cc " ) ;
2005-06-25 14:55:30 -07:00
# else
2010-02-26 22:37:31 +01:00
asm volatile ( " lpswe %0 " : : " Q " ( psw ) : " cc " ) ;
2005-06-25 14:55:30 -07:00
# endif
}
2005-04-16 15:20:36 -07:00
/*
* Set PSW mask to specified value , while leaving the
* PSW addr pointing to the next instruction .
*/
static inline void __load_psw_mask ( unsigned long mask )
{
unsigned long addr ;
psw_t psw ;
2005-06-25 14:55:30 -07:00
2005-04-16 15:20:36 -07:00
psw . mask = mask ;
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2006-09-28 16:56:43 +02:00
asm volatile (
" basr %0,0 \n "
" 0: ahi %0,1f-0b \n "
2010-02-26 22:37:31 +01:00
" st %0,%O1+4(%R1) \n "
" lpsw %1 \n "
2005-04-16 15:20:36 -07:00
" 1: "
2010-02-26 22:37:31 +01:00
: " =&d " ( addr ) , " =Q " ( psw ) : " Q " ( psw ) : " memory " , " cc " ) ;
2012-05-23 16:24:51 +02:00
# else /* CONFIG_64BIT */
2006-09-28 16:56:43 +02:00
asm volatile (
" larl %0,1f \n "
2010-02-26 22:37:31 +01:00
" stg %0,%O1+8(%R1) \n "
" lpswe %1 \n "
2005-04-16 15:20:36 -07:00
" 1: "
2010-02-26 22:37:31 +01:00
: " =&d " ( addr ) , " =Q " ( psw ) : " Q " ( psw ) : " memory " , " cc " ) ;
2012-05-23 16:24:51 +02:00
# endif /* CONFIG_64BIT */
2005-04-16 15:20:36 -07:00
}
2011-10-30 15:16:48 +01:00
/*
* Rewind PSW instruction address by specified number of bytes .
*/
static inline unsigned long __rewind_psw ( psw_t psw , unsigned long ilc )
{
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2011-10-30 15:16:48 +01:00
if ( psw . addr & PSW_ADDR_AMODE )
/* 31 bit mode */
return ( psw . addr - ilc ) | PSW_ADDR_AMODE ;
/* 24 bit mode */
return ( psw . addr - ilc ) & ( ( 1UL < < 24 ) - 1 ) ;
# else
unsigned long mask ;
mask = ( psw . mask & PSW_MASK_EA ) ? - 1UL :
( psw . mask & PSW_MASK_BA ) ? ( 1UL < < 31 ) - 1 :
( 1UL < < 24 ) - 1 ;
return ( psw . addr - ilc ) & mask ;
# endif
}
2005-04-16 15:20:36 -07:00
/*
* Function to drop a processor into disabled wait state
*/
2012-01-12 17:17:21 -08:00
static inline void __noreturn disabled_wait ( unsigned long code )
2005-04-16 15:20:36 -07:00
{
unsigned long ctl_buf ;
2005-06-25 14:55:30 -07:00
psw_t dw_psw ;
2005-04-16 15:20:36 -07:00
2011-10-30 15:16:50 +01:00
dw_psw . mask = PSW_MASK_BASE | PSW_MASK_WAIT | PSW_MASK_BA | PSW_MASK_EA ;
2005-06-25 14:55:30 -07:00
dw_psw . addr = code ;
2005-04-16 15:20:36 -07:00
/*
* Store status and then load disabled wait psw ,
* the processor is dead afterwards
*/
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2006-09-28 16:56:43 +02:00
asm volatile (
" stctl 0,0,0(%2) \n "
" ni 0(%2),0xef \n " /* switch off protection */
" lctl 0,0,0(%2) \n "
" stpt 0xd8 \n " /* store timer */
" stckc 0xe0 \n " /* store clock comparator */
" stpx 0x108 \n " /* store prefix register */
" stam 0,15,0x120 \n " /* store access registers */
" std 0,0x160 \n " /* store f0 */
" std 2,0x168 \n " /* store f2 */
" std 4,0x170 \n " /* store f4 */
" std 6,0x178 \n " /* store f6 */
" stm 0,15,0x180 \n " /* store general registers */
" stctl 0,15,0x1c0 \n " /* store control registers */
" oi 0x1c0,0x10 \n " /* fake protection bit */
" lpsw 0(%1) "
: " =m " ( ctl_buf )
: " a " ( & dw_psw ) , " a " ( & ctl_buf ) , " m " ( dw_psw ) : " cc " ) ;
2012-05-23 16:24:51 +02:00
# else /* CONFIG_64BIT */
2006-09-28 16:56:43 +02:00
asm volatile (
" stctg 0,0,0(%2) \n "
" ni 4(%2),0xef \n " /* switch off protection */
" lctlg 0,0,0(%2) \n "
" lghi 1,0x1000 \n "
" stpt 0x328(1) \n " /* store timer */
" stckc 0x330(1) \n " /* store clock comparator */
" stpx 0x318(1) \n " /* store prefix register */
" stam 0,15,0x340(1) \n " /* store access registers */
" stfpc 0x31c(1) \n " /* store fpu control */
" std 0,0x200(1) \n " /* store f0 */
" std 1,0x208(1) \n " /* store f1 */
" std 2,0x210(1) \n " /* store f2 */
" std 3,0x218(1) \n " /* store f3 */
" std 4,0x220(1) \n " /* store f4 */
" std 5,0x228(1) \n " /* store f5 */
" std 6,0x230(1) \n " /* store f6 */
" std 7,0x238(1) \n " /* store f7 */
" std 8,0x240(1) \n " /* store f8 */
" std 9,0x248(1) \n " /* store f9 */
" std 10,0x250(1) \n " /* store f10 */
" std 11,0x258(1) \n " /* store f11 */
" std 12,0x260(1) \n " /* store f12 */
" std 13,0x268(1) \n " /* store f13 */
" std 14,0x270(1) \n " /* store f14 */
" std 15,0x278(1) \n " /* store f15 */
" stmg 0,15,0x280(1) \n " /* store general registers */
" stctg 0,15,0x380(1) \n " /* store control registers */
" oi 0x384(1),0x10 \n " /* fake protection bit */
" lpswe 0(%1) "
: " =m " ( ctl_buf )
2009-09-22 22:58:47 +02:00
: " a " ( & dw_psw ) , " a " ( & ctl_buf ) , " m " ( dw_psw ) : " cc " , " 0 " , " 1 " ) ;
2012-05-23 16:24:51 +02:00
# endif /* CONFIG_64BIT */
2008-12-25 13:39:16 +01:00
while ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
2012-03-28 18:30:02 +01:00
/*
* Use to set psw mask except for the first byte which
* won ' t be changed by this function .
*/
static inline void
__set_psw_mask ( unsigned long mask )
{
__load_psw_mask ( mask | ( arch_local_save_flags ( ) & ~ ( - 1UL > > 8 ) ) ) ;
}
# define local_mcck_enable() \
__set_psw_mask ( psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK )
# define local_mcck_disable() \
__set_psw_mask ( psw_kernel_bits | PSW_MASK_DAT )
2007-02-05 21:18:37 +01:00
/*
* Basic Machine Check / Program Check Handler .
*/
extern void s390_base_mcck_handler ( void ) ;
extern void s390_base_pgm_handler ( void ) ;
extern void s390_base_ext_handler ( void ) ;
extern void ( * s390_base_mcck_handler_fn ) ( void ) ;
extern void ( * s390_base_pgm_handler_fn ) ( void ) ;
extern void ( * s390_base_ext_handler_fn ) ( void ) ;
2006-09-25 23:31:33 -07:00
# define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
2006-09-20 15:58:20 +02:00
/*
* Helper macro for exception table entries
*/
2012-05-23 16:24:51 +02:00
# ifndef CONFIG_64BIT
2006-09-20 15:58:20 +02:00
# define EX_TABLE(_fault,_target) \
" .section __ex_table, \" a \" \n " \
" .align 4 \n " \
" .long " # _fault " , " # _target " \n " \
" .previous \n "
# else
# define EX_TABLE(_fault,_target) \
" .section __ex_table, \" a \" \n " \
" .align 8 \n " \
" .quad " # _fault " , " # _target " \n " \
" .previous \n "
# endif
2012-06-05 09:59:52 +02:00
extern int memcpy_real ( void * , void * , size_t ) ;
extern void memcpy_absolute ( void * , void * , size_t ) ;
# define mem_assign_absolute(dest, val) { \
__typeof__ ( dest ) __tmp = ( val ) ; \
\
BUILD_BUG_ON ( sizeof ( __tmp ) ! = sizeof ( val ) ) ; \
memcpy_absolute ( & ( dest ) , & __tmp , sizeof ( __tmp ) ) ; \
}
2005-04-16 15:20:36 -07:00
# endif /* __ASM_S390_PROCESSOR_H */