Merge branch 'master' into core32
[profile/ivi/syslinux.git] / core / ui.inc
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
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 load_config_file:
18                 call parse_config               ; Parse configuration file
19 no_config_file:
20
21                 call adv_init
22 ;
23 ; Check for an ADV boot-once entry
24 ;
25                 mov dl,ADV_BOOTONCE
26                 call adv_get
27                 jcxz .no_bootonce
28
29 .have_bootone:
30                 ; We apparently have a boot-once set; clear it and
31                 ; then execute the boot-once...
32
33                 ; Save the boot-once data; SI = data, CX = length
34                 mov di,command_line
35                 rep movsb
36                 xor ax,ax
37                 stosb
38
39                 ; Clear the boot-once data from the ADV
40                 xor cx,cx                       ; Set to zero = delete
41                 call adv_set
42                 jc .err
43                 call adv_write
44 .err:           jmp load_kernel
45
46 .no_bootonce:
47
48                 ; *** TEST HACK ***
49                 pm_call hello
50
51 ;
52 ; Check whether or not we are supposed to display the boot prompt.
53 ;
54 check_for_key:
55                 test byte [KbdFlags],5Bh        ; Shift Alt Caps Scroll
56                 jnz enter_command
57                 cmp word [ForcePrompt],0        ; Force prompt?
58                 jz auto_boot
59                 cmp word [DefaultLevel],1       ; Active UI statement?
60                 ja auto_boot
61
62 enter_command:
63                 cmp word [NoEscape],0           ; If NOESCAPE, no prompt,
64                 jne auto_boot                   ; always run default cmd
65
66                 mov si,boot_prompt
67                 call writestr
68
69                 mov byte [FuncFlag],0           ; <Ctrl-F> not pressed
70                 mov di,command_line
71
72 ;
73 ; get the very first character -- we can either time
74 ; out, or receive a character press at this time.  Some dorky BIOSes stuff
75 ; a return in the buffer on bootup, so wipe the keyboard buffer first.
76 ;
77 clear_buffer:   mov ah,11h                      ; Check for pending char
78                 int 16h
79                 jz get_char_time
80                 mov ah,10h                      ; Get char
81                 int 16h
82                 jmp short clear_buffer
83
84                 ; For the first character, both KbdTimeout and
85                 ; TotalTimeout apply; after that, only TotalTimeout.
86
87 get_char_time:
88                 mov eax,[TotalTimeout]
89                 mov [ThisTotalTo],eax
90                 mov eax,[KbdTimeout]
91                 mov [ThisKbdTo],eax
92
93 get_char:
94                 call getchar_timeout
95                 and dword [ThisKbdTo],0         ; For the next time...
96
97                 and al,al
98                 jz func_key
99
100 got_ascii:      cmp al,7Fh                      ; <DEL> == <BS>
101                 je backspace
102                 cmp al,' '                      ; ASCII?
103                 jb not_ascii
104                 ja enter_char
105                 cmp di,command_line             ; Space must not be first
106                 je short get_char
107 enter_char:     test byte [FuncFlag],1
108                 jnz ctrl_f                      ; Keystroke after <Ctrl-F>
109                 cmp di,max_cmd_len+command_line ; Check there's space
110                 jnb short get_char
111                 stosb                           ; Save it
112                 call writechr                   ; Echo to screen
113                 jmp short get_char
114 not_ascii:
115                 cmp al,0Dh                      ; Enter
116                 je command_done
117                 cmp al,09h                      ; Tab
118                 je display_labels
119                 cmp al,'F' & 1Fh                ; <Ctrl-F>
120                 je set_func_flag
121 %if IS_PXELINUX
122                 cmp al,'N' & 1Fh                ; <Ctrl-N>
123                 je show_network_info
124 %endif
125                 cmp al,'U' & 1Fh                ; <Ctrl-U>
126                 je kill_command                 ; Kill input line
127                 cmp al,'V' & 1Fh                ; <Ctrl-V>
128                 je print_version
129                 cmp al,'X' & 1Fh                ; <Ctrl-X>
130                 je force_text_mode
131                 cmp al,08h                      ; Backspace
132                 jne get_char
133 backspace:      cmp di,command_line             ; Make sure there is anything
134                 je get_char                     ; to erase
135                 dec di                          ; Unstore one character
136                 mov si,wipe_char                ; and erase it from the screen
137                 call writestr
138 get_char_2:
139                 jmp short get_char
140
141 kill_command:
142                 call crlf
143                 jmp enter_command
144
145 force_text_mode:
146                 call vgaclearmode
147                 jmp enter_command
148
149 set_func_flag:
150                 mov byte [FuncFlag],1
151                 jmp short get_char_2
152
153 display_labels:
154                 cmp word [NoComplete],0         ; Label completion enabled?
155                 jne get_char_2
156                 push di                         ; Save pointer
157                 mov cx,di
158                 sub cx,command_line
159                 call crlf
160                 mov esi,[HighMemSize]           ; Start from top of memory
161 .scan:
162                 cmp esi,[VKernelEnd]
163                 jbe .not_vk
164
165                 push cx                         ; save command line size
166
167                 mov edi,VKernelBuf
168                 pm_call rllunpack
169                 ; ESI updated on return
170
171                 sub di,cx                       ; Return to beginning of buf
172                 pop cx                          ; restore command line size
173                 push si                         ; save SI
174                 cmp cx,0
175                 jz .print
176                 push di
177                 push cx
178                 mov si,command_line
179                 es repe cmpsb
180                 pop cx
181                 pop di
182                 jne .next
183 .print:
184                 mov al,' '
185                 call writechr
186
187                 mov si,di
188                 call writestr
189 .next:
190                 pop si                          ; restore SI
191                 jmp .scan
192 .not_vk:
193                 call crlf
194                 jmp fk_wrcmd
195
196 ctrl_f:
197                 xor ah,ah
198                 mov [FuncFlag],ah
199                 cmp al,'0'
200                 jb get_char_2
201                 je .zero                        ; <Ctrl-F>0 = F10
202                 or al,20h                       ; Lower case
203                 cmp al,'9'
204                 jna .digit
205                 cmp al,'a'                      ; F10-F12 = <Ctrl-F>A, B, C
206                 jb get_char_2
207                 cmp al,'c'
208                 ja get_char_2
209                 sub al,'a'-10
210                 jmp show_help
211 .zero:
212                 mov al,10
213                 jmp show_help
214 .digit:
215                 sub al,'1'
216                 jmp show_help
217
218 func_key:
219                 ; AL = 0 if we get here
220                 xchg al,ah
221                 cmp al,44h                      ; F10
222                 ja .f11_f12
223                 sub al,3Bh                      ; F1
224                 jb get_char_2
225                 jmp show_help
226 .f11_f12:
227                 cmp al,85h                      ; F11
228                 jb get_char_2
229                 cmp al,86h                      ; F12
230                 ja get_char_2
231                 sub al,85h-10
232
233 show_help:      ; AX = func key # (0 = F1, 9 = F10, 11 = F12)
234                 push di                         ; Save end-of-cmdline pointer
235                 shl ax,FILENAME_MAX_LG2         ; Convert to pointer
236                 add ax,FKeyName
237                 xchg di,ax
238                 cmp byte [di+NULLOFFSET],NULLFILE
239                 je short fk_nofile              ; Undefined F-key
240                 call open
241                 jz short fk_nofile              ; File not found
242                 call crlf
243                 call get_msg_file
244                 jmp short fk_wrcmd
245
246 print_version:
247                 push di                         ; Command line write pointer
248                 mov si,syslinux_banner
249                 call writestr
250 %ifdef HAVE_BIOSNAME
251                 mov si,[BIOSName]
252                 call writestr
253 %endif
254                 mov si,copyright_str
255                 call writestr
256
257                 ; ... fall through ...
258
259                 ; Write the boot prompt and command line again and
260                 ; wait for input.  Note that this expects the cursor
261                 ; to already have been CRLF'd, and that the old value
262                 ; of DI (the command line write pointer) is on the stack.
263 fk_wrcmd:
264                 mov si,boot_prompt
265                 call writestr
266                 pop di                          ; Command line write pointer
267                 push di
268                 mov byte [di],0                 ; Null-terminate command line
269                 mov si,command_line
270                 call writestr                   ; Write command line so far
271 fk_nofile:      pop di
272                 jmp get_char
273
274 ;
275 ; Show network info (in the form of the ipappend strings)
276 ;
277 %if IS_PXELINUX
278 show_network_info:
279                 push di                         ; Command line write pointer
280                 call crlf
281                 mov si,IPAppends                ; See comboot.doc
282                 mov cx,numIPAppends
283 .loop:
284                 lodsw
285                 push si
286                 mov si,ax
287                 call writestr
288                 call crlf
289                 pop si
290                 loop .loop
291                 jmp fk_wrcmd
292 %endif
293
294 ;
295 ; Jump here to run the default command line
296 ;
297 auto_boot:
298                 mov si,default_cmd
299                 mov di,command_line
300                 mov cx,(max_cmd_len+4) >> 2
301                 rep movsd
302                 jmp short load_kernel
303
304 ;
305 ; Jump here when the command line is completed
306 ;
307 command_done:
308                 call crlf
309                 cmp di,command_line             ; Did we just hit return?
310                 je auto_boot
311                 xor al,al                       ; Store a final null
312                 stosb
313
314 load_kernel:                                    ; Load the kernel now
315 ;
316 ; First we need to mangle the kernel name the way DOS would...
317 ;
318                 mov si,command_line
319                 mov di,KernelName
320                 push si
321                 call mangle_name
322                 pop si
323 ;
324 ; Fast-forward to first option (we start over from the beginning, since
325 ; mangle_name doesn't necessarily return a consistent ending state.)
326 ;
327 clin_non_wsp:   lodsb
328                 cmp al,' '
329                 ja clin_non_wsp
330 clin_is_wsp:    and al,al
331                 jz clin_opt_ptr
332                 lodsb
333                 cmp al,' '
334                 jbe clin_is_wsp
335 clin_opt_ptr:   dec si                          ; Point to first nonblank
336                 mov [CmdOptPtr],si              ; Save ptr to first option
337 ;
338 ; If "allowoptions 0", put a null character here in order to ignore any
339 ; user-specified options.
340 ;
341                 mov ax,[AllowOptions]
342                 and ax,ax
343                 jnz clin_opt_ok
344                 mov [si],al
345 clin_opt_ok:
346
347 ;
348 ; Now check if it is a "virtual kernel"
349 ;
350 vk_check:
351                 mov esi,[HighMemSize]           ; Start from top of memory
352 .scan:
353                 cmp esi,[VKernelEnd]
354                 jbe .not_vk
355
356                 mov edi,VKernelBuf
357                 pm_call rllunpack
358                 ; ESI updated on return
359
360                 sub di,cx                       ; Return to beginning of buf
361                 push si
362                 mov si,command_line
363 .loop:
364                 lodsb
365                 cmp al,' '
366                 jbe .done
367                 scasb
368                 je .loop
369 .nomatch:
370                 pop si
371                 jmp .scan
372 .done:
373                 cmp byte [di],0                 ; Must match end of string
374                 jne .nomatch
375                 pop si
376
377 ;
378 ; We *are* using a "virtual kernel"
379 ;
380 .found:
381                 push es
382                 push word real_mode_seg
383                 pop es
384                 mov di,cmd_line_here
385                 mov si,VKernelBuf+vk_append
386                 mov cx,[VKernelBuf+vk_appendlen]
387                 rep movsb
388                 mov [CmdLinePtr],di             ; Where to add rest of cmd
389                 pop es
390                 mov di,KernelName
391                 push di
392                 mov si,VKernelBuf+vk_rname
393                 mov cx,FILENAME_MAX             ; We need ECX == CX later
394                 rep movsb
395                 pop di
396 %if IS_PXELINUX
397                 mov al,[VKernelBuf+vk_ipappend]
398                 mov [IPAppend],al
399 %endif
400                 xor bx,bx                       ; Try only one version
401
402                 mov al,[VKernelBuf+vk_type]
403                 mov [KernelType],al
404
405 %if HAS_LOCALBOOT
406                 ; Is this a "localboot" pseudo-kernel?
407                 cmp al,VK_LOCALBOOT             ; al == KernelType
408                 mov ax,[VKernelBuf+vk_rname]    ; Possible localboot type
409                 je local_boot
410 %endif
411                 jmp get_kernel
412
413 .not_vk:
414 ;
415 ; Not a "virtual kernel" - check that's OK and construct the command line
416 ;
417                 cmp word [AllowImplicit],byte 0
418                 je bad_implicit
419                 push es
420                 push si
421                 push di
422                 mov di,real_mode_seg
423                 mov es,di
424                 mov si,AppendBuf
425                 mov di,cmd_line_here
426                 mov cx,[AppendLen]
427                 rep movsb
428                 mov [CmdLinePtr],di
429                 pop di
430                 pop si
431                 pop es
432
433                 mov [KernelType], cl            ; CL == 0 here
434
435 ;
436 ; Find the kernel on disk
437 ;
438 get_kernel:     mov byte [KernelName+FILENAME_MAX],0    ; Zero-terminate filename/extension
439                 mov di,KernelName+4*IS_PXELINUX
440                 cmp byte [di],' '
441                 jbe bad_kernel                  ; Missing kernel name
442                 xor al,al
443                 mov cx,FILENAME_MAX-5           ; Need 4 chars + null
444                 repne scasb                     ; Scan for final null
445                 jne .no_skip
446                 dec di                          ; Point to final null
447 .no_skip:       mov [KernelExtPtr],di
448                 mov bx,exten_table
449 .search_loop:   push bx
450                 mov di,KernelName               ; Search on disk
451                 call searchdir
452                 pop bx
453                 jnz kernel_good
454                 mov eax,[bx]                    ; Try a different extension
455                 mov si,[KernelExtPtr]
456                 mov [si],eax
457                 mov byte [si+4],0
458                 add bx,byte 4
459                 cmp bx,exten_table_end
460                 jna .search_loop                ; allow == case (final case)
461                 ; Fall into bad_kernel
462 ;
463 ; bad_kernel: Kernel image not found
464 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
465 ;
466 bad_implicit:
467 bad_kernel:
468                 mov cx,[OnerrorLen]
469                 and cx,cx
470                 jnz on_error
471 .really:
472                 mov si,KernelName
473                 mov di,KernelCName
474                 push di
475                 call unmangle_name              ; Get human form
476                 mov si,err_notfound             ; Complain about missing kernel
477                 call writestr
478                 pop si                          ; KernelCName
479                 call writestr
480                 mov si,crlf_msg
481                 jmp abort_load                  ; Ask user for clue
482
483 ;
484 ; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
485 ;
486 on_error:
487                 mov si,Onerror
488                 mov di,command_line
489                 push si                         ; <A>
490                 push di                         ; <B>
491                 push cx                         ; <C>
492                 push cx                         ; <D>
493                 push di                         ; <E>
494                 repe cmpsb
495                 pop di                          ; <E> di == command_line
496                 pop bx                          ; <D> bx == [OnerrorLen]
497                 je bad_kernel.really            ; Onerror matches command_line already
498                 neg bx                          ; bx == -[OnerrorLen]
499                 lea cx,[max_cmd_len+bx]
500                 ; CX == max_cmd_len-[OnerrorLen]
501                 mov di,command_line+max_cmd_len-1
502                 mov byte [di+1],0               ; Enforce null-termination
503                 lea si,[di+bx]
504                 std
505                 rep movsb                       ; Make space in command_line
506                 cld
507                 pop cx                          ; <C> cx == [OnerrorLen]
508                 pop di                          ; <B> di == command_line
509                 pop si                          ; <A> si  == Onerror
510                 rep movsb
511                 jmp load_kernel
512
513 ;
514 ; kernel_corrupt: Called if the kernel file does not seem healthy
515 ;
516 kernel_corrupt: mov si,err_notkernel
517                 jmp abort_load
518
519 ;
520 ; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
521 ; which can be adjusted by the caller based on the corresponding
522 ; master variables; on return they're updated.
523 ;
524 ; This cheats.  If we say "no timeout" we actually get a timeout of
525 ; 7.5 years.
526 ;
527 getchar_timeout:
528                 call vgashowcursor
529                 call reset_idle
530
531 .loop:
532                 push word [BIOS_timer]
533                 call pollchar
534                 jnz .got_char
535                 pop ax
536                 cmp ax,[BIOS_timer]             ; Has the timer advanced?
537                 je .loop
538                 call do_idle
539
540                 dec dword [ThisKbdTo]
541                 jz .timeout
542                 dec dword [ThisTotalTo]
543                 jnz .loop
544
545 .timeout:
546                 ; Timeout!!!!
547                 pop cx                          ; Discard return address
548                 call vgahidecursor
549                 mov si,Ontimeout                ; Copy ontimeout command
550                 mov di,command_line
551                 mov cx,[OntimeoutLen]           ; if we have one...
552                 rep movsb
553                 jmp command_done
554
555 .got_char:
556                 pop cx                          ; Discard
557                 call getchar
558                 call vgahidecursor
559                 ret
560
561 ;
562 ; This is it!  We have a name (and location on the disk)... let's load
563 ; that sucker!!  First we have to decide what kind of file this is; base
564 ; that decision on the file extension.  The following extensions are
565 ; recognized; case insensitive:
566 ;
567 ; .com  - COMBOOT image
568 ; .cbt  - COMBOOT image
569 ; .c32  - COM32 image
570 ; .bs   - Boot sector
571 ; .0    - PXE bootstrap program (PXELINUX only)
572 ; .bin  - Boot sector
573 ; .bss  - Boot sector, but transfer over DOS superblock (SYSLINUX only)
574 ; .img  - Floppy image (ISOLINUX only)
575 ;
576 ; Anything else is assumed to be a Linux kernel.
577 ;
578                 section .bss16
579                 alignb 4
580 Kernel_EAX      resd 1
581 Kernel_SI       resw 1
582
583                 section .text16
584 kernel_good_saved:
585                 ; Alternate entry point for which the return from
586                 ; searchdir is stored in memory.  This is used for
587                 ; COMBOOT function INT 22h, AX=0016h.
588                 mov si,[Kernel_SI]
589                 mov eax,[Kernel_EAX]
590
591 kernel_good:
592                 pushad
593                 ;
594                 ; Common initialization for all kernel types
595                 ;
596                 xor ax,ax
597                 mov [InitRDPtr],ax
598                 mov [QuietBoot],al
599 %if IS_PXELINUX
600                 mov [KeepPXE],al
601 %endif
602
603                 mov si,KernelName
604                 mov di,KernelCName
605                 call unmangle_name
606                 sub di,KernelCName
607                 mov [KernelCNameLen],di
608
609                 ; Default memory limit, can be overridden by image loaders
610                 mov eax,[HighMemRsvd]
611                 mov [MyHighMemSize],eax
612
613                 popad
614
615                 push di
616                 push ax
617                 mov di,KernelName+4*IS_PXELINUX
618                 xor al,al
619                 mov cx,FILENAME_MAX
620                 repne scasb
621                 jne .one_step
622                 dec di
623 .one_step:      mov ecx,[di-4]                  ; 4 bytes before end
624                 pop ax
625                 pop di
626
627 ;
628 ; At this point, EAX contains the size of the kernel, SI contains
629 ; the file handle/cluster pointer, and ECX contains the extension (if any.)
630 ;
631                 movzx di,byte [KernelType]
632                 add di,di
633                 jmp [kerneltype_table+di]
634
635 is_unknown_filetype:
636                 or ecx,20202000h                ; Force lower case (except dot)
637
638                 cmp ecx,'.com'
639                 je is_comboot_image
640                 cmp ecx,'.cbt'
641                 je is_comboot_image
642                 cmp ecx,'.c32'
643                 je is_com32_image
644 %if IS_ISOLINUX
645                 cmp ecx,'.img'
646                 je is_disk_image
647 %endif
648                 cmp ecx,'.bss'
649                 je is_bss_sector
650                 cmp ecx,'.bin'
651                 je is_bootsector
652                 shr ecx,8
653                 cmp ecx,'.bs'
654                 je is_bootsector
655                 shr ecx,8
656                 cmp cx,'.0'
657                 je is_bootsector
658
659                 ; Otherwise Linux kernel
660                 jmp is_linux_kernel
661
662 is_config_file:
663                 pusha
664                 mov si,KernelCName              ; Save the config file name, for posterity
665                 mov di,ConfigName
666                 call strcpy
667                 popa
668                 call openfd
669                 call reset_config
670                 jmp load_config_file
671
672 ; This is an image type we can't deal with
673 is_bad_image:
674                 mov si,err_badimage
675                 call writestr
676                 jmp enter_command
677
678 %if IS_SYSLINUX
679                 ; ok
680 %else
681 is_bss_sector   equ is_bad_image
682 %endif
683 %if IS_ISOLINUX
684                 ; ok
685 %else
686 is_disk_image   equ is_bad_image
687 %endif
688
689                 section .data16
690 boot_prompt     db 'boot: ', 0
691 wipe_char       db BS, ' ', BS, 0
692 err_badimage    db 'Invalid image type for this media type!', CR, LF, 0
693 err_notfound    db 'Could not find kernel image: ',0
694 err_notkernel   db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
695
696
697                 alignz 2
698 kerneltype_table:
699                 dw is_unknown_filetype  ; VK_KERNEL
700                 dw is_linux_kernel      ; VK_LINUX
701                 dw is_bootsector        ; VK_BOOT
702                 dw is_bss_sector        ; VK_BSS
703                 dw is_bootsector        ; VK_PXE
704                 dw is_disk_image        ; VK_FDIMAGE
705                 dw is_comboot_image     ; VK_COMBOOT
706                 dw is_com32_image       ; VK_COM32
707                 dw is_config_file       ; VK_CONFIG
708
709                 section .bss16
710                 alignb 4
711 ThisKbdTo       resd 1                  ; Temporary holder for KbdTimeout
712 ThisTotalTo     resd 1                  ; Temporary holder for TotalTimeout
713 KernelExtPtr    resw 1                  ; During search, final null pointer
714 CmdOptPtr       resw 1                  ; Pointer to first option on cmd line
715 KbdFlags        resb 1                  ; Check for keyboard escapes
716 FuncFlag        resb 1                  ; Escape sequences received from keyboard
717 KernelType      resb 1                  ; Kernel type, from vkernel, if known
718
719                 section .text16
720 ;
721 ; Linux kernel loading code is common.
722 ;
723 %include "runkernel.inc"
724
725 ;
726 ; COMBOOT-loading code
727 ;
728 %include "comboot.inc"
729 %include "com32.inc"
730 %include "cmdline.inc"
731
732 ;
733 ; Boot sector loading code
734 ;
735 %include "bootsect.inc"
736
737 ;
738 ; Abort loading code
739 ;
740 %include "abort.inc"
741
742 ;
743 ; Hardware cleanup common code
744 ;
745 %include "cleanup.inc"