Stealth whitespace cleanup (automated)
[profile/ivi/syslinux.git] / ui.inc
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2007 H. Peter Anvin - All Rights Reserved
4 ;;
5 ;;   This program is free software; you can redistribute it and/or modify
6 ;;   it under the terms of the GNU General Public License as published by
7 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
9 ;;   (at your option) any later version; incorporated herein by reference.
10 ;;
11 ;; -----------------------------------------------------------------------
12
13 ;
14 ; This file should be entered with the config file open (for getc)
15 ;
16 load_config_file:
17                 call parse_config               ; Parse configuration file
18 no_config_file:
19
20 ;
21 ; Check whether or not we are supposed to display the boot prompt.
22 ;
23 check_for_key:
24                 cmp word [ForcePrompt],0        ; Force prompt?
25                 jnz enter_command
26                 test byte [KbdFlags],5Bh        ; Shift Alt Caps Scroll
27                 jz auto_boot                    ; If neither, default boot
28
29 enter_command:
30                 cmp word [NoEscape],0           ; If NOESCAPE, no prompt,
31                 jne auto_boot                   ; always run default cmd
32
33                 mov si,boot_prompt
34                 call cwritestr
35
36                 mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
37                 mov di,command_line
38
39 ;
40 ; get the very first character -- we can either time
41 ; out, or receive a character press at this time.  Some dorky BIOSes stuff
42 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
43 ;
44 clear_buffer:   mov ah,11h                      ; Check for pending char
45                 int 16h
46                 jz get_char_time
47                 mov ah,10h                      ; Get char
48                 int 16h
49                 jmp short clear_buffer
50
51                 ; For the first character, both KbdTimeout and
52                 ; TotalTimeout apply; after that, only TotalTimeout.
53
54 get_char_time:
55                 mov eax,[TotalTimeout]
56                 mov [ThisTotalTo],eax
57                 mov eax,[KbdTimeout]
58                 mov [ThisKbdTo],eax
59
60 get_char:
61                 call getchar_timeout
62                 and dword [ThisKbdTo],0         ; For the next time...
63
64                 and al,al
65                 jz func_key
66
67 got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
68                 je backspace
69                 cmp al,' '                      ; ASCII?
70                 jb not_ascii
71                 ja enter_char
72                 cmp di,command_line             ; Space must not be first
73                 je short get_char
74 enter_char:     test byte [FuncFlag],1
75                 jz .not_ctrl_f
76                 mov byte [FuncFlag],0
77                 cmp al,'0'
78                 jb .not_ctrl_f
79                 je ctrl_f_0
80                 cmp al,'9'
81                 jbe ctrl_f
82 .not_ctrl_f:    cmp di,max_cmd_len+command_line ; Check there's space
83                 jnb short get_char
84                 stosb                           ; Save it
85                 call writechr                   ; Echo to screen
86                 jmp short get_char
87 not_ascii:      mov byte [FuncFlag],0
88                 cmp al,0Dh                      ; Enter
89                 je command_done
90                 cmp al,'F' & 1Fh                ; <Ctrl-F>
91                 je set_func_flag
92                 cmp al,'U' & 1Fh                ; <Ctrl-U>
93                 je kill_command                 ; Kill input line
94                 cmp al,'V' & 1Fh                ; <Ctrl-V>
95                 je print_version
96                 cmp al,'X' & 1Fh                ; <Ctrl-X>
97                 je force_text_mode
98                 cmp al,08h                      ; Backspace
99                 jne get_char
100 backspace:      cmp di,command_line             ; Make sure there is anything
101                 je get_char                     ; to erase
102                 dec di                          ; Unstore one character
103                 mov si,wipe_char                ; and erase it from the screen
104                 call cwritestr
105                 jmp short get_char_2
106
107 kill_command:
108                 call crlf
109                 jmp enter_command
110
111 force_text_mode:
112                 call vgaclearmode
113                 jmp enter_command
114
115 set_func_flag:
116                 mov byte [FuncFlag],1
117 get_char_2:
118                 jmp short get_char
119
120 ctrl_f_0:       add al,10                       ; <Ctrl-F>0 == F10
121 ctrl_f:         sub al,'1'
122                 xor ah,ah
123                 jmp short show_help
124
125 func_key:
126                 ; AL = 0 if we get here
127                 xchg al,ah
128                 cmp al,68                       ; F10
129                 ja short get_char_2
130                 sub al,59                       ; F1
131                 jb short get_char_2
132 show_help:      ; AX = func key # (0 = F1, 9 = F10)
133                 push di                         ; Save end-of-cmdline pointer
134                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
135                 add ax,FKeyName
136                 xchg di,ax
137                 cmp byte [di+NULLOFFSET],NULLFILE
138                 je short fk_nofile              ; Undefined F-key
139                 call searchdir
140                 jz short fk_nofile              ; File not found
141                 push si
142                 call crlf
143                 pop si
144                 call get_msg_file
145                 jmp short fk_wrcmd
146
147 print_version:
148                 push di                         ; Command line write pointer
149                 mov si,syslinux_banner
150                 call cwritestr
151 %ifdef HAVE_BIOSNAME
152                 mov si,[BIOSName]
153                 call cwritestr
154 %endif
155                 mov si,copyright_str
156                 call cwritestr
157
158                 ; ... fall through ...
159
160                 ; Write the boot prompt and command line again and
161                 ; wait for input.  Note that this expects the cursor
162                 ; to already have been CRLF'd, and that the old value
163                 ; of DI (the command line write pointer) is on the stack.
164 fk_wrcmd:
165                 mov si,boot_prompt
166                 call cwritestr
167                 pop di                          ; Command line write pointer
168                 push di
169                 mov byte [di],0                 ; Null-terminate command line
170                 mov si,command_line
171                 call cwritestr                  ; Write command line so far
172 fk_nofile:      pop di
173                 jmp short get_char_2
174
175 ;
176 ; Jump here to run the default command line
177 ;
178 auto_boot:
179                 mov si,default_cmd
180                 mov di,command_line
181                 mov cx,(max_cmd_len+4) >> 2
182                 rep movsd
183                 jmp short load_kernel
184
185 ;
186 ; Jump here when the command line is completed
187 ;
188 command_done:
189                 call crlf
190                 cmp di,command_line             ; Did we just hit return?
191                 je auto_boot
192                 xor al,al                       ; Store a final null
193                 stosb
194
195 load_kernel:                                    ; Load the kernel now
196 ;
197 ; First we need to mangle the kernel name the way DOS would...
198 ;
199                 mov si,command_line
200                 mov di,KernelName
201                 push si
202                 call mangle_name
203                 pop si
204 ;
205 ; Fast-forward to first option (we start over from the beginning, since
206 ; mangle_name doesn't necessarily return a consistent ending state.)
207 ;
208 clin_non_wsp:   lodsb
209                 cmp al,' '
210                 ja clin_non_wsp
211 clin_is_wsp:    and al,al
212                 jz clin_opt_ptr
213                 lodsb
214                 cmp al,' '
215                 jbe clin_is_wsp
216 clin_opt_ptr:   dec si                          ; Point to first nonblank
217                 mov [CmdOptPtr],si              ; Save ptr to first option
218 ;
219 ; If "allowoptions 0", put a null character here in order to ignore any
220 ; user-specified options.
221 ;
222                 mov ax,[AllowOptions]
223                 and ax,ax
224                 jnz clin_opt_ok
225                 mov [si],al
226 clin_opt_ok:
227
228 ;
229 ; Now check if it is a "virtual kernel"
230 ;
231 vk_check:
232                 xor si,si                       ; Beginning of vk_seg
233 .scan:
234                 cmp si,[VKernelBytes]
235                 jae .not_vk
236
237                 push ds
238                 push word vk_seg
239                 pop ds
240
241                 mov di,VKernelBuf
242                 call rllunpack
243                 pop ds
244                 ; SI updated on return
245
246                 sub di,cx                       ; Return to beginning of buf
247                 push si
248                 mov si,KernelName
249                 mov cx,FILENAME_MAX
250                 es repe cmpsb
251                 pop si
252                 je .found
253                 jmp .scan
254
255 ;
256 ; We *are* using a "virtual kernel"
257 ;
258 .found:
259                 push es
260                 push word real_mode_seg
261                 pop es
262                 mov di,cmd_line_here
263                 mov si,VKernelBuf+vk_append
264                 mov cx,[VKernelBuf+vk_appendlen]
265                 rep movsb
266                 mov [CmdLinePtr],di             ; Where to add rest of cmd
267                 pop es
268                 mov di,KernelName
269                 push di
270                 mov si,VKernelBuf+vk_rname
271                 mov cx,FILENAME_MAX             ; We need ECX == CX later
272                 rep movsb
273                 pop di
274 %if IS_PXELINUX
275                 mov al,[VKernelBuf+vk_ipappend]
276                 mov [IPAppend],al
277 %endif
278                 xor bx,bx                       ; Try only one version
279
280                 mov al, [VKernelBuf+vk_type]
281                 mov [KernelType], al
282
283 %if IS_PXELINUX || IS_ISOLINUX
284                 ; Is this a "localboot" pseudo-kernel?
285 %if IS_PXELINUX
286                 cmp byte [VKernelBuf+vk_rname+4], 0
287 %else
288                 cmp byte [VKernelBuf+vk_rname], 0
289 %endif
290                 jne get_kernel          ; No, it's real, go get it
291
292                 mov ax, [VKernelBuf+vk_rname+1]
293                 jmp local_boot
294 %else
295                 jmp get_kernel
296 %endif
297
298 .not_vk:
299
300 ;
301 ; Not a "virtual kernel" - check that's OK and construct the command line
302 ;
303                 cmp word [AllowImplicit],byte 0
304                 je bad_implicit
305                 push es
306                 push si
307                 push di
308                 mov di,real_mode_seg
309                 mov es,di
310                 mov si,AppendBuf
311                 mov di,cmd_line_here
312                 mov cx,[AppendLen]
313                 rep movsb
314                 mov [CmdLinePtr],di
315                 pop di
316                 pop si
317                 pop es
318
319                 mov [KernelType], cl            ; CL == 0 here
320
321 ;
322 ; Find the kernel on disk
323 ;
324 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
325                 mov di,KernelName+4*IS_PXELINUX
326                 xor al,al
327                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
328                 repne scasb                     ; Scan for final null
329                 jne .no_skip
330                 dec di                          ; Point to final null
331 .no_skip:       mov [KernelExtPtr],di
332                 mov bx,exten_table
333 .search_loop:   push bx
334                 mov di,KernelName               ; Search on disk
335                 call searchdir
336                 pop bx
337                 jnz kernel_good
338                 mov eax,[bx]                    ; Try a different extension
339                 mov si,[KernelExtPtr]
340                 mov [si],eax
341                 mov byte [si+4],0
342                 add bx,byte 4
343                 cmp bx,exten_table_end
344                 jna .search_loop                ; allow == case (final case)
345                 ; Fall into bad_kernel
346 ;
347 ; bad_kernel: Kernel image not found
348 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
349 ;
350 bad_implicit:
351 bad_kernel:
352                 mov cx,[OnerrorLen]
353                 and cx,cx
354                 jnz on_error
355 .really:
356                 mov si,KernelName
357                 mov di,KernelCName
358                 push di
359                 call unmangle_name              ; Get human form
360                 mov si,err_notfound             ; Complain about missing kernel
361                 call cwritestr
362                 pop si                          ; KernelCName
363                 call cwritestr
364                 mov si,crlf_msg
365                 jmp abort_load                  ; Ask user for clue
366
367 ;
368 ; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
369 ;
370 on_error:
371                 mov si,Onerror
372                 mov di,command_line
373                 push si                         ; <A>
374                 push di                         ; <B>
375                 push cx                         ; <C>
376                 push cx                         ; <D>
377                 push di                         ; <E>
378                 repe cmpsb
379                 pop di                          ; <E> di == command_line
380                 pop bx                          ; <D> bx == [OnerrorLen]
381                 je bad_kernel.really            ; Onerror matches command_line already
382                 neg bx                          ; bx == -[OnerrorLen]
383                 lea cx,[max_cmd_len+bx]
384                 ; CX == max_cmd_len-[OnerrorLen]
385                 mov di,command_line+max_cmd_len-1
386                 mov byte [di+1],0               ; Enforce null-termination
387                 lea si,[di+bx]
388                 std
389                 rep movsb                       ; Make space in command_line
390                 cld
391                 pop cx                          ; <C> cx == [OnerrorLen]
392                 pop di                          ; <B> di == command_line
393                 pop si                          ; <A> si  == Onerror
394                 rep movsb
395                 jmp load_kernel
396
397 ;
398 ; kernel_corrupt: Called if the kernel file does not seem healthy
399 ;
400 kernel_corrupt: mov si,err_notkernel
401                 jmp abort_load
402
403 ;
404 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
405 ; which can be adjusted by the caller based on the corresponding
406 ; master variables; on return they're updated.
407 ;
408 ; This cheats.  If we say "no timeout" we actually get a timeout of
409 ; 7.5 years.
410 ;
411 getchar_timeout:
412                 call vgashowcursor
413                 RESET_IDLE
414
415 .loop:
416                 push word [BIOS_timer]
417                 call pollchar
418                 jnz .got_char
419                 pop ax
420                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
421                 je .loop
422                 DO_IDLE
423
424                 dec dword [ThisKbdTo]
425                 jz .timeout
426                 dec dword [ThisTotalTo]
427                 jnz .loop
428
429 .timeout:
430                 ; Timeout!!!!
431                 pop cx                          ; Discard return address
432                 call vgahidecursor
433                 mov si,Ontimeout                ; Copy ontimeout command
434                 mov di,command_line
435                 mov cx,[OntimeoutLen]           ; if we have one...
436                 rep movsb
437                 jmp command_done
438
439 .got_char:
440                 pop cx                          ; Discard
441                 call getchar
442                 call vgahidecursor
443                 ret
444
445 ;
446 ; This is it!  We have a name (and location on the disk)... let's load
447 ; that sucker!!  First we have to decide what kind of file this is; base
448 ; that decision on the file extension.  The following extensions are
449 ; recognized; case insensitive:
450 ;
451 ; .com  - COMBOOT image
452 ; .cbt  - COMBOOT image
453 ; .c32  - COM32 image
454 ; .bs   - Boot sector
455 ; .0    - PXE bootstrap program (PXELINUX only)
456 ; .bin  - Boot sector
457 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
458 ; .img  - Floppy image (ISOLINUX only)
459 ;
460 ; Anything else is assumed to be a Linux kernel.
461 ;
462                 section .bss
463                 alignb 4
464 Kernel_EAX      resd 1
465 Kernel_SI       resw 1
466
467                 section .text
468 kernel_good_saved:
469                 ; Alternate entry point for which the return from
470                 ; searchdir is stored in memory.  This is used for
471                 ; COMBOOT function INT 22h, AX=0016h.
472                 mov si,[Kernel_SI]
473                 mov eax,[Kernel_EAX]
474                 mov dx,[Kernel_EAX+2]
475
476 kernel_good:
477                 pusha
478                 mov si,KernelName
479                 mov di,KernelCName
480                 call unmangle_name
481                 sub di,KernelCName
482                 mov [KernelCNameLen],di
483                 popa
484
485                 push di
486                 push ax
487                 mov di,KernelName+4*IS_PXELINUX
488                 xor al,al
489                 mov cx,FILENAME_MAX
490                 repne scasb
491                 jne .one_step
492                 dec di
493 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
494                 pop ax
495                 pop di
496
497 ;
498 ; At this point, DX:AX contains the size of the kernel, SI contains
499 ; the file handle/cluster pointer, and ECX contains the extension (if any.)
500 ;
501                 movzx di,byte [KernelType]
502                 add di,di
503                 jmp [kerneltype_table+di]
504
505 is_unknown_filetype:
506                 or ecx,20202000h                ; Force lower case (except dot)
507
508                 cmp ecx,'.com'
509                 je is_comboot_image
510                 cmp ecx,'.cbt'
511                 je is_comboot_image
512                 cmp ecx,'.c32'
513                 je is_com32_image
514 %if IS_ISOLINUX
515                 cmp ecx,'.img'
516                 je is_disk_image
517 %endif
518                 cmp ecx,'.bss'
519                 je is_bss_sector
520                 cmp ecx,'.bin'
521                 je is_bootsector
522                 shr ecx,8
523                 cmp ecx,'.bs'
524                 je is_bootsector
525                 shr ecx,8
526                 cmp cx,'.0'
527                 je is_bootsector
528
529                 ; Otherwise Linux kernel
530                 jmp is_linux_kernel
531
532 is_config_file:
533                 pusha
534                 mov si,KernelCName              ; Save the config file name, for posterity
535                 mov di,ConfigName
536                 call strcpy
537                 popa
538                 call openfd
539                 call reset_config
540                 jmp load_config_file
541
542 ; This is an image type we can't deal with
543 is_bad_image:
544                 mov si,err_badimage
545                 call cwritestr
546                 jmp enter_command
547
548 %if IS_SYSLINUX || IS_MDSLINUX
549                 ; ok
550 %else
551 is_bss_sector   equ is_bad_image
552 %endif
553 %if IS_ISOLINUX
554                 ; ok
555 %else
556 is_disk_image   equ is_bad_image
557 %endif
558
559                 section .data
560 err_badimage    db 'Invalid image type for this media type!', CR, LF, 0
561
562                 align 2, db 0
563 kerneltype_table:
564                 dw is_unknown_filetype  ; VK_KERNEL
565                 dw is_linux_kernel      ; VK_LINUX
566                 dw is_bootsector        ; VK_BOOT
567                 dw is_bss_sector        ; VK_BSS
568                 dw is_bootsector        ; VK_PXE
569                 dw is_disk_image        ; VK_FDIMAGE
570                 dw is_comboot_image     ; VK_COMBOOT
571                 dw is_com32_image       ; VK_COM32
572                 dw is_config_file       ; VK_CONFIG
573
574                 section .bss
575                 alignb 4
576 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
577 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
578 KernelExtPtr    resw 1                  ; During search, final null pointer
579 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
580 KbdFlags        resb 1                  ; Check for keyboard escapes
581 FuncFlag        resb 1                  ; Escape sequences received from keyboard
582 KernelType      resb 1                  ; Kernel type, from vkernel, if known
583
584                 section .text