summaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/relocate_kernel.S
blob: 2561e52b8d9bc8f47f00b88600fa3e884c590d9f (plain)
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