1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/linkage.h>
3#include <linux/kexec.h>
4
5#include <asm/assembly.h>
6#include <asm/asm-offsets.h>
7#include <asm/page.h>
8#include <asm/setup.h>
9#include <asm/psw.h>
10
11.level PA_ASM_LEVEL
12
13.macro	kexec_param name
14.align 8
15ENTRY(kexec\()_\name)
16#ifdef CONFIG_64BIT
17	.dword 0
18#else
19	.word 0
20#endif
21
22ENTRY(kexec\()_\name\()_offset)
23	.word kexec\()_\name - relocate_new_kernel
24.endm
25
26.text
27
28/* args:
29 * r26 - kimage->head
30 * r25 - start address of kernel
31 * r24 - physical address of relocate code
32 */
33
34ENTRY_CFI(relocate_new_kernel)
350:	copy	%arg1, %rp
36	/* disable I and Q bit, so we are allowed to execute RFI */
37	rsm PSW_SM_I, %r0
38	nop
39	nop
40	nop
41	nop
42	nop
43	nop
44	nop
45
46	rsm PSW_SM_Q, %r0
47	nop
48	nop
49	nop
50	nop
51	nop
52	nop
53	nop
54
55	/*
56	 * After return-from-interrupt, we want to run without Code/Data
57	 * translation enabled just like on a normal boot.
58	 */
59
60	/* calculate new physical execution address */
61	ldo	1f-0b(%arg2), %r1
62	mtctl	%r0, %cr17 /* IIASQ */
63	mtctl	%r0, %cr17 /* IIASQ */
64	mtctl	%r1, %cr18 /* IIAOQ */
65	ldo	4(%r1),%r1
66	mtctl	%r1, %cr18 /* IIAOQ */
67#ifdef CONFIG_64BIT
68	depdi,z	1, PSW_W_BIT, 1, %r1
69	mtctl	%r1, %cr22 /* IPSW */
70#else
71	mtctl	%r0, %cr22 /* IPSW */
72#endif
73	/* lets go... */
74	rfi
751:	nop
76	nop
77
78.Lloop:
79	LDREG,ma	REG_SZ(%arg0), %r3
80	/* If crash kernel, no copy needed */
81	cmpib,COND(=),n 0,%r3,boot
82
83	bb,<,n		%r3, 31 - IND_DONE_BIT, boot
84	bb,>=,n		%r3, 31 - IND_INDIRECTION_BIT, .Lnotind
85	/* indirection, load and restart */
86	movb		%r3, %arg0, .Lloop
87	depi		0, 31, PAGE_SHIFT, %arg0
88
89.Lnotind:
90	bb,>=,n		%r3, 31 - IND_DESTINATION_BIT, .Lnotdest
91	b		.Lloop
92	copy		%r3, %r20
93
94.Lnotdest:
95	bb,>=		%r3, 31 - IND_SOURCE_BIT, .Lloop
96	depi		0, 31, PAGE_SHIFT, %r3
97	copy		%r3, %r21
98
99	/* copy page */
100	copy		%r0, %r18
101	zdepi		1, 31 - PAGE_SHIFT, 1, %r18
102	add		%r20, %r18, %r17
103
104	depi		0, 31, PAGE_SHIFT, %r20
105.Lcopy:
106	copy		%r20, %r12
107	LDREG,ma	REG_SZ(%r21), %r8
108	LDREG,ma	REG_SZ(%r21), %r9
109	LDREG,ma	REG_SZ(%r21), %r10
110	LDREG,ma	REG_SZ(%r21), %r11
111	STREG,ma	%r8, REG_SZ(%r20)
112	STREG,ma	%r9, REG_SZ(%r20)
113	STREG,ma	%r10, REG_SZ(%r20)
114	STREG,ma	%r11, REG_SZ(%r20)
115
116#ifndef CONFIG_64BIT
117	LDREG,ma	REG_SZ(%r21), %r8
118	LDREG,ma	REG_SZ(%r21), %r9
119	LDREG,ma	REG_SZ(%r21), %r10
120	LDREG,ma	REG_SZ(%r21), %r11
121	STREG,ma	%r8, REG_SZ(%r20)
122	STREG,ma	%r9, REG_SZ(%r20)
123	STREG,ma	%r10, REG_SZ(%r20)
124	STREG,ma	%r11, REG_SZ(%r20)
125#endif
126
127	fdc		%r0(%r12)
128	cmpb,COND(<<)	%r20,%r17,.Lcopy
129	fic		(%sr4, %r12)
130	b,n		.Lloop
131
132boot:
133	mtctl	%r0, %cr15
134
135	LDREG	kexec_free_mem-0b(%arg2), %arg0
136	LDREG	kexec_cmdline-0b(%arg2), %arg1
137	LDREG	kexec_initrd_end-0b(%arg2), %arg3
138	LDREG	kexec_initrd_start-0b(%arg2), %arg2
139	bv,n %r0(%rp)
140
141ENDPROC_CFI(relocate_new_kernel);
142
143ENTRY(relocate_new_kernel_size)
144       .word relocate_new_kernel_size - relocate_new_kernel
145
146kexec_param cmdline
147kexec_param initrd_start
148kexec_param initrd_end
149kexec_param free_mem
150