Import version 1.8.3
[s390-tools.git] / zipl / boot / menu.S
blobf1f40c227a45597dab3841fe4fe7b3c9bb3520c2
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
23 #include "sclp.S"
25         sclp_base
26         sclp_print
27         sclp_read
28         sclp_read_info
29         sclp_param
32 # Subroutine which implements an interactive boot menu.
34 # Returns:
35 #   R2  = configuration number to boot
38 _menu:
39         stm    %r6,%r15,24(%r15)                # save registers
40         stidp  LC_CPUID                         # need CPUID for VM check
42         basr   %r13,0                           # get base register
43 .LbaseM1:
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
57         bras   %r14,_sclp_setup
58         ltr    %r2,%r2                          # init succeeded?
59         jnz    .LendM1
61         bras   %r14,_menu_param                 # get loadparm
63         ltr    %r2,%r2                          # got number?
64         jnz    .LnonumberM1
66         lr     %r8,%r3                          # save configuration number
67         j      .LendmenuM1
69 .LnonumberM1:
70         chi    %r2,1                            # got keyword?
71         jne    .LnokeywordM1
73         ltr    %r3,%r3                          # keyword 'PROMPT'?
74         jz     .LdopromptM1
76 .LnokeywordM1:
77         lh     %r1,MENU_PARAM_FLAG(%r6)
78         ltr    %r1,%r1                          # is menu enabled?
79         jz     .LendmenuM1                      # nope, skip it
81 .LdopromptM1:
82         lh     %r2,MENU_PARAM_BANNER(%r6)       # print banner
83         ar     %r2,%r6
84         bras   %r14,_sclp_print
86         bras   %r14,_menu_list                  # print config list
88         tm     LC_CPUID,0xff                    # check for VM
89         jno    .LnovmnoteM1
91         la     %r2,.Ltext1M0-.LbaseM1(%r13)     # print VM note
92         bras   %r14,_sclp_print
94 .LnovmnoteM1:
95         lr     %r2,%r6                          # print menu prompt
96         bras   %r14,_menu_read
97         lr     %r8,%r2                          # save menu result
99 .LendmenuM1:
100         chi    %r8,0                            # make sure number is correct
101         jl     .LnumnotokM1
103         chi    %r8,62
104         jle    .LnumokM1
106 .LnumnotokM1:
107         lpsw   .LpswM1-.LbaseM1(%r13)           # indicate invalid config
109 .LnumokM1:
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
117         sll    %r0,1
118         ar     %r4,%r0
120         lh     %r4,0(%r4)                       # get address
121         ltr    %r4,%r4                          # valid configuration?
122         jz     .LnumnotokM1                     # no
124         ar     %r4,%r6
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
130 .LcopyloopM1:
131         ic     %r0,0(%r1,%r4)                   # copy config name
132         stc    %r0,0(%r1,%r3)
133         ltr    %r0,%r0
134         jz     .LendloopM1
135         ahi    %r1,1
136         j      .LcopyloopM1
138 .LendloopM1:
139         ar     %r3,%r1
140         mvc    0(.Ltext5M0-.Ltext4M0,%r3),.Ltext4M0-.LbaseM1(%r13)
142 .LprintconfM1:
143         bras   %r14,_sclp_print
145         # append "BOOT_IMAGE=<num>" to parameter line
147         sr     %r0,%r0
148         sr     %r1,%r1
149         lr     %r2,%r7                          # address of extra parmline
150         lhi    %r3,MENU_PARM_LENGTH
152 .LfindendM1:
153         ic     %r0,0(%r1,%r2)
154         ltr    %r0,%r0
155         jz     .LfoundendM1
156         ahi    %r1,1
157         brct   %r3,.LfindendM1
158         j      .LcleanupM1
160 .LfoundendM1:
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
169         chi    %r0,0x40
170         je     .LblankM1
172         stc    %r0,0(%r2)                       # store first digit
173         ahi    %r2,1
175 .LblankM1:
176         mvc    0(1,%r2),1(%r9)                  # store second digit
177         ahi    %r2,1
179         xc     0(1,%r2),0(%r2)                  # append null byte
181 .LcleanupM1:
182         la     %r2,1                            # cleanup sclp interface
183         bras   %r14,_sclp_setup
185 .LendM1:
186         lr     %r2,%r8                          # get menu result
187         lm     %r6,%r15,120(%r15)               # restore registers
189         br     %r14
191         .align 8
192 .LpswM1:
193         .long  0x000a0000,0x00000300            # PSW to indicate invalid config
197 # Subroutine which prints out the list of available boot configurations.
200 _menu_list:
201         stm    %r6,%r15,24(%r15)                # save registers
203         basr   %r13,0                           # get base register
204 .LbaseM2:
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
210         sr     %r9,%r9
212 .LloopM2:
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
226 .LemptyconfigM2:
227         ahi    %r9,2                            # increase config name offset
228         brct   %r6,.LloopM2
230         la     %r2,.Ltext5M0-.LbaseM2(%r13)     # print empty line
231         bras   %r14,_sclp_print
233         lm     %r6,%r15,120(%r15)               # restore registers
235         br     %r14
239 # Subroutine which prints out the boot prompt.
242 _menu_prompt:
243         stm    %r6,%r15,24(%r15)                # save registers
245         basr   %r13,0                           # get base register
246 .LbaseM3:
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
257         # "Please choose..."
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
264         # "default will.."
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)
271         sr     %r0,%r0
272 .LloopzeroesM3:
273         ic     %r0,0(%r3)                       # remove leading zeroes
275         chi    %r0,0xf0                         # leading zero?
276         jne    .LloopdigitsM3
278         mvc    0(16,%r3),1(%r3)                 # remove zero
279         j      .LloopzeroesM3
281 .LloopdigitsM3:
282         ic     %r0,0(%r3)                       # skip digits
284         ltr    %r0,%r0                          # end of string?
285         jz     .LendloopdigitsM3
287         oi     0(%r3),0xf0                      # overwrite sign zone
289         ahi    %r3,1
290         j      .LloopdigitsM3
292 .LendloopdigitsM3:
293         # " seconds"
294         mvc    0(.Ltext9M0-.Ltext8M0,%r3),.Ltext8M0-.LbaseM3(%r13)
295         ahi    %r3,.Ltext9M0-.Ltext8M0
297 .LnotimeoutM3:
298         # ":"
299         mvc    0(.Ltext10M0-.Ltext9M0,%r3),.Ltext9M0-.LbaseM3(%r13)
301         bras   %r14,_sclp_print                 # print prompt
303         lm     %r6,%r15,120(%r15)               # restore registers
305         br     %r14
307 .LdecimalM3:
308         .quad  0
312 # Subroutine which reads and interprets user input.
314 # Returns:
315 #   R2  = configuration number to boot
318 _menu_read:
319         stm    %r6,%r15,24(%r15)                # save registers
321         basr   %r13,0                           # get base register
322 .LbaseM4:
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
328 .LpromptM4:
329         bras   %r14,_menu_prompt                # print menu prompt
331         lh     %r2,MENU_PARAM_TIMEOUT(%r6)      # get timeout value
332         lr     %r3,%r7
333         bras   %r14,_sclp_read
335         ltr    %r2,%r2                          # got input?
336         jnz    .LusedefaultM4
338         sth    %r2,MENU_PARAM_TIMEOUT(%r6)      # deactivate timeout
340         ltr    %r8,%r3                          # save input length
341         jz     .LpromptM4
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
349 .LnotolowerM4:
350         lr     %r2,%r7                          # get number
351         lr     %r3,%r8
352         bras   %r14,_menu_etoi
354         ltr    %r9,%r4                          # save and test valid flag
355         jnz    .LnoconfigM4
357         ltr    %r1,%r5                          # check for valid configuration
358         jl     .LnoconfigM4                     # negative value?
360         chi    %r1,62                           # too high?
361         jh     .LnoconfigM4
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?
366         jz     .LnoconfigM4
368         ltr    %r3,%r3                          # check for additional params
369         jz     .LnoaddparamM4
371         sr     %r0,%r0
372         l      %r4,.LparmlineM0-.LbaseM4(%r13)  # get address for parmline
374 .LcopyaddparamM4:
375         ic     %r0,0(%r2)                       # copy rest of parmline
376         stc    %r0,0(%r4)
377         ahi    %r2,1
378         ahi    %r4,1
379         brct   %r3,.LcopyaddparamM4
381 .LnoaddparamM4:
382         lr     %r2,%r5
383         j      .LendM4
385 .LnoconfigM4:
386         la     %r2,.Ltext10M0-.LbaseM4(%r13)    # "Error: undefined config.."
387         bras   %r14,_sclp_print
389         j      .LpromptM4
391 .LusedefaultM4:
392         sr     %r2,%r2                          # set default configuration
394 .LendM4:
395         lm     %r6,%r15,120(%r15)               # restore registers
397         br     %r14
401 # Subroutine to convert an EBCDIC string to all lower case.
403 # Parameters:
404 #   R2  = address of EBCDIC string
405 #   R3  = length of string
408 _menu_tolower:
409         sr     %r0,%r0
411 .LloopM5:
412         ic     %r0,0(%r2)                       # convert input to lowercase
414         chi    %r0,0xc1                         # 'A' - 'I'
415         jl     .LnoupperM5
417         chi    %r0,0xc9
418         jle    .LtolowerM5
420         chi    %r0,0xd1                         # 'J' - 'R'
421         jl     .LnoupperM5
423         chi    %r0,0xd9
424         jle    .LtolowerM5
426         chi    %r0,0xe2                         # 'S' - 'Z'
427         jl     .LnoupperM5
429         chi    %r0,0xe9
430         jh     .LnoupperM5
432 .LtolowerM5:
433         ni     0(%r2),0xbf                      # remove upper case bit
435 .LnoupperM5:
436         ahi    %r2,1                            # next char
437         brct   %r3,.LloopM5
439         br     %r14
443 # Subroutine to parse an EBCDIC string as a decimal integer number.
445 # Parameters:
446 #   R2  = address of EBCDIC string
447 #   R3  = length of string
449 # Returns:
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
456 _menu_etoi:
457         sr     %r0,%r0
458         lhi    %r4,1                            # non-success return code
459         sr     %r5,%r5                          # resulting number
461 .LskipspaceM6:
462         ic     %r0,0(%r2)                       # skip leading spaces
464         chi    %r0,0x40                         # is current char a space?
465         jne    .LafterspaceM6
467         ahi    %r2,1                            # skip spaces
468         brct   %r3,.LskipspaceM6
470         j      .LendM6                          # reached end of string
472 .LafterspaceM6:
473         lhi    %r1,0x0f
475 .LtonumberM6:
476         ic     %r0,0(%r2)
478         chi    %r0,0x40                         # got a space?
479         je     .LgotnumberM6                    # valid end of number separator
481         chi    %r0,0xf0                         # got a digit?
482         jl     .LendM6
484         chi    %r0,0xf9
485         jh     .LendM6
487         mhi    %r5,10                           # current number * 10
489         nr     %r0,%r1                          # add digit
490         ar     %r5,%r0
492         ahi    %r2,1                            # next character
493         brct   %r3,.LtonumberM6                 # until end of input string
495 .LgotnumberM6:
496         sr     %r4,%r4
498 .LendM6:
499         br     %r14
503 # Subroutine used to interpret load parameter.
505 # Returns:
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
510 _menu_param:
511         stm    %r6,%r15,24(%r15)                # save registers
513         basr   %r13,0                           # get base register
514 .LbaseM7:
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?
523         jnz    .LerrorM7
525         lr     %r2,%r6                          # try to parse number
526         lhi    %r3,8
527         bras   %r14,_menu_etoi
529         ltr    %r2,%r4                          # got number?
530         lr     %r3,%r5
531         jz     .LendM7
533         lhi    %r1,8                            # remove trailing spaces
534         la     %r2,7(%r6)
536 .LremblanksM7:
537         cli    0(%r2),0x40                      # got space?
538         jne    .LafterblanksM7
540         xc     0(1,%r2),0(%r2)                  # write zero
542         ahi    %r2,-1                           # check next char
543         brct   %r1,.LremblanksM7
545 .LafterblanksM7:
546         lr     %r2,%r6                          # convert loadparm to lowercase
547         lhi    %r3,8
548         bras   %r14,_menu_tolower
550         # check for keyword
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
558         sr     %r3,%r3
560         j      .LendM7
562 .LerrorM7:
563         lhi    %r2,2                            # failure
565 .LendM7:
566         lm     %r6,%r15,120(%r15)               # restore registers
568         br     %r14
570 .LparamM7:
571         .byte  0,0,0,0,0,0,0,0                  # room for the load parameter
573 .LkeypromptM7:
574         # 'prompt\0'
575         .byte  0x97, 0x99, 0x96, 0x94, 0x97, 0xa3, 0x00
576         .align 2
579         # Global constants
581 .LparmareaM0:
582         .long  .Lmenuparam
583 .LparmlineM0:
584         .long  MENU_PARMLINE
585 .LtempareaM0:
586         .long  MENU_TEMP_AREA
589         # Menu text
591 .Ltext1M0:
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
598 .Ltext2M0:
599         # "Booting "
600         .byte  0xc2, 0x96, 0x96, 0xa3, 0x89, 0x95, 0x87, 0x40
601 .Ltext4M0:
602         # "..."
603         .byte  0x4b, 0x4b, 0x4b, 0x00
604 .Ltext5M0:
605         # "\n"
606         .byte  0x40, 0x00
607 .Ltext6M0:
608         # "Please choose"
609         .byte  0xd7, 0x93, 0x85, 0x81, 0xa2, 0x85, 0x40, 0x83, 0x88, 0x96
610         .byte  0x96, 0xa2, 0x85
611 .Ltext7M0:
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
616 .Ltext8M0:
617         # " seconds)"
618         .byte  0x40, 0xa2, 0x85, 0x83, 0x96, 0x95, 0x84, 0xa2, 0x5d
619 .Ltext9M0:
620         # ":"
621         .byte  0x7a, 0x00
622 .Ltext10M0:
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
628 .Ltext11M0:
629         # " BOOT_IMAGE="
630         .byte  0x40, 0xc2, 0xd6, 0xd6, 0xe3, 0x6d, 0xc9, 0xd4, 0xc1, 0xc7
631         .byte  0xc5, 0x7e
632 .Ltext12M0:
634         .align 2
636         .macro menu_param_area
637         .align 2
638 .Lmenuparam:
639         .endm