aboutsummaryrefslogtreecommitdiffstats
path: root/core/ui.inc
diff options
context:
space:
mode:
Diffstat (limited to 'core/ui.inc')
-rw-r--r--core/ui.inc683
1 files changed, 683 insertions, 0 deletions
diff --git a/core/ui.inc b/core/ui.inc
new file mode 100644
index 00000000..3fc3e639
--- /dev/null
+++ b/core/ui.inc
@@ -0,0 +1,683 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;;
+;; 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:
+ cmp word [ForcePrompt],0 ; Force prompt?
+ jnz enter_command
+ test byte [KbdFlags],5Bh ; Shift Alt Caps Scroll
+ jz auto_boot ; If neither, default boot
+
+enter_command:
+ cmp word [NoEscape],0 ; If NOESCAPE, no prompt,
+ jne auto_boot ; always run default cmd
+
+ mov si,boot_prompt
+ call cwritestr
+
+ 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,'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 cwritestr
+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
+
+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 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 cwritestr
+%ifdef HAVE_BIOSNAME
+ mov si,[BIOSName]
+ call cwritestr
+%endif
+ mov si,copyright_str
+ call cwritestr
+
+ ; ... 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 cwritestr
+ pop di ; Command line write pointer
+ push di
+ mov byte [di],0 ; Null-terminate command line
+ mov si,command_line
+ call cwritestr ; 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 cwritestr
+ call crlf
+ pop si
+ loop .loop
+ jmp fk_wrcmd
+%endif
+
+;
+; Jump here to run the default command line
+;
+auto_boot:
+ mov si,default_cmd
+ mov di,command_line
+ mov cx,(max_cmd_len+4) >> 2
+ rep movsd
+ jmp short load_kernel
+
+;
+; 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
+ call mangle_name
+ pop si
+;
+; Fast-forward to first option (we start over from the beginning, since
+; 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 di,VKernelBuf
+ call rllunpack
+ ; ESI updated on return
+
+ sub di,cx ; Return to beginning of buf
+ push si
+ mov si,KernelName
+ mov cx,FILENAME_MAX
+ es repe cmpsb
+ pop si
+ je .found
+ jmp .scan
+
+;
+; 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 [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?
+%if IS_PXELINUX
+ cmp byte [VKernelBuf+vk_rname+4], 0
+%else
+ cmp byte [VKernelBuf+vk_rname], 0
+%endif
+ jne get_kernel ; No, it's real, go get it
+
+ mov ax, [VKernelBuf+vk_rname+1]
+ jmp local_boot
+%else
+ jmp get_kernel
+%endif
+
+.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 [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+4*IS_PXELINUX
+ 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
+ call 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,KernelName
+ mov di,KernelCName
+ push di
+ call unmangle_name ; Get human form
+ mov si,err_notfound ; Complain about missing kernel
+ call cwritestr
+ pop si ; KernelCName
+ call cwritestr
+ 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
+ RESET_IDLE
+
+.loop:
+ push word [BIOS_timer]
+ call pollchar
+ jnz .got_char
+ pop ax
+ cmp ax,[BIOS_timer] ; Has the timer advanced?
+ je .loop
+ DO_IDLE
+
+ 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 .bss
+ alignb 4
+Kernel_EAX resd 1
+Kernel_SI resw 1
+
+ section .text
+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
+
+ mov si,KernelName
+ mov di,KernelCName
+ call unmangle_name
+ sub di,KernelCName
+ mov [KernelCNameLen],di
+
+ ; Default memory limit, can be overridden by image loaders
+ mov eax,[HighMemRsvd]
+ mov [MyHighMemSize],eax
+
+ popad
+
+ push di
+ push ax
+ mov di,KernelName+4*IS_PXELINUX
+ 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:
+ pusha
+ mov si,KernelCName ; Save the config file name, for posterity
+ mov di,ConfigName
+ call strcpy
+ popa
+ 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 cwritestr
+ jmp enter_command
+
+%if IS_SYSLINUX || IS_MDSLINUX
+ ; ok
+%else
+is_bss_sector equ is_bad_image
+%endif
+%if IS_ISOLINUX
+ ; ok
+%else
+is_disk_image equ is_bad_image
+%endif
+
+ section .data
+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
+
+
+ align 2, db 0
+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 .bss
+ 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 .text
+;
+; 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"