[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git-commits-head
Subject:    [PATCH] s390: kernel stack options.
From:       Linux Kernel Mailing List <linux-kernel () vger ! kernel ! org>
Date:       2004-08-31 17:42:58
Message-ID: 200408311921.i7VJL8R8025482 () hera ! kernel ! org
[Download RAW message or body]

ChangeSet 1.1922, 2004/08/31 10:42:58-07:00, schwidefsky@de.ibm.com

	[PATCH] s390: kernel stack options.
	
	This adds support for the new compiler options -mkernel-backchain,
	-mstack-size, -mstack-guard, -mwarn-dynamicstack and -mwarn-framesize.
	
	The option -mkernel-backchain enables the use of modified layout for the
	stack frames of kernel functions.  This breaks the ABI, modules compiled
	with the option won't work on a kernel compiled with the option and vice
	versa.  The positive effect of the option is a drastic reduction of kernel
	stack use.  The trick is that the new frame layout allows to overlap the 96
	(31 bit)/160 (64 bit) byte bias areas of the functions on the call chain.
	This lowers the minimal stack usage of a function from 96 bytes to 16 bytes
	(31 bit) and 160 bytes to 24 bytes (64 bit).  The kernel stack use is
	decreased to a point where it is possible to use 4K (31 bit) / 8K (64 bit)
	stacks.  The split into process stack and interrupt stack is already in
	place.
	
	The options -mstack-size and -mstack-guard are used to detect kernel stack
	overflows.  The compiler adds code to the prolog of every function that
	causes an illegal operation if the kernel stack is about to overflow.
	
	The options -mwarn-dynamicstack and -mwarn-framesize cause the compiler to
	emit warnings if a function uses dynamic stack allocation or if the
	function frame size is bigger then a specified limit.
	
	To play safe all the new options are configurable.
	
	Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
	Signed-off-by: Andrew Morton <akpm@osdl.org>
	Signed-off-by: Linus Torvalds <torvalds@osdl.org>



 arch/s390/Kconfig              |  126 ++++++++++++++++++++++++++++++++---------
 arch/s390/Makefile             |   26 +++++++-
 arch/s390/defconfig            |   14 +++-
 arch/s390/kernel/asm-offsets.c |    4 +
 arch/s390/kernel/entry.S       |   85 +++++++++++++++++++--------
 arch/s390/kernel/entry64.S     |   91 ++++++++++++++++++++---------
 arch/s390/kernel/head.S        |    6 +
 arch/s390/kernel/head64.S      |    6 +
 arch/s390/kernel/process.c     |   68 ++++++++--------------
 arch/s390/kernel/setup.c       |    4 +
 arch/s390/kernel/smp.c         |   14 +++-
 arch/s390/kernel/traps.c       |   96 ++++++++++++++++++++++---------
 include/asm-s390/lowcore.h     |    8 +-
 include/asm-s390/processor.h   |   19 ++++++
 include/asm-s390/thread_info.h |   38 +++++++-----
 15 files changed, 428 insertions(+), 177 deletions(-)


diff -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig
--- a/arch/s390/Kconfig	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/Kconfig	2004-08-31 12:21:19 -07:00
@@ -48,33 +48,6 @@
 	depends on ARCH_S390X = 'n'
 	default y
 
-choice
-	prompt "Processor type"
-	default MARCH_G5
-
-config MARCH_G5
-	bool "S/390 model G5 and G6"
-	depends on ARCH_S390_31
-	help
-	  Select this to build a 31 bit kernel that works
-	  on all S/390 and zSeries machines.
-
-config MARCH_Z900
-	bool "IBM eServer zSeries model z800 and z900"
-	help
-	  Select this to optimize for zSeries machines. This
-	  will enable some optimizations that are not available
-	  on older 31 bit only CPUs.
-
-config MARCH_Z990
-	bool "IBM eServer zSeries model z890 and z990"
-	help
-	  Select this enable optimizations for model z890/z990.
-	  This will be slightly faster but does not work on
-	  older machines such as the z900.
-
-endchoice
-
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
@@ -148,6 +121,105 @@
 	help
 	  This allows you to run 32-bit Linux/ELF binaries on your zSeries
 	  in 64 bit mode. Everybody wants this; say Y.
+
+comment "Code generation options"
+
+choice
+	prompt "Processor type"
+	default MARCH_G5
+
+config MARCH_G5
+	bool "S/390 model G5 and G6"
+	depends on ARCH_S390_31
+	help
+	  Select this to build a 31 bit kernel that works
+	  on all S/390 and zSeries machines.
+
+config MARCH_Z900
+	bool "IBM eServer zSeries model z800 and z900"
+	help
+	  Select this to optimize for zSeries machines. This
+	  will enable some optimizations that are not available
+	  on older 31 bit only CPUs.
+
+config MARCH_Z990
+	bool "IBM eServer zSeries model z890 and z990"
+	help
+	  Select this enable optimizations for model z890/z990.
+	  This will be slightly faster but does not work on
+	  older machines such as the z900.
+
+endchoice
+
+config PACK_STACK
+	bool "Pack kernel stack"
+	help
+	  This option enables the compiler option -mkernel-backchain if it
+	  is available. If the option is available the compiler supports
+	  the new stack layout which dramatically reduces the minimum stack
+	  frame size. With an old compiler a non-leaf function needs a
+	  minimum of 96 bytes on 31 bit and 160 bytes on 64 bit. With
+	  -mkernel-backchain the minimum size drops to 16 byte on 31 bit
+	  and 24 byte on 64 bit.
+
+	  Say Y if you are unsure.
+
+config SMALL_STACK
+	bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb"
+	depends on PACK_STACK
+	help
+	  If you say Y here and the compiler supports the -mkernel-backchain
+	  option the kernel will use a smaller kernel stack size. For 31 bit
+	  the reduced size is 4kb instead of 8kb and for 64 bit it is 8kb
+	  instead of 16kb. This allows to run more thread on a system and
+	  reduces the pressure on the memory management for higher order
+	  page allocations.
+
+	  Say N if you are unsure.
+
+
+config CHECK_STACK
+	bool "Detect kernel stack overflow"
+	help
+	  This option enables the compiler option -mstack-guard and
+	  -mstack-size if they are available. If the compiler supports them
+	  it will emit additional code to each function prolog to trigger
+	  an illegal operation if the kernel stack is about to overflow.
+
+	  Say N if you are unsure.
+
+config STACK_GUARD
+	int "Size of the guard area (128-1024)"
+	range 128 1024
+	depends on CHECK_STACK
+	default "256"
+	help
+	  This allows you to specify the size of the guard area at the lower
+	  end of the kernel stack. If the kernel stack points into the guard
+	  area on function entry an illegal operation is triggered. The size
+	  needs to be a power of 2. Please keep in mind that the size of an
+	  interrupt frame is 184 bytes for 31 bit and 328 bytes on 64 bit.
+	  The minimum size for the stack guard should be 256 for 31 bit and
+	  512 for 64 bit.
+
+config WARN_STACK
+	bool "Emit compiler warnings for function with broken stack usage"
+	help
+	  This option enables the compiler options -mwarn-framesize and
+	  -mwarn-dynamicstack. If the compiler supports these options it
+	  will generate warnings for function which either use alloca or
+	  create a stack frame bigger then CONFIG_WARN_STACK_SIZE.
+
+	  Say N if you are unsure.
+
+config WARN_STACK_SIZE
+	int "Maximum frame size considered safe (128-2048)"
+	range 128 2048
+	depends on WARN_STACK
+	default "256"
+	help
+	  This allows you to specify the maximum frame size a function may
+	  have without the compiler complaining about it.
 
 comment "I/O subsystem configuration"
 
diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/Makefile	2004-08-31 12:21:19 -07:00
@@ -18,6 +18,7 @@
 CFLAGS		+= -m31
 AFLAGS		+= -m31
 UTS_MACHINE	:= s390
+STACK_SIZE	:= 8192
 endif
 
 ifdef CONFIG_ARCH_S390X
@@ -26,16 +27,37 @@
 CFLAGS		+= -m64
 AFLAGS		+= -m64
 UTS_MACHINE	:= s390x
+STACK_SIZE	:= 16384
 endif
 
 cflags-$(CONFIG_MARCH_G5)   += $(call cc-option,-march=g5)
 cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
 cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
 
-CFLAGS		+= $(cflags-y)
+ifeq ($(call cc-option-yn,-mkernel-backchain),y)
+cflags-$(CONFIG_PACK_STACK)  += -mkernel-backchain -D__PACK_STACK
+aflags-$(CONFIG_PACK_STACK)  += -D__PACK_STACK
+cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+ifdef CONFIG_SMALL_STACK
+STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
+endif
+endif
+
+ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
+cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE)
+cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD)
+endif
+
+ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
+cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack
+cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE)
+endif
+
+CFLAGS		+= -mbackchain $(cflags-y)
 CFLAGS		+= $(call cc-option,-finline-limit=10000)
 CFLAGS 		+= -pipe -fno-strength-reduce -Wno-sign-compare 
-CFLAGS		+= -mbackchain
+AFLAGS		+= $(aflags-y)
 
 OBJCOPYFLAGS	:= -O binary
 LDFLAGS_vmlinux := -e start
diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/defconfig	2004-08-31 12:21:19 -07:00
@@ -58,13 +58,21 @@
 # CONFIG_ARCH_S390X is not set
 # CONFIG_64BIT is not set
 CONFIG_ARCH_S390_31=y
-CONFIG_MARCH_G5=y
-# CONFIG_MARCH_Z900 is not set
-# CONFIG_MARCH_Z990 is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=32
 # CONFIG_HOTPLUG_CPU is not set
 CONFIG_MATHEMU=y
+
+#
+# Code generation options
+#
+CONFIG_MARCH_G5=y
+# CONFIG_MARCH_Z900 is not set
+# CONFIG_MARCH_Z990 is not set
+CONFIG_PACK_STACK=y
+# CONFIG_SMALL_STACK is not set
+# CONFIG_CHECK_STACK is not set
+# CONFIG_WARN_STACK is not set
 
 #
 # I/O subsystem configuration
diff -Nru a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
--- a/arch/s390/kernel/asm-offsets.c	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/asm-offsets.c	2004-08-31 12:21:19 -07:00
@@ -39,5 +39,9 @@
 	DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),);
 	DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),);
 	DEFINE(__PT_SIZE, sizeof(struct pt_regs),);
+	BLANK();
+	DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),);
+	DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),);
+	DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),);
 	return 0;
 }
diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
--- a/arch/s390/kernel/entry.S	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/entry.S	2004-08-31 12:21:19 -07:00
@@ -19,6 +19,7 @@
 #include <asm/thread_info.h>
 #include <asm/offsets.h>
 #include <asm/unistd.h>
+#include <asm/page.h>
 
 /*
  * Stack layout for the system_call stack entry.
@@ -52,6 +53,9 @@
 		 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
+STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
+STACK_SIZE  = 1 << STACK_SHIFT
+
 #define BASED(name) name-system_call(%r13)
 
 /*
@@ -86,10 +90,16 @@
 	bnz	BASED(1f)
 0:	l	%r14,__LC_ASYNC_STACK	# are we already on the async stack ?
 	slr	%r14,%r15
-	sra	%r14,13
+	sra	%r14,STACK_SHIFT
 	be	BASED(2f)
 1:	l	%r15,__LC_ASYNC_STACK
 	.endif
+#ifdef CONFIG_CHECK_STACK
+	b	BASED(3f)
+2:	tml	%r15,STACK_SIZE - CONFIG_STACK_GUARD
+	bz	BASED(stack_overflow)
+3:
+#endif
 2:	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
 	mvc	SP_PSW(8,%r15),0(%r12)	# move user PSW to stack
 	la	%r12,\psworg
@@ -99,7 +109,7 @@
 	st	%r12,SP_ILC(%r15)
 	mvc	SP_R12(16,%r15),\savearea # move %r12-%r15 to stack
 	la	%r12,0
-	st	%r12,0(%r15)		# clear back chain
+	st	%r12,__SF_BACKCHAIN(%r15)	# clear back chain
 	.endm
 
 	.macro  RESTORE_ALL sync
@@ -124,19 +134,19 @@
 __switch_to_base:
 	tm	__THREAD_per(%r3),0xe8		# new process is using per ?
 	bz	__switch_to_noper-__switch_to_base(%r1)	# if not we're fine
-        stctl   %c9,%c11,24(%r15)		# We are using per stuff
-        clc     __THREAD_per(12,%r3),24(%r15)
+        stctl   %c9,%c11,__SF_EMPTY(%r15)	# We are using per stuff
+        clc     __THREAD_per(12,%r3),__SF_EMPTY(%r15)
         be      __switch_to_noper-__switch_to_base(%r1)	# we got away w/o bashing TLB's
         lctl    %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 __switch_to_noper:
-        stm     %r6,%r15,24(%r15)       # store __switch_to registers of prev task
+        stm     %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
 	st	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
 	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
-	lm	%r6,%r15,24(%r15)	# load __switch_to registers of next task
+	lm	%r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
 	st	%r3,__LC_CURRENT	# __LC_CURRENT = current task struct
 	l	%r3,__THREAD_info(%r3)  # load thread_info from task struct
 	st	%r3,__LC_THREAD_INFO
-	ahi	%r3,8192
+	ahi	%r3,STACK_SIZE
 	st	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
 	br	%r14
 
@@ -146,24 +156,24 @@
  */
 	.global do_call_softirq
 do_call_softirq:
-	stnsm	24(%r15),0xfc
-	stm	%r12,%r15,28(%r15)
+	stnsm	__SF_EMPTY(%r15),0xfc
+	stm	%r12,%r15,__SF_GPRS(%r15)
 	lr	%r12,%r15
         basr    %r13,0
 do_call_base:
 	l	%r0,__LC_ASYNC_STACK
 	slr     %r0,%r15
-	sra	%r0,13
+	sra	%r0,STACK_SHIFT
 	be	0f-do_call_base(%r13)
 	l	%r15,__LC_ASYNC_STACK
 0:	sl	%r15,.Lc_overhead-do_call_base(%r13)
-        st	%r12,0(%r15)	# store backchain
+        st	%r12,__SF_BACKCHAIN(%r15)	# store backchain
 	l	%r1,.Ldo_softirq-do_call_base(%r13)
 	basr	%r14,%r1
-	lm	%r12,%r15,28(%r12)
-	ssm	24(%r15)
+	lm	%r12,%r15,__SF_GPRS(%r12)
+	ssm	__SF_EMPTY(%r15)
 	br	%r14
-	
+
 __critical_start:
 /*
  * SVC interrupt handler routine. System calls are synchronous events and
@@ -309,7 +319,7 @@
 	st	%r15,SP_R15(%r15)	# store stack pointer for new kthread
 0:	l       %r1,BASED(.Lschedtail)
 	basr    %r14,%r1
-        stosm   24(%r15),0x03     # reenable interrupts
+        stosm   __SF_EMPTY(%r15),0x03     # reenable interrupts
 	b	BASED(sysc_return)
 
 #
@@ -460,7 +470,7 @@
 	mvc	__THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
 	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
 	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-	stosm	24(%r15),0x03		# reenable interrupts
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	b	BASED(sysc_do_svc)
 
 /*
@@ -496,16 +506,16 @@
 	l	%r1,SP_R15(%r15)
 	s	%r1,BASED(.Lc_spsize)
 	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
-        xc      0(4,%r1),0(%r1)        # clear back chain
+        xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
 	lr	%r15,%r1
 io_resume_loop:
 	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
 	bno	BASED(io_leave)
 	mvc     __TI_precount(4,%r9),BASED(.Lc_pactive)
-        stosm   24(%r15),0x03          # reenable interrupts
+        stosm   __SF_EMPTY(%r15),0x03  # reenable interrupts
         l       %r1,BASED(.Lschedule)
 	basr	%r14,%r1	       # call schedule
-        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
+        stnsm   __SF_EMPTY(%r15),0xfc  # disable I/O and ext. interrupts
 	xc      __TI_precount(4,%r9),__TI_precount(%r9)
 	b	BASED(io_resume_loop)
 #endif
@@ -517,7 +527,7 @@
 	l	%r1,__LC_KERNEL_STACK
 	s	%r1,BASED(.Lc_spsize)
 	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
-        xc      0(4,%r1),0(%r1)        # clear back chain
+        xc      __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
 	lr	%r15,%r1
 #
 # One of the work bits is on. Find out which one.
@@ -535,9 +545,9 @@
 #	
 io_reschedule:        
         l       %r1,BASED(.Lschedule)
-        stosm   24(%r15),0x03          # reenable interrupts
+        stosm   __SF_EMPTY(%r15),0x03  # reenable interrupts
 	basr    %r14,%r1	       # call scheduler
-        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
+        stnsm   __SF_EMPTY(%r15),0xfc  # disable I/O and ext. interrupts
 	tm	__TI_flags+3(%r9),_TIF_WORK_INT
 	bz	BASED(io_leave)        # there is no work to do
 	b	BASED(io_work_loop)
@@ -546,12 +556,12 @@
 # _TIF_SIGPENDING is set, call do_signal
 #
 io_sigpending:     
-        stosm   24(%r15),0x03          # reenable interrupts
+        stosm   __SF_EMPTY(%r15),0x03  # reenable interrupts
         la      %r2,SP_PTREGS(%r15)    # load pt_regs
         sr      %r3,%r3                # clear *oldset
         l       %r1,BASED(.Ldo_signal)
 	basr    %r14,%r1	       # call do_signal
-        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
+        stnsm   __SF_EMPTY(%r15),0xfc  # disable I/O and ext. interrupts
 	b	BASED(io_leave)        # out of here, do NOT recheck
 
 /*
@@ -593,7 +603,7 @@
         lctl    %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
         lam     %a0,%a15,__LC_AREGS_SAVE_AREA
         stosm   0(%r15),0x04           # now we can turn dat on
-        lm      %r6,%r15,24(%r15)      # load registers from clone
+        lm      %r6,%r15,__SF_GPRS(%r15) # load registers from clone
         basr    %r14,0
         l       %r14,restart_addr-.(%r14)
         br      %r14                   # branch to start_secondary
@@ -612,6 +622,31 @@
 restart_crash:
         .long  0x000a0000,0x00000000
 restart_go:
+#endif
+
+#ifdef CONFIG_CHECK_STACK
+/*
+ * The synchronous or the asynchronous stack overflowed. We are dead.
+ * No need to properly save the registers, we are going to panic anyway.
+ * Setup a pt_regs so that show_trace can provide a good call trace.
+ */
+stack_overflow:
+	l	%r15,__LC_PANIC_STACK	# change to panic stack
+	sl	%r15,BASED(.Lc_spsize)
+	mvc	SP_PSW(8,%r15),0(%r12)	# move user PSW to stack
+	stm	%r0,%r11,SP_R0(%r15)	# store gprs %r0-%r11 to kernel stack
+	la	%r1,__LC_SAVE_AREA
+	ch	%r12,BASED(.L0x020)	# old psw addr == __LC_SVC_OLD_PSW ?
+	be	BASED(0f)
+	ch	%r12,BASED(.L0x028)	# old psw addr == __LC_PGM_OLD_PSW ?
+	be	BASED(0f)
+	la	%r1,__LC_SAVE_AREA+16
+0:	mvc	SP_R12(16,%r15),0(%r1)	# move %r12-%r15 to stack
+        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+	l	%r1,BASED(1f)		# branch to kernel_stack_overflow
+        la      %r2,SP_PTREGS(%r15)	# load pt_regs
+	br	%r1
+1:	.long  kernel_stack_overflow
 #endif
 
 cleanup_table_system_call:
diff -Nru a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
--- a/arch/s390/kernel/entry64.S	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/entry64.S	2004-08-31 12:21:19 -07:00
@@ -19,6 +19,7 @@
 #include <asm/thread_info.h>
 #include <asm/offsets.h>
 #include <asm/unistd.h>
+#include <asm/page.h>
 
 /*
  * Stack layout for the system_call stack entry.
@@ -48,6 +49,9 @@
 SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
 SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 
+STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
+STACK_SIZE  = 1 << STACK_SHIFT
+
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
 		 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
@@ -85,10 +89,16 @@
 	jnz	1f
 0:	lg	%r14,__LC_ASYNC_STACK	# are we already on the async. stack ?
 	slgr	%r14,%r15
-	srag	%r14,%r14,14
+	srag	%r14,%r14,STACK_SHIFT
 	jz	2f
 1:	lg	%r15,__LC_ASYNC_STACK	# load async stack
 	.endif
+#ifdef CONFIG_CHECK_STACK
+	j	3f
+2:	tml	%r15,STACK_SIZE - CONFIG_STACK_GUARD
+	jz	stack_overflow
+3:
+#endif
 2:	aghi    %r15,-SP_SIZE		# make room for registers & psw
 	mvc     SP_PSW(16,%r15),0(%r12)	# move user PSW to stack
 	la	%r12,\psworg
@@ -98,7 +108,7 @@
 	st	%r12,SP_ILC(%r15)
 	mvc	SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
 	la	%r12,0
-	stg	%r12,0(%r15)
+	stg	%r12,__SF_BACKCHAIN(%r15)
         .endm
 
 	.macro	RESTORE_ALL sync
@@ -121,19 +131,19 @@
 __switch_to:
 	tm	__THREAD_per+4(%r3),0xe8 # is the new process using per ?
 	jz	__switch_to_noper		# if not we're fine
-        stctg   %c9,%c11,48(%r15)       # We are using per stuff
-        clc     __THREAD_per(24,%r3),48(%r15)
+        stctg   %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
+        clc     __THREAD_per(24,%r3),__SF_EMPTY(%r15)
         je      __switch_to_noper            # we got away without bashing TLB's
         lctlg   %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 __switch_to_noper:
-        stmg    %r6,%r15,48(%r15)       # store __switch_to registers of prev task
+        stmg    %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
 	stg	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
 	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
-        lmg     %r6,%r15,48(%r15)       # load __switch_to registers of next task
+        lmg     %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
 	stg	%r3,__LC_CURRENT	# __LC_CURRENT = current task struct
 	lg	%r3,__THREAD_info(%r3)  # load thread_info from task struct
 	stg	%r3,__LC_THREAD_INFO
-	aghi	%r3,16384
+	aghi	%r3,STACK_SIZE
 	stg	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
 	br	%r14
 
@@ -143,19 +153,19 @@
  */
 	.global do_call_softirq
 do_call_softirq:
-	stnsm	48(%r15),0xfc
-	stmg	%r12,%r15,56(%r15)
+	stnsm	__SF_EMPTY(%r15),0xfc
+	stmg	%r12,%r15,__SF_GPRS(%r15)
 	lgr	%r12,%r15
 	lg	%r0,__LC_ASYNC_STACK
 	slgr    %r0,%r15
-	srag	%r0,%r0,14
+	srag	%r0,%r0,STACK_SHIFT
 	je	0f
 	lg	%r15,__LC_ASYNC_STACK
 0:	aghi	%r15,-STACK_FRAME_OVERHEAD
-	stg	%r12,0(%r15)		# store back chain
+	stg	%r12,__SF_BACKCHAIN(%r15)	# store back chain
 	brasl	%r14,do_softirq
-	lmg	%r12,%r15,56(%r12)
-	ssm	48(%r15)
+	lmg	%r12,%r15,__SF_GPRS(%r12)
+	ssm	__SF_EMPTY(%r15)
 	br	%r14
 
 __critical_start:
@@ -507,7 +517,7 @@
 	mvc	__THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
 	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
 	oi	__TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-	stosm	48(%r15),0x03		# reenable interrupts
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	j	sysc_do_svc
 
 /*
@@ -542,16 +552,16 @@
 	lg	%r1,SP_R15(%r15)
 	aghi	%r1,-SP_SIZE
 	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
-        xc      0(8,%r1),0(%r1)        # clear back chain
+        xc      __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
 	lgr	%r15,%r1
 io_resume_loop:
 	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
 	jno	io_leave
 	larl    %r1,.Lc_pactive
 	mvc     __TI_precount(4,%r9),0(%r1)
-        stosm   48(%r15),0x03          # reenable interrupts
+        stosm   __SF_EMPTY(%r15),0x03   # reenable interrupts
 	brasl   %r14,schedule          # call schedule
-        stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
+        stnsm   __SF_EMPTY(%r15),0xfc   # disable I/O and ext. interrupts
 	xc      __TI_precount(4,%r9),__TI_precount(%r9)
 	j	io_resume_loop
 #endif
@@ -563,7 +573,7 @@
 	lg	%r1,__LC_KERNEL_STACK
 	aghi	%r1,-SP_SIZE
 	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
-        xc      0(8,%r1),0(%r1)        # clear back chain
+        xc      __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
 	lgr	%r15,%r1
 #
 # One of the work bits is on. Find out which one.
@@ -580,23 +590,23 @@
 # _TIF_NEED_RESCHED is set, call schedule
 #	
 io_reschedule:        
-        stosm   48(%r15),0x03       # reenable interrupts
-        brasl   %r14,schedule       # call scheduler
-        stnsm   48(%r15),0xfc       # disable I/O and ext. interrupts
+	stosm   __SF_EMPTY(%r15),0x03	# reenable interrupts
+	brasl   %r14,schedule		# call scheduler
+	stnsm   __SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
 	tm	__TI_flags+7(%r9),_TIF_WORK_INT
-	jz	io_leave               # there is no work to do
+	jz	io_leave		# there is no work to do
 	j	io_work_loop
 
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
 io_sigpending:     
-        stosm   48(%r15),0x03       # reenable interrupts
-        la      %r2,SP_PTREGS(%r15) # load pt_regs
-        slgr    %r3,%r3             # clear *oldset
-	brasl	%r14,do_signal      # call do_signal
-        stnsm   48(%r15),0xfc       # disable I/O and ext. interrupts
-	j	sysc_leave          # out of here, do NOT recheck
+	stosm   __SF_EMPTY(%r15),0x03	# reenable interrupts
+	la      %r2,SP_PTREGS(%r15)	# load pt_regs
+	slgr    %r3,%r3			# clear *oldset
+	brasl	%r14,do_signal		# call do_signal
+	stnsm   __SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
+	j	sysc_leave		# out of here, do NOT recheck
 
 /*
  * External interrupt handler routine
@@ -635,7 +645,7 @@
         lghi    %r10,__LC_AREGS_SAVE_AREA
         lam     %a0,%a15,0(%r10)
         stosm   0(%r15),0x04           # now we can turn dat on
-        lmg     %r6,%r15,48(%r15)      # load registers from clone
+        lmg     %r6,%r15,__SF_GPRS(%r15) # load registers from clone
 	jg      start_secondary
 #else
 /*
@@ -650,6 +660,29 @@
 restart_crash:
         .long  0x000a0000,0x00000000,0x00000000,0x00000000
 restart_go:
+#endif
+
+#ifdef CONFIG_CHECK_STACK
+/*
+ * The synchronous or the asynchronous stack overflowed. We are dead.
+ * No need to properly save the registers, we are going to panic anyway.
+ * Setup a pt_regs so that show_trace can provide a good call trace.
+ */
+stack_overflow:
+	lg	%r15,__LC_PANIC_STACK	# change to panic stack
+	aghi	%r1,-SP_SIZE
+	mvc	SP_PSW(16,%r15),0(%r12)	# move user PSW to stack
+	stmg	%r0,%r11,SP_R0(%r15)	# store gprs %r0-%r11 to kernel stack
+	la	%r1,__LC_SAVE_AREA
+	chi	%r12,__LC_SVC_OLD_PSW
+	je	0f
+	chi	%r12,__LC_PGM_OLD_PSW
+	je	0f
+	la	%r1,__LC_SAVE_AREA+16
+0:	mvc	SP_R12(32,%r15),0(%r1)  # move %r12-%r15 to stack
+        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+        la      %r2,SP_PTREGS(%r15)	# load pt_regs
+	jg	kernel_stack_overflow
 #endif
 
 cleanup_table_system_call:
diff -Nru a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
--- a/arch/s390/kernel/head.S	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/head.S	2004-08-31 12:21:19 -07:00
@@ -31,6 +31,8 @@
 #include <asm/setup.h>
 #include <asm/lowcore.h>
 #include <asm/offsets.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
 
 #ifndef CONFIG_IPL
         .org   0
@@ -741,10 +743,10 @@
 #
         l     %r15,.Linittu-.LPG2(%r13)
 	mvc   __LC_CURRENT(4),__TI_task(%r15)
-        ahi   %r15,8192                 # init_task_union + 8192
+        ahi   %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
         st    %r15,__LC_KERNEL_STACK    # set end of kernel stack
         ahi   %r15,-96
-        xc    0(4,%r15),0(%r15)         # set backchain to zero
+        xc    __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 
 # check control registers
         stctl  %c0,%c15,0(%r15)
diff -Nru a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
--- a/arch/s390/kernel/head64.S	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/head64.S	2004-08-31 12:21:19 -07:00
@@ -31,6 +31,8 @@
 #include <asm/setup.h>
 #include <asm/lowcore.h>
 #include <asm/offsets.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
 
 #ifndef CONFIG_IPL
         .org   0
@@ -741,10 +743,10 @@
 	larl  %r15,init_thread_union
 	lg    %r14,__TI_task(%r15)      # cache current in lowcore
 	stg   %r14,__LC_CURRENT
-        aghi  %r15,16384                # init_task_union + 16384
+        aghi  %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
-        xc    0(8,%r15),0(%r15)         # set backchain to zero
+        xc    __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
 
 # check control registers
         stctg  %c0,%c15,0(%r15)
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
--- a/arch/s390/kernel/process.c	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/process.c	2004-08-31 12:21:19 -07:00
@@ -58,14 +58,11 @@
  */
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-	unsigned long bc;
+	struct stack_frame *sf;
 
-	bc = *((unsigned long *) tsk->thread.ksp);
-#ifndef CONFIG_ARCH_S390X
-	return *((unsigned long *) (bc+56));
-#else
-	return *((unsigned long *) (bc+112));
-#endif
+	sf = (struct stack_frame *) tsk->thread.ksp;
+	sf = (struct stack_frame *) sf->back_chain;
+	return sf->gprs[8];
 }
 
 /*
@@ -232,20 +229,13 @@
 	unsigned long unused,
         struct task_struct * p, struct pt_regs * regs)
 {
-        struct stack_frame
+        struct fake_frame
           {
-            unsigned long back_chain;
-            unsigned long eos;
-            unsigned long glue1;
-            unsigned long glue2;
-            unsigned long scratch[2];
-            unsigned long gprs[10];    /* gprs 6 -15                       */
-            unsigned int  fprs[4];     /* fpr 4 and 6                      */
-            unsigned int  empty[4];
+	    struct stack_frame sf;
             struct pt_regs childregs;
           } *frame;
 
-        frame = ((struct stack_frame *)
+        frame = ((struct fake_frame *)
 		 (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
         p->thread.ksp = (unsigned long) frame;
 	p->set_child_tid = p->clear_child_tid = NULL;
@@ -253,13 +243,13 @@
         frame->childregs = *regs;
 	frame->childregs.gprs[2] = 0;	/* child returns 0 on fork. */
         frame->childregs.gprs[15] = new_stackp;
-        frame->back_chain = frame->eos = 0;
+        frame->sf.back_chain = 0;
 
         /* new return point is ret_from_fork */
-        frame->gprs[8] = (unsigned long) ret_from_fork;
+        frame->sf.gprs[8] = (unsigned long) ret_from_fork;
 
         /* fake return stack for resume(), don't go back to schedule */
-        frame->gprs[9] = (unsigned long) frame;
+        frame->sf.gprs[9] = (unsigned long) frame;
 
 	/* Save access registers to new thread structure. */
 	save_access_regs(&p->thread.acrs[0]);
@@ -402,30 +392,26 @@
 
 unsigned long get_wchan(struct task_struct *p)
 {
-	unsigned long r14, r15, bc;
-	unsigned long stack_page;
-	int count = 0;
-	if (!p || p == current || p->state == TASK_RUNNING)
+	struct stack_frame *sf, *low, *high;
+	unsigned long return_address;
+	int count;
+
+	if (!p || p == current || p->state == TASK_RUNNING || !p->thread_info)
 		return 0;
-	stack_page = (unsigned long) p->thread_info;
-	r15 = p->thread.ksp;
-	if (!stack_page || r15 < stack_page ||
-	    r15 >= THREAD_SIZE - sizeof(unsigned long) + stack_page)
+	low = (struct stack_frame *) p->thread_info;
+	high = (struct stack_frame *)
+		((unsigned long) p->thread_info + THREAD_SIZE) - 1;
+	sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN);
+	if (sf <= low || sf > high)
 		return 0;
-	bc = (*(unsigned long *) r15) & PSW_ADDR_INSN;
-	do {
-		if (bc < stack_page ||
-		    bc >= THREAD_SIZE - sizeof(unsigned long) + stack_page)
+	for (count = 0; count < 16; count++) {
+		sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+		if (sf <= low || sf > high)
 			return 0;
-#ifndef CONFIG_ARCH_S390X
-		r14 = (*(unsigned long *) (bc+56)) & PSW_ADDR_INSN;
-#else
-		r14 = *(unsigned long *) (bc+112);
-#endif
-		if (!in_sched_functions(r14))
-			return r14;
-		bc = (*(unsigned long *) bc) & PSW_ADDR_INSN;
-	} while (count++ < 16);
+		return_address = sf->gprs[8] & PSW_ADDR_INSN;
+		if (!in_sched_functions(return_address))
+			return return_address;
+	}
 	return 0;
 }
 
diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
--- a/arch/s390/kernel/setup.c	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/setup.c	2004-08-31 12:21:19 -07:00
@@ -503,6 +503,10 @@
 	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
 	lc->async_stack = (unsigned long)
 		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
+#ifdef CONFIG_CHECK_STACK
+	lc->panic_stack = (unsigned long)
+		__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
+#endif
 	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
 	lc->thread_info = (unsigned long) &init_thread_union;
 #ifdef CONFIG_ARCH_S390X
diff -Nru a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
--- a/arch/s390/kernel/smp.c	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/smp.c	2004-08-31 12:21:19 -07:00
@@ -741,7 +741,7 @@
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-	unsigned long async_stack;
+	unsigned long stack;
 	unsigned int cpu;
         int i;
 
@@ -761,12 +761,18 @@
 		lowcore_ptr[i] = (struct _lowcore *)
 			__get_free_pages(GFP_KERNEL|GFP_DMA, 
 					sizeof(void*) == 8 ? 1 : 0);
-		async_stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER);
-		if (lowcore_ptr[i] == NULL || async_stack == 0ULL)
+		stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER);
+		if (lowcore_ptr[i] == NULL || stack == 0ULL)
 			panic("smp_boot_cpus failed to allocate memory\n");
 
 		*(lowcore_ptr[i]) = S390_lowcore;
-		lowcore_ptr[i]->async_stack = async_stack + (ASYNC_SIZE);
+		lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
+#ifdef CONFIG_CHECK_STACK
+		stack = __get_free_pages(GFP_KERNEL,0);
+		if (stack == 0ULL)
+			panic("smp_boot_cpus failed to allocate memory\n");
+		lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
+#endif
 	}
 	set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
 
diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
--- a/arch/s390/kernel/traps.c	2004-08-31 12:21:19 -07:00
+++ b/arch/s390/kernel/traps.c	2004-08-31 12:21:19 -07:00
@@ -67,54 +67,93 @@
 #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
 
 #ifndef CONFIG_ARCH_S390X
-#define RET_ADDR 56
 #define FOURLONG "%08lx %08lx %08lx %08lx\n"
 static int kstack_depth_to_print = 12;
-
 #else /* CONFIG_ARCH_S390X */
-#define RET_ADDR 112
 #define FOURLONG "%016lx %016lx %016lx %016lx\n"
 static int kstack_depth_to_print = 20;
-
 #endif /* CONFIG_ARCH_S390X */
 
-void show_trace(struct task_struct *task, unsigned long * stack)
+/*
+ * For show_trace we have tree different stack to consider:
+ *   - the panic stack which is used if the kernel stack has overflown
+ *   - the asynchronous interrupt stack (cpu related)
+ *   - the synchronous kernel stack (process related)
+ * The stack trace can start at any of the three stack and can potentially
+ * touch all of them. The order is: panic stack, async stack, sync stack.
+ */
+static unsigned long
+__show_trace(unsigned long sp, unsigned long low, unsigned long high)
 {
-	unsigned long backchain, low_addr, high_addr, ret_addr;
+	struct stack_frame *sf;
+	struct pt_regs *regs;
 
-	if (!stack)
-		stack = (task == NULL) ? *stack_pointer : &(task->thread.ksp);
+	while (1) {
+		sp = sp & PSW_ADDR_INSN;
+		if (sp < low || sp > high - sizeof(*sf))
+			return sp;
+		sf = (struct stack_frame *) sp;
+		printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+		print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
+		/* Follow the backchain. */
+		while (1) {
+			low = sp;
+			sp = sf->back_chain & PSW_ADDR_INSN;
+			if (!sp)
+				break;
+			if (sp <= low || sp > high - sizeof(*sf))
+				return sp;
+			sf = (struct stack_frame *) sp;
+			printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+			print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
+		}
+		/* Zero backchain detected, check for interrupt frame. */
+		sp = (unsigned long) (sf + 1);
+		if (sp <= low || sp > high - sizeof(*regs))
+			return sp;
+		regs = (struct pt_regs *) sp;
+		printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
+		print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
+		low = sp;
+		sp = regs->gprs[15];
+	}
+}
 
+void show_trace(struct task_struct *task, unsigned long * stack)
+{
+	register unsigned long __r15 asm ("15");
+	unsigned long sp;
+
+	sp = (unsigned long) stack;
+	if (!sp)
+		sp = task ? task->thread.ksp : __r15;
 	printk("Call Trace:\n");
-	low_addr = ((unsigned long) stack) & PSW_ADDR_INSN;
-	high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
-	/* Skip the first frame (biased stack) */
-	backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN;
-	/* Print up to 8 lines */
-	while  (backchain > low_addr && backchain <= high_addr) {
-		ret_addr = *((unsigned long *) (backchain+RET_ADDR)) & PSW_ADDR_INSN;
-		printk(" [<%016lx>] ", ret_addr);
-		print_symbol("%s\n", ret_addr);
-		low_addr = backchain;
-		backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN;
-	}
+#ifdef CONFIG_CHECK_STACK
+	sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
+			  S390_lowcore.panic_stack);
+#endif
+	sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
+			  S390_lowcore.async_stack);
+	if (task)
+		__show_trace(sp, (unsigned long) task->thread_info,
+			     (unsigned long) task->thread_info + THREAD_SIZE);
+	else
+		__show_trace(sp, S390_lowcore.thread_info - THREAD_SIZE,
+			     S390_lowcore.thread_info);
 	printk("\n");
 }
 
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
+	register unsigned long * __r15 asm ("15");
 	unsigned long *stack;
 	int i;
 
 	// debugging aid: "show_stack(NULL);" prints the
 	// back trace for this cpu.
 
-	if (!sp) {
-		if (task)
-			sp = (unsigned long *) task->thread.ksp;
-		else
-			sp = *stack_pointer;
-	}
+	if (!sp)
+		sp = task ? (unsigned long *) task->thread.ksp : __r15;
 
 	stack = sp;
 	for (i = 0; i < kstack_depth_to_print; i++) {
@@ -591,6 +630,11 @@
 	}
 }
 
+asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
+{
+	die("Kernel stack overflow", regs, 0);
+	panic("Corrupt kernel stack, can't continue.");
+}
 
 
 /* init is done in lowcore.S and head.S */
diff -Nru a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
--- a/include/asm-s390/lowcore.h	2004-08-31 12:21:19 -07:00
+++ b/include/asm-s390/lowcore.h	2004-08-31 12:21:19 -07:00
@@ -68,6 +68,7 @@
 #define __LC_ASYNC_STACK                0xC48
 #define __LC_KERNEL_ASCE		0xC4C
 #define __LC_USER_ASCE			0xC50
+#define __LC_PANIC_STACK                0xC54
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
@@ -80,6 +81,7 @@
 #define __LC_ASYNC_STACK                0xD50
 #define __LC_KERNEL_ASCE		0xD58
 #define __LC_USER_ASCE			0xD60
+#define __LC_PANIC_STACK                0xD68
 #define __LC_CPUID                      0xD90
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
@@ -176,7 +178,8 @@
 	__u32        async_stack;              /* 0xc48 */
 	__u32        kernel_asce;              /* 0xc4c */
 	__u32        user_asce;                /* 0xc50 */
-	__u8         pad10[0xc60-0xc54];       /* 0xc54 */
+	__u32        panic_stack;              /* 0xc54 */
+	__u8         pad10[0xc60-0xc58];       /* 0xc58 */
 	/* entry.S sensitive area start */
 	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
 	__u32        ipl_device;               /* 0xc7c */
@@ -257,7 +260,8 @@
 	__u64        async_stack;              /* 0xd50 */
 	__u64        kernel_asce;              /* 0xd58 */
 	__u64        user_asce;                /* 0xd60 */
-	__u8         pad10[0xd80-0xd68];       /* 0xd68 */
+	__u64        panic_stack;              /* 0xd68 */
+	__u8         pad10[0xd80-0xd70];       /* 0xd70 */
 	/* entry.S sensitive area start */
 	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
 	__u32        ipl_device;               /* 0xdb8 */
diff -Nru a/include/asm-s390/processor.h b/include/asm-s390/processor.h
--- a/include/asm-s390/processor.h	2004-08-31 12:21:19 -07:00
+++ b/include/asm-s390/processor.h	2004-08-31 12:21:19 -07:00
@@ -103,6 +103,25 @@
 
 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
 
 #ifndef __s390x__
diff -Nru a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h
--- a/include/asm-s390/thread_info.h	2004-08-31 12:21:19 -07:00
+++ b/include/asm-s390/thread_info.h	2004-08-31 12:21:19 -07:00
@@ -11,6 +11,30 @@
 
 #ifdef __KERNEL__
 
+/*
+ * Size of kernel stack for each process
+ */
+#ifndef __s390x__
+#ifndef __SMALL_STACK
+#define THREAD_ORDER 1
+#define ASYNC_ORDER  1
+#else
+#define THREAD_ORDER 0
+#define ASYNC_ORDER  0
+#endif
+#else /* __s390x__ */
+#ifndef __SMALL_STACK_STACK
+#define THREAD_ORDER 2
+#define ASYNC_ORDER  2
+#else
+#define THREAD_ORDER 1
+#define ASYNC_ORDER  1
+#endif
+#endif /* __s390x__ */
+
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+#define ASYNC_SIZE  (PAGE_SIZE << ASYNC_ORDER)
+
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 #include <asm/lowcore.h>
@@ -46,20 +70,6 @@
 
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
-
-/*
- * Size of kernel stack for each process
- */
-#ifndef __s390x__
-#define THREAD_ORDER 1
-#define ASYNC_ORDER  1
-#else /* __s390x__ */
-#define THREAD_ORDER 2
-#define ASYNC_ORDER  2
-#endif /* __s390x__ */
-
-#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
-#define ASYNC_SIZE  (PAGE_SIZE << ASYNC_ORDER)
 
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic