;; ----------------------------------------------------------------------- ;; ;; Copyright 1994-2007 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) ; call parse_config ; Parse configuration file no_config_file: ; ; 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 ; 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 ; == 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 jz .not_ctrl_f mov byte [FuncFlag],0 cmp al,'0' jb .not_ctrl_f je ctrl_f_0 cmp al,'9' jbe ctrl_f .not_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: mov byte [FuncFlag],0 cmp al,0Dh ; Enter je command_done cmp al,'F' & 1Fh ; je set_func_flag cmp al,'U' & 1Fh ; je kill_command ; Kill input line cmp al,'V' & 1Fh ; je print_version cmp al,'X' & 1Fh ; 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 jmp short get_char_2 kill_command: call crlf jmp enter_command force_text_mode: call vgaclearmode jmp enter_command set_func_flag: mov byte [FuncFlag],1 get_char_2: jmp short get_char ctrl_f_0: add al,10 ; 0 == F10 ctrl_f: sub al,'1' xor ah,ah jmp short show_help func_key: ; AL = 0 if we get here xchg al,ah cmp al,68 ; F10 ja short get_char_2 sub al,59 ; F1 jb short get_char_2 show_help: ; AX = func key # (0 = F1, 9 = F10) 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 searchdir jz short fk_nofile ; File not found push si call crlf pop si 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 short get_char_2 ; ; 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 push di call mangle_name pop di 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: xor si,si ; Beginning of vk_seg .scan: cmp si,[VKernelBytes] jae .not_vk push ds push word vk_seg pop ds mov di,VKernelBuf call rllunpack pop ds ; SI 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 %if IS_PXELINUX || IS_ISOLINUX ; 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 ; ; Find the kernel on disk ; get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension %if IS_SYSLINUX || IS_MDSLINUX ; SYSLINUX has to deal with DOS mangled names... mov eax,[KernelName+8] ; Save initial extension mov [exten_table_end],eax ; Last case == initial ext. %else 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 %endif 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 %if IS_SYSLINUX || IS_MDSLINUX mov [KernelName+8],eax %else mov si,[KernelExtPtr] mov [si],eax mov byte [si+4],0 %endif 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 ; push di ; push cx ; push cx ; push di ; repe cmpsb pop di ; di == command_line pop bx ; 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 ; cx == [OnerrorLen] pop di ; di == command_line pop si ; 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] mov dx,[Kernel_EAX+2] kernel_good: pusha mov si,KernelName mov di,KernelCName call unmangle_name sub di,KernelCName mov [KernelCNameLen],di popa 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, DX:AX contains the size of the kernel, and SI contains ; the file handle/cluster pointer. ; 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 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 section .text