xref: /kvm-unit-tests/s390x/cstart64.S (revision be704aff683c54fc108deaafacc7cb89ad0648d9)
1/*
2 * s390x startup code
3 *
4 * Copyright (c) 2017 Red Hat Inc
5 *
6 * Authors:
7 *  Thomas Huth <thuth@redhat.com>
8 *  David Hildenbrand <david@redhat.com>
9 *
10 * This code is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Library General Public License version 2.
12 */
13#include <asm/asm-offsets.h>
14#include <asm/sigp.h>
15
16.section .init
17
18/*
19 * Short init between 0x10000 and 0x10480 and then jump to 0x11000.
20 * 0x10480 - 0x11000 are written to by bootloader.
21 *
22 * For KVM and TCG kernel boot we are in 64 bit z/Arch mode.
23 * When booting from disk the initial short psw is in 31 bit mode.
24 * When running under LPAR or z/VM, we might start in 31 bit and esam mode.
25 */
26	.globl start
27start:
28	/* Switch to z/Architecture mode and 64-bit */
29	slr     %r0, %r0		# Set cpuid to zero
30	lhi     %r1, 2			# mode 2 = esame
31	sigp    %r1, %r0, SIGP_SET_ARCHITECTURE
32	/* XOR all registers with themselves to clear them fully. */
33	.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
34	xgr \i,\i
35	.endr
36	sam64				# Set addressing mode to 64 bit
37	/* setup stack */
38	larl	%r15, stackptr
39	/* setup initial PSW mask + control registers*/
40	larl	%r1, initial_psw
41	lpswe	0(%r1)
42clear_bss_start:
43	larl 	%r2, __bss_start
44	larl 	%r3, __bss_end
45	slgr 	%r3, %r2		# Get sizeof bss
46	aghi 	%r3,-1
47	srlg 	%r4,%r3,8		# Calc number of 256 byte chunks
48	ltgr 	%r4,%r4
49	lgr 	%r1,%r2
50	jz	clear_bss_remainder		# If none, clear remaining bytes
51clear_bss_loop:
52	xc	0(256,%r1), 0(%r1)	# Clear 256 byte chunks via xor
53	la	%r1, 256(%r1)
54	brctg 	%r4, clear_bss_loop
55clear_bss_remainder:
56	larl	%r2, memsetxc
57	ex 	%r3, 0(%r2)
58	/* setup pgm interrupt handler */
59	larl	%r1, pgm_int_psw
60	mvc	GEN_LC_PGM_NEW_PSW(16), 0(%r1)
61	/* setup ext interrupt handler */
62	larl	%r1, ext_int_psw
63	mvc	GEN_LC_EXT_NEW_PSW(16), 0(%r1)
64	/* setup mcck interrupt handler */
65	larl	%r1, mcck_int_psw
66	mvc	GEN_LC_MCCK_NEW_PSW(16), 0(%r1)
67	/* setup io interrupt handler */
68	larl	%r1, io_int_psw
69	mvc	GEN_LC_IO_NEW_PSW(16), 0(%r1)
70	/* setup svc interrupt handler */
71	larl	%r1, svc_int_psw
72	mvc	GEN_LC_SVC_NEW_PSW(16), 0(%r1)
73	/* setup cr0, enabling e.g. AFP-register control */
74	larl	%r1, initial_cr0
75	lctlg	%c0, %c0, 0(%r1)
76	/* call setup() */
77	brasl	%r14, setup
78	/* forward test parameter */
79	larl	%r2, __argc
80	llgf	%r2, 0(%r2)
81	larl	%r3, __argv
82	/* call to main() */
83	brasl	%r14, main
84	/* forward exit code */
85	lgr	%r3, %r2
86	/* call exit() */
87	j exit
88
89memsetxc:
90	xc 0(1,%r1),0(%r1)
91
92	.macro SAVE_REGS
93	/* save grs 0-15 */
94	stmg	%r0, %r15, GEN_LC_SW_INT_GRS
95	/* save crs 0-15 */
96	stctg	%c0, %c15, GEN_LC_SW_INT_CRS
97	/* load a cr0 that has the AFP control bit which enables all FPRs */
98	larl	%r1, initial_cr0
99	lctlg	%c0, %c0, 0(%r1)
100	/* save fprs 0-15 + fpc */
101	la	%r1, GEN_LC_SW_INT_FPRS
102	.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
103	std	\i, \i * 8(%r1)
104	.endr
105	stfpc	GEN_LC_SW_INT_FPC
106	.endm
107
108	.macro RESTORE_REGS
109	/* restore fprs 0-15 + fpc */
110	la	%r1, GEN_LC_SW_INT_FPRS
111	.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
112	ld	\i, \i * 8(%r1)
113	.endr
114	lfpc	GEN_LC_SW_INT_FPC
115	/* restore crs 0-15 */
116	lctlg	%c0, %c15, GEN_LC_SW_INT_CRS
117	/* restore grs 0-15 */
118	lmg	%r0, %r15, GEN_LC_SW_INT_GRS
119	.endm
120
121/* Save registers on the stack (r15), so we can have stacked interrupts. */
122	.macro SAVE_REGS_STACK
123	/* Allocate a stack frame for 15 general registers */
124	slgfi   %r15, 15 * 8
125	/* Store registers r0 to r14 on the stack */
126	stmg    %r0, %r14, 0(%r15)
127	/* Allocate a stack frame for 16 floating point registers */
128	/* The size of a FP register is the size of an double word */
129	slgfi   %r15, 16 * 8
130	/* Save fp register on stack: offset to SP is multiple of reg number */
131	.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
132	std	\i, \i * 8(%r15)
133	.endr
134	/* Save fpc, but keep stack aligned on 64bits */
135	slgfi   %r15, 8
136	efpc	%r0
137	stg	%r0, 0(%r15)
138	.endm
139
140/* Restore the register in reverse order */
141	.macro RESTORE_REGS_STACK
142	/* Restore fpc */
143	lfpc	0(%r15)
144	algfi	%r15, 8
145	/* Restore fp register from stack: SP still where it was left */
146	/* and offset to SP is a multiple of reg number */
147	.irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
148	ld	\i, \i * 8(%r15)
149	.endr
150	/* Now that we're done, rewind the stack pointer by 16 double word */
151	algfi   %r15, 16 * 8
152	/* Load the registers from stack */
153	lmg     %r0, %r14, 0(%r15)
154	/* Rewind the stack by 15 double word */
155	algfi   %r15, 15 * 8
156	.endm
157
158.section .text
159/*
160 * load_reset calling convention:
161 * %r2 subcode (0 or 1)
162 */
163.globl diag308_load_reset
164diag308_load_reset:
165	SAVE_REGS
166	/* Backup current PSW mask, as we have to restore it on success */
167	epsw	%r0, %r1
168	st	%r0, GEN_LC_SW_INT_PSW
169	st	%r1, GEN_LC_SW_INT_PSW + 4
170	/* Load reset psw mask (short psw, 64 bit) */
171	lg	%r0, reset_psw
172	/* Load the success label address */
173	larl    %r1, 0f
174	/* Or it to the mask */
175	ogr	%r0, %r1
176	/* Store it at the reset PSW location (real 0x0) */
177	stg	%r0, 0
178	/* Do the reset */
179	diag    %r0,%r2,0x308
180	/* Failure path */
181	xgr	%r2, %r2
182	br	%r14
183	/* Success path */
184	/* load a cr0 that has the AFP control bit which enables all FPRs */
1850:	larl	%r1, initial_cr0
186	lctlg	%c0, %c0, 0(%r1)
187	RESTORE_REGS
188	lhi	%r2, 1
189	larl	%r0, 1f
190	stg	%r0, GEN_LC_SW_INT_PSW + 8
191	lpswe	GEN_LC_SW_INT_PSW
1921:	br	%r14
193
194.globl smp_cpu_setup_state
195smp_cpu_setup_state:
196	xgr	%r1, %r1
197	lmg     %r0, %r15, GEN_LC_SW_INT_GRS
198	lctlg   %c0, %c0, GEN_LC_SW_INT_CRS
199	/* We should only go once through cpu setup and not for every restart */
200	stg	%r14, GEN_LC_RESTART_NEW_PSW + 8
201	larl	%r14, 0f
202	lpswe	GEN_LC_SW_INT_PSW
203	/* If the function returns, just loop here */
2040:	j	0
205
206pgm_int:
207	SAVE_REGS
208	brasl	%r14, handle_pgm_int
209	RESTORE_REGS
210	lpswe	GEN_LC_PGM_OLD_PSW
211
212ext_int:
213	SAVE_REGS
214	brasl	%r14, handle_ext_int
215	RESTORE_REGS
216	lpswe	GEN_LC_EXT_OLD_PSW
217
218mcck_int:
219	SAVE_REGS
220	brasl	%r14, handle_mcck_int
221	RESTORE_REGS
222	lpswe	GEN_LC_MCCK_OLD_PSW
223
224io_int:
225	SAVE_REGS_STACK
226	brasl	%r14, handle_io_int
227	RESTORE_REGS_STACK
228	lpswe	GEN_LC_IO_OLD_PSW
229
230svc_int:
231	SAVE_REGS
232	brasl	%r14, handle_svc_int
233	RESTORE_REGS
234	lpswe	GEN_LC_SVC_OLD_PSW
235
236	.align	8
237reset_psw:
238	.quad	0x0008000180000000
239initial_psw:
240	.quad	0x0000000180000000, clear_bss_start
241pgm_int_psw:
242	.quad	0x0000000180000000, pgm_int
243ext_int_psw:
244	.quad	0x0000000180000000, ext_int
245mcck_int_psw:
246	.quad	0x0000000180000000, mcck_int
247io_int_psw:
248	.quad	0x0000000180000000, io_int
249svc_int_psw:
250	.quad	0x0000000180000000, svc_int
251initial_cr0:
252	/* enable AFP-register control, so FP regs (+BFP instr) can be used */
253	.quad	0x0000000000040000
254