diff options
author | hpa <hpa> | 2002-10-24 00:59:08 +0000 |
---|---|---|
committer | hpa <hpa> | 2002-10-24 00:59:08 +0000 |
commit | ea2c13ab4e1760cc2e5b5737016eb6d308bfe29e (patch) | |
tree | 583238aba27b0fdcf10861c6127aeb45fdbb838e | |
parent | 6f5159e474dd731591e536f15776c94ce4754f73 (diff) | |
download | syslinux-ea2c13ab4e1760cc2e5b5737016eb6d308bfe29e.tar.gz |
* Unify the command-line handling and extension-scanning codesyslinux-2.00-pre10
* Fix bug relating to '/' characters in ISOLINUX
* Add <Ctrl-V> to display the version number
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | bootsect.inc | 2 | ||||
-rw-r--r-- | isolinux.asm | 361 | ||||
-rw-r--r-- | ldlinux.asm | 337 | ||||
-rw-r--r-- | pxelinux.asm | 355 | ||||
-rw-r--r-- | ui.inc | 414 |
6 files changed, 443 insertions, 1033 deletions
@@ -4,13 +4,18 @@ apply to that specific program only; other changes apply to both. Changes in 2.00: * ALL: Add support for "COM32" (32-bit COMBOOT) images. * ALL: Add an API for COMBOOT/COM32 images. See comboot.doc - for details. + for details. There is a C development environment for + COM32 being created; it should be ready at some point in + the future. * Fix mbr.asm so that it actually works. * SYSLINUX: The syslinux installer *SHOULD* now be safe to run setuid root. * PXELINUX: Fix bug where PXELINUX would override random chunks of the UNDI code segment! Thanks to Kevin Tran for finding this bug. + * ISOLINUX: Fix a bug related to slashes in pathnames. + * ALL: Make the <Ctrl-V> key print out the version; this is + to help debugging. Changes in 1.76: * ISOLINUX: Remove code no longer used which caused hangs on diff --git a/bootsect.inc b/bootsect.inc index d3e50fc9..b114c4eb 100644 --- a/bootsect.inc +++ b/bootsect.inc @@ -108,7 +108,7 @@ load_bootsec: jmp bcopy_over_self %if IS_SYSLINUX = 0 -is_bss_image: +is_bss_sector: mov si,err_bssimage call cwritestr jmp enter_command diff --git a/isolinux.asm b/isolinux.asm index ce2520c5..7966f9ea 100644 --- a/isolinux.asm +++ b/isolinux.asm @@ -838,359 +838,10 @@ load_config: %endif ; -; Now we have the config file open +; Now we have the config file open. Parse the config file and +; run the user interface. ; - 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],byte 0 ; Force prompt? - jnz enter_command - test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt - jz auto_boot ; If neither, default boot - -enter_command: - 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,1 ; Check for pending char - int 16h - jz get_char_time - xor ax,ax ; Get char - int 16h - jmp short clear_buffer -get_char_time: - call vgashowcursor - mov cx,[KbdTimeOut] - and cx,cx - jz get_char ; Timeout == 0 -> no timeout - inc cx ; The first loop will happen - ; immediately as we don't - ; know the appropriate DX value -time_loop: push cx -tick_loop: push dx - call pollchar - jnz get_char_pop - mov dx,[BIOS_timer] ; Get time "of day" - pop ax - cmp dx,ax ; Has the timer advanced? - je tick_loop - pop cx - loop time_loop ; If so, decrement counter - call vgahidecursor - jmp command_done ; Timeout! - -get_char_pop: pop eax ; Clear stack -get_char: - call vgashowcursor - call getchar - call vgahidecursor - 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 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 get_char - stosb ; Save it - call writechr ; Echo to screen -get_char_2: jmp short get_char -not_ascii: mov byte [FuncFlag],0 - cmp al,0Dh ; Enter - je command_done - cmp al,06h ; <Ctrl-F> - je set_func_flag - 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 - -set_func_flag: - mov byte [FuncFlag],1 - jmp short get_char_2 - -ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10 -ctrl_f: push di - sub al,'1' - xor ah,ah - jmp short show_help - -func_key: - ; AL = 0 if we get here - push di - cmp ah,68 ; F10 - ja get_char_2 - sub ah,59 ; F1 - jb get_char_2 - xchg al,ah -show_help: ; AX = func key # (0 = F1, 9 = F10) - shl ax,FILENAME_MAX_LG2 ; Convert to pointer - xchg di,ax - add di,FKeyName - cmp byte [di],NULLFILE - je get_char_2 ; Undefined F-key - call searchdir - jz fk_nofile - push si - call crlf - pop si - call get_msg_file - jmp short fk_wrcmd -fk_nofile: - call crlf -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 - pop di - jmp short get_char_2 -auto_boot: - mov si,default_cmd - mov di,command_line - mov cx,(max_cmd_len+4) >> 2 - rep movsd - jmp short load_kernel -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 -; -; Now check if it is a "virtual kernel" -; - mov cx,[VKernelCtr] - push ds - push word vk_seg - pop ds - cmp cx,byte 0 - je not_vk - xor si,si ; Point to first vkernel -vk_check: pusha - mov cx,FILENAME_MAX - repe cmpsb ; Is this it? - je vk_found - popa - add si,vk_size - loop vk_check -not_vk: pop ds -; -; 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 - mov di,KernelName - 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) -bad_kernel: - 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 -; -; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" -; -bad_implicit: mov si,KernelName ; For the error message - mov di,KernelCName - call unmangle_name - jmp short bad_kernel -; -; vk_found: We *are* using a "virtual kernel" -; -vk_found: popa - push di - mov di,VKernelBuf - mov cx,vk_size >> 2 - rep movsd - push es ; Restore old DS - pop ds - 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 - pop di ; DI -> KernelName - push di - mov si,VKernelBuf+vk_rname - mov cx,FILENAME_MAX ; We need ECX == CX later - rep movsb - pop di - xor bx,bx ; Try only one version - - ; Is this a "localboot" pseudo-kernel? - cmp byte [VKernelBuf+vk_rname], 0 - jne get_kernel ; No, it's real, go get it - - mov ax, [VKernelBuf+vk_rname+1] - jmp local_boot -; -; kernel_corrupt: Called if the kernel file does not seem healthy -; -kernel_corrupt: mov si,err_notkernel - jmp abort_load -; -; 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. -; -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 - 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 - - cmp ecx,'.com' - je is_comboot_image - cmp ecx,'.cbt' - je is_comboot_image - cmp ecx,'.c32' - je is_com32_image - cmp ecx,'.img' - je is_disk_image - cmp ecx,'.bss' - je is_bss_image - 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 +%include "ui.inc" ; ; Linux kernel loading code is common. @@ -1476,8 +1127,11 @@ searchdir_iso: mov [di-1],byte 0 ; Terminate at directory name mov cl,02h ; Search for directory xchg cl,[ISOFlags] - push di + + push di ; Save these... push cx + + ; Create recursion stack frame... push word .resume ; Where to "return" to push es .isfile: xchg ax,di @@ -1554,6 +1208,7 @@ searchdir_iso: xchg edx,eax ; Directory length in edx pop cx ; Old ISOFlags pop di ; Next filename pointer + mov byte [di-1], '/' ; Restore slash mov [ISOFlags],cl ; Restore the flags jz .failure ; Did we fail? If so fail for real! jmp .look_for_slash ; Otherwise, next level diff --git a/ldlinux.asm b/ldlinux.asm index d81353b5..73803308 100644 --- a/ldlinux.asm +++ b/ldlinux.asm @@ -144,6 +144,7 @@ ClustPerMoby resd 1 ; Clusters per 64K ClustSize resd 1 ; Bytes/cluster KernelName resb 12 ; Mangled name for kernel ; (note the spare byte after!) +OrigKernelExt resd 1 ; Original kernel extension FBytes equ $ ; Used by open/getc FBytes1 resw 1 FBytes2 resw 1 @@ -1028,325 +1029,12 @@ mkkeymap: stosb mov di,syslinux_cfg call open jz no_config_file -; -; Now we have the config file open -; - 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],byte 0 ; Force prompt? - jnz enter_command - test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt - jz auto_boot ; If neither, default boot - -enter_command: - 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,1 ; Check for pending char - int 16h - jz get_char_time - xor ax,ax ; Get char - int 16h - jmp short clear_buffer -get_char_time: - call vgashowcursor - mov cx,[KbdTimeOut] - and cx,cx - jz get_char ; Timeout == 0 -> no timeout - inc cx ; The first loop will happen - ; immediately as we don't - ; know the appropriate DX value -time_loop: push cx -tick_loop: push dx - call pollchar - jnz get_char_pop - xor ax,ax - int 1Ah ; Get time "of day" - pop ax - cmp dx,ax ; Has the timer advanced? - je tick_loop - pop cx - loop time_loop ; If so, decrement counter - call vgahidecursor - jmp command_done ; Timeout! - -get_char_pop: pop eax ; Clear stack -get_char: - call vgashowcursor - call getchar - call vgahidecursor - 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 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 get_char - stosb ; Save it - call writechr ; Echo to screen -get_char_2: jmp short get_char -not_ascii: mov byte [FuncFlag],0 - cmp al,0Dh ; Enter - je command_done - cmp al,06h ; <Ctrl-F> - je set_func_flag - 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 - -set_func_flag: - mov byte [FuncFlag],1 - jmp short get_char_2 -ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10 -ctrl_f: push di - sub al,'1' - xor ah,ah - jmp short show_help - -func_key: - ; AL = 0 if we get here - push di - cmp ah,68 ; F10 - ja get_char_2 - sub ah,59 ; F1 - jb get_char_2 - xchg al,ah -show_help: ; AX = func key # (0 = F1, 9 = F10) - shl ax,FILENAME_MAX_LG2 ; Convert to pointer - xchg di,ax - add di,FKeyName - cmp byte [di],NULLFILE - je get_char_2 ; Undefined F-key - call searchdir - jz fk_nofile - push si - call crlf - pop si - call get_msg_file - jmp short fk_wrcmd -fk_nofile: - call crlf -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 - pop di - jmp short get_char_2 -auto_boot: - mov si,default_cmd - mov di,command_line - mov cx,(max_cmd_len+4) >> 2 - rep movsd - jmp short load_kernel -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 -; -; Now check if it is a "virtual kernel" ; - mov cx,[VKernelCtr] - push ds - push word vk_seg - pop ds - cmp cx,byte 0 - je not_vk - xor si,si ; Point to first vkernel -vk_check: pusha - mov cx,11 - repe cmpsb ; Is this it? - je vk_found - popa - add si,vk_size - loop vk_check -not_vk: pop ds -; -; 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 bx,exten_count << 2 ; Alternates to try -; -; Find the kernel on disk -; -get_kernel: mov byte [KernelName+11],0 ; Zero-terminate filename/extension - mov eax,[KernelName+8] ; Save initial extension - mov [OrigKernelExt],eax -.search_loop: push bx - mov di,KernelName ; Search on disk - call searchdir - pop bx - jnz kernel_good - mov eax,[exten_table+bx] ; Try a different extension - mov [KernelName+8],eax - sub bx,byte 4 - jnb .search_loop -bad_kernel: - 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 +; Now we have the config file open. Parse the config file and +; run the user interface. ; -; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" -; -bad_implicit: mov si,KernelName ; For the error message - mov di,KernelCName - call unmangle_name - jmp short bad_kernel -; -; vk_found: We *are* using a "virtual kernel" -; -vk_found: popa - push di - mov di,VKernelBuf - mov cx,vk_size >> 2 - rep movsd - push es ; Restore old DS - pop ds - 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 - pop di ; DI -> KernelName - push di - mov si,VKernelBuf+vk_rname - mov cx,11 ; We need ECX == CX later - rep movsb - pop di - xor bx,bx ; Try only one version - jmp get_kernel -; -; kernel_corrupt: Called if the kernel file does not seem healthy -; -kernel_corrupt: mov si,err_notkernel - jmp abort_load -; -; 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: -; -; .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. -; -kernel_good: - pusha - mov si,KernelName - mov di,KernelCName - call unmangle_name ; Get human form - sub di,KernelCName - mov [KernelCNameLen],di - popa - - mov ecx,[KernelName+8] ; Get (mangled) extension - and ecx,00ffffffh ; 3 bytes only - cmp ecx,'COM' - je is_comboot_image - cmp ecx,'CBT' - je is_comboot_image - cmp ecx,'C32' - je is_com32_image - cmp ecx,'BS ' - je is_bootsector - cmp ecx,'BIN' - je is_bootsector - cmp ecx,'BSS' - je is_bss_sector - ; Otherwise Linux kernel +%include "ui.inc" ; ; Linux kernel loading code is common. @@ -1699,20 +1387,17 @@ initrd_cmd_len equ 7 ; Config file keyword table ; %include "keywords.inc" + ; -; Extensions to search for (in *reverse* order). Note that the last -; (lexically first) entry in the table is a placeholder for the original -; extension, needed for error messages. The exten_table is shifted so -; the table is 1-based; this is because a "loop" cx is used as index. +; Extensions to search for (in *forward* order). ; -exten_table: -OrigKernelExt: dd 0 ; Original extension - db 'COM',0 ; COMBOOT (same as DOS) - db 'BS ',0 ; Boot Sector +exten_table: db 'CBT',0 ; COMBOOT (specific) db 'BSS',0 ; Boot Sector (add superblock) - db 'CBT',0 ; COMBOOT (specific) + db 'BS ',0 ; Boot Sector + db 'COM',0 ; COMBOOT (same as DOS) +exten_table_end: + dd 0, 0 ; Need 8 null bytes here -exten_count equ (($-exten_table) >> 2) - 1 ; Number of alternates ; ; Misc initialized (data) variables ; diff --git a/pxelinux.asm b/pxelinux.asm index e4572b88..7df0bc7c 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -772,364 +772,15 @@ config_scan: jmp no_config_file -; -; Now we have the config file open -; .success: add sp,byte 16 ; Adjust stack - 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],byte 0 ; Force prompt? - jnz enter_command - test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt - jz auto_boot ; If neither, default boot - -enter_command: - 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,1 ; Check for pending char - int 16h - jz get_char_time - xor ax,ax ; Get char - int 16h - jmp short clear_buffer -get_char_time: - call vgashowcursor - mov cx,[KbdTimeOut] - and cx,cx - jz get_char ; Timeout == 0 -> no timeout - inc cx ; The first loop will happen - ; immediately as we don't - ; know the appropriate DX value -time_loop: push cx -tick_loop: push dx - call pollchar - jnz get_char_pop - mov dx,[BIOS_timer] ; Get time "of day" - pop ax - cmp dx,ax ; Has the timer advanced? - je tick_loop - pop cx - loop time_loop ; If so, decrement counter - call vgahidecursor - jmp command_done ; Timeout! - -get_char_pop: pop eax ; Clear stack -get_char: - call vgashowcursor - call getchar - call vgahidecursor - 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 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 get_char - stosb ; Save it - call writechr ; Echo to screen -get_char_2: jmp short get_char -not_ascii: mov byte [FuncFlag],0 - cmp al,0Dh ; Enter - je command_done - cmp al,06h ; <Ctrl-F> - je set_func_flag - 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 - -set_func_flag: - mov byte [FuncFlag],1 - jmp short get_char_2 - -ctrl_f_0: add al,10 ; <Ctrl-F>0 == F10 -ctrl_f: push di - sub al,'1' - xor ah,ah - jmp short show_help - -func_key: - ; AL = 0 if we get here - push di - cmp ah,68 ; F10 - ja get_char_2 - sub ah,59 ; F1 - jb get_char_2 - xchg al,ah -show_help: ; AX = func key # (0 = F1, 9 = F10) - shl ax,FILENAME_MAX_LG2 ; Convert to pointer - xchg di,ax - add di,FKeyName - cmp byte [di],NULLFILE - je get_char_2 ; Undefined F-key - call searchdir - jz fk_nofile - push si - call crlf - pop si - call get_msg_file - jmp short fk_wrcmd -fk_nofile: - call crlf -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 - pop di - jmp short get_char_2 -auto_boot: - mov si,default_cmd - mov di,command_line - mov cx,(max_cmd_len+4) >> 2 - rep movsd - jmp short load_kernel -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 -; -; Now check if it is a "virtual kernel" -; - mov cx,[VKernelCtr] - push ds - push word vk_seg - pop ds - cmp cx,byte 0 - je not_vk - xor si,si ; Point to first vkernel -vk_check: pusha - mov cx,FILENAME_MAX - repe cmpsb ; Is this it? - je vk_found - popa - add si,vk_size - loop vk_check -not_vk: pop ds -; -; 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 - mov di,KernelName - 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) -bad_kernel: - 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 -; -; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" -; -bad_implicit: mov si,KernelName ; For the error message - mov di,KernelCName - call unmangle_name - jmp short bad_kernel -; -; vk_found: We *are* using a "virtual kernel" -; -vk_found: popa - push di - mov di,VKernelBuf - mov cx,vk_size >> 2 - rep movsd - push es ; Restore old DS - pop ds - 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 - pop di ; DI -> KernelName - push di - mov si,VKernelBuf+vk_rname - mov cx,FILENAME_MAX ; We need ECX == CX later - rep movsb - pop di - mov al,[VKernelBuf+vk_ipappend] - mov [IPAppend],al - xor bx,bx ; Try only one version - ; Is this a "localboot" pseudo-kernel? - cmp byte [VKernelBuf+vk_rname], 0 - jne get_kernel ; No, it's real, go get it - - mov ax, [VKernelBuf+vk_rname+1] - jmp local_boot -; -; kernel_corrupt: Called if the kernel file does not seem healthy -; -kernel_corrupt: mov si,err_notkernel - jmp abort_load -; -; 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) +; Now we have the config file open. Parse the config file and +; run the user interface. ; -; Boot sectors are currently not supported by PXELINUX. -; -; Anything else is assumed to be a Linux kernel. -; -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 - 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 +%include "ui.inc" ; -; 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 - - cmp ecx,'.com' - je is_comboot_image - cmp ecx,'.cbt' - je is_comboot_image - cmp ecx,'.c32' - je is_com32_image - cmp ecx,'.bss' - je is_bss_image - 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 -; ; Linux kernel loading code is common. However, we need to define ; a couple of helper macros... ; @@ -0,0 +1,414 @@ +;; $Id$ +;; ----------------------------------------------------------------------- +;; +;; Copyright 1994-2002 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, +;; Bostom 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],byte 0 ; Force prompt? + jnz enter_command + test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt + jz auto_boot ; If neither, default boot + +enter_command: + 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,1 ; Check for pending char + int 16h + jz get_char_time + xor ax,ax ; Get char + int 16h + jmp short clear_buffer +get_char_time: + call vgashowcursor + mov cx,[KbdTimeOut] + and cx,cx + jz get_char ; Timeout == 0 -> no timeout + inc cx ; The first loop will happen + ; immediately as we don't + ; know the appropriate DX value +time_loop: push cx +tick_loop: push dx + call pollchar + jnz get_char_pop + mov dx,[BIOS_timer] ; Get time "of day" + pop ax + cmp dx,ax ; Has the timer advanced? + je tick_loop + pop cx + loop time_loop ; If so, decrement counter + call vgahidecursor + jmp command_done ; Timeout! + +get_char_pop: pop eax ; Clear stack +get_char: + call vgashowcursor + call getchar + call vgahidecursor + 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 + 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,06h ; <Ctrl-F> + je set_func_flag + cmp al,16h ; <Ctrl-V> + je print_version + 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 + +set_func_flag: + mov byte [FuncFlag],1 +get_char_2: + jmp short get_char + +ctrl_f_0: add al,10 ; <Ctrl-F>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],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 + 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 +auto_boot: + mov si,default_cmd + mov di,command_line + mov cx,(max_cmd_len+4) >> 2 + rep movsd + jmp short load_kernel +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 +; +; Now check if it is a "virtual kernel" +; + mov cx,[VKernelCtr] + push ds + push word vk_seg + pop ds + cmp cx,byte 0 + je not_vk + xor si,si ; Point to first vkernel +vk_check: pusha + mov cx,FILENAME_MAX + repe cmpsb ; Is this it? + je vk_found + popa + add si,vk_size + loop vk_check +not_vk: pop ds +; +; 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 ; 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 + 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 + 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) +bad_kernel: + 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 +; +; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" +; +bad_implicit: mov si,KernelName ; For the error message + mov di,KernelCName + call unmangle_name + jmp short bad_kernel +; +; vk_found: We *are* using a "virtual kernel" +; +vk_found: popa + push di + mov di,VKernelBuf + mov cx,vk_size >> 2 + rep movsd + push es ; Restore old DS + pop ds + 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 + pop di ; 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_SYSLINUX + jmp get_kernel +%else + ; Is this a "localboot" pseudo-kernel? + cmp byte [VKernelBuf+vk_rname], 0 + jne get_kernel ; No, it's real, go get it + + mov ax, [VKernelBuf+vk_rname+1] + jmp local_boot +%endif + +; +; kernel_corrupt: Called if the kernel file does not seem healthy +; +kernel_corrupt: mov si,err_notkernel + jmp abort_load +; +; 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. +; +kernel_good: + pusha + mov si,KernelName + mov di,KernelCName + call unmangle_name + sub di,KernelCName + mov [KernelCNameLen],di + popa + +%if IS_SYSLINUX + mov ecx,[KernelName+7] + mov cl,'.' +%else + 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 +%endif + +; +; 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 + + 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 +%if IS_SYSLINUX + cmp ecx,'.bs ' + je is_bootsector + cmp ecx,'.0 ' + je is_bootsector +%else + shr ecx,8 + cmp ecx,'.bs' + je is_bootsector + shr ecx,8 + cmp cx,'.0' + je is_bootsector +%endif + ; Otherwise Linux kernel + |