From c059874482e85e47d26830a29f6a336d4773f10c0431ed607691fa38fabe5b37 Mon Sep 17 00:00:00 2001 From: OBS User autobuild Date: Wed, 28 Apr 2010 20:29:50 +0000 Subject: [PATCH] Accepting request 38954 from system:install:head checked in (request 38954) OBS-URL: https://build.opensuse.org/request/show/38954 OBS-URL: https://build.opensuse.org/package/show/system:install:head/syslinux?expand=0&rev=24 --- README.gfxboot | 4 +- syslinux-3.86-compat.diff | 4 +- syslinux-3.86-gfxboot.diff | 2581 +++++++++++++++++++++++++++++++++++- syslinux.changes | 5 - syslinux.spec | 1 - 5 files changed, 2575 insertions(+), 20 deletions(-) diff --git a/README.gfxboot b/README.gfxboot index 13f9e21..3e9feae 100644 --- a/README.gfxboot +++ b/README.gfxboot @@ -1,4 +1,4 @@ -gfxboot is now loaded via a COM32 module. If you used a line like +gfxboot is now loaded via a COM module. If you used a line like gfxboot bootlogo @@ -6,7 +6,7 @@ before in isolinux.cfg or syslinux.cfg, change this to ui gfxboot bootlogo -and add /usr/share/syslinux/gfxboot.c32 to your boot directory (the one +and add /usr/share/syslinux/gfxboot.com to your boot directory (the one where the config file is). You can also use diff --git a/syslinux-3.86-compat.diff b/syslinux-3.86-compat.diff index f4f2a88..4bb5741 100644 --- a/syslinux-3.86-compat.diff +++ b/syslinux-3.86-compat.diff @@ -30,7 +30,7 @@ index 65d71c9..2302536 100644 ret ; -+; "gfxboot" command; Shorthand for "ui gfxboot.c32" ++; "gfxboot" command; Shorthand for "ui gfxboot.com" +; +pc_gfxboot: + mov ax,2 @@ -51,7 +51,7 @@ index 65d71c9..2302536 100644 section .data vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0 SerialNotice db 1 ; Only print this once -+gfxboot_cmd db 'gfxboot.c32 ', 0 ++gfxboot_cmd db 'gfxboot.com ', 0 section .bss alignb 4 diff --git a/syslinux-3.86-gfxboot.diff b/syslinux-3.86-gfxboot.diff index 5117482..d4c2b47 100644 --- a/syslinux-3.86-gfxboot.diff +++ b/syslinux-3.86-gfxboot.diff @@ -173,11 +173,268 @@ index 23429bd..54f2e19 100644 ; ----------------------------------------------------------------------------- ; Common modules ; ----------------------------------------------------------------------------- +diff --git a/core/abort.inc b/core/abort.inc +index 5b16b9d..cc59fa7 100644 +--- a/core/abort.inc ++++ b/core/abort.inc +@@ -24,6 +24,10 @@ + ; assumes CS == DS + ; + dot_pause: ++ push ax ++ mov al,5 ++ call [comboot_hook] ++ pop ax + push si + mov si,dot_msg + call writestr_qchk +@@ -63,6 +67,8 @@ abort_check: + abort_load: + mov bx,error_or_command + abort_load_chain: ++ mov al,80h ++ call [comboot_hook] ; may not return + RESET_STACK_AND_SEGS AX + call writestr ; Expects SI -> error msg + +diff --git a/core/loadhigh.inc b/core/loadhigh.inc +index 8ff9da1..91061fc 100644 +--- a/core/loadhigh.inc ++++ b/core/loadhigh.inc +@@ -101,6 +101,8 @@ load_high: + ret + + .overflow: mov si,err_nohighmem ++ mov al,83h ++ call [comboot_hook] ; may not return + jmp abort_load + + section .data +diff --git a/core/runkernel.inc b/core/runkernel.inc +index e738706..5da5bc9 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -233,6 +233,8 @@ new_kernel: + mov [LoadFlags],al + + any_kernel: ++ mov al,4 ++ call [comboot_hook] + mov si,loading_msg + call writestr_qchk + mov si,KernelCName ; Print kernel name part of +@@ -324,6 +326,9 @@ load_initrd: + ; + call abort_check ; Last chance!! + ++ mov al,6 ++ call [comboot_hook] ++ + mov si,ready_msg + call writestr_qchk + +@@ -497,6 +502,8 @@ old_kernel: + xor ax,ax + cmp word [InitRDPtr],ax ; Old kernel can't have initrd + je .load ++ mov al,82h ++ call [comboot_hook] ; may not return + mov si,err_oldkernel + jmp abort_load + .load: +@@ -621,6 +628,8 @@ loadinitrd: + ret + + .notthere: ++ mov al,81h ++ call [comboot_hook] ; may not return + mov si,err_noinitrd + call writestr + mov si,InitRDCName +diff --git a/core/ui.inc b/core/ui.inc +index ed96ccd..0d896fc 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -417,8 +417,12 @@ vk_check: + %if HAS_LOCALBOOT + ; Is this a "localboot" pseudo-kernel? + cmp al,VK_LOCALBOOT ; al == KernelType ++ jne .no_local_boot ++ mov al,7 ++ call [comboot_hook] + mov ax,[VKernelBuf+vk_rname] ; Possible localboot type +- je local_boot ++ jmp local_boot ++.no_local_boot: + %endif + jmp get_kernel + +@@ -483,6 +487,8 @@ bad_kernel: + .really: + mov si,KernelName + mov di,KernelCName ++ mov al,81h ++ call [comboot_hook] ; may not return + push di + call unmangle_name ; Get human form + mov si,err_notfound ; Complain about missing kernel +@@ -525,7 +531,10 @@ on_error: + ; + ; kernel_corrupt: Called if the kernel file does not seem healthy + ; +-kernel_corrupt: mov si,err_notkernel ++kernel_corrupt: ++ mov al,82h ++ call [comboot_hook] ; may not return ++ mov si,err_notkernel + jmp abort_load + + ; diff --git a/core/comboot.inc b/core/comboot.inc -index f8a7853..37bd0f2 100644 +index f8a7853..f6abe1b 100644 --- a/core/comboot.inc +++ b/core/comboot.inc -@@ -970,6 +970,45 @@ comapi_shufraw: +@@ -96,24 +96,23 @@ is_comboot_image: + shl ax,6 ; Kilobytes -> paragraphs + mov word [es:02h],ax + +-%ifndef DEPEND +-%if real_mode_seg != comboot_seg +-%error "This code assumes real_mode_seg == comboot_seg" +-%endif +-%endif + ; Copy the command line from high memory ++ push word real_mode_seg ++ pop ds + mov si,cmd_line_here + mov cx,125 ; Max cmdline len (minus space and CR) + mov di,081h ; Offset in PSP for command line + mov al,' ' ; DOS command lines begin with a space + stosb + +-.loop: es lodsb ++.loop: lodsb + and al,al + jz .done + stosb + loop .loop + .done: ++ push cs ++ pop ds + + mov al,0Dh ; CR after last character + stosb +diff --git a/core/layout.inc b/core/layout.inc +index 19b5057..15dc8ff 100644 +--- a/core/layout.inc ++++ b/core/layout.inc +@@ -141,4 +141,4 @@ real_mode_seg equ cache_seg + 1000h + pktbuf_seg equ cache_seg ; PXELINUX packet buffers + %endif + +-comboot_seg equ real_mode_seg ; COMBOOT image loading zone ++comboot_seg equ real_mode_seg + 1000h ; COMBOOT image loading zone +diff --git a/core/runkernel.inc b/core/runkernel.inc +index 5da5bc9..033019c 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -168,7 +168,7 @@ opt_mem: + ret + + opt_quiet: +- mov byte [QuietBoot],QUIET_FLAG ++ or byte [QuietBoot],QUIET_FLAG + ret + + %if IS_PXELINUX +@@ -228,7 +228,9 @@ new_kernel: + ; we were provided. + ; + mov al,[es:su_loadflags] +- or al,[QuietBoot] ; Set QUIET_FLAG if needed ++ mov ah,[QuietBoot] ; Set QUIET_FLAG if needed ++ and ah,QUIET_FLAG ++ or al,ah + mov [es:su_loadflags],al + mov [LoadFlags],al + +@@ -642,7 +644,7 @@ loadinitrd: + ; assumes CS == DS + ; + writestr_qchk: +- test byte [QuietBoot],QUIET_FLAG ++ test byte [QuietBoot],QUIET_FLAG | 2 + jz writestr + ret + +@@ -697,4 +699,6 @@ KernelVersion resw 1 ; Kernel protocol version + ; + InitRDPtr resw 1 ; Pointer to initrd= option in command line + LoadFlags resb 1 ; Loadflags from kernel +-QuietBoot resb 1 ; Set if a quiet boot is requested ++ ++ section .data ++QuietBoot db 0 ; Set if a quiet boot is requested +diff --git a/core/ui.inc b/core/ui.inc +index 0d896fc..a256ed0 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -616,7 +616,7 @@ kernel_good: + ; + xor ax,ax + mov [InitRDPtr],ax +- mov [QuietBoot],al ++ and byte [QuietBoot],~QUIET_FLAG + %if IS_PXELINUX + mov [KeepPXE],al + %endif +diff --git a/core/runkernel.inc b/core/runkernel.inc +index 033019c..c9f37c3 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -266,7 +266,7 @@ read_kernel: + mov ecx,8000h ; 32K + sub ecx,esi ; Number of bytes to copy + add esi,(real_mode_seg << 4) ; Pointer to source +- mov edi,100000h ; Copy to address 100000h ++ mov edi,[KernelStart] ; Copy to kernel address + + call bcopy ; Transfer to high memory + +@@ -438,7 +438,7 @@ setup_move: + + mov eax,10000h ; Target address of low kernel + stosd +- mov eax,100000h ; Where currently loaded ++ mov eax,[KernelStart] ; Where currently loaded + stosd + neg eax + add eax,[KernelEnd] +@@ -446,9 +446,13 @@ setup_move: + inc cx + + mov bx,9000h ; Revised real mode segment ++ jmp .loading_initrd + + .loading_high: ++ mov eax,[KernelStart] ++ mov [fs:su_code32start],eax + ++.loading_initrd: + cmp word [InitRDPtr],0 ; Did we have an initrd? + je .no_initrd + +@@ -702,3 +706,5 @@ LoadFlags resb 1 ; Loadflags from kernel + + section .data + QuietBoot db 0 ; Set if a quiet boot is requested ++ alignz 4 ++KernelStart dd 100000h +diff --git a/core/comboot.inc b/core/comboot.inc +index f6abe1b..8b7ee5c 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -969,6 +969,45 @@ comapi_shufraw: mov ecx,P_ECX jmp shuffle_and_boot_raw @@ -223,31 +480,231 @@ index f8a7853..37bd0f2 100644 section .data %macro int21 2 -@@ -1029,6 +1068,8 @@ int22_table: +@@ -976,6 +1015,109 @@ comapi_shufraw: + dw %2 + %endmacro + ++ ++; ++; INT 22h AX=0027h Run command, return on error ++; ++; Terminates the COMBOOT program and executes the command line in ++; ES:BX as if it had been entered by the user. ++; CS:SI: comboot callback (via far call) ++; EDI kernel load address ++; EDX memory end (sets MyHighMemSize if != 0) ++; ++comapi_run2: ++ push word P_CS ++ push word P_SI ++ pop dword [comboot_far] ++ push dword P_EDI ++ pop dword [KernelStart] ++ mov edx,P_EDX ++ or edx,edx ++ jz .nohimemsize ++%if HIGHMEM_SLOP != 0 ++ sub edx,HIGHMEM_SLOP ++%endif ++.nohimemsize: ++ mov [AltHighMemSize],edx ++ mov ds,P_ES ++ mov si,P_BX ++ mov di,command_line ++ call strcpy ++ push cs ++ pop ds ++ push cs ++ pop es ++ mov [comboot_sp_save],sp ; save stack pointer ++ mov word [comboot_hook],comboot_hook_entry ++ or byte [QuietBoot],2 ++ jmp load_kernel ; Run a new kernel ++ ++comapi_run2_cont: ++ mov word [comboot_hook],comboot_hook_nop ++ mov sp,[comboot_sp_save] ; fix stack pointer ++ and byte [QuietBoot],~2 ++ clc ++ ret ++ ++ ++; ++; INT 22h AX=0028h Get memory size ++; ++comapi_memsize: ++ push dword [HighMemSize] ++ pop dword P_EAX ++ clc ++ ret ++ ++ ++; ++; Callback function used at various places during kernel/initrd loading. ++; ++; The function either returns or continues at comapi_run2_cont. ++; ++; AL: ++; bit 7: 0/1 return/don't return ++; bit 0-6: function code ++; 0: abort kernel/initrd loading ++; 1: kernel/initrd not found ++; 2: kernel corrupt ++; 3: out of memory (while initrd loading) ++; 4: progress start ++; 5: progress increment ++; 6: progress end: kernel loaded, stop gfxboot ++; 7: stop gfxboot ++; ++comboot_hook_entry: ++ pushad ++ push gs ++ push fs ++ push es ++ push ds ++ call far [comboot_far] ++ pop ds ++ pop es ++ pop fs ++ pop gs ++ popad ++ pushad ++ and al,7fh ++ cmp al,6 ++ jnz .notlast ++ push es ++ mov si,DOSSaveVectors ++ mov di,4*20h ++ mov cx,20h ++ push word 0 ++ pop es ++ rep movsd ; Restore DOS-range vectors ++ pop es ++.notlast: ++ popad ++ test al,80h ++ jnz comapi_run2_cont ++comboot_hook_nop: ++ ret ++ + int21_table: + int21 00h, comboot_return + int21 01h, comboot_getkey +@@ -1028,8 +1170,16 @@ int22_table: dw comapi_closedir ; 0022 close directory dw comapi_shufsize ; 0023 query shuffler size dw comapi_shufraw ; 0024 cleanup, shuffle and boot raw + dw comapi_setcwd ; 0025 set current working directory + dw comapi_mount ; 0026 read fs structures (aka mount) ++ dw comapi_run2 ; 0027 like 0003, but return on error ++ dw comapi_memsize ; 0028 get memory size int22_count equ ($-int22_table)/2 ++comboot_sp_save dw 0 ++comboot_hook dw comboot_hook_nop ++comboot_far dd 0 ++ APIKeyWait db 0 -@@ -1049,8 +1090,9 @@ feature_flags_len equ ($-feature_flags) + APIKeyFlag db 0 + +@@ -1048,8 +1198,10 @@ feature_flags_len equ ($-feature_flags) err_notdos db ': attempted DOS system call INT ',0 err_comlarge db 'COMBOOT image too large.', CR, LF, 0 - section .bss1 + section .bss2 alignb 4 ++AltHighMemSize resd 1 DOSErrTramp resd 33 ; Error trampolines +TmpDirName resb FILENAME_MAX ConfigName resb FILENAME_MAX CurrentDirName resb FILENAME_MAX +diff --git a/core/comboot.inc b/core/comboot.inc +index 8b7ee5c..5adbe74 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1050,12 +1050,14 @@ comapi_run2: + mov [comboot_sp_save],sp ; save stack pointer + mov word [comboot_hook],comboot_hook_entry + or byte [QuietBoot],2 ++ mov byte [comboot_run2_active],1 + jmp load_kernel ; Run a new kernel + + comapi_run2_cont: + mov word [comboot_hook],comboot_hook_nop + mov sp,[comboot_sp_save] ; fix stack pointer + and byte [QuietBoot],~2 ++ mov byte [comboot_run2_active],0 + clc + ret + +@@ -1179,6 +1181,7 @@ int22_count equ ($-int22_table)/2 + comboot_sp_save dw 0 + comboot_hook dw comboot_hook_nop + comboot_far dd 0 ++comboot_run2_active db 0 + + APIKeyWait db 0 + APIKeyFlag db 0 +diff --git a/core/ui.inc b/core/ui.inc +index a256ed0..40f7636 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -394,9 +394,13 @@ vk_check: + push word real_mode_seg + pop es + mov di,cmd_line_here ++ ; append line already included in this case ++ cmp byte [comboot_run2_active],0 ++ jnz .no_append_copy + mov si,VKernelBuf+vk_append + mov cx,[VKernelBuf+vk_appendlen] + rep movsb ++.no_append_copy: + mov [CmdLinePtr],di ; Where to add rest of cmd + pop es + mov di,KernelName +diff --git a/core/comboot.inc b/core/comboot.inc +index 5adbe74..c6bfab2 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1095,6 +1095,7 @@ comboot_hook_entry: + push fs + push es + push ds ++ mov ecx,[KernelSize] + call far [comboot_far] + pop ds + pop es +diff --git a/core/ui.inc b/core/ui.inc +index 40f7636..ef69a4d 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -632,7 +632,11 @@ kernel_good: + mov [KernelCNameLen],di + + ; Default memory limit, can be overridden by image loaders ++ mov eax,[AltHighMemSize] ++ or eax,eax ++ jnz .altsize + mov eax,[HighMemRsvd] ++.altsize: + mov [MyHighMemSize],eax + + popad +@@ -653,6 +657,7 @@ kernel_good: + ; At this point, EAX contains the size of the kernel, SI contains + ; the file handle/cluster pointer, and ECX contains the extension (if any.) + ; ++ mov [KernelSize],eax + movzx di,byte [KernelType] + add di,di + jmp [kerneltype_table+di] diff --git a/doc/comboot.txt b/doc/comboot.txt -index eb43708..13d18f6 100644 +index eb43708..2b1349d 100644 --- a/doc/comboot.txt +++ b/doc/comboot.txt -@@ -949,3 +949,20 @@ AX=0024h [3.80] Cleanup, shuffle and boot, raw version +@@ -949,3 +949,38 @@ AX=0024h [3.80] Cleanup, shuffle and boot, raw version with read/write data segments, matching the respective code segment. For mode 0, B=0 and the limits will be 64K, for mode 1, B=1 and the limits will be 4 GB. @@ -268,16 +725,2120 @@ index eb43708..13d18f6 100644 + + Reads filesystem data (e.g. after a CDROM change). + ++ ++AX=0027h [3.84] Run command ++ Input: AX 0027h ++ ES:BX null-terminated command string ++ SI comboot callback function (called via far call) ++ EDI kernel load address ++ EDX if != 0: initrd load address (that is: memory end) ++ Output: Does not return if the kernel loads correctly. ++ ++ Executes the command line as if it had been entered by the user. ++ Note that this function does return (with CF = 0) if there are ++ problems or the user aborted the load. Else it terminates the ++ COMBOOT program and starts the kernel. ++ ++AX=0028h [3.84] Get memory size ++ Input: AX 0028h ++ Output: EAX high memory size (in bytes) ++ diff --git a/modules/Makefile b/modules/Makefile -index 77020ea..f318364 100644 +index 77020ea..e6e7905 100644 --- a/modules/Makefile +++ b/modules/Makefile -@@ -19,7 +19,7 @@ include $(topdir)/MCONFIG.embedded +@@ -19,6 +19,11 @@ include $(topdir)/MCONFIG.embedded INCLUDES = -I$(com32)/include --BINS = pxechain.com gfxboot.com poweroff.com int18.com -+BINS = pxechain.com poweroff.com int18.com ++CFLAGS_COM = -O2 -Wall -Wno-pointer-sign -fomit-frame-pointer -m32 -march=i386 \ ++ -fno-align-functions -fno-align-labels -fno-align-jumps -fno-align-loops \ ++ -fno-builtin -nostdinc -I . ++ASMFLAGS_COM = -O99 -felf ++ + BINS = pxechain.com gfxboot.com poweroff.com int18.com all: $(BINS) +@@ -49,6 +54,15 @@ $(LIB): $(LIBOBJS) + %.ppm.gz: %.png + $(PNGTOPNM) $< | gzip -9 > $@ ++libio.o: libio.asm ++ nasm $(ASMFLAGS_COM) -o $@ -l $*.lst $< ++ ++gfxboot.o: gfxboot.c libio.h ++ $(CC) -g $(CFLAGS_COM) -c -o $@ $< ++ ++gfxboot.com: gfxboot.o libio.o ++ ld -M -Tcom.ld -o $@ $^ >$*.map ++ + tidy dist: + rm -f *.o *.a *.lst *.elf *.map .*.d + +diff --git a/modules/com.ld b/modules/com.ld +new file mode 100644 +index 0000000..a98f9aa +--- /dev/null ++++ b/modules/com.ld +@@ -0,0 +1,16 @@ ++/* ++ linker script for DOS program (.COM) ++ */ ++ ++OUTPUT_FORMAT("binary") ++OUTPUT_ARCH(i386) ++SEARCH_DIR(".") ++ENTRY(_start) ++SECTIONS ++{ ++ .init 0x100 : { *(.init) } ++ .text : { *(.text) } ++ .rodata : { *(.rodata*) } ++ .data : { *(.data) } ++ .bss : { __bss_start = .; *(.bss) } ++} +diff --git a/modules/gfxboot.c b/modules/gfxboot.c +new file mode 100644 +index 0000000..a59da40 +--- /dev/null ++++ b/modules/gfxboot.c +@@ -0,0 +1,1040 @@ ++/* ++ * ++ * gfxboot.c ++ * ++ * A comboot program to load gfxboot graphics. ++ * ++ * It is based on work done by Sebastian Herbszt in gfxboot.asm. ++ * ++ * Copyright (c) 2009 Steffen Winterfeldt. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++ ++#define ID_SYSLINUX 0x31 ++#define ID_PXELINUX 0x32 ++#define ID_ISOLINUX 0x33 ++#define ID_EXTLINUX 0x34 ++ ++#define MAX_CONFIG_LINE_LEN 2048 ++#define MAX_CMDLINE_LEN 1024 ++ ++// basic memory layout in MB ++#define GFX_MEMORY_START 1 ++#define GFX_MEMORY_SIZE 7 ++// assume initrd needs at least that much ++#define INITRD_MIN_MEMORY 64 ++ ++#define GFX_BC_INIT 0 ++#define GFX_BC_DONE 1 ++#define GFX_BC_INPUT 2 ++#define GFX_BC_MENU_INIT 3 ++#define GFX_BC_INFOBOX_INIT 4 ++#define GFX_BC_INFOBOX_DONE 5 ++#define GFX_BC_PROGRESS_INIT 6 ++#define GFX_BC_PROGRESS_DONE 7 ++#define GFX_BC_PROGRESS_UPDATE 8 ++#define GFX_BC_PROGRESS_LIMIT 9 // unused ++#define GFX_BC_PASSWORD_INIT 10 ++#define GFX_BC_PASSWORD_DONE 11 ++ ++// for now, static values ++#define MENU_LABEL_SIZE 128 ++#define MENU_ARG_SIZE 512 ++#define MENU_ENTRY_SIZE (MENU_LABEL_SIZE + MENU_ARG_SIZE) ++// entry 0 is reserved for the default entry ++#define MAX_MENU_ENTRIES (0x10000 / MENU_ENTRY_SIZE) ++ ++ ++typedef struct { ++ uint16_t handle; ++ uint16_t block_size; ++ int file_size; // file size (-1: unknown) ++ uint32_t buf; // must be block_size ++ unsigned buf_size; // in block_size units ++ unsigned data_len; // valid bytes in buf ++ unsigned buf_idx; // read pos in buffer ++} fd_t; ++ ++ ++// gfx config data (52 bytes) ++typedef struct __attribute__ ((packed)) { ++ uint8_t bootloader; // 0: boot loader type (0: lilo, 1: syslinux, 2: grub) ++ uint8_t sector_shift; // 1: sector shift ++ uint8_t media_type; // 2: media type (0: disk, 1: floppy, 2: cdrom) ++ uint8_t failsafe; // 3: turn on failsafe mode (bitmask) ++ // 0: SHIFT pressed ++ // 1: skip gfxboot ++ // 2: skip monitor detection ++ uint8_t sysconfig_size; // 4: size of sysconfig data ++ uint8_t boot_drive; // 5: BIOS boot drive ++ uint16_t callback; // 6: offset to callback handler ++ uint16_t bootloader_seg; // 8: code/data segment used by bootloader; must follow gfx_callback ++ uint16_t reserved_1; // 10 ++ uint32_t user_info_0; // 12: data for info box ++ uint32_t user_info_1; // 16: data for info box ++ uint32_t bios_mem_size; // 20: BIOS memory size (in bytes) ++ uint16_t xmem_0; // 24: extended mem area 0 (start:size in MB; 12:4 bits) ++ uint16_t xmem_1; // 26: extended mem area 1 ++ uint16_t xmem_2; // 28: extended mem area 2 ++ uint16_t xmem_3; // 30: extended mem area 3 ++ uint32_t file; // 32: start of gfx file ++ uint32_t archive_start; // 36: start of cpio archive ++ uint32_t archive_end; // 40: end of cpio archive ++ uint32_t mem0_start; // 44: low free memory start ++ uint32_t mem0_end; // 48: low free memory end ++} gfx_config_t; ++ ++ ++// menu description (18 bytes) ++typedef struct __attribute__ ((packed)) { ++ uint16_t entries; ++ uint32_t default_entry; // seg:ofs ++ uint32_t label_list; // seg:ofs ++ uint16_t label_size; ++ uint32_t arg_list; // seg:ofs ++ uint16_t arg_size; ++} menu_t; ++ ++ ++// e820 mem descriptor ++typedef struct __attribute__ ((packed)) { ++ uint64_t base; ++ uint64_t len; ++ uint32_t type; ++ uint32_t cont; ++} mem_info_t; ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// global file descriptor, implicitly used by read(), getc(), fgets() ++fd_t fd; ++ ++gfx_config_t gfx_config; ++menu_t menu; ++ ++struct { ++ uint32_t jmp_table[12]; ++ uint16_t code_seg; ++ char fname_buf[64]; ++} gfx; ++ ++unsigned comboot, comboot_len; ++unsigned io_buf, io_buf_len; ++unsigned menu_buf, menu_buf_len; ++unsigned freemem, freemem_len; ++ ++unsigned initrd_end; ++unsigned kernel_start; ++ ++int timeout; ++ ++char cmdline[MAX_CMDLINE_LEN]; ++char current_label[64]; ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ ++int open(char *name); ++int open32(uint32_t name); ++int read(void *buf, int size); ++int read32(uint32_t buf, int size); ++int getc(void); ++char *fgets(char *s, int size); ++ ++int strlen(char *s); ++int strcmp(char *s1, char *s2); ++char *skip_spaces(char *s); ++char *skip_nonspaces(char *s); ++void chop_line(char *s); ++ ++int atoi(char *s); ++ ++uint32_t get_config_file_name32(void); ++int read_config_file(void); ++ ++unsigned magic_ok(uint32_t buf); ++unsigned find_file(uint32_t buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len); ++ ++int get_mem_info(mem_info_t *mi); ++int gfx_init(char *file); ++void gfx_done(void); ++int gfx_input(void); ++int gfx_menu_init(void); ++ ++void gfx_infobox32(int type, uint32_t str1, uint32_t str2); ++void gfx_infobox(int type, char *str1, char *str2); ++ ++void boot(void); ++void show_message(char *file); ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int main(int argc, char **argv) ++{ ++ x86regs_t r; ++ uint8_t syslinux_id; ++ int menu_index; ++ ++ r.eax = 0x0a; // Get Derivative-Specific Information ++ r.ecx = 9; ++ x86int(0x22, &r); ++ syslinux_id = (uint8_t) r.eax; ++ gfx_config.sector_shift = (uint8_t) r.ecx; ++ gfx_config.boot_drive = (uint8_t) r.edx; ++ ++ // define our memory layout ++ // all must be at least 16 bytes aligned ++ ++ // 64k comboot code ++ comboot = comboot_seg() << 4; ++ comboot_len = 0x10000; ++ ++ // 16k file io buffer ++ io_buf = comboot + comboot_len; ++ io_buf_len = 0x4000; ++ ++ // 64k for parsed menu data ++ menu_buf = io_buf + io_buf_len; ++ menu_buf_len = 0x10000; ++ ++ // use remaining mem for gfx core ++ freemem = menu_buf + menu_buf_len; ++ // comboot api passes low memory end at address 2 ++ freemem_len = ((*(uint16_t *) 2) << 4) - freemem; ++ ++ gfx_config.bootloader = 1; ++ gfx_config.sysconfig_size = sizeof gfx_config; ++ gfx_config.bootloader_seg = comboot >> 4; ++ ++ // not gfx_cb() directly, we need a wrapper ++ gfx_config.callback = (uint32_t) _gfx_cb; ++ ++ if(syslinux_id == ID_PXELINUX) { ++ gfx_config.sector_shift = 11; ++ gfx_config.boot_drive = 0; ++ } ++ ++ if(argc < 2) { ++ printf("Usage: gfxboot.com bootlogo_file [message_file]\n"); ++ if(argc > 2) show_message(argv[2]); ++ ++ return 0; ++ } ++ ++ if(read_config_file()) { ++ printf("Error reading config file\n"); ++ if(argc > 2) show_message(argv[2]); ++ ++ return 0; ++ } ++ ++ if(gfx_init(argv[1])) { ++ printf("Error setting up gfxboot\n"); ++ if(argc > 2) show_message(argv[2]); ++ ++ return 0; ++ } ++ ++ gfx_menu_init(); ++ ++ for(;;) { ++ menu_index = gfx_input(); ++ ++ // abort gfx, return to text mode prompt ++ if(menu_index == -1) { ++ gfx_done(); ++ break; ++ } ++ ++ // get label name, is needed later for messages etc. ++ memcpy(current_label, cmdline, sizeof current_label); ++ current_label[sizeof current_label - 1] = 0; ++ *skip_nonspaces(current_label) = 0; ++ ++ // does not return if it succeeds ++ boot(); ++ } ++ ++ if(argc > 2) show_message(argv[2]); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// 0: ok, -1: error ++// ++int open32(uint32_t name) ++{ ++ x86regs_t r; ++ ++ fd.handle = 0; ++ fd.data_len = fd.buf_idx = 0; ++ ++ r.esi = name & 0xf; ++ r.eax = 0x06; // Open file ++ r.es = name >> 4; ++ x86int(0x22, &r); ++ ++ fd.block_size = r.ecx; ++ fd.file_size = r.eax; ++ ++ if( ++ (r.eflags & X86_CF) || ++ !fd.file_size || !fd.block_size || fd.block_size > io_buf_len ++ ) return -1; ++ ++ fd.handle = r.esi; ++ ++ fd.buf = io_buf; ++ fd.buf_size = io_buf_len / fd.block_size; ++ ++ // printf("block size = 0x%x, file size = %d\n", fd.block_size, fd.file_size); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// 0: ok, -1: error ++// ++int open(char *name) ++{ ++ return open32((uint32_t) name + comboot); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// Note: buf is 32bit address ++// ++int read32(uint32_t buf, int size) ++{ ++ x86regs_t r; ++ int i, len = 0; ++ ++ while(size) { ++ i = fd.data_len - fd.buf_idx; ++ ++ if(i > 0) { ++ i = i < size ? i : size; ++ memcpy32(buf, fd.buf + fd.buf_idx, i); ++ len += i; ++ buf += i; ++ size -= i; ++ fd.buf_idx += i; ++ } ++ ++ if(!size || !fd.handle) break; ++ ++ r.eax = 0x07; // Read file ++ r.ecx = fd.buf_size; ++ r.ebx = 0; ++ r.es = fd.buf >> 4; ++ r.esi = fd.handle; ++ x86int(0x22, &r); ++ fd.handle = r.esi; ++ fd.data_len = r.ecx; ++ fd.buf_idx = 0; ++ } ++ ++ return len; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int read(void *buf, int size) ++{ ++ return read32((uint32_t) buf + comboot, size); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int getc() ++{ ++ char buf[1]; ++ ++ return read(buf, 1) ? *buf : EOF; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++char *fgets(char *s, int size) ++{ ++ char *buf = s; ++ int c = EOF; ++ ++ while(size--) { ++ c = getc(); ++ if(c == EOF) break; ++ *buf++ = c; ++ if(c == 0x0a) break; ++ } ++ ++ *buf = 0; ++ ++ return c == EOF && s == buf ? 0 : s; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int strlen(char *s) ++{ ++ char *s0 = s + 1; ++ ++ while(*s++); ++ ++ return s - s0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int strcmp(char *s1, char *s2) ++{ ++ while(*s1 && *s1 == *s2) s1++, s2++; ++ ++ return (uint8_t) *s1 - (uint8_t) *s2; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++char *skip_spaces(char *s) ++{ ++ while(*s && (*s == ' ' || *s == '\t')) s++; ++ ++ return s; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++char *skip_nonspaces(char *s) ++{ ++ while(*s && *s != ' ' && *s != '\t') s++; ++ ++ return s; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void chop_line(char *s) ++{ ++ int i = strlen(s); ++ ++ if(!i) return; ++ ++ while(--i >= 0) { ++ if(s[i] == ' ' || s[i] == '\t' || s[i] == '\n') { ++ s[i] = 0; ++ } ++ else { ++ break; ++ } ++ } ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int atoi(char *s) ++{ ++ int i = 0, sign = 1; ++ ++ if(*s == '-') s++, sign = -1; ++ if(*s == '+') s++; ++ ++ while(*s >= '0' && *s <= '9') { ++ i = 10 * i + *s++ - '0'; ++ } ++ ++ return sign * i; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// config file name (32 bit address) ++// ++uint32_t get_config_file_name32() ++{ ++ x86regs_t r; ++ ++ r.eax = 0x0e; // Get configuration file name ++ x86int(0x22, &r); ++ ++ return (r.es << 4) + (uint16_t) r.ebx; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Read and parse syslinux config file. ++// ++// return: ++// 0: ok, 1: error ++// ++int read_config_file(void) ++{ ++ char *s, *t, buf[MAX_CONFIG_LINE_LEN]; ++ unsigned u; ++ int menu_idx = 0; ++ ++ // clear memory before we start ++ memset32(menu_buf, 0, menu_buf_len); ++ ++ if(open32(get_config_file_name32()) == -1) return 1; ++ ++ while((s = fgets(buf, sizeof buf))) { ++ chop_line(s); ++ s = skip_spaces(s); ++ if(!*s || *s == '#') continue; ++ t = skip_nonspaces(s); ++ if(*t) *t++ = 0; ++ t = skip_spaces(t); ++ ++ if(!strcmp(s, "timeout")) { ++ timeout = atoi(t); ++ } ++ ++ if(!strcmp(s, "default")) { ++ u = strlen(t); ++ if(u > MENU_LABEL_SIZE - 1) u = MENU_LABEL_SIZE - 1; ++ memcpy32(menu_buf, comboot + (uint32_t) t, u); ++ } ++ ++ if(!strcmp(s, "label")) { ++ menu_idx++; ++ if(menu_idx < MAX_MENU_ENTRIES) { ++ u = strlen(t); ++ if(u > MENU_LABEL_SIZE - 1) u = MENU_LABEL_SIZE - 1; ++ memcpy32( ++ menu_buf + menu_idx * MENU_LABEL_SIZE, ++ comboot + (uint32_t) t, ++ u ++ ); ++ } ++ } ++ ++ if(!strcmp(s, "append")) { ++ if(menu_idx < MAX_MENU_ENTRIES) { ++ u = strlen(t); ++ if(u > MENU_ARG_SIZE - 1) u = MENU_ARG_SIZE - 1; ++ memcpy32( ++ menu_buf + menu_idx * MENU_ARG_SIZE + MAX_MENU_ENTRIES * MENU_LABEL_SIZE, ++ comboot + (uint32_t) t, ++ u ++ ); ++ } ++ } ++ } ++ ++ menu.entries = menu_idx; ++ menu.label_size = MENU_LABEL_SIZE; ++ menu.arg_size = MENU_ARG_SIZE; ++ menu.default_entry = ((menu_buf >> 4) << 16) + (menu_buf & 0xf); ++ u = menu_buf + MENU_LABEL_SIZE; ++ menu.label_list = ((u >> 4) << 16) + (u & 0xf); ++ u = menu_buf + MAX_MENU_ENTRIES * MENU_LABEL_SIZE + MENU_ARG_SIZE; ++ menu.arg_list = ((u >> 4) << 16) + (u & 0xf); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Check header and return code start offset. ++// ++// Note: buf is 32bit address ++// ++unsigned magic_ok(uint32_t buf) ++{ ++ if( ++ _mem32(buf) == 0x0b2d97f00 && /* magic id */ ++ (_mem8(buf + 4) == 8) /* version 8 */ ++ ) { ++ return _mem32(buf + 8); ++ } ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// Search cpio archive for gfx file. ++// ++// Note: buf is 32bit address ++// ++unsigned find_file(uint32_t buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len) ++{ ++ unsigned i, fname_len, code_start = 0; ++ ++ *gfx_file_start = 0; ++ ++ for(i = 0; i < len;) { ++ if((len - i) >= 0x1a && _mem16(buf + i) == 0x71c7) { ++ fname_len = _mem16(buf + i + 20); ++ *file_len = _mem16(buf + i + 24) + (_mem16(buf + i + 22) << 16); ++ i += 26 + fname_len; ++ i = ((i + 1) & ~1); ++ if((code_start = magic_ok(buf + i))) { ++ *gfx_file_start = i; ++ return code_start; ++ } ++ i += *file_len; ++ i = ((i + 1) & ~1); ++ } ++ else { ++ break; ++ } ++ } ++ ++ return code_start; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void gfx_cb(x86regs_t *r) ++{ ++ uint8_t f_nr = r->eax; ++ ++ switch(f_nr) { ++ case 0: // cb_status ++ // edx = filename buffer (64 bytes) ++ r->edx = comboot + (uint32_t) gfx.fname_buf; ++ r->eax = 0; ++ // printf("<0x%x, %p + 0x%x>", r->edx, gfx.fname_buf, comboot); ++ break; ++ ++ case 1: // cb_fopen ++ // file name in gfx.fname_buf ++ // al = 0: ok, 1: file not found ++ // ecx = file length (al = 0) ++ if(open(gfx.fname_buf) == -1) { ++ r->eax = 1; ++ } ++ else { ++ r->eax = 0; ++ r->ecx = fd.file_size; ++ } ++ break; ++ ++ case 2: // cb_fread ++ // edx = buffer address (linear) ++ // ecx = data length (< 64k) ++ if(!fd.handle) { ++ r->eax = r->ecx = 0; ++ break; ++ } ++ r->esi = fd.handle; ++ r->ebx = 0; ++ r->es = io_buf >> 4; ++ r->ecx = io_buf_len / fd.block_size; ++ r->eax = 7; ++ x86int(0x22, r); ++ fd.handle = r->esi; ++ if((r->eflags & X86_CF)) { ++ r->eax = 1; ++ } ++ else { ++ r->edx = io_buf; ++ r->eax = 0; ++ } ++ break; ++ ++ case 3: // cb_getcwd ++ // edx filename ++ r->eax = 0x1f; // Get current working directory ++ x86int(0x22, r); ++ r->edx = (r->es << 4) + (uint16_t) r->ebx; ++ r->eax = 0; ++ break; ++ ++ case 4: // cb_chdir ++ r->es = comboot >> 4; ++ r->ebx = (uint32_t) gfx.fname_buf; ++ r->eax = 0x25; // Get current working directory ++ x86int(0x22, r); ++ r->eax = (r->eflags & X86_CF) ? 1 : 0; ++ break; ++ ++ case 5: // cb_readsector ++ // in: edx = sector ++ // out: edx = buffer (linear address) ++ r->esi = r->edi = 0; ++ r->ebx = 0; ++ r->es = io_buf >> 4; ++ r->ecx = 1; ++ r->eax = 0x19; // Read disk ++ x86int(0x22, r); ++ r->eax = 0; ++ r->edx = io_buf; ++ break; ++ ++ case 6: // cb_mount ++ r->eax = 0x26; ++ x86int(0x22, r); ++ r->eax = (r->eflags & X86_CF) ? 1 : 0; ++ break; ++ ++ default: ++ r->eax = 0xff; ++ } ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// 0: ok, 1: error ++// ++int get_mem_info(mem_info_t *mi) ++{ ++ x86regs_t r; ++ ++ mi->base = mi->len = mi->type = 0; ++ ++ r.eax = 0xe820; ++ r.edx = 0x534d4150; ++ r.ebx = mi->cont; ++ r.ecx = 20; ++ r.es = comboot >> 4; ++ r.edi = (unsigned) mi; ++ x86int(0x15, &r); ++ ++ mi->cont = 0; ++ if(r.eax != 0x534d4150 || (r.eflags & X86_CF)) return 1; ++ mi->cont = r.ebx; ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// 0: ok, 1: error ++// ++int gfx_init(char *file) ++{ ++ x86regs_t r; ++ int file_max, file_size, ofs; ++ unsigned u, code_start, file_start = 0, file_len = 0; ++ unsigned start2, len2, end2; ++ mem_info_t mi; ++ ++ gfx_config.mem0_start = freemem; ++ gfx_config.mem0_end = freemem + freemem_len; ++ ++ kernel_start = (GFX_MEMORY_START + GFX_MEMORY_SIZE) << 20; ++ initrd_end = 0; ++ ++ gfx_config.xmem_0 = (GFX_MEMORY_START << 4) + GFX_MEMORY_SIZE; ++ ++ r.eax = 0x28; // Get memory size ++ x86int(0x22, &r); ++ u = (r.eflags & X86_CF) ? 0 : r.eax; ++ ++ // round up ++ gfx_config.bios_mem_size = u ? ((u + 0xfffff) >> 20) << 20 : 256; ++ ++ if(u > 0) { ++ // new interface ++ ++ if(u < INITRD_MIN_MEMORY << 20) { ++ // ok, maybe there is a bigger block... ++ ++ mi.cont = 0; ++ start2 = len2 = 0; ++ while(!get_mem_info(&mi)) { ++#if 0 ++ printf( ++ "%08x%08x %08x%08x %08x %08x\n", ++ (unsigned) (mi.base >> 32), (unsigned) mi.base, ++ (unsigned) (mi.len >> 32), (unsigned) mi.len, ++ mi.type, mi.cont ++ ); ++#endif ++ if(mi.type == 1) { ++ if((mi.base >> 32) || (mi.base + mi.len) >> 32) break; ++ if(mi.len > len2) { ++ start2 = mi.base; ++ len2 = mi.len; ++ } ++ } ++ ++ if(!mi.cont) break; ++ } ++ ++#if 0 ++ printf("largest: %08x %08x\n", start2, len2); ++ getchar(); ++#endif ++ ++ if(len2 && len2 > 2 << 20 && len2 > u) { ++ // align to full MBs ++ end2 = (start2 + len2) & ~0xfffff; ++ start2 = (start2 + 0xfffff) & ~0xfffff; ++ len2 = end2 - start2; ++ } ++ else { ++ start2 = len2 = 0; ++ } ++ ++ if(len2) { ++ u = len2; ++ initrd_end = end2; ++ // we could relocate the kernel as well... ++ // kernel_start = start2; ++ } ++ } ++ ++ if(u < INITRD_MIN_MEMORY << 20) { ++ // a bit too small for us ++ printf("%u MB RAM is a bit small... - giving up\n", u >> 20); ++ ++ return 1; ++ } ++ } ++ ++#if 0 ++ printf("mem = 0x%05x, mem0_start = 0x%05x, mem0_end = 0x%05x\n", ++ gfx.mem, gfx_config.mem0_start, gfx_config.mem0_end ++ ); ++#endif ++ ++ if(open(file) == -1) return 1; ++ ++ // leave room for later alignment ++ gfx_config.archive_start = gfx_config.mem0_start + 0x10; ++ ++ // read at most that much ++ file_size = file_max = gfx_config.mem0_end - gfx_config.archive_start; ++ ++ if(fd.file_size != -1 && fd.file_size > file_size) return 1; ++ ++ // if we have the real size, use it ++ if(fd.file_size != -1) file_size = fd.file_size; ++ ++ file_size = read32(gfx_config.archive_start, file_size); ++ ++ if(!file_size || file_size == file_max) return 1; ++ ++ gfx_config.archive_end = gfx_config.archive_start + file_size; ++ ++ // update free mem pointer & align it a bit ++ gfx_config.mem0_start = (gfx_config.archive_end + 3) & ~3; ++ ++ // locate file inside cpio archive ++ if(!(code_start = find_file(gfx_config.archive_start, file_size, &file_start, &file_len))) { ++ printf("%s: invalid file format\n", file); ++ ++ return 1; ++ } ++ ++#if 0 ++ printf("code_start = 0x%x, archive_start = 0x%x, file size = 0x%x, file_start = 0x%x, file_len = 0x%x\n", ++ code_start, gfx_config.archive_start, file_size, file_start, file_len ++ ); ++#endif ++ ++ if((ofs = (gfx_config.archive_start + file_start + code_start) & 0xf)) { ++ printf("oops: needs to be aligned!\n"); ++ ++ memcpy32(gfx_config.archive_start - ofs, gfx_config.archive_start, file_size); ++ gfx_config.archive_start -= ofs; ++ gfx_config.archive_end -= ofs; ++ ++ return 1; ++ } ++ ++ gfx_config.file = gfx_config.archive_start + file_start; ++ gfx.code_seg = (gfx_config.file + code_start) >> 4; ++ ++ for(u = 0; u < sizeof gfx.jmp_table / sizeof *gfx.jmp_table; u++) { ++ gfx.jmp_table[u] = (gfx.code_seg << 16) + _mem16(gfx_config.file + code_start + 2 * u); ++ } ++ ++#if 0 ++ for(u = 0; u < sizeof gfx.jmp_table / sizeof *gfx.jmp_table; u++) { ++ printf("%d: 0x%08x\n", u, gfx.jmp_table[u]); ++ } ++#endif ++ ++ // we are ready to start ++ ++ r.esi = comboot + (uint32_t) &gfx_config; ++ farcall(gfx.jmp_table[GFX_BC_INIT], &r); ++ ++ if((r.eflags & X86_CF)) { ++ printf("graphics initialization failed\n"); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void gfx_done() ++{ ++ x86regs_t r; ++ ++ farcall(gfx.jmp_table[GFX_BC_DONE], &r); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// ++// return: ++// boot menu index (-1: go to text mode prompt) ++// ++int gfx_input() ++{ ++ x86regs_t r; ++ ++ r.edi = comboot + (uint32_t) cmdline; ++ r.ecx = sizeof cmdline; ++ r.eax = timeout * 182 / 100; ++ timeout = 0; // use timeout only first time ++ farcall(gfx.jmp_table[GFX_BC_INPUT], &r); ++ if((r.eflags & X86_CF)) r.eax = 1; ++ ++ if(r.eax == 1) return -1; ++ ++ return r.ebx; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int gfx_menu_init() ++{ ++ x86regs_t r; ++ ++ r.esi = comboot + (uint32_t) &menu; ++ farcall(gfx.jmp_table[GFX_BC_MENU_INIT], &r); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void gfx_infobox(int type, char *str1, char *str2) ++{ ++ gfx_infobox32(type, comboot + (uint32_t) str1, str2 ? comboot + (uint32_t) str2 : 0); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void gfx_infobox32(int type, uint32_t str1, uint32_t str2) ++{ ++ x86regs_t r; ++ ++ r.eax = type; ++ r.esi = str1; ++ r.edi = str2; ++ farcall(gfx.jmp_table[GFX_BC_INFOBOX_INIT], &r); ++ r.edi = r.eax = 0; ++ farcall(gfx.jmp_table[GFX_BC_INPUT], &r); ++ farcall(gfx.jmp_table[GFX_BC_INFOBOX_DONE], &r); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Load & run kernel. ++// ++// Returns only on error. ++// ++void boot() ++{ ++ x86regs_t r; ++ ++ r.es = comboot >> 4; ++ r.ebx = (uint32_t) cmdline; ++ r.edi = kernel_start; // kernel load address ++ r.edx = initrd_end; // end of initrd load area (or 0) ++ r.esi = (uint32_t) _syslinux_hook; // cs:si = syslinux callbacks ++ r.eax = 0x27; // Load & run kernel (extended API) ++ ++ x86int(0x22, &r); ++ if(!(r.eflags & X86_CF)) return; ++ ++ r.es = comboot >> 4; ++ r.ebx = (uint32_t) cmdline; ++ r.eax = 3; // Run command ++ x86int(0x22, &r); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void syslinux_hook(x86regs_t *r) ++{ ++ uint8_t f_nr = r->eax; ++ ++ // bit 7: 0/1 continue/don't continue kernel loading in syslinux ++ ++ switch(f_nr & 0x7f) { ++ case 0: // abort kernel/initrd loading ++ gfx_infobox(0, "abort kernel loading", 0); ++ break; ++ ++ case 1: // kernel/initrd not found ++ gfx_infobox(0, "kernel not found: ", current_label); ++ break; ++ ++ case 2: // kernel corrupt ++ gfx_infobox(0, "kernel broken", 0); ++ break; ++ ++ case 3: // out of memory (while initrd loading) ++ gfx_infobox(0, "out of memory", 0); ++ break; ++ ++ case 4: // progress start ++ r->eax = r->ecx >> gfx_config.sector_shift; // kernel size in sectors ++ r->esi = comboot + (uint32_t) current_label; ++ farcall(gfx.jmp_table[GFX_BC_PROGRESS_INIT], r); ++ break; ++ ++ case 5: // progress increment ++ // always 64k ++ r->eax = 0x10000 >> gfx_config.sector_shift; ++ farcall(gfx.jmp_table[GFX_BC_PROGRESS_UPDATE], r); ++ break; ++ ++ case 6: // progress end: kernel loaded, stop gfxboot ++ farcall(gfx.jmp_table[GFX_BC_PROGRESS_DONE], r); ++ gfx_done(); ++ break; ++ ++ case 7: // stop gfxboot ++ gfx_done(); ++ break; ++ } ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void show_message(char *file) ++{ ++ int c; ++ ++ if(open(file) == -1) return; ++ ++ while((c = getc()) != EOF) { ++ if(c < ' ' && c != '\n' && c != '\t') continue; ++ printf("%c", c); ++ } ++} ++ ++ +diff --git a/modules/libio.asm b/modules/libio.asm +new file mode 100644 +index 0000000..1f77b44 +--- /dev/null ++++ b/modules/libio.asm +@@ -0,0 +1,854 @@ ++; ++; libio.asm ++; ++; A very minimalistic libc fragment. ++; ++; Copyright (c) 2009 Steffen Winterfeldt. ++; ++; 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. ++; ++ ++ ++; max argv elements passed to main() ++%define MAX_ARGS 8 ++ ++ ++ bits 16 ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; interface functions ++; ++; Make sure not to modify registers! ++; ++ ++ global printf ++ global getchar ++ global clrscr ++ global memcpy ++ global memcpy32 ++ global memset ++ global memset32 ++ global x86int ++ global farcall ++ global reboot ++ ++ global _gfx_cb ++ extern gfx_cb ++ global _syslinux_hook ++ extern syslinux_hook ++ ++ global _start ++ extern _main ++ ++ extern __bss_start ++ ++ section .init ++ ++_start: ++ cld ++ ++ ; clear static memory ++ mov di,__bss_start ++ mov cx,sp ++ sub cx,di ++ xor ax,ax ++ rep stosb ++ ++ ; parse args ++ mov ebx,80h ++ movzx si,byte [bx] ++ mov byte [si+81h],0dh ; just make sure ++ xor ecx,ecx ++ sub sp,MAX_ARGS * 4 ++ mov ebp,esp ++ inc cx ++cmd_10: ++ inc bx ++ call skip_spaces ++ cmp al,0dh ++ jz cmd_60 ++ imul si,cx,4 ++ mov [bp+si],ebx ++ call skip_nonspaces ++ mov byte [bx],0 ++ inc cx ++ cmp cx,MAX_ARGS ++ jae cmd_60 ++ cmp al,0dh ++ jnz cmd_10 ++cmd_60: ++ mov byte [bx],0 ++ ++ mov [bp],ebx ; argv[0] = "" ++ ++ push ebp ++ push ecx ++ ++ call dword _main ++ ++ add sp,MAX_ARGS * 4 + 8 ++ ++ ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++skip_spaces: ++ mov al,[bx] ++ cmp al,0dh ++ jz skip_spaces_90 ++ cmp al,' ' ++ jz skip_spaces_10 ++ cmp al,9 ++ jnz skip_spaces_90 ++skip_spaces_10: ++ inc bx ++ jmp skip_spaces ++skip_spaces_90: ++ ret ++ ++skip_nonspaces: ++ mov al,[bx] ++ cmp al,0dh ++ jz skip_nonspaces_90 ++ cmp al,' ' ++ jz skip_nonspaces_90 ++ cmp al,9 ++ jz skip_nonspaces_90 ++ inc bx ++ jmp skip_nonspaces ++skip_nonspaces_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ section .text ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Write text to console. ++; ++; args on stack ++; ++; Note: 32 bit call/ret! ++; ++printf: ++ mov [pf_args],sp ++ ++ pushad ++ ++ call pf_next_arg ++ call pf_next_arg ++ mov si,ax ++printf_10: ++ lodsb ++ or al,al ++ jz printf_90 ++ cmp al,'%' ++ jnz printf_70 ++ mov byte [pf_pad],' ' ++ lodsb ++ dec si ++ cmp al,'0' ++ jnz printf_20 ++ mov [pf_pad],al ++printf_20: ++ call get_number ++ mov [pf_num],ecx ++ lodsb ++ or al,al ++ jz printf_90 ++ cmp al,'%' ++ jz printf_70 ++ ++ cmp al,'S' ++ jnz printf_23 ++ mov byte [pf_raw_char],1 ++ jmp printf_24 ++printf_23: ++ cmp al,'s' ++ jnz printf_30 ++printf_24: ++ push si ++ ++ call pf_next_arg ++ mov si,ax ++ call puts ++ ++ sub ecx,[pf_num] ++ neg ecx ++ mov al,' ' ++ call putc_n ++ ++ pop si ++ ++ mov byte [pf_raw_char],0 ++ jmp printf_10 ++ ++printf_30: ++ cmp al,'u' ++ jnz printf_35 ++ ++ mov dx,10 ++printf_31: ++ push si ++ ++ call pf_next_arg ++ or dh,dh ++ jz printf_34 ++ test eax,eax ++ jns printf_34 ++ neg eax ++ push eax ++ mov al,'-' ++ call putc ++ pop eax ++printf_34: ++ mov cl,[pf_num] ++ mov ch,[pf_pad] ++ call number ++ call puts ++ ++ pop si ++ ++ jmp printf_10 ++ ++printf_35: ++ cmp al,'x' ++ jnz printf_36 ++ ++printf_35a: ++ mov dx,10h ++ jmp printf_31 ++ ++printf_36: ++ cmp al,'d' ++ jnz printf_37 ++printf_36a: ++ mov dx,10ah ++ jmp printf_31 ++ ++printf_37: ++ cmp al,'i' ++ jz printf_36a ++ ++ cmp al,'p' ++ jnz printf_40 ++ mov al,'0' ++ call putc ++ mov al,'x' ++ call putc ++ jmp printf_35a ++ ++printf_40: ++ cmp al,'c' ++ jnz printf_45 ++ ++ push si ++ call pf_next_arg ++ call putc ++ pop si ++ jmp printf_10 ++printf_45: ++ ++ ; more ... ++ ++ ++printf_70: ++ call putc ++ jmp printf_10 ++printf_90: ++ popad ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Get next printf arg from [pf_args]. ++; ++; return: ++; eax arg ++; ++; changes no regs ++; ++pf_next_arg: ++ movzx eax,word [pf_args] ++ add word [pf_args],4 ++ mov eax,[eax] ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Convert string to number. ++; ++; si string ++; ++; return: ++; ecx number ++; si points past number ++; CF not a number ++; ++get_number: ++ ++ xor ecx,ecx ++ mov ah,1 ++get_number_10: ++ lodsb ++ or al,al ++ jz get_number_90 ++ sub al,'0' ++ jb get_number_90 ++ cmp al,9 ++ ja get_number_90 ++ movzx eax,al ++ imul ecx,ecx,10 ++ add ecx,eax ++ jmp get_number_10 ++get_number_90: ++ dec si ++ shr ah,1 ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Convert a number to string. ++; ++; eax number ++; cl field size ++; ch padding char ++; dl base ++; ++; return: ++; si string ++; ++number: ++ mov di,num_buf ++ push ax ++ push cx ++ mov al,ch ++ mov cx,num_buf_end - num_buf ++ rep stosb ++ pop cx ++ pop ax ++ movzx cx,cl ++ movzx ebx,dl ++number_10: ++ xor edx,edx ++ div ebx ++ cmp dl,9 ++ jbe number_20 ++ add dl,27h ++number_20: ++ add dl,'0' ++ dec edi ++ mov [di],dl ++ or eax,eax ++ jz number_30 ++ cmp di,num_buf ++ ja number_10 ++number_30: ++ mov si,di ++ or cx,cx ++ jz number_90 ++ cmp cx,num_buf_end - num_buf ++ jae number_90 ++ mov si,num_buf_end ++ sub si,cx ++number_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Write string. ++; ++; si text ++; ++; return: ++; cx length ++; ++puts: ++ xor cx,cx ++puts_10: ++ lodsb ++ or al,al ++ jz puts_90 ++ call putc ++ inc cx ++ jmp puts_10 ++puts_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Write char multiple times. ++; ++; al char ++; cx count (does nothing if count <= 0) ++; ++putc_n: ++ cmp cx,0 ++ jle putc_n_90 ++ call putc ++ dec cx ++ jmp putc_n ++putc_n_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Print char. ++; ++; al char ++; ++putc: ++ pusha ++ cmp al,0ah ++ jnz putc_30 ++ push ax ++ mov al,0dh ++ call putc_50 ++ pop ax ++putc_30: ++ call putc_50 ++ popa ++ ret ++putc_50: ++ mov bx,7 ++ mov ah,0eh ++ int 10h ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Read char from stdin. ++; ++; return: ++; eax char ++; ++; Note: 32 bit call/ret! ++; ++getchar: ++ pushad ++ mov ah,10h ++ int 16h ++ mov [gc_tmp],al ++ popad ++ movzx eax,byte [gc_tmp] ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Clear screen. ++; ++; Note: 32 bit call/ret! ++; ++clrscr: ++ pushad ++ push es ++ push word 40h ++ pop es ++ mov ax,600h ++ mov bh,7 ++ xor cx,cx ++ mov dl,[es:4ah] ++ or dl,dl ++ jnz clrscr_20 ++ mov dl,80 ++clrscr_20: ++ dec dl ++ mov dh,[es:84h] ++ or dh,dh ++ jnz clrscr_30 ++ mov dh,24 ++clrscr_30: ++ int 10h ++ mov ah,2 ++ mov bh,[es:62h] ++ xor dx,dx ++ int 10h ++ pop es ++ popad ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; dst = memcpy(dst, src, size). ++; ++; args on stack ++; ++; return: ++; eax dst ++; ++; Note: 32 bit call/ret! ++; ++memcpy: ++ pushad ++ ++ mov edi,[esp+0x20+4] ++ mov esi,[esp+0x20+8] ++ mov ecx,[esp+0x20+12] ++ ++ rep movsb ++ ++ popad ++ ++ mov eax,[esp+4] ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; dst = memset(dst, val, size). ++; ++; args on stack ++; ++; return: ++; eax dst ++; ++; Note: 32 bit call/ret! ++; ++memset: ++ pushad ++ ++ mov edi,[esp+0x20+4] ++ mov al,[esp+0x20+8] ++ mov ecx,[esp+0x20+12] ++ ++ rep stosb ++ ++ popad ++ ++ mov eax,[esp+4] ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; dst = memset32(dst, val, size). ++; ++; args on stack ++; ++; return: ++; eax dst ++; ++; Note: 32 bit call/ret! ++; ++memset32: ++ pushad ++ ++ push es ++ ++ mov ebx,[esp+0x22+4] ; edi ++ mov al,[esp+0x22+8] ++ mov edx,[esp+0x22+12] ++ ++memset32_20: ++ mov edi,ebx ++ mov ecx,ebx ++ and di,0fh ++ shr ecx,4 ++ mov es,cx ++ ++ mov ecx,0fff0h ++ cmp edx,ecx ++ ja memset32_40 ++ mov ecx,edx ++memset32_40: ++ add ebx,ecx ++ sub edx,ecx ++ ++ rep stosb ++ ++ jnz memset32_20 ++ ++ pop es ++ ++ popad ++ ++ mov eax,[esp+4] ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; dst = memcpy32(dst, src, size). ++; ++; dst, src are 32bit linear addresses ++; ++; args on stack ++; ++; return: ++; eax dst ++; ++; Note: 32 bit call/ret! ++; ++memcpy32: ++ pushad ++ ++ push ds ++ push es ++ ++ mov ebx,[esp+0x24+4] ; edi ++ mov eax,[esp+0x24+8] ; esi ++ mov edx,[esp+0x24+12] ++ ++memcpy32_20: ++ mov edi,ebx ++ mov ecx,ebx ++ and di,0fh ++ shr ecx,4 ++ mov es,cx ++ ++ mov esi,eax ++ mov ecx,eax ++ and si,0fh ++ shr ecx,4 ++ mov ds,cx ++ ++ mov ecx,0fff0h ++ cmp edx,ecx ++ ja memcpy32_40 ++ mov ecx,edx ++memcpy32_40: ++ add ebx,ecx ++ add eax,ecx ++ sub edx,ecx ++ ++ rep movsb ++ ++ jnz memcpy32_20 ++ ++ pop es ++ pop ds ++ ++ popad ++ ++ mov eax,[esp+4] ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; x86int(int, *regs). ++; ++; args on stack ++; ++; Note: 32 bit call/ret! ++; ++x86int: ++ pushad ++ ++ mov al,[esp+0x20+4] ++ mov [x86int_p],al ++ mov ebx,[esp+0x20+8] ++ ++ mov ecx,[bx+8] ++ mov edx,[bx+0ch] ++ mov esi,[bx+10h] ++ mov edi,[bx+14h] ++ mov ebp,[bx+18h] ++ mov ah,[bx+1ch] ; eflags ++ sahf ++ mov eax,[bx] ++ ++ mov es,[bx+22h] ++ mov fs,[bx+24h] ++ mov gs,[bx+26h] ++ mov ds,[bx+20h] ++ ++ mov ebx,[cs:bx+4] ++ ++ int 0h ++x86int_p equ $-1 ++ ++ push ebx ++ mov ebx,[esp+0x24+8] ++ pop dword [cs:bx+4] ++ ++ mov [cs:bx],eax ++ mov [cs:bx+20h],ds ++ ++ mov ax,cs ++ mov ds,ax ++ ++ mov [cs:bx+22h],es ++ mov [cs:bx+24h],fs ++ mov [cs:bx+26h],gs ++ ++ mov es,ax ++ mov fs,ax ++ mov gs,ax ++ ++ mov [bx+8],ecx ++ mov [bx+0ch],edx ++ mov [bx+10h],esi ++ mov [bx+14h],edi ++ mov [bx+18h],ebp ++ pushfd ++ pop dword [bx+1ch] ++ ++ popad ++ ++ o32 ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; farcall(addr, *regs). ++; ++; args on stack ++; ++; Note: 32 bit call/ret! ++; ++farcall: ++ pushad ++ ++ mov ebx,[esp+0x20+8] ++ ++ mov ecx,[bx+8] ++ mov edx,[bx+0ch] ++ mov esi,[bx+10h] ++ mov edi,[bx+14h] ++ mov ebp,[bx+18h] ++ mov ah,[bx+1ch] ; eflags ++ sahf ++ mov eax,[bx] ++ ++ mov [farcall_stack],sp ++ sub word [farcall_stack],1000h ; 4k stack should be enough for gfxboot ++ mov [farcall_stack+2],ss ++ ++ mov es,[bx+22h] ++ mov fs,[bx+24h] ++ mov gs,[bx+26h] ++ mov ds,[bx+20h] ++ ++ mov ebx,[cs:bx+4] ++ ++ call far [esp+0x20+4] ++ ++ push ebx ++ mov ebx,[esp+0x24+8] ++ pop dword [cs:bx+4] ++ ++ mov [cs:bx],eax ++ mov [cs:bx+20h],ds ++ ++ mov ax,cs ++ mov ds,ax ++ ++ mov [cs:bx+22h],es ++ mov [cs:bx+24h],fs ++ mov [cs:bx+26h],gs ++ ++ mov es,ax ++ mov fs,ax ++ mov gs,ax ++ ++ mov [bx+8],ecx ++ mov [bx+0ch],edx ++ mov [bx+10h],esi ++ mov [bx+14h],edi ++ mov [bx+18h],ebp ++ pushfd ++ pop dword [bx+1ch] ++ ++ popad ++ ++ o32 ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; wrapper around gfx_cb() ++; ++; we need to switch stack to ensure ss = cs = ds = es for gcc ++; ++_gfx_cb: ++ push cs ++ pop ds ++ push cs ++ pop es ++ mov [cb_stack],sp ++ mov [cb_stack+2],ss ++ lss sp,[farcall_stack] ++ sub sp,28h ; sizeof x86regs_t ++ mov [esp+18h],ebp ++ mov ebp,esp ++ push ebp ++ mov [bp],eax ++ mov [bp+4],ebx ++ mov [bp+8],ecx ++ mov [bp+0ch],edx ++ mov [bp+10h],esi ++ mov [bp+14h],edi ++ call dword gfx_cb ++ lea ebp,[esp+4] ++ mov eax,[bp] ++ mov ebx,[bp+4] ++ mov ecx,[bp+8] ++ mov edx,[bp+0ch] ++ mov esi,[bp+10h] ++ mov edi,[bp+14h] ++ mov ebp,[bp+18h] ++ lss sp,[cb_stack] ++ retf ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; wrapper around syslinux_hook() ++; ++; ensure cs = ds = es for gcc ++; ++_syslinux_hook: ++ push cs ++ pop ds ++ push cs ++ pop es ++ sub sp,28h ; sizeof x86regs_t ++ mov [esp+18h],ebp ++ mov ebp,esp ++ push ebp ++ mov [bp],eax ++ mov [bp+4],ebx ++ mov [bp+8],ecx ++ mov [bp+0ch],edx ++ mov [bp+10h],esi ++ mov [bp+14h],edi ++ call dword syslinux_hook ++ lea ebp,[esp+4] ++ mov eax,[bp] ++ mov ebx,[bp+4] ++ mov ecx,[bp+8] ++ mov edx,[bp+0ch] ++ mov esi,[bp+10h] ++ mov edi,[bp+14h] ++ mov ebp,[bp+18h] ++ add sp,28h+4 ++ retf ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++reboot: ++ mov word [472h],1234h ++ jmp 0ffffh:0 ++ int 19h ++ jmp $ ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ section .data ++ ++farcall_stack dd 0 ++cb_stack dd 0 ++ ++; buffer for number conversions ++; must be large enough for ps_status_info() ++num_buf times 23h db 0 ++num_buf_end db 0 ++ ++; temp data for printf ++pf_args dw 0 ++pf_num dd 0 ++pf_sig db 0 ++pf_pad db 0 ++pf_raw_char db 0 ++gc_tmp db 0 ++ +diff --git a/modules/libio.h b/modules/libio.h +new file mode 100644 +index 0000000..16af520 +--- /dev/null ++++ b/modules/libio.h +@@ -0,0 +1,133 @@ ++/* ++ * ++ * libio.h include file for libio ++ * ++ * Copyright (c) 2009 Steffen Winterfeldt. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef _LIBIO_H ++#define _LIBIO_H ++ ++ ++asm(".code16gcc\n"); ++ ++ ++#define int8_t char ++#define int16_t short ++#define int32_t int ++#define int64_t long long ++#define uint8_t unsigned char ++#define uint16_t unsigned short ++#define uint32_t unsigned ++#define uint64_t unsigned long long ++ ++#define X86_CF 0x0001 ++#define X86_PF 0x0004 ++#define X86_AF 0x0010 ++#define X86_ZF 0x0040 ++#define X86_SF 0x0080 ++#define X86_TF 0x0100 ++#define X86_IF 0x0200 ++#define X86_DF 0x0400 ++#define X86_OF 0x0800 ++ ++#define EOF -1 ++ ++#define main _main ++ ++ ++typedef struct __attribute ((packed)) { ++ uint32_t eax, ebx, ecx, edx, esi, edi, ebp, eflags; ++ uint16_t ds, es, fs, gs; ++} x86regs_t; ++ ++ ++static inline uint16_t comboot_seg(void) ++{ ++ uint16_t u; ++ ++ asm("mov %%cs, %0" : "=r" (u)); ++ ++ return u; ++} ++ ++ ++static inline uint8_t _mem8(uint32_t p) ++{ ++ uint8_t u; ++ ++ asm( ++ "movl %1,%%esi\n" ++ "shrl $4,%%esi\n" ++ "mov %%si,%%fs\n" ++ "movl %1,%%esi\n" ++ "and $15, %%si\n" ++ "movb %%fs:(%%si),%0\n" ++ : "=abcd" (u) : "r" (p) : "si" ++ ); ++ ++ return u; ++} ++ ++ ++static inline uint16_t _mem16(uint32_t p) ++{ ++ uint16_t u; ++ ++ asm( ++ "movl %1,%%esi\n" ++ "shrl $4,%%esi\n" ++ "mov %%si,%%fs\n" ++ "movl %1,%%esi\n" ++ "and $15, %%si\n" ++ "movw %%fs:(%%si),%0\n" ++ : "=r" (u) : "r" (p) : "si" ++ ); ++ ++ return u; ++} ++ ++ ++static inline uint32_t _mem32(uint32_t p) ++{ ++ uint32_t u; ++ ++ asm( ++ "movl %1,%%esi\n" ++ "shrl $4,%%esi\n" ++ "mov %%si,%%fs\n" ++ "movl %1,%%esi\n" ++ "and $15, %%si\n" ++ "movl %%fs:(%%si),%0\n" ++ : "=r" (u) : "r" (p) : "si" ++ ); ++ ++ return u; ++} ++ ++ ++int _main(int argc, char **argv); ++void printf(char *format, ...) __attribute__ ((format (printf, 1, 2))); ++int getchar(void); ++void clrscr(void); ++void *memcpy(void *dest, const void *src, int n); ++uint32_t memcpy32(uint32_t dest, uint32_t src, int n); ++void *memset(void *dest, int c, int n); ++uint32_t memset32(uint32_t dest, int c, int n); ++void x86int(unsigned intr, x86regs_t *regs); ++void farcall(uint32_t seg_ofs, x86regs_t *regs); ++void gfx_cb(x86regs_t *r); ++void _gfx_cb(void); ++void syslinux_hook(x86regs_t *r); ++void _syslinux_hook(void); ++void reboot(void); ++ ++#endif /* _LIBIO_H */ ++ diff --git a/syslinux.changes b/syslinux.changes index 7289329..b2626c7 100644 --- a/syslinux.changes +++ b/syslinux.changes @@ -1,8 +1,3 @@ -------------------------------------------------------------------- -Tue Apr 27 17:33:10 CEST 2010 - snwint@suse.de - -- drop obsolete gfxboot.com - ------------------------------------------------------------------- Mon Apr 19 15:41:01 CEST 2010 - snwint@suse.de diff --git a/syslinux.spec b/syslinux.spec index 75905ee..1b2ed91 100644 --- a/syslinux.spec +++ b/syslinux.spec @@ -60,7 +60,6 @@ Authors: cp %{SOURCE2} . export CFLAGS="$RPM_OPT_FLAGS" chmod +x core/add_crc -rm -f modules/gfxboot.com make spotless make