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