2 # s390-tools/zipl/boot/menu.S
3 # Interactive boot menu.
5 # Copyright IBM Corp. 2004, 2006.
7 # Author(s): Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
11 LC_CPUID = 0xC60 # low core addres for cpu id
13 MENU_PARM_LENGTH = 896 # max length of parmline
14 MENU_PARMLINE = 0xA000-0x400 # address for additional params
15 MENU_TEMP_AREA = 0x5000 # address for temp storage
17 MENU_PARAM_FLAG = 0 # offset of flag parameter
18 MENU_PARAM_TIMEOUT = 2 # offset of timeout parameter
19 MENU_PARAM_BANNER = 4 # offset of banner parameter
20 MENU_PARAM_CONFIG = 6 # offset of config parameter
32 # Subroutine which implements an interactive boot menu.
35 # R2 = configuration number to boot
39 stm %r6,%r15,24(%r15) # save registers
40 stidp LC_CPUID # need CPUID for VM check
42 basr %r13,0 # get base register
44 ahi %r15,-96 # create stack frame
46 l %r6,.LparmareaM0-.LbaseM1(%r13) # get menu param area address
48 sr %r8,%r8 # default config = 0
50 l %r7,.LparmlineM0-.LbaseM1(%r13) # get address for parmline
51 xc 0(256,%r7),0(%r7) # clear parmline area
52 xc 256(256,%r7),256(%r7)
53 xc 512(256,%r7),512(%r7)
54 xc 768(256,%r7),768(%r7)
56 sr %r2,%r2 # initialize sclp
58 ltr %r2,%r2 # init succeeded?
61 bras %r14,_menu_param # get loadparm
63 ltr %r2,%r2 # got number?
66 lr %r8,%r3 # save configuration number
70 chi %r2,1 # got keyword?
73 ltr %r3,%r3 # keyword 'PROMPT'?
77 lh %r1,MENU_PARAM_FLAG(%r6)
78 ltr %r1,%r1 # is menu enabled?
79 jz .LendmenuM1 # nope, skip it
82 lh %r2,MENU_PARAM_BANNER(%r6) # print banner
86 bras %r14,_menu_list # print config list
88 tm LC_CPUID,0xff # check for VM
91 la %r2,.Ltext1M0-.LbaseM1(%r13) # print VM note
95 lr %r2,%r6 # print menu prompt
97 lr %r8,%r2 # save menu result
100 chi %r8,0 # make sure number is correct
107 lpsw .LpswM1-.LbaseM1(%r13) # indicate invalid config
110 l %r2,.LtempareaM0-.LbaseM1(%r13) # print config name
111 mvc 0(.Ltext5M0-.Ltext2M0,%r2),.Ltext2M0-.LbaseM1(%r13)
113 la %r3,.Ltext4M0-.Ltext2M0(%r2)
114 la %r4,MENU_PARAM_CONFIG(%r6) # address of first config text
116 lr %r0,%r8 # get offset for config
120 lh %r4,0(%r4) # get address
121 ltr %r4,%r4 # valid configuration?
125 lr %r9,%r4 # save number string address
126 ahi %r4,4 # skip number string
128 sr %r0,%r0 # temp = 0
129 sr %r1,%r1 # index = 0
131 ic %r0,0(%r1,%r4) # copy config name
140 mvc 0(.Ltext5M0-.Ltext4M0,%r3),.Ltext4M0-.LbaseM1(%r13)
143 bras %r14,_sclp_print
145 # append "BOOT_IMAGE=<num>" to parameter line
149 lr %r2,%r7 # address of extra parmline
150 lhi %r3,MENU_PARM_LENGTH
161 chi %r1,MENU_PARM_LENGTH-(.Ltext12M0-.Ltext11M0+3)
162 jhe .LcleanupM1 # parmline too long
164 ar %r2,%r1 # append " BOOT_IMAGE="
165 mvc 0(.Ltext12M0-.Ltext11M0,%r2),.Ltext11M0-.LbaseM1(%r13)
166 ahi %r2,.Ltext12M0-.Ltext11M0
168 ic %r0,0(%r9) # skip leading blank
172 stc %r0,0(%r2) # store first digit
176 mvc 0(1,%r2),1(%r9) # store second digit
179 xc 0(1,%r2),0(%r2) # append null byte
182 la %r2,1 # cleanup sclp interface
183 bras %r14,_sclp_setup
186 lr %r2,%r8 # get menu result
187 lm %r6,%r15,120(%r15) # restore registers
193 .long 0x000a0000,0x00000300 # PSW to indicate invalid config
197 # Subroutine which prints out the list of available boot configurations.
201 stm %r6,%r15,24(%r15) # save registers
203 basr %r13,0 # get base register
205 ahi %r15,-96 # create stack frame
207 l %r8,.LparmareaM0-.LbaseM2(%r13) # get menu param area address
208 la %r6,63 # number of configs
209 la %r7,MENU_PARAM_CONFIG(%r8) # address of first config text
213 lh %r2,0(%r9,%r7) # get offset for config name
214 ltr %r2,%r2 # no config name?
215 jz .LemptyconfigM2 # skip
217 ar %r2,%r8 # print config name
218 bras %r14,_sclp_print
220 ltr %r9,%r9 # first config?
221 jnz .LemptyconfigM2 # no, skip
223 la %r2,.Ltext5M0-.LbaseM2(%r13) # print empty line
224 bras %r14,_sclp_print
227 ahi %r9,2 # increase config name offset
230 la %r2,.Ltext5M0-.LbaseM2(%r13) # print empty line
231 bras %r14,_sclp_print
233 lm %r6,%r15,120(%r15) # restore registers
239 # Subroutine which prints out the boot prompt.
243 stm %r6,%r15,24(%r15) # save registers
245 basr %r13,0 # get base register
247 ahi %r15,-96 # create stack frame
249 l %r2,.LparmareaM0-.LbaseM3(%r13) # get menu param area address
250 lh %r0,MENU_PARAM_TIMEOUT(%r2) # get timeout value
252 l %r3,.LtempareaM0-.LbaseM3(%r13) # get temp area
253 lr %r2,%r3 # save temp area
255 xc 0(.Ltext10M0-.Ltext6M0+16,%r3),0(%r3) # clear temp area
258 mvc 0(.Ltext7M0-.Ltext6M0,%r3),.Ltext6M0-.LbaseM3(%r13)
259 ahi %r3,.Ltext7M0-.Ltext6M0
261 ltr %r0,%r0 # timeout set?
262 jz .LnotimeoutM3 # no, skip
265 mvc 0(.Ltext8M0-.Ltext7M0,%r3),.Ltext7M0-.LbaseM3(%r13)
266 ahi %r3,.Ltext8M0-.Ltext7M0
268 cvd %r0,.LdecimalM3-.LbaseM3(%r13) # convert to EBCDIC number
269 unpk 0(16,%r3),.LdecimalM3-.LbaseM3(8,%r13)
273 ic %r0,0(%r3) # remove leading zeroes
275 chi %r0,0xf0 # leading zero?
278 mvc 0(16,%r3),1(%r3) # remove zero
282 ic %r0,0(%r3) # skip digits
284 ltr %r0,%r0 # end of string?
287 oi 0(%r3),0xf0 # overwrite sign zone
294 mvc 0(.Ltext9M0-.Ltext8M0,%r3),.Ltext8M0-.LbaseM3(%r13)
295 ahi %r3,.Ltext9M0-.Ltext8M0
299 mvc 0(.Ltext10M0-.Ltext9M0,%r3),.Ltext9M0-.LbaseM3(%r13)
301 bras %r14,_sclp_print # print prompt
303 lm %r6,%r15,120(%r15) # restore registers
312 # Subroutine which reads and interprets user input.
315 # R2 = configuration number to boot
319 stm %r6,%r15,24(%r15) # save registers
321 basr %r13,0 # get base register
323 ahi %r15,-96 # create stack frame
325 l %r6,.LparmareaM0-.LbaseM4(%r13) # get menu param area address
326 l %r7,.LtempareaM0-.LbaseM4(%r13) # get temp area = input area
329 bras %r14,_menu_prompt # print menu prompt
331 lh %r2,MENU_PARAM_TIMEOUT(%r6) # get timeout value
335 ltr %r2,%r2 # got input?
338 sth %r2,MENU_PARAM_TIMEOUT(%r6) # deactivate timeout
340 ltr %r8,%r3 # save input length
343 tm LC_CPUID,0xff # VM?
344 jno .LnotolowerM4 # no, skip
346 lr %r2,%r7 # convert input to lower case
347 bras %r14,_menu_tolower
350 lr %r2,%r7 # get number
354 ltr %r9,%r4 # save and test valid flag
357 ltr %r1,%r5 # check for valid configuration
358 jl .LnoconfigM4 # negative value?
360 chi %r1,62 # too high?
363 sll %r1,1 # get offset into menu param
364 lh %r1,MENU_PARAM_CONFIG(%r1,%r6) # get text offset
365 ltr %r1,%r1 # available?
368 ltr %r3,%r3 # check for additional params
372 l %r4,.LparmlineM0-.LbaseM4(%r13) # get address for parmline
375 ic %r0,0(%r2) # copy rest of parmline
379 brct %r3,.LcopyaddparamM4
386 la %r2,.Ltext10M0-.LbaseM4(%r13) # "Error: undefined config.."
387 bras %r14,_sclp_print
392 sr %r2,%r2 # set default configuration
395 lm %r6,%r15,120(%r15) # restore registers
401 # Subroutine to convert an EBCDIC string to all lower case.
404 # R2 = address of EBCDIC string
405 # R3 = length of string
412 ic %r0,0(%r2) # convert input to lowercase
414 chi %r0,0xc1 # 'A' - 'I'
420 chi %r0,0xd1 # 'J' - 'R'
426 chi %r0,0xe2 # 'S' - 'Z'
433 ni 0(%r2),0xbf # remove upper case bit
436 ahi %r2,1 # next char
443 # Subroutine to parse an EBCDIC string as a decimal integer number.
446 # R2 = address of EBCDIC string
447 # R3 = length of string
450 # R2 = address of rest of EBCDIC string after number
451 # R3 = remaining length of string after number
452 # R4 = 0 if valid number was found, non-zero otherwise
453 # R5 = number if R4 = 0
458 lhi %r4,1 # non-success return code
459 sr %r5,%r5 # resulting number
462 ic %r0,0(%r2) # skip leading spaces
464 chi %r0,0x40 # is current char a space?
467 ahi %r2,1 # skip spaces
468 brct %r3,.LskipspaceM6
470 j .LendM6 # reached end of string
478 chi %r0,0x40 # got a space?
479 je .LgotnumberM6 # valid end of number separator
481 chi %r0,0xf0 # got a digit?
487 mhi %r5,10 # current number * 10
489 nr %r0,%r1 # add digit
492 ahi %r2,1 # next character
493 brct %r3,.LtonumberM6 # until end of input string
503 # Subroutine used to interpret load parameter.
506 # R2 = 0 if a number was found, 1 if a keyword was found, 2 otherwise
507 # R3 = number value if R2=0, keyword number if R2=1
511 stm %r6,%r15,24(%r15) # save registers
513 basr %r13,0 # get base register
515 ahi %r15,-96 # create stack frame
517 la %r6,.LparamM7-.LbaseM7(%r13) # parameter area
519 lr %r2,%r6 # retrieve load parameter
520 bras %r14,_sclp_param
522 ltr %r2,%r2 # success?
525 lr %r2,%r6 # try to parse number
529 ltr %r2,%r4 # got number?
533 lhi %r1,8 # remove trailing spaces
537 cli 0(%r2),0x40 # got space?
540 xc 0(1,%r2),0(%r2) # write zero
542 ahi %r2,-1 # check next char
543 brct %r1,.LremblanksM7
546 lr %r2,%r6 # convert loadparm to lowercase
548 bras %r14,_menu_tolower
551 sr %r0,%r0 # set ending char to '\0'
552 lr %r2,%r6 # get param address
553 la %r3,.LkeypromptM7-.LbaseM7(%r13) # get keyword address
554 clst %r2,%r3 # compare strings until '\0'
555 brc 7,.LerrorM7 # not equal
557 lhi %r2,1 # found keyword
566 lm %r6,%r15,120(%r15) # restore registers
571 .byte 0,0,0,0,0,0,0,0 # room for the load parameter
575 .byte 0x97, 0x99, 0x96, 0x94, 0x97, 0xa3, 0x00
592 # "Note: VM users please use '#cp vi vmsg <input>'\n"
593 .byte 0xd5, 0x96, 0xa3, 0x85, 0x7a, 0x40, 0xe5, 0xd4, 0x40, 0xa4
594 .byte 0xa2, 0x85, 0x99, 0xa2, 0x40, 0x97, 0x93, 0x85, 0x81, 0xa2
595 .byte 0x85, 0x40, 0xa4, 0xa2, 0x85, 0x40, 0x7d, 0x7b, 0x83, 0x97
596 .byte 0x40, 0xa5, 0x89, 0x40, 0xa5, 0x94, 0xa2, 0x87, 0x40, 0x4c
597 .byte 0x89, 0x95, 0x97, 0xa4, 0xa3, 0x6e, 0x7d, 0x15, 0x40, 0x00
600 .byte 0xc2, 0x96, 0x96, 0xa3, 0x89, 0x95, 0x87, 0x40
603 .byte 0x4b, 0x4b, 0x4b, 0x00
609 .byte 0xd7, 0x93, 0x85, 0x81, 0xa2, 0x85, 0x40, 0x83, 0x88, 0x96
610 .byte 0x96, 0xa2, 0x85
612 # " (default will boot in "
613 .byte 0x40, 0x4d, 0x84, 0x85, 0x86, 0x81, 0xa4, 0x93, 0xa3, 0x40
614 .byte 0xa6, 0x89, 0x93, 0x93, 0x40, 0x82, 0x96, 0x96, 0xa3, 0x40
615 .byte 0x89, 0x95, 0x40
618 .byte 0x40, 0xa2, 0x85, 0x83, 0x96, 0x95, 0x84, 0xa2, 0x5d
623 # "Error: undefined configuration\n"
624 .byte 0xc5, 0x99, 0x99, 0x96, 0x99, 0x7a, 0x40, 0xa4, 0x95, 0x84
625 .byte 0x85, 0x86, 0x89, 0x95, 0x85, 0x84, 0x40, 0x83, 0x96, 0x95
626 .byte 0x86, 0x89, 0x87, 0xa4, 0x99, 0x81, 0xa3, 0x89, 0x96, 0x95
627 .byte 0x15, 0x40, 0x00
630 .byte 0x40, 0xc2, 0xd6, 0xd6, 0xe3, 0x6d, 0xc9, 0xd4, 0xc1, 0xc7
636 .macro menu_param_area