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