Merge with syslinux-3.35
[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                 push di
203                 call mangle_name
204                 pop di
205                 pop si
206 ;
207 ; Fast-forward to first option (we start over from the beginning, since
208 ; mangle_name doesn't necessarily return a consistent ending state.)
209 ;
210 clin_non_wsp:   lodsb
211                 cmp al,' '
212                 ja clin_non_wsp
213 clin_is_wsp:    and al,al
214                 jz clin_opt_ptr
215                 lodsb
216                 cmp al,' '
217                 jbe clin_is_wsp
218 clin_opt_ptr:   dec si                          ; Point to first nonblank
219                 mov [CmdOptPtr],si              ; Save ptr to first option
220 ;
221 ; If "allowoptions 0", put a null character here in order to ignore any
222 ; user-specified options.
223 ;
224                 mov ax,[AllowOptions]
225                 and ax,ax
226                 jnz clin_opt_ok
227                 mov [si],al
228 clin_opt_ok:
229
230 ;
231 ; Now check if it is a "virtual kernel"
232 ;
233 vk_check:
234                 xor si,si                       ; Beginning of vk_seg
235 .scan:
236                 cmp si,[VKernelBytes]
237                 jae .not_vk
238
239                 push ds
240                 push word vk_seg
241                 pop ds
242
243                 mov di,VKernelBuf
244                 call rllunpack
245                 pop ds
246                 ; SI updated on return
247
248                 sub di,cx                       ; Return to beginning of buf
249                 push si
250                 mov si,KernelName
251                 mov cx,FILENAME_MAX
252                 es repe cmpsb
253                 pop si
254                 je .found
255                 jmp .scan
256
257 ;
258 ; We *are* using a "virtual kernel"
259 ;
260 .found:
261                 push es
262                 push word real_mode_seg
263                 pop es
264                 mov di,cmd_line_here
265                 mov si,VKernelBuf+vk_append
266                 mov cx,[VKernelBuf+vk_appendlen]
267                 rep movsb
268                 mov [CmdLinePtr],di             ; Where to add rest of cmd
269                 pop es
270                 mov di,KernelName
271                 push di
272                 mov si,VKernelBuf+vk_rname
273                 mov cx,FILENAME_MAX             ; We need ECX == CX later
274                 rep movsb
275                 pop di
276 %if IS_PXELINUX
277                 mov al,[VKernelBuf+vk_ipappend]
278                 mov [IPAppend],al
279 %endif
280                 xor bx,bx                       ; Try only one version
281
282                 mov al, [VKernelBuf+vk_type]
283                 mov [KernelType], al
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                 mov [KernelType], cl            ; CL == 0 here
322
323 ;
324 ; Find the kernel on disk
325 ;
326 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
327 %if IS_SYSLINUX || IS_MDSLINUX                  ; SYSLINUX has to deal with DOS mangled names...
328                 mov eax,[KernelName+8]          ; Save initial extension
329                 mov [exten_table_end],eax       ; Last case == initial ext.
330 %else
331                 mov di,KernelName+4*IS_PXELINUX
332                 xor al,al
333                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
334                 repne scasb                     ; Scan for final null
335                 jne .no_skip
336                 dec di                          ; Point to final null
337 .no_skip:       mov [KernelExtPtr],di
338 %endif
339                 mov bx,exten_table
340 .search_loop:   push bx
341                 mov di,KernelName               ; Search on disk
342                 call searchdir
343                 pop bx
344                 jnz kernel_good
345                 mov eax,[bx]                    ; Try a different extension
346 %if IS_SYSLINUX || IS_MDSLINUX
347                 mov [KernelName+8],eax
348 %else
349                 mov si,[KernelExtPtr]
350                 mov [si],eax
351                 mov byte [si+4],0
352 %endif
353                 add bx,byte 4
354                 cmp bx,exten_table_end
355                 jna .search_loop                ; allow == case (final case)
356                 ; Fall into bad_kernel
357 ;
358 ; bad_kernel: Kernel image not found
359 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
360 ;
361 bad_implicit:
362 bad_kernel:
363                 mov cx,[OnerrorLen]
364                 and cx,cx
365                 jnz on_error
366 .really:
367                 mov si,KernelName
368                 mov di,KernelCName
369                 push di
370                 call unmangle_name              ; Get human form
371                 mov si,err_notfound             ; Complain about missing kernel
372                 call cwritestr
373                 pop si                          ; KernelCName
374                 call cwritestr
375                 mov si,crlf_msg
376                 jmp abort_load                  ; Ask user for clue
377
378 ;
379 ; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
380 ;
381 on_error:
382                 mov si,Onerror
383                 mov di,command_line
384                 push si                         ; <A>
385                 push di                         ; <B>
386                 push cx                         ; <C>
387                 push cx                         ; <D>
388                 push di                         ; <E>
389                 repe cmpsb
390                 pop di                          ; <E> di == command_line
391                 pop bx                          ; <D> bx == [OnerrorLen]
392                 je bad_kernel.really            ; Onerror matches command_line already
393                 neg bx                          ; bx == -[OnerrorLen]
394                 lea cx,[max_cmd_len+bx]
395                 ; CX == max_cmd_len-[OnerrorLen]
396                 mov di,command_line+max_cmd_len-1
397                 mov byte [di+1],0               ; Enforce null-termination
398                 lea si,[di+bx]
399                 std
400                 rep movsb                       ; Make space in command_line
401                 cld
402                 pop cx                          ; <C> cx == [OnerrorLen]
403                 pop di                          ; <B> di == command_line
404                 pop si                          ; <A> si  == Onerror
405                 rep movsb
406                 jmp load_kernel
407
408 ;
409 ; kernel_corrupt: Called if the kernel file does not seem healthy
410 ;
411 kernel_corrupt: mov si,err_notkernel
412                 jmp abort_load
413
414 ;
415 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
416 ; which can be adjusted by the caller based on the corresponding
417 ; master variables; on return they're updated.
418 ;
419 ; This cheats.  If we say "no timeout" we actually get a timeout of
420 ; 7.5 years.
421 ;
422 getchar_timeout:
423                 call vgashowcursor
424                 RESET_IDLE
425
426 .loop:
427                 push word [BIOS_timer]
428                 call pollchar
429                 jnz .got_char
430                 pop ax
431                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
432                 je .loop
433                 DO_IDLE
434
435                 dec dword [ThisKbdTo]
436                 jz .timeout
437                 dec dword [ThisTotalTo]
438                 jnz .loop
439
440 .timeout:
441                 ; Timeout!!!!
442                 pop cx                          ; Discard return address
443                 call vgahidecursor
444                 mov si,Ontimeout                ; Copy ontimeout command
445                 mov di,command_line
446                 mov cx,[OntimeoutLen]           ; if we have one...
447                 rep movsb
448                 jmp command_done
449
450 .got_char:
451                 pop cx                          ; Discard
452                 call getchar
453                 call vgahidecursor
454                 ret
455
456 ;
457 ; This is it!  We have a name (and location on the disk)... let's load
458 ; that sucker!!  First we have to decide what kind of file this is; base
459 ; that decision on the file extension.  The following extensions are
460 ; recognized; case insensitive:
461 ;
462 ; .com  - COMBOOT image
463 ; .cbt  - COMBOOT image
464 ; .c32  - COM32 image
465 ; .bs   - Boot sector
466 ; .0    - PXE bootstrap program (PXELINUX only)
467 ; .bin  - Boot sector
468 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
469 ; .img  - Floppy image (ISOLINUX only)
470 ;
471 ; Anything else is assumed to be a Linux kernel.
472 ;
473                 section .bss
474                 alignb 4
475 Kernel_EAX      resd 1
476 Kernel_SI       resw 1
477
478                 section .text
479 kernel_good_saved:
480                 ; Alternate entry point for which the return from
481                 ; searchdir is stored in memory.  This is used for
482                 ; COMBOOT function INT 22h, AX=0016h.
483                 mov si,[Kernel_SI]
484                 mov eax,[Kernel_EAX]
485                 mov dx,[Kernel_EAX+2]
486
487 kernel_good:
488                 pusha
489                 mov si,KernelName
490                 mov di,KernelCName
491                 call unmangle_name
492                 sub di,KernelCName
493                 mov [KernelCNameLen],di
494                 popa
495
496 %if IS_SYSLINUX || IS_MDSLINUX
497                 mov ecx,[KernelName+7]
498                 mov cl,'.'
499 %else
500                 push di
501                 push ax
502                 mov di,KernelName+4*IS_PXELINUX
503                 xor al,al
504                 mov cx,FILENAME_MAX
505                 repne scasb
506                 jne .one_step
507                 dec di
508 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
509                 pop ax
510                 pop di
511 %endif
512
513 ;
514 ; At this point, DX:AX contains the size of the kernel, SI contains
515 ; the file handle/cluster pointer, and ECX contains the extension (if any.)
516 ;
517                 movzx di,byte [KernelType]
518                 add di,di
519                 jmp [kerneltype_table+di]
520
521 is_unknown_filetype:
522                 or ecx,20202000h                ; Force lower case (except dot)
523
524                 cmp ecx,'.com'
525                 je is_comboot_image
526                 cmp ecx,'.cbt'
527                 je is_comboot_image
528                 cmp ecx,'.c32'
529                 je is_com32_image
530 %if IS_ISOLINUX
531                 cmp ecx,'.img'
532                 je is_disk_image
533 %endif
534                 cmp ecx,'.bss'
535                 je is_bss_sector
536                 cmp ecx,'.bin'
537                 je is_bootsector
538 %if IS_SYSLINUX || IS_MDSLINUX
539                 cmp ecx,'.bs '
540                 je is_bootsector
541                 cmp ecx,'.0  '
542                 je is_bootsector
543 %else
544                 shr ecx,8
545                 cmp ecx,'.bs'
546                 je is_bootsector
547                 shr ecx,8
548                 cmp cx,'.0'
549                 je is_bootsector
550 %endif
551                 ; Otherwise Linux kernel
552                 jmp is_linux_kernel
553
554 is_config_file:
555                 call openfd
556                 call reset_config
557                 jmp load_config_file
558
559 ; This is an image type we can't deal with
560 is_bad_image:
561                 mov si,err_badimage
562                 call cwritestr
563                 jmp enter_command
564
565 %if IS_SYSLINUX || IS_MDSLINUX
566                 ; ok
567 %else
568 is_bss_sector   equ is_bad_image
569 %endif
570 %if IS_ISOLINUX
571                 ; ok
572 %else
573 is_disk_image   equ is_bad_image
574 %endif
575
576                 section .data
577 err_badimage    db 'Invalid image type for this media type!', CR, LF, 0
578
579                 align 2, db 0
580 kerneltype_table:
581                 dw is_unknown_filetype  ; VK_KERNEL
582                 dw is_linux_kernel      ; VK_LINUX
583                 dw is_bootsector        ; VK_BOOT
584                 dw is_bss_sector        ; VK_BSS
585                 dw is_disk_image        ; VK_FDIMAGE
586                 dw is_comboot_image     ; VK_COMBOOT
587                 dw is_com32_image       ; VK_COM32
588                 dw is_config_file       ; VK_CONFIG
589
590                 section .bss
591                 alignb 4
592 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
593 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
594 KernelExtPtr    resw 1                  ; During search, final null pointer
595 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
596 KbdFlags        resb 1                  ; Check for keyboard escapes
597 FuncFlag        resb 1                  ; Escape sequences received from keyboard
598 KernelType      resb 1                  ; Kernel type, from vkernel, if known
599
600                 section .text