Adding upstream version 3.30~pre4.
[syslinux-debian/hramrach.git] / ui.inc
blob6ea3a4a6a842e6d3b7854b5158a56a66ab3913c2
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2005 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.
11 ;; -----------------------------------------------------------------------
14 ; This file should be entered with the config file open (for getc)
16                 call parse_config               ; Parse configuration file
17 no_config_file:
19 ; Check whether or not we are supposed to display the boot prompt.
21 check_for_key:
22                 cmp word [ForcePrompt],0        ; Force prompt?
23                 jnz enter_command
24                 test byte [KbdFlags],5Bh        ; Shift Alt Caps Scroll
25                 jz auto_boot                    ; If neither, default boot
27 enter_command:
28                 cmp word [NoEscape],0           ; If NOESCAPE, no prompt,
29                 jne auto_boot                   ; always run default cmd
31                 mov si,boot_prompt
32                 call cwritestr
34                 mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
35                 mov di,command_line
38 ; get the very first character -- we can either time
39 ; out, or receive a character press at this time.  Some dorky BIOSes stuff
40 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
42 clear_buffer:   mov ah,11h                      ; Check for pending char
43                 int 16h
44                 jz get_char_time
45                 mov ah,10h                      ; Get char
46                 int 16h
47                 jmp short clear_buffer
49                 ; For the first character, both KbdTimeout and
50                 ; TotalTimeout apply; after that, only TotalTimeout.
52 get_char_time:
53                 mov eax,[TotalTimeout]
54                 mov [ThisTotalTo],eax
55                 mov eax,[KbdTimeout]
56                 mov [ThisKbdTo],eax
58 get_char:
59                 call getchar_timeout
60                 and dword [ThisKbdTo],0         ; For the next time...
62                 and al,al
63                 jz func_key
65 got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
66                 je backspace
67                 cmp al,' '                      ; ASCII?
68                 jb not_ascii
69                 ja enter_char
70                 cmp di,command_line             ; Space must not be first
71                 je short get_char
72 enter_char:     test byte [FuncFlag],1
73                 jz .not_ctrl_f
74                 mov byte [FuncFlag],0
75                 cmp al,'0'
76                 jb .not_ctrl_f
77                 je ctrl_f_0
78                 cmp al,'9'
79                 jbe ctrl_f
80 .not_ctrl_f:    cmp di,max_cmd_len+command_line ; Check there's space
81                 jnb short get_char
82                 stosb                           ; Save it
83                 call writechr                   ; Echo to screen
84                 jmp short get_char
85 not_ascii:      mov byte [FuncFlag],0
86                 cmp al,0Dh                      ; Enter
87                 je command_done
88                 cmp al,'F' & 1Fh                ; <Ctrl-F>
89                 je set_func_flag
90                 cmp al,'U' & 1Fh                ; <Ctrl-U>
91                 je kill_command                 ; Kill input line
92                 cmp al,'V' & 1Fh                ; <Ctrl-V>
93                 je print_version
94                 cmp al,'X' & 1Fh                ; <Ctrl-X>
95                 je force_text_mode
96                 cmp al,08h                      ; Backspace
97                 jne get_char
98 backspace:      cmp di,command_line             ; Make sure there is anything
99                 je get_char                     ; to erase
100                 dec di                          ; Unstore one character
101                 mov si,wipe_char                ; and erase it from the screen
102                 call cwritestr
103                 jmp short get_char_2
105 kill_command:
106                 call crlf
107                 jmp enter_command
109 force_text_mode:
110                 call vgaclearmode
111                 jmp enter_command
113 set_func_flag:
114                 mov byte [FuncFlag],1
115 get_char_2:
116                 jmp short get_char
118 ctrl_f_0:       add al,10                       ; <Ctrl-F>0 == F10
119 ctrl_f:         sub al,'1'
120                 xor ah,ah
121                 jmp short show_help
123 func_key:
124                 ; AL = 0 if we get here
125                 xchg al,ah
126                 cmp al,68                       ; F10
127                 ja short get_char_2
128                 sub al,59                       ; F1
129                 jb short get_char_2
130 show_help:      ; AX = func key # (0 = F1, 9 = F10)
131                 push di                         ; Save end-of-cmdline pointer
132                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
133                 add ax,FKeyName
134                 xchg di,ax
135                 cmp byte [di+NULLOFFSET],NULLFILE
136                 je short fk_nofile              ; Undefined F-key
137                 call searchdir
138                 jz short fk_nofile              ; File not found
139                 push si
140                 call crlf
141                 pop si
142                 call get_msg_file
143                 jmp short fk_wrcmd
145 print_version:
146                 push di                         ; Command line write pointer
147                 mov si,syslinux_banner
148                 call cwritestr
149 %ifdef HAVE_BIOSNAME
150                 mov si,[BIOSName]
151                 call cwritestr
152 %endif
153                 mov si,copyright_str
154                 call cwritestr
156                 ; ... fall through ...
158                 ; Write the boot prompt and command line again and
159                 ; wait for input.  Note that this expects the cursor
160                 ; to already have been CRLF'd, and that the old value
161                 ; of DI (the command line write pointer) is on the stack.
162 fk_wrcmd:
163                 mov si,boot_prompt
164                 call cwritestr
165                 pop di                          ; Command line write pointer
166                 push di
167                 mov byte [di],0                 ; Null-terminate command line
168                 mov si,command_line
169                 call cwritestr                  ; Write command line so far
170 fk_nofile:      pop di
171                 jmp short get_char_2
174 ; Jump here to run the default command line
176 auto_boot:
177                 mov si,default_cmd
178                 mov di,command_line
179                 mov cx,(max_cmd_len+4) >> 2
180                 rep movsd
181                 jmp short load_kernel
184 ; Jump here when the command line is completed
186 command_done:
187                 call crlf
188                 cmp di,command_line             ; Did we just hit return?
189                 je auto_boot
190                 xor al,al                       ; Store a final null
191                 stosb
193 load_kernel:                                    ; Load the kernel now
195 ; First we need to mangle the kernel name the way DOS would...
197                 mov si,command_line
198                 mov di,KernelName
199                 push si
200                 push di
201                 call mangle_name
202                 pop di
203                 pop si
205 ; Fast-forward to first option (we start over from the beginning, since
206 ; mangle_name doesn't necessarily return a consistent ending state.)
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
219 ; If "allowoptions 0", put a null character here in order to ignore any
220 ; user-specified options.
222                 mov ax,[AllowOptions]
223                 and ax,ax
224                 jnz clin_opt_ok
225                 mov [si],al
226 clin_opt_ok:
229 ; Now check if it is a "virtual kernel"
231 vk_check:
232                 xor si,si                       ; Beginning of vk_seg
233 .scan:
234                 cmp si,[VKernelBytes]
235                 jae .not_vk
237                 push ds
238                 push word vk_seg
239                 pop ds
241                 mov di,VKernelBuf
242                 call rllunpack
243                 pop ds
244                 ; SI updated on return
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
256 ; We *are* using a "virtual kernel"
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
280 %if IS_PXELINUX || IS_ISOLINUX
281                 ; Is this a "localboot" pseudo-kernel?
282 %if IS_PXELINUX
283                 cmp byte [VKernelBuf+vk_rname+4], 0
284 %else
285                 cmp byte [VKernelBuf+vk_rname], 0
286 %endif
287                 jne get_kernel          ; No, it's real, go get it
289                 mov ax, [VKernelBuf+vk_rname+1]
290                 jmp local_boot
291 %else
292                 jmp get_kernel
293 %endif
295 .not_vk:
298 ; Not a "virtual kernel" - check that's OK and construct the command line
300                 cmp word [AllowImplicit],byte 0
301                 je bad_implicit
302                 push es
303                 push si
304                 push di
305                 mov di,real_mode_seg
306                 mov es,di
307                 mov si,AppendBuf
308                 mov di,cmd_line_here
309                 mov cx,[AppendLen]
310                 rep movsb
311                 mov [CmdLinePtr],di
312                 pop di
313                 pop si
314                 pop es
316 ; Find the kernel on disk
318 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
319 %if IS_SYSLINUX || IS_MDSLINUX                  ; SYSLINUX has to deal with DOS mangled names...
320                 mov eax,[KernelName+8]          ; Save initial extension
321                 mov [exten_table_end],eax       ; Last case == initial ext.
322 %else
323                 mov di,KernelName+4*IS_PXELINUX
324                 xor al,al
325                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
326                 repne scasb                     ; Scan for final null
327                 jne .no_skip
328                 dec di                          ; Point to final null
329 .no_skip:       mov [KernelExtPtr],di
330 %endif
331                 mov bx,exten_table
332 .search_loop:   push bx
333                 mov di,KernelName               ; Search on disk
334                 call searchdir
335                 pop bx
336                 jnz kernel_good
337                 mov eax,[bx]                    ; Try a different extension
338 %if IS_SYSLINUX || IS_MDSLINUX
339                 mov [KernelName+8],eax
340 %else
341                 mov si,[KernelExtPtr]
342                 mov [si],eax
343                 mov byte [si+4],0
344 %endif
345                 add bx,byte 4
346                 cmp bx,exten_table_end
347                 jna .search_loop                ; allow == case (final case)
348                 ; Fall into bad_kernel
350 ; bad_kernel: Kernel image not found
351 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
353 bad_implicit:
354 bad_kernel:
355                 mov cx,[OnerrorLen]
356                 and cx,cx
357                 jnz on_error
358 .really:
359                 mov si,KernelName
360                 mov di,KernelCName
361                 push di
362                 call unmangle_name              ; Get human form
363                 mov si,err_notfound             ; Complain about missing kernel
364                 call cwritestr
365                 pop si                          ; KernelCName
366                 call cwritestr
367                 mov si,crlf_msg
368                 jmp abort_load                  ; Ask user for clue
371 ; on_error: bad kernel, but we have onerror set
373 on_error:
374                 mov si,Onerror
375                 mov di,command_line
376                 push si                         ; <A>
377                 push di                         ; <B>
378                 push cx                         ; <C>
379                 push cx                         ; <D>
380                 push di                         ; <E>
381                 repe cmpsb
382                 pop di                          ; <E> di == command_line
383                 pop bx                          ; <D> bx == [OnerrorLen]
384                 je bad_kernel.really            ; Onerror matches command_line already
385                 neg bx                          ; bx == -[OnerrorLen]
386                 lea cx,[max_cmd_len+bx]
387                 ; CX == max_cmd_len-[OnerrorLen]
388                 mov di,command_line+max_cmd_len-1
389                 mov byte [di+1],0               ; Enforce null-termination
390                 lea si,[di+bx]
391                 std
392                 rep movsb                       ; Make space in command_line
393                 cld
394                 pop cx                          ; <C> cx == [OnerrorLen]
395                 pop di                          ; <B> di == command_line
396                 pop si                          ; <A> si  == Onerror
397                 rep movsb
398                 jmp load_kernel
401 ; kernel_corrupt: Called if the kernel file does not seem healthy
403 kernel_corrupt: mov si,err_notkernel
404                 jmp abort_load
407 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
408 ; which can be adjusted by the caller based on the corresponding
409 ; master variables; on return they're updated.
411 ; This cheats.  If we say "no timeout" we actually get a timeout of
412 ; 7.5 years.
414 getchar_timeout:
415                 call vgashowcursor
416                 RESET_IDLE
418 .loop:
419                 push word [BIOS_timer]
420                 call pollchar
421                 jnz .got_char
422                 pop ax
423                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
424                 je .loop
425                 DO_IDLE
427                 dec dword [ThisKbdTo]
428                 jz .timeout
429                 dec dword [ThisTotalTo]
430                 jnz .loop
432 .timeout:
433                 ; Timeout!!!!
434                 pop cx                          ; Discard return address
435                 call vgahidecursor
436                 mov si,Ontimeout                ; Copy ontimeout command
437                 mov di,command_line
438                 mov cx,[OntimeoutLen]           ; if we have one...
439                 rep movsb
440                 jmp command_done
442 .got_char:
443                 pop cx                          ; Discard
444                 call getchar
445                 call vgahidecursor
446                 ret
449 ; This is it!  We have a name (and location on the disk)... let's load
450 ; that sucker!!  First we have to decide what kind of file this is; base
451 ; that decision on the file extension.  The following extensions are
452 ; recognized; case insensitive:
454 ; .com  - COMBOOT image
455 ; .cbt  - COMBOOT image
456 ; .c32  - COM32 image
457 ; .bs   - Boot sector
458 ; .0    - PXE bootstrap program (PXELINUX only)
459 ; .bin  - Boot sector
460 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
461 ; .img  - Floppy image (ISOLINUX only)
463 ; Anything else is assumed to be a Linux kernel.
465                 section .bss
466                 alignb 4
467 Kernel_EAX      resd 1
468 Kernel_SI       resw 1
470                 section .text
471 kernel_good_saved:
472                 ; Alternate entry point for which the return from
473                 ; searchdir is stored in memory.  This is used for
474                 ; COMBOOT function INT 22h, AX=0016h.
475                 mov si,[Kernel_SI]
476                 mov eax,[Kernel_EAX]
477                 mov dx,[Kernel_EAX+2]
479 kernel_good:
480                 pusha
481                 mov si,KernelName
482                 mov di,KernelCName
483                 call unmangle_name
484                 sub di,KernelCName
485                 mov [KernelCNameLen],di
486                 popa
488 %if IS_SYSLINUX || IS_MDSLINUX
489                 mov ecx,[KernelName+7]
490                 mov cl,'.'
491 %else
492                 push di
493                 push ax
494                 mov di,KernelName+4*IS_PXELINUX
495                 xor al,al
496                 mov cx,FILENAME_MAX
497                 repne scasb
498                 jne .one_step
499                 dec di
500 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
501                 pop ax
502                 pop di
503 %endif
506 ; At this point, DX:AX contains the size of the kernel, and SI contains
507 ; the file handle/cluster pointer.
509                 or ecx,20202000h                ; Force lower case (except dot)
511                 cmp ecx,'.com'
512                 je is_comboot_image
513                 cmp ecx,'.cbt'
514                 je is_comboot_image
515                 cmp ecx,'.c32'
516                 je is_com32_image
517 %if IS_ISOLINUX
518                 cmp ecx,'.img'
519                 je is_disk_image
520 %endif
521                 cmp ecx,'.bss'
522                 je is_bss_sector
523                 cmp ecx,'.bin'
524                 je is_bootsector
525 %if IS_SYSLINUX || IS_MDSLINUX
526                 cmp ecx,'.bs '
527                 je is_bootsector
528                 cmp ecx,'.0  '
529                 je is_bootsector
530 %else
531                 shr ecx,8
532                 cmp ecx,'.bs'
533                 je is_bootsector
534                 shr ecx,8
535                 cmp cx,'.0'
536                 je is_bootsector
537 %endif
538                 ; Otherwise Linux kernel
540                 section .bss
541                 alignb 4
542 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
543 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
544 KernelExtPtr    resw 1                  ; During search, final null pointer
545 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
546 KbdFlags        resb 1                  ; Check for keyboard escapes
547 FuncFlag        resb 1                  ; Escape sequences received from keyboard
549                 section .text