--- add_crc +++ add_crc @@ -0,0 +1,49 @@ +#! /usr/bin/perl + +use integer; + +# patch crc over first sector - 64 bytes into isolinux + +$file = shift; +$list = "$file"; +$list =~ s/\.bin$/.lst/; + +open F, $list; + +while() { + if(/^\s*\d+\s*(\S+)\s*0+\s*(\<\d+\>\s*)?csum_value\s*dd\s*0/) { + $ofs = hex $1; + } +} +close F; + +die "oops 1\n" unless $ofs && !($ofs & 3); + +# print "$ofs\n"; + +open F, $file or die "$file: $!\n"; + +$file_size = -s $file; + +sysread F, $buf, $file_size; + +close F; + +die "oops 1\n" if $file_size != length($buf); + +@x = unpack "V512", $buf; + +for ($sum = 0, $i = 16; $i < 512; $i++) { + $sum += $x[$i]; +} + +# printf "0x%08x\n", $sum; + +$ns = pack "V", -$sum; + +substr($buf, $ofs, 4) = $ns; + +open F, ">$file" or die "$file: $!\n"; + +syswrite F, $buf; + --- bcopy32.inc +++ bcopy32.inc @@ -65,7 +65,17 @@ ; EDI - first byte after target ; ECX - zero ; -bcopy: push eax +bcopy: +%if do_test + add esi,ecx + add edi,ecx + mov ecx,1000000*100 +.delay: + a32 ; NOT at the same line as the loop! + loop .delay + ret +%endif + push eax pushf ; Saves, among others, the IF flag push gs push fs --- config.inc +++ config.inc @@ -20,6 +20,8 @@ %ifndef _CONFIG_INC %define _CONFIG_INC +%define do_test 0 + max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit HIGHMEM_MAX equ 037FFFFFFh ; DEFAULT highest address for an initrd DEFAULT_BAUD equ 9600 ; Default baud rate for serial port --- conio.inc +++ conio.inc @@ -46,6 +46,13 @@ ; set by routine searchdir ; get_msg_file: +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + ; don't load if we have a graphics image + ret +.nogfx: +%endif push es shl edx,16 ; EDX <- DX:AX (length of file) mov dx,ax @@ -323,6 +330,9 @@ RESET_IDLE .again: DO_IDLE +%ifdef WITH_GFX + call chk_update +%endif mov ah,1 ; Poll keyboard int 16h jnz .kbd ; Keyboard input? --- fixofs +++ fixofs @@ -0,0 +1,4 @@ +#! /usr/bin/perl -p + +$ok = 1 if /org\s+7c00h/i; +s/^(\s*(\d+)\s+)([0-9A-Fa-f]{8})/$1 . sprintf("%08X", hex($3)+0x7c00)/e if $ok; --- gethostip.c +++ gethostip.c @@ -120,7 +120,7 @@ if ( output & 4 ) { unsigned long addr = - (((unsigned char *)host->h_addr)[0] << 24UL) + + ((unsigned long) ((unsigned char *)host->h_addr)[0] << 24UL) + (((unsigned char *)host->h_addr)[1] << 16UL) + (((unsigned char *)host->h_addr)[2] << 8UL) + (((unsigned char *)host->h_addr)[3]); --- gfxlogo.inc +++ gfxlogo.inc @@ -0,0 +1,637 @@ +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; gfx stuff +; +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +; != 0 -> everything's fine +; note: moved to ldlinux.asm/isolinux.asm +; gfx_ok db 0 + +gfx_mem_end_seg dw 0 + + align 4, db 0 +; the memory area we are working with +gfx_mem dd 0 ; linear address +gfx_mem_align dd 0 ; aligned data start +gfx_mem_file dd 0 ; aligned gfx data start +gfx_mem_max dd 0 ; end address +gfx_mem_free dd 0 ; start of free area for malloc (after pcx image) + +; interface to loadable gfx extension (seg:ofs values) +gfx_bc_jt dd 0 + +gfx_bc_init dd 0 +gfx_bc_done dd 0 +gfx_bc_input dd 0 +gfx_bc_menu_init dd 0 +gfx_bc_infobox_init dd 0 +gfx_bc_infobox_done dd 0 +gfx_bc_progress_init dd 0 +gfx_bc_progress_done dd 0 +gfx_bc_progress_update dd 0 +gfx_bc_progress_limit dd 0 +gfx_bc_password_init dd 0 +gfx_bc_password_done dd 0 + +gfx_menu_max_entries equ 16 +gfx_menu_tmp equ mi_buf ; a reasonably sized buffer +gfx_menu_def zb 13 +gfx_menu_entry zb 13 * gfx_menu_max_entries + +%if 0 +gfx_password_buf zb 32 +gfx_msg_wrong_image db 'Could not find kernel image: ', 0 +gfx_msg_wrong_password db 'Sorry, incorrect password.', 0 +%endif + +; menu entry descriptor +menu_entries equ 0 +menu_default equ 2 ; seg:ofs +menu_ent_list equ 6 ; seg:ofs +menu_ent_size equ 10 +menu_arg_list equ 12 ; seg:ofs +menu_arg_size equ 16 +sizeof_menu_desc equ 18 + +menu_desc zb sizeof_menu_desc + +; system config data +gfx_sysconfig equ $ +gfx_bootloader db 1 +gfx_update db 0 +gfx_video_mode_list dw fb_mode_list +gfx_video_modes db fb_mode_entries +gfx_boot_drive db 0 +gfx_reload_fs db 0 +gfx_user_note dw 0 +gfx_reserved zb 3 +gfx_user_info_0 dd 0 +gfx_user_info_1 dd 0 +gfx_mem_size dd 0 + +%macro lin2segofs 3 + push %1 + call gfx_l2so + pop %3 + pop %2 +%endmacro + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; must not change registers! +; +gfx_get_sysconfig: + push ax + mov al,[wants_update] + mov [gfx_update],al +%if IS_ISOLINUX + mov al,[DriveNo] +%else + mov al,[bsDriveNumber] +%endif + mov [gfx_boot_drive],al + push dword [HighMemSize] + pop dword [gfx_mem_size] + pop ax + ret + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_set_sysconfig: + push ax + mov al,[gfx_update] + mov [wants_update],al + pop ax + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Initialize graphics code. Load and display graphics data. +; +; dx:ax file length +; si start cluster +; +; return: [gfx_ok] = 0/1 +; +gfx_init: + push es + + cld + + movzx ecx,word [gfx_mem_end_seg] + shl ecx,4 + jz near gfx_init_80 + + ; define our memory area + ; gfx_mem _must_ be 16-byte aligned + mov dword [gfx_mem],10000h + mov dword [gfx_mem_free],10000h + mov dword [gfx_mem_max],ecx + + call gfx_read_file + cmp byte [gfx_ok],0 + jz near gfx_init_90 + + ; align 4 + mov eax,[gfx_mem_free] + add eax,3 + and eax,~3 + mov [gfx_mem_free],eax + + ; setup jump table + les bx,[gfx_bc_jt] + + mov ax,[es:bx] + mov [gfx_bc_init],ax + mov [gfx_bc_init+2],es + + mov ax,[es:bx+2] + mov [gfx_bc_done],ax + mov [gfx_bc_done+2],es + + mov ax,[es:bx+4] + mov [gfx_bc_input],ax + mov [gfx_bc_input+2],es + + mov ax,[es:bx+6] + mov [gfx_bc_menu_init],ax + mov [gfx_bc_menu_init+2],es + + mov ax,[es:bx+8] + mov [gfx_bc_infobox_init],ax + mov [gfx_bc_infobox_init+2],es + + mov ax,[es:bx+10] + mov [gfx_bc_infobox_done],ax + mov [gfx_bc_infobox_done+2],es + + mov ax,[es:bx+12] + mov [gfx_bc_progress_init],ax + mov [gfx_bc_progress_init+2],es + + mov ax,[es:bx+14] + mov [gfx_bc_progress_done],ax + mov [gfx_bc_progress_done+2],es + + mov ax,[es:bx+16] + mov [gfx_bc_progress_update],ax + mov [gfx_bc_progress_update+2],es + + mov ax,[es:bx+18] + mov [gfx_bc_progress_limit],ax + mov [gfx_bc_progress_limit+2],es + + mov ax,[es:bx+20] + mov [gfx_bc_password_init],ax + mov [gfx_bc_password_init+2],es + + mov ax,[es:bx+22] + mov [gfx_bc_password_done],ax + mov [gfx_bc_password_done+2],es + + mov eax,[gfx_mem_file] + mov ebx,[gfx_mem_free] + mov ecx,[gfx_mem_max] + mov edi,[gfx_mem_align] + mov dx,cs + + mov si,gfx_sysconfig + call far [gfx_bc_init] + jc gfx_init_80 + + call highmemsize + + mov byte [gfx_ok],1 + + jmp gfx_init_90 + +gfx_init_80: + mov byte [gfx_ok],0 +gfx_init_90: + pop es + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Back to text mode. +; +; return: [gfx_ok] = 0 +; +gfx_done: + cmp byte [gfx_ok],0 + jz gfx_done_90 + call far [gfx_bc_done] + mov byte [gfx_ok],0 + call gfx_set_sysconfig +gfx_done_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_input: + cmp byte [gfx_ok],0 + jz gfx_input_90 + call gfx_get_sysconfig + call far [gfx_bc_input] + pushf + call gfx_set_sysconfig + popf + jnc gfx_input_50 + mov ax,1 +gfx_input_50: + cmp ax,1 + jnz gfx_input_90 + push ax + call gfx_done + pop ax +gfx_input_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_setup_menu: + cmp byte [gfx_ok],0 + jz gfx_setup_menu_90 + + push ds + pop es + mov si,default_cmd + mov di,gfx_menu_tmp + call mangle_name + mov si,gfx_menu_tmp + mov di,gfx_menu_def + call unmangle_name + mov ax,[VKernelCtr] + cmp ax,gfx_menu_max_entries + jb gfx_setup_menu_10 + mov ax,gfx_menu_max_entries +gfx_setup_menu_10: + mov [menu_desc+menu_entries],ax + or ax,ax + jz gfx_setup_menu_90 + xor si,si + mov di,gfx_menu_entry +gfx_setup_menu_20: + push di + push si + shl si,vk_shift + push ds + push word vk_seg + pop ds + mov bx,[si+vk_appendlen] + mov byte [bx+si+vk_append],0 ; make it zero terminated + call unmangle_name + pop ds + pop si + pop di + add di,13 + inc si + cmp si,[menu_desc+menu_entries] + jb gfx_setup_menu_20 + + mov si,menu_desc + + mov word [si+menu_default],gfx_menu_def + mov [si+menu_default+2],ds + + mov word [si+menu_ent_list],gfx_menu_entry + mov [si+menu_ent_list+2],ds + mov word [si+menu_ent_size],13 + + mov word [si+menu_arg_list],vk_append + mov word [si+menu_arg_list+2],vk_seg + mov word [si+menu_arg_size],vk_size + + push ds + pop es + + call gfx_get_sysconfig + call far [gfx_bc_menu_init] + +gfx_setup_menu_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_infobox: + pushad + cmp byte [gfx_ok],0 + jz gfx_infobox_90 + call far [gfx_bc_infobox_init] + xor di,di + xor ax,ax + call far [gfx_bc_input] + call far [gfx_bc_infobox_done] +gfx_infobox_90: + popad + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_progress_init: + pushad + cmp byte [gfx_ok],0 + jz gfx_progress_init_90 + movzx eax,ax + call far [gfx_bc_progress_init] +gfx_progress_init_90: + popad + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_progress_done: + pushad + cmp byte [gfx_ok],0 + jz gfx_progress_done_90 + call far [gfx_bc_progress_done] +gfx_progress_done_90: + popad + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_progress_update: + pushad + cmp byte [gfx_ok],0 + jz gfx_progress_update_90 + movzx eax,cx + call far [gfx_bc_progress_update] +gfx_progress_update_90: + popad + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_progress_limit: + pushad + cmp byte [gfx_ok],0 + jz gfx_progress_limit_90 + movzx eax,ax + movzx edx,dx + call far [gfx_bc_progress_limit] +gfx_progress_limit_90: + popad + ret + + +%if 0 +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +gfx_password: + pushad + cmp byte [gfx_ok],0 + stc + jz gfx_password_90 + call far [gfx_bc_password_init] + mov di,gfx_password_buf + mov cx,32 + xor ax,ax + call far [gfx_bc_input] + mov si,gfx_password_buf + call far [gfx_bc_password_done] + jnc gfx_password_90 + mov si,gfx_msg_wrong_password + xor di,di + mov al,0 + call far [gfx_bc_infobox_init] + xor di,di + xor ax,ax + call far [gfx_bc_input] + call far [gfx_bc_infobox_done] + stc +gfx_password_90: + popad + ret +%endif + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Read graphics data and store them at [gfx_mem]. +; +; dx:ax file length +; si start cluster +; +; return: [gfx_ok] = 0/1 +; +gfx_read_file: + push es + mov byte [gfx_ok],0 + mov edi,[gfx_mem] + push dx ; DX:AX = length of file + push ax + pop edx + mov eax,[gfx_mem_free] + lea eax,[eax+edx+0fh] ; add space for alignment + cmp eax,[gfx_mem_max] ; max. length + ja near gfx_read_file_90 + mov [gfx_mem_free],eax + +gfx_read_file_10: + mov bx,trackbuf + mov cx,[BufSafe] + push edi + push edx + call getfssec + pop edx + pop edi + movzx ecx,word [BufSafeBytes] + cmp edx,ecx + jae gfx_read_file_20 + mov ecx,edx +gfx_read_file_20: + push ecx + push edi + push si ; Save current cluster + push es + mov si,trackbuf + push edi + call gfx_l2so + pop di + pop es + rep movsb + pop es + pop si + pop edi + pop ecx + add edi,ecx + sub edx,ecx + ja gfx_read_file_10 + + call find_file + or eax,eax + jz gfx_read_file_90 + push edi + push eax + add eax,edi + call align_it + pop eax + pop edi + sub edi,[gfx_mem] + add edi,[gfx_mem_align] + mov [gfx_mem_file],edi + add eax,edi + shr eax,4 + mov [gfx_bc_jt+2],ax + + mov byte [gfx_ok],1 + +gfx_read_file_90: + pop es + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; locate graphics file +; +; return: eax: code offset (0 -> no file found) +; edi: gfx file start +; +find_file: + mov edi,[gfx_mem] + lin2segofs edi,es,bx + call magic_ok + or eax,eax + jnz find_file_90 + + ; ok, maybe it's a cpio archive + + ; note: edi must be properly aligned (2)! + +find_file_20: + mov ecx,[gfx_mem_free] + sub ecx,26 + 12 ; min cpio header + gfx header + cmp edi,ecx + jae find_file_90 + + lin2segofs edi,es,bx + cmp word [es:bx],71c7h + jnz find_file_90 ; no cpio record + + movzx esi,word [es:bx+20] ; file name size + + inc si + and si,~1 ; align + + mov ecx,[es:bx+22] ; data size + rol ecx,16 ; get word order right + + inc ecx + and ecx,byte ~1 ; align + + add si,26 ; skip header + + add edi,esi + add bx,si + call magic_ok + or eax,eax + jnz find_file_90 + + add edi,ecx + jmp find_file_20 + +find_file_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; es:bx file start +; +; return: eax: offset to code entry +; +; Notes: +; - changes no regs except eax +; +magic_ok: + xor eax,eax + cmp dword [es:bx],0b2d97f00h ; header.magic_id + jnz magic_ok_90 + cmp byte [es:bx+4],5 ; header.version + jnz magic_ok_90 + mov eax,[es:bx+8] +magic_ok_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; eax address to be aligned +; +align_it: + push dword [gfx_mem] + pop dword [gfx_mem_align] + neg al + and eax,byte 0fh + jz align_it_90 + add [gfx_mem_align],eax + mov esi,[gfx_mem] + mov ebx,[gfx_mem_free] + sub ebx,esi + sub ebx,byte 0fh + add esi,ebx + dec esi + + std + +align_it_30: + or ebx,ebx + jz align_it_60 + mov ecx,ebx + cmp ebx,8000h + jb align_it_40 + mov ecx,8000h +align_it_40: + push esi + sub ebx,ecx + sub [esp],ecx + push esi + call gfx_l2so + pop si + add si,8000h + sub word [esp],(8000h >> 4) + pop es + mov di,si + add di,ax + es rep movsb + pop esi + jmp align_it_30 +align_it_60: + + cld + +align_it_90: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +; Convert 32bit linear address to seg:ofs. +; +; dword [esp + 2]: linear address +; +; return: +; dword [esp + 2]: seg:ofs +; +; Notes: +; - changes no regs +; +gfx_l2so: + push eax + mov eax,[esp + 6] + shr eax,4 + mov [esp + 8],ax + and word [esp + 6],byte 0fh + pop eax + ret + --- isolinux.asm +++ isolinux.asm @@ -20,6 +20,10 @@ ; **************************************************************************** %define IS_ISOLINUX 1 + +%define WITH_GFX 1 +; %define DEBUG_DISKIO + %include "macros.inc" %include "config.inc" %include "kernel.inc" @@ -58,9 +62,9 @@ ; ; Note: this structure can be added to, but it must ; -%define vk_power 6 ; log2(max number of vkernels) +%define vk_power 5 ; log2(max number of vkernels) %define max_vk (1 << vk_power) ; Maximum number of vkernels -%define vk_shift (16-vk_power) ; Number of bits to shift +%define vk_shift (15-vk_power) ; Number of bits to shift %define vk_size (1 << vk_shift) ; Size of a vkernel buffer struc vkernel @@ -74,7 +78,7 @@ endstruc %ifndef DEPEND -%if (vk_end > vk_size) || (vk_size*max_vk > 65536) +%if (vk_end > vk_size) || (vk_size*max_vk > 8000h) %error "Too many vkernels defined, reduce vk_power" %endif %endif @@ -83,9 +87,9 @@ ; Segment assignments in the bottom 640K ; 0000h - main code/data segment (and BIOS segment) ; -real_mode_seg equ 3000h -vk_seg equ 2000h ; Virtual kernels -xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem +real_mode_seg equ 7000h +vk_seg equ 6800h ; Virtual kernels +xfer_buf_seg equ 8000h ; Bounce buffer for I/O to high mem comboot_seg equ real_mode_seg ; COMBOOT image loading zone ; @@ -221,9 +225,21 @@ alignb 4 default_cmd resb max_cmd_len+1 ; "default" command line +InitRDClust resw 1 ; Initrd size in clusters +InitRDSize resd 1 ; Initrd size in bytes +Splashat resd 1 ; Load address (linear) for splash +SplashClust resw 1 ; Splash size in clusters +SplashName resb FILENAME_MAX ; Mangled Splash image name +SplashCName resb FILENAME_MAX ; Unmangled Splash image name + alignb open_file_t_size Files resb MAX_OPEN*open_file_t_size +vbe_buf resb 200h ; VBE2 buffer +ddc_buf resb 80h ; for DDC info +mi_buf resb 200h ; VBE mode info & disk buffer +mi_list resb 100h ; VBE mode list + section .text org 7C00h ;; @@ -290,6 +306,21 @@ mov [ImageSectors],ax ; boot file sectors mov [DriveNo],dl + + ; check whether the BIOS did load us correctly + cmp dl,80h ; some BIOSes try to do floppy emulation... + jb bios_err + cmp dword [FirstSecSum], byte 0 + jz bios_ok +bios_err: + mov si,broken_bios_msg + call writemsg + jmp short $ +broken_bios_msg db 13, 10, 'Cannot boot from this CD. Please use CD2 or try a BIOS update.', 13, 10, 0 + align 4 +csum_value dd 0 +bios_ok: + %ifdef DEBUG_MESSAGES mov si,startup_msg call writemsg @@ -298,6 +329,9 @@ call crlf %endif +%if 0 + ; Some BIOSes don't like that call. + ; Now figure out what we're actually doing ; Note: use passed-in DL value rather than 7Fh because ; at least some BIOSes will get the wrong value otherwise @@ -318,6 +352,8 @@ call crlf %endif +%endif + found_drive: ; Some BIOSes apparently have limitations on the size ; that may be loaded (despite the El Torito spec being very @@ -390,6 +426,9 @@ %endif jmp all_read ; Jump to main code +%if 0 + ; doesn't work anyway, see above + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -571,6 +610,7 @@ call writehex2 call crlf jmp .found_drive ; Pray that this works... +%endif fatal_error: mov si,nothing_msg @@ -630,10 +670,17 @@ ; getlinsec: mov si,dapa ; Load up the DAPA - mov [si+4],bx - mov bx,es - mov [si+6],bx mov [si+8],eax + ; seems that some BIOSes have problems if the target + ; segment is 0 (don't ask); to avoid this, we normalize + ; the buffer address here + ; -> seen on Acer TravelMate C102Ti + mov [si+4],bx + and word [si+4],0fh + mov ax,es + shr bx,4 + add ax,bx + mov [si+6],ax .loop: push bp ; Sectors left cmp bp,[MaxTransfer] @@ -660,14 +707,72 @@ ; INT 13h with retry xint13: mov byte [RetryCount],retry_count .try: pushad +%ifdef DEBUG_DISKIO + pushad + mov cx,16 +.zap: + lodsb + call writehex2 + mov al,' ' + call writechr + loop .zap + mov ah,0 + int 16h + popad +%endif + ; seen buggy bios that overwrites buffer address on error... + push dword [dapa + 4] int 13h + pop dword [dapa + 4] +%ifdef DEBUG_DISKIO + pushad + pushf + push ax + mov al,':' + call writechr + mov al,' ' + call writechr + pop ax + sbb al,al + call writehex4 + call crlf + mov ah,0 + int 16h + popf + popad +%endif jc .error +.noerror: add sp,byte 8*4 ; Clean up stack ret .error: + or ah,ah + jz .noerror mov [DiskError],ah ; Save error code popad mov [DiskSys],ax ; Save system call number + + test byte [gfx_user_note],1 + jz .noeject + cmp byte [RetryCount],4 + ja .noeject + cmp byte [DiskError],0aah ; drive not ready + jnz .noeject + ; might have been cdrom eject, wait a bit + cmp byte [gfx_ok],0 + jz .noeject + push si + push di + push ax + mov si,err_not_ready + xor di,di + mov al,0 + call gfx_infobox + pop ax + pop di + pop si +.noeject: + dec byte [RetryCount] jz .real_error push ax @@ -716,6 +821,17 @@ mov fs,ax mov gs,ax sti + + cmp byte [gfx_ok],0 + jz .nogfx + mov si,err_failed_gfx + xor di,di + mov al,1 + call gfx_infobox + call gfx_done + call do_reboot +.nogfx: + mov si,err_bootfailed call cwritestr call getchar @@ -765,6 +881,9 @@ crlf_msg db CR, LF null_msg db 0 +err_failed_gfx db 'Error reading boot CD.', 0 +err_not_ready db 'CDROM drive not ready.', 0 + ; ; El Torito spec packet ; @@ -912,12 +1031,21 @@ inc al loop mkkeymap + test byte [KbdFlags],3 + jpe .nogfx ; left xor right shift: skip BIOS calls/no gfx + mov byte [do_nogfx],1 + mov byte [no_fkeys],1 ; no special F-key processing +.nogfx: + ; ; Now, we need to sniff out the actual filesystem data structures. ; mkisofs gave us a pointer to the primary volume descriptor ; (which will be at 16 only for a single-session disk!); from the PVD ; we should be able to find the rest of what we need to know. ; + call get_fs_structures + jmp get_fs_struct_done + get_fs_structures: mov eax,[bi_pvd] mov bx,trackbuf @@ -967,6 +1095,9 @@ call crlf %endif .no_isolinux_dir: + ret + +get_fs_struct_done: ; ; Locate the configuration file @@ -1562,6 +1693,10 @@ %include "strcpy.inc" ; strcpy() %include "rawcon.inc" ; Console I/O w/o using the console functions +%include "suse.inc" ; most of the new stuff is in suse.inc +%include "gfxlogo.inc" ; add gfx things + + ; ----------------------------------------------------------------------------- ; Begin data section ; ----------------------------------------------------------------------------- @@ -1581,7 +1716,8 @@ db 'booting, and I will take your word for it.', CR, LF, 0 err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 err_noparm db 'Missing parameter in config file.', CR, LF, 0 -err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_noinitrd db CR, LF +err_noinitrda db 'Could not find ramdisk image: ', 0 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' @@ -1606,6 +1742,7 @@ default_len equ ($-default_str) boot_dir db '/boot' ; /boot/isolinux isolinux_dir db '/isolinux', 0 + zb 64 ConfigName equ $ isolinux_cfg db 'isolinux.cfg', 0 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 @@ -1672,7 +1809,6 @@ OnerrorLen dw 0 ; Bytes in onerror command KbdTimeOut dw 0 ; Keyboard timeout (if any) CmdLinePtr dw cmd_line_here ; Command line advancing pointer -initrd_flag equ $ initrd_ptr dw 0 ; Initial ramdisk pointer/flag VKernelCtr dw 0 ; Number of registered vkernels ForcePrompt dw 0 ; Force prompt @@ -1719,6 +1855,8 @@ end_of_code equ (ldlinux_end-bootsec)+7C00h getcbuf equ (end_of_code + 511) & 0FE00h +; dd getcbuf + trackbufsize + ; VGA font buffer at the end of memory (so loading a font works even ; in graphics mode.) vgafontbuf equ 0E000h --- keywords +++ keywords @@ -29,3 +29,10 @@ f10 f11 f12 +initrdsize +readinfo +framebuffer +verbose +gfxboot +notice +disksize --- keywords.inc +++ keywords.inc @@ -77,6 +77,17 @@ %if IS_PXELINUX || IS_ISOLINUX keyword localboot, pc_localboot %endif +%ifdef WITH_GFX + keyword initrdsize, pc_setint16, ExpInitRDClust + keyword readinfo, pc_setint16, ReadInfo + keyword framebuffer, pc_setint16, FrameBuffer + keyword verbose, pc_setint16, do_write_msg + keyword gfxboot, pc_filecmd, get_gfx_file + keyword notice, pc_setint16, gfx_user_note +%if IS_SYSLINUX + keyword disksize, pc_disksize, DiskSize +%endif +%endif keywd_count equ ($-keywd_table)/keywd_size --- ldlinux.asm +++ ldlinux.asm @@ -29,6 +29,9 @@ %ifndef IS_MDSLINUX %define IS_SYSLINUX 1 %endif + +%define WITH_GFX 1 + %include "macros.inc" %include "config.inc" %include "kernel.inc" @@ -63,9 +66,9 @@ ; ; Note: this structure can be added to, but it must ; -%define vk_power 7 ; log2(max number of vkernels) +%define vk_power 6 ; log2(max number of vkernels) %define max_vk (1 << vk_power) ; Maximum number of vkernels -%define vk_shift (16-vk_power) ; Number of bits to shift +%define vk_shift (15-vk_power) ; Number of bits to shift %define vk_size (1 << vk_shift) ; Size of a vkernel buffer struc vkernel @@ -79,7 +82,7 @@ endstruc %ifndef DEPEND -%if (vk_end > vk_size) || (vk_size*max_vk > 65536) +%if (vk_end > vk_size) || (vk_size*max_vk > 8000h) %error "Too many vkernels defined, reduce vk_power" %endif %endif @@ -91,10 +94,10 @@ ; ; 0000h - main code/data segment (and BIOS segment) ; -real_mode_seg equ 5000h -fat_seg equ 3000h ; 128K area for FAT (2x64K) -vk_seg equ 2000h ; Virtual kernels -xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem +real_mode_seg equ 7000h +fat_seg equ 4800h ; up to 128K area for FAT (2x64K) +vk_seg equ 6800h ; Virtual kernels +xfer_buf_seg equ 8000h ; Bounce buffer for I/O to high mem comboot_seg equ real_mode_seg ; COMBOOT image loading zone ; --------------------------------------------------------------------------- @@ -110,6 +113,9 @@ ; trackbuf ends at 5000h +; VGA font buffer +vgafontbuf equ 5000h + ; ; Constants for the xfer_buf_seg ; @@ -122,7 +128,7 @@ xbs_vgatmpbuf equ 2*trackbufsize - absolute 5000h ; Here we keep our BSS stuff + absolute 7000h ; Here we keep our BSS stuff VKernelBuf: resb vk_size ; "Current" vkernel alignb 4 AppendBuf resb max_cmd_len+1 ; append= @@ -219,6 +225,15 @@ alignb 4 default_cmd resb max_cmd_len+1 ; "default" command line +InitRDClust resw 1 ; Initrd size in clusters +InitRDSize resd 1 ; Initrd size in bytes +Splashat resd 1 ; Load address (linear) for splash +SplashClust resw 1 ; Splash size in clusters +SplashName resb 11 ; Mangled Splash image name +SplashCName resb 13 ; Unmangled Splash image name +FATSegment resb 2 ; FAT segment + + section .text org 7C00h ; @@ -712,6 +727,7 @@ ; We can really only rely on a single sector having been loaded. Hence ; we should load the FAT into RAM and start chasing pointers... ; + xor ax,ax cwd inc dx ; DX:AX <- 64K @@ -719,13 +735,26 @@ mov si,ax push es - mov bx,fat_seg ; Load into fat_seg:0000 - mov es,bx mov eax,[bsHidden] ; Hidden sectors add edx,[bxResSectors] add eax,edx mov ecx,[bxFATsecs] ; Sectors/FAT + + mov bx,fat_seg ; Load into fat_seg:0000 + + ; calculate start of fat buffer segment + cmp ch,1 ; oops, > 128k? + jae update_fat_50 + mov bx,cx + shl bx,5 + neg bx + add bx,fat_seg + 2000h +update_fat_50: + + mov [FATSegment],bx + mov es,bx + fat_load_loop: mov ebp,ecx ; Make sure high EBP = 0 cmp bp,si @@ -869,7 +898,7 @@ mov bp,si ; Remaining sector count jmp short .getchunk .lastchunk: pop eax - call getlinsec + call getlinsec2 pop cx pop si popf @@ -881,10 +910,13 @@ ; getlinsecsr: save registers, call getlinsec, restore registers ; getlinsecsr: pushad - call getlinsec + call getlinsec2 popad ret +getlinsec2: + jmp near getlinsec + ; ; nextcluster: Advance a cluster pointer in SI to the next cluster ; pointed at in the FAT tables. CF=0 on return if end of file. @@ -895,7 +927,7 @@ nextcluster_fat12: push bx push ds - mov bx,fat_seg + mov bx,[FATSegment] mov ds,bx mov bx,si ; Multiply by 3/2 shr bx,1 ; CF now set if odd @@ -916,10 +948,11 @@ nextcluster_fat16: push ax push ds - mov ax,fat_seg + mov ax,[FATSegment] shl si,1 jnc .seg0 - mov ax,fat_seg+1000h + mov ax,[FATSegment] + add ax,1000h .seg0: mov ds,ax mov si,[si] cmp si,0FFF0h @@ -1054,6 +1087,12 @@ inc al loop mkkeymap + test byte [KbdFlags],3 + jpe .no_gfx ; left xor right shift: skip BIOS calls/no gfx + mov byte [do_nogfx],1 + mov byte [no_fkeys],1 ; no special F-key processing +.no_gfx: + ; ; Load configuration file ; @@ -1088,6 +1127,10 @@ ; abort_check: let the user abort with or ; abort_check: + cmp byte [gfx_ok],0 + jz .nogfx + ret +.nogfx: call pollchar jz ac_ret1 pusha @@ -1173,7 +1216,7 @@ mov [EndofDirSec],ax ; End of loaded pop eax mov bx,trackbuf - call getlinsecsr + call dir_cache mov si,trackbuf dir_test_name: cmp byte [si],0 ; Directory high water mark je dir_return ; Failed @@ -1203,6 +1246,63 @@ pop bp ret +; like getlinsecsr, but read from cache, if possible +dir_cache: + cmp byte [UserFont],0 + jz dir_cache_20 + jmp getlinsecsr ; cache is shared with vgafontbuf +dir_cache_20: + cmp eax,[DirCacheStart] + jnz dir_cache_50 + cmp bp,[DirCacheSectors] + jnz dir_cache_50 + or bp,bp + jz dir_cache_50 + + pusha + mov di,bx + mov si,vgafontbuf + mov ax,[bsBytesPerSec] + mul bp + xchg ax,cx + rep movsb + popa + + ret +dir_cache_50: + call getlinsecsr + + pusha + xchg ax,cx + mov ax,[bsBytesPerSec] + mul bp + xchg ax,cx + or cx,cx + jz dir_cache_80 + cmp cx,1000h ; smaller than vgafontbuf and trackbuf + ja dir_cache_80 + + mov [DirCacheStart],eax + mov [DirCacheSectors],bp + + mov di,vgafontbuf + mov si,bx + push ds + push es + + push es + push ds + pop es + pop ds + rep movsb + + pop es + pop ds +dir_cache_80: + popa + + ret + ; ; writechr: Write a single character in AL to the console without ; mangling any registers; handle video pages correctly. @@ -1225,6 +1325,15 @@ ; starting with "kaboom.patch" with this part kaboom2: + cmp byte [gfx_ok],0 + jz .nogfx + mov si,err_failed_gfx + xor di,di + mov al,1 + call gfx_infobox + call gfx_done + call do_reboot +.nogfx: mov si,err_bootfailed call cwritestr call getchar @@ -1358,6 +1467,9 @@ %include "highmem.inc" ; High memory sizing %include "strcpy.inc" ; strcpy() +%include "suse.inc" ; most of the new stuff is in suse.inc +%include "gfxlogo.inc" ; add gfx things + ; ----------------------------------------------------------------------------- ; Begin data section ; ----------------------------------------------------------------------------- @@ -1389,7 +1501,8 @@ db 'booting, and I will take your word for it.', CR, LF, 0 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0 -err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 +err_noinitrd db CR, LF +err_noinitrda db 'Could not find ramdisk image: ', 0 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' @@ -1399,6 +1512,7 @@ err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' db 'a key to continue.', CR, LF, 0 +err_failed_gfx db 'Error reading from disk.', 0 ready_msg db 'Ready.', CR, LF, 0 crlfloading_msg db CR, LF loading_msg db 'Loading ', 0 @@ -1447,7 +1561,6 @@ OnerrorLen dw 0 ; Bytes in onerror command KbdTimeOut dw 0 ; Keyboard timeout (if any) CmdLinePtr dw cmd_line_here ; Command line advancing pointer -initrd_flag equ $ initrd_ptr dw 0 ; Initial ramdisk pointer/flag VKernelCtr dw 0 ; Number of registered vkernels ForcePrompt dw 0 ; Force prompt @@ -1457,6 +1570,9 @@ VGAFontSize dw 16 ; Defaults to 16 byte font UserFont db 0 ; Using a user-specified font ScrollAttribute db 07h ; White on black (for text mode) +DirCacheStart dd 0 ; first cached dir sector +DirCacheSectors dw 0 ; cached sectors + ; ; Stuff for the command line; we do some trickery here with equ to avoid ; tons of zeros appended to our file and wasting space @@ -1473,13 +1589,15 @@ end_of_code equ (ldlinux_end-bootsec)+7C00h getcbuf equ (end_of_code + 511) & 0FE00h -; VGA font buffer at the end of memory (so loading a font works even -; in graphics mode.) -vgafontbuf equ 0E000h + absolute getcbuf + trackbufsize +vbe_buf resb 200h ; VBE2 buffer +ddc_buf resb 80h ; for DDC info +mi_buf resb 200h ; VBE mode info & disk buffer +mi_list resb 100h ; VBE mode list ; This is a compile-time assert that we didn't run out of space %ifndef DEPEND -%if (getcbuf+trackbufsize) > vgafontbuf +%if getcbuf < 7c00h || $ > 10000h %error "Out of memory, better reorganize something..." %endif %endif --- loadhigh.inc +++ loadhigh.inc @@ -43,10 +43,21 @@ .read_loop: and si,si ; If SI == 0 then we have end of file jz .eof + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx +%endif + push si mov si,dot_msg call cwritestr pop si + +%ifdef WITH_GFX +.isgfx: +%endif + call abort_check push eax ; Total bytes to transfer @@ -65,6 +76,14 @@ push edi ; Target buffer mov cx,ax xor bx,bx ; ES:0 + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + call gfx_progress_update +.nogfx: +%endif + call getfssec ; Load the data into xfer_buf_seg pop edi ; Target buffer pop ecx ; Byte count this round --- Makefile +++ Makefile @@ -18,7 +18,7 @@ OSTYPE = $(shell uname -msr) CC = gcc INCLUDE = -CFLAGS = -W -Wall -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 +CFLAGS = -W -Wall -O2 -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 PIC = -fPIC LDFLAGS = -O2 -s AR = ar @@ -26,7 +26,7 @@ NASM = nasm -O99 NINCLUDE = -BINDIR = /usr/bin +BINDIR = /usr/sbin LIBDIR = /usr/lib AUXDIR = $(LIBDIR)/syslinux INCDIR = /usr/include @@ -55,7 +55,7 @@ # mingw suite installed BTARGET = kwdhash.gen version.gen ldlinux.bss ldlinux.sys ldlinux.bin \ pxelinux.0 mbr.bin isolinux.bin isolinux-debug.bin \ - libsyslinux.a syslinux.exe $(LIB_SO) + libsyslinux.a $(LIB_SO) ITARGET = syslinux.com syslinux syslinux-nomtools copybs.com gethostip \ mkdiskimage DOCS = COPYING NEWS README TODO BUGS *.doc sample menu com32 @@ -68,7 +68,7 @@ INSTALL_BIN = syslinux gethostip ppmtolss16 lss16toppm # Things to install in /usr/lib/syslinux INSTALL_AUX = pxelinux.0 isolinux.bin isolinux-debug.bin \ - syslinux.com syslinux.exe copybs.com memdisk/memdisk + syslinux.com copybs.com memdisk/memdisk # Things to install in /usr/lib INSTALL_LIB = $(LIB_SO) libsyslinux.a # Things to install in /usr/include @@ -104,7 +104,7 @@ kwdhash.gen: keywords genhash.pl $(PERL) genhash.pl < keywords > kwdhash.gen -ldlinux.bin: ldlinux.asm kwdhash.gen version.gen +ldlinux.bin: ldlinux.asm kwdhash.gen version.gen suse.inc gfxlogo.inc $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ -l ldlinux.lst -o ldlinux.bin ldlinux.asm @@ -112,17 +112,19 @@ $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ -l pxelinux.lst -o pxelinux.bin pxelinux.asm -isolinux.bin: isolinux.asm kwdhash.gen version.gen +isolinux.bin: isolinux.asm kwdhash.gen version.gen suse.inc gfxlogo.inc $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ -l isolinux.lst -o isolinux.bin isolinux.asm + ./add_crc $@ pxelinux.0: pxelinux.bin cp pxelinux.bin pxelinux.0 # Special verbose version of isolinux.bin -isolinux-debug.bin: isolinux-debug.asm kwdhash.gen +isolinux-debug.bin: isolinux-debug.asm kwdhash.gen suse.inc gfxlogo.inc $(NASM) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ -l isolinux-debug.lst -o isolinux-debug.bin isolinux-debug.asm + ./add_crc $@ ldlinux.bss: ldlinux.bin dd if=ldlinux.bin of=ldlinux.bss bs=512 count=1 @@ -212,7 +214,7 @@ dist: tidy for dir in . sample memdisk ; do \ - ( cd $$dir && rm -f *~ \#* core ) ; \ + ( cd $$dir && rm -f *~ \#* core *.lst ) ; \ done local-spotless: --- memdisk/init.S16 +++ memdisk/init.S16 @@ -42,7 +42,7 @@ _start: jmp start - # This is the setup header, and it must start at %cs:2 (old 0x9020:2) +/* This is the setup header, and it must start at %cs:2 (old 0x9020:2) */ .ascii "HdrS" # header signature .word 0x0203 # header version number (>= 0x0105) @@ -57,7 +57,7 @@ # See Documentation/i386/boot.txt for # assigned ids - # flags, unused bits must be zero (RFU) bit within loadflags +/* flags, unused bits must be zero (RFU) bit within loadflags */ loadflags: LOADED_HIGH = 1 # If set, the kernel is loaded high CAN_USE_HEAP = 0x80 # If set, the loader also has set --- memdisk/Makefile +++ memdisk/Makefile @@ -20,7 +20,7 @@ ALIGN := $(call gcc_ok,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0) CC = gcc $(M32) -CFLAGS = -g -W -Wall -Os -fomit-frame-pointer -march=i386 $(ALIGN) \ +CFLAGS = -g -W -Wall -O2 -fomit-frame-pointer -march=i386 $(ALIGN) \ -DVERSION='"$(VERSION)"' -DDATE='"$(DATE)"' LDFLAGS = -g INCLUDE = -I../com32/include --- parseconfig.inc +++ parseconfig.inc @@ -266,6 +266,20 @@ ; pc_comment equ pc_getline ; Get a line and discard +%if IS_SYSLINUX +; +; like pc_setint16, but patch sector read funtion, too +; +pc_disksize: + push ax + call getint + pop si + jc .err + mov [si],bx + mov word [getlinsec2 + 1], getlinsec3 - getlinsec2 - 3 +.err: ret +%endif + ; ; Common subroutine: load line into trackbuf; returns with SI -> trackbuf ; --- README.SuSE +++ README.SuSE @@ -0,0 +1,50 @@ +syslinux/isolinux support a graphical boot screen using VESA BIOS +extensions. (Note that this is different from the graphics support that +syslinux comes with which uses a 640x480, 16 colors VGA mode). + +To use it you have to prepare a special boot logo file and put a line like +this into syslinux.cfg/iso.linux.cfg: + + gfxboot bootscreen + +The tools to create 'bootscreen' from the above example are in the +gfxboot package. Please _do_ have a look at its documentation before +you begin. + +Note that you cannot use comboot images and graphics at the same time as the +memory used for the picture overlaps the comboot loading area. + + +Before starting the Linux kernel syslinux will get some info from the BIOS. +To control this, there are some new options in syslinux.cfg: + + - readinfo + + "readinfo 1" enables the above feature; the default is 0 + "readinfo 2" enables even features + + - framebuffer + + "framebuffer 1" will get a video mode list from the VESA + BIOS and select an appropriate video mode for the linux kernel + + - verbose + + "verbose 1" enables some debug messages + +You can have a boot disk with a file system that spans several disks. +syslinux will ask you for disk changes if necessary. To enable this feature, +use + + - disksize + +Note that every individual disk must have at least a valid FAT boot sector. +syslinux will use the serial number stored there to verify that the correct +disk has been inserted (its last hex digit is the zero based disk number). + + +To make room for the graphics the maximum number of menu entries had to be +reduced. syslinux can have 64, isolinux 32 entries (used to be 128 and 64 +resp.). If you need more you can apply more-menu-entries.dif (included in +the syslinux source rpm) and get the original number back. + --- runkernel.inc +++ runkernel.inc @@ -52,8 +52,20 @@ kernel_sane: push ax push dx push si + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx + call hide_vmode +%endif + mov si,loading_msg call cwritestr + +%ifdef WITH_GFX +.isgfx: +%endif + ; ; Now start transferring the kernel ; @@ -116,6 +128,56 @@ mov si,KernelCName ; Unmangled kernel name mov cx,[KernelCNameLen] rep movsb + +%ifdef WITH_GFX +; +; Insert special linuxrc data here +; + cmp byte [lxrc_data1],0 + jz .nosusedata + mov si,lxrc_data + call str_copy +.nosusedata: + + cmp byte [gfx_ok],0 + jnz .isgfx + + cmp byte [video_mode],0 + jnz .vmode_10 + mov si,opt_textmode + call str_copy +.vmode_10: + cmp byte [video_mode],1 + jnz .vmode_20 + mov eax,640 + (480 << 16) + jmp .vmode_40 +.vmode_20: + cmp byte [video_mode],2 + jnz .vmode_30 + mov eax,800 + (600 << 16) + jmp .vmode_40 +.vmode_30: + cmp byte [video_mode],3 + jnz .vmode_90 + mov eax,1024 + (768 << 16) +.vmode_40: + push di + call find_fb + pop di + or cx,cx + jz .vmode_90 + mov si,opt_video_mode + xchg ax,cx + xchg al,ah + call byte_to_hex + mov al,ah + call byte_to_hex + mov si,opt_video + call str_copy +.vmode_90: +.isgfx: +%endif + mov al,' ' ; Space stosb @@ -124,6 +186,18 @@ mov si,[CmdOptPtr] ; Options from user input call strcpy +%ifdef WITH_GFX +; debug: print final kernel command line + push ds + push es + pop ds + mov si,cmd_line_here + call xwritestr + pop ds + mov si,crlf_msg + call xwritestr +%endif + ; ; Scan through the command line for anything that looks like we might be ; interested in. The original version of this code automatically assumed @@ -144,6 +218,12 @@ je is_vga_cmd cmp eax,'mem=' je is_mem_cmd + +%ifdef WITH_GFX + cmp eax,'SLX=' + je is_slx_cmd +%endif + %if IS_PXELINUX cmp eax,'keep' ; Is it "keeppxe"? jne .notkeep @@ -199,11 +279,58 @@ %endif mov [cs:HighMemSize],ebx jmp short skip_this_opt + +%ifdef WITH_GFX +is_slx_cmd: + add si,byte 4 + call parseint + jc skip_this_opt ; Not an integer + mov [cs:SLXOption],bx + jmp short skip_this_opt +%endif + cmdline_end: push cs ; Restore standard DS pop ds sub si,cmd_line_here mov [CmdLineLen],si ; Length including final null + +%ifdef WITH_GFX + call boot_hd + jnc start_hd_90 + cmp byte [gfx_ok],0 + jz start_hd_50 + mov al,0 + mov si,err_bad_mbr2 + xor di,di + call gfx_infobox + mov si,no_msg + jmp abort_load +start_hd_50: + mov si,err_bad_mbr1 + call cwritestr + mov si,crlf_msg + jmp abort_load +start_hd_90: + + call lookup_initrd + jnc start_loading + cmp word [ExpInitRDClust],byte 0 + jz near initrd_notthere + +start_loading: + + call lookup_splash + cmp byte [gfx_ok],0 + jz kernel_nogfx + mov ax,[KernelClust] + add ax,[InitRDClust] + add ax,[SplashClust] + mov si,KernelCName + call gfx_progress_init +kernel_nogfx: +%endif + ; ; Now check if we have a large kernel, which needs to be loaded high ; @@ -241,11 +368,21 @@ ; jumping to it. ; read_kernel: + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx +%endif + mov si,KernelCName ; Print kernel name part of call cwritestr ; "Loading" message mov si,dotdot_msg ; Print dots call cwritestr +%ifdef WITH_GFX +.isgfx: +%endif + mov eax,[HighMemSize] sub eax,100000h ; Load address cmp eax,[KernelSize] @@ -266,8 +403,18 @@ ; On exit EDI -> where to load the rest +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx2 +%endif + mov si,dot_msg ; Progress report call cwritestr + +%ifdef WITH_GFX +.isgfx2: +%endif + call abort_check pop ecx ; Number of bytes in the initial portion @@ -282,17 +429,75 @@ mov ax,real_mode_seg ; Set to real mode seg mov es,ax +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx3 +%endif + mov si,dot_msg call cwritestr +%ifdef WITH_GFX +.isgfx3: +%endif + + ; ; Now see if we have an initial RAMdisk; if so, do requisite computation ; We know we have a new kernel; the old_kernel code already will have objected ; if we tried to load initrd using an old kernel ; + +%ifdef WITH_GFX +%if IS_SYSLINUX + cmp byte [InitRDMissing],0 + jz load_initrd + + ; ok, the initrd is missing, ask user to replace disk + + cmp byte [gfx_ok],0 + jz load_i_10 + mov al,0 + mov si,mod_disk_msga + xor di,di + call gfx_infobox + jmp load_i_20 +load_i_10: + mov si,clrln_msg + call cwritestr + mov si,mod_disk_msg + call cwritestr + call wait_for_key + +load_i_20: + call detach_cd + ; call reload_boot + ; call update_fat + call lookup_initrd + pushf + cmp byte [gfx_ok],0 + jnz load_i_50 + mov si,clrln_msg + call cwritestr +load_i_50: + popf + jc initrd_notthere +%endif +%endif + load_initrd: test byte [initrd_flag],1 jz nk_noinitrd + +%ifdef WITH_GFX + call lookup_splash ; find splash and add size + mov edx,[InitRDSize] + add edx,3 + and edx,~3 + push edx + add edx,[splashlen] + mov [es:su_ramdisklen],edx +%else push es ; ES->real_mode_seg push ds pop es ; We need ES==DS @@ -307,6 +512,8 @@ jz initrd_notthere mov [es:su_ramdisklen1],ax ; Ram disk length mov [es:su_ramdisklen2],dx +%endif + mov edx,[HighMemSize] ; End of memory dec edx mov eax,[RamdiskMax] ; Highest address allowed by kernel @@ -319,10 +526,37 @@ sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk xor dx,dx ; Round down to 64K boundary mov [es:su_ramdiskat],edx ; Load address + +%ifdef WITH_GFX + pop eax + add edx,eax + mov [Splashat],edx ; Load address for splash + mov si,[initrd_ptr] +%endif + call loadinitrd ; Load initial ramdisk + +%ifdef WITH_GFX + cmp word [SplashClust],0 + jz short initrd_end + call loadsplash +%endif + jmp short initrd_end initrd_notthere: + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + mov si,err_noinitrda + mov di,InitRDCName + mov al,1 + call gfx_infobox + call do_reboot +.nogfx: +%endif + mov si,err_noinitrd call cwritestr mov si,InitRDCName @@ -330,18 +564,70 @@ mov si,crlf_msg jmp abort_load -no_high_mem: mov si,err_nohighmem ; Error routine - jmp abort_load +no_high_mem: + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + mov si,err_nohighmem + xor di,di + mov al,1 + call gfx_infobox + call do_reboot +.nogfx: +%endif + + mov si,err_nohighmem ; Error routine + jmp abort_load initrd_end: nk_noinitrd: + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + call gfx_progress_done + call abort_check + jmp update_disk +.nogfx: +%endif + ; ; Abandon hope, ye that enter here! We do no longer permit aborts. ; call abort_check ; Last chance!! +%ifdef WITH_GFX + mov si,clrln_msg +%else mov si,ready_msg +%endif + + call cwritestr + +%ifdef WITH_GFX +update_disk: +; +; if the user has an update disk, give him a chance to insert it now +; + cmp byte [wants_update],0 + jz .update_done + + cmp byte [gfx_ok],0 + jz .update_20 + + mov al,0 + mov si,upd_msg_1a + xor di,di + call gfx_infobox + jmp .update_done +.update_20: + mov si,upd_msg_1 call cwritestr + call wait_for_key +.update_done: + call gfx_done +%endif call vgaclearmode ; We can't trust ourselves after this @@ -474,6 +760,14 @@ xor ax,ax int 16h %endif + +%if do_test + mov si,test_ok_msg + call cwritestr + jmp $ +test_ok_msg db 'done.', 0 +%endif + ; ; Set up segment registers and the Linux real-mode stack ; Note: es == the real mode segment @@ -514,7 +808,7 @@ ; ; Need to be set: ; su_ramdiskat - Where in memory to load -; su_ramdisklen - Size of file +; su_ramdisklen - Size of file (WITH_GFX: InitRDSize) ; SI - initrd filehandle/cluster pointer ; loadinitrd: @@ -522,8 +816,22 @@ mov ax,real_mode_seg mov es,ax mov edi,[es:su_ramdiskat] ; initrd load address + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jnz .isgfx +%endif + push si + +%ifdef WITH_GFX + mov si,clrln_msg + call cwritestr + mov si,loading_msg ; Write "Loading " +%else mov si,crlfloading_msg ; Write "Loading " +%endif + call cwritestr mov si,InitRDCName ; Write ramdisk name call cwritestr @@ -531,9 +839,296 @@ call cwritestr pop si +%ifdef WITH_GFX +.isgfx: + mov eax,[InitRDSize] +%else mov eax,[es:su_ramdisklen] +%endif + call load_high ; Load the file +%ifndef WITH_GFX call crlf +%endif + pop es ; Restore original ES ret + + +%ifdef WITH_GFX + +; +; terminate cdrom boot floppy emulation +; +detach_cd: + test byte [SLXOption],1 ; just make it configurable + jnz detach_cd_90 + push es ; you never know... + mov si,trackbuf + mov ax,4b00h + mov byte [si],13h ; packet size + xor dx,dx ; dl: drive 0 + int 13h ; terminate floppy emulation + pop es +detach_cd_90: + ret + +; +; boot mbr, if SLXOption says so +; +; CF = 1 if failed +; +boot_hd: + mov ax,[SLXOption] + test al,2 ; should we do it? + jz boot_hd_90 + push es + shr ax,2 +%if IS_SYSLINUX + xchg [bsDriveNumber],al +%endif + push ax + call detach_cd +%if IS_SYSLINUX + xor eax,eax + mov es,ax + mov bx,trackbuf + push bx + call getonesec +%elif IS_ISOLINUX + pop dx + mov ax,0201h + xor cx,cx + mov es,cx + inc cx + xor dh,dh + mov bx,trackbuf + push bx + int 13h +%endif + pop si + cmp word [si+0x1fe],0aa55h + jnz boot_hd_80 + cmp word [si], byte 0 + jz boot_hd_80 + mov di,7c00h + push di + mov cx,0x100 + cld + rep movsw + call gfx_done + ret +boot_hd_80: +%if IS_SYSLINUX + pop ax + mov [bsDriveNumber],al +%endif + pop es + and word [SLXOption],byte 0 + stc +boot_hd_90: + ret + +%if 0 +; +; Doesn't work anyway: FAT area size has been made to fit the initial FAT. +; + +; +; reload boot block +; +reload_boot: + push es + xor ax,ax + xor dx,dx + mov es,ax + mov bx,trackbuf + push bx + call getonesec + pop si + add si,superblock-bootsec + mov di,superblock + mov cx,superblock_len + cld + rep movsb + + ; we can't reuse the bootblock code, it wouldn't fit :-(( + + ; expand the superblock to dwords + xor eax,eax + mov si,superblock + mov di,SuperInfo + mov cx,superinfo_size +.loop: + lodsw + dec si + stosd ; Store expanded word + xor ah,ah + stosd ; Store expanded byte + loop .loop + + ; rework things below + + movzx ax,[bsFATs] ; Number of FATs + mul word [bsFATsecs] ; Get the size of the FAT area + add ax,[bsHidden1] ; Add hidden sectors + adc dx,[bsHidden2] + add ax,[bsResSectors] ; And reserved sectors + adc dx,byte 0 + + mov [RootDir1],ax ; Location of root directory + mov [RootDir2],dx + mov [DataArea1],ax + mov [DataArea2],dx + + mov ax,32 ; Size of a directory entry + mul word [bsRootDirEnts] + mov bx,[bsBytesPerSec] + add ax,bx ; Round up, not down + dec ax + div bx ; Now we have the size of the root dir + mov [RootDirSize],ax + + add [DataArea1],ax + adc word [DataArea2],byte 0 + +reload_boot_90: + pop es + ret +%endif + +; +; look for initrd, get its size and prepare for loading it +; return: CF = 1 if it wasn't found +; +lookup_initrd: + and word [InitRDClust], byte 0 + test byte [initrd_flag],1 + jz lookup_initrd_90 + push word [ExpInitRDClust] + pop word [InitRDClust] + push es ; ES->real_mode_seg + push ds + pop es ; We need ES==DS + mov si,InitRD + mov di,InitRDCName + call unmangle_name ; Create human-readable name + sub di,InitRDCName + mov [InitRDCNameLen],di + mov di,InitRD + call searchdir ; Look for it in directory + pop es + stc + mov byte [InitRDMissing],1 ; remember for later + jz lookup_initrd_90 + mov byte [InitRDMissing],0 + mov [initrd_ptr],si ; Save cluster pointer + mov [InitRDSize],ax ; Size in bytes + mov [InitRDSize + 2],dx + div word [ClustSize] + and dx,dx ; Round up + setnz dl + movzx dx,dl + add ax,dx + mov [InitRDClust],ax ; Ramdisk clusters +lookup_initrd_90: + ret + +; +; look for splash, get its size and prepare for loading it +; return: CF = 1 if it wasn't found +; +lookup_splash: + and word [SplashClust], byte 0 + test byte [initrd_flag],1 + jz lookup_splash_90 + mov ax,[es:bs_vidmode] + mov si,fb_mode_list + mov cx,fb_mode_entries +lookup_splash_10: + cmp [si+fb_mode],ax + jz lookup_splash_20 + add si,sizeof_fb_entry + loop lookup_splash_10 + jmp lookup_splash_90 +lookup_splash_20: + mov ax,[si+fb_width] + call lookup_splash_to_dec + mov [SplashCName], eax + mov ax,[si+fb_height] + call lookup_splash_to_dec + mov [SplashCName+4], eax + mov [SplashCName+8], dword '.spl' + mov [SplashCName+12], byte 0 + push es + push ds + pop es + mov si,SplashCName + mov di,SplashName + call mangle_name + mov di,SplashName + call searchdir + pop es + stc + jz lookup_splash_90 + mov [splash_ptr],si ; Save cluster pointer + mov [splashlen],ax + mov [splashlen+2],dx + div word [ClustSize] + and dx,dx ; Round up + setnz dl + movzx dx,dl + add ax,dx + mov [SplashClust],ax ; Splash clusters +lookup_splash_90: + ret + +lookup_splash_to_dec: + push dx + push bx + push ecx + xor cx,cx + xor dx,dx + mov bx,10 + div bx + xchg ch,dl + div bx + xchg cl,dl + shl ecx,8 + div bx + xchg cl,dl + shl ecx,8 + mov cl,al + mov eax,ecx + pop ecx + pop bx + pop dx + add eax,0x30303030 + ret + + +; +; Load Splash into high memory +; +loadsplash: + cmp byte [gfx_ok],0 + jnz .isgfx + + mov si,clrln_msg + call cwritestr + mov si,loading_msg ; Write "Loading " + call cwritestr + mov si,SplashCName ; Write splash name + call cwritestr + mov si,dotdot_msg ; Write dots + call cwritestr + +.isgfx: + mov si,[splash_ptr] + mov edi,[Splashat] ; splash load address + mov eax,[splashlen] + call load_high ; Load the file + ret + +%endif --- suse.inc +++ suse.inc @@ -0,0 +1,1346 @@ +; +; some extra functionality for syslinux +; + +msg_0 db ' ', 0 +msg_1 db 10, 0 + +vbe_msg_0 db 'looking for VBE...', 13, 10, 0 +vbe_msg_1 db 'VBE ok', 13, 10, 0 +vbe_msg_2 db 'DDC supported', 13, 10, 0 +vbe_msg_3 db 'got EDID record', 13, 10, 0 +vbe_msg_4 db 'VBE >= 2.0, looking for fb modes...', 13, 10, 0 +vbe_msg_5 db ' mode found', 13, 10, 0 +vbe_msg_6 db 'x', 0, +vbe_msg_7 db 'fb modes broken', 13, 10, 0 +apm_msg_0 db 'looking for APM...', 13, 10, 0 +apm_msg_1 db 'APM ok', 13, 10, 0 +hd_msg_0 db 'reading mbr...', 13, 10, 0 +hd_msg_1 db 'got mbr', 13, 10, 0 +hd_msg_2 db 'edd?', 13, 10, 0 +hd_msg_3 db 'edd ok', 13, 10, 0 +hd_msg_4 db 'drive 8' +hd_msg_4a db '0h ok', 13, 10, 0 +hd_msg_5 db 'cd type 4 boot', 13, 10, 0 +kbd_msg_0 db 'kbd id?', 13, 10, 0 +kbd_msg_1 db 'got kbd id', 13, 10, 0 +upd_msg_0 db ' Update floppy', 0 +upd_msg_1 db 13, ' ' + db 13, 'Please insert the driver update floppy/CDROM; then press ENTER to continue.', 0 +upd_msg_1a db 'Please insert the driver update floppy/CDROM.', 0 +mod_disk_msg db 'Please insert module disk 1; then press ENTER to continue.', 0 +mod_disk_msga db 'Please insert module disk 1.', 0 +boot_disk_msg db 'Please insert boot disk ' +boot_disk_msg0 db '0; then press ENTER to continue.', 0 +boot_ndisk_msg db 'This is not boot disk ' +boot_ndisk_msg0 db '0. Press ENTER to continue.', 0 +%if 0 +prod_excl db 'VMware', 0 +prod_excl_end equ $-1 +%endif + +do_write_msg db 0, 0 ; set to get some debug messages +wants_update db 0 +do_nogfx db 0 +no_fkeys db 0 +vmode_shown db 0 +hd_disk db 80h +dec_buf zb 10h +opt_textmode db ' textmode=1', 0 +opt_video db ' vga=0x' +opt_video_mode db '0000', 0 +ddc_timings dw 0 ; standard ddc timing info +ddc_xtimings dd 0, 0, 0, 0 +ddc_mult dd 0, 1 ; needed for ddc timing calculation + dd 3, 4 + dd 4, 5 + dd 9, 16 +video_mem dw 0 ; video memory size in 64k units +video_mode db 1 ; mode index: 0:text, 1:640x480, 2:800x600, 3:1024x768 +video_mode_mask db 0 ; supported modes: bit 2:800x600, bit 3:1024x768 +video_mode_num dw 0 ; mode number +xread_pack db 10h ; packet size + db 0 ; reserved + dw 1 ; sector count + dw mi_buf ; buffer offset +xread_pack_seg dw 0 ; buffer segment + dd 0, 0 ; sector number + +; framebuffer mode list +; Don't rearrange offsets, they're used in gfxboot, too! +fb_mode equ 0 ; word +fb_width equ 2 ; word +fb_height equ 4 ; word, must follow fb_width +fb_bits equ 6 ; byte +fb_ok equ 7 ; monitor supports it +sizeof_fb_entry equ 8 + +fb_mode_entries equ 16 +fb_mode_list times fb_mode_entries * sizeof_fb_entry db 0 + +lxrc_ptr dw lxrc_data1 +lxrc_data db 0 +lxrc_data1 zb 0fah + +splash_ptr dw 0 ; splash pointer +splashlen dd 0 ; splash len +FrameBuffer dw 0 ; Add an appropriate vga= line for kernel fb's +ReadInfo dw 0 ; Get some info from BIOS +ExpInitRDClust dw 0 ; Expected ramdisk size in clusters +InitRDMissing db 0 ; Set if it was missig +initrd_flag db 0 ; used to be overlayed with initrd_ptr !? +SLXOption dw 0 ; control sysliux via cmdline +DiskSize dw 0 ; unlimited +CurrentDisk db 0 ; current disk + +err_bad_mbr1 db CR, LF, +err_bad_mbr2 db 'Failed to start from Harddisk', 0 +load_gfx_msg db 'Loading...', 0 +no_msg db 0 +clrln_msg db 0dh, ' ', 0dh, 0 +gfx_ok db 0 + +; +; Read VBE info. +; +; es = ds! +; +get_vbe_info: + mov di,vbe_buf + mov dword [di],32454256h ; 'VBE2' + and word [di+4],byte 0 ; just in case + mov ax,4f00h + int 10h + cmp ax,4fh + jz get_vbe_info_90 + ; no vbe support: set vbe version to 0 + and word [di+4],byte 0 + stc +get_vbe_info_90: + ret +; +; Read EDID record via DDC +; +read_ddc: + pushad ; don't modify any regs + push es + push ds + pop es + mov si,vbe_msg_0 + call xwritestr + call get_vbe_info + jc near read_ddc_done + mov ax,[vbe_buf+12h] + mov [video_mem],ax + mov si,vbe_msg_1 + call xwritestr + xor cx,cx + xor dx,dx + mov ax,4f15h + mov bl,0 + int 10h + cmp ax,4fh + jnz near read_ddc_done + mov si,vbe_msg_2 + call xwritestr + push ds + pop es + mov di,ddc_buf + push di + mov cx,80h + xor ax,ax + rep stosb + pop di + mov ax,4f15h + mov bl,1 + xor cx,cx + xor dx,dx + int 10h + cmp ax,4fh + jnz near read_ddc_done + mov si,vbe_msg_3 + call xwritestr + mov bx,ddc_buf + + mov al,[bx+23h] + mov [ddc_timings],al + mov al,[bx+24h] + mov [ddc_timings+1],al + + mov cx,4 + lea si,[bx+26h] + mov di,ddc_xtimings +read_ddc_40: + lodsb + cmp al,1 + jbe read_ddc_70 + + movzx ebp,al + add bp,byte 31 + shl bp,3 + + mov al,[si] + shr al,6 + jz read_ddc_70 + movzx bx,al + shl bx,3 + + mov eax,ebp + mul dword [bx+ddc_mult] + div dword [bx+ddc_mult+4] + + jz read_ddc_70 + + shl eax,16 + add eax,ebp + mov [di],eax + +read_ddc_70: + inc si + add di,4 + loop read_ddc_40 + +read_ddc_done: + pop es + popad + ret + +; get apm capabilities & VBE video memory size +read_apm: + pushad ; don't modify any regs + push es + push ds + pop es + + mov si,[lxrc_ptr] + mov byte [si],',' + inc word [lxrc_ptr] + + mov si,apm_msg_0 + call xwritestr + mov ax,5300h + xor bx,bx + int 15h + jc read_apm_done + push cx + push ax + mov si,apm_msg_1 + call xwritestr + pop ax + + mov si,[lxrc_ptr] + + shl ah,4 + and al,0fh + or al,ah + call byte_to_hex + + pop ax + call byte_to_hex + + ; add VBE version info + + mov ax,[vbe_buf+4] + shl ah,4 + and al,0fh + or al,ah + call byte_to_hex + + ; add video mem size + + mov ax,[vbe_buf+12h] + xchg al,ah + call byte_to_hex + xchg al,ah + call byte_to_hex + + mov [lxrc_ptr],si + mov byte [si],0 + +read_apm_done: + pop es + popad + ret + +; read 1st hd sector & compute crc +read_hd: + pushad ; don't modify any regs + push es + push ds + pop es + + mov si,[lxrc_ptr] + mov byte [si],',' + inc word [lxrc_ptr] + mov byte [si + 1],0 + + ; maybe we booted from cdrom with an hd image + ; (special magic from our mbr loader) + cmp byte [7c03h],19 + jnz read_hd_03 + mov byte [hd_disk],81h + mov byte [hd_msg_4a],'1' + mov si,hd_msg_5 + call xwritestr +read_hd_03: + + mov si,hd_msg_2 + call xwritestr + + mov ah,41h + mov bx,55aah + mov dl,[hd_disk] + int 13h + mov bp,0 + jc read_hd_05 + cmp bx,0aa55h + jnz read_hd_05 + test cl,1 + jz read_hd_05 + + inc bp + + mov si,hd_msg_3 + call xwritestr + +read_hd_05: + mov si,hd_msg_0 + call xwritestr + + mov ah,10h + mov dl,[hd_disk] + push bp + int 13h + pop bp + jc near read_hd_done + cmp ah,0 + jnz near read_hd_done + + mov si,hd_msg_4 + call xwritestr + + mov ax,0201h + mov cx,1 + mov dh,ch ; dh = 0 + mov dl,[hd_disk] + mov bx,mi_buf + push bp + int 13h + pop bp + jc near read_hd_done + + mov si,hd_msg_1 + call xwritestr + + mov si,mi_buf + xor ebx,ebx + mov cx,200h + mov edi,57 + stc + sbb eax,eax +read_hd_20: + mov bl,[si] + inc si + add eax,ebx + mul edi + dec cx + jnz read_hd_20 + + mov si,[lxrc_ptr] + + mov bx,4 +read_hd_40: + rol eax,8 + call byte_to_hex + dec bx + jnz read_hd_40 + + or bp,bp + jz read_hd_90 + mov byte [si],'.' + inc si + + + ; get device path info + + push si + mov ax,4800h + mov dl,[hd_disk] + mov si,mi_buf + mov di,si + push ds + pop es + mov cx,100h + rep stosb + ; some BIOSes use only one byte as buffer len + mov word [si],0ffh + int 13h + pop si + jc read_hd_90 + + mov bx,mi_buf + cmp word [bx],38h + jb read_hd_90 + + cmp word [bx+1eh],0beddh + jnz read_hd_90 + + cmp dword [bx+24h],20494350h ; 'PCI ' + jnz read_hd_90 + + mov al,[bx+30h] + call byte_to_hex + mov al,[bx+31h] + call byte_to_hex + mov al,[bx+32h] + call byte_to_hex + +read_hd_90: + mov [lxrc_ptr],si + mov byte [si],0 + +read_hd_done: + pop es + popad + ret + +; read keyboard id +read_kbd: + pushad ; don't modify any regs + push es + push ds + pop es + + mov si,[lxrc_ptr] + mov byte [si],',' + inc word [lxrc_ptr] + + mov si,kbd_msg_0 + call xwritestr + mov ax,900h + int 16h + test al,10h + jz read_kbd_done + + mov si,kbd_msg_1 + call xwritestr + mov ah,0ah + xor bx,bx + int 16h + + mov si,[lxrc_ptr] + mov al,bh + call byte_to_hex + mov al,bl + call byte_to_hex + + mov [lxrc_ptr],si + mov byte [si],0 + +read_kbd_done: + pop es + popad + ret + +; +; Read VBE2 mode info +; +; We use the VBE record returned earlier by the DDC calls. +; +; Go through the mode list and look for a video mode with frame buffer +; support. +; +read_vbe_modes: + pushad ; don't modify any regs + push es + push gs + push ds + pop es + + ; always support this mode + mov eax,640 + (480 << 16) + xor cx,cx + mov dh,4 + call add_fb_to_list2 + call enable_fb + + cmp word [FrameBuffer],byte 0 + jz near read_vbe_done + cmp word [vbe_buf+4],200h + jb near read_vbe_done + mov si,vbe_msg_4 + call xwritestr + ; do it again, data structures may have been overwritten + ; by ddc call + call get_vbe_info + jc near read_vbe_done + +%if 0 + xor ebx,ebx + lgs bx,[vbe_buf+1ah] + mov eax,gs + shl eax,4 + add eax,ebx + or eax,eax + jz read_vbe_10 + cmp eax,100000h + jae read_vbe_10 + call check_prod_excl + jc read_vbe_10 + mov si,vbe_msg_7 + call xwritestr + jmp near read_vbe_done +read_vbe_10: +%endif + + ; copy the list + lgs si,[vbe_buf+0eh] + mov cx,127 ; buffer has 128 entries + push ds + pop es + mov di,mi_list + mov bx,di + cld +read_vbe_15: + gs lodsw + stosw + cmp ax,0xffff + jz read_vbe_17 + loop read_vbe_15 +read_vbe_17: + mov word [di],0xffff +read_vbe_20: + mov cx,[bx] + inc bx + inc bx + cmp cx,0xffff + jz read_vbe_50 + + mov ax,4f01h + mov di,mi_buf + push cx + int 10h + pop cx + cmp ax,4fh + jnz read_vbe_20 + + test byte [mi_buf],1 ; mode supported? + jz read_vbe_20 + cmp dword [mi_buf+28h],byte 0 ; frame buffer start + jz read_vbe_20 + + mov eax,[mi_buf+12h] ; size + mov dl,[mi_buf+1bh] ; color mode (aka memory model) + mov dh,[mi_buf+19h] ; color depth + cmp dl,6 ; direct color + jnz read_vbe_30 + sub dh,[mi_buf+25h] ; reserved color bits + jmp read_vbe_40 +read_vbe_30: + cmp dl,4 ; PL8 + jnz read_vbe_20 + mov dh,8 +read_vbe_40: + + ; cx mode + ; eax resolution + ; dh color bits + + call add_fb_to_list + jmp read_vbe_20 + +read_vbe_50: + mov eax,640 + (480 << 16) + call enable_fb + + test word [ddc_timings],0ef03h + jnz read_vbe_51 + cmp word [video_mem],0x3e ; at least 4MB-128k + jb read_vbe_52 +read_vbe_51: + mov eax,800 + (600 << 16) + call enable_fb + +read_vbe_52: + test word [ddc_timings],0f00h + jnz read_vbe_53 + cmp word [video_mem],0x200 ; at least 32MB + jb read_vbe_54 +read_vbe_53: + mov eax,1024 + (768 << 16) + call enable_fb + +read_vbe_54: + test word [ddc_timings],0100h + jz read_vbe_56 + mov eax,1280 + (1024 << 16) + call enable_fb + +read_vbe_56: + mov cx,4 + mov si,ddc_xtimings +read_vbe_58: + lodsd + push si + push cx + call enable_fb + pop cx + pop si + loop read_vbe_58 + + ; preselect mode for text interface + + mov eax,800 + (600 << 16) + call find_fb + cmp dl,1 + jb read_vbe_60 + or byte [video_mode_mask],1 << 2 + cmp dl,2 + jb read_vbe_60 + mov byte [video_mode],2 +read_vbe_60: + + mov eax,1024 + (768 << 16) + call find_fb + cmp dl,1 + jb read_vbe_62 + or byte [video_mode_mask],1 << 3 + cmp dl,2 + jb read_vbe_62 + mov byte [video_mode],3 +read_vbe_62: + +read_vbe_done: + pop gs + pop es + popad + ret + + +%if 0 +; go through exclude list +; +; in: gs:bx product string +; out: CF 0/1 found/not found +; +check_prod_excl: + cld + mov si,prod_excl +check_prod_excl_20: + mov di,bx + dec di +check_prod_excl_30: + inc di + lodsb + or al,al + jz check_prod_excl_90 + cmp al,[gs:di] + jz check_prod_excl_30 +check_prod_excl_40: + lodsb + or al,al + jnz check_prod_excl_40 + cmp si,prod_excl_end + jb check_prod_excl_20 + stc +check_prod_excl_90: + ret +%endif + + +; add fb mode to mode list +; +; cx mode +; eax resolution +; dh color bits +; +; only added if color bits are 8 or 16 and resolution is at least 640x480 +; +; must not change bx & eax +; +add_fb_to_list: + cmp dh,8 + jz add_fb_10 + cmp dh,16 + jnz add_fb_90 +add_fb_to_list2: +add_fb_10: + cmp ax,640 + jb add_fb_90 + mov esi,eax + shr esi,16 + cmp si,480 + jb add_fb_90 + mov si,fb_mode_list + mov bp,fb_mode_entries +add_fb_20: + cmp eax,[si+fb_width] + jz add_fb_40 + cmp byte [si+fb_bits],0 + jz add_fb_40 + add si,sizeof_fb_entry + dec bp + jnz add_fb_20 + jmp add_fb_90 +add_fb_40: + cmp [si+fb_bits],dh + jae add_fb_90 + mov [si+fb_mode],cx + or cx,cx + jz add_fb_50 + add byte [si+fb_mode+1],2 ; for linux kernel +add_fb_50: + mov [si+fb_width],eax + mov [si+fb_bits],dh +add_fb_90: + ret + + +; tag fb mode as supported +; +; eax resolution +; +enable_fb: + mov si,fb_mode_list + mov bp,fb_mode_entries + mov edx,eax + shr edx,16 +enable_fb_10: + cmp byte [si+fb_bits],0 + jz enable_fb_90 + cmp [si+fb_width],ax + ja enable_fb_50 + cmp [si+fb_height],dx + ja enable_fb_50 + mov byte [si+fb_ok],1 +enable_fb_50: + add si,sizeof_fb_entry + dec bp + jnz enable_fb_10 +enable_fb_90: + ret + + +; find fb mode +; +; eax resolution +; +; return: +; dl 0: not found, 1: found but not supp, 2: ok +; cx mode number +; +find_fb: + mov si,fb_mode_list + mov bp,fb_mode_entries + xor dl,dl + xor cx,cx +find_fb_10: + cmp byte [si+fb_bits],0 + jz find_fb_90 + cmp [si+fb_width],eax + jnz find_fb_50 + mov dl,[si+fb_ok] + inc dx + mov cx,[si+fb_mode] +find_fb_50: + add si,sizeof_fb_entry + dec bp + jnz find_fb_10 +find_fb_90: + ret + + +; unpack EISA ID +; ax -> [si] +; +unpack_eisa: + mov cx,ax + shr cx,10 + and cl,1fh + add cl,'A'-1 + mov [si],cl + mov cx,ax + shr cx,5 + and cl,1fh + add cl,'A'-1 + mov [si+1],cl + mov cx,ax + and cl,1fh + add cl,'A'-1 + mov [si+2],cl + add si,3 + ret + +; al -> to hex +; +byte_to_hex: + mov cl,al + shr cl,4 + call byte_to_hex_10 + mov cl,al + and cl,0fh +byte_to_hex_10: + cmp cl,10 + jb byte_to_hex_20 + add cl,7 +byte_to_hex_20: + add cl,'0' + mov [si],cl + inc si + ret + +; +; write function +; +xwritestr: + cmp byte [cs:do_write_msg],0 + jz xwritestr_10 + call cwritestr +xwritestr_10: + ret + +; +; ax: Number +; +xwritedec: + pusha + mov si,dec_buf+0fh + mov byte [si],0 +xwritedec_20: + xor dx,dx + mov cx,10 + div cx + add dl,'0' + dec si + mov [si],dl + or ax,ax + jnz xwritedec_20 + call xwritestr + popa + ret + +; +; see if user wants to use an update disk +; +chk_update: + cmp byte [gfx_ok],0 + jz chk_update_nogfx + ret +chk_update_nogfx: + pusha + clc + mov ah,12h + int 16h + jc chk_update_90 + + cmp byte [wants_update],0 + jnz chk_update_90 + test ah,0ah ; left or right ALT key + jz chk_update_90 + mov byte [wants_update],1 + mov cx,183bh + mov si,upd_msg_0 + push ax + call cwritestr_xy + pop ax + +chk_update_90: + popa + ret + +; +; cl, ch: x,y +; si: text +; +cwritestr_xy: + push ds + pusha + push cx + mov ah,3 + mov bh,0 + int 10h + pop cx + push dx + mov dx,cx + mov ah,2 + mov bh,0 + int 10h + call cwritestr +cwritestr_xy_80: + pop dx + mov ah,2 + mov bh,0 + int 10h +cwritestr_xy_90: + popa + pop ds + ret + +; +; wait for 'enter' key pressed +; +wait_for_key: + pusha +wait_for_key_10: + mov ah,0 + int 16h + cmp al,13 + jnz wait_for_key_10 + popa + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +vmode_msg_0 db 'F2=Text mode' +vmode_msg_1 db 'F3=640x480' +vmode_msg_2 db 'F4=800x600' +vmode_msg_3 db 'F5=1024x768' +vmode_msg_clr times vmode_msg_clr - vmode_msg_0 + 3 * 3 db ' ' +vmode_msg_end equ $ + +show_vmode: + push es + pusha + + cmp byte [no_fkeys],0 + jnz near show_vmode_95 + + mov ah,3 + mov bh,0 + int 10h + push dx + + mov byte [vmode_shown],1 + + push ds + pop es + + mov dx,1800h + mov cx,vmode_msg_1 - vmode_msg_0 + mov bp,vmode_msg_0 + mov bx,07h + cmp byte [video_mode],0 + jnz show_vmode_10 + mov bl,70h +show_vmode_10: + mov ax,1300h + int 10h + + mov dh,18h + mov dl,vmode_msg_1 - vmode_msg_0 + 3 + mov cx,vmode_msg_2 - vmode_msg_1 + mov bp,vmode_msg_1 + mov bx,07h + cmp byte [video_mode],1 + jnz show_vmode_20 + mov bl,70h +show_vmode_20: + mov ax,1300h + int 10h + + + test byte [video_mode_mask],1 << 2 + jz show_vmode_40 + + mov dh,18h + mov dl,vmode_msg_2 - vmode_msg_0 + 2 * 3 + mov cx,vmode_msg_3 - vmode_msg_2 + mov bp,vmode_msg_2 + mov bx,07h + cmp byte [video_mode],2 + jnz show_vmode_30 + mov bl,70h +show_vmode_30: + mov ax,1300h + int 10h +show_vmode_40: + + test byte [video_mode_mask],1 << 3 + jz show_vmode_60 + + mov dh,18h + mov dl,vmode_msg_3 - vmode_msg_0 + 3 * 3 + mov cx,vmode_msg_clr - vmode_msg_3 + mov bp,vmode_msg_3 + mov bx,07h + cmp byte [video_mode],3 + jnz show_vmode_50 + mov bl,70h +show_vmode_50: + mov ax,1300h + int 10h +show_vmode_60: + + +show_vmode_90: + pop dx + mov ah,2 + mov bh,0 + int 10h + +show_vmode_95: + + popa + pop es + ret + +hide_vmode: + pusha + cmp byte [vmode_shown],0 + jz hide_vmode_90 + + mov ah,3 + mov bh,0 + int 10h + push dx + + mov dx,1800h + mov cx,vmode_msg_end - vmode_msg_clr + mov bp,vmode_msg_clr + mov bx,07h + mov ax,1300h + int 10h + + pop dx + mov ah,2 + mov bh,0 + int 10h + +hide_vmode_90: + popa + ret + +process_fkeys: + cmp al,1 + jb process_fkeys_90 + cmp al,5 + cmc + jc process_fkeys_90 + + cmp al,3 + jnz process_fkeys_20 + test byte [video_mode_mask],1 << 2 + jz process_fkeys_90 +process_fkeys_20: + cmp al,4 + jnz process_fkeys_30 + test byte [video_mode_mask],1 << 3 + jz process_fkeys_90 +process_fkeys_30: + + mov [video_mode],al + sub byte [video_mode],1 + call show_vmode + clc +process_fkeys_90: + ret + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; string copy +; +; ds:si -> es:di +; +str_copy: + lodsb + stosb + or al,al + jnz str_copy + dec di + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; do a reboot +; +do_reboot: + call gfx_done + mov word [472h],1234h + push word 0ffffh + push word 0 + retf + int 19h + jmp $ + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; look for a fsc notebook lcd panel and set ddc_timings +read_fsc: + pushad + push es + push ds + cmp word [ddc_timings],byte 0 + jnz read_fsc_90 + + push word 0xf000 + pop ds + xor di,di +read_fsc_10: + cmp dword [di],0x696a7546 + jnz read_fsc_30 + cmp dword [di+4],0x20757374 + jnz read_fsc_30 + mov cx,0x20 + xor bx,bx + mov si,di +read_fsc_20: + lodsb + add bl,al + dec cx + jnz read_fsc_20 + or bl,bl + jnz read_fsc_30 + mov al,[di+23] + and al,0xf0 + jnz read_fsc_90 + mov bl,[di+21] + and bx,0xf0 + shr bx,3 + mov ax,[cs:bx+fsc_bits] + mov [cs:ddc_timings],ax + jmp read_fsc_90 +read_fsc_30: + add di,0x10 + jnz read_fsc_10 +read_fsc_90: + pop ds + pop es + popad + ret + +fsc_bits: + dw 0, 0x0004, 0x4000, 0x0200, 0x0100, 0x0200, 0, 0x4000 + dw 0x0200, 0, 0, 0, 0, 0, 0, 0 + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; read gfx data +get_gfx_file: + cmp byte [do_nogfx],0 + jnz .done + push si + mov si,load_gfx_msg + call cwritestr + pop si +%if IS_SYSLINUX + push word [FATSegment] + pop word [gfx_mem_end_seg] +%elif IS_ISOLINUX + mov word [gfx_mem_end_seg],vk_seg +%endif + call gfx_init ; Load and display file + cmp byte [gfx_ok],0 + jz .done + mov si,crlf_msg + call cwritestr +.done: + ret + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; Use VESA 2.0 calls to read the EDID monitor record. The Data will +; later be appended to the kernel command line. +; +; Get the APM status from the BIOS. +; +get_bios_info: + inc byte [no_fkeys] + cmp word [ReadInfo],0 + jz .done + dec byte [no_fkeys] + mov al,[KbdFlags] + and al,3 + jpo .done ; left xor right shift: skip BIOS calls + jz .not_verbose ; !(left and right shift) + mov byte [do_write_msg],1 +.not_verbose: + call read_ddc ; read Display Data Channel + call read_fsc + call read_apm ; get APM status + cmp word [ReadInfo],1 + jb .no_disk_read + call read_hd ; get crc of 1st hd block +.no_disk_read: + call read_kbd + call read_vbe_modes ; get VBE2 mode support + mov si,lxrc_data + 1 + call xwritestr + mov si,crlf_msg + call xwritestr +.done: + ret + + +; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; read from disk, ask for disk change, if necessary + +; EAX - Linear sector number +; ES:BX - Target buffer +; BP - Sector count +; +; (es:)bx gets updated + +%if IS_SYSLINUX + +; %define DEBUG_XXX + +getlinsec3: +%ifdef DEBUG_XXX + mov si,txt0 + call dump_params + call crlf +%endif + mov cx,[DiskSize] + or cx,cx + jz getlinsec3_70 ; unlimited + + xor dx,dx + div cx + xchg ax,dx + movzx eax,ax + + mov si,ax + add si,bp + sub si,cx + jbe getlinsec3_40 + ; split + + sub bp,si + movzx ebp,bp + push ebp + push eax + push si + push dx + call getlinsec3_40 + pop dx + pop bp + pop eax + pop esi + add eax,esi + movzx ebp,bp + inc dl + +getlinsec3_40: + push es + pushad + call disk_change + popad + pop es + jc kaboom +getlinsec3_70: +%ifdef DEBUG_XXX + mov si,txt1 + call dump_params + mov si,txt3 + call cwritestr + push ax + mov al,[CurrentDisk] + call writehex2 + pop ax + call crlf + pushad + call getchar + popad +%endif + call getlinsec + ret + +%ifdef DEBUG_XXX +dump_params: + push eax + call cwritestr + mov ax,es + call writehex4 + mov si,txt2 + call cwritestr + mov ax,bx + call writehex4 + mov si,txt3 + call cwritestr + pop eax + push eax + call writehex8 + mov si,txt3 + call cwritestr + mov ax,bp + call writehex4 + pop eax + ret + +txt0 db 'linsec3: ', 0 +txt1 db 'linsec: ', 0 +txt2 db ':', 0 +txt3 db ', ', 0 + +%include "writehex.inc" + +%endif + +boot_disk_msg1 db '' + +; dl: new disk +; return: CF = 1 -> error +disk_change: + cmp dl,[CurrentDisk] + jz disk_change_90 + + mov [CurrentDisk],dl + movzx eax,dl + mov [gfx_user_info_0],eax + add dl,'1' + mov [boot_disk_msg0],dl + mov [boot_ndisk_msg0],dl + +disk_change_20: + cmp byte [gfx_ok],0 + jz disk_change_40 + mov al,3 + xor di,di + xor si,si + call gfx_infobox + + jmp disk_change_50 +disk_change_40: + mov si,clrln_msg + call cwritestr + mov si,boot_disk_msg + call cwritestr + call wait_for_key + mov si,clrln_msg + call cwritestr +disk_change_50: + xor eax,eax + mov bp,1 + push bx + call getlinsec + pop bx + mov eax,[es:bx+27h] + sub eax,[bxVolumeID] + movzx edx,byte [CurrentDisk] + cmp eax,edx + jz disk_change_90 + mov [gfx_user_info_1],eax + + cmp byte [gfx_ok],0 + jz disk_change_70 + mov al,4 + xor di,di + xor si,si + call gfx_infobox + + jmp disk_change_50 +disk_change_70: + mov si,clrln_msg + call cwritestr + mov si,boot_ndisk_msg + call cwritestr +; mov eax,[es:bx+27h] +; call writehex8 + call wait_for_key + mov si,clrln_msg + call cwritestr + + jmp disk_change_20 +disk_change_90: + ret + +%endif + --- ui.inc +++ ui.inc @@ -16,6 +16,15 @@ ; call parse_config ; Parse configuration file no_config_file: + +%ifdef WITH_GFX + ; vbe things and such + call get_bios_info + + ; build gfx menu + call gfx_setup_menu +%endif + ; ; Check whether or not we are supposed to display the boot prompt. ; @@ -26,9 +35,27 @@ jz auto_boot ; If neither, default boot enter_command: + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + mov di,command_line + mov cx,max_cmd_len + xor ax,ax + xchg ax,[KbdTimeOut] ; only the first time + call gfx_input + cmp ax,1 + jnz load_kernel +.nogfx: +%endif + mov si,boot_prompt call cwritestr +%ifdef WITH_GFX + call show_vmode +%endif + mov byte [FuncFlag],0 ; not pressed mov di,command_line ; @@ -53,6 +80,11 @@ ; know the appropriate DX value time_loop: push cx tick_loop: push dx + +%ifdef WITH_GFX + call chk_update +%endif + call pollchar jnz get_char_pop mov dx,[BIOS_timer] ; Get time "of day" @@ -139,6 +171,12 @@ sub al,59 ; F1 jb short get_char_2 show_help: ; AX = func key # (0 = F1, 9 = F10) + +%ifdef WITH_GFX + call process_fkeys + jnc get_char_2 +%endif + push di ; Save end-of-cmdline pointer shl ax,FILENAME_MAX_LG2 ; Convert to pointer add ax,FKeyName @@ -190,6 +228,17 @@ stosb load_kernel: ; Load the kernel now + +%if IS_ISOLINUX + test byte [gfx_user_note],1 + jz .noreload + pushad + ; Maybe clear Files, too? + call get_fs_structures + popad +.noreload: +%endif + ; ; First we need to mangle the kernel name the way DOS would... ; @@ -309,6 +358,18 @@ push di call unmangle_name ; Get human form mov si,err_notfound ; Complain about missing kernel + +%ifdef WITH_GFX + cmp byte [gfx_ok],0 + jz .nogfx + pop di + mov al,2 + call gfx_infobox + mov si,no_msg + jmp abort_load +.nogfx: +%endif + call cwritestr pop si ; KernelCName call cwritestr @@ -359,9 +420,21 @@ push word real_mode_seg pop es mov di,cmd_line_here + +%ifdef WITH_GFX + ; gfx code includes them + cmp byte [gfx_ok],0 + jnz .isgfx +%endif + mov si,VKernelBuf+vk_append mov cx,[VKernelBuf+vk_appendlen] rep movsb + +%ifdef WITH_GFX +.isgfx: +%endif + mov [CmdLinePtr],di ; Where to add rest of cmd pop es pop di ; DI -> KernelName