Workaround for VMware console bug; make more common code common
[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                 jnz ctrl_f                      ; Keystroke after <Ctrl-F>
76                 cmp di,max_cmd_len+command_line ; Check there's space
77                 jnb short get_char
78                 stosb                           ; Save it
79                 call writechr                   ; Echo to screen
80                 jmp short get_char
81 not_ascii:
82                 cmp al,0Dh                      ; Enter
83                 je command_done
84                 cmp al,'F' & 1Fh                ; <Ctrl-F>
85                 je set_func_flag
86 %if IS_PXELINUX
87                 cmp al,'N' & 1Fh                ; <Ctrl-N>
88                 je show_network_info
89 %endif
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 get_char_2:
104                 jmp short get_char
105
106 kill_command:
107                 call crlf
108                 jmp enter_command
109
110 force_text_mode:
111                 call vgaclearmode
112                 jmp enter_command
113
114 set_func_flag:
115                 mov byte [FuncFlag],1
116                 jmp short get_char_2
117
118 ctrl_f:
119                 xor ah,ah
120                 mov [FuncFlag],ah
121                 cmp al,'0'
122                 jb get_char_2
123                 je .zero                        ; <Ctrl-F>0 = F10
124                 or al,20h                       ; Lower case
125                 cmp al,'9'
126                 jna .digit
127                 cmp al,'a'                      ; F10-F12 = <Ctrl-F>A, B, C
128                 jb get_char_2
129                 cmp al,'c'
130                 ja get_char_2
131                 sub al,'a'-10
132                 jmp show_help
133 .zero:
134                 mov al,10
135                 jmp show_help
136 .digit:
137                 sub al,'1'
138                 jmp show_help
139
140 func_key:
141                 ; AL = 0 if we get here
142                 xchg al,ah
143                 cmp al,44h                      ; F10
144                 ja .f11_f12
145                 sub al,3Bh                      ; F1
146                 jb get_char_2
147                 jmp show_help
148 .f11_f12:
149                 cmp al,85h                      ; F11
150                 jb get_char_2
151                 cmp al,86h                      ; F12
152                 ja get_char_2
153                 sub al,85h-10
154
155 show_help:      ; AX = func key # (0 = F1, 9 = F10, 11 = F12)
156                 push di                         ; Save end-of-cmdline pointer
157                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
158                 add ax,FKeyName
159                 xchg di,ax
160                 cmp byte [di+NULLOFFSET],NULLFILE
161                 je short fk_nofile              ; Undefined F-key
162                 call searchdir
163                 jz short fk_nofile              ; File not found
164                 push si
165                 call crlf
166                 pop si
167                 call get_msg_file
168                 jmp short fk_wrcmd
169
170 print_version:
171                 push di                         ; Command line write pointer
172                 mov si,syslinux_banner
173                 call cwritestr
174 %ifdef HAVE_BIOSNAME
175                 mov si,[BIOSName]
176                 call cwritestr
177 %endif
178                 mov si,copyright_str
179                 call cwritestr
180
181                 ; ... fall through ...
182
183                 ; Write the boot prompt and command line again and
184                 ; wait for input.  Note that this expects the cursor
185                 ; to already have been CRLF'd, and that the old value
186                 ; of DI (the command line write pointer) is on the stack.
187 fk_wrcmd:
188                 mov si,boot_prompt
189                 call cwritestr
190                 pop di                          ; Command line write pointer
191                 push di
192                 mov byte [di],0                 ; Null-terminate command line
193                 mov si,command_line
194                 call cwritestr                  ; Write command line so far
195 fk_nofile:      pop di
196                 jmp get_char
197
198 ;
199 ; Show network info (in the form of the ipappend strings)
200 ;
201 %if IS_PXELINUX
202 show_network_info:
203                 push di                         ; Command line write pointer
204                 call crlf
205                 mov si,IPAppends                ; See comboot.doc
206                 mov cx,numIPAppends
207 .loop:
208                 lodsw
209                 push si
210                 mov si,ax
211                 call cwritestr
212                 call crlf
213                 pop si
214                 loop .loop
215                 jmp fk_wrcmd
216 %endif
217
218 ;
219 ; Jump here to run the default command line
220 ;
221 auto_boot:
222                 mov si,default_cmd
223                 mov di,command_line
224                 mov cx,(max_cmd_len+4) >> 2
225                 rep movsd
226                 jmp short load_kernel
227
228 ;
229 ; Jump here when the command line is completed
230 ;
231 command_done:
232                 call crlf
233                 cmp di,command_line             ; Did we just hit return?
234                 je auto_boot
235                 xor al,al                       ; Store a final null
236                 stosb
237
238 load_kernel:                                    ; Load the kernel now
239 ;
240 ; First we need to mangle the kernel name the way DOS would...
241 ;
242                 mov si,command_line
243                 mov di,KernelName
244                 push si
245                 call mangle_name
246                 pop si
247 ;
248 ; Fast-forward to first option (we start over from the beginning, since
249 ; mangle_name doesn't necessarily return a consistent ending state.)
250 ;
251 clin_non_wsp:   lodsb
252                 cmp al,' '
253                 ja clin_non_wsp
254 clin_is_wsp:    and al,al
255                 jz clin_opt_ptr
256                 lodsb
257                 cmp al,' '
258                 jbe clin_is_wsp
259 clin_opt_ptr:   dec si                          ; Point to first nonblank
260                 mov [CmdOptPtr],si              ; Save ptr to first option
261 ;
262 ; If "allowoptions 0", put a null character here in order to ignore any
263 ; user-specified options.
264 ;
265                 mov ax,[AllowOptions]
266                 and ax,ax
267                 jnz clin_opt_ok
268                 mov [si],al
269 clin_opt_ok:
270
271 ;
272 ; Now check if it is a "virtual kernel"
273 ;
274 vk_check:
275                 xor si,si                       ; Beginning of vk_seg
276 .scan:
277                 cmp si,[VKernelBytes]
278                 jae .not_vk
279
280                 push ds
281                 push word vk_seg
282                 pop ds
283
284                 mov di,VKernelBuf
285                 call rllunpack
286                 pop ds
287                 ; SI updated on return
288
289                 sub di,cx                       ; Return to beginning of buf
290                 push si
291                 mov si,KernelName
292                 mov cx,FILENAME_MAX
293                 es repe cmpsb
294                 pop si
295                 je .found
296                 jmp .scan
297
298 ;
299 ; We *are* using a "virtual kernel"
300 ;
301 .found:
302                 push es
303                 push word real_mode_seg
304                 pop es
305                 mov di,cmd_line_here
306                 mov si,VKernelBuf+vk_append
307                 mov cx,[VKernelBuf+vk_appendlen]
308                 rep movsb
309                 mov [CmdLinePtr],di             ; Where to add rest of cmd
310                 pop es
311                 mov di,KernelName
312                 push di
313                 mov si,VKernelBuf+vk_rname
314                 mov cx,FILENAME_MAX             ; We need ECX == CX later
315                 rep movsb
316                 pop di
317 %if IS_PXELINUX
318                 mov al,[VKernelBuf+vk_ipappend]
319                 mov [IPAppend],al
320 %endif
321                 xor bx,bx                       ; Try only one version
322
323                 mov al, [VKernelBuf+vk_type]
324                 mov [KernelType], al
325
326 %if IS_PXELINUX || IS_ISOLINUX
327                 ; Is this a "localboot" pseudo-kernel?
328 %if IS_PXELINUX
329                 cmp byte [VKernelBuf+vk_rname+4], 0
330 %else
331                 cmp byte [VKernelBuf+vk_rname], 0
332 %endif
333                 jne get_kernel          ; No, it's real, go get it
334
335                 mov ax, [VKernelBuf+vk_rname+1]
336                 jmp local_boot
337 %else
338                 jmp get_kernel
339 %endif
340
341 .not_vk:
342
343 ;
344 ; Not a "virtual kernel" - check that's OK and construct the command line
345 ;
346                 cmp word [AllowImplicit],byte 0
347                 je bad_implicit
348                 push es
349                 push si
350                 push di
351                 mov di,real_mode_seg
352                 mov es,di
353                 mov si,AppendBuf
354                 mov di,cmd_line_here
355                 mov cx,[AppendLen]
356                 rep movsb
357                 mov [CmdLinePtr],di
358                 pop di
359                 pop si
360                 pop es
361
362                 mov [KernelType], cl            ; CL == 0 here
363
364 ;
365 ; Find the kernel on disk
366 ;
367 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
368                 mov di,KernelName+4*IS_PXELINUX
369                 xor al,al
370                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
371                 repne scasb                     ; Scan for final null
372                 jne .no_skip
373                 dec di                          ; Point to final null
374 .no_skip:       mov [KernelExtPtr],di
375                 mov bx,exten_table
376 .search_loop:   push bx
377                 mov di,KernelName               ; Search on disk
378                 call searchdir
379                 pop bx
380                 jnz kernel_good
381                 mov eax,[bx]                    ; Try a different extension
382                 mov si,[KernelExtPtr]
383                 mov [si],eax
384                 mov byte [si+4],0
385                 add bx,byte 4
386                 cmp bx,exten_table_end
387                 jna .search_loop                ; allow == case (final case)
388                 ; Fall into bad_kernel
389 ;
390 ; bad_kernel: Kernel image not found
391 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
392 ;
393 bad_implicit:
394 bad_kernel:
395                 mov cx,[OnerrorLen]
396                 and cx,cx
397                 jnz on_error
398 .really:
399                 mov si,KernelName
400                 mov di,KernelCName
401                 push di
402                 call unmangle_name              ; Get human form
403                 mov si,err_notfound             ; Complain about missing kernel
404                 call cwritestr
405                 pop si                          ; KernelCName
406                 call cwritestr
407                 mov si,crlf_msg
408                 jmp abort_load                  ; Ask user for clue
409
410 ;
411 ; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
412 ;
413 on_error:
414                 mov si,Onerror
415                 mov di,command_line
416                 push si                         ; <A>
417                 push di                         ; <B>
418                 push cx                         ; <C>
419                 push cx                         ; <D>
420                 push di                         ; <E>
421                 repe cmpsb
422                 pop di                          ; <E> di == command_line
423                 pop bx                          ; <D> bx == [OnerrorLen]
424                 je bad_kernel.really            ; Onerror matches command_line already
425                 neg bx                          ; bx == -[OnerrorLen]
426                 lea cx,[max_cmd_len+bx]
427                 ; CX == max_cmd_len-[OnerrorLen]
428                 mov di,command_line+max_cmd_len-1
429                 mov byte [di+1],0               ; Enforce null-termination
430                 lea si,[di+bx]
431                 std
432                 rep movsb                       ; Make space in command_line
433                 cld
434                 pop cx                          ; <C> cx == [OnerrorLen]
435                 pop di                          ; <B> di == command_line
436                 pop si                          ; <A> si  == Onerror
437                 rep movsb
438                 jmp load_kernel
439
440 ;
441 ; kernel_corrupt: Called if the kernel file does not seem healthy
442 ;
443 kernel_corrupt: mov si,err_notkernel
444                 jmp abort_load
445
446 ;
447 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
448 ; which can be adjusted by the caller based on the corresponding
449 ; master variables; on return they're updated.
450 ;
451 ; This cheats.  If we say "no timeout" we actually get a timeout of
452 ; 7.5 years.
453 ;
454 getchar_timeout:
455                 call vgashowcursor
456                 RESET_IDLE
457
458 .loop:
459                 push word [BIOS_timer]
460                 call pollchar
461                 jnz .got_char
462                 pop ax
463                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
464                 je .loop
465                 DO_IDLE
466
467                 dec dword [ThisKbdTo]
468                 jz .timeout
469                 dec dword [ThisTotalTo]
470                 jnz .loop
471
472 .timeout:
473                 ; Timeout!!!!
474                 pop cx                          ; Discard return address
475                 call vgahidecursor
476                 mov si,Ontimeout                ; Copy ontimeout command
477                 mov di,command_line
478                 mov cx,[OntimeoutLen]           ; if we have one...
479                 rep movsb
480                 jmp command_done
481
482 .got_char:
483                 pop cx                          ; Discard
484                 call getchar
485                 call vgahidecursor
486                 ret
487
488 ;
489 ; This is it!  We have a name (and location on the disk)... let's load
490 ; that sucker!!  First we have to decide what kind of file this is; base
491 ; that decision on the file extension.  The following extensions are
492 ; recognized; case insensitive:
493 ;
494 ; .com  - COMBOOT image
495 ; .cbt  - COMBOOT image
496 ; .c32  - COM32 image
497 ; .bs   - Boot sector
498 ; .0    - PXE bootstrap program (PXELINUX only)
499 ; .bin  - Boot sector
500 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
501 ; .img  - Floppy image (ISOLINUX only)
502 ;
503 ; Anything else is assumed to be a Linux kernel.
504 ;
505                 section .bss
506                 alignb 4
507 Kernel_EAX      resd 1
508 Kernel_SI       resw 1
509
510                 section .text
511 kernel_good_saved:
512                 ; Alternate entry point for which the return from
513                 ; searchdir is stored in memory.  This is used for
514                 ; COMBOOT function INT 22h, AX=0016h.
515                 mov si,[Kernel_SI]
516                 mov eax,[Kernel_EAX]
517                 mov dx,[Kernel_EAX+2]
518
519 kernel_good:
520                 pusha
521                 mov si,KernelName
522                 mov di,KernelCName
523                 call unmangle_name
524                 sub di,KernelCName
525                 mov [KernelCNameLen],di
526                 popa
527
528                 push di
529                 push ax
530                 mov di,KernelName+4*IS_PXELINUX
531                 xor al,al
532                 mov cx,FILENAME_MAX
533                 repne scasb
534                 jne .one_step
535                 dec di
536 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
537                 pop ax
538                 pop di
539
540 ;
541 ; At this point, DX:AX contains the size of the kernel, SI contains
542 ; the file handle/cluster pointer, and ECX contains the extension (if any.)
543 ;
544                 movzx di,byte [KernelType]
545                 add di,di
546                 jmp [kerneltype_table+di]
547
548 is_unknown_filetype:
549                 or ecx,20202000h                ; Force lower case (except dot)
550
551                 cmp ecx,'.com'
552                 je is_comboot_image
553                 cmp ecx,'.cbt'
554                 je is_comboot_image
555                 cmp ecx,'.c32'
556                 je is_com32_image
557 %if IS_ISOLINUX
558                 cmp ecx,'.img'
559                 je is_disk_image
560 %endif
561                 cmp ecx,'.bss'
562                 je is_bss_sector
563                 cmp ecx,'.bin'
564                 je is_bootsector
565                 shr ecx,8
566                 cmp ecx,'.bs'
567                 je is_bootsector
568                 shr ecx,8
569                 cmp cx,'.0'
570                 je is_bootsector
571
572                 ; Otherwise Linux kernel
573                 jmp is_linux_kernel
574
575 is_config_file:
576                 pusha
577                 mov si,KernelCName              ; Save the config file name, for posterity
578                 mov di,ConfigName
579                 call strcpy
580                 popa
581                 call openfd
582                 call reset_config
583                 jmp load_config_file
584
585 ; This is an image type we can't deal with
586 is_bad_image:
587                 mov si,err_badimage
588                 call cwritestr
589                 jmp enter_command
590
591 %if IS_SYSLINUX || IS_MDSLINUX
592                 ; ok
593 %else
594 is_bss_sector   equ is_bad_image
595 %endif
596 %if IS_ISOLINUX
597                 ; ok
598 %else
599 is_disk_image   equ is_bad_image
600 %endif
601
602                 section .data
603 err_badimage    db 'Invalid image type for this media type!', CR, LF, 0
604
605                 align 2, db 0
606 kerneltype_table:
607                 dw is_unknown_filetype  ; VK_KERNEL
608                 dw is_linux_kernel      ; VK_LINUX
609                 dw is_bootsector        ; VK_BOOT
610                 dw is_bss_sector        ; VK_BSS
611                 dw is_bootsector        ; VK_PXE
612                 dw is_disk_image        ; VK_FDIMAGE
613                 dw is_comboot_image     ; VK_COMBOOT
614                 dw is_com32_image       ; VK_COM32
615                 dw is_config_file       ; VK_CONFIG
616
617                 section .bss
618                 alignb 4
619 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
620 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
621 KernelExtPtr    resw 1                  ; During search, final null pointer
622 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
623 KbdFlags        resb 1                  ; Check for keyboard escapes
624 FuncFlag        resb 1                  ; Escape sequences received from keyboard
625 KernelType      resb 1                  ; Kernel type, from vkernel, if known
626
627                 section .text
628 ;
629 ; Linux kernel loading code is common.
630 ;
631 %include "runkernel.inc"
632
633 ;
634 ; COMBOOT-loading code
635 ;
636 %include "comboot.inc"
637 %include "com32.inc"
638 %include "cmdline.inc"
639
640 ;
641 ; Boot sector loading code
642 ;
643 %include "bootsect.inc"
644
645 ;
646 ; Abort loading code
647 ;
648 %include "abort.inc"
649
650 ;
651 ; Hardware cleanup common code
652 ;
653 %include "cleanup.inc"