diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2009-06-12 04:26:24 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-12 04:27:30 -0400 |
commit | d90cbd469c9c7c1494fc2084af9319e6a557368b (patch) | |
tree | efb312e668fa596a0493f5318c19d07795e3a8b0 /arch/s390/kernel/sclp.S | |
parent | 8c4caa4fbfc18aa50d9d682f502303a8e0d72726 (diff) |
[S390] add mini sclp driver
This adds a mini sclp device driver for very early use. The primary
and probably only use will be to emit a message to the console if the
cpu doesn't provide the minimum required capabilities to run the kernel.
After printing the message a disabled wait will be loaded and the
machine stops operating.
Printing the message is also part of this patch.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/sclp.S')
-rw-r--r-- | arch/s390/kernel/sclp.S | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S new file mode 100644 index 000000000000..20639dfe0c42 --- /dev/null +++ b/arch/s390/kernel/sclp.S | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * Mini SCLP driver. | ||
3 | * | ||
4 | * Copyright IBM Corp. 2004,2009 | ||
5 | * | ||
6 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>, | ||
7 | * Heiko Carstens <heiko.carstens@de.ibm.com>, | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | LC_EXT_NEW_PSW = 0x58 # addr of ext int handler | ||
12 | LC_EXT_INT_PARAM = 0x80 # addr of ext int parameter | ||
13 | LC_EXT_INT_CODE = 0x86 # addr of ext int code | ||
14 | |||
15 | # | ||
16 | # Subroutine which waits synchronously until either an external interruption | ||
17 | # or a timeout occurs. | ||
18 | # | ||
19 | # Parameters: | ||
20 | # R2 = 0 for no timeout, non-zero for timeout in (approximated) seconds | ||
21 | # | ||
22 | # Returns: | ||
23 | # R2 = 0 on interrupt, 2 on timeout | ||
24 | # R3 = external interruption parameter if R2=0 | ||
25 | # | ||
26 | |||
27 | .section ".init.text","ax" | ||
28 | |||
29 | _sclp_wait_int: | ||
30 | stm %r6,%r15,24(%r15) # save registers | ||
31 | basr %r13,0 # get base register | ||
32 | .LbaseS1: | ||
33 | ahi %r15,-96 # create stack frame | ||
34 | la %r8,LC_EXT_NEW_PSW # register int handler | ||
35 | mvc .LoldpswS1-.LbaseS1(8,%r13),0(%r8) | ||
36 | mvc 0(8,%r8),.LextpswS1-.LbaseS1(%r13) | ||
37 | lhi %r6,0x0200 # cr mask for ext int (cr0.54) | ||
38 | ltr %r2,%r2 | ||
39 | jz .LsetctS1 | ||
40 | ahi %r6,0x0800 # cr mask for clock int (cr0.52) | ||
41 | stck .LtimeS1-.LbaseS1(%r13) # initiate timeout | ||
42 | al %r2,.LtimeS1-.LbaseS1(%r13) | ||
43 | st %r2,.LtimeS1-.LbaseS1(%r13) | ||
44 | sckc .LtimeS1-.LbaseS1(%r13) | ||
45 | |||
46 | .LsetctS1: | ||
47 | stctl %c0,%c0,.LctlS1-.LbaseS1(%r13) # enable required interrupts | ||
48 | l %r0,.LctlS1-.LbaseS1(%r13) | ||
49 | lhi %r1,~(0x200 | 0x800) # clear old values | ||
50 | nr %r1,%r0 | ||
51 | or %r1,%r6 # set new value | ||
52 | st %r1,.LctlS1-.LbaseS1(%r13) | ||
53 | lctl %c0,%c0,.LctlS1-.LbaseS1(%r13) | ||
54 | st %r0,.LctlS1-.LbaseS1(%r13) | ||
55 | lhi %r2,2 # return code for timeout | ||
56 | .LloopS1: | ||
57 | lpsw .LwaitpswS1-.LbaseS1(%r13) # wait until interrupt | ||
58 | .LwaitS1: | ||
59 | lh %r7,LC_EXT_INT_CODE | ||
60 | chi %r7,0x1004 # timeout? | ||
61 | je .LtimeoutS1 | ||
62 | chi %r7,0x2401 # service int? | ||
63 | jne .LloopS1 | ||
64 | sr %r2,%r2 | ||
65 | l %r3,LC_EXT_INT_PARAM | ||
66 | .LtimeoutS1: | ||
67 | lctl %c0,%c0,.LctlS1-.LbaseS1(%r13) # restore interrupt setting | ||
68 | # restore old handler | ||
69 | mvc 0(8,%r8),.LoldpswS1-.LbaseS1(%r13) | ||
70 | lm %r6,%r15,120(%r15) # restore registers | ||
71 | br %r14 # return to caller | ||
72 | |||
73 | .align 8 | ||
74 | .LoldpswS1: | ||
75 | .long 0, 0 # old ext int PSW | ||
76 | .LextpswS1: | ||
77 | .long 0x00080000, 0x80000000+.LwaitS1 # PSW to handle ext int | ||
78 | .LwaitpswS1: | ||
79 | .long 0x010a0000, 0x00000000+.LloopS1 # PSW to wait for ext int | ||
80 | .LtimeS1: | ||
81 | .quad 0 # current time | ||
82 | .LctlS1: | ||
83 | .long 0 # CT0 contents | ||
84 | |||
85 | # | ||
86 | # Subroutine to synchronously issue a service call. | ||
87 | # | ||
88 | # Parameters: | ||
89 | # R2 = command word | ||
90 | # R3 = sccb address | ||
91 | # | ||
92 | # Returns: | ||
93 | # R2 = 0 on success, 1 on failure | ||
94 | # R3 = sccb response code if R2 = 0 | ||
95 | # | ||
96 | |||
97 | _sclp_servc: | ||
98 | stm %r6,%r15,24(%r15) # save registers | ||
99 | ahi %r15,-96 # create stack frame | ||
100 | lr %r6,%r2 # save command word | ||
101 | lr %r7,%r3 # save sccb address | ||
102 | .LretryS2: | ||
103 | lhi %r2,1 # error return code | ||
104 | .insn rre,0xb2200000,%r6,%r7 # servc | ||
105 | brc 1,.LendS2 # exit if not operational | ||
106 | brc 8,.LnotbusyS2 # go on if not busy | ||
107 | sr %r2,%r2 # wait until no longer busy | ||
108 | bras %r14,_sclp_wait_int | ||
109 | j .LretryS2 # retry | ||
110 | .LnotbusyS2: | ||
111 | sr %r2,%r2 # wait until result | ||
112 | bras %r14,_sclp_wait_int | ||
113 | sr %r2,%r2 | ||
114 | lh %r3,6(%r7) | ||
115 | .LendS2: | ||
116 | lm %r6,%r15,120(%r15) # restore registers | ||
117 | br %r14 | ||
118 | |||
119 | # | ||
120 | # Subroutine to set up the SCLP interface. | ||
121 | # | ||
122 | # Parameters: | ||
123 | # R2 = 0 to activate, non-zero to deactivate | ||
124 | # | ||
125 | # Returns: | ||
126 | # R2 = 0 on success, non-zero on failure | ||
127 | # | ||
128 | |||
129 | _sclp_setup: | ||
130 | stm %r6,%r15,24(%r15) # save registers | ||
131 | ahi %r15,-96 # create stack frame | ||
132 | basr %r13,0 # get base register | ||
133 | .LbaseS3: | ||
134 | l %r6,.LsccbS0-.LbaseS3(%r13) # prepare init mask sccb | ||
135 | mvc 0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13) | ||
136 | ltr %r2,%r2 # initialization? | ||
137 | jz .LdoinitS3 # go ahead | ||
138 | # clear masks | ||
139 | xc .LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6) | ||
140 | .LdoinitS3: | ||
141 | l %r2,.LwritemaskS3-.LbaseS3(%r13)# get command word | ||
142 | lr %r3,%r6 # get sccb address | ||
143 | bras %r14,_sclp_servc # issue service call | ||
144 | ltr %r2,%r2 # servc successful? | ||
145 | jnz .LerrorS3 | ||
146 | chi %r3,0x20 # write mask successful? | ||
147 | jne .LerrorS3 | ||
148 | # check masks | ||
149 | la %r2,.LinitmaskS3-.LinitsccbS3(%r6) | ||
150 | l %r1,0(%r2) # receive mask ok? | ||
151 | n %r1,12(%r2) | ||
152 | cl %r1,0(%r2) | ||
153 | jne .LerrorS3 | ||
154 | l %r1,4(%r2) # send mask ok? | ||
155 | n %r1,8(%r2) | ||
156 | cl %r1,4(%r2) | ||
157 | sr %r2,%r2 | ||
158 | je .LendS3 | ||
159 | .LerrorS3: | ||
160 | lhi %r2,1 # error return code | ||
161 | .LendS3: | ||
162 | lm %r6,%r15,120(%r15) # restore registers | ||
163 | br %r14 | ||
164 | .LwritemaskS3: | ||
165 | .long 0x00780005 # SCLP command for write mask | ||
166 | .LinitsccbS3: | ||
167 | .word .LinitendS3-.LinitsccbS3 | ||
168 | .byte 0,0,0,0 | ||
169 | .word 0 | ||
170 | .word 0 | ||
171 | .word 4 | ||
172 | .LinitmaskS3: | ||
173 | .long 0x80000000 | ||
174 | .long 0x40000000 | ||
175 | .long 0 | ||
176 | .long 0 | ||
177 | .LinitendS3: | ||
178 | |||
179 | # | ||
180 | # Subroutine which prints a given text to the SCLP console. | ||
181 | # | ||
182 | # Parameters: | ||
183 | # R2 = address of nil-terminated ASCII text | ||
184 | # | ||
185 | # Returns: | ||
186 | # R2 = 0 on success, 1 on failure | ||
187 | # | ||
188 | |||
189 | _sclp_print: | ||
190 | stm %r6,%r15,24(%r15) # save registers | ||
191 | ahi %r15,-96 # create stack frame | ||
192 | basr %r13,0 # get base register | ||
193 | .LbaseS4: | ||
194 | l %r8,.LsccbS0-.LbaseS4(%r13) # prepare write data sccb | ||
195 | mvc 0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13) | ||
196 | la %r7,.LmtoS4-.LwritesccbS4(%r8) # current mto addr | ||
197 | sr %r0,%r0 | ||
198 | l %r10,.Lascebc-.LbaseS4(%r13) # address of translation table | ||
199 | .LinitmtoS4: | ||
200 | # initialize mto | ||
201 | mvc 0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13) | ||
202 | lhi %r6,.LmtoendS4-.LmtoS4 # current mto length | ||
203 | .LloopS4: | ||
204 | ic %r0,0(%r2) # get character | ||
205 | ahi %r2,1 | ||
206 | ltr %r0,%r0 # end of string? | ||
207 | jz .LfinalizemtoS4 | ||
208 | chi %r0,0x15 # end of line (NL)? | ||
209 | jz .LfinalizemtoS4 | ||
210 | stc %r0,0(%r6,%r7) # copy to mto | ||
211 | la %r11,0(%r6,%r7) | ||
212 | tr 0(1,%r11),0(%r10) # translate to EBCDIC | ||
213 | ahi %r6,1 | ||
214 | j .LloopS4 | ||
215 | .LfinalizemtoS4: | ||
216 | sth %r6,0(%r7) # update mto length | ||
217 | lh %r9,.LmdbS4-.LwritesccbS4(%r8) # update mdb length | ||
218 | ar %r9,%r6 | ||
219 | sth %r9,.LmdbS4-.LwritesccbS4(%r8) | ||
220 | lh %r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length | ||
221 | ar %r9,%r6 | ||
222 | sth %r9,.LevbufS4-.LwritesccbS4(%r8) | ||
223 | lh %r9,0(%r8) # update sccb length | ||
224 | ar %r9,%r6 | ||
225 | sth %r9,0(%r8) | ||
226 | ar %r7,%r6 # update current mto adress | ||
227 | ltr %r0,%r0 # more characters? | ||
228 | jnz .LinitmtoS4 | ||
229 | l %r2,.LwritedataS4-.LbaseS4(%r13)# write data | ||
230 | lr %r3,%r8 | ||
231 | bras %r14,_sclp_servc | ||
232 | ltr %r2,%r2 # servc successful? | ||
233 | jnz .LendS4 | ||
234 | chi %r3,0x20 # write data successful? | ||
235 | je .LendS4 | ||
236 | lhi %r2,1 # error return code | ||
237 | .LendS4: | ||
238 | lm %r6,%r15,120(%r15) # restore registers | ||
239 | br %r14 | ||
240 | |||
241 | # | ||
242 | # Function which prints a given text to the SCLP console. | ||
243 | # | ||
244 | # Parameters: | ||
245 | # R2 = address of nil-terminated ASCII text | ||
246 | # | ||
247 | # Returns: | ||
248 | # R2 = 0 on success, 1 on failure | ||
249 | # | ||
250 | |||
251 | .globl _sclp_print_early | ||
252 | _sclp_print_early: | ||
253 | stm %r6,%r15,24(%r15) # save registers | ||
254 | ahi %r15,-96 # create stack frame | ||
255 | lr %r10,%r2 # save string pointer | ||
256 | lhi %r2,0 | ||
257 | bras %r14,_sclp_setup # enable console | ||
258 | ltr %r2,%r2 | ||
259 | jnz .LendS5 | ||
260 | lr %r2,%r10 | ||
261 | bras %r14,_sclp_print # print string | ||
262 | ltr %r2,%r2 | ||
263 | jnz .LendS5 | ||
264 | lhi %r2,1 | ||
265 | bras %r14,_sclp_setup # disable console | ||
266 | .LendS5: | ||
267 | lm %r6,%r15,120(%r15) # restore registers | ||
268 | br %r14 | ||
269 | |||
270 | .LwritedataS4: | ||
271 | .long 0x00760005 # SCLP command for write data | ||
272 | .LwritesccbS4: | ||
273 | # sccb | ||
274 | .word .LmtoS4-.LwritesccbS4 | ||
275 | .byte 0 | ||
276 | .byte 0,0,0 | ||
277 | .word 0 | ||
278 | |||
279 | # evbuf | ||
280 | .LevbufS4: | ||
281 | .word .LmtoS4-.LevbufS4 | ||
282 | .byte 0x02 | ||
283 | .byte 0 | ||
284 | .word 0 | ||
285 | |||
286 | .LmdbS4: | ||
287 | # mdb | ||
288 | .word .LmtoS4-.LmdbS4 | ||
289 | .word 1 | ||
290 | .long 0xd4c4c240 | ||
291 | .long 1 | ||
292 | |||
293 | # go | ||
294 | .LgoS4: | ||
295 | .word .LmtoS4-.LgoS4 | ||
296 | .word 1 | ||
297 | .long 0 | ||
298 | .byte 0,0,0,0,0,0,0,0 | ||
299 | .byte 0,0,0 | ||
300 | .byte 0 | ||
301 | .byte 0,0,0,0,0,0,0 | ||
302 | .byte 0 | ||
303 | .word 0 | ||
304 | .byte 0,0,0,0,0,0,0,0,0,0 | ||
305 | .byte 0,0,0,0,0,0,0,0 | ||
306 | .byte 0,0,0,0,0,0,0,0 | ||
307 | |||
308 | .LmtoS4: | ||
309 | .word .LmtoendS4-.LmtoS4 | ||
310 | .word 4 | ||
311 | .word 0x1000 | ||
312 | .byte 0 | ||
313 | .byte 0,0,0 | ||
314 | .LmtoendS4: | ||
315 | |||
316 | # Global constants | ||
317 | .LsccbS0: | ||
318 | .long _sclp_work_area | ||
319 | .Lascebc: | ||
320 | .long _ascebc | ||
321 | .previous | ||
322 | |||
323 | .section ".init.data","a" | ||
324 | .balign 4096 | ||
325 | _sclp_work_area: | ||
326 | .fill 4096 | ||
327 | .previous | ||