So here it is. Ugly and far from acceptable shape but nonetheless it seems to
work. Parts are borrowed from syslinux core and of course the gfxboot patch for
syslinux 3.63.
Syntax: gfxboot.com <bootlogo file>
- Sebastian
--- /dev/null 2007-09-21 23:50:58.000000000 +0200
+++ syslinux-3.73-pre6/modules/gfxboot.asm 2008-11-22 19:01:10.000000000 +0100
@@ -0,0 +1,883 @@
+ absolute 0
+pspInt20: resw 1
+pspNextP: resw 1
+ resb 124
+pspCmdLen: resb 1
+pspCmdArg: resb 127
+
+ section .text
+ org 100h
+
+_start:
+ mov ax,2
+ mov bx, msg_progname
+ int 22h
+
+ mov ax,2
+ mov bx, msg_crlf
+ int 22h
+
+ push es
+ mov ax,0ah
+ mov cl,9
+ int 22h
+ pop es
+ cmp al,32h
+ jnz not_pxelinux
+
+ mov ax,2
+ mov bx,msg_pxelinux
+ int 22h
+ ret
+not_pxelinux:
+ mov [derivative_id],al
+ mov [drivenumber],dl
+ mov [sectorshift],cl
+ mov ax,1
+ shl ax,cl
+ mov [sectorsize],ax
+ mov ax,trackbufsize
+ shr ax,cl
+ mov [BufSafe],ax
+
+ xor cx,cx
+ mov cl,[pspCmdLen]
+ dec cx
+ and cx,cx
+ jne continue
+
+ mov ax,2
+ mov bx, msg_usage
+ int 22h
+ ret
+continue:
+ mov di,pspCmdArg+1
+ add di,cx
+ dec di
+ std
+ mov al,' '
+ repe scasb
+ inc cx
+ cld
+ mov [pspCmdLen],cl
+ mov si,pspCmdArg+1
+ mov di,si
+ add di,cx
+ xor al,al
+ stosb
+ mov si,pspCmdArg+1
+
+; get config file name
+ mov ax,0eh
+ int 22h
+
+; open config file
+ mov si,bx ; es:bx config file name
+ mov ax,6
+ int 22h
+ jc no_config_file
+ and eax,eax
+ jz no_config_file
+ jmp got_config_file
+no_config_file:
+ push es
+ push bx
+ push cs
+ pop es
+ mov bx, msg_config_file
+ mov ax,2
+ int 22h
+ mov bx, msg_space
+ mov ax,2
+ int 22h
+ pop bx
+ pop es
+ mov ax,2
+ int 22h
+ push cs
+ pop es
+ mov bx, msg_space
+ mov ax,2
+ int 22h
+ mov bx, msg_missing
+ mov ax,2
+ int 22h
+ mov ax,2
+ mov bx, msg_crlf
+ int 22h
+ ret
+got_config_file:
+ push cs
+ pop es
+ call parse_config
+
+; get_gfx_file
+ mov ax,cs
+ add ax,2000h
+ mov word [gfx_mem_start_seg],ax
+ mov ax,[pspNextP]
+ mov word [gfx_mem_end_seg],ax
+
+ call gfx_init
+ jc error
+
+ call gfx_setup_menu
+ jc exit
+
+input:
+ call gfx_input
+ jc exit
+
+ cmp eax,1
+ jz exit
+
+ cmp eax,2
+ jz boot
+
+ jmp input
+
+boot:
+ call far [gfx_bc_done]
+ mov ax,cs
+ mov es,ax
+ mov bx,command_line
+ mov ax,3
+ int 22h
+exit:
+ call far [gfx_bc_done]
+error:
+ ret
+
+cb_table dw cb_status ; 0
+ dw cb_fopen ; 1
+ dw cb_fread ; 2
+ dw cb_getcwd ; 3
+ dw cb_chdir ; 4
+ dw cb_readsector ; 5
+cb_len equ ($-cb_table)/2
+
+gfx_cb:
+ push cs
+ pop ds
+
+ cmp al,cb_len
+ jae gfx_cb_error
+
+ movzx bx,al
+ add bx,bx
+ call word [bx+cb_table]
+ jmp gfx_cb_end
+gfx_cb_error:
+ mov al,0ffh
+gfx_cb_end:
+ retf
+
+; Return status info
+;
+; return:
+; edx filename buffer (64 bytes)
+;
+cb_status:
+ mov edx,cs
+ shl edx,4
+ add edx,fname_buf
+
+ xor al,al
+ ret
+
+; Open file
+;
+; return:
+; al 0: ok, 1: file not found
+; ecx file length (al = 0)
+;
+cb_fopen:
+ push ds
+ pop es
+ mov ax,6
+ mov si,fname_buf
+ int 22h
+ jnc cb_fopen_ok
+ mov al,1
+ jmp cb_fopen_end
+cb_fopen_ok:
+ mov ecx,eax
+ mov [f_handle],si
+ mov [f_size],ecx
+ xor al,al
+cb_fopen_end:
+ ret
+
+; Read next chunk
+;
+; return:
+; edx buffer address (linear)
+; ecx data length (< 64k)
+;
+cb_fread:
+ cmp dword [f_size],0
+ jz cb_fread_eof
+ push ds
+ pop es
+ mov ax,7
+ mov si,[f_handle]
+ mov bx,trackbuf
+ mov cx,[BufSafe]
+ int 22h
+ mov al,1
+ jc cb_fread_end
+ sub [f_size], ecx
+ mov edx,cs
+ shl edx,4
+ add edx,trackbuf
+cb_fread_eof:
+ xor al,al
+cb_fread_end:
+ ret
+
+; Return current working directory
+;
+; return:
+; edx filename
+;
+cb_getcwd:
+ mov edx,cs
+ shl edx,4
+ add edx,gfx_slash
+ xor al,al
+ ret
+
+; Set current working directory
+;
+cb_chdir:
+ xor al,al
+ ret
+
+; Read sector
+;
+; edx sector
+;
+; return:
+; edx buffer (linear address)
+;
+; Note: does not return on error!
+;
+cb_readsector:
+ push esi
+ push edi
+ push ds
+ pop es
+ mov ax,19h
+ xor esi,esi
+ xor edi,edi
+ mov cx,1
+ mov bx,trackbuf
+ int 22h
+ pop edi
+ pop esi
+ mov edx,ds
+ shl dx,4
+ add edx,trackbuf
+ xor al,al
+ ret
+
+gfx_init:
+ mov ax,0e801h
+ xor bx,bx
+ xor cx,cx
+ xor dx,dx
+ int 15h
+ jnc got_e801
+
+ mov ax,2
+ mov bx, msg_memory
+ int 22h
+ stc
+ ret
+
+got_e801:
+ cmp ax,3c00h
+ jb mem_below_16mb
+ shl ebx,6
+ add eax,ebx
+
+mem_below_16mb:
+ shl eax,10
+ mov [gfx_bios_mem_size],eax
+ shr eax,20
+ cmp ax,16
+ jb skip_extended
+
+ mov word [gfx_xmem_0],81h ; 1MB at 8MB
+ mov word [gfx_xmem_1],0a1h ; 1MB at 10MB
+ mov dword [gfx_save_area1],7f0000h ; 8MB-64k
+
+skip_extended:
+ movzx ebx,word [gfx_mem_start_seg]
+ shl ebx,4
+
+ movzx ecx,word [gfx_mem_end_seg]
+ shl ecx,4
+
+ mov dword [gfx_mem],ebx
+ mov dword [gfx_mem0_start],ebx
+ mov dword [gfx_mem0_end],ecx
+
+ call gfx_read_file
+ jc gfx_init_end
+
+ call gfx_get_sysconfig
+
+ ; align 4
+ mov eax,[gfx_mem0_start]
+ add eax,3
+ and eax,~3
+ mov [gfx_mem0_start],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 esi,cs
+ shl esi,4
+ add esi,gfx_sysconfig
+ call far [gfx_bc_init]
+
+gfx_init_end:
+ ret
+
+gfx_read_file:
+; open file
+; es:si - file name
+
+ push cs
+ pop es
+ mov ax,6
+ mov si,pspCmdArg+1
+ int 22h
+ jnc gfx_file_read
+ stc
+ ret
+
+gfx_file_read:
+; si - file handle
+; eax - length of file in bytes, or -1
+; cx - file block size
+
+ mov [file_length],eax
+ mov edx,eax
+ mov [gfx_archive_end],edx
+ mov edi, [gfx_mem]
+ mov eax,[gfx_mem0_start]
+ lea eax,[eax+edx+0fh]
+ cmp eax,[gfx_mem0_end]
+ jbe read_bootlogo
+
+ mov ax,2
+ mov bx,msg_bootlogo_toobig
+ int 22h
+ stc
+ ret
+
+read_bootlogo:
+ mov [gfx_mem0_start],eax
+ mov eax,[file_length]
+; read file
+; si - file handle
+; es:bx - buffer
+; cx - number of blocks to read
+
+read:
+ push eax
+ mov ax,7
+ mov bx,trackbuf
+ mov cx,[BufSafe]
+ int 22h
+
+ push edi
+ push ecx
+ push si
+ push es
+
+ mov si,trackbuf
+ push edi
+ call gfx_l2so
+ pop di
+ pop es
+
+ rep movsb ; move ds:si -> es:di, length ecx
+ pop es
+ pop si
+ pop ecx
+ pop edi
+
+ pop eax
+ add edi, ecx
+ sub eax, ecx
+ jnz read
+
+bootlogo_read_done:
+ call find_file
+ or eax,eax
+ jnz found_bootlogo
+ stc
+ ret
+
+found_bootlogo:
+ push edi
+ push eax
+ add eax,edi
+ push dword [gfx_mem]
+ pop dword [gfx_archive_start]
+ neg al
+ and eax,byte 0fh
+ jz no_align
+ add [gfx_archive_start],eax
+
+no_align:
+ pop eax
+ pop edi
+ sub edi,[gfx_mem]
+ mov ecx,[gfx_archive_start]
+ add edi,ecx
+ mov [gfx_file],edi
+ add [gfx_archive_end],ecx
+ add eax,edi
+ shr eax,4
+ mov [gfx_bc_jt+2],ax
+ ret
+
+gfx_get_sysconfig:
+ mov ah,0
+ cmp byte [derivative_id],33h
+ jnz not_isolinux
+ mov ah,2
+not_isolinux:
+ mov al,[drivenumber]
+ mov [gfx_boot_drive],al
+ cmp al,80h ; floppy ?
+ jae not_floppy
+ mov ah,1
+not_floppy:
+ mov byte [gfx_media_type],ah
+ mov ah,[sectorshift]
+ mov byte [gfx_sector_shift],ah
+ mov ax,cs
+ mov [gfx_bootloader_seg],ax
+ ret
+
+gfx_setup_menu:
+ push es
+ push ds
+ pop es
+
+ mov word [menu_desc+menu_ent_list],0
+ mov di,[menu_seg]
+ mov [menu_desc+menu_ent_list+2],di
+
+ mov word [menu_desc+menu_default],0
+ mov [menu_desc+menu_default+2],di
+
+ mov di,256
+ mov [menu_desc+menu_arg_list],di
+ mov di,[menu_seg]
+ mov [menu_desc+menu_arg_list+2],di
+
+ mov cx,[label_cnt]
+ mov [menu_desc+menu_entries],cx
+
+ mov cx,256*2
+ mov [menu_desc+menu_ent_size],cx
+ mov [menu_desc+menu_arg_size],cx
+
+ mov esi,ds
+ shl esi,4
+ add esi,menu_desc
+
+ call far [gfx_bc_menu_init]
+ pop es
+ ret
+
+magic_ok:
+ xor eax,eax
+ cmp dword [es:bx],0b2d97f00h ; header.magic_id
+ jnz magic_ok_end
+ cmp byte [es:bx+4],8 ; header.version
+ jnz magic_ok_end
+ mov eax,[es:bx+8]
+magic_ok_end:
+ ret
+
+find_file:
+ mov edi,[gfx_mem]
+ push edi
+ call gfx_l2so
+ pop bx
+ pop es
+ call magic_ok
+ or eax,eax
+ jnz find_file_end
+
+find_file_loop:
+ mov ecx,[gfx_mem0_start]
+ sub ecx,26 + 12 ; min cpio header + gfx header
+ cmp edi,ecx
+ jae find_file_end
+ push edi
+ call gfx_l2so
+ pop bx
+ pop es
+ cmp word [es:bx],71c7h
+ jnz find_file_end
+ mov ax,[es:bx+20] ; file name size
+ movzx esi,ax
+
+ inc si
+ and si,~1 ; align
+
+ mov eax,[es:bx+22] ; data size
+ rol eax,16 ; get word order right
+ mov ecx,eax
+
+ 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_end
+
+ add edi,ecx
+ jmp find_file_loop
+
+find_file_end:
+ ret
+
+gfx_input:
+ mov edi,cs
+ shl edi,4
+ add edi, command_line ; buffer (0: no buffer)
+ mov ecx, max_cmd_len ; buffer size
+; xor eax,eax ; timeout value (0: no timeout)
+ mov eax,100 ; timeout value (0: no timeout)
+
+ call far [gfx_bc_input]
+ ret
+
+gfx_l2so:
+ push eax
+ mov eax,[esp + 6]
+ shr eax,4
+ mov [esp + 8],ax
+ and word [esp + 6],byte 0fh
+ pop eax
+ ret
+
+parse_config:
+ mov [f_handle],si
+ push es
+ mov ax,cs
+ add ax,1000h
+ mov es,ax
+ mov word [menu_seg],ax
+ xor eax,eax
+ mov cx,4000h
+ mov di,0
+ rep stosd
+ pop es
+.read:
+ call skipspace
+ jz .eof
+ jc .read
+ cmp al,'#'
+ je .nextline
+ or al,20h ; convert to lower case
+ mov di,configbuf
+ stosb
+.read_loop:
+ call getc
+ jc .eof
+ cmp al,' '
+ jbe .done
+ or al,20h ; convert to lower case
+ stosb
+ jmp .read_loop
+.done:
+ call ungetc
+
+ xor ax,ax
+ stosb
+%ifdef DEBUG
+ mov ax,2
+ mov bx, configbuf
+ int 22h
+
+ mov ax,2
+ mov bx, msg_crlf
+ int 22h
+%endif
+ push si
+ push di
+ xor ecx,ecx
+ mov si,configbuf
+ mov di,label_keyword+1
+ mov cl, byte [label_keyword]
+ call memcmp
+ pop di
+ pop si
+ jz .do_label
+
+.nextline:
+ call skipline
+ jmp .read
+
+.do_label:
+ call skipspace
+ jz .eof
+ jc .noparm
+ call ungetc
+ push es
+ push di
+ mov ax,[menu_seg]
+ mov es,ax
+ mov di,[menu_off]
+ call getline
+ mov di,[menu_off]
+ add di,512
+ mov [menu_off],di
+ pop di
+ pop es
+ inc word [label_cnt]
+
+ jmp .read
+
+.eof:
+.noparm:
+ ret
+
+skipline:
+ cmp al,10
+ je .end
+ call getc
+ jc .end
+ jmp skipline
+.end:
+ ret
+
+skipspace:
+.loop:
+ call getc
+ jc .eof
+ cmp al,0Ah
+ je .eoln
+ cmp al,' '
+ jbe .loop
+ ret
+.eof:
+ cmp al,al
+ stc
+ ret
+.eoln:
+ add al,0FFh
+ ret
+
+ungetc:
+ mov byte [ungetc_cnt],1
+ mov byte [ungetcdata],al
+ ret
+
+getc:
+ cmp byte [ungetc_cnt],1
+ jne .noungetc
+ mov byte [ungetc_cnt],0
+ mov al,[ungetcdata]
+ clc
+ ret
+.noungetc:
+ sub word [bufbytes],1
+ jc .get_data
+ mov si,trackbuf
+ add si,[bufdata]
+ mov al,[si]
+ inc word [bufdata]
+ clc
+ ret
+.get_data:
+ mov si,[f_handle]
+ and si,si
+ jz .empty
+ mov ax,7
+ mov bx,trackbuf
+ mov cx,[BufSafe]
+ int 22h
+ mov word [bufdata],0
+ jc .empty
+ mov [f_handle],si
+ mov [bufbytes],cx
+ jmp getc
+.empty:
+ mov word [f_handle],0
+ mov word [bufbytes],0
+ stc
+ ret
+
+getline:
+ call skipspace
+ jz .eof
+ jc .eoln
+ call ungetc
+.loop:
+ call getc
+ jc .ret
+ cmp al,' '
+ jna .ctrl
+.store:
+ stosb
+ jmp .loop
+.ctrl:
+ cmp al,10
+ je .ret
+ mov al,' '
+ jmp .store
+.eoln:
+ clc
+ jmp .ret
+.eof:
+ stc
+.ret:
+ xor al,al
+ stosb
+ ret
+
+
+memcmp:
+ push si
+ push di
+ push ax
+.loop:
+ mov al,[si]
+ mov ah,[di]
+ inc si
+ inc di
+ cmp al,ah
+ loope .loop
+ pop ax
+ pop di
+ pop si
+ ret
+
+ section .data
+msg_progname db 'gfxboot: ',0
+gfxboot_file db 'bootlogo',0
+derivative_id db 0
+drivenumber db 0
+sectorshift db 0
+sectorsize dw 0
+trackbufsize equ 16384
+trackbuf times trackbufsize db 0
+BufSafe dw 0
+file_length dd 0
+
+bufbytes dw 0
+bufdata dw 0
+configbuf times trackbufsize db 0
+ungetc_cnt db 0
+ungetcdata db 0
+label_keyword db 6,'label',0
+label_cnt dw 0
+
+msg_config_file db 'Configuration file',0
+msg_missing db 'missing',0
+msg_usage db 'Usage: gfxboot.com <bootlogo>',0dh,0ah,0
+msg_memory db 'Could not detect available memory size',0dh,0ah,0
+msg_bootlogo_toobig db 'bootlogo file too big',0dh,0ah,0
+msg_pxelinux db 'pxelinux is not supported',0dh,0ah,0
+msg_space db ' ',0
+msg_crlf db 0dh,0ah,0
+
+f_handle dw 0
+f_size dd 0
+fname_buf times 64 db 0
+fname_buf_len equ $ - fname_buf
+gfx_slash db '/', 0
+db0 db 0
+max_cmd_len equ 2047
+command_line times max_cmd_len+2 db 0
+
+; 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 times sizeof_menu_desc db 0
+menu_seg dw 0
+menu_off dw 0
+
+gfx_mem_start_seg dw 0
+gfx_mem_end_seg dw 0
+
+ align 4, db 0
+gfx_mem dd 0 ; linear address
+gfx_save_area1 dd 0 ; 64k
+gfx_save_area1_used db 0 ; != 0 if area1 is in use
+
+; 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
+
+; system config data (52 bytes)
+gfx_sysconfig equ $
+gfx_bootloader db 1 ; 0: boot loader type (0: lilo, 1: syslinux, 2: grub)
+gfx_sector_shift db 9 ; 1: sector shift
+gfx_media_typ db 0 ; 2: media type (0: disk, 1: floppy, 2: cdrom)
+gfx_failsafe db 0 ; 3: turn on failsafe mode (bitmask)
+ ; 0: SHIFT pressed
+ ; 1: skip gfxboot
+ ; 2: skip monitor detection
+gfx_sysconfig_size db gfx_sysconfig_end-gfx_sysconfig ; 4: size of sysconfig
data
+gfx_boot_drive db 0 ; 5: BIOS boot drive
+gfx_callback dw gfx_cb ; 6: offset to callback handler
+gfx_bootloader_seg dw 0 ; 8: code/data segment used by bootloader; must
follow gfx_callback
+gfx_reserved_1 dw 0 ; 10
+gfx_user_info_0 dd 0 ; 12: data for info box
+gfx_user_info_1 dd 0 ; 16: data for info box
+gfx_bios_mem_size dd 0 ; 20: BIOS memory size (in bytes)
+gfx_xmem_0 dw 0 ; 24: extended mem area 0 (start:size in MB; 12:4 bits)
+gfx_xmem_1 dw 0 ; 26: extended mem area 1
+gfx_xmem_2 dw 0 ; 28: extended mem area 2
+gfx_xmem_3 dw 0 ; 20: extended mem area 3
+gfx_file dd 0 ; 32: start of gfx file
+gfx_archive_start dd 0 ; 36: start of cpio archive
+gfx_archive_end dd 0 ; 40: end of cpio archive
+gfx_mem0_start dd 0 ; 44: low free memory start
+gfx_mem0_end dd 0 ; 48: low free memory end
+gfx_sysconfig_end equ $
+