]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
1da177e4 | 2 | /* |
a53c8fab | 3 | * Copyright IBM Corp. 1999, 2010 |
0ad775db HC |
4 | * |
5 | * Author(s): Hartmut Penner <hp@de.ibm.com> | |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | |
7 | * Rob van der Heij <rvdhei@iae.nl> | |
8 | * Heiko Carstens <heiko.carstens@de.ibm.com> | |
1da177e4 LT |
9 | * |
10 | * There are 5 different IPL methods | |
11 | * 1) load the image directly into ram at address 0 and do an PSW restart | |
12 | * 2) linload will load the image from address 0x10000 to memory 0x10000 | |
13 | * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) | |
14 | * 3) generate the tape ipl header, store the generated image on a tape | |
15 | * and ipl from it | |
16 | * In case of SL tape you need to IPL 5 times to get past VOL1 etc | |
17 | * 4) generate the vm reader ipl header, move the generated image to the | |
18 | * VM reader (use option NOH!) and do a ipl from reader (VM only) | |
19 | * 5) direct call of start by the SALIPL loader | |
20 | * We use the cpuid to distinguish between VM and native ipl | |
21 | * params for kernel are pushed to 0x10400 (see setup.h) | |
0ad775db | 22 | * |
1da177e4 LT |
23 | */ |
24 | ||
2133bb8d | 25 | #include <linux/init.h> |
144d634a | 26 | #include <linux/linkage.h> |
0013a854 | 27 | #include <asm/asm-offsets.h> |
1da177e4 LT |
28 | #include <asm/thread_info.h> |
29 | #include <asm/page.h> | |
c6eafbf9 | 30 | #include <asm/ptrace.h> |
1da177e4 | 31 | |
0ad775db | 32 | #define ARCH_OFFSET 4 |
0ad775db | 33 | |
2133bb8d | 34 | __HEAD |
1da177e4 | 35 | |
25d83cbf HC |
36 | #define IPL_BS 0x730 |
37 | .org 0 | |
38 | .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded | |
39 | .long 0x02000018,0x60000050 # by ipl to addresses 0-23. | |
40 | .long 0x02000068,0x60000050 # (a PSW and two CCWs). | |
41 | .fill 80-24,1,0x40 # bytes 24-79 are discarded !! | |
42 | .long 0x020000f0,0x60000050 # The next 160 byte are loaded | |
43 | .long 0x02000140,0x60000050 # to addresses 0x18-0xb7 | |
44 | .long 0x02000190,0x60000050 # They form the continuation | |
45 | .long 0x020001e0,0x60000050 # of the CCW program started | |
46 | .long 0x02000230,0x60000050 # by ipl and load the range | |
47 | .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image | |
48 | .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730 | |
49 | .long 0x02000320,0x60000050 # in memory. At the end of | |
50 | .long 0x02000370,0x60000050 # the channel program the PSW | |
51 | .long 0x020003c0,0x60000050 # at location 0 is loaded. | |
52 | .long 0x02000410,0x60000050 # Initial processing starts | |
51eee033 | 53 | .long 0x02000460,0x60000050 # at 0x200 = iplstart. |
25d83cbf HC |
54 | .long 0x020004b0,0x60000050 |
55 | .long 0x02000500,0x60000050 | |
56 | .long 0x02000550,0x60000050 | |
57 | .long 0x020005a0,0x60000050 | |
58 | .long 0x020005f0,0x60000050 | |
59 | .long 0x02000640,0x60000050 | |
60 | .long 0x02000690,0x60000050 | |
61 | .long 0x020006e0,0x20000050 | |
1da177e4 | 62 | |
da9ed30d | 63 | .org __LC_RST_NEW_PSW # 0x1a0 |
8e5a7627 | 64 | .quad 0,iplstart |
da9ed30d VG |
65 | .org __LC_PGM_NEW_PSW # 0x1d0 |
66 | .quad 0x0000000180000000,startup_pgm_check_handler | |
8e5a7627 | 67 | |
51eee033 | 68 | .org 0x200 |
51eee033 MS |
69 | |
70 | # | |
71 | # subroutine to wait for end I/O | |
72 | # | |
73 | .Lirqwait: | |
34ba2450 | 74 | mvc __LC_IO_NEW_PSW(16),.Lnewpsw # set up IO interrupt psw |
51eee033 MS |
75 | lpsw .Lwaitpsw |
76 | .Lioint: | |
77 | br %r14 | |
78 | .align 8 | |
79 | .Lnewpsw: | |
80 | .quad 0x0000000080000000,.Lioint | |
51eee033 MS |
81 | .Lwaitpsw: |
82 | .long 0x020a0000,0x80000000+.Lioint | |
83 | ||
1da177e4 LT |
84 | # |
85 | # subroutine for loading cards from the reader | |
86 | # | |
25d83cbf | 87 | .Lloader: |
51eee033 | 88 | la %r4,0(%r14) |
25d83cbf HC |
89 | la %r3,.Lorb # r2 = address of orb into r2 |
90 | la %r5,.Lirb # r4 = address of irb | |
91 | la %r6,.Lccws | |
92 | la %r7,20 | |
1da177e4 | 93 | .Linit: |
25d83cbf HC |
94 | st %r2,4(%r6) # initialize CCW data addresses |
95 | la %r2,0x50(%r2) | |
96 | la %r6,8(%r6) | |
97 | bct 7,.Linit | |
1da177e4 | 98 | |
25d83cbf HC |
99 | lctl %c6,%c6,.Lcr6 # set IO subclass mask |
100 | slr %r2,%r2 | |
1da177e4 | 101 | .Lldlp: |
25d83cbf HC |
102 | ssch 0(%r3) # load chunk of 1600 bytes |
103 | bnz .Llderr | |
1da177e4 | 104 | .Lwait4irq: |
51eee033 | 105 | bas %r14,.Lirqwait |
34ba2450 | 106 | c %r1,__LC_SUBCHANNEL_ID # compare subchannel number |
25d83cbf HC |
107 | bne .Lwait4irq |
108 | tsch 0(%r5) | |
1da177e4 | 109 | |
25d83cbf HC |
110 | slr %r0,%r0 |
111 | ic %r0,8(%r5) # get device status | |
112 | chi %r0,8 # channel end ? | |
113 | be .Lcont | |
114 | chi %r0,12 # channel end + device end ? | |
115 | be .Lcont | |
1da177e4 | 116 | |
25d83cbf HC |
117 | l %r0,4(%r5) |
118 | s %r0,8(%r3) # r0/8 = number of ccws executed | |
119 | mhi %r0,10 # *10 = number of bytes in ccws | |
120 | lh %r3,10(%r5) # get residual count | |
121 | sr %r0,%r3 # #ccws*80-residual=#bytes read | |
122 | ar %r2,%r0 | |
123 | ||
51eee033 | 124 | br %r4 # r2 contains the total size |
1da177e4 LT |
125 | |
126 | .Lcont: | |
25d83cbf HC |
127 | ahi %r2,0x640 # add 0x640 to total size |
128 | la %r6,.Lccws | |
129 | la %r7,20 | |
1da177e4 | 130 | .Lincr: |
25d83cbf HC |
131 | l %r0,4(%r6) # update CCW data addresses |
132 | ahi %r0,0x640 | |
133 | st %r0,4(%r6) | |
134 | ahi %r6,8 | |
135 | bct 7,.Lincr | |
1da177e4 | 136 | |
25d83cbf | 137 | b .Lldlp |
1da177e4 | 138 | .Llderr: |
25d83cbf | 139 | lpsw .Lcrash |
1da177e4 | 140 | |
25d83cbf HC |
141 | .align 8 |
142 | .Lorb: .long 0x00000000,0x0080ff00,.Lccws | |
143 | .Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | |
144 | .Lcr6: .long 0xff000000 | |
145 | .Lloadp:.long 0,0 | |
146 | .align 8 | |
147 | .Lcrash:.long 0x000a0000,0x00000000 | |
1da177e4 | 148 | |
25d83cbf HC |
149 | .align 8 |
150 | .Lccws: .rept 19 | |
151 | .long 0x02600050,0x00000000 | |
152 | .endr | |
153 | .long 0x02200050,0x00000000 | |
1da177e4 LT |
154 | |
155 | iplstart: | |
f52c74fe HC |
156 | mvi __LC_AR_MODE_ID,1 # set esame flag |
157 | slr %r0,%r0 # set cpuid to zero | |
158 | lhi %r1,2 # mode 2 = esame (dump) | |
159 | sigp %r1,%r0,0x12 # switch to esame mode | |
160 | bras %r13,0f | |
161 | .fill 16,4,0x0 | |
162 | 0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs | |
163 | sam31 # switch to 31 bit addressing mode | |
34ba2450 | 164 | lh %r1,__LC_SUBCHANNEL_ID # test if subchannel number |
25d83cbf | 165 | bct %r1,.Lnoload # is valid |
34ba2450 | 166 | l %r1,__LC_SUBCHANNEL_ID # load ipl subchannel number |
25d83cbf HC |
167 | la %r2,IPL_BS # load start address |
168 | bas %r14,.Lloader # load rest of ipl image | |
169 | l %r12,.Lparm # pointer to parameter area | |
170 | st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number | |
1da177e4 LT |
171 | |
172 | # | |
173 | # load parameter file from ipl device | |
174 | # | |
175 | .Lagain1: | |
25d83cbf HC |
176 | l %r2,.Linitrd # ramdisk loc. is temp |
177 | bas %r14,.Lloader # load parameter file | |
178 | ltr %r2,%r2 # got anything ? | |
179 | bz .Lnopf | |
180 | chi %r2,895 | |
181 | bnh .Lnotrunc | |
182 | la %r2,895 | |
1da177e4 | 183 | .Lnotrunc: |
25d83cbf HC |
184 | l %r4,.Linitrd |
185 | clc 0(3,%r4),.L_hdr # if it is HDRx | |
186 | bz .Lagain1 # skip dataset header | |
187 | clc 0(3,%r4),.L_eof # if it is EOFx | |
188 | bz .Lagain1 # skip dateset trailer | |
189 | la %r5,0(%r4,%r2) | |
190 | lr %r3,%r2 | |
61fd330d | 191 | la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line |
25d83cbf HC |
192 | mvc 0(256,%r3),0(%r4) |
193 | mvc 256(256,%r3),256(%r4) | |
194 | mvc 512(256,%r3),512(%r4) | |
195 | mvc 768(122,%r3),768(%r4) | |
196 | slr %r0,%r0 | |
197 | b .Lcntlp | |
1da177e4 | 198 | .Ldelspc: |
25d83cbf HC |
199 | ic %r0,0(%r2,%r3) |
200 | chi %r0,0x20 # is it a space ? | |
201 | be .Lcntlp | |
202 | ahi %r2,1 | |
203 | b .Leolp | |
1da177e4 | 204 | .Lcntlp: |
25d83cbf | 205 | brct %r2,.Ldelspc |
1da177e4 | 206 | .Leolp: |
25d83cbf HC |
207 | slr %r0,%r0 |
208 | stc %r0,0(%r2,%r3) # terminate buffer | |
1da177e4 LT |
209 | .Lnopf: |
210 | ||
211 | # | |
212 | # load ramdisk from ipl device | |
25d83cbf | 213 | # |
1da177e4 | 214 | .Lagain2: |
25d83cbf HC |
215 | l %r2,.Linitrd # addr of ramdisk |
216 | st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) | |
217 | bas %r14,.Lloader # load ramdisk | |
218 | st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of rd | |
219 | ltr %r2,%r2 | |
220 | bnz .Lrdcont | |
221 | st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found | |
1da177e4 | 222 | .Lrdcont: |
25d83cbf | 223 | l %r2,.Linitrd |
1da177e4 | 224 | |
25d83cbf HC |
225 | clc 0(3,%r2),.L_hdr # skip HDRx and EOFx |
226 | bz .Lagain2 | |
227 | clc 0(3,%r2),.L_eof | |
228 | bz .Lagain2 | |
1da177e4 | 229 | |
1da177e4 LT |
230 | # |
231 | # reset files in VM reader | |
232 | # | |
51eee033 MS |
233 | stidp .Lcpuid # store cpuid |
234 | tm .Lcpuid,0xff # running VM ? | |
25d83cbf HC |
235 | bno .Lnoreset |
236 | la %r2,.Lreset | |
237 | lhi %r3,26 | |
238 | diag %r2,%r3,8 | |
239 | la %r5,.Lirb | |
240 | stsch 0(%r5) # check if irq is pending | |
241 | tm 30(%r5),0x0f # by verifying if any of the | |
242 | bnz .Lwaitforirq # activity or status control | |
243 | tm 31(%r5),0xff # bits is set in the schib | |
244 | bz .Lnoreset | |
350e3ade | 245 | .Lwaitforirq: |
51eee033 | 246 | bas %r14,.Lirqwait # wait for IO interrupt |
34ba2450 | 247 | c %r1,__LC_SUBCHANNEL_ID # compare subchannel number |
51eee033 | 248 | bne .Lwaitforirq |
25d83cbf HC |
249 | la %r5,.Lirb |
250 | tsch 0(%r5) | |
1da177e4 | 251 | .Lnoreset: |
25d83cbf | 252 | b .Lnoload |
2b071886 | 253 | |
1da177e4 LT |
254 | # |
255 | # everything loaded, go for it | |
256 | # | |
257 | .Lnoload: | |
25d83cbf HC |
258 | l %r1,.Lstartup |
259 | br %r1 | |
1da177e4 | 260 | |
e033b9a0 | 261 | .Linitrd:.long _end # default address of initrd |
1da177e4 LT |
262 | .Lparm: .long PARMAREA |
263 | .Lstartup: .long startup | |
25d83cbf HC |
264 | .Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 |
265 | .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 | |
266 | .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" | |
267 | .L_eof: .long 0xc5d6c600 /* C'EOF' */ | |
268 | .L_hdr: .long 0xc8c4d900 /* C'HDR' */ | |
51eee033 MS |
269 | .align 8 |
270 | .Lcpuid:.fill 8,1,0 | |
1da177e4 | 271 | |
e37f50e1 MS |
272 | # |
273 | # startup-code at 0x10000, running in absolute addressing mode | |
274 | # this is called either by the ipl loader or directly by PSW restart | |
275 | # or linload or SALIPL | |
276 | # | |
277 | .org 0x10000 | |
144d634a | 278 | ENTRY(startup) |
60a0c68d | 279 | j .Lep_startup_normal |
627c9b62 | 280 | .org EP_OFFSET |
60a0c68d MH |
281 | # |
282 | # This is a list of s390 kernel entry points. At address 0x1000f the number of | |
283 | # valid entry points is stored. | |
284 | # | |
285 | # IMPORTANT: Do not change this table, it is s390 kernel ABI! | |
286 | # | |
627c9b62 | 287 | .ascii EP_STRING |
60a0c68d MH |
288 | .byte 0x00,0x01 |
289 | # | |
290 | # kdump startup-code at 0x10010, running in 64 bit absolute addressing mode | |
291 | # | |
292 | .org 0x10010 | |
293 | ENTRY(startup_kdump) | |
294 | j .Lep_startup_kdump | |
295 | .Lep_startup_normal: | |
51eee033 MS |
296 | mvi __LC_AR_MODE_ID,1 # set esame flag |
297 | slr %r0,%r0 # set cpuid to zero | |
298 | lhi %r1,2 # mode 2 = esame (dump) | |
299 | sigp %r1,%r0,0x12 # switch to esame mode | |
300 | bras %r13,0f | |
301 | .fill 16,4,0x0 | |
302 | 0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs | |
c6eafbf9 | 303 | sam64 # switch to 64 bit addressing mode |
1844c9bc | 304 | basr %r13,0 # get base |
e37f50e1 | 305 | .LPG0: |
866ba284 MS |
306 | xc 0x200(256),0x200 # partially clear lowcore |
307 | xc 0x300(256),0x300 | |
60a0c68d | 308 | xc 0xe00(256),0xe00 |
76cdd44c | 309 | xc 0xf00(256),0xf00 |
a80313ff | 310 | lctlg %c0,%c15,.Lctl-.LPG0(%r13) # load control registers |
6e2ef5e4 MS |
311 | stcke __LC_BOOT_CLOCK |
312 | mvc __LC_LAST_UPDATE_CLOCK(8),__LC_BOOT_CLOCK+1 | |
991c1505 HC |
313 | spt 6f-.LPG0(%r13) |
314 | mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13) | |
be2412c2 | 315 | l %r15,.Lstack-.LPG0(%r13) |
be2412c2 | 316 | brasl %r14,verify_facilities |
8f75582a | 317 | brasl %r14,startup_kernel |
51eee033 | 318 | |
be2412c2 | 319 | .Lstack: |
19733fe8 | 320 | .long 0x8000 + (1<<(PAGE_SHIFT+BOOT_STACK_ORDER)) - STACK_FRAME_OVERHEAD |
ab96e798 | 321 | .align 8 |
991c1505 | 322 | 6: .long 0x7fffffff,0xffffffff |
e37f50e1 | 323 | |
a80313ff GS |
324 | .Lctl: .quad 0x04040000 # cr0: AFP registers & secondary space |
325 | .quad 0 # cr1: primary space segment table | |
326 | .quad .Lduct # cr2: dispatchable unit control table | |
327 | .quad 0 # cr3: instruction authorization | |
328 | .quad 0xffff # cr4: instruction authorization | |
329 | .quad .Lduct # cr5: primary-aste origin | |
330 | .quad 0 # cr6: I/O interrupts | |
331 | .quad 0 # cr7: secondary space segment table | |
17248ea0 | 332 | .quad 0x0000000000008000 # cr8: access registers translation |
a80313ff GS |
333 | .quad 0 # cr9: tracing off |
334 | .quad 0 # cr10: tracing off | |
335 | .quad 0 # cr11: tracing off | |
336 | .quad 0 # cr12: tracing off | |
337 | .quad 0 # cr13: home space segment table | |
338 | .quad 0xc0000000 # cr14: machine check handling off | |
339 | .quad .Llinkage_stack # cr15: linkage stack operations | |
340 | ||
341 | .section .dma.data,"aw",@progbits | |
342 | .Lduct: .long 0,.Laste,.Laste,0,.Lduald,0,0,0 | |
343 | .long 0,0,0,0,0,0,0,0 | |
344 | .Llinkage_stack: | |
345 | .long 0,0,0x89000000,0,0,0,0x8a000000,0 | |
346 | .align 64 | |
347 | .Laste: .quad 0,0xffffffffffffffff,0,0,0,0,0,0 | |
348 | .align 128 | |
349 | .Lduald:.rept 8 | |
350 | .long 0x80000000,0,0,0 # invalid access-list entries | |
351 | .endr | |
352 | .previous | |
353 | ||
60a0c68d MH |
354 | #include "head_kdump.S" |
355 | ||
da9ed30d VG |
356 | # |
357 | # This program check is active immediately after kernel start | |
358 | # and until early_pgm_check_handler is set in kernel/early.c | |
359 | # It simply saves general/control registers and psw in | |
360 | # the save area and does disabled wait with a faulty address. | |
361 | # | |
362 | ENTRY(startup_pgm_check_handler) | |
363 | stmg %r0,%r15,__LC_SAVE_AREA_SYNC | |
364 | la %r1,4095 | |
365 | stctg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1) | |
366 | mvc __LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC | |
367 | mvc __LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW | |
da9ed30d VG |
368 | mvc __LC_RETURN_PSW(16),__LC_PGM_OLD_PSW |
369 | ni __LC_RETURN_PSW,0xfc # remove IO and EX bits | |
370 | ni __LC_RETURN_PSW+1,0xfb # remove MCHK bit | |
371 | oi __LC_RETURN_PSW+1,0x2 # set wait state bit | |
724dc336 VG |
372 | larl %r2,.Lold_psw_disabled_wait |
373 | stg %r2,__LC_PGM_NEW_PSW+8 | |
374 | l %r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r2) | |
375 | brasl %r14,print_pgm_check_info | |
376 | .Lold_psw_disabled_wait: | |
377 | la %r1,4095 | |
378 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) | |
da9ed30d | 379 | lpswe __LC_RETURN_PSW # disabled wait |
724dc336 VG |
380 | .Ldump_info_stack: |
381 | .long 0x5000 + PAGE_SIZE - STACK_FRAME_OVERHEAD | |
da9ed30d VG |
382 | ENDPROC(startup_pgm_check_handler) |
383 | ||
e37f50e1 MS |
384 | # |
385 | # params at 10400 (setup.h) | |
d0d249d7 | 386 | # Must be keept in sync with struct parmarea in setup.h |
e37f50e1 MS |
387 | # |
388 | .org PARMAREA | |
d0d249d7 PR |
389 | .quad 0 # IPL_DEVICE |
390 | .quad 0 # INITRD_START | |
391 | .quad 0 # INITRD_SIZE | |
392 | .quad 0 # OLDMEM_BASE | |
393 | .quad 0 # OLDMEM_SIZE | |
6abe2819 | 394 | .quad kernel_version # points to kernel version string |
e37f50e1 MS |
395 | |
396 | .org COMMAND_LINE | |
397 | .byte "root=/dev/ram0 ro" | |
398 | .byte 0 | |
399 | ||
087c4d74 GS |
400 | .org EARLY_SCCB_OFFSET |
401 | .fill 4096 | |
402 | ||
403 | .org HEAD_END |