xref: /linux/arch/s390/kernel/text_amode31.S (revision 8838a1a2d219a86ab05e679c73f68dd75a25aca5)
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Code that needs to run below 2 GB.
4 *
5 * Copyright IBM Corp. 2019
6 */
7
8#include <linux/linkage.h>
9#include <asm/asm-extable.h>
10#include <asm/errno.h>
11#include <asm/sigp.h>
12
13	.section .amode31.text,"ax"
14/*
15 * Simplified version of expoline thunk. The normal thunks can not be used here,
16 * because they might be more than 2 GB away, and not reachable by the relative
17 * branch. No comdat, exrl, etc. optimizations used here, because it only
18 * affects a few functions that are not performance-relevant.
19 */
20	.macro BR_EX_AMODE31_r14
21	exrl	0,0f
22	j	.
230:	br	%r14
24	.endm
25
26/*
27 * int _diag14_amode31(unsigned long rx, unsigned long ry1, unsigned long subcode)
28 */
29SYM_FUNC_START(_diag14_amode31)
30	lgr	%r1,%r2
31	lgr	%r2,%r3
32	lgr	%r3,%r4
33	lhi	%r5,-EIO
34	sam31
35	diag	%r1,%r2,0x14
36.Ldiag14_ex:
37	ipm	%r5
38	srl	%r5,28
39.Ldiag14_fault:
40	sam64
41	lgfr	%r2,%r5
42	BR_EX_AMODE31_r14
43	EX_TABLE_AMODE31(.Ldiag14_ex, .Ldiag14_fault)
44SYM_FUNC_END(_diag14_amode31)
45
46/*
47 * int _diag210_amode31(struct diag210 *addr)
48 */
49SYM_FUNC_START(_diag210_amode31)
50	lgr	%r1,%r2
51	lhi	%r2,-1
52	sam31
53	diag	%r1,%r0,0x210
54.Ldiag210_ex:
55	ipm	%r2
56	srl	%r2,28
57.Ldiag210_fault:
58	sam64
59	lgfr	%r2,%r2
60	BR_EX_AMODE31_r14
61	EX_TABLE_AMODE31(.Ldiag210_ex, .Ldiag210_fault)
62SYM_FUNC_END(_diag210_amode31)
63
64/*
65 * int diag8c(struct diag8c *addr, struct ccw_dev_id *devno, size_t len)
66*/
67SYM_FUNC_START(_diag8c_amode31)
68	llgf	%r3,0(%r3)
69	sam31
70	diag	%r2,%r4,0x8c
71.Ldiag8c_ex:
72	sam64
73	lgfr	%r2,%r3
74	BR_EX_AMODE31_r14
75	EX_TABLE_AMODE31(.Ldiag8c_ex, .Ldiag8c_ex)
76SYM_FUNC_END(_diag8c_amode31)
77/*
78 * int _diag26c_amode31(void *req, void *resp, enum diag26c_sc subcode)
79 */
80SYM_FUNC_START(_diag26c_amode31)
81	lghi	%r5,-EOPNOTSUPP
82	sam31
83	diag	%r2,%r4,0x26c
84.Ldiag26c_ex:
85	sam64
86	lgfr	%r2,%r5
87	BR_EX_AMODE31_r14
88	EX_TABLE_AMODE31(.Ldiag26c_ex, .Ldiag26c_ex)
89SYM_FUNC_END(_diag26c_amode31)
90
91/*
92 * void _diag0c_amode31(unsigned long rx)
93 */
94SYM_FUNC_START(_diag0c_amode31)
95	sam31
96	diag	%r2,%r2,0x0c
97	sam64
98	BR_EX_AMODE31_r14
99SYM_FUNC_END(_diag0c_amode31)
100
101/*
102 * void _diag308_reset_amode31(void)
103 *
104 * Calls diag 308 subcode 1 and continues execution
105 */
106SYM_FUNC_START(_diag308_reset_amode31)
107	larl	%r4,ctlregs		# Save control registers
108	stctg	%c0,%c15,0(%r4)
109	lg	%r2,0(%r4)		# Disable lowcore protection
110	nilh	%r2,0xefff
111	larl	%r4,ctlreg0
112	stg	%r2,0(%r4)
113	lctlg	%c0,%c0,0(%r4)
114	larl	%r4,fpctl		# Floating point control register
115	stfpc	0(%r4)
116	larl	%r4,prefix		# Save prefix register
117	stpx	0(%r4)
118	larl	%r4,prefix_zero	# Set prefix register to 0
119	spx	0(%r4)
120	larl	%r4,continue_psw	# Save PSW flags
121	epsw	%r2,%r3
122	stm	%r2,%r3,0(%r4)
123	larl	%r4,.Lrestart_part2	# Setup restart PSW at absolute 0
124	larl	%r3,restart_diag308_psw
125	og	%r4,0(%r3)		# Save PSW
126	lghi	%r3,0
127	sturg	%r4,%r3			# Use sturg, because of large pages
128	lghi	%r1,1
129	lghi	%r0,0
130	diag	%r0,%r1,0x308
131.Lrestart_part2:
132	lhi	%r0,0			# Load r0 with zero
133	lhi	%r1,2			# Use mode 2 = ESAME (dump)
134	sigp	%r1,%r0,SIGP_SET_ARCHITECTURE	# Switch to ESAME mode
135	sam64				# Switch to 64 bit addressing mode
136	larl	%r4,ctlregs		# Restore control registers
137	lctlg	%c0,%c15,0(%r4)
138	larl	%r4,fpctl		# Restore floating point ctl register
139	lfpc	0(%r4)
140	larl	%r4,prefix		# Restore prefix register
141	spx	0(%r4)
142	larl	%r4,continue_psw	# Restore PSW flags
143	larl	%r2,.Lcontinue
144	stg	%r2,8(%r4)
145	lpswe	0(%r4)
146.Lcontinue:
147	BR_EX_AMODE31_r14
148SYM_FUNC_END(_diag308_reset_amode31)
149
150	.section .amode31.data,"aw",@progbits
151	.balign	8
152SYM_DATA_LOCAL(restart_diag308_psw,	.long 0x00080000,0x80000000)
153SYM_DATA_LOCAL(continue_psw,		.quad 0,0)
154SYM_DATA_LOCAL(ctlreg0,			.quad 0)
155SYM_DATA_LOCAL(ctlregs,			.fill 16,8,0)
156SYM_DATA_LOCAL(fpctl,			.long 0)
157SYM_DATA_LOCAL(prefix,			.long 0)
158SYM_DATA_LOCAL(prefix_zero,		.long 0)
159