Support Ctrl-U -> kill entire input
[profile/ivi/syslinux.git] / ui.inc
1 ;; $Id$
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 ;;   Bostom 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,1                        ; Check for pending char
40                 int 16h
41                 jz get_char_time
42                 xor ax,ax                       ; 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,06h                      ; <Ctrl-F>
106                 je set_func_flag
107                 cmp al,15h                      ; <Ctrl-U>
108                 je kill_command                 ; Kill input line
109                 cmp al,16h                      ; <Ctrl-V>
110                 je print_version
111                 cmp al,08h                      ; Backspace
112                 jne get_char
113 backspace:      cmp di,command_line             ; Make sure there is anything
114                 je get_char                     ; to erase
115                 dec di                          ; Unstore one character
116                 mov si,wipe_char                ; and erase it from the screen
117                 call cwritestr
118                 jmp short get_char_2
119
120 kill_command:
121                 call crlf
122                 jmp enter_command
123
124 set_func_flag:
125                 mov byte [FuncFlag],1
126 get_char_2:
127                 jmp short get_char
128
129 ctrl_f_0:       add al,10                       ; <Ctrl-F>0 == F10
130 ctrl_f:         sub al,'1'
131                 xor ah,ah
132                 jmp short show_help
133
134 func_key:
135                 ; AL = 0 if we get here
136                 xchg al,ah
137                 cmp al,68                       ; F10
138                 ja short get_char_2
139                 sub al,59                       ; F1
140                 jb short get_char_2
141 show_help:      ; AX = func key # (0 = F1, 9 = F10)
142                 push di                         ; Save end-of-cmdline pointer
143                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
144                 add ax,FKeyName
145                 xchg di,ax
146                 cmp byte [di],NULLFILE
147                 je short fk_nofile              ; Undefined F-key
148                 call searchdir
149                 jz short fk_nofile              ; File not found
150                 push si
151                 call crlf
152                 pop si
153                 call get_msg_file
154                 jmp short fk_wrcmd
155
156 print_version:
157                 push di                         ; Command line write pointer
158                 mov si,syslinux_banner
159                 call cwritestr
160                 mov si,copyright_str
161                 call cwritestr
162
163                 ; ... fall through ...
164
165                 ; Write the boot prompt and command line again and
166                 ; wait for input.  Note that this expects the cursor
167                 ; to already have been CRLF'd, and that the old value
168                 ; of DI (the command line write pointer) is on the stack.
169 fk_wrcmd:
170                 mov si,boot_prompt
171                 call cwritestr
172                 pop di                          ; Command line write pointer
173                 push di
174                 mov byte [di],0                 ; Null-terminate command line
175                 mov si,command_line
176                 call cwritestr                  ; Write command line so far
177 fk_nofile:      pop di
178                 jmp short get_char_2
179 auto_boot:
180                 mov si,default_cmd
181                 mov di,command_line
182                 mov cx,(max_cmd_len+4) >> 2
183                 rep movsd
184                 jmp short load_kernel
185 command_done:
186                 call crlf
187                 cmp di,command_line             ; Did we just hit return?
188                 je auto_boot
189                 xor al,al                       ; Store a final null
190                 stosb
191
192 load_kernel:                                    ; Load the kernel now
193 ;
194 ; First we need to mangle the kernel name the way DOS would...
195 ;
196                 mov si,command_line
197                 mov di,KernelName
198                 push si
199                 push di
200                 call mangle_name
201                 pop di
202                 pop si
203 ;
204 ; Fast-forward to first option (we start over from the beginning, since
205 ; mangle_name doesn't necessarily return a consistent ending state.)
206 ;
207 clin_non_wsp:   lodsb
208                 cmp al,' '
209                 ja clin_non_wsp
210 clin_is_wsp:    and al,al
211                 jz clin_opt_ptr
212                 lodsb
213                 cmp al,' '
214                 jbe clin_is_wsp
215 clin_opt_ptr:   dec si                          ; Point to first nonblank
216                 mov [CmdOptPtr],si              ; Save ptr to first option
217 ;
218 ; Now check if it is a "virtual kernel"
219 ;
220                 mov cx,[VKernelCtr]
221                 push ds
222                 push word vk_seg
223                 pop ds
224                 cmp cx,byte 0
225                 je not_vk
226                 xor si,si                       ; Point to first vkernel
227 vk_check:       pusha
228                 mov cx,FILENAME_MAX
229                 repe cmpsb                      ; Is this it?
230                 je vk_found
231                 popa
232                 add si,vk_size
233                 loop vk_check
234 not_vk:         pop ds
235 ;
236 ; Not a "virtual kernel" - check that's OK and construct the command line
237 ;
238                 cmp word [AllowImplicit],byte 0
239                 je bad_implicit
240                 push es
241                 push si
242                 push di
243                 mov di,real_mode_seg
244                 mov es,di
245                 mov si,AppendBuf
246                 mov di,cmd_line_here
247                 mov cx,[AppendLen]
248                 rep movsb
249                 mov [CmdLinePtr],di
250                 pop di
251                 pop si
252                 pop es
253 ;
254 ; Find the kernel on disk
255 ;
256 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
257 %if IS_SYSLINUX || IS_MDSLINUX                  ; SYSLINUX has to deal with DOS mangled names...
258                 mov eax,[KernelName+8]          ; Save initial extension
259                 mov [exten_table_end],eax       ; Last case == initial ext.
260 %else
261                 mov di,KernelName
262                 xor al,al
263                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
264                 repne scasb                     ; Scan for final null
265                 jne .no_skip
266                 dec di                          ; Point to final null 
267 .no_skip:       mov [KernelExtPtr],di
268 %endif
269                 mov bx,exten_table
270 .search_loop:   push bx
271                 mov di,KernelName               ; Search on disk
272                 call searchdir
273                 pop bx
274                 jnz kernel_good
275                 mov eax,[bx]                    ; Try a different extension
276 %if IS_SYSLINUX || IS_MDSLINUX
277                 mov [KernelName+8],eax
278 %else
279                 mov si,[KernelExtPtr]
280                 mov [si],eax
281                 mov byte [si+4],0
282 %endif
283                 add bx,byte 4
284                 cmp bx,exten_table_end
285                 jna .search_loop                ; allow == case (final case)
286                 ; Fall into bad_kernel
287 ;
288 ; bad_kernel: Kernel image not found
289 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
290 ;
291 bad_implicit:
292 bad_kernel:
293                 mov cx,[OnerrorLen]
294                 and cx,cx
295                 jnz on_error
296 .really:
297                 mov si,KernelName
298                 mov di,KernelCName
299                 push di
300                 call unmangle_name              ; Get human form
301                 mov si,err_notfound             ; Complain about missing kernel
302                 call cwritestr
303                 pop si                          ; KernelCName
304                 call cwritestr
305                 mov si,crlf_msg
306                 jmp abort_load                  ; Ask user for clue
307
308 ;
309 ; on_error: bad kernel, but we have onerror set
310 ;
311 on_error:
312                 mov si,Onerror
313                 mov di,command_line
314                 push si                         ; <A>
315                 push di                         ; <B>
316                 push cx                         ; <C>
317                 push cx                         ; <D>
318                 push di                         ; <E>
319                 repe cmpsb
320                 pop di                          ; <E> di == command_line
321                 pop bx                          ; <D> bx == [OnerrorLen]
322                 je bad_kernel.really            ; Onerror matches command_line already
323                 neg bx                          ; bx == -[OnerrorLen]
324                 lea cx,[max_cmd_len+bx]
325                 ; CX == max_cmd_len-[OnerrorLen]
326                 mov di,command_line+max_cmd_len-1
327                 mov byte [di+1],0               ; Enforce null-termination
328                 lea si,[di+bx]
329                 std
330                 rep movsb                       ; Make space in command_line
331                 cld
332                 pop cx                          ; <C> cx == [OnerrorLen]
333                 pop di                          ; <B> di == command_line
334                 pop si                          ; <A> si  == Onerror
335                 rep movsb
336                 jmp load_kernel
337
338 ;
339 ; vk_found: We *are* using a "virtual kernel"
340 ;
341 vk_found:       popa
342                 push di
343                 mov di,VKernelBuf
344                 mov cx,vk_size >> 2
345                 rep movsd
346                 push es                         ; Restore old DS
347                 pop ds
348                 push es
349                 push word real_mode_seg
350                 pop es
351                 mov di,cmd_line_here
352                 mov si,VKernelBuf+vk_append
353                 mov cx,[VKernelBuf+vk_appendlen]
354                 rep movsb
355                 mov [CmdLinePtr],di             ; Where to add rest of cmd
356                 pop es
357                 pop di                          ; DI -> KernelName
358                 push di 
359                 mov si,VKernelBuf+vk_rname
360                 mov cx,FILENAME_MAX             ; We need ECX == CX later
361                 rep movsb
362                 pop di
363 %if IS_PXELINUX
364                 mov al,[VKernelBuf+vk_ipappend]
365                 mov [IPAppend],al
366 %endif
367                 xor bx,bx                       ; Try only one version
368
369 %if IS_SYSLINUX || IS_MDSLINUX
370                 jmp get_kernel
371 %else
372                 ; Is this a "localboot" pseudo-kernel?
373                 cmp byte [VKernelBuf+vk_rname], 0
374                 jne get_kernel          ; No, it's real, go get it
375
376                 mov ax, [VKernelBuf+vk_rname+1]
377                 jmp local_boot
378 %endif
379
380 ;
381 ; kernel_corrupt: Called if the kernel file does not seem healthy
382 ;
383 kernel_corrupt: mov si,err_notkernel
384                 jmp abort_load
385 ;
386 ; This is it!  We have a name (and location on the disk)... let's load
387 ; that sucker!!  First we have to decide what kind of file this is; base
388 ; that decision on the file extension.  The following extensions are
389 ; recognized; case insensitive:
390 ;
391 ; .com  - COMBOOT image
392 ; .cbt  - COMBOOT image
393 ; .c32  - COM32 image
394 ; .bs   - Boot sector
395 ; .0    - PXE bootstrap program (PXELINUX only)
396 ; .bin  - Boot sector
397 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
398 ; .img  - Floppy image (ISOLINUX only)
399 ;
400 ; Anything else is assumed to be a Linux kernel.
401 ;
402 kernel_good:
403                 pusha
404                 mov si,KernelName
405                 mov di,KernelCName
406                 call unmangle_name
407                 sub di,KernelCName
408                 mov [KernelCNameLen],di
409                 popa
410                 
411 %if IS_SYSLINUX || IS_MDSLINUX
412                 mov ecx,[KernelName+7]
413                 mov cl,'.'
414 %else
415                 push di
416                 push ax
417                 mov di,KernelName
418                 xor al,al
419                 mov cx,FILENAME_MAX
420                 repne scasb
421                 jne .one_step
422                 dec di
423 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
424                 pop ax
425                 pop di
426 %endif
427
428 ;
429 ; At this point, DX:AX contains the size of the kernel, and SI contains
430 ; the file handle/cluster pointer.
431 ;
432                 or ecx,20202000h                ; Force lower case
433
434                 cmp ecx,'.com'
435                 je is_comboot_image
436                 cmp ecx,'.cbt'
437                 je is_comboot_image
438                 cmp ecx,'.c32'
439                 je is_com32_image
440 %if IS_ISOLINUX
441                 cmp ecx,'.img'
442                 je is_disk_image
443 %endif
444                 cmp ecx,'.bss'
445                 je is_bss_sector
446                 cmp ecx,'.bin'
447                 je is_bootsector
448 %if IS_SYSLINUX || IS_MDSLINUX
449                 cmp ecx,'.bs '
450                 je is_bootsector
451                 cmp ecx,'.0  '
452                 je is_bootsector
453 %else
454                 shr ecx,8
455                 cmp ecx,'.bs'
456                 je is_bootsector
457                 shr ecx,8
458                 cmp cx,'.0'
459                 je is_bootsector
460 %endif
461                 ; Otherwise Linux kernel
462