entry.S 33.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3
/*
 *    S390 low-level entry points.
 *
4
 *    Copyright IBM Corp. 1999, 2012
Linus Torvalds's avatar
Linus Torvalds committed
5
 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
Heiko Carstens's avatar
Heiko Carstens committed
6 7
 *		 Hartmut Penner (hp@de.ibm.com),
 *		 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
8
 *		 Heiko Carstens <heiko.carstens@de.ibm.com>
Linus Torvalds's avatar
Linus Torvalds committed
9 10
 */

11
#include <linux/init.h>
12
#include <linux/linkage.h>
13
#include <asm/processor.h>
Linus Torvalds's avatar
Linus Torvalds committed
14 15 16 17
#include <asm/cache.h>
#include <asm/errno.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
18
#include <asm/asm-offsets.h>
Linus Torvalds's avatar
Linus Torvalds committed
19 20
#include <asm/unistd.h>
#include <asm/page.h>
21
#include <asm/sigp.h>
22
#include <asm/irq.h>
23
#include <asm/vx-insn.h>
24 25
#include <asm/setup.h>
#include <asm/nmi.h>
Linus Torvalds's avatar
Linus Torvalds committed
26

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
__PT_R0      =	__PT_GPRS
__PT_R1      =	__PT_GPRS + 8
__PT_R2      =	__PT_GPRS + 16
__PT_R3      =	__PT_GPRS + 24
__PT_R4      =	__PT_GPRS + 32
__PT_R5      =	__PT_GPRS + 40
__PT_R6      =	__PT_GPRS + 48
__PT_R7      =	__PT_GPRS + 56
__PT_R8      =	__PT_GPRS + 64
__PT_R9      =	__PT_GPRS + 72
__PT_R10     =	__PT_GPRS + 80
__PT_R11     =	__PT_GPRS + 88
__PT_R12     =	__PT_GPRS + 96
__PT_R13     =	__PT_GPRS + 104
__PT_R14     =	__PT_GPRS + 112
__PT_R15     =	__PT_GPRS + 120
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45

STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE  = 1 << STACK_SHIFT
46
STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
Linus Torvalds's avatar
Linus Torvalds committed
47

48 49
_TIF_WORK	= (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
		   _TIF_UPROBE)
50 51
_TIF_TRACE	= (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
		   _TIF_SYSCALL_TRACEPOINT)
52
_CIF_WORK	= (_CIF_MCCK_PENDING | _CIF_ASCE | _CIF_FPU)
53
_PIF_WORK	= (_PIF_PER_TRAP)
Linus Torvalds's avatar
Linus Torvalds committed
54

55
#define BASED(name) name-cleanup_critical(%r13)
Linus Torvalds's avatar
Linus Torvalds committed
56

57
	.macro	TRACE_IRQS_ON
58
#ifdef CONFIG_TRACE_IRQFLAGS
59 60
	basr	%r2,%r0
	brasl	%r14,trace_hardirqs_on_caller
61
#endif
62 63 64
	.endm

	.macro	TRACE_IRQS_OFF
65
#ifdef CONFIG_TRACE_IRQFLAGS
66 67
	basr	%r2,%r0
	brasl	%r14,trace_hardirqs_off_caller
68
#endif
69
	.endm
70 71

	.macro	LOCKDEP_SYS_EXIT
72 73 74
#ifdef CONFIG_LOCKDEP
	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
	jz	.+10
75
	brasl	%r14,lockdep_sys_exit
76
#endif
Linus Torvalds's avatar
Linus Torvalds committed
77 78
	.endm

79
	.macro	CHECK_STACK stacksize,savearea
80
#ifdef CONFIG_CHECK_STACK
81 82 83
	tml	%r15,\stacksize - CONFIG_STACK_GUARD
	lghi	%r14,\savearea
	jz	stack_overflow
84 85 86
#endif
	.endm

87
	.macro	SWITCH_ASYNC savearea,timer
88 89 90 91 92
	tmhh	%r8,0x0001		# interrupting from user ?
	jnz	1f
	lgr	%r14,%r9
	slg	%r14,BASED(.Lcritical_start)
	clg	%r14,BASED(.Lcritical_length)
Linus Torvalds's avatar
Linus Torvalds committed
93
	jhe	0f
94
	lghi	%r11,\savearea		# inside critical section, do cleanup
Linus Torvalds's avatar
Linus Torvalds committed
95
	brasl	%r14,cleanup_critical
96
	tmhh	%r8,0x0001		# retest problem state after cleanup
Linus Torvalds's avatar
Linus Torvalds committed
97
	jnz	1f
98
0:	lg	%r14,__LC_ASYNC_STACK	# are we already on the async stack?
Linus Torvalds's avatar
Linus Torvalds committed
99
	slgr	%r14,%r15
100
	srag	%r14,%r14,STACK_SHIFT
101
	jnz	2f
102
	CHECK_STACK 1<<STACK_SHIFT,\savearea
103
	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
104 105 106
	j	3f
1:	LAST_BREAK %r14
	UPDATE_VTIME %r14,%r15,\timer
107
2:	lg	%r15,__LC_ASYNC_STACK	# load async stack
108
3:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
Heiko Carstens's avatar
Heiko Carstens committed
109
	.endm
Linus Torvalds's avatar
Linus Torvalds committed
110

111 112 113 114 115 116 117 118 119
	.macro UPDATE_VTIME w1,w2,enter_timer
	lg	\w1,__LC_EXIT_TIMER
	lg	\w2,__LC_LAST_UPDATE_TIMER
	slg	\w1,\enter_timer
	slg	\w2,__LC_EXIT_TIMER
	alg	\w1,__LC_USER_TIMER
	alg	\w2,__LC_SYSTEM_TIMER
	stg	\w1,__LC_USER_TIMER
	stg	\w2,__LC_SYSTEM_TIMER
120
	mvc	__LC_LAST_UPDATE_TIMER(8),\enter_timer
Linus Torvalds's avatar
Linus Torvalds committed
121 122
	.endm

123 124 125 126
	.macro	LAST_BREAK scratch
	srag	\scratch,%r10,23
	jz	.+10
	stg	%r10,__TI_last_break(%r12)
127 128
	.endm

129
	.macro REENABLE_IRQS
130 131 132
	stg	%r8,__LC_RETURN_PSW
	ni	__LC_RETURN_PSW,0xbf
	ssm	__LC_RETURN_PSW
133 134
	.endm

135
	.macro STCK savearea
136
#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES
137 138 139 140 141 142
	.insn	s,0xb27c0000,\savearea		# store clock fast
#else
	.insn	s,0xb2050000,\savearea		# store clock
#endif
	.endm

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	/*
	 * The TSTMSK macro generates a test-under-mask instruction by
	 * calculating the memory offset for the specified mask value.
	 * Mask value can be any constant.  The macro shifts the mask
	 * value to calculate the memory offset for the test-under-mask
	 * instruction.
	 */
	.macro TSTMSK addr, mask, size=8, bytepos=0
		.if (\bytepos < \size) && (\mask >> 8)
			.if (\mask & 0xff)
				.error "Mask exceeds byte boundary"
			.endif
			TSTMSK \addr, "(\mask >> 8)", \size, "(\bytepos + 1)"
			.exitm
		.endif
		.ifeq \mask
			.error "Mask must not be zero"
		.endif
		off = \size - \bytepos - 1
		tm	off+\addr, \mask
	.endm

165 166
	.section .kprobes.text, "ax"

Linus Torvalds's avatar
Linus Torvalds committed
167 168 169 170 171 172 173
/*
 * Scheduler resume function, called by switch_to
 *  gpr2 = (task_struct *) prev
 *  gpr3 = (task_struct *) next
 * Returns:
 *  gpr2 = prev
 */
174
ENTRY(__switch_to)
175
	stmg	%r6,%r15,__SF_GPRS(%r15)	# store gprs of prev task
176 177 178 179 180 181 182
	lgr	%r1,%r2
	aghi	%r1,__TASK_thread		# thread_struct of prev task
	lg	%r4,__TASK_thread_info(%r2)	# get thread_info of prev
	lg	%r5,__TASK_thread_info(%r3)	# get thread_info of next
	stg	%r15,__THREAD_ksp(%r1)		# store kernel stack of prev
	lgr	%r1,%r3
	aghi	%r1,__TASK_thread		# thread_struct of next task
183
	lgr	%r15,%r5
184
	aghi	%r15,STACK_INIT			# end of kernel stack of next
185 186 187
	stg	%r3,__LC_CURRENT		# store task struct of next
	stg	%r5,__LC_THREAD_INFO		# store thread info of next
	stg	%r15,__LC_KERNEL_STACK		# store end of kernel stack
188
	lg	%r15,__THREAD_ksp(%r1)		# load kernel stack of next
189
	lctl	%c4,%c4,__TASK_pid(%r3)		# load pid to control reg. 4
190
	mvc	__LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
191
	lmg	%r6,%r15,__SF_GPRS(%r15)	# load gprs of next task
192 193 194
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
	bzr	%r14
	.insn	s,0xb2800000,__LC_LPP		# set program parameter
Linus Torvalds's avatar
Linus Torvalds committed
195 196
	br	%r14

197
.L__critical_start:
198 199 200 201 202 203 204 205 206 207 208

#if IS_ENABLED(CONFIG_KVM)
/*
 * sie64a calling convention:
 * %r2 pointer to sie control block
 * %r3 guest register save area
 */
ENTRY(sie64a)
	stmg	%r6,%r14,__SF_GPRS(%r15)	# save kernel registers
	stg	%r2,__SF_EMPTY(%r15)		# save control block pointer
	stg	%r3,__SF_EMPTY+8(%r15)		# save guest register save area
209
	xc	__SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0
210
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU		# load guest fp/vx registers ?
211 212 213 214 215 216 217 218 219 220 221 222 223
	jno	.Lsie_load_guest_gprs
	brasl	%r14,load_fpu_regs		# load guest fp/vx regs
.Lsie_load_guest_gprs:
	lmg	%r0,%r13,0(%r3)			# load guest gprs 0-13
	lg	%r14,__LC_GMAP			# get gmap pointer
	ltgr	%r14,%r14
	jz	.Lsie_gmap
	lctlg	%c1,%c1,__GMAP_ASCE(%r14)	# load primary asce
.Lsie_gmap:
	lg	%r14,__SF_EMPTY(%r15)		# get control block pointer
	oi	__SIE_PROG0C+3(%r14),1		# we are going into SIE now
	tm	__SIE_PROG20+3(%r14),3		# last exit...
	jnz	.Lsie_skip
224
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
225 226 227 228 229 230 231
	jo	.Lsie_skip			# exit if fp/vx regs changed
	sie	0(%r14)
.Lsie_skip:
	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
.Lsie_done:
# some program checks are suppressing. C code (e.g. do_protection_exception)
232 233 234 235
# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
# Other instructions between sie64a and .Lsie_done should not cause program
# interrupts. So lets use 3 nops as a landing pad for all possible rewinds.
236
# See also .Lcleanup_sie
237 238 239 240 241 242
.Lrewind_pad6:
	nopr	7
.Lrewind_pad4:
	nopr	7
.Lrewind_pad2:
	nopr	7
243 244 245 246 247
	.globl sie_exit
sie_exit:
	lg	%r14,__SF_EMPTY+8(%r15)		# load guest register save area
	stmg	%r0,%r13,0(%r14)		# save guest gprs 0-13
	lmg	%r6,%r14,__SF_GPRS(%r15)	# restore kernel registers
248
	lg	%r2,__SF_EMPTY+16(%r15)		# return exit reason code
249 250 251
	br	%r14
.Lsie_fault:
	lghi	%r14,-EFAULT
252
	stg	%r14,__SF_EMPTY+16(%r15)	# set exit reason code
253 254
	j	sie_exit

255 256 257
	EX_TABLE(.Lrewind_pad6,.Lsie_fault)
	EX_TABLE(.Lrewind_pad4,.Lsie_fault)
	EX_TABLE(.Lrewind_pad2,.Lsie_fault)
258 259 260
	EX_TABLE(sie_exit,.Lsie_fault)
#endif

Linus Torvalds's avatar
Linus Torvalds committed
261 262 263 264 265
/*
 * SVC interrupt handler routine. System calls are synchronous events and
 * are executed with interrupts enabled.
 */

266
ENTRY(system_call)
267
	stpt	__LC_SYNC_ENTER_TIMER
268
.Lsysc_stmg:
269 270 271
	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
	lg	%r10,__LC_LAST_BREAK
	lg	%r12,__LC_THREAD_INFO
272
	lghi	%r14,_PIF_SYSCALL
273
.Lsysc_per:
274 275 276
	lg	%r15,__LC_KERNEL_STACK
	la	%r11,STACK_FRAME_OVERHEAD(%r15)	# pointer to pt_regs
	LAST_BREAK %r13
277 278
.Lsysc_vtime:
	UPDATE_VTIME %r10,%r13,__LC_SYNC_ENTER_TIMER
279 280 281
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
	mvc	__PT_PSW(16,%r11),__LC_SVC_OLD_PSW
282
	mvc	__PT_INT_CODE(4,%r11),__LC_SVC_ILC
283
	stg	%r14,__PT_FLAGS(%r11)
284
.Lsysc_do_svc:
285
	lg	%r10,__TI_sysc_table(%r12)	# address of system call table
286
	llgh	%r8,__PT_INT_CODE+2(%r11)
287
	slag	%r8,%r8,2			# shift and test for svc 0
288
	jnz	.Lsysc_nr_ok
Linus Torvalds's avatar
Linus Torvalds committed
289
	# svc 0: system call number in %r1
290
	llgfr	%r1,%r1				# clear high word in r1
291
	cghi	%r1,NR_syscalls
292
	jnl	.Lsysc_nr_ok
293
	sth	%r1,__PT_INT_CODE+2(%r11)
294
	slag	%r8,%r1,2
295
.Lsysc_nr_ok:
296 297 298 299
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	stg	%r2,__PT_ORIG_GPR2(%r11)
	stg	%r7,STACK_FRAME_OVERHEAD(%r15)
	lgf	%r9,0(%r8,%r10)			# get system call add.
300
	TSTMSK	__TI_flags(%r12),_TIF_TRACE
301
	jnz	.Lsysc_tracesys
302 303
	basr	%r14,%r9			# call sys_xxxx
	stg	%r2,__PT_R2(%r11)		# store return value
Linus Torvalds's avatar
Linus Torvalds committed
304

305
.Lsysc_return:
306
	LOCKDEP_SYS_EXIT
307
.Lsysc_tif:
308
	TSTMSK	__PT_FLAGS(%r11),_PIF_WORK
309
	jnz	.Lsysc_work
310
	TSTMSK	__TI_flags(%r12),_TIF_WORK
311
	jnz	.Lsysc_work			# check for work
312
	TSTMSK	__LC_CPU_FLAGS,_CIF_WORK
313 314
	jnz	.Lsysc_work
.Lsysc_restore:
315 316 317
	lg	%r14,__LC_VDSO_PER_CPU
	lmg	%r0,%r10,__PT_R0(%r11)
	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
318
.Lsysc_exit_timer:
319 320 321 322
	stpt	__LC_EXIT_TIMER
	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
	lmg	%r11,%r15,__PT_R11(%r11)
	lpswe	__LC_RETURN_PSW
323
.Lsysc_done:
324

325 326 327
#
# One of the work bits is on. Find out which one.
#
328
.Lsysc_work:
329
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
330
	jo	.Lsysc_mcck_pending
331
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
332
	jo	.Lsysc_reschedule
333
#ifdef CONFIG_UPROBES
334
	TSTMSK	__TI_flags(%r12),_TIF_UPROBE
335
	jo	.Lsysc_uprobe_notify
336
#endif
337
	TSTMSK	__PT_FLAGS(%r11),_PIF_PER_TRAP
338
	jo	.Lsysc_singlestep
339
	TSTMSK	__TI_flags(%r12),_TIF_SIGPENDING
340
	jo	.Lsysc_sigpending
341
	TSTMSK	__TI_flags(%r12),_TIF_NOTIFY_RESUME
342
	jo	.Lsysc_notify_resume
343
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
344
	jo	.Lsysc_vxrs
345
	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE
346 347
	jo	.Lsysc_uaccess
	j	.Lsysc_return		# beware of critical section cleanup
Linus Torvalds's avatar
Linus Torvalds committed
348 349 350

#
# _TIF_NEED_RESCHED is set, call schedule
Heiko Carstens's avatar
Heiko Carstens committed
351
#
352 353
.Lsysc_reschedule:
	larl	%r14,.Lsysc_return
354
	jg	schedule
Linus Torvalds's avatar
Linus Torvalds committed
355

356
#
357
# _CIF_MCCK_PENDING is set, call handler
358
#
359 360
.Lsysc_mcck_pending:
	larl	%r14,.Lsysc_return
Heiko Carstens's avatar
Heiko Carstens committed
361
	jg	s390_handle_mcck	# TIF bit will be cleared by handler
362

363
#
364
# _CIF_ASCE is set, load user space asce
365
#
366
.Lsysc_uaccess:
367
	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE
368
	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
369
	j	.Lsysc_return
370

371 372 373 374 375 376 377
#
# CIF_FPU is set, restore floating-point controls and floating-point registers.
#
.Lsysc_vxrs:
	larl	%r14,.Lsysc_return
	jg	load_fpu_regs

Linus Torvalds's avatar
Linus Torvalds committed
378
#
379
# _TIF_SIGPENDING is set, call do_signal
Linus Torvalds's avatar
Linus Torvalds committed
380
#
381
.Lsysc_sigpending:
382 383
	lgr	%r2,%r11		# pass pointer to pt_regs
	brasl	%r14,do_signal
384
	TSTMSK	__PT_FLAGS(%r11),_PIF_SYSCALL
385
	jno	.Lsysc_return
386
	lmg	%r2,%r7,__PT_R2(%r11)	# load svc arguments
387
	lg	%r10,__TI_sysc_table(%r12)	# address of system call table
388
	lghi	%r8,0			# svc 0 returns -ENOSYS
389
	llgh	%r1,__PT_INT_CODE+2(%r11)	# load new svc number
390
	cghi	%r1,NR_syscalls
391
	jnl	.Lsysc_nr_ok		# invalid svc number -> do svc 0
392
	slag	%r8,%r1,2
393
	j	.Lsysc_nr_ok		# restart svc
Linus Torvalds's avatar
Linus Torvalds committed
394

Martin Schwidefsky's avatar
Martin Schwidefsky committed
395 396 397
#
# _TIF_NOTIFY_RESUME is set, call do_notify_resume
#
398
.Lsysc_notify_resume:
399
	lgr	%r2,%r11		# pass pointer to pt_regs
400
	larl	%r14,.Lsysc_return
401
	jg	do_notify_resume
Martin Schwidefsky's avatar
Martin Schwidefsky committed
402

403 404 405 406
#
# _TIF_UPROBE is set, call uprobe_notify_resume
#
#ifdef CONFIG_UPROBES
407
.Lsysc_uprobe_notify:
408
	lgr	%r2,%r11		# pass pointer to pt_regs
409
	larl	%r14,.Lsysc_return
410 411 412
	jg	uprobe_notify_resume
#endif

Linus Torvalds's avatar
Linus Torvalds committed
413
#
414
# _PIF_PER_TRAP is set, call do_per_trap
Linus Torvalds's avatar
Linus Torvalds committed
415
#
416
.Lsysc_singlestep:
417
	ni	__PT_FLAGS+7(%r11),255-_PIF_PER_TRAP
418
	lgr	%r2,%r11		# pass pointer to pt_regs
419
	larl	%r14,.Lsysc_return
Martin Schwidefsky's avatar
Martin Schwidefsky committed
420
	jg	do_per_trap
Linus Torvalds's avatar
Linus Torvalds committed
421 422

#
Martin Schwidefsky's avatar
Martin Schwidefsky committed
423 424
# call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
# and after the system call
Linus Torvalds's avatar
Linus Torvalds committed
425
#
426
.Lsysc_tracesys:
427
	lgr	%r2,%r11		# pass pointer to pt_regs
Linus Torvalds's avatar
Linus Torvalds committed
428
	la	%r3,0
429
	llgh	%r0,__PT_INT_CODE+2(%r11)
430
	stg	%r0,__PT_R2(%r11)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
431
	brasl	%r14,do_syscall_trace_enter
Linus Torvalds's avatar
Linus Torvalds committed
432
	lghi	%r0,NR_syscalls
Martin Schwidefsky's avatar
Martin Schwidefsky committed
433
	clgr	%r0,%r2
434
	jnh	.Lsysc_tracenogo
435 436
	sllg	%r8,%r2,2
	lgf	%r9,0(%r8,%r10)
437
.Lsysc_tracego:
438 439 440 441 442
	lmg	%r3,%r7,__PT_R3(%r11)
	stg	%r7,STACK_FRAME_OVERHEAD(%r15)
	lg	%r2,__PT_ORIG_GPR2(%r11)
	basr	%r14,%r9		# call sys_xxx
	stg	%r2,__PT_R2(%r11)	# store return value
443
.Lsysc_tracenogo:
444
	TSTMSK	__TI_flags(%r12),_TIF_TRACE
445
	jz	.Lsysc_return
446
	lgr	%r2,%r11		# pass pointer to pt_regs
447
	larl	%r14,.Lsysc_return
Martin Schwidefsky's avatar
Martin Schwidefsky committed
448
	jg	do_syscall_trace_exit
Linus Torvalds's avatar
Linus Torvalds committed
449 450 451 452

#
# a new process exits the kernel with ret_from_fork
#
453
ENTRY(ret_from_fork)
454 455
	la	%r11,STACK_FRAME_OVERHEAD(%r15)
	lg	%r12,__LC_THREAD_INFO
456 457 458
	brasl	%r14,schedule_tail
	TRACE_IRQS_ON
	ssm	__LC_SVC_NEW_PSW	# reenable interrupts
459
	tm	__PT_PSW+1(%r11),0x01	# forking a kernel thread ?
460
	jne	.Lsysc_tracenogo
461 462
	# it's a kernel thread
	lmg	%r9,%r10,__PT_R9(%r11)	# load gprs
463 464 465
ENTRY(kernel_thread_starter)
	la	%r2,0(%r10)
	basr	%r14,%r9
466
	j	.Lsysc_tracenogo
Linus Torvalds's avatar
Linus Torvalds committed
467 468 469 470 471

/*
 * Program check handler routine
 */

472
ENTRY(pgm_check_handler)
473
	stpt	__LC_SYNC_ENTER_TIMER
474 475 476
	stmg	%r8,%r15,__LC_SAVE_AREA_SYNC
	lg	%r10,__LC_LAST_BREAK
	lg	%r12,__LC_THREAD_INFO
477
	larl	%r13,cleanup_critical
478 479
	lmg	%r8,%r9,__LC_PGM_OLD_PSW
	tmhh	%r8,0x0001		# test problem state bit
480 481 482 483 484 485 486 487 488 489 490
	jnz	2f			# -> fault in user space
#if IS_ENABLED(CONFIG_KVM)
	# cleanup critical section for sie64a
	lgr	%r14,%r9
	slg	%r14,BASED(.Lsie_critical_start)
	clg	%r14,BASED(.Lsie_critical_length)
	jhe	0f
	brasl	%r14,.Lcleanup_sie
#endif
0:	tmhh	%r8,0x4000		# PER bit set in old PSW ?
	jnz	1f			# -> enabled, can't be a double fault
491
	tm	__LC_PGM_ILC+3,0x80	# check for per exception
492
	jnz	.Lpgm_svcper		# -> single stepped svc
493
1:	CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
494
	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
495
	j	3f
496 497
2:	LAST_BREAK %r14
	UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
498
	lg	%r15,__LC_KERNEL_STACK
499
	lg	%r14,__TI_task(%r12)
500
	aghi	%r14,__TASK_thread	# pointer to thread_struct
501 502
	lghi	%r13,__LC_PGM_TDB
	tm	__LC_PGM_ILC+2,0x02	# check for transaction abort
503
	jz	3f
504
	mvc	__THREAD_trap_tdb(256,%r14),0(%r13)
505
3:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
506 507 508
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
	stmg	%r8,%r9,__PT_PSW(%r11)
509 510
	mvc	__PT_INT_CODE(4,%r11),__LC_PGM_ILC
	mvc	__PT_INT_PARM_LONG(8,%r11),__LC_TRANS_EXC_CODE
511
	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
512 513
	stg	%r10,__PT_ARGS(%r11)
	tm	__LC_PGM_ILC+3,0x80	# check for per exception
514
	jz	4f
515
	tmhh	%r8,0x0001		# kernel per event ?
516
	jz	.Lpgm_kprobe
517
	oi	__PT_FLAGS+7(%r11),_PIF_PER_TRAP
518
	mvc	__THREAD_per_address(8,%r14),__LC_PER_ADDRESS
519 520
	mvc	__THREAD_per_cause(2,%r14),__LC_PER_CODE
	mvc	__THREAD_per_paid(1,%r14),__LC_PER_ACCESS_ID
521
4:	REENABLE_IRQS
522
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
523
	larl	%r1,pgm_check_table
524 525
	llgh	%r10,__PT_INT_CODE+2(%r11)
	nill	%r10,0x007f
526
	sll	%r10,2
527
	je	.Lpgm_return
528
	lgf	%r1,0(%r10,%r1)		# load address of handler routine
529
	lgr	%r2,%r11		# pass pointer to pt_regs
530
	basr	%r14,%r1		# branch to interrupt-handler
531 532 533 534 535
.Lpgm_return:
	LOCKDEP_SYS_EXIT
	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
	jno	.Lsysc_restore
	j	.Lsysc_tif
Linus Torvalds's avatar
Linus Torvalds committed
536 537

#
538
# PER event in supervisor state, must be kprobes
Linus Torvalds's avatar
Linus Torvalds committed
539
#
540
.Lpgm_kprobe:
541 542 543 544
	REENABLE_IRQS
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	lgr	%r2,%r11		# pass pointer to pt_regs
	brasl	%r14,do_per_trap
545
	j	.Lpgm_return
Linus Torvalds's avatar
Linus Torvalds committed
546

Michael Grundy's avatar
Michael Grundy committed
547
#
548
# single stepped system call
Michael Grundy's avatar
Michael Grundy committed
549
#
550
.Lpgm_svcper:
551
	mvc	__LC_RETURN_PSW(8),__LC_SVC_NEW_PSW
552
	larl	%r14,.Lsysc_per
553
	stg	%r14,__LC_RETURN_PSW+8
554
	lghi	%r14,_PIF_SYSCALL | _PIF_PER_TRAP
555
	lpswe	__LC_RETURN_PSW		# branch to .Lsysc_per and enable irqs
Michael Grundy's avatar
Michael Grundy committed
556

Linus Torvalds's avatar
Linus Torvalds committed
557 558 559
/*
 * IO interrupt handler routine
 */
560
ENTRY(io_int_handler)
561
	STCK	__LC_INT_CLOCK
562
	stpt	__LC_ASYNC_ENTER_TIMER
563 564 565
	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
	lg	%r10,__LC_LAST_BREAK
	lg	%r12,__LC_THREAD_INFO
566
	larl	%r13,cleanup_critical
567
	lmg	%r8,%r9,__LC_IO_OLD_PSW
568
	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
569 570 571
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
	stmg	%r8,%r9,__PT_PSW(%r11)
572
	mvc	__PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
573
	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
574 575
	TSTMSK	__LC_CPU_FLAGS,_CIF_IGNORE_IRQ
	jo	.Lio_restore
576
	TRACE_IRQS_OFF
577
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
578
.Lio_loop:
579
	lgr	%r2,%r11		# pass pointer to pt_regs
580 581
	lghi	%r3,IO_INTERRUPT
	tm	__PT_INT_CODE+8(%r11),0x80	# adapter interrupt ?
582
	jz	.Lio_call
583
	lghi	%r3,THIN_INTERRUPT
584
.Lio_call:
585
	brasl	%r14,do_IRQ
586
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPAR
587
	jz	.Lio_return
588
	tpi	0
589
	jz	.Lio_return
590
	mvc	__PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
591 592
	j	.Lio_loop
.Lio_return:
593 594
	LOCKDEP_SYS_EXIT
	TRACE_IRQS_ON
595
.Lio_tif:
596
	TSTMSK	__TI_flags(%r12),_TIF_WORK
597
	jnz	.Lio_work		# there is work to do (signals etc.)
598
	TSTMSK	__LC_CPU_FLAGS,_CIF_WORK
599 600
	jnz	.Lio_work
.Lio_restore:
601 602 603
	lg	%r14,__LC_VDSO_PER_CPU
	lmg	%r0,%r10,__PT_R0(%r11)
	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r11)
604
.Lio_exit_timer:
605 606 607 608
	stpt	__LC_EXIT_TIMER
	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
	lmg	%r11,%r15,__PT_R11(%r11)
	lpswe	__LC_RETURN_PSW
609
.Lio_done:
Linus Torvalds's avatar
Linus Torvalds committed
610

611
#
612
# There is work todo, find out in which context we have been interrupted:
613
# 1) if we return to user space we can do all _TIF_WORK work
614 615 616 617 618
# 2) if we return to kernel code and kvm is enabled check if we need to
#    modify the psw to leave SIE
# 3) if we return to kernel code and preemptive scheduling is enabled check
#    the preemption counter and if it is zero call preempt_schedule_irq
# Before any work can be done, a switch to the kernel stack is required.
619
#
620
.Lio_work:
621
	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
622
	jo	.Lio_work_user		# yes -> do resched & signal
623
#ifdef CONFIG_PREEMPT
624
	# check for preemptive scheduling
625
	icm	%r0,15,__TI_precount(%r12)
626
	jnz	.Lio_restore		# preemption is disabled
627
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
628
	jno	.Lio_restore
Linus Torvalds's avatar
Linus Torvalds committed
629
	# switch to kernel stack
630 631 632 633 634
	lg	%r1,__PT_R15(%r11)
	aghi	%r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
	mvc	STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
	xc	__SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
	la	%r11,STACK_FRAME_OVERHEAD(%r1)
Linus Torvalds's avatar
Linus Torvalds committed
635
	lgr	%r15,%r1
636
	# TRACE_IRQS_ON already done at .Lio_return, call
637 638 639
	# TRACE_IRQS_OFF to keep things symmetrical
	TRACE_IRQS_OFF
	brasl	%r14,preempt_schedule_irq
640
	j	.Lio_return
641
#else
642
	j	.Lio_restore
643
#endif
Linus Torvalds's avatar
Linus Torvalds committed
644

645 646 647
#
# Need to do work before returning to userspace, switch to kernel stack
#
648
.Lio_work_user:
Linus Torvalds's avatar
Linus Torvalds committed
649
	lg	%r1,__LC_KERNEL_STACK
650 651 652
	mvc	STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
	xc	__SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
	la	%r11,STACK_FRAME_OVERHEAD(%r1)
Linus Torvalds's avatar
Linus Torvalds committed
653
	lgr	%r15,%r1
654

Linus Torvalds's avatar
Linus Torvalds committed
655 656 657
#
# One of the work bits is on. Find out which one.
#
658
.Lio_work_tif:
659
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
660
	jo	.Lio_mcck_pending
661
	TSTMSK	__TI_flags(%r12),_TIF_NEED_RESCHED
662
	jo	.Lio_reschedule
663
	TSTMSK	__TI_flags(%r12),_TIF_SIGPENDING
664
	jo	.Lio_sigpending
665
	TSTMSK	__TI_flags(%r12),_TIF_NOTIFY_RESUME
666
	jo	.Lio_notify_resume
667
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
668
	jo	.Lio_vxrs
669
	TSTMSK	__LC_CPU_FLAGS,_CIF_ASCE
670 671
	jo	.Lio_uaccess
	j	.Lio_return		# beware of critical section cleanup
672

673
#
674
# _CIF_MCCK_PENDING is set, call handler
675
#
676 677
.Lio_mcck_pending:
	# TRACE_IRQS_ON already done at .Lio_return
Heiko Carstens's avatar
Heiko Carstens committed
678
	brasl	%r14,s390_handle_mcck	# TIF bit will be cleared by handler
679
	TRACE_IRQS_OFF
680
	j	.Lio_return
681

682
#
683
# _CIF_ASCE is set, load user space asce
684
#
685
.Lio_uaccess:
686
	ni	__LC_CPU_FLAGS+7,255-_CIF_ASCE
687
	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
688
	j	.Lio_return
689

690 691 692 693 694 695 696
#
# CIF_FPU is set, restore floating-point controls and floating-point registers.
#
.Lio_vxrs:
	larl	%r14,.Lio_return
	jg	load_fpu_regs

Linus Torvalds's avatar
Linus Torvalds committed
697 698
#
# _TIF_NEED_RESCHED is set, call schedule
Heiko Carstens's avatar
Heiko Carstens committed
699
#
700 701
.Lio_reschedule:
	# TRACE_IRQS_ON already done at .Lio_return
702
	ssm	__LC_SVC_NEW_PSW	# reenable interrupts
Heiko Carstens's avatar
Heiko Carstens committed
703
	brasl	%r14,schedule		# call scheduler
704
	ssm	__LC_PGM_NEW_PSW	# disable I/O and ext. interrupts
705
	TRACE_IRQS_OFF
706
	j	.Lio_return
Linus Torvalds's avatar
Linus Torvalds committed
707 708

#
709
# _TIF_SIGPENDING or is set, call do_signal
Linus Torvalds's avatar
Linus Torvalds committed
710
#
711 712
.Lio_sigpending:
	# TRACE_IRQS_ON already done at .Lio_return
713 714 715 716
	ssm	__LC_SVC_NEW_PSW	# reenable interrupts
	lgr	%r2,%r11		# pass pointer to pt_regs
	brasl	%r14,do_signal
	ssm	__LC_PGM_NEW_PSW	# disable I/O and ext. interrupts
717
	TRACE_IRQS_OFF
718
	j	.Lio_return
Linus Torvalds's avatar
Linus Torvalds committed
719

Martin Schwidefsky's avatar
Martin Schwidefsky committed
720 721 722
#
# _TIF_NOTIFY_RESUME or is set, call do_notify_resume
#
723 724
.Lio_notify_resume:
	# TRACE_IRQS_ON already done at .Lio_return
725 726 727 728
	ssm	__LC_SVC_NEW_PSW	# reenable interrupts
	lgr	%r2,%r11		# pass pointer to pt_regs
	brasl	%r14,do_notify_resume
	ssm	__LC_PGM_NEW_PSW	# disable I/O and ext. interrupts
Martin Schwidefsky's avatar
Martin Schwidefsky committed
729
	TRACE_IRQS_OFF
730
	j	.Lio_return
Martin Schwidefsky's avatar
Martin Schwidefsky committed
731

Linus Torvalds's avatar
Linus Torvalds committed
732 733 734
/*
 * External interrupt handler routine
 */
735
ENTRY(ext_int_handler)
736
	STCK	__LC_INT_CLOCK
737
	stpt	__LC_ASYNC_ENTER_TIMER
738 739 740
	stmg	%r8,%r15,__LC_SAVE_AREA_ASYNC
	lg	%r10,__LC_LAST_BREAK
	lg	%r12,__LC_THREAD_INFO
741
	larl	%r13,cleanup_critical
742
	lmg	%r8,%r9,__LC_EXT_OLD_PSW
743
	SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER
744 745 746
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
	stmg	%r8,%r9,__PT_PSW(%r11)
747 748 749 750
	lghi	%r1,__LC_EXT_PARAMS2
	mvc	__PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
	mvc	__PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
	mvc	__PT_INT_PARM_LONG(8,%r11),0(%r1)
751
	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
752 753
	TSTMSK	__LC_CPU_FLAGS,_CIF_IGNORE_IRQ
	jo	.Lio_restore
754
	TRACE_IRQS_OFF
755
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
756
	lgr	%r2,%r11		# pass pointer to pt_regs
757 758
	lghi	%r3,EXT_INTERRUPT
	brasl	%r14,do_IRQ
759
	j	.Lio_return
Linus Torvalds's avatar
Linus Torvalds committed
760

Martin Schwidefsky's avatar
Martin Schwidefsky committed
761
/*
762
 * Load idle PSW. The second "half" of this function is in .Lcleanup_idle.
Martin Schwidefsky's avatar
Martin Schwidefsky committed
763 764
 */
ENTRY(psw_idle)
765
	stg	%r3,__SF_EMPTY(%r15)
766
	larl	%r1,.Lpsw_idle_lpsw+4
Martin Schwidefsky's avatar
Martin Schwidefsky committed
767
	stg	%r1,__SF_EMPTY+8(%r15)
768 769 770 771 772 773 774 775
#ifdef CONFIG_SMP
	larl	%r1,smp_cpu_mtid
	llgf	%r1,0(%r1)
	ltgr	%r1,%r1
	jz	.Lpsw_idle_stcctm
	.insn	rsy,0xeb0000000017,%r1,5,__SF_EMPTY+16(%r15)
.Lpsw_idle_stcctm:
#endif
776 777
	STCK	__CLOCK_IDLE_ENTER(%r2)
	stpt	__TIMER_IDLE_ENTER(%r2)
778
.Lpsw_idle_lpsw:
Martin Schwidefsky's avatar
Martin Schwidefsky committed
779 780
	lpswe	__SF_EMPTY(%r15)
	br	%r14
781
.Lpsw_idle_end:
Martin Schwidefsky's avatar
Martin Schwidefsky committed
782

783 784 785 786 787 788
/*
 * Store floating-point controls and floating-point or vector register
 * depending whether the vector facility is available.	A critical section
 * cleanup assures that the registers are stored even if interrupted for
 * some other work.  The CIF_FPU flag is set to trigger a lazy restore
 * of the register contents at return from io or a system call.
789 790
 */
ENTRY(save_fpu_regs)
791 792
	lg	%r2,__LC_CURRENT
	aghi	%r2,__TASK_thread
793
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
794
	bor	%r14
795
	stfpc	__THREAD_FPU_fpc(%r2)
796
.Lsave_fpu_regs_fpc_end:
797
	lg	%r3,__THREAD_FPU_regs(%r2)
798
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
	jz	.Lsave_fpu_regs_fp	  # no -> store FP regs
.Lsave_fpu_regs_vx_low:
	VSTM	%v0,%v15,0,%r3		  # vstm 0,15,0(3)
.Lsave_fpu_regs_vx_high:
	VSTM	%v16,%v31,256,%r3	  # vstm 16,31,256(3)
	j	.Lsave_fpu_regs_done	  # -> set CIF_FPU flag
.Lsave_fpu_regs_fp:
	std	0,0(%r3)
	std	1,8(%r3)
	std	2,16(%r3)
	std	3,24(%r3)
	std	4,32(%r3)
	std	5,40(%r3)
	std	6,48(%r3)
	std	7,56(%r3)
	std	8,64(%r3)
	std	9,72(%r3)
	std	10,80(%r3)
	std	11,88(%r3)
	std	12,96(%r3)
	std	13,104(%r3)
	std	14,112(%r3)
	std	15,120(%r3)
.Lsave_fpu_regs_done:
	oi	__LC_CPU_FLAGS+7,_CIF_FPU
	br	%r14
.Lsave_fpu_regs_end:

827 828 829 830
/*
 * Load floating-point controls and floating-point or vector registers.
 * A critical section cleanup assures that the register contents are
 * loaded even if interrupted for some other work.
831 832 833 834
 *
 * There are special calling conventions to fit into sysc and io return work:
 *	%r15:	<kernel stack>
 * The function requires:
835
 *	%r4
836 837
 */
load_fpu_regs:
838 839
	lg	%r4,__LC_CURRENT
	aghi	%r4,__TASK_thread
840
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
841
	bnor	%r14
842
	lfpc	__THREAD_FPU_fpc(%r4)
843
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_VX
844
	lg	%r4,__THREAD_FPU_regs(%r4)	# %r4 <- reg save area
845
	jz	.Lload_fpu_regs_fp		# -> no VX, load FP regs
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
.Lload_fpu_regs_vx:
	VLM	%v0,%v15,0,%r4
.Lload_fpu_regs_vx_high:
	VLM	%v16,%v31,256,%r4
	j	.Lload_fpu_regs_done
.Lload_fpu_regs_fp:
	ld	0,0(%r4)
	ld	1,8(%r4)
	ld	2,16(%r4)
	ld	3,24(%r4)
	ld	4,32(%r4)
	ld	5,40(%r4)
	ld	6,48(%r4)
	ld	7,56(%r4)
	ld	8,64(%r4)
	ld	9,72(%r4)
	ld	10,80(%r4)
	ld	11,88(%r4)
	ld	12,96(%r4)
	ld	13,104(%r4)
	ld	14,112(%r4)
	ld	15,120(%r4)
.Lload_fpu_regs_done:
	ni	__LC_CPU_FLAGS+7,255-_CIF_FPU
	br	%r14
.Lload_fpu_regs_end:

873
.L__critical_end:
874

Linus Torvalds's avatar
Linus Torvalds committed
875 876 877
/*
 * Machine check handler routines
 */
878
ENTRY(mcck_int_handler)
879
	STCK	__LC_MCCK_CLOCK
880 881
	la	%r1,4095		# revalidate r1
	spt	__LC_CPU_TIMER_SAVE_AREA-4095(%r1)	# revalidate cpu timer
Heiko Carstens's avatar
Heiko Carstens committed
882
	lmg	%r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
883 884
	lg	%r10,__LC_LAST_BREAK
	lg	%r12,__LC_THREAD_INFO
885
	larl	%r13,cleanup_critical
886
	lmg	%r8,%r9,__LC_MCK_OLD_PSW
887
	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_SYSTEM_DAMAGE
888
	jo	.Lmcck_panic		# yes -> rest of mcck code invalid
889 890
	lghi	%r14,__LC_CPU_TIMER_SAVE_AREA
	mvc	__LC_MCCK_ENTER_TIMER(8),0(%r14)
891
	TSTMSK	__LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID
892
	jo	3f
893 894 895 896 897
	la	%r14,__LC_SYNC_ENTER_TIMER
	clc	0(8,%r14),__LC_ASYNC_ENTER_TIMER
	jl	0f
	la	%r14,__LC_ASYNC_ENTER_TIMER
0:	clc	0(8,%r14),__LC_EXIT_TIMER
898
	jl	1f
899
	la	%r14,__LC_EXIT_TIMER
900 901
1:	clc	0(8,%r14),__LC_LAST_UPDATE_TIMER
	jl	2f
902
	la	%r14,__LC_LAST_UPDATE_TIMER
903
2:	spt	0(%r14)
904
	mvc	__LC_MCCK_ENTER_TIMER(8),0(%r14)
905
3:	TSTMSK	__LC_MCCK_CODE,(MCCK_CODE_PSW_MWP_VALID|MCCK_CODE_PSW_IA_VALID)
906
	jno	.Lmcck_panic		# no -> skip cleanup critical
907
	SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_MCCK_ENTER_TIMER
908
.Lmcck_skip:
909 910 911
	lghi	%r14,__LC_GPREGS_SAVE_AREA+64
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),0(%r14)
912
	stmg	%r8,%r9,__PT_PSW(%r11)
913
	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
914 915
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	lgr	%r2,%r11		# pass pointer to pt_regs
916
	brasl	%r14,s390_do_machine_check
917
	tm	__PT_PSW+1(%r11),0x01	# returning to user ?
918
	jno	.Lmcck_return
919
	lg	%r1,__LC_KERNEL_STACK	# switch to kernel stack
920 921 922
	mvc	STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
	xc	__SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
	la	%r11,STACK_FRAME_OVERHEAD(%r1)
923
	lgr	%r15,%r1
924
	ssm	__LC_PGM_NEW_PSW	# turn dat on, keep irqs off
925
	TSTMSK	__LC_CPU_FLAGS,_CIF_MCCK_PENDING
926
	jno	.Lmcck_return
927
	TRACE_IRQS_OFF
928
	brasl	%r14,s390_handle_mcck
929
	TRACE_IRQS_ON
930
.Lmcck_return:
931 932 933
	lg	%r14,__LC_VDSO_PER_CPU
	lmg	%r0,%r10,__PT_R0(%r11)
	mvc	__LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW
934 935 936
	tm	__LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
	jno	0f
	stpt	__LC_EXIT_TIMER
937 938 939 940
	mvc	__VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER
0:	lmg	%r11,%r15,__PT_R11(%r11)
	lpswe	__LC_RETURN_MCCK_PSW

941
.Lmcck_panic:
942
	lg	%r15,__LC_PANIC_STACK
943
	aghi	%r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
944
	j	.Lmcck_skip
Linus Torvalds's avatar
Linus Torvalds committed
945

946 947 948
#
# PSW restart interrupt handler
#
Martin Schwidefsky's avatar
Martin Schwidefsky committed
949
ENTRY(restart_int_handler)
950 951 952 953
	TSTMSK	__LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
	jz	0f
	.insn	s,0xb2800000,__LC_LPP
0:	stg	%r15,__LC_SAVE_AREA_RESTART
Martin Schwidefsky's avatar
Martin Schwidefsky committed
954
	lg	%r15,__LC_RESTART_STACK
955
	aghi	%r15,-__PT_SIZE			# create pt_regs on stack
Martin Schwidefsky's avatar
Martin Schwidefsky committed
956
	xc	0(__PT_SIZE,%r15),0(%r15)
957 958 959
	stmg	%r0,%r14,__PT_R0(%r15)
	mvc	__PT_R15(8,%r15),__LC_SAVE_AREA_RESTART
	mvc	__PT_PSW(16,%r15),__LC_RST_OLD_PSW # store restart old psw
Martin Schwidefsky's avatar
Martin Schwidefsky committed
960 961
	aghi	%r15,-STACK_FRAME_OVERHEAD	# create stack frame on stack
	xc	0(STACK_FRAME_OVERHEAD,%r15),0(%r15)
962 963 964
	lg	%r1,__LC_RESTART_FN		# load fn, parm & source cpu
	lg	%r2,__LC_RESTART_DATA
	lg	%r3,__LC_RESTART_SOURCE
Martin Schwidefsky's avatar
Martin Schwidefsky committed
965 966
	ltgr	%r3,%r3				# test source cpu address
	jm	1f				# negative -> skip source stop
967
0:	sigp	%r4,%r3,SIGP_SENSE		# sigp sense to source cpu
Martin Schwidefsky's avatar
Martin Schwidefsky committed
968 969 970 971
	brc	10,0b				# wait for status stored
1:	basr	%r14,%r1			# call function
	stap	__SF_EMPTY(%r15)		# store cpu address
	llgh	%r3,__SF_EMPTY(%r15)
972
2:	sigp	%r4,%r3,SIGP_STOP		# sigp stop to current cpu
Martin Schwidefsky's avatar
Martin Schwidefsky committed
973 974
	brc	2,2b
3:	j	3b
975

976 977
	.section .kprobes.text, "ax"

Linus Torvalds's avatar
Linus Torvalds committed
978 979 980 981 982 983 984
#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:
985 986
	lg	%r15,__LC_PANIC_STACK	# change to panic stack
	la	%r11,STACK_FRAME_OVERHEAD(%r15)
987 988 989 990 991 992
	stmg	%r0,%r7,__PT_R0(%r11)
	stmg	%r8,%r9,__PT_PSW(%r11)
	mvc	__PT_R8(64,%r11),0(%r14)
	stg	%r10,__PT_ORIG_GPR2(%r11) # store last break to orig_gpr2
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	lgr	%r2,%r11		# pass pointer to pt_regs
Linus Torvalds's avatar
Linus Torvalds committed
993 994 995 996
	jg	kernel_stack_overflow
#endif

cleanup_critical:
997 998 999 1000 1001 1002
#if IS_ENABLED(CONFIG_KVM)
	clg	%r9,BASED(.Lcleanup_table_sie)	# .Lsie_gmap
	jl	0f
	clg	%r9,BASED(.Lcleanup_table_sie+8)# .Lsie_done
	jl	.Lcleanup_sie
#endif
1003
	clg	%r9,BASED(.Lcleanup_table)	# system_call
Linus Torvalds's avatar
Linus Torvalds committed
1004
	jl	0f
1005 1006 1007
	clg	%r9,BASED(.Lcleanup_table+8)	# .Lsysc_do_svc
	jl	.Lcleanup_system_call
	clg	%r9,BASED(.Lcleanup_table+16)	# .Lsysc_tif
Linus Torvalds's avatar
Linus Torvalds committed
1008
	jl	0f
1009 1010 1011 1012 1013
	clg	%r9,BASED(.Lcleanup_table+24)	# .Lsysc_restore
	jl	.Lcleanup_sysc_tif
	clg	%r9,BASED(.Lcleanup_table+32)	# .Lsysc_done
	jl	.Lcleanup_sysc_restore
	clg	%r9,BASED(.Lcleanup_table+40)	# .Lio_tif
1014
	jl	0f
1015 1016 1017 1018 1019
	clg	%r9,BASED(.Lcleanup_table+48)	# .Lio_restore
	jl	.Lcleanup_io_tif
	clg	%r9,BASED(.Lcleanup_table+56)	# .Lio_done
	jl	.Lcleanup_io_restore
	clg	%r9,BASED(.Lcleanup_table+64)	# psw_idle
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1020
	jl	0f
1021 1022
	clg	%r9,BASED(.Lcleanup_table+72)	# .Lpsw_idle_end
	jl	.Lcleanup_idle
1023 1024 1025 1026 1027 1028 1029 1030
	clg	%r9,BASED(.Lcleanup_table+80)	# save_fpu_regs
	jl	0f
	clg	%r9,BASED(.Lcleanup_table+88)	# .Lsave_fpu_regs_end
	jl	.Lcleanup_save_fpu_regs
	clg	%r9,BASED(.Lcleanup_table+96)	# load_fpu_regs
	jl	0f
	clg	%r9,BASED(.Lcleanup_table+104)	# .Lload_fpu_regs_end
	jl	.Lcleanup_load_fpu_regs
1031 1032
0:	br	%r14

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
	.align	8
.Lcleanup_table:
	.quad	system_call
	.quad	.Lsysc_do_svc
	.quad	.Lsysc_tif
	.quad	.Lsysc_restore
	.quad	.Lsysc_done
	.quad	.Lio_tif
	.quad	.Lio_restore
	.quad	.Lio_done
	.quad	psw_idle
	.quad	.Lpsw_idle_end
	.quad	save_fpu_regs
	.quad	.Lsave_fpu_regs_end
	.quad	load_fpu_regs
	.quad	.Lload_fpu_regs_end

#if IS_ENABLED(CONFIG_KVM)
.Lcleanup_table_sie:
	.quad	.Lsie_gmap
	.quad	.Lsie_done

.Lcleanup_sie:
	lg	%r9,__SF_EMPTY(%r15)		# get control block pointer
1057
	ni	__SIE_PROG0C+3(%r9),0xfe	# no longer in SIE
1058 1059 1060 1061
	lctlg	%c1,%c1,__LC_USER_ASCE		# load primary asce
	larl	%r9,sie_exit			# skip forward to sie_exit
	br	%r14
#endif
Linus Torvalds's avatar
Linus Torvalds committed
1062

1063
.Lcleanup_system_call:
1064
	# check if stpt has been executed
1065
	clg	%r9,BASED(.Lcleanup_system_call_insn)
Linus Torvalds's avatar
Linus Torvalds committed
1066 1067
	jh	0f
	mvc	__LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
1068
	cghi	%r11,__LC_SAVE_AREA_ASYNC
1069
	je	0f
1070 1071
	mvc	__LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER
0:	# check if stmg has been executed
1072
	clg	%r9,BASED(.Lcleanup_system_call_insn+8)
Linus Torvalds's avatar
Linus Torvalds committed
1073
	jh	0f
1074 1075
	mvc	__LC_SAVE_AREA_SYNC(64),0(%r11)
0:	# check if base register setup + TIF bit load has been done
1076
	clg	%r9,BASED(.Lcleanup_system_call_insn+16)
1077 1078 1079 1080 1081
	jhe	0f
	# set up saved registers r10 and r12
	stg	%r10,16(%r11)		# r10 last break
	stg	%r12,32(%r11)		# r12 thread-info pointer
0:	# check if the user time update has been done
1082
	clg	%r9,BASED(.Lcleanup_system_call_insn+24)
1083 1084 1085 1086 1087 1088
	jh	0f
	lg	%r15,__LC_EXIT_TIMER
	slg	%r15,__LC_SYNC_ENTER_TIMER
	alg	%r15,__LC_USER_TIMER
	stg	%r15,__LC_USER_TIMER
0:	# check if the system time update has been done
1089
	clg	%r9,BASED(.Lcleanup_system_call_insn+32)
1090 1091 1092 1093 1094 1095
	jh	0f
	lg	%r15,__LC_LAST_UPDATE_TIMER
	slg	%r15,__LC_EXIT_TIMER
	alg	%r15,__LC_SYSTEM_TIMER
	stg	%r15,__LC_SYSTEM_TIMER
0:	# update accounting time stamp
Linus Torvalds's avatar
Linus Torvalds committed
1096
	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
1097 1098 1099
	# do LAST_BREAK
	lg	%r9,16(%r11)
	srag	%r9,%r9,23
1100
	jz	0f
1101 1102 1103
	mvc	__TI_last_break(8,%r12),16(%r11)
0:	# set up saved register r11
	lg	%r15,__LC_KERNEL_STACK
1104 1105
	la	%r9,STACK_FRAME_OVERHEAD(%r15)
	stg	%r9,24(%r11)		# r11 pt_regs pointer
1106
	# fill pt_regs
1107 1108 1109 1110
	mvc	__PT_R8(64,%r9),__LC_SAVE_AREA_SYNC
	stmg	%r0,%r7,__PT_R0(%r9)
	mvc	__PT_PSW(16,%r9),__LC_SVC_OLD_PSW
	mvc	__PT_INT_CODE(4,%r9),__LC_SVC_ILC
1111 1112
	xc	__PT_FLAGS(8,%r9),__PT_FLAGS(%r9)
	mvi	__PT_FLAGS+7(%r9),_PIF_SYSCALL
1113 1114 1115
	# setup saved register r15
	stg	%r15,56(%r11)		# r15 stack pointer
	# set new psw address and exit
1116
	larl	%r9,.Lsysc_do_svc
Linus Torvalds's avatar
Linus Torvalds committed
1117
	br	%r14
1118
.Lcleanup_system_call_insn:
Heiko Carstens's avatar
Heiko Carstens committed
1119
	.quad	system_call
1120 1121
	.quad	.Lsysc_stmg
	.quad	.Lsysc_per
1122
	.quad	.Lsysc_vtime+36
1123
	.quad	.Lsysc_vtime+42
Linus Torvalds's avatar
Linus Torvalds committed
1124

1125 1126
.Lcleanup_sysc_tif:
	larl	%r9,.Lsysc_tif
Linus Torvalds's avatar
Linus Torvalds committed
1127 1128
	br	%r14

1129
.Lcleanup_sysc_restore:
1130
	# check if stpt has been executed
1131
	clg	%r9,BASED(.Lcleanup_sysc_restore_insn)
1132 1133 1134
	jh	0f
	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
	cghi	%r11,__LC_SAVE_AREA_ASYNC
1135
	je	0f
1136 1137 1138
	mvc	__LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
0:	clg	%r9,BASED(.Lcleanup_sysc_restore_insn+8)
	je	1f
1139 1140 1141 1142
	lg	%r9,24(%r11)		# get saved pointer to pt_regs
	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
	mvc	0(64,%r11),__PT_R8(%r9)
	lmg	%r0,%r7,__PT_R0(%r9)
1143
1:	lmg	%r8,%r9,__LC_RETURN_PSW
Linus Torvalds's avatar
Linus Torvalds committed
1144
	br	%r14
1145
.Lcleanup_sysc_restore_insn:
1146
	.quad	.Lsysc_exit_timer
1147
	.quad	.Lsysc_done - 4
Linus Torvalds's avatar
Linus Torvalds committed
1148

1149 1150
.Lcleanup_io_tif:
	larl	%r9,.Lio_tif
1151 1152
	br	%r14

1153
.Lcleanup_io_restore:
1154
	# check if stpt has been executed
1155
	clg	%r9,BASED(.Lcleanup_io_restore_insn)
1156 1157 1158 1159
	jh	0f
	mvc	__LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
0:	clg	%r9,BASED(.Lcleanup_io_restore_insn+8)
	je	1f
1160 1161 1162 1163
	lg	%r9,24(%r11)		# get saved r11 pointer to pt_regs
	mvc	__LC_RETURN_PSW(16),__PT_PSW(%r9)
	mvc	0(64,%r11),__PT_R8(%r9)
	lmg	%r0,%r7,__PT_R0(%r9)
1164
1:	lmg	%r8,%r9,__LC_RETURN_PSW
1165
	br	%r14
1166
.Lcleanup_io_restore_insn:
1167
	.quad	.Lio_exit_timer
1168
	.quad	.Lio_done - 4
1169

1170
.Lcleanup_idle:
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1171
	# copy interrupt clock & cpu timer
1172 1173
	mvc	__CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK
	mvc	__TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1174 1175
	cghi	%r11,__LC_SAVE_AREA_ASYNC
	je	0f
1176 1177
	mvc	__CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK
	mvc	__TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1178
0:	# check if stck & stpt have been executed
1179
	clg	%r9,BASED(.Lcleanup_idle_insn)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1180
	jhe	1f
1181 1182
	mvc	__CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2)
	mvc	__TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r2)
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
1:	# calculate idle cycles
#ifdef CONFIG_SMP
	clg	%r9,BASED(.Lcleanup_idle_insn)
	jl	3f
	larl	%r1,smp_cpu_mtid
	llgf	%r1,0(%r1)
	ltgr	%r1,%r1
	jz	3f
	.insn	rsy,0xeb0000000017,%r1,5,__SF_EMPTY+80(%r15)
	larl	%r3,mt_cycles
	ag	%r3,__LC_PERCPU_OFFSET
	la	%r4,__SF_EMPTY+16(%r15)
2:	lg	%r0,0(%r3)
	slg	%r0,0(%r4)
	alg	%r0,64(%r4)
	stg	%r0,0(%r3)
	la	%r3,8(%r3)
	la	%r4,8(%r4)
	brct	%r1,2b
#endif
3:	# account system time going idle
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1204
	lg	%r9,__LC_STEAL_TIMER
1205
	alg	%r9,__CLOCK_IDLE_ENTER(%r2)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1206 1207
	slg	%r9,__LC_LAST_UPDATE_CLOCK
	stg	%r9,__LC_STEAL_TIMER
1208
	mvc	__LC_LAST_UPDATE_CLOCK(8),__CLOCK_IDLE_EXIT(%r2)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1209 1210
	lg	%r9,__LC_SYSTEM_TIMER
	alg	%r9,__LC_LAST_UPDATE_TIMER
1211
	slg	%r9,__TIMER_IDLE_ENTER(%r2)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1212
	stg	%r9,__LC_SYSTEM_TIMER
1213
	mvc	__LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2)
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1214
	# prepare return psw
1215
	nihh	%r8,0xfcfd		# clear irq & wait state bits
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1216 1217
	lg	%r9,48(%r11)		# return from psw_idle
	br	%r14
1218 1219
.Lcleanup_idle_insn:
	.quad	.Lpsw_idle_lpsw
Martin Schwidefsky's avatar
Martin Schwidefsky committed
1220

1221
.Lcleanup_save_fpu_regs:
1222
	larl	%r9,save_fpu_regs
1223 1224 1225
	br	%r14

.Lcleanup_load_fpu_regs:
1226
	larl	%r9,load_fpu_regs
1227 1228
	br	%r14

Linus Torvalds's avatar
Linus Torvalds committed
1229 1230 1231
/*
 * Integer constants
 */
1232
	.align	8
Linus Torvalds's avatar
Linus Torvalds committed
1233
.Lcritical_start:
1234
	.quad	.L__critical_start
1235
.Lcritical_length:
1236
	.quad	.L__critical_end - .L__critical_start
1237
#if IS_ENABLED(CONFIG_KVM)
1238
.Lsie_critical_start:
1239
	.quad	.Lsie_gmap
1240
.Lsie_critical_length:
1241
	.quad	.Lsie_done - .Lsie_gmap
1242 1243
#endif

Heiko Carstens's avatar
Heiko Carstens committed
1244 1245
	.section .rodata, "a"
#define SYSCALL(esame,emu)	.long esame
1246
	.globl	sys_call_table
Linus Torvalds's avatar
Linus Torvalds committed
1247 1248 1249 1250
sys_call_table:
#include "syscalls.S"
#undef SYSCALL

1251
#ifdef CONFIG_COMPAT
Linus Torvalds's avatar
Linus Torvalds committed
1252

Heiko Carstens's avatar
Heiko Carstens committed
1253
#define SYSCALL(esame,emu)	.long emu
1254
	.globl	sys_call_table_emu
Linus Torvalds's avatar
Linus Torvalds committed
1255 1256 1257 1258
sys_call_table_emu:
#include "syscalls.S"
#undef SYSCALL
#endif