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