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 |
15 | ENTRY(kexec\()_\name) |
16 | #ifdef CONFIG_64BIT |
17 | .dword 0 |
18 | #else |
19 | .word 0 |
20 | #endif |
21 | |
22 | ENTRY(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 | |
34 | ENTRY_CFI(relocate_new_kernel) |
35 | 0: 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 |
75 | 1: 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 | |
132 | boot: |
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 | |
141 | ENDPROC_CFI(relocate_new_kernel); |
142 | |
143 | ENTRY(relocate_new_kernel_size) |
144 | .word relocate_new_kernel_size - relocate_new_kernel |
145 | |
146 | kexec_param cmdline |
147 | kexec_param initrd_start |
148 | kexec_param initrd_end |
149 | kexec_param free_mem |
150 | |