blob: e3aed13f0084daf68d2918541b96cd7a37daf1f5 [file] [log] [blame]
; ****************************************************************************
;
; gfxboot.asm
;
; Copyright 2008-2009 Sebastian Herbszt
;
; This module is based on the gfxboot integration patch by Steffen Winterfeldt:
;
; Copyright 2001-2008 Steffen Winterfeldt
;
; Some parts borrowed from Syslinux core:
;
; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
; Boston MA 02111-1307, USA; either version 2 of the License, or
; (at your option) any later version; incorporated herein by reference.
;
; ****************************************************************************
absolute 0
pspInt20: resw 1
pspNextP: resw 1
resb 124
pspCmdLen: resb 1
pspCmdArg: resb 127
;%define DEBUG
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 dl,0 ; fake drive number
mov cl,11 ; fake sector size 2048 bytes
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
cb_fopen_failed:
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
or si,si
jnz cb_fread_noeof
and dword [f_size],0
cb_fread_noeof:
mov edx,cs
shl edx,4
add edx,trackbuf
jmp cb_fread_ok
cb_fread_eof:
xor ecx,ecx
cb_fread_ok:
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 al,1
jc cb_readsector_end
mov edx,ds
shl dx,4
add edx,trackbuf
xor al,al
cb_readsector_end:
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],88h ; 8MB at 8MB
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 edx,[gfx_mem0_end]
sub edx,[gfx_mem0_start]
sub edx,0fh ; space to allow for aligning later
; edx: max allowed size
cmp eax,-1 ; unknown file size -> set to max allowed size
jnz .has_size
mov eax,edx
.has_size:
cmp eax,edx
jbe read_bootlogo
gfx_file_too_big:
mov ax,2
mov bx,msg_bootlogo_toobig
int 22h
stc
ret
read_bootlogo:
mov [file_length],eax
mov edi,[gfx_mem]
; 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
; si == 0: EOF
or si,si
jz gfx_read_done
add edi,ecx
sub eax,ecx
ja read
jmp gfx_file_too_big
gfx_read_done:
sub eax,ecx
mov edx,[file_length]
sub edx,eax
; edx = real file size
mov [gfx_archive_end],edx
add edx,[gfx_mem0_start]
add edx,0fh ; for alignment
mov [gfx_mem0_start],edx
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],dentry_buf
mov [menu_desc+menu_default+2],cs
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
push si
push di
xor ecx,ecx
mov si,configbuf
mov di,default_keyword+1
mov cl, byte [default_keyword]
call memcmp
pop di
pop si
jz .do_default
.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
.do_default:
call skipspace
jz .eof
jc .noparm
call ungetc
push es
push di
push cs
pop es
mov di,dentry_buf
call getline
pop di
pop es
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
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
default_keyword db 7,'default',0
label_cnt dw 0
msg_progname db 'gfxboot: ',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_unknown_file_size db 'unknown file size',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
dentry_buf times 512 db 0
dentry_buf_len equ $ - dentry_buf
; 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_type 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 $