diff options
Diffstat (limited to 'contrib/syslinux-4.02/core/ui.inc')
-rw-r--r-- | contrib/syslinux-4.02/core/ui.inc | 748 |
1 files changed, 748 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/core/ui.inc b/contrib/syslinux-4.02/core/ui.inc new file mode 100644 index 0000000..2d44447 --- /dev/null +++ b/contrib/syslinux-4.02/core/ui.inc @@ -0,0 +1,748 @@ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved +;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +;; Boston MA 02111-1307, USA; either version 2 of the License, or +;; (at your option) any later version; incorporated herein by reference. +;; +;; ----------------------------------------------------------------------- + +; +; This file should be entered with the config file open (for getc) +; +load_config_file: + call parse_config ; Parse configuration file +no_config_file: + + call adv_init +; +; Check for an ADV boot-once entry +; + mov dl,ADV_BOOTONCE + call adv_get + jcxz .no_bootonce + +.have_bootone: + ; We apparently have a boot-once set; clear it and + ; then execute the boot-once... + + ; Save the boot-once data; SI = data, CX = length + mov di,command_line + rep movsb + xor ax,ax + stosb + + ; Clear the boot-once data from the ADV + xor cx,cx ; Set to zero = delete + call adv_set + jc .err + call adv_write +.err: jmp load_kernel + +.no_bootonce: + +; +; Check whether or not we are supposed to display the boot prompt. +; +check_for_key: + test byte [KbdFlags],5Bh ; Shift Alt Caps Scroll + jnz enter_command + cmp word [ForcePrompt],0 ; Force prompt? + jz auto_boot + cmp word [DefaultLevel],1 ; Active UI statement? + ja auto_boot + +enter_command: + cmp word [NoEscape],0 ; If NOESCAPE, no prompt, + jne auto_boot ; always run default cmd + + mov si,boot_prompt + call writestr + + mov byte [FuncFlag],0 ; <Ctrl-F> not pressed + mov di,command_line + +; +; get the very first character -- we can either time +; out, or receive a character press at this time. Some dorky BIOSes stuff +; a return in the buffer on bootup, so wipe the keyboard buffer first. +; +clear_buffer: mov ah,11h ; Check for pending char + int 16h + jz get_char_time + mov ah,10h ; Get char + int 16h + jmp short clear_buffer + + ; For the first character, both KbdTimeout and + ; TotalTimeout apply; after that, only TotalTimeout. + +get_char_time: + mov eax,[TotalTimeout] + mov [ThisTotalTo],eax + mov eax,[KbdTimeout] + mov [ThisKbdTo],eax + +get_char: + call getchar_timeout + and dword [ThisKbdTo],0 ; For the next time... + + and al,al + jz func_key + +got_ascii: cmp al,7Fh ; <DEL> == <BS> + je backspace + cmp al,' ' ; ASCII? + jb not_ascii + ja enter_char + cmp di,command_line ; Space must not be first + je short get_char +enter_char: test byte [FuncFlag],1 + jnz ctrl_f ; Keystroke after <Ctrl-F> + cmp di,max_cmd_len+command_line ; Check there's space + jnb short get_char + stosb ; Save it + call writechr ; Echo to screen + jmp short get_char +not_ascii: + cmp al,0Dh ; Enter + je command_done + cmp al,09h ; Tab + je display_labels + cmp al,'F' & 1Fh ; <Ctrl-F> + je set_func_flag +%if IS_PXELINUX + cmp al,'N' & 1Fh ; <Ctrl-N> + je show_network_info +%endif + cmp al,'U' & 1Fh ; <Ctrl-U> + je kill_command ; Kill input line + cmp al,'V' & 1Fh ; <Ctrl-V> + je print_version + cmp al,'X' & 1Fh ; <Ctrl-X> + je force_text_mode + cmp al,08h ; Backspace + jne get_char +backspace: cmp di,command_line ; Make sure there is anything + je get_char ; to erase + dec di ; Unstore one character + mov si,wipe_char ; and erase it from the screen + call writestr +get_char_2: + jmp short get_char + +kill_command: + call crlf + jmp enter_command + +force_text_mode: + call vgaclearmode + jmp enter_command + +set_func_flag: + mov byte [FuncFlag],1 + jmp short get_char_2 + +display_labels: + cmp word [NoComplete],0 ; Label completion enabled? + jne get_char_2 + push di ; Save pointer + mov cx,di + sub cx,command_line + call crlf + mov esi,[HighMemSize] ; Start from top of memory +.scan: + cmp esi,[VKernelEnd] + jbe .not_vk + + push cx ; save command line size + + mov edi,VKernelBuf + pm_call rllunpack + ; ESI updated on return + + sub di,cx ; Return to beginning of buf + pop cx ; restore command line size + push si ; save SI + cmp cx,0 + jz .print + push di + push cx + mov si,command_line + es repe cmpsb + pop cx + pop di + jne .next +.print: + mov al,' ' + call writechr + + mov si,di + call writestr +.next: + pop si ; restore SI + jmp .scan +.not_vk: + call crlf + jmp fk_wrcmd + +ctrl_f: + xor ah,ah + mov [FuncFlag],ah + cmp al,'0' + jb get_char_2 + je .zero ; <Ctrl-F>0 = F10 + or al,20h ; Lower case + cmp al,'9' + jna .digit + cmp al,'a' ; F10-F12 = <Ctrl-F>A, B, C + jb get_char_2 + cmp al,'c' + ja get_char_2 + sub al,'a'-10 + jmp show_help +.zero: + mov al,10 + jmp show_help +.digit: + sub al,'1' + jmp show_help + +func_key: + ; AL = 0 if we get here + xchg al,ah + cmp al,44h ; F10 + ja .f11_f12 + sub al,3Bh ; F1 + jb get_char_2 + jmp show_help +.f11_f12: + cmp al,85h ; F11 + jb get_char_2 + cmp al,86h ; F12 + ja get_char_2 + sub al,85h-10 + +show_help: ; AX = func key # (0 = F1, 9 = F10, 11 = F12) + push di ; Save end-of-cmdline pointer + shl ax,FILENAME_MAX_LG2 ; Convert to pointer + add ax,FKeyName + xchg di,ax + cmp byte [di+NULLOFFSET],NULLFILE + je short fk_nofile ; Undefined F-key + call core_open + jz short fk_nofile ; File not found + call crlf + call get_msg_file + jmp short fk_wrcmd + +print_version: + push di ; Command line write pointer + mov si,syslinux_banner + call writestr +%ifdef HAVE_BIOSNAME + mov si,[BIOSName] + call writestr +%endif + mov si,copyright_str + call writestr + + ; ... fall through ... + + ; Write the boot prompt and command line again and + ; wait for input. Note that this expects the cursor + ; to already have been CRLF'd, and that the old value + ; of DI (the command line write pointer) is on the stack. +fk_wrcmd: + mov si,boot_prompt + call writestr + pop di ; Command line write pointer + push di + mov byte [di],0 ; Null-terminate command line + mov si,command_line + call writestr ; Write command line so far +fk_nofile: pop di + jmp get_char + +; +; Show network info (in the form of the ipappend strings) +; +%if IS_PXELINUX +show_network_info: + push di ; Command line write pointer + call crlf + mov si,IPAppends ; See comboot.doc + mov cx,numIPAppends +.loop: + lodsw + push si + mov si,ax + call writestr + call crlf + pop si + loop .loop + jmp fk_wrcmd +%endif + +; +; Jump here to run the default command line +; +auto_boot: + cmp word [DefaultLevel],0 ; No UI or DEFAULT? + jne .have_default + mov si,no_default_msg + call writestr + cmp word [NoEscape],0 ; NOESCAPE but no DEFAULT? + jne kaboom ; If so, we're stuck! + jmp enter_command + +.have_default: + mov si,default_cmd + mov di,command_line + mov cx,(max_cmd_len+4) >> 2 + rep movsd + jmp short load_kernel + + section .data16 +no_default_msg db 'No DEFAULT or UI configuration directive found!' + db CR, LF, 0 + + section .text16 + +; +; Jump here when the command line is completed +; +command_done: + call crlf + cmp di,command_line ; Did we just hit return? + je auto_boot + xor al,al ; Store a final null + stosb + +load_kernel: ; Load the kernel now +; +; First we need to mangle the kernel name the way DOS would... +; + mov si,command_line + mov di,KernelName + push si + pm_call pm_mangle_name + pop si +; +; Fast-forward to first option (we start over from the beginning, since +; pm_mangle_name doesn't necessarily return a consistent ending state.) +; +clin_non_wsp: lodsb + cmp al,' ' + ja clin_non_wsp +clin_is_wsp: and al,al + jz clin_opt_ptr + lodsb + cmp al,' ' + jbe clin_is_wsp +clin_opt_ptr: dec si ; Point to first nonblank + mov [CmdOptPtr],si ; Save ptr to first option +; +; If "allowoptions 0", put a null character here in order to ignore any +; user-specified options. +; + mov ax,[AllowOptions] + and ax,ax + jnz clin_opt_ok + mov [si],al +clin_opt_ok: + +; +; Now check if it is a "virtual kernel" +; +vk_check: + mov esi,[HighMemSize] ; Start from top of memory +.scan: + cmp esi,[VKernelEnd] + jbe .not_vk + + mov edi,VKernelBuf + pm_call rllunpack + ; ESI updated on return + + sub di,cx ; Return to beginning of buf + push si + mov si,command_line +.loop: + lodsb + cmp al,' ' + jbe .done + scasb + je .loop +.nomatch: + pop si + jmp .scan +.done: + cmp byte [di],0 ; Must match end of string + jne .nomatch + pop si + +; +; We *are* using a "virtual kernel" +; +.found: + push es + push word real_mode_seg + pop es + mov di,cmd_line_here + mov si,VKernelBuf+vk_append + mov cx,[VKernelBuf+vk_appendlen] + rep movsb + mov byte [es:di],cl ; Null-terminate + mov [CmdLinePtr],di ; Where to add rest of cmd + pop es + mov di,KernelName + push di + mov si,VKernelBuf+vk_rname + mov cx,FILENAME_MAX ; We need ECX == CX later + rep movsb + pop di +%if IS_PXELINUX + mov al,[VKernelBuf+vk_ipappend] + mov [IPAppend],al +%endif + xor bx,bx ; Try only one version + + mov al,[VKernelBuf+vk_type] + mov [KernelType],al + +%if HAS_LOCALBOOT + ; Is this a "localboot" pseudo-kernel? + cmp al,VK_LOCALBOOT ; al == KernelType + mov ax,[VKernelBuf+vk_rname] ; Possible localboot type + je local_boot +%endif + jmp get_kernel + +.not_vk: +; +; Not a "virtual kernel" - check that's OK and construct the command line +; + cmp word [AllowImplicit],byte 0 + je bad_implicit + push es + push si + push di + mov di,real_mode_seg + mov es,di + mov si,AppendBuf + mov di,cmd_line_here + mov cx,[AppendLen] + rep movsb + mov byte [es:di],cl ; Null-terminate + mov [CmdLinePtr],di + pop di + pop si + pop es + + mov [KernelType], cl ; CL == 0 here + +; +; Find the kernel on disk +; +get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension + mov di,KernelName + cmp byte [di],' ' + jbe bad_kernel ; Missing kernel name + xor al,al + mov cx,FILENAME_MAX-5 ; Need 4 chars + null + repne scasb ; Scan for final null + jne .no_skip + dec di ; Point to final null +.no_skip: mov [KernelExtPtr],di + mov bx,exten_table +.search_loop: push bx + mov di,KernelName ; Search on disk + pm_call pm_searchdir + pop bx + jnz kernel_good + mov eax,[bx] ; Try a different extension + mov si,[KernelExtPtr] + mov [si],eax + mov byte [si+4],0 + add bx,byte 4 + cmp bx,exten_table_end + jna .search_loop ; allow == case (final case) + ; Fall into bad_kernel +; +; bad_kernel: Kernel image not found +; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" +; +bad_implicit: +bad_kernel: + mov cx,[OnerrorLen] + and cx,cx + jnz on_error +.really: + mov si,err_notfound ; Complain about missing kernel + call writestr + mov si,KernelName + call writestr + mov si,crlf_msg + jmp abort_load ; Ask user for clue + +; +; on_error: bad kernel, but we have onerror set; CX = OnerrorLen +; +on_error: + mov si,Onerror + mov di,command_line + push si ; <A> + push di ; <B> + push cx ; <C> + push cx ; <D> + push di ; <E> + repe cmpsb + pop di ; <E> di == command_line + pop bx ; <D> bx == [OnerrorLen] + je bad_kernel.really ; Onerror matches command_line already + neg bx ; bx == -[OnerrorLen] + lea cx,[max_cmd_len+bx] + ; CX == max_cmd_len-[OnerrorLen] + mov di,command_line+max_cmd_len-1 + mov byte [di+1],0 ; Enforce null-termination + lea si,[di+bx] + std + rep movsb ; Make space in command_line + cld + pop cx ; <C> cx == [OnerrorLen] + pop di ; <B> di == command_line + pop si ; <A> si == Onerror + rep movsb + jmp load_kernel + +; +; kernel_corrupt: Called if the kernel file does not seem healthy +; +kernel_corrupt: mov si,err_notkernel + jmp abort_load + +; +; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts +; which can be adjusted by the caller based on the corresponding +; master variables; on return they're updated. +; +; This cheats. If we say "no timeout" we actually get a timeout of +; 7.5 years. +; +getchar_timeout: + call vgashowcursor + call reset_idle + +.loop: + push word [__jiffies] + call pollchar + jnz .got_char + call do_idle + pop ax + cmp ax,[__jiffies] ; Has the timer advanced? + je .loop + + dec dword [ThisKbdTo] + jz .timeout + dec dword [ThisTotalTo] + jnz .loop + +.timeout: + ; Timeout!!!! + pop cx ; Discard return address + call vgahidecursor + mov si,Ontimeout ; Copy ontimeout command + mov di,command_line + mov cx,[OntimeoutLen] ; if we have one... + rep movsb + jmp command_done + +.got_char: + pop cx ; Discard + call getchar + call vgahidecursor + ret + +; +; This is it! We have a name (and location on the disk)... let's load +; that sucker!! First we have to decide what kind of file this is; base +; that decision on the file extension. The following extensions are +; recognized; case insensitive: +; +; .com - COMBOOT image +; .cbt - COMBOOT image +; .c32 - COM32 image +; .bs - Boot sector +; .0 - PXE bootstrap program (PXELINUX only) +; .bin - Boot sector +; .bss - Boot sector, but transfer over DOS superblock (SYSLINUX only) +; .img - Floppy image (ISOLINUX only) +; +; Anything else is assumed to be a Linux kernel. +; + section .bss16 + alignb 4 +Kernel_EAX resd 1 +Kernel_SI resw 1 + + section .text16 +kernel_good_saved: + ; Alternate entry point for which the return from + ; searchdir is stored in memory. This is used for + ; COMBOOT function INT 22h, AX=0016h. + mov si,[Kernel_SI] + mov eax,[Kernel_EAX] + +kernel_good: + pushad + ; + ; Common initialization for all kernel types + ; + xor ax,ax + mov [InitRDPtr],ax + mov [QuietBoot],al +%if IS_PXELINUX + mov [KeepPXE],al +%endif + + ; Default memory limit, can be overridden by image loaders + mov eax,[HighMemRsvd] + mov [MyHighMemSize],eax + + popad + + push di + push ax + mov di,KernelName + xor al,al + mov cx,FILENAME_MAX + repne scasb + jne .one_step + dec di +.one_step: mov ecx,[di-4] ; 4 bytes before end + pop ax + pop di + +; +; At this point, EAX contains the size of the kernel, SI contains +; the file handle/cluster pointer, and ECX contains the extension (if any.) +; + movzx di,byte [KernelType] + add di,di + jmp [kerneltype_table+di] + +is_unknown_filetype: + or ecx,20202000h ; Force lower case (except dot) + + cmp ecx,'.com' + je is_comboot_image + cmp ecx,'.cbt' + je is_comboot_image + cmp ecx,'.c32' + je is_com32_image +%if IS_ISOLINUX + cmp ecx,'.img' + je is_disk_image +%endif + cmp ecx,'.bss' + je is_bss_sector + cmp ecx,'.bin' + je is_bootsector + shr ecx,8 + cmp ecx,'.bs' + je is_bootsector + shr ecx,8 + cmp cx,'.0' + je is_bootsector + + ; Otherwise Linux kernel + jmp is_linux_kernel + +is_config_file: + push si + call make_plain_cmdline + pm_call pm_is_config_file + pop si + call openfd + call reset_config + jmp load_config_file + +; This is an image type we can't deal with +is_bad_image: + mov si,err_badimage + call writestr + jmp enter_command + +%if IS_SYSLINUX + ; ok +%else +is_bss_sector equ is_bad_image +%endif +%if IS_ISOLINUX + ; ok +%else +is_disk_image equ is_bad_image +%endif + + section .data16 +boot_prompt db 'boot: ', 0 +wipe_char db BS, ' ', BS, 0 +err_badimage db 'Invalid image type for this media type!', CR, LF, 0 +err_notfound db 'Could not find kernel image: ',0 +err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 + + + alignz 2 +kerneltype_table: + dw is_unknown_filetype ; VK_KERNEL + dw is_linux_kernel ; VK_LINUX + dw is_bootsector ; VK_BOOT + dw is_bss_sector ; VK_BSS + dw is_bootsector ; VK_PXE + dw is_disk_image ; VK_FDIMAGE + dw is_comboot_image ; VK_COMBOOT + dw is_com32_image ; VK_COM32 + dw is_config_file ; VK_CONFIG + + section .bss16 + alignb 4 +ThisKbdTo resd 1 ; Temporary holder for KbdTimeout +ThisTotalTo resd 1 ; Temporary holder for TotalTimeout +KernelExtPtr resw 1 ; During search, final null pointer +CmdOptPtr resw 1 ; Pointer to first option on cmd line +KbdFlags resb 1 ; Check for keyboard escapes +FuncFlag resb 1 ; Escape sequences received from keyboard +KernelType resb 1 ; Kernel type, from vkernel, if known + + section .text16 +; +; Linux kernel loading code is common. +; +%include "runkernel.inc" + +; +; COMBOOT-loading code +; +%include "comboot.inc" +%include "com32.inc" +%include "cmdline.inc" + +; +; Boot sector loading code +; +%include "bootsect.inc" + +; +; Abort loading code +; +%include "abort.inc" + +; +; Hardware cleanup common code +; +%include "cleanup.inc" |