diff options
author | Daniel Baumann <mail@daniel-baumann.ch> | 2014-02-08 07:45:50 -0800 |
---|---|---|
committer | Daniel Baumann <mail@daniel-baumann.ch> | 2014-02-08 07:45:50 -0800 |
commit | 10177fb8fe31b38d78cbf299addf0f6bd0f08c86 (patch) | |
tree | 4fecc8217000b83d88b0bc813f199174a392d64e /patches |
Import gfxboot_4.5.2-1.1.orig.tar.xz
[dgit import orig gfxboot_4.5.2-1.1.orig.tar.xz]
Diffstat (limited to 'patches')
28 files changed, 11520 insertions, 0 deletions
diff --git a/patches/gfxboot_c32.diff b/patches/gfxboot_c32.diff new file mode 100644 index 0000000..4dae3ea --- /dev/null +++ b/patches/gfxboot_c32.diff @@ -0,0 +1,1080 @@ +diff --git a/Makefile b/Makefile +index 76abff5..c964e8d 100644 +--- a/Makefile ++++ b/Makefile +@@ -32,7 +32,7 @@ include $(topdir)/MCONFIG + # List of module objects that should be installed for all derivatives + MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \ + com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \ +- com32/hdt/*.c32 com32/rosh/*.c32 ++ com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 + + # syslinux.exe is BTARGET so as to not require everyone to have the + # mingw suite installed +diff --git a/com32/Makefile b/com32/Makefile +index 4a58485..69a125e 100644 +--- a/com32/Makefile ++++ b/com32/Makefile +@@ -1,3 +1,3 @@ +-SUBDIRS = lib gpllib libutil modules mboot menu samples rosh cmenu hdt ++SUBDIRS = lib gpllib libutil modules mboot menu samples rosh cmenu hdt gfxboot + all tidy dist clean spotless install: + set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done +diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile +new file mode 100644 +index 0000000..2affcde +--- /dev/null ++++ b/com32/gfxboot/Makefile +@@ -0,0 +1,44 @@ ++## ----------------------------------------------------------------------- ++## ++## Copyright 2001-2009 H. Peter Anvin - All Rights Reserved ++## Copyright 2009 Intel Corporation; author: H. Peter Anvin ++## ++## 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. ++## ++## ----------------------------------------------------------------------- ++ ++topdir = ../.. ++include ../MCONFIG ++ ++MODULES = gfxboot.c32 ++ ++all: $(MODULES) ++ ++gfxboot.elf : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS) ++ $(LD) $(LDFLAGS) -o $@ $^ ++ ++realmode_callback.o: realmode_callback.asm ++ nasm -f bin -O99 -o $*.tmp -l $*.lst $< ++ objcopy -B i386 -I binary -O elf32-i386 \ ++ --redefine-sym _binary_$*_tmp_start=$*_start \ ++ --redefine-sym _binary_$*_tmp_end=$*_end \ ++ --strip-symbol _binary_$*_tmp_size \ ++ $*.tmp $@ ++ ++tidy dist: ++ rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp ++ ++clean: tidy ++ rm -f *.lnx ++ ++spotless: clean ++ rm -f *.lss *.c32 *.com ++ rm -f *~ \#* ++ ++install: ++ ++-include .*.d +diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c +new file mode 100644 +index 0000000..e1b865a +--- /dev/null ++++ b/com32/gfxboot/gfxboot.c +@@ -0,0 +1,806 @@ ++/* ++ * ++ * gfxboot.c ++ * ++ * A com32 module to load gfxboot graphics. ++ * ++ * 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 <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <string.h> ++#include <fcntl.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++ ++#include <syslinux/loadfile.h> ++#include <syslinux/config.h> ++#include <syslinux/linux.h> ++#include <syslinux/boot.h> ++#include <console.h> ++#include <com32.h> ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++#define MAX_CONFIG_LINE_LEN 2048 ++#define MAX_CMDLINE_LEN 2048 ++ ++// buffer for realmode callback ++// must be at least block size; can in theory be larger than 4k, but there's ++// not enough space left ++#define REALMODE_BUF_SIZE 4096 ++ ++// gfxboot working memory in MB ++#define GFX_MEMORY_SIZE 7 ++ ++// read chunk size for progress bar ++#define CHUNK_SIZE (64 << 10) ++ ++// callback function numbers ++#define GFX_CB_INIT 0 ++#define GFX_CB_DONE 1 ++#define GFX_CB_INPUT 2 ++#define GFX_CB_MENU_INIT 3 ++#define GFX_CB_INFOBOX_INIT 4 ++#define GFX_CB_INFOBOX_DONE 5 ++#define GFX_CB_PROGRESS_INIT 6 ++#define GFX_CB_PROGRESS_DONE 7 ++#define GFX_CB_PROGRESS_UPDATE 8 ++#define GFX_CB_PROGRESS_LIMIT 9 // unused ++#define GFX_CB_PASSWORD_INIT 10 ++#define GFX_CB_PASSWORD_DONE 11 ++ ++// real mode code chunk, will be placed into bounce buffer ++extern void realmode_callback_start, realmode_callback_end; ++ ++// gets in the way ++#undef linux ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// gfxboot config data (64 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 serial_port; // 10: syslinux initialized serial port from 'serial' option ++ 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) - obsolete ++ uint16_t xmem_1; // 26: extended mem area 1 - obsolete ++ uint16_t xmem_2; // 28: extended mem area 2 - obsolete ++ uint16_t xmem_3; // 30: extended mem area 3 - obsolete ++ 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 ++ uint32_t xmem_start; // 52: extended mem start ++ uint32_t xmem_end; // 56: extended mem end ++ uint16_t features; // 60: feature flags returned by GFX_CB_INIT ++ // 0: GFX_CB_MENU_INIT accepts 32 bit addresses ++ // 1: knows about xmem_start, xmem_end ++ uint16_t reserved_1; // 62: ++} gfx_config_t; ++ ++ ++// gfxboot menu description (18 bytes) ++typedef struct __attribute__ ((packed)) { ++ uint16_t entries; ++ char *default_entry; ++ char *label_list; ++ uint16_t label_size; ++ char *arg_list; ++ uint16_t arg_size; ++} gfx_menu_t; ++ ++ ++// menu description ++typedef struct menu_s { ++ struct menu_s *next; ++ char *label; ++ char *kernel; ++ char *linux; ++ char *localboot; ++ char *initrd; ++ char *append; ++ char *ipappend; ++} menu_t; ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++gfx_config_t gfx_config; ++gfx_menu_t gfx_menu; ++ ++menu_t *menu; ++menu_t *menu_default; ++ ++struct { ++ uint32_t jmp_table[12]; ++ uint16_t code_seg; ++ char fname_buf[64]; ++} gfx; ++ ++void *lowmem_buf; ++unsigned lowmem_buf_size; ++ ++int timeout; ++ ++char cmdline[MAX_CMDLINE_LEN]; ++ ++void *save_buf; ++unsigned save_buf_size; ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void show_message(char *file); ++char *get_config_file_name(void); ++char *skip_spaces(char *s); ++char *skip_nonspaces(char *s); ++void chop_line(char *s); ++int read_config_file(void); ++unsigned magic_ok(unsigned char *buf, unsigned *code_size); ++unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size); ++int gfx_init(char *file); ++int gfx_menu_init(void); ++void gfx_done(void); ++int gfx_input(void); ++ssize_t save_read(int fd, void *buf, size_t size); ++void *load_one(char *file, ssize_t *file_size); ++void boot(void); ++void boot_entry(menu_t *menu_ptr, char *arg); ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int main(int argc, char **argv) ++{ ++ int menu_index; ++ enum syslinux_filesystem syslinux_id; ++ com32sys_t r; ++ ++ openconsole(&dev_stdcon_r, &dev_stdcon_w); ++ ++ syslinux_id = syslinux_version()->filesystem; ++ ++ lowmem_buf = __com32.cs_bounce; ++ lowmem_buf_size = __com32.cs_bounce_size; ++ ++ r.eax.l = 0x0a; // Get Derivative-Specific Information ++ r.ecx.l = 9; ++ __intcall(0x22, &r, &r); ++ gfx_config.sector_shift = (uint8_t) r.ecx.l; ++ gfx_config.boot_drive = (uint8_t) r.edx.l; ++ ++ if(syslinux_id == SYSLINUX_FS_PXELINUX) { ++ gfx_config.sector_shift = 11; ++ gfx_config.boot_drive = 0; ++ } ++ ++ gfx_config.bootloader = 1; ++ gfx_config.sysconfig_size = sizeof gfx_config; ++ gfx_config.bootloader_seg = 0; // apparently not needed ++ ++ save_buf_size = lowmem_buf_size; ++ save_buf = malloc(save_buf_size); ++ ++ if(argc < 2) { ++ printf("Usage: gfxboot.c32 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; ++ } ++ ++ // does not return if it succeeds ++ boot(); ++ } ++ ++ if(argc > 2) show_message(argv[2]); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void show_message(char *file) ++{ ++ int c; ++ FILE *f; ++ ++ if(!(f = fopen(file, "r"))) return; ++ ++ while((c = getc(f)) != EOF) { ++ if(c < ' ' && c != '\n' && c != '\t') continue; ++ printf("%c", c); ++ } ++ ++ fclose(f); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++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; ++ } ++ } ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Read and parse syslinux config file. ++// ++// return: ++// 0: ok, 1: error ++// ++int read_config_file(void) ++{ ++ FILE *f; ++ char *s, *t, buf[MAX_CONFIG_LINE_LEN]; ++ unsigned u, menu_idx = 0, label_size = 0, append_size = 0; ++ menu_t *menu_ptr = NULL, **menu_next = &menu; ++ ++ menu_default = calloc(1, sizeof *menu_default); ++ ++ if(!(f = fopen(syslinux_config_file(), "r"))) return 1; ++ ++ while((s = fgets(buf, sizeof buf, f))) { ++ 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); ++ continue; ++ } ++ ++ if(!strcmp(s, "default")) { ++ menu_default->label = strdup(t); ++ u = strlen(t); ++ if(u > label_size) label_size = u; ++ continue; ++ } ++ ++ if(!strcmp(s, "label")) { ++ menu_ptr = *menu_next = calloc(1, sizeof **menu_next); ++ menu_next = &menu_ptr->next; ++ menu_idx++; ++ menu_ptr->label = strdup(t); ++ u = strlen(t); ++ if(u > label_size) label_size = u; ++ continue; ++ } ++ ++ if(!strcmp(s, "kernel") && menu_ptr) { ++ menu_ptr->kernel = strdup(t); ++ continue; ++ } ++ ++ if(!strcmp(s, "linux") && menu_ptr) { ++ menu_ptr->linux = strdup(t); ++ continue; ++ } ++ ++ if(!strcmp(s, "localboot") && menu_ptr) { ++ menu_ptr->localboot = strdup(t); ++ continue; ++ } ++ ++ if(!strcmp(s, "initrd") && menu_ptr) { ++ menu_ptr->initrd = strdup(t); ++ continue; ++ } ++ ++ if(!strcmp(s, "append")) { ++ (menu_ptr ?: menu_default)->append = strdup(t); ++ u = strlen(t); ++ if(u > append_size) append_size = u; ++ continue; ++ } ++ ++ if(!strcmp(s, "ipappend")) { ++ (menu_ptr ?: menu_default)->ipappend = strdup(t); ++ continue; ++ } ++ } ++ ++ fclose(f); ++ ++ // final '\0' ++ label_size++; ++ append_size++; ++ ++ gfx_menu.entries = menu_idx; ++ gfx_menu.label_size = label_size; ++ gfx_menu.arg_size = append_size; ++ ++ gfx_menu.default_entry = menu_default->label; ++ if(!gfx_menu.default_entry && menu) { ++ gfx_menu.default_entry = menu->label; ++ } ++ ++ gfx_menu.label_list = calloc(menu_idx, label_size); ++ gfx_menu.arg_list = calloc(menu_idx, append_size); ++ ++ for(u = 0, menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, u++) { ++ if(!menu_ptr->append) menu_ptr->append = menu_default->append; ++ if(!menu_ptr->ipappend) menu_ptr->ipappend = menu_default->ipappend; ++ ++ if(menu_ptr->label) strcpy(gfx_menu.label_list + u * label_size, menu_ptr->label); ++ if(menu_ptr->append) strcpy(gfx_menu.arg_list + u * append_size, menu_ptr->append); ++ } ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Check header and return code start offset. ++// ++unsigned magic_ok(unsigned char *buf, unsigned *code_size) ++{ ++ if( ++ *(unsigned *) buf == 0x0b2d97f00 && // magic id ++ (buf[4] == 8) // version 8 ++ ) { ++ *code_size = *(unsigned *) (buf + 12); ++ return *(unsigned *) (buf + 8); ++ } ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Search cpio archive for gfx file. ++// ++unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size) ++{ ++ unsigned i, fname_len, code_start = 0; ++ ++ *gfx_file_start = 0; ++ *code_size = 0; ++ ++ for(i = 0; i < len;) { ++ if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) { ++ fname_len = *(unsigned short *) (buf + i + 20); ++ *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16); ++ i += 26 + fname_len; ++ i = ((i + 1) & ~1); ++ if((code_start = magic_ok(buf + i, code_size))) { ++ *gfx_file_start = i; ++ return code_start; ++ } ++ i += *file_len; ++ i = ((i + 1) & ~1); ++ } ++ else { ++ break; ++ } ++ } ++ ++ return code_start; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Initialize gfxboot code. ++// ++// return: ++// 0: ok, 1: error ++// ++int gfx_init(char *file) ++{ ++ size_t archive_size = 0; ++ void *archive; ++ unsigned code_start, code_size, file_start, file_len, u; ++ com32sys_t r; ++ void *lowmem = lowmem_buf; ++ unsigned lowmem_size = lowmem_buf_size; ++ ++ printf("Loading %s...\n", file); ++ if(loadfile(file, &archive, &archive_size)) return 1; ++ ++ if(!archive_size) return 1; ++ ++ // printf("%s: %d\n", file, archive_size); ++ ++ gfx_config.archive_start = (uint32_t) archive; ++ gfx_config.archive_end = gfx_config.archive_start + archive_size; ++ ++ // locate file inside cpio archive ++ if(!(code_start = find_file(archive, archive_size, &file_start, &file_len, &code_size))) { ++ printf("%s: invalid file format\n", file); ++ return 1; ++ } ++ ++#if 0 ++ printf( ++ "code_start = 0x%x, code_size = 0x%x\n" ++ "archive_start = 0x%x, archive size = 0x%x\n" ++ "file_start = 0x%x, file_len = 0x%x\n", ++ code_start, code_size, ++ gfx_config.archive_start, archive_size, ++ file_start, file_len ++ ); ++#endif ++ ++ gfx_config.file = gfx_config.archive_start + file_start; ++ ++ u = &realmode_callback_end - &realmode_callback_start; ++ u = (u + REALMODE_BUF_SIZE + 0xf) & ~0xf; ++ ++ if(u + code_size > lowmem_size) { ++ printf("bounce buffer too small: size %u, needed %u\n", lowmem_size, u + code_size); ++ return 1; ++ } ++ ++ memcpy(lowmem + REALMODE_BUF_SIZE, &realmode_callback_start, &realmode_callback_end - &realmode_callback_start); ++ ++ // fill in buffer size and location ++ *(uint16_t *) (lowmem + REALMODE_BUF_SIZE) = REALMODE_BUF_SIZE; ++ *(uint16_t *) (lowmem + REALMODE_BUF_SIZE + 2) = (uint32_t) lowmem >> 4; ++ ++ gfx_config.bootloader_seg = ((uint32_t) lowmem + REALMODE_BUF_SIZE) >> 4; ++ gfx_config.callback = 4; // start address ++ ++ lowmem += u; ++ lowmem_size -= u; ++ ++ memcpy(lowmem, archive + file_start + code_start, code_size); ++ ++ gfx_config.mem0_start = (uint32_t) lowmem + code_size; ++ gfx_config.mem0_end = (uint32_t) lowmem + lowmem_size; ++ // align a bit ++ gfx_config.mem0_start = (gfx_config.mem0_start + 0xf) & ~0xf; ++ ++ gfx_config.xmem_start = (uint32_t) malloc(GFX_MEMORY_SIZE << 20); ++ if(gfx_config.xmem_start) { ++ gfx_config.xmem_end = gfx_config.xmem_start + (GFX_MEMORY_SIZE << 20); ++ } ++ ++ // fake; not used anyway ++ gfx_config.bios_mem_size = 256 << 20; ++ ++ gfx.code_seg = (uint32_t) lowmem >> 4; ++ ++ for(u = 0; u < sizeof gfx.jmp_table / sizeof *gfx.jmp_table; u++) { ++ gfx.jmp_table[u] = (gfx.code_seg << 16) + *(uint16_t *) (lowmem + 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.l = (uint32_t) &gfx_config; ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INIT], &r, &r); ++ ++ if((r.eflags.l & EFLAGS_CF)) { ++ printf("graphics initialization failed\n"); ++ ++ return 1; ++ } ++ ++ if((gfx_config.features & 3) != 3) { ++ gfx_done(); ++ ++ printf("%s: boot graphics code too old, please use newer version\n", file); ++ ++ return 1; ++ } ++ ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++int gfx_menu_init() ++{ ++ com32sys_t r; ++ ++ r.esi.l = (uint32_t) &gfx_menu; ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_MENU_INIT], &r, &r); ++ ++ return 0; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++void gfx_done() ++{ ++ com32sys_t r; ++ ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_DONE], &r, &r); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Run gfxboot main loop. ++// ++// return: ++// boot menu index (-1: go to text mode prompt) ++// ++int gfx_input() ++{ ++ com32sys_t r; ++ ++ r.edi.l = (uint32_t) cmdline; ++ r.ecx.l = sizeof cmdline; ++ r.eax.l = timeout * 182 / 100; ++ timeout = 0; // use timeout only first time ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INPUT], &r, &r); ++ if((r.eflags.l & EFLAGS_CF)) r.eax.l = 1; ++ ++ if(r.eax.l == 1) return -1; ++ ++ return r.ebx.l; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Like read(2) but preserve bounce buffer. ++// ++ssize_t save_read(int fd, void *buf, size_t size) ++{ ++ ssize_t i; ++ ++ memcpy(save_buf, lowmem_buf, save_buf_size); ++ i = read(fd, buf, size); ++ memcpy(lowmem_buf, save_buf, save_buf_size); ++ ++ return i; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Read file and update progress bar. ++// ++void *load_one(char *file, ssize_t *file_size) ++{ ++ int fd; ++ void *buf = NULL; ++ struct stat sbuf; ++ ssize_t size = 0, cur, i; ++ com32sys_t r; ++ ++ *file_size = 0; ++ ++ if((fd = open(file, O_RDONLY)) == -1) { ++ printf("%s: file not found\n", file); ++ return buf; ++ } ++ ++ if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) size = sbuf.st_size; ++ ++ i = 0; ++ ++ if(size) { ++ buf = malloc(size); ++ for(i = 1, cur = 0 ; cur < size && i > 0; cur += i) { ++ i = save_read(fd, buf + cur, CHUNK_SIZE); ++ r.eax.l = i >> gfx_config.sector_shift; ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r); ++ } ++ } ++ else { ++ do { ++ buf = realloc(buf, size + CHUNK_SIZE); ++ i = save_read(fd, buf + size, CHUNK_SIZE); ++ size += i; ++ r.eax.l = i >> gfx_config.sector_shift; ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r); ++ } while(i > 0); ++ } ++ ++ close(fd); ++ ++ if(i == -1) { ++ free(buf); ++ buf = NULL; ++ size = 0; ++ } ++ ++ *file_size = size; ++ ++ return buf; ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Locate menu entry and boot. ++// ++void boot() ++{ ++ char *label, *arg, *s; ++ menu_t *menu_ptr; ++ ++ label = skip_spaces(cmdline); ++ arg = skip_spaces(s = skip_nonspaces(label)); ++ *s = 0; ++ ++ for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next) { ++ if(menu_ptr->label && !strcmp(menu_ptr->label, label)) break; ++ } ++ ++ boot_entry(menu_ptr, arg); ++} ++ ++ ++// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++// Load & run kernel. ++// ++// Returns only on error. ++// ++void boot_entry(menu_t *menu_ptr, char *arg) ++{ ++ void *kernel, *initrd_buf; ++ ssize_t kernel_size = 0, initrd_size = 0; ++ struct initramfs *initrd = NULL; ++ char *file, *cmd_buf; ++ int fd; ++ struct stat sbuf; ++ com32sys_t r; ++ char *s, *s0, *t, *initrd_arg; ++ ++ if(!menu_ptr) return; ++ ++ if(menu_ptr->localboot) { ++ gfx_done(); ++ syslinux_local_boot(atoi(arg)); ++ ++ return; ++ } ++ ++ file = menu_ptr->kernel; ++ if(!file) file = menu_ptr->linux; ++ if(!file) return; ++ ++ // first, load kernel ++ ++ r.eax.l = 0; // kernel size in sectors ++ ++ if((fd = open(file, O_RDONLY)) >= 0) { ++ if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) r.eax.l = sbuf.st_size >> gfx_config.sector_shift; ++ close(fd); ++ } ++ ++ r.esi.l = (uint32_t) file; ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_INIT], &r, &r); ++ ++ kernel = load_one(file, &kernel_size); ++ ++ if(!kernel) { ++ gfx_done(); ++ printf("%s: read error\n", file); ++ return; ++ } ++ ++ if(kernel_size < 1024 || *(uint32_t *) (kernel + 0x202) != 0x53726448) { ++ // not a linux kernel ++ gfx_done(); ++ asprintf(&cmd_buf, "%s %s", menu_ptr->label, arg); ++ syslinux_run_command(cmd_buf); ++ return; ++ } ++ ++ // printf("kernel = %p, size = %d\n", kernel, kernel_size); ++ ++ // parse cmdline for "initrd" option ++ ++ initrd_arg = menu_ptr->initrd; ++ ++ s = s0 = strdup(arg); ++ ++ while(*s && strncmp(s, "initrd=", sizeof "initrd=" - 1)) { ++ s = skip_spaces(skip_nonspaces(s)); ++ } ++ ++ if(*s) { ++ s += sizeof "initrd=" - 1; ++ *skip_nonspaces(s) = 0; ++ initrd_arg = s; ++ } ++ ++ if(initrd_arg) { ++ initrd = initramfs_init(); ++ ++ while((t = strsep(&s, ","))) { ++ initrd_buf = load_one(t, &initrd_size); ++ ++ if(!initrd_buf) { ++ printf("%s: read error\n", t); ++ free(s0); ++ return; ++ } ++ ++ initramfs_add_data(initrd, initrd_buf, initrd_size, initrd_size, 4); ++ ++ // printf("initrd = %p, size = %d\n", initrd_buf, initrd_size); ++ } ++ } ++ ++ free(s0); ++ ++ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_DONE], &r, &r); ++ ++ syslinux_boot_linux(kernel, kernel_size, initrd, arg); ++} ++ ++ +diff --git a/com32/gfxboot/realmode_callback.asm b/com32/gfxboot/realmode_callback.asm +new file mode 100644 +index 0000000..fb5461d +--- /dev/null ++++ b/com32/gfxboot/realmode_callback.asm +@@ -0,0 +1,190 @@ ++ bits 16 ++ ++ section .text ++ ++ ; must be filled in ++f_buf_size dw 0 ++f_buf_seg dw 0 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++gfx_cb: ++ push cs ++ pop ds ++ ++ cmp al,cb_len ++ jae gfx_cb_80 ++ ++ movzx bx,al ++ add bx,bx ++ call word [bx+cb_table] ++ jmp gfx_cb_90 ++ ++gfx_cb_80: ++ mov al,0ffh ++gfx_cb_90: ++ retf ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Return status info. ++; ++; return: ++; edx filename buffer (64 bytes) ++; ++cb_status: ++ mov edx,cs ++ shl edx,4 ++ add edx,f_name ++ xor al,al ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Open file. ++; ++; return: ++; al 0: ok, 1: file not found ++; ecx file length (al = 0) ++; ++cb_fopen: ++ mov si,f_name ++ push ds ++ pop es ++ mov ax,6 ++ int 22h ++ xchg edx,eax ++ mov al,1 ++ jc cb_fopen_90 ++ cmp cx,[f_buf_size] ++ ja cb_fopen_90 ++ or cx,cx ++ jz cb_fopen_90 ++ mov [f_block_size],cx ++ or edx,edx ++ jz cb_fopen_90 ++ mov [f_handle],si ++ mov [f_size],edx ++ mov ecx,edx ++ mov ax,[f_buf_size] ++ cwd ++ div word [f_block_size] ++ mov [f_blocks],ax ++ ++ xor al,al ++cb_fopen_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Read next chunk. ++; ++; return: ++; edx buffer address (linear) ++; ecx data length (< 64k) ++; ++cb_fread: ++ xor ecx,ecx ++ mov si,[f_handle] ++ or si,si ++ jz cb_fread_80 ++ mov cx,[f_blocks] ++ mov es,[f_buf_seg] ++ xor bx,bx ++ mov ax,7 ++ int 22h ++ mov [f_handle],si ++ mov al,1 ++ jc cb_fread_90 ++cb_fread_80: ++ xor al,al ++cb_fread_90: ++ movzx edx,word [f_buf_seg] ++ shl edx,4 ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Return current working directory. ++; ++; return: ++; edx filename ++; ++cb_getcwd: ++ mov ax,15h ++ int 22h ++ mov edx,es ++ shl edx,4 ++ movzx ebx,bx ++ add edx,ebx ++ xor al,al ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Set current working directory. ++; ++cb_chdir: ++ mov bx,f_name ++ push ds ++ pop es ++ mov ax,25h ++ int 22h ++ xor al,al ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; read sector ++; ++; edx sector ++; ++; return: ++; edx buffer (linear address) ++; ++; Note: does not return on error! ++; ++cb_readsector: ++ xor edi,edi ++ xor esi,esi ++ mov cx,1 ++ mov es,[f_buf_seg] ++ xor bx,bx ++ mov ax,19h ++ int 22h ++ movzx edx,word [f_buf_seg] ++ shl edx,4 ++ xor al,al ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; Re-read fs structures. ++; ++cb_mount: ++ mov ax,26h ++ int 22h ++ setc al ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++ align 2, db 0 ++ ++cb_table dw cb_status ++ dw cb_fopen ++ dw cb_fread ++ dw cb_getcwd ++ dw cb_chdir ++ dw cb_readsector ++ dw cb_mount ++cb_len equ ($-cb_table)/2 ++ ++f_handle dw 0 ++f_block_size dw 0 ++f_blocks dw 0 ++f_size dd 0 ++f_name times 64 db 0 ++f_name_len equ $ - f_name ++ diff --git a/patches/grub-0.97.diff b/patches/grub-0.97.diff new file mode 100644 index 0000000..6874b06 --- /dev/null +++ b/patches/grub-0.97.diff @@ -0,0 +1,1006 @@ +--- docs/grub.texi ++++ docs/grub.texi +@@ -2118,6 +2118,7 @@ + * default:: Set the default entry + * fallback:: Set the fallback entry + * hiddenmenu:: Hide the menu interface ++* gfxmenu:: Use graphical menu interface + * timeout:: Set the timeout + * title:: Start a menu entry + @end menu +@@ -2150,6 +2151,15 @@ + @end deffn + + ++@node gfxmenu ++@subsection gfxmenu ++ ++@deffn Command gfxmenu file ++Use the graphical menu interface. The graphics data are taken from ++@var{file} and must be created using 'mkbootmsg' from the gfxboot package. ++@end deffn ++ ++ + @node hiddenmenu + @subsection hiddenmenu + +--- grub/asmstub.c ++++ grub/asmstub.c +@@ -498,6 +498,32 @@ + return 0; + } + ++/* graphical menu functions . */ ++int ++gfx_init (gfx_data_t *gfx_data) ++{ ++ return 0; ++} ++ ++int ++gfx_done (gfx_data_t *gfx_data) ++{ ++ return 0; ++} ++ ++int ++gfx_input (gfx_data_t *gfx_data, int *menu_entry) ++{ ++ return 0; ++} ++ ++int ++gfx_setup_menu (gfx_data_t *gfx_data) ++{ ++ return 0; ++} ++ ++ + /* low-level timing info */ + int + getrtsecs (void) +--- stage2/asm.S ++++ stage2/asm.S +@@ -1614,6 +1614,286 @@ + popl %ebp + ret + ++ ++/* ++ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ * ++ * graphical menu functions ++ * ++ */ ++ ++/* ++ * int gfx_init (gfx_data_t *gfx_data) ++ * ++ * init gfx things ++ * ++ * return vales: ++ * 0: ok ++ * 1: failed ++ * sets gfx_data->ok ++ */ ++ ++ENTRY(gfx_init) ++ pushl %ebp ++ movl %esp, %ebp ++ ++ pushl %edi ++ pushl %esi ++ pushl %ebx ++ ++ movl 8(%ebp),%edx ++ movl %edx,%edi ++ leal gfx_ofs_sys_cfg(%edx),%esi ++ andl $0xf,%edi ++ shrl $4,%edx ++ ++ pushl %ebp ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ movw %dx,%ds ++ ++ lcall *gfx_ofs_jmp_table + 4 * 0 (%di) ++ ++ sbbl %ebx,%ebx ++ negl %ebx ++ ++ popw %ds ++ ++ DATA32 call EXT_C(real_to_prot) ++ .code32 ++ ++ popl %ebp ++ ++ movl %ebx,%eax ++ xorl $1,%ebx ++ movl 8(%ebp),%edx ++ movl %ebx,gfx_ofs_ok(%edx) ++ ++ popl %ebx ++ popl %esi ++ popl %edi ++ ++ popl %ebp ++ ret ++ ++ ++/* ++ * int gfx_done (gfx_data_t *gfx_data) ++ * ++ * shut down gfx things ++ * ++ * return vales: ++ * always 0 ++ * sets gfx_data->ok ++ */ ++ ++ENTRY(gfx_done) ++ pushl %ebp ++ movl %esp, %ebp ++ ++ pushl %edi ++ pushl %esi ++ pushl %ebx ++ ++ movl 8(%ebp),%edx ++ movl %edx,%ebx ++ andl $0xf,%ebx ++ shrl $4,%edx ++ ++ pushl %ebp ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ ++ movw %dx,%ds ++ ++ lcall *gfx_ofs_jmp_table + 4 * 1 (%bx) ++ ++ popw %ds ++ ++ DATA32 call EXT_C(real_to_prot) ++ .code32 ++ ++ popl %ebp ++ ++ xorl %eax,%eax ++ movl 8(%ebp),%edx ++ movl %eax,gfx_ofs_ok(%edx) ++ ++ popl %ebx ++ popl %esi ++ popl %edi ++ ++ popl %ebp ++ ret ++ ++ ++/* ++ * int gfx_input (gfx_data_t *gfx_data, int *menu_entry) ++ * ++ * let user enter a command line ++ * ++ * uses gfx_data->cmdline as buffer ++ * ++ * return values: ++ * 1: abort ++ * 2: boot ++ * menu_entry: selected entry ++ */ ++ ++ENTRY(gfx_input) ++ pushl %ebp ++ movl %esp, %ebp ++ ++ pushl %edi ++ pushl %esi ++ pushl %ebx ++ ++ movl 8(%ebp),%edx ++ movl %edx,%ebx ++ leal gfx_ofs_sys_cfg(%edx),%esi ++ andl $0xf,%ebx ++ shrl $4,%edx ++ ++ pushl %ebp ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ ++ movw %dx,%ds ++ ++ movl gfx_ofs_cmdline(%bx),%edi ++ movl gfx_ofs_cmdline_len(%bx),%ecx ++ movl gfx_ofs_timeout(%bx),%eax ++ imull $18,%eax ++ ++ lcall *gfx_ofs_jmp_table + 4 * 2 (%bx) ++ ++ movl %eax,%ecx ++ ++ popw %ds ++ ++ DATA32 call EXT_C(real_to_prot) ++ .code32 ++ ++ popl %ebp ++ ++ movl 12(%ebp),%edx ++ movl %ebx,(%edx) ++ ++ movl %ecx,%eax ++ ++ popl %ebx ++ popl %esi ++ popl %edi ++ ++ popl %ebp ++ ret ++ ++ ++/* ++ * int gfx_setup_menu (gfx_data_t *gfx_data) ++ * ++ * draw boot menu ++ * ++ * return values: ++ * always 0 ++ */ ++ ++/* menu entry descriptor */ ++#define menu_entries 0 ++#define menu_default 2 /* seg:ofs */ ++#define menu_ent_list 6 /* seg:ofs */ ++#define menu_ent_size 10 ++#define menu_arg_list 12 /* seg:ofs */ ++#define menu_arg_size 16 ++#define sizeof_menu_desc 18 ++ ++ENTRY(gfx_setup_menu) ++ pushl %ebp ++ movl %esp, %ebp ++ ++ pushl %edi ++ pushl %esi ++ pushl %ebx ++ ++ movl 8(%ebp),%edx ++ movl %edx,%ebx ++ andl $0xf,%ebx ++ shrl $4,%edx ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ ++ movw %dx,%ds ++ shll $4,%edx ++ ++ subw $sizeof_menu_desc,%sp ++ movw %esp,%ebp ++ ++ movl gfx_ofs_menu_entries(%bx),%eax ++ movw %ax,menu_entries(%bp) ++ ++ movl gfx_ofs_menu_default_entry(%bx),%eax ++ subl %edx,%eax ++ movw %ax,menu_default(%bp) ++ movw %ds,menu_default+2(%bp) ++ ++ movl gfx_ofs_menu_list(%bx),%eax ++ subl %edx,%eax ++ movw %ax,menu_ent_list(%bp) ++ movw %ds,menu_ent_list+2(%bp) ++ ++ movl gfx_ofs_menu_entry_len(%bx),%eax ++ movw %ax,menu_ent_size(%bp) ++ ++ movl gfx_ofs_args_list(%bx),%eax ++ subl %edx,%eax ++ movw %ax,menu_arg_list(%bp) ++ movw %ds,menu_arg_list+2(%bp) ++ ++ movl gfx_ofs_args_entry_len(%bx),%eax ++ movw %ax,menu_arg_size(%bp) ++ ++ movl %ss,%esi ++ shll $4,%esi ++ addl %ebp,%esi ++ ++ lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bx) ++ ++ addw $sizeof_menu_desc,%sp ++ ++ popw %ds ++ ++ DATA32 call EXT_C(real_to_prot) ++ .code32 ++ ++ xorl %eax,%eax ++ ++ popl %ebx ++ popl %esi ++ popl %edi ++ ++ popl %ebp ++ ret ++ ++ ++/* ++ * ++ * end graphics stuff ++ * ++ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ */ ++ + + /* + * gateA20(int linear) +--- stage2/builtins.c ++++ stage2/builtins.c +@@ -63,6 +63,8 @@ + int fallback_entries[MAX_FALLBACK_ENTRIES]; + /* The number of current entry. */ + int current_entryno; ++/* graphics file */ ++char graphics_file[64]; + /* The address for Multiboot command-line buffer. */ + static char *mb_cmdline; + /* The password. */ +@@ -1351,6 +1353,26 @@ + }; + + ++/* graphics */ ++static int ++gfxmenu_func (char *arg, int flags) ++{ ++ memmove(graphics_file, arg, sizeof graphics_file - 1); ++ graphics_file[sizeof graphics_file - 1] = 0; ++ ++ return 0; ++} ++ ++static struct builtin builtin_gfxmenu = ++{ ++ "gfxmenu", ++ gfxmenu_func, ++ BUILTIN_MENU | BUILTIN_HELP_LIST, ++ "gfxmenu FILE", ++ "Use the graphical menu from FILE." ++}; ++ ++ + /* geometry */ + static int + geometry_func (char *arg, int flags) +@@ -4874,6 +4896,7 @@ + &builtin_find, + &builtin_fstest, + &builtin_geometry, ++ &builtin_gfxmenu, + &builtin_halt, + &builtin_help, + &builtin_hiddenmenu, +--- stage2/shared.h ++++ stage2/shared.h +@@ -374,6 +374,22 @@ + #endif /* WITHOUT_LIBC_STUBS */ + + ++/* see typedef gfx_data_t below */ ++#define gfx_ofs_ok 0x00 ++#define gfx_ofs_code_seg 0x04 ++#define gfx_ofs_jmp_table 0x08 ++#define gfx_ofs_sys_cfg 0x38 ++#define gfx_ofs_cmdline 0x6c ++#define gfx_ofs_cmdline_len 0x70 ++#define gfx_ofs_menu_list 0x74 ++#define gfx_ofs_menu_default_entry 0x78 ++#define gfx_ofs_menu_entries 0x7c ++#define gfx_ofs_menu_entry_len 0x80 ++#define gfx_ofs_args_list 0x84 ++#define gfx_ofs_args_entry_len 0x88 ++#define gfx_ofs_timeout 0x8c ++ ++ + #ifndef ASM_FILE + /* + * Below this should be ONLY defines and other constructs for C code. +@@ -595,6 +611,38 @@ + extern int default_entry; + extern int current_entryno; + ++ ++/* ++ * graphics menu stuff ++ * ++ * Note: gfx_data and all data referred to in it must lie within a 64k area. ++ */ ++typedef struct { ++ unsigned ok; /* set while we're in graphics mode */ ++ unsigned code_seg; /* code segment of binary graphics code */ ++ unsigned jmp_table[12]; /* link to graphics functions */ ++ unsigned char sys_cfg[52]; /* sys_cfg[0]: identifies boot loader (grub == 2) */ ++ char *cmdline; /* command line returned by gfx_input() */ ++ unsigned cmdline_len; /* length of the above */ ++ char *menu_list; /* list of menu entries, each of fixed length (menu_entry_len) */ ++ char *menu_default_entry; /* the default entry */ ++ unsigned menu_entries; /* number of entries in menu_list */ ++ unsigned menu_entry_len; /* one entry */ ++ char *args_list; /* same structure as menu_list, menu_entries entries */ ++ unsigned args_entry_len; /* one entry */ ++ unsigned timeout; /* in seconds (0: no timeout) */ ++} __attribute__ ((packed)) gfx_data_t; ++ ++extern gfx_data_t *graphics_data; ++ ++/* pointer to graphics image data */ ++extern char graphics_file[64]; ++ ++int gfx_init(gfx_data_t *gfx_data); ++int gfx_done(gfx_data_t *gfx_data); ++int gfx_input(gfx_data_t *gfx_data, int *menu_entry); ++int gfx_setup_menu(gfx_data_t *gfx_data); ++ + /* The constants for password types. */ + typedef enum + { +--- stage2/stage2.c ++++ stage2/stage2.c +@@ -22,6 +22,8 @@ + + grub_jmp_buf restart_env; + ++gfx_data_t *graphics_data; ++ + #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS) + + # if defined(PRESET_MENU_STRING) +@@ -310,6 +312,12 @@ + + if (! auth && password) + { ++ if (*graphics_file) ++ { ++ printf ("\ ++ WARNING: graphical menu doesn\'t work\ ++ in conjunction with the password feature\n" ); ++ } + printf ("\ + Press enter to boot the selected OS or \'p\' to enter a\n\ + password to unlock the next set of features."); +@@ -753,6 +761,493 @@ + } + + ++ ++#if 0 ++/* for debugging */ ++static void hexdump(unsigned char *buf, unsigned len) ++{ ++ int i, j = 0; ++ char s[17]; ++ unsigned addr = (unsigned) buf; ++ ++ s[16] = 0; ++ while(len--) { ++ i = buf[j]; ++ i = i & 0xff; ++ s[j & 15] = (i >= 0x20 && i <= 0x7e) ? i : '.'; ++ if(!(j & 15)) { ++ printf("%x ", j + addr); ++ } ++ if(!(j & 7) && (j & 15)) printf(" "); ++ /* stupid grub_printf */ ++ printf("%x", (i >> 4) & 0x0f); ++ printf("%x ", i & 0x0f); ++ if(!(++j & 15)) { ++ printf(" %s\n", s); ++ } ++ } ++ ++ if(j & 15) { ++ s[j & 15] = 0; ++ if(!(j & 8)) printf(" "); ++ i = 1 + 3 * (16 - (j & 15)); ++ while(i--) printf(" "); ++ printf("%s\n", s); ++ } ++} ++#endif ++ ++ ++/* kernel + (grub-)module options */ ++#define GFX_CMD_BUF_SIZE 512 ++ ++/* command line separator char */ ++#define GFX_CMD_SEP 1 ++ ++/* ++ * Go through config entry and find kernel args, if any. ++ * Put things into buf and return it. ++ */ ++static char *get_kernel_args(char *cfg, char *buf) ++{ ++ int i, j; ++ char *s, *t = "", *p, *t2; ++ ++ *(p = buf) = 0; ++ ++ for(j = 0; ; j++) { ++ s = get_entry(cfg, j, 0); ++ if(!*s) break; ++ if( ++ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && ++ (s[6] == ' ' || s[6] == '\t') ++ ) { ++ t = skip_to(0, s); ++ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; ++ if(*t) t = skip_to(0, t); ++ if(t2 && t2 < t) break; /* module is likely a normal initrd -> skip */ ++ i = strlen(t); ++ if(p - buf + i > GFX_CMD_BUF_SIZE - 2) break; ++ *p++ = GFX_CMD_SEP; ++ strcpy(p, t); ++ p += i; ++ ++ continue; ++ } ++ } ++ ++ if(*buf) buf++; /* skip initial separator char */ ++ ++ return buf; ++} ++ ++ ++/* ++ * Check header and return code start offset. ++ */ ++static unsigned magic_ok(unsigned char *buf) ++{ ++ if( ++ *(unsigned *) buf == 0x0b2d97f00 && /* magic id */ ++ (buf[4] == 8) /* version 8 */ ++ ) { ++ return *(unsigned *) (buf + 8); ++ } ++ ++ return 0; ++} ++ ++ ++/* ++ * Search cpio archive for gfx file. ++ */ ++static unsigned find_file(unsigned char *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 && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) { ++ fname_len = *(unsigned short *) (buf + i + 20); ++ *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (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; ++} ++ ++static inline unsigned char * stack_ptr(void) ++{ ++ unsigned char * u; ++ ++ asm("movl %%esp, %0" : "=r" (u)); ++ ++ return u; ++} ++ ++static void sleep(int delay) ++{ ++ int tick, last_tick = currticks(); ++ ++ delay *= 18; ++ ++ while(delay--) { ++ while((tick = currticks()) == last_tick) { } ++ last_tick = tick; ++ } ++} ++ ++static void wait_for_key() ++{ ++ printf("Press a key to continue..."); ++ getkey(); ++ printf("\r \r"); ++} ++ ++ ++/* ++ * Leave that much space on the heap. Everything else goes to the graphics ++ * functions. ++ * ++ * 0x2000 is _not_ enough ++ */ ++#define MIN_HEAP_SIZE 0x4000 ++#define MIN_GFX_FREE 0x1000 ++ ++#define SC_BOOTLOADER 0 ++#define SC_FAILSAFE 3 ++#define SC_SYSCONFIG_SIZE 4 ++#define SC_BOOTLOADER_SEG 8 ++#define SC_XMEM_0 24 ++#define SC_XMEM_1 26 ++#define SC_XMEM_2 28 ++#define SC_XMEM_3 30 ++#define SC_FILE 32 ++#define SC_ARCHIVE_START 36 ++#define SC_ARCHIVE_END 40 ++#define SC_MEM0_START 44 ++#define SC_MEM0_END 48 ++ ++/* ++ * Does normally not return. ++ */ ++static void ++run_graphics_menu (char *menu_entries, char *config_entries, int num_entries, ++ char *heap, int entryno) ++{ ++ unsigned char *buf, *buf_ext; ++ unsigned buf_size, buf_ext_size, code_start, file_start; ++ char *s, *t, *t2, *cfg, *new_config, *p; ++ char *saved_heap; ++ int i, j, max_len, gfx_file_size, verbose; ++ int selected_entry; ++ gfx_data_t *gfx_data; ++ char *cmd_buf; ++ unsigned mem0_start, mem0_end, file_len; ++ ++ /* ++ * check gfx_data_t struct offsets for consistency; gcc will optimize away ++ * the whole block ++ */ ++ ++ /* dummy function to make ld fail */ ++ { ++ extern void wrong_struct_size(void); ++ #define gfx_ofs_check(a) if(gfx_ofs_##a != (char *) &gfx_data->a - (char *) gfx_data) wrong_struct_size(); ++ gfx_ofs_check(ok); ++ gfx_ofs_check(code_seg); ++ gfx_ofs_check(jmp_table); ++ gfx_ofs_check(sys_cfg); ++ gfx_ofs_check(cmdline); ++ gfx_ofs_check(cmdline_len); ++ gfx_ofs_check(menu_list); ++ gfx_ofs_check(menu_default_entry); ++ gfx_ofs_check(menu_entries); ++ gfx_ofs_check(menu_entry_len); ++ gfx_ofs_check(args_list); ++ gfx_ofs_check(args_entry_len); ++ gfx_ofs_check(timeout); ++ #undef gfx_ofs_check ++ } ++ ++ if(!num_entries) return; ++ ++ graphics_data = gfx_data = (gfx_data_t *) heap; ++ heap += sizeof *gfx_data; ++ memset(gfx_data, 0, sizeof *gfx_data); ++ ++ gfx_data->sys_cfg[SC_BOOTLOADER] = 2; /* bootloader: grub */ ++ gfx_data->sys_cfg[SC_SYSCONFIG_SIZE] = 52; /* config data size */ ++ *(unsigned short *) (gfx_data->sys_cfg + SC_BOOTLOADER_SEG) = (unsigned) gfx_data >> 4; /* segment */ ++ gfx_data->sys_cfg[SC_XMEM_0] = 0x21; /* 1MB @ 2MB */ ++ gfx_data->sys_cfg[SC_XMEM_1] = 0x41; /* 1MB @ 4MB */ ++ verbose = (*(unsigned char *) 0x417) & 3 ? 1 : 0; /* SHIFT pressed */ ++ gfx_data->sys_cfg[SC_FAILSAFE] = verbose; ++ ++ gfx_data->timeout = grub_timeout >= 0 ? grub_timeout : 0; ++ ++ ++ /* setup command line edit buffer */ ++ ++ gfx_data->cmdline_len = 256; ++ ++ gfx_data->cmdline = heap; ++ heap += gfx_data->cmdline_len; ++ memset(gfx_data->cmdline, 0, gfx_data->cmdline_len); ++ ++ cmd_buf = heap; ++ heap += GFX_CMD_BUF_SIZE; ++ ++ /* setup menu entries */ ++ ++ for(i = max_len = 0; i < num_entries; i++) { ++ j = strlen(get_entry(menu_entries, i, 0)); ++ if(j > max_len) max_len = j; ++ } ++ ++ if(!max_len) return; ++ ++ gfx_data->menu_entry_len = max_len + 1; ++ gfx_data->menu_entries = num_entries; ++ ++ gfx_data->menu_list = heap; ++ heap += gfx_data->menu_entry_len * gfx_data->menu_entries; ++ ++ memset(gfx_data->menu_list, 0, gfx_data->menu_entry_len * gfx_data->menu_entries); ++ ++ for(i = 0; i < (int) gfx_data->menu_entries; i++) { ++ strcpy(gfx_data->menu_list + i * gfx_data->menu_entry_len, get_entry(menu_entries, i, 0)); ++ } ++ ++ gfx_data->menu_default_entry = gfx_data->menu_list + entryno * gfx_data->menu_entry_len; ++ ++ ++ /* setup list of kernel args */ ++ ++ for(i = max_len = 0; i < num_entries; i++) { ++ s = get_kernel_args(get_entry(config_entries, i, 1), cmd_buf); ++ j = strlen(s); ++ if(j > max_len) max_len = j; ++ } ++ ++ gfx_data->args_entry_len = max_len + 1; ++ ++ gfx_data->args_list = heap; ++ heap += gfx_data->args_entry_len * gfx_data->menu_entries; ++ ++ memset(gfx_data->args_list, 0, gfx_data->args_entry_len * gfx_data->menu_entries); ++ ++ for(i = 0; i < (int) gfx_data->menu_entries; i++) { ++ strcpy(gfx_data->args_list + i* gfx_data->args_entry_len, get_kernel_args(get_entry(config_entries, i, 1), cmd_buf)); ++ } ++ ++ ++ /* go back here when we no longer need the graphics data */ ++ saved_heap = heap; ++ ++ ++ /* get memory area to be used by graphics functions */ ++ ++ /* use 1MB starting at 2MB as file buffer */ ++ buf_ext = (unsigned char *) (2 << 20); ++ buf_ext_size = 1 << 20; ++ ++ /* must be 16-byte aligned */ ++ buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf); ++ ++ buf_size = stack_ptr() - buf - MIN_HEAP_SIZE; ++ buf_size &= ~0xf; ++ ++ mem0_start = (unsigned) buf; ++ mem0_end = mem0_start + buf_size; ++ ++ if(verbose) { ++ printf("low memory 0x%x - 0x%x (%d bytes)\n", mem0_start, mem0_end, buf_size); ++ wait_for_key(); ++ } ++ ++ heap += buf_size; ++ ++ /* read the file */ ++ ++ if(!grub_open(graphics_file)) { ++ printf("%s: file not found\n", graphics_file); ++ sleep(5); ++ heap = saved_heap; ++ return; ++ } ++ ++ gfx_file_size = grub_read(buf_ext, buf_ext_size); ++ ++ grub_close(); ++ ++ if(gfx_file_size <= 0) { ++ printf("%s: read error\n", graphics_file); ++ sleep(5); ++ heap = saved_heap; ++ return; ++ } ++ ++ if(verbose) { ++ printf("%s: %d bytes (%d bytes left)\n", graphics_file, gfx_file_size, buf_ext_size - gfx_file_size); ++ wait_for_key(); ++ } ++ ++ /* locate file inside cpio archive */ ++ if(!(code_start = find_file(buf_ext, gfx_file_size, &file_start, &file_len))) { ++ printf("%s: invalid file format\n", graphics_file); ++ sleep(5); ++ heap = saved_heap; ++ return; ++ } ++ ++ if(verbose) { ++ printf("init: start 0x%x, len %d; code offset 0x%x\n", file_start, file_len, code_start); ++ wait_for_key(); ++ } ++ ++ if(file_len - code_start + MIN_GFX_FREE > buf_size) { ++ printf("not enough free memory: %d extra bytes need\n", file_len - code_start + MIN_GFX_FREE - buf_size); ++ sleep(5); ++ heap = saved_heap; ++ return; ++ } ++ ++ memcpy((void *) buf, (void *) (buf_ext + file_start + code_start), file_len - code_start); ++ ++ mem0_start += file_len - code_start; ++ mem0_start = (mem0_start + 3) & ~3; /* align */ ++ ++ /* init interface to graphics functions */ ++ ++ *(unsigned *) (gfx_data->sys_cfg + SC_FILE) = (unsigned) buf_ext + file_start; ++ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_START) = (unsigned) buf_ext; ++ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_END) = (unsigned) buf_ext + gfx_file_size; ++ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_START) = mem0_start; ++ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_END) = mem0_end; ++ ++ gfx_data->code_seg = (unsigned) buf >> 4; ++ ++ if(verbose) { ++ printf("init 0x%x, archive 0x%x - 0x%x, low mem 0x%x - 0x%x\ncode seg 0x%x\n", ++ (unsigned) buf_ext + file_start, ++ (unsigned) buf_ext, (unsigned) buf_ext + gfx_file_size, ++ mem0_start, mem0_end, gfx_data->code_seg ++ ); ++ wait_for_key(); ++ } ++ ++ for(i = 0; (unsigned) i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) { ++ gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) buf)[i]; ++ } ++ ++ if(verbose) { ++ for(i = 0; i < 12; i++) { ++ printf("%d: 0x%x\n", i, gfx_data->jmp_table[i]); ++ } ++ ++ for(i = 0; i < gfx_data->menu_entries; i++) { ++ printf("\"%s\" -- \"%s\"\n", ++ gfx_data->menu_list + i * gfx_data->menu_entry_len, ++ gfx_data->args_list + i * gfx_data->args_entry_len ++ ); ++ } ++ ++ printf("default: \"%s\"\n", gfx_data->menu_default_entry); ++ wait_for_key(); ++ } ++ ++ /* switch to graphics mode */ ++ ++ if(gfx_init(gfx_data)) { ++ printf("graphics initialization failed\n"); ++ sleep(5); ++ heap = saved_heap; ++ return; ++ } ++ ++ gfx_setup_menu(gfx_data); ++ ++ i = gfx_input(gfx_data, &selected_entry); ++ ++ /* ESC -> show text menu */ ++ if(i == 1) { ++ gfx_done(gfx_data); ++ grub_timeout = -1; ++ ++ heap = saved_heap; ++ return; ++ } ++ ++ gfx_done(gfx_data); ++ ++ heap = saved_heap; /* free most of the graphics data */ ++ ++ // printf("cmdline: >%s<, entry = %d\n", gfx_data->cmdline, selected_entry); ++ ++ if(selected_entry < 0 || selected_entry > num_entries) return; ++ ++ ++ /* create new config with modified kernel option */ ++ ++ cfg = get_entry(config_entries, selected_entry, 1); ++ ++ new_config = heap; ++ ++ for(p = gfx_data->cmdline, i = 0; ; i++) { ++ s = get_entry(cfg, i, 0); ++ if(!*s) { ++ if(!i) *heap++ = 0; ++ *heap++ = 0; ++ break; ++ } ++ /* note: must match get_kernel_args() */ ++ if( ++ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && ++ (s[6] == ' ' || s[6] == '\t') ++ ) { ++ t = skip_to(0, s); ++ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; ++ if(*t) t = skip_to(0, t); ++ if(t2 && t2 < t) { /* module is likely a normal initrd -> skip */ ++ strcpy(heap, s); ++ heap += strlen(s) + 1; ++ continue; ++ } ++ memmove(heap, s, t - s); ++ heap += t - s; ++ *heap++ = ' '; ++ while(*p && *p != GFX_CMD_SEP) *heap++ = *p++; ++ *heap++ = 0; ++ if(*p == GFX_CMD_SEP) p++; ++ } ++ else { ++ strcpy(heap, s); ++ heap += strlen(s) + 1; ++ } ++ } ++ ++ *heap++ = 0; ++ ++ // hexdump(new_config, heap - new_config); ++ // getkey(); ++ ++ run_script(new_config, heap); ++} ++ ++ + static int + get_line_from_config (char *cmdline, int maxlen, int read_from_file) + { +@@ -1062,9 +1557,12 @@ + } + else + { +- /* Run menu interface. */ +- run_menu (menu_entries, config_entries, num_entries, +- menu_entries + menu_len, default_entry); ++ if (*graphics_file && !password && show_menu && grub_timeout) ++ { ++ run_graphics_menu(menu_entries, config_entries, num_entries,menu_entries + menu_len, default_entry); ++ } ++ /* Run menu interface. */ ++ run_menu (menu_entries, config_entries, num_entries, menu_entries + menu_len, default_entry); + } + } + } +--- stage2/stage2.c ++++ stage2/stage2.c +@@ -1199,6 +1199,9 @@ + + if(selected_entry < 0 || selected_entry > num_entries) return; + ++ /* for 'savedefault' */ ++ current_entryno = selected_entry; ++ + + /* create new config with modified kernel option */ + diff --git a/patches/lilo-22.7.diff b/patches/lilo-22.7.diff new file mode 100644 index 0000000..a1bdc20 --- /dev/null +++ b/patches/lilo-22.7.diff @@ -0,0 +1,1133 @@ +--- Makefile ++++ Makefile +@@ -330,15 +330,15 @@ + first.s: first.S lilo.h version.h Makefile + $(CPP) $(PCONFIG) -DFIRST=0x199d1f05 -o first.s first.S + +-second.s: second.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ ++second.s: second.S gfxlogo.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ + graph.S menu.S strlen.S bitmap.S crt.S display4.S Makefile + $(CPP) $(PCONFIG) -DTEXT=0x8bd7820b second.S -o second.s + +-third.s: second.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ ++third.s: second.S gfxlogo.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ + graph.S menu.S strlen.S bitmap.S crt.S display4.S Makefile + $(CPP) $(PCONFIG) -DMENU=0x7920a7c2 second.S -o third.s + +-bitmap.s: second.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ ++bitmap.s: second.S gfxlogo.S read.S volume.S mapper.S biosdata.S shs3.S bdata.h lilo.h version.h \ + graph.S menu.S strlen.S bitmap.S crt.S display4.S Makefile + $(CPP) $(PCONFIG) -DBITMAP=0xf54f8b9d second.S -o bitmap.s + +--- bsect.c ++++ bsect.c +@@ -774,6 +774,7 @@ + if (st.st_size > i) + die("%s is too big (> %d bytes)",message,i); + param2.msg_len = bitmap ? (st.st_size+15)/16 : st.st_size; ++ if(!bitmap) param2.msg_len = st.st_size > 0xffff ? 0xffff : st.st_size; + map_begin_section(); + #ifndef LCF_UNIFY + map_add(&geo,0,((st.st_size)+SECTOR_SIZE-1)/SECTOR_SIZE); +--- gfxlogo.S ++++ gfxlogo.S +@@ -0,0 +1,764 @@ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; gfx stuff ++; ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ ++; != 0 -> everything is fine ++gfx_ok: .byte 0 ++ ++; we need it at some point ++gfx_tmp: .word 0 ++ ++; the memory area we are working with ++gfx_mem: .long 0 ; linear address ++ ++; interface to loadable gfx extension (seg:ofs values) ++gfx_bc_jt: .long 0 ++ ++gfx_bc_init: .long 0 ++gfx_bc_done: .long 0 ++gfx_bc_input: .long 0 ++gfx_bc_menu_init: .long 0 ++gfx_bc_infobox_init: .long 0 ++gfx_bc_infobox_done: .long 0 ++gfx_bc_progress_init: .long 0 ++gfx_bc_progress_done: .long 0 ++gfx_bc_progress_update: .long 0 ++gfx_bc_progress_limit: .long 0 ++gfx_bc_password_init: .long 0 ++gfx_bc_password_done: .long 0 ++ ++; system config data (52 bytes) ++gfx_sysconfig: ++gfx_bootloader: .byte 0 ++gfx_sector_shift: .byte 0 ++gfx_media_type: .byte 0 ++gfx_failsafe: .byte 0 ++gfx_sysconfig_size: .byte gfx_sysconfig_end-gfx_sysconfig ++gfx_boot_drive: .byte 0 ++gfx_callback: .word 0 ++gfx_bootloader_seg: .word 0 ++gfx_reserved_1: .word 0 ++gfx_user_info_0: .long 0 ++gfx_user_info_1: .long 0 ++gfx_bios_mem_size: .long 0 ++gfx_xmem_0: .word 0x21 ; extended mem area 0 (start:size in MB; 12:4 bits) ++gfx_xmem_1: .word 0x41 ++gfx_xmem_2: .word 0 ++gfx_xmem_3: .word 0 ++gfx_file: .long 0 ++gfx_archive_start: .long 0 ++gfx_archive_end: .long 0 ++gfx_mem0_start: .long 0 ++gfx_mem0_end: .long 0 ++gfx_sysconfig_end: ++ ++; 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: .blkb sizeof_menu_desc ++ ++; 64 dummy entries (all "") ++gfx_args_entry: .blkb 64 ++ ++gfx_password_buf: .blkb 32 ++gfx_msg_wrong_image: .ascii "Could not find kernel image: " ++ .byte 0 ++gfx_msg_wrong_password: .ascii "Sorry, incorrect password." ++ .byte 0 ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; I really have no idea how to get as86 to do this properly ++ ++ macro farcall ++ .byte 0xff ++ .byte 0x1e ++ .word ?1 ++ mend ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_get_sysconfig: ++ xor ax,ax ++ ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_set_sysconfig: ++ ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; Initialize graphics code. Load and display graphics data. ++; ++; edi file length ++; ++; return: [gfx_ok] = 0/1 ++; ++gfx_init: ++ push es ++ ++ cld ++ ++ mov byte gfx_ok,#0 ++ ++ ; no gfx if we use a serial line ++ cmp byte par2_port,#0 ++ jnz near gfx_init_90 ++ ++ mov gfx_bootloader_seg,cs ++ mov gfx_archive_end,edi ++ ++ ; define our memory area ++ ; gfx_mem _must_ be 16-byte aligned ++ mov dword gfx_mem,#0x10000 ++ add edi,gfx_mem ++ add edi,#15 ; add space for alignment ++ mov gfx_mem0_start,edi ++ mov dword gfx_mem0_end,#0x80000 ++ ++ sub edi,gfx_mem0_end ++ neg edi ++ cmp edi,#0x1000 ; we need some minimum space ++ jc near gfx_init_80 ++ ++ ; align 4 ++ mov eax,gfx_mem0_start ++ add eax,#3 ++ and eax,#~3 ++ mov gfx_mem0_start,eax ++ ++ call find_file ++ or eax,eax ++ jz near gfx_init_80 ++ ++ push edi ++ push eax ++ add eax,edi ++ call align_it ++ 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 ++ ++ ; setup jump table ++ les bx,gfx_bc_jt ++ ++ seg es ++ mov ax,(bx) ++ mov gfx_bc_init,ax ++ mov gfx_bc_init+2,es ++ ++ seg es ++ mov ax,(bx+2) ++ mov gfx_bc_done,ax ++ mov gfx_bc_done+2,es ++ ++ seg es ++ mov ax,(bx+4) ++ mov gfx_bc_input,ax ++ mov gfx_bc_input+2,es ++ ++ seg es ++ mov ax,(bx+6) ++ mov gfx_bc_menu_init,ax ++ mov gfx_bc_menu_init+2,es ++ ++ seg es ++ mov ax,(bx+8) ++ mov gfx_bc_infobox_init,ax ++ mov gfx_bc_infobox_init+2,es ++ ++ seg es ++ mov ax,(bx+10) ++ mov gfx_bc_infobox_done,ax ++ mov gfx_bc_infobox_done+2,es ++ ++ seg es ++ mov ax,(bx+12) ++ mov gfx_bc_progress_init,ax ++ mov gfx_bc_progress_init+2,es ++ ++ seg es ++ mov ax,(bx+14) ++ mov gfx_bc_progress_done,ax ++ mov gfx_bc_progress_done+2,es ++ ++ seg es ++ mov ax,(bx+16) ++ mov gfx_bc_progress_update,ax ++ mov gfx_bc_progress_update+2,es ++ ++ seg es ++ mov ax,(bx+18) ++ mov gfx_bc_progress_limit,ax ++ mov gfx_bc_progress_limit+2,es ++ ++ seg es ++ mov ax,(bx+20) ++ mov gfx_bc_password_init,ax ++ mov gfx_bc_password_init+2,es ++ ++ seg es ++ mov ax,(bx+22) ++ mov gfx_bc_password_done,ax ++ mov gfx_bc_password_done+2,es ++ ++ ; esi sysconfig data ++ .byte 0x66 ++ mov si,ds ; mov esi,ds ++ shl esi,4 ++ add esi,#gfx_sysconfig ++ ++ farcall(gfx_bc_init) ++ ++ jc gfx_init_80 ++ ++ 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 ++ farcall(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 ++ ++ mov ax,#0xffff ++ xchg ax,par2_timeout ++ ++ ; map 0xffff -> 0 ++ add ax,#1 ++ cmc ++ sbb ax,#0 ++ ++gfx_input_20: ++ .byte 0x66 ++ mov di,ds ; mov edi,ds ++ shl edi,4 ++ add edi,#cmdline ++ mov ecx,#CL_LENGTH ++ movzx eax,ax ++ ++ ; edi buffer (0: no buffer) ++ ; ecx buffer size ++ ; eax timeout value (0: no timeout) ++ ++ farcall(gfx_bc_input) ++ ++ pushf ++ call gfx_set_sysconfig ++ popf ++ jnc gfx_input_50 ++ mov ax,#1 ++gfx_input_50: ++ cmp ax,#1 ++ jz gfx_input_80 ++ ++ call find_boot_image ++ jnc gfx_input_90 ++ ++ .byte 0x66 ++ mov cx,ds ; mov ecx,ds ++ shl ecx,4 ++ lea esi,(ecx+gfx_msg_wrong_image) ++ lea edi,(ecx+cmdline) ++ ++ mov al,#0 ++ call gfx_infobox ++ ++ xor ax,ax ++ jmp gfx_input_20 ++gfx_input_80: ++ push ax ++ call gfx_done ++ pop ax ++gfx_input_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_setup_menu: ++ cmp byte gfx_ok,#0 ++ jz gfx_setup_menu_90 ++ ++ mov si,#DESCR0 ++ mov di,si ++ xor ax,ax ++ mov cx,#IMAGES ++gfx_setup_menu_20: ++ cmp byte (si),#0 ++ jz gfx_setup_menu_30 ++ inc ax ++ add si,#id_size ++ loop gfx_setup_menu_20 ++gfx_setup_menu_30: ++ mov esi,#menu_desc ++ ++ xor ah,ah ++ mov (si+menu_entries),ax ++ ++ mov (si+menu_default),di ++ mov (si+menu_default+2),ds ++ ++ mov (si+menu_ent_list),di ++ mov (si+menu_ent_list+2),ds ++ mov word (si+menu_ent_size),#id_size ++ ++ mov word (si+menu_arg_list),#gfx_args_entry ++ mov (si+menu_arg_list+2),ds ++ mov word (si+menu_arg_size),#1 ++ ++ .byte 0x66 ++ mov ax,ds ; mov eax,ds ++ shl eax,4 ++ add esi,eax ++ ++ farcall(gfx_bc_menu_init) ++gfx_setup_menu_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_infobox: ++ pushad ++ cmp byte gfx_ok,#0 ++ jz gfx_infobox_90 ++ farcall(gfx_bc_infobox_init) ++ xor edi,edi ++ xor eax,eax ++ farcall(gfx_bc_input) ++ farcall(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 ++ farcall(gfx_bc_progress_init) ++gfx_progress_init_90: ++ popad ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_progress_done: ++ pushad ++ cmp byte gfx_ok,#0 ++ jz gfx_progress_done_90 ++ farcall(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 ++ farcall(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 ++ farcall(gfx_bc_progress_limit) ++gfx_progress_limit_90: ++ popad ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; ds:di image descr ++; ++gfx_password: ++ push es ++ pushad ++ cmp byte gfx_ok,#0 ++ stc ++ jz gfx_password_90 ++ push di ++ .byte 0x66 ++ mov cx,ds ; mov ecx,ds ++ shl ecx,4 ++ lea esi,(ecx+gfx_password_buf) ; not used ++ movzx edi,di ++ add edi,ecx ++ farcall(gfx_bc_password_init) ++ .byte 0x66 ++ mov di,ds ; mov edi,ds ++ shl edi,4 ++ add edi,#gfx_password_buf ++ mov ecx,#32 ++ xor eax,eax ++ farcall(gfx_bc_input) ++ .byte 0x66 ++ mov si,ds ; mov esi,ds ++ shl esi,4 ++ add esi,#gfx_password_buf ++ farcall(gfx_bc_password_done) ++ pop di ++ call check_password ++ jnc gfx_password_90 ++ .byte 0x66 ++ mov si,ds ; mov esi,ds ++ shl esi,4 ++ add esi,#gfx_msg_wrong_password ++ xor edi,edi ++ mov al,#0 ++ farcall(gfx_bc_infobox_init) ++ xor edi,edi ++ xor eax,eax ++ farcall(gfx_bc_input) ++ farcall(gfx_bc_infobox_done) ++ stc ++gfx_password_90: ++ popad ++ pop es ++ 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),#0xf ++ pop eax ++ ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; locate the boot image ++; ++; return: ++; bx boot image index ++; CF error (image not found) ++; ++find_boot_image: ++ mov dx,#DESCR0 ++ mov cx,#IMAGES ++ ++ xor bx,bx ++ ++find_boot_image_10: ++ mov si,dx ++ mov di,#cmdline ++find_boot_image_20: ++ mov al,(si) ++ or al,al ++ jz find_boot_image_60 ++ cmp al,(di) ++ jnz find_boot_image_30 ++ inc si ++ inc di ++ jmp find_boot_image_20 ++find_boot_image_30: ++ inc bx ++ add dx,#id_size ++ cmp bx,cx ++ jb find_boot_image_10 ++ ; not found, strip options for fancy error message ++ ++ mov si,#cmdline ++ mov cx,#MAX_IMAGE_NAME+1 ++find_boot_image_40: ++ cmp byte (si),#0x20+1 ++ inc si ++ jb find_boot_image_50 ++ loop find_boot_image_40 ++find_boot_image_50: ++ mov byte (si-1),#0 ++ jmp find_boot_image_80 ++find_boot_image_60: ++ mov al,(di) ++ cmp al,#0x20 ++ ja find_boot_image_30 ++ imul bx,bx,#id_size ++ add bx,#DESCR0 ++ jmp find_boot_image_90 ++find_boot_image_80: ++ stc ++find_boot_image_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; ds:di image descr ++; ++; CF = 0: password valid ++; ++check_password: ++#if defined(SHS_PASSWORDS) ++ mov bp,di ++ mov di,#gfx_password_buf ++ mov si,di ++ push ds ++ pop es ++ mov cx,#32 - 1 ++ xor al,al ++ repne ++ scasb ++ sub cx,#32 - 1 ++ not cx ++ mov bx,cx ++ ++ push ss ++ pop es ++ mov cx,#32 ++ sub sp,cx ++ mov di,sp ++ rep ++ movsb ++ mov si,sp ++ ++ push bp ++ ++ push bx ; length ++ push si ; ss:si password ++ call _shsInit ++ call _shsUpdate ++ call _shsFinal ++ pop si ++ pop bx ++ ++ pop di ++ ++ add di,#id_password_crc ++ mov si,#shs_digest ++ mov cx,#MAX_PW_CRC*4 ++ push ds ++ pop es ++ repe ++ cmpsb ++ je check_pw_50 ++ inc cx ++check_pw_50: ++ add sp,#32 ++ pushad ; clear password buffer ++ mov di,#gfx_password_buf ++ mov cx,#32 ++ xor al,al ++ rep ++ stosb ++ popad ++ cmp cx,#1 ++ cmc ++#endif ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; locate graphics file ++; ++; return: eax: code offset (0 -> no file found) ++; edi: gfx file start ++; ++find_file: ++ mov edi,gfx_mem ++ push edi ++ call gfx_l2so ++ pop bx ++ pop es ++ 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_mem0_start ++ sub ecx,#26 + 12 ; min cpio header + gfx header ++ cmp edi,ecx ++ jae find_file_90 ++ ++ push edi ++ call gfx_l2so ++ pop bx ++ pop es ++ seg es ++ cmp word (bx),#0x71c7 ++ jnz find_file_90 ; no cpio record ++ ++ seg es ++ movzx esi,word (bx+20) ; file name size ++ ++ inc si ++ and si,#~1 ; align ++ ++ seg es ++ mov ecx,(bx+22) ; data size ++ rol ecx,#16 ; get word order right ++ ++ inc ecx ++ and ecx,#~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 ++ seg es ++ cmp dword (bx),#0x0b2d97f00 ; header.magic_id ++ jnz magic_ok_90 ++ ; version 8 ++ seg es ++ cmp byte (bx+4),#8 ; header.version ++ jb magic_ok_90 ++ seg es ++ cmp byte (bx+4),#8 ; header.version ++ ja magic_ok_90 ++ seg es ++ mov eax,(bx+8) ++magic_ok_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; eax address to be aligned ++; ++align_it: ++ push dword gfx_mem ++ pop dword gfx_archive_start ++ neg al ++ and eax,#0x0f ++ jz align_it_90 ++ add gfx_archive_start,eax ++ mov esi,gfx_mem ++ mov ebx,gfx_mem0_start ++ sub ebx,esi ++ sub ebx,#0x0f ++ add esi,ebx ++ dec esi ++ ++ std ++ ++align_it_30: ++ or ebx,ebx ++ jz align_it_60 ++ mov ecx,ebx ++ cmp ebx,#0x8000 ++ jb align_it_40 ++ mov ecx,#0x8000 ++align_it_40: ++ push esi ++ sub ebx,ecx ++ sub (esp),ecx ++ push esi ++ call gfx_l2so ++ pop si ++ add si,#0x8000 ++ sub word (esp),#0x8000 >> 4 ++ pop es ++ mov di,si ++ add di,ax ++ seg es ++ rep ++ movsb ++ pop esi ++ jmp align_it_30 ++align_it_60: ++ ++ cld ++ ++align_it_90: ++ ret ++ ++ +--- lilo.h ++++ lilo.h +@@ -331,7 +331,7 @@ + #define DC_MAGIC 0xf4f2 /* magic number of default cmd. line sector */ + #define DC_MGOFF 0x6b6d /* magic number for disabled line */ + +-#define MAX_MESSAGE 65535 /* maximum message length */ ++#define MAX_MESSAGE 8*64*1024-1 /* maximum message length (512k) */ + #define MAX_MENU_TITLE 37 /* maximum MENU title length */ + + #define NEW_HDR_SIG "HdrS" /* setup header signature */ +--- second.S ++++ second.S +@@ -618,7 +618,8 @@ + seg es + cmp byte ptr (si),#0 ! empty ? + je iloop ! yes -> enter interactive mode +- jmp niloop ! enter non-interactive mode ++niloop0: ++ br niloop ! enter non-interactive mode + + ! No external parameters after timeout -> boot first image + +@@ -626,7 +627,7 @@ + pop es + mov si,#DFLCMD+2 ! default command line ? + cmp byte ptr (si),#0 +- jne niloop ! yes -> use it ++ jne niloop0 ! yes -> use it + mov ax,nodfl ! no idea how to tell as86 to do jmp (addr) :-( + jmp ax ! fall through + +@@ -634,16 +635,23 @@ + ! Command input processor + + iloop: +-#if defined(MENU) || defined(BITMAP) ++#ifdef BITMAP + call menu_setup + #endif + + #ifndef BITMAP ++ cmp byte gfx_ok,#0 ++ jnz iloop_gfx ++ ++ ; load message before doing anything else ++ ; the graphics/text stuff is mixed in a rather messy way... ++ + ;; BEG_FS + ;; SEG_FS ! message disabled ? + cmp word ptr par2_msg_len,#0 ;MSG_OFF+SSDIFF,#0 + ;; END_FS +- je nomsg ! yes -> skip this ++ ; _must_ be 'jz'! ++ jz iloop_20 ! yes -> skip this + call crlf + ;BEG_FS + ;SEG_FS ! load the message file +@@ -657,13 +665,96 @@ + call sread + call loadfile + ++ ; es:bx points to file end ++ movzx ebx,bx ++ xor edi,edi ++ mov di,es ++ shl edi,4 ++ add edi,ebx ++ sub edi,#SYSSEG * 16 ++ ++ ; edi -> message file size ++ + xor bx,bx ! set the terminating NUL and disable further + ! messages + xchg bx,par2_msg_len ;MSG_OFF+SSDIFF + + push #SYSSEG + pop ds +- mov byte ptr (bx),#0 ++ ++ cmp word ptr 0,#0x71c7 ; cpio header ++ jz iloop_cpio ++ ++ cmp dword ptr 0,#0x0b2d97f00 ; magic header ++ ; _must_ be 'jnz'! ++ jnz iloop_10 ++ ++iloop_cpio: ++ ++ push cs ++ pop ds ++ ++ ; graphical message ++ ++ call gfx_init ++ push cs ++ pop es ++ cmp byte gfx_ok,#0 ++ jz iloop ++ call gfx_setup_menu ++iloop_gfx: ++ push cs ++ pop es ++ call gfx_input ++ cmp ax,#1 ++ jz iloop ; text mode ++ mov gfx_tmp,bx ++ jmp near scan_cmdline ++ ++ ; normal text message ++iloop_10: ++ ; keep the zero flag! ++ mov byte ptr (bx),#0 ++ push cs ++ pop ds ++ ++iloop_20: ++#ifdef MENU ++ pushf ++ call menu_setup ++ popf ++#endif ++ jnz totxt ++ ++ mov ax,showit ++ mov dx,showit+2 ++ mov bx,ax ++ or bx,dx ++ jz iloop_40 ++ push ds ++ shl dx,12 ++ mov bx,ax ++ and bx,#0xf ++ shr ax,4 ++ add ax,dx ++ add ax,#SYSSEG ++ mov ds,ax ++ call say ++ pop ds ++ xor ax,ax ++ mov showit,ax ++ mov showit+2,ax ++iloop_40: ++ ++ jmp nomsg ++ ++showit: ++ .long 0 ++ ++totxt: ++ push #SYSSEG ++ pop ds ++ + xor bx,bx ! display the message + call say + +@@ -699,12 +790,6 @@ + mov al,(si) + inc si + jmp gotinp ! go on +- +-tolist: +-#ifdef BITMAP +- call menu_exit +-#endif +- br list ! ... + + kbinp: + mov cx,#brto ! get a key +@@ -733,7 +818,7 @@ + cmp al,#8 ! BS ? + je todelch ! yes -> erase one character + cmp al,#13 ! CR ? +- je cr ! yes -> go on ++ je near cr ! yes -> go on + cmp al,#127 ! DEL ? + je todelch ! yes -> erase one character + ja input ! non-printable -> ignore it +@@ -783,6 +868,11 @@ + + todelch:br delch ! ... + todell: br delline ! ... ++tolist: ++#ifdef BITMAP ++ call menu_exit ++#endif ++ br list ! ... + + ! End of input, process the command line + +@@ -825,6 +915,8 @@ + or al,al ! at end ? + jnz cpsav ! no -> go on + ++ ++scan_cmdline: + cmp bx,#cmdline ! empty line ? + je notrspc ! yes -> boot first image + cmp byte ptr (bx-1),#32 ! trailing space ? +@@ -882,6 +974,11 @@ + je chkvga ! yes -> look for options again + or al,al ! at end ? + jnz vsknb ! no -> go on ++ ++ mov bx,gfx_tmp ++ cmp byte gfx_ok,#0 ++ jnz near boot ++ + call crlf ! write CR/LF + cmp di,#cmdline+1 ! empty line ? + emptyl: je bfirst ! yes -> boot first image +@@ -1073,6 +1170,16 @@ + ;; SEG_FS + mov word ptr par2_timeout,#0xffff ; cancel timeout + ;; END_FS ++ ++ cmp byte gfx_ok,#0 ++ jz dopw_nogfx ++ mov di,bx ++ call gfx_password ++ pop bx ++ jnc toboot ++ jmp near iloop ++dopw_nogfx: ++ + mov bx,#msg_pw ! display a prompt + call say + +@@ -1450,7 +1557,9 @@ + + ! Boot the image BX points to + +-doboot: mov byte ptr prechr,#61 ! switch to equal sign ++doboot: ++ call gfx_done ++ mov byte ptr prechr,#61 ! switch to equal sign + push bx ! save image descr + mov bx,#msg_l ! say hi + call say +@@ -3274,6 +3383,8 @@ + + + ++#include "gfxlogo.S" ++ + #ifdef SHS_PASSWORDS + #include "shs3.S" + #endif +@@ -3421,6 +3532,8 @@ + jmp vgaput1 + #else + xor cx,cx ++ mov bh,ch ++ mov bl,#10 ; bx: base (_not_ bl!) + mov ah,cl + test byte ptr (si),#0xff ! no value ? + jz vgaerr ! yes -> error +@@ -3429,17 +3542,47 @@ + jz vgaput ! yes -> done + cmp al,#32 + je vgaput +- cmp al,#48 ! is it a digit ? (0x30=48="0") +- jb vgaerr ! no -> error +- cmp al,#57 ! 57=0x39="9" +- ja vgaerr +- sub al,#48 ! cx = cx*10+al-'0' +- imul cx,#10 ++ cmp al,#0x61 ++ jb vgadig_10 ++ sub al,#0x20 ; upper case ++vgadig_10: ++ or cx,cx ++ jnz vgadig_20 ++ cmp al,#0x58 ++ jnz vgadig_20 ++ mov bl,#16 ; hex ++ jmp vgadig ++vgadig_20: ++ cmp al,#0x3a ++ jb vgadig_30 ++ sub al,#7 ++vgadig_30: ++ sub al,#0x30 ++ jb vgaerr ; not a digit ++ cmp al,bl ++ jae vgaerr ; larger than current base ++ imul cx,bx + add cx,ax + jnc vgadig ! next one + #endif + +-vgaerr: mov bx,#msg_v ! display an error message ++vgaerr: ++ mov bx,#msg_v ! display an error message ++ cmp byte gfx_ok,#0 ++ jz vgaerr_txt ++ lea esi,(bx+1) ; skip initial NL ++ .byte 0x66 ++ mov di,ds ; mov edi,ds ++ shl edi,4 ++ add esi,edi ++ xor edi,edi ++ mov al,#0 ++ mov msg_v1,al ; drop final NL ++ call gfx_infobox ++ mov byte msg_v1,#10 ; put it back ++ stc ++ ret ++vgaerr_txt: + call say + /* ifdef HIGHMEM_MAX */ + xor eax,eax +@@ -3583,8 +3726,10 @@ + xor dx,dx + mov cx,#10 ! default radix is decimal + cmp byte ptr (si),#0x39 +- ja s2lbad ! error if > '9' ++ /* Those were changed to jna and previously */ ++ ja s2lbad ! error if > '9' + cmp byte ptr (si),#0x30 ! == '0'? ++ /* Likewise */ + jb s2lbad ! error if < '0' + jne s2lnext + inc si +@@ -3890,8 +4035,8 @@ + + msg_v: .byte 10 + .ascii "Valid vga values are ASK, NORMAL, EXTENDED or a " +- .ascii "decimal number." +- .byte 10,0 ++ .ascii "number." ++msg_v1: .byte 10,0 + + msg_pks:.byte 10 + .ascii "Invalid hexadecimal number. - Ignoring remaining items." diff --git a/patches/syslinux-3.63.diff b/patches/syslinux-3.63.diff new file mode 100644 index 0000000..ab9d657 --- /dev/null +++ b/patches/syslinux-3.63.diff @@ -0,0 +1,2352 @@ +--- Makefile ++++ Makefile +@@ -146,15 +146,16 @@ + $(PERL) genhash.pl < keywords > kwdhash.gen + + # Standard rule for {isolinux,isolinux-debug}.bin +-iso%.bin: iso%.asm kwdhash.gen version.gen ++iso%.bin: iso%.asm kwdhash.gen version.gen gfxboot.inc + $(NASM) $(NASMOPT) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=$(@:.bin=.map) -l $(@:.bin=.lsr) -o $@ $< + $(PERL) lstadjust.pl $(@:.bin=.lsr) $(@:.bin=.map) $(@:.bin=.lst) + $(PERL) checksumiso.pl $@ + $(PERL) checkov.pl $(@:.bin=.map) $@ ++ -./add_crc $@ + + # Standard rule for {ldlinux,pxelinux,extlinux}.bin +-%.bin: %.asm kwdhash.gen version.gen ++%.bin: %.asm kwdhash.gen version.gen gfxboot.inc + $(NASM) $(NASMOPT) -f bin -DDATE_STR="'$(DATE)'" -DHEXDATE="$(HEXDATE)" \ + -DMAP=$(@:.bin=.map) -l $(@:.bin=.lsr) -o $@ $< + $(PERL) lstadjust.pl $(@:.bin=.lsr) $(@:.bin=.map) $(@:.bin=.lst) +--- README.gfxboot ++++ README.gfxboot +@@ -0,0 +1,41 @@ ++Graphical boot screen ++===================== ++ ++ syslinux/isolinux support a graphical boot screen using VESA BIOS ++ extensions. (Note that this is different from the graphics support that ++ syslinux comes with). ++ ++ To use it you have to prepare a special boot logo file and put a line like ++ this into syslinux.cfg/isolinux.cfg: ++ ++ gfxboot foo ++ ++ The tools to create 'foo' 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 overlaps the comboot loading area. ++ ++ If you encouter problems with the graphics code, hold down SHIFT while ++ syslinux starts. This will put it into 'failsafe' mode that lets you ++ interactively skip critical parts (like monitor detection). ++ ++ ++ ++Spread boot images over several floppy disks (syslinux) ++======================================================= ++ ++ You can prepare boot disks with a file system that spans several disks. ++ The 'mkbootdisk' script from the openSUSE project can create a suitable ++ file system. ++ ++ syslinux will ask you for disk changes if necessary. To enable this ++ feature, use ++ ++ disksize <size_of_single_disk_in_sectors> ++ ++ 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). ++ +--- abort.inc ++++ abort.inc +@@ -21,6 +21,11 @@ + ; abort_check: let the user abort with <ESC> or <Ctrl-C> + ; + abort_check: ++%ifdef WITH_GFX ++ ; don't ++ cmp byte [gfx_ok],0 ++ jnz .ret1 ++%endif + call pollchar + jz .ret1 + pusha +--- add_crc ++++ add_crc +@@ -0,0 +1,57 @@ ++#! /usr/bin/perl ++ ++use integer; ++ ++# for isolinux ++# ++# Ensure checksum over (first sector - 64 bytes) [internally: FirstSecSum] ++# is 0 by adjusting the variable csum_value. ++# ++# Though isolinux checks the integrity with a separate checksum after all ++# data has been loaded this does not help with BIOSes that don't get even ++# the first 2k right. Hence this additional check. :-( ++# ++ ++$file = shift; ++$list = "$file"; ++$list =~ s/\.bin$/.lsr/; ++ ++open F, $list; ++ ++while(<F>) { ++ 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; ++ +--- com32/libutil/get_key.c ++++ com32/libutil/get_key.c +@@ -42,6 +42,10 @@ + #include <getkey.h> + #include <libutil.h> + ++#ifndef CLK_TCK ++# define CLK_TCK __sysconf(2) ++#endif ++ + struct keycode { + int code; + int seqlen; +--- com32/modules/cpuid.c ++++ com32/modules/cpuid.c +@@ -254,7 +254,7 @@ + + static int smp_scan_config (unsigned long base, unsigned long length) + { +- unsigned long *bp = base; ++ unsigned long *bp = (unsigned long *) base; + struct intel_mp_floating *mpf; + + // printf("Scan SMP from %p for %ld bytes.\n", bp,length); +--- com32/samples/keytest.c ++++ com32/samples/keytest.c +@@ -25,6 +25,10 @@ + #include <consoles.h> /* Provided by libutil */ + #include <getkey.h> + ++#ifndef CLK_TCK ++# define CLK_TCK __sysconf(2) ++#endif ++ + static void cooked_keys(void) + { + int key; +--- conio.inc ++++ conio.inc +@@ -49,6 +49,14 @@ + ; Assumes CS == DS == ES. + ; + get_msg_file: ++%ifdef WITH_GFX ++ ; don't load if graphics code is active ++ cmp byte [gfx_ok],0 ++ jz .nogfx ++ jmp close ++.nogfx: ++%endif ++ + mov byte [TextAttribute],07h ; Default grey on white + mov byte [DisplayMask],07h ; Display text in all modes + call msg_initvars +--- doc/syslinux.txt ++++ doc/syslinux.txt +@@ -230,7 +230,7 @@ + Append nothing. APPEND with a single hyphen as argument in a + LABEL section can be used to override a global APPEND. + +- LOCALBOOT type [ISOLINUX, PXELINUX] ++ LOCALBOOT type [ISOLINUX, SYSLINUX, PXELINUX] + On PXELINUX, specifying "LOCALBOOT 0" instead of a "KERNEL" + option means invoking this particular label will cause a local + disk boot instead of booting a kernel. +@@ -244,12 +244,11 @@ + UNDI or PXE stacks are, don't worry -- you don't want them, + just specify 0. + +- On ISOLINUX, the "type" specifies the local drive number to +- boot from; 0x00 is the primary floppy drive and 0x80 is the +- primary hard drive. The special value -1 causes ISOLINUX to +- report failure to the BIOS, which, on recent BIOSes, should +- mean that the next boot device in the boot sequence should be +- activated. ++ On ISOLINUX and SYSLINUX, the "type" specifies the local drive ++ number to boot from; 0x00 is the primary floppy drive and 0x80 is ++ the primary hard drive. The special value -1 causes them to report ++ failure to the BIOS, which, on recent BIOSes, should mean that the ++ next boot device in the boot sequence should be activated. + + IMPLICIT flag_val + If flag_val is 0, do not load a kernel image unless it has been +--- gfxboot.inc ++++ gfxboot.inc +@@ -0,0 +1,1355 @@ ++ section .text ++ ++load_gfx_msg db 'Loading...', 0 ++no_msg db 0 ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; do a reboot ++; ++do_reboot: ++ call gfx_done ++ mov word [472h],1234h ++ push word 0ffffh ++ push word 0 ++ retf ++ int 19h ++ jmp $ ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; 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 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; read gfx data ++get_gfx_file: ++ push si ++ mov si,load_gfx_msg ++ call cwritestr ++ pop si ++ mov word [gfx_mem_start_seg],first_free_seg ++ push ds ++ push 40h ++ pop ds ++ mov bx,[13h] ; mem size in kb ++ pop ds ++ shl bx,6 ++ mov word [gfx_mem_end_seg],bx ++ ++ call gfx_init ; Load and display file ++ cmp byte [gfx_ok],0 ++ jz .done ++ mov si,crlf_msg ++ call cwritestr ++.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 ++ xor edx,edx ++ call getlinsec.jmp ++ 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 ++ ++ ++; 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 ++ xor edx,edx ++ call getlinsec.jmp ++ pop bx ++ mov eax,[es:bx+27h] ++ sub eax,[bsVolumeID] ++ 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 ++ ++ ++bsVolumeID equ bsHugeSectors+7 ++ ++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 ++ ++DiskSize dw 0 ; unlimited ++CurrentDisk db 0 ; current disk ++ ++clrln_msg db 0dh, ' ', 0dh, 0 ++ ++ ++cache_metadata: ++ cmp word [DiskSize],0 ++ jz cache_md_90 ++ ++ mov eax,[FAT] ++ mov ecx,[bxFATsecs] ++cache_md_20: ++ push eax ++ push cx ++ call getcachesector ++ pop cx ++ pop eax ++ inc eax ++ loop cache_md_20 ++ ++ mov eax,[RootDir] ++cache_md_40: ++ push eax ++ call getcachesector ++ pop eax ++ call nextsector ++ jnc cache_md_40 ++ ++cache_md_90: ++ ret ++ ++ ++%endif ++ ++ ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; gfx stuff ++; ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++ ++; != 0 -> graphics active ++gfx_ok db 0 ++gfx_cwritestr_old db 0c3h ; 'ret' ++gfx_cpio_swab db 0 ++gfx_cd_changed db 0 ++ ++gfx_mem_start_seg dw 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_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 ++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 ++ ++; 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 (52 bytes) ++gfx_sysconfig equ $ ++gfx_bootloader db 1 ; 0: boot loader type (0: lilo, 1: syslinux, 2: grub) ++gfx_sector_shift db SECTOR_SHIFT ; 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 $ ++ ++gfx_slash db '/', 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,[DriveNumber] ++ mov [gfx_boot_drive],al ++ ++%if IS_ISOLINUX ++ mov ah,2 ++%else ++ mov ah,0 ++%endif ++ cmp al,80h ; floppy ? ++ jae gfx_get_sysconfig_20 ++ mov ah,1 ++gfx_get_sysconfig_20: ++ ++ mov [gfx_media_type],ah ++ ++ mov [gfx_bootloader_seg],cs ++ ++ 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 ++ ++ test byte [KbdFlags],3 ++ jz gfx_init_10 ++ mov byte [gfx_failsafe],1 ++ call ask_user ++gfx_init_10: ++ ++ test byte [gfx_failsafe],2 ++ jnz gfx_init_80 ++ ++ call highmemsize ++ ++ ; setup extended memory areas ++ pusha ++ mov eax,[HighMemSize] ++ mov [gfx_bios_mem_size],eax ++ mov eax,[VKernelEnd] ++ shr eax,20 ++ cmp ax,16 ++ jb gfx_init_40 ; at least 16MB ++ 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 ++gfx_init_40: ++ popa ++ ++ cld ++ ++ movzx ebx,word [gfx_mem_start_seg] ++ shl ebx,4 ++ jz gfx_init_80 ++ ++ movzx ecx,word [gfx_mem_end_seg] ++ shl ecx,4 ++ jz gfx_init_80 ++ ++ cmp ecx,ebx ++ jbe gfx_init_80 ++ ++ ; define our memory area ++ ; gfx_mem _must_ be 16-byte aligned ++ mov dword [gfx_mem],ebx ++ mov dword [gfx_mem0_start],ebx ++ mov dword [gfx_mem0_end],ecx ++ ++ call gfx_read_file ++ cmp byte [gfx_ok],0 ++ jz near gfx_init_90 ++ ++ 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 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 esi,cs ++ shl esi,4 ++ add esi,gfx_sysconfig ++ call far [gfx_bc_init] ++ jc gfx_init_80 ++ ++ mov byte [gfx_ok],1 ++ ++ ; turn off 'cwritestr' ++ mov al,[cwritestr] ++ cmp al,0c3h ++ jz gfx_init_90 ++ mov [gfx_cwritestr_old],al ++ mov byte [cwritestr],0c3h ++ ++ 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: ++ push ax ++ cmp byte [gfx_ok],0 ++ jz gfx_done_90 ++ call far [gfx_bc_done] ++ mov byte [gfx_ok],0 ++ ++ ; reactivate 'cwritestr' ++ mov al,[gfx_cwritestr_old] ++ cmp al,0c3h ++ jz gfx_done_90 ++ mov [cwritestr],al ++gfx_done_90: ++ pop ax ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_input: ++ cmp byte [gfx_ok],0 ++ jz gfx_input_90 ++ cmp byte [gfx_save_area1_used],0 ++ jz gfx_input_10 ++ ; recover saved menu layout, gfxboot has references into it ++ pushad ++ mov esi,[gfx_save_area1] ++ mov edi,gfx_menu_seg << 4 ++ mov ecx,10000h ++ call bcopy ++ popad ++gfx_input_10: ++ call far [gfx_bc_input] ++ 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 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; es:di string ++; return: ++; cx length ++gfx_strlen: ++ mov cx,-1 ++ mov al,0 ++ repnz scasb ++ not cx ++ dec cx ++ ret ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_setup_menu: ++ push es ++ cmp byte [gfx_ok],0 ++ jz gfx_setup_menu_90 ++ ++ mov dword [menu_desc+menu_default],gfx_menu_seg << 16 ++ ++ push ds ++ pop es ++ mov si,default_cmd ++ mov di,trackbuf ++ call mangle_name ++ mov si,trackbuf ++ les di,[menu_desc+menu_default] ++ call unmangle_name ++ inc di ++ ++ mov [menu_desc+menu_ent_list],di ++ mov [menu_desc+menu_ent_list+2],es ++ mov [menu_desc+menu_arg_list],di ++ mov [menu_desc+menu_arg_list+2],es ++ ++ ; first, count entries and find max kernel and append length ++ ++ push ds ++ pop es ++ ++ mov esi,[HighMemSize] ++ jmp gfx_setup_menu_20 ++gfx_setup_menu_10: ++ mov di,VKernelBuf ++ call rllunpack ++ ++ ; count only non empty entries ++ cmp byte [VKernelBuf],0 ++ jz gfx_setup_menu_20 ++ ++ inc word [menu_desc+menu_entries] ++ ++ push esi ++ mov si,VKernelBuf ++ mov di,KernelCName ++ push di ++ call unmangle_name ++ pop di ++ pop esi ++ ++ call gfx_strlen ++ ++ cmp cx,[menu_desc+menu_ent_size] ++ jbe gfx_setup_menu_15 ++ mov [menu_desc+menu_ent_size],cx ++gfx_setup_menu_15: ++ mov ax,[VKernelBuf+vk_appendlen] ++ cmp ax,[menu_desc+menu_arg_size] ++ jbe gfx_setup_menu_20 ++ mov [menu_desc+menu_arg_size],ax ++ ++gfx_setup_menu_20: ++ cmp esi,[VKernelEnd] ++ ja gfx_setup_menu_10 ++ ++ inc word [menu_desc+menu_ent_size] ++ mov ax,[menu_desc+menu_ent_size] ++ inc ax ++ add [menu_desc+menu_arg_size],ax ++ ++ ; ...and again, but this time copy entries ++ ++ mov word [menu_desc+menu_entries],0 ++ ++ mov esi,[HighMemSize] ++ jmp gfx_setup_menu_60 ++gfx_setup_menu_30: ++ mov di,VKernelBuf ++ call rllunpack ++ ++ ; count only non empty entries ++ cmp byte [VKernelBuf],0 ++ jz gfx_setup_menu_60 ++ ++ mov di,[menu_desc+menu_arg_list] ++ add di,[menu_desc+menu_arg_size] ++ jc gfx_setup_menu_60 ++ ++ inc word [menu_desc+menu_entries] ++ ++ push esi ++ ++ mov si,VKernelBuf ++ mov di,KernelCName ++ push di ++ call unmangle_name ++ pop si ++ mov cx,[menu_desc+menu_ent_size] ++ les di,[menu_desc+menu_arg_list] ++ ++ rep movsb ++ ++ mov cx,[VKernelBuf+vk_appendlen] ++ mov si,VKernelBuf+vk_append ++ rep movsb ++ mov byte [es:di],0 ++ ++ pop esi ++ ++ push ds ++ pop es ++ ++ mov ax,[menu_desc+menu_arg_size] ++ add [menu_desc+menu_arg_list],ax ++ ++gfx_setup_menu_60: ++ cmp esi,[VKernelEnd] ++ ja gfx_setup_menu_30 ++ ++ mov ax,[menu_desc+menu_ent_size] ++ mov bx,[menu_desc+menu_arg_size] ++ mov [menu_desc+menu_ent_size],bx ++ add ax,[menu_desc+menu_ent_list] ++ mov [menu_desc+menu_arg_list],ax ++ ++ mov esi,ds ++ shl esi,4 ++ add esi,menu_desc ++ ++ call far [gfx_bc_menu_init] ++ ++ ; save menu structure, gfxboot uses references into it ++ mov edi,[gfx_save_area1] ++ or edi,edi ++ jz gfx_setup_menu_90 ++ mov esi,gfx_menu_seg << 4 ++ mov ecx,10000h ++ call bcopy ++ mov byte [gfx_save_area1_used],1 ++ ++gfx_setup_menu_90: ++ pop es ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++gfx_infobox: ++ pushad ++ cmp byte [gfx_ok],0 ++ jz gfx_infobox_90 ++ mov ecx,ds ++ shl ecx,4 ++ movzx esi,si ++ movzx edi,di ++ or si,si ++ jz gfx_infobox_20 ++ add esi,ecx ++gfx_infobox_20: ++ or di,di ++ jz gfx_infobox_30 ++ add edi,ecx ++gfx_infobox_30: ++ call far [gfx_bc_infobox_init] ++ xor edi,edi ++ xor eax,eax ++ 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 ++ 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 edi,ds ++ shl edi,4 ++ add edi,gfx_password_buf ++ mov ecx,32 ++ xor eax,eax ++ call far [gfx_bc_input] ++ mov esi,ds ++ shl esi,4 ++ add esi,gfx_password_buf ++ call far [gfx_bc_password_done] ++ jnc gfx_password_90 ++ mov esi,ds ++ shl esi,4 ++ add esi,gfx_msg_wrong_password ++ xor edi,edi ++ mov al,0 ++ call far [gfx_bc_infobox_init] ++ xor edi,edi ++ xor eax,eax ++ 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 [gfx_archive_end],edx ++ mov eax,[gfx_mem0_start] ++ lea eax,[eax+edx+0fh] ; add space for alignment ++ cmp eax,[gfx_mem0_end] ; max. length ++ ja near gfx_read_file_90 ++ mov [gfx_mem0_start],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] ++ 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 ++ ++ 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_mem0_start] ++ 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 ++ jz find_file_30 ; normal cpio record ++ cmp word [es:bx],0c771h ; maybe byte-swapped? ++ jnz find_file_90 ; no cpio record ++ mov byte [gfx_cpio_swab],1 ++ ++find_file_30: ++ mov ax,[es:bx+20] ; file name size ++ call cpio_swab ++ movzx esi,ax ++ ++ inc si ++ and si,~1 ; align ++ ++ mov eax,[es:bx+22] ; data size ++ call cpio_swab ++ rol eax,16 ; get word order right ++ call cpio_swab ++ 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_90 ++ ++ add edi,ecx ++ jmp find_file_20 ++ ++find_file_90: ++ ret ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; byte-swap cpio data if appropriate ++; ++; ax: word to swap ++; ++; return: ax: swapped if [gfx_cpio_swab], otherwise same as input ++; ++cpio_swab: ++ cmp byte [gfx_cpio_swab],0 ++ jz cpio_swab_90 ++ xchg ah,al ++ ++cpio_swab_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],8 ; 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_archive_start] ++ neg al ++ and eax,byte 0fh ++ jz align_it_90 ++ add [gfx_archive_start],eax ++ mov esi,[gfx_mem] ++ mov ebx,[gfx_mem0_start] ++ 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 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; Ask user whether to continue. ++; ++; don't change regs ++; ++ask_user: ++ pushad ++ ++ mov si,failsafe_msg_0 ++ call cwritestr ++ ++ mov dx,2 ++ mov si,failsafe_msg_1 ++ call ask_question ++ ++ test byte [gfx_failsafe],2 ++ jnz ask_user_90 ++ ++ mov dx,4 ++ mov si,failsafe_msg_2 ++ call ask_question ++ ++ask_user_90: ++ ++ popad ++ ret ++ ++ ++; si: text ++; dh: 'yes'-mask ++; dl: 'no'-mask ++ask_question: ++ push dx ++ call cwritestr ++ mov si,failsafe_msg_q ++ call cwritestr ++ pop dx ++ ++ask_question_20: ++ push dx ++ mov ah,0 ++ int 16h ++ pop dx ++ ++ cmp al,13 ++ jnz ask_question_30 ++ mov al,'y' ++ask_question_30: ++ or al,20h ; force lower case ++ ++ cmp al,'y' ++ jz ask_question_40 ++ cmp al,'n' ++ jnz ask_question_20 ++ or byte [gfx_failsafe],dl ++ jmp ask_question_50 ++ask_question_40: ++ or byte [gfx_failsafe],dh ++ask_question_50: ++ ++ mov si,failsafe_key ++ mov [si],al ++ call cwritestr ++ ++ ret ++ ++failsafe_msg_q db ' (y/n)? y', 8, 0 ++ ++failsafe_msg_0 db 13, 10, 10, 10, 0 ++failsafe_msg_1 db 'Load boot graphics', 0 ++failsafe_msg_2 db 'Detect display size', 0 ++ ++failsafe_key db 0, 13, 10, 0 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++; 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 ++ ++ ++; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ++; ++cb_table dw cb_status ++ dw cb_fopen ++ dw cb_fread ++ dw cb_getcwd ++ dw cb_chdir ++ dw cb_readsector ++cb_len equ ($-cb_table)/2 ++ ++f_handle dw 0 ++f_size dd 0 ++fname_buf times 64 db 0 ++fname_buf_len equ $ - fname_buf ++ ++ ++gfx_cb: ++ push cs ++ pop ds ++ ++ cmp al,cb_len ++ jae gfx_cb_80 ++ ++ movzx bx,al ++ add bx,bx ++ call word [bx+cb_table] ++ jmp gfx_cb_90 ++ ++gfx_cb_80: ++ mov al,0ffh ++gfx_cb_90: ++ 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: ++ mov si,fname_buf ++ mov di,VGAFileMBuf ; we just need some space ++ push ds ++ pop es ++ push di ++ call mangle_name ++ pop di ++ call searchdir ++ xchg ax,bx ++ mov al,1 ++ jz cb_fopen_90 ++ mov [f_handle],si ++ mov cx,dx ++ shl ecx,16 ++ mov cx,bx ++ mov [f_size],ecx ++cb_fopen_80: ++ xor al,al ++cb_fopen_90: ++ ret ++ ++ ++; Read next chunk. ++; ++; return: ++; edx buffer address (linear) ++; ecx data length (< 64k) ++; ++cb_fread: ++ cmp dword [f_size],0 ++ jz cb_fread_80 ++ push cs ++ pop es ++ mov bx,trackbuf ++ mov cx,[BufSafe] ++ mov si,[f_handle] ++ call getfssec ++ mov [f_handle],si ++ mov ecx,[f_size] ++ movzx edx,word [BufSafeBytes] ++ cmp ecx,edx ++ jbe cb_fread_50 ++ mov ecx,edx ++cb_fread_50: ++ sub [f_size],ecx ++ mov edx,cs ++ shl edx,4 ++ add edx,trackbuf ++ ++cb_fread_80: ++ xor al,al ++cb_fread_90: ++ ret ++ ++ ++; Return current working directory. ++; ++; return: ++; edx filename ++; ++cb_getcwd: ++ mov edx,cs ++ shl edx,4 ++%if IS_ISOLINUX ++ add edx,isolinux_dir ++%else ++ add edx,gfx_slash ++%endif ++ xor al,al ++ ret ++ ++ ++; Set current working directory. ++; ++cb_chdir: ++%if IS_ISOLINUX ++ ++ push cs ++ pop es ++ mov si,fname_buf ++ mov di,isolinux_dir ++cb_chdir_20: ++ lodsb ++ stosb ++ or al,al ++ jz cb_chdir_60 ++ cmp di,config_name - 1 ++ jb cb_chdir_20 ++ xor al,al ++ stosb ++cb_chdir_60: ++ call get_fs_structures ++ ++%endif ++ xor al,al ++ ret ++ ++ ++; read sector ++; ++; edx sector ++; ++; return: ++; edx buffer (linear address) ++; ++; Note: does not return on error! ++; ++cb_readsector: ++ mov eax,edx ++ push ds ++ pop es ++ mov bx,trackbuf ++ call getonesec ++ mov edx,ds ++ shl edx,4 ++ add edx,trackbuf ++ xor al,al ++ ret ++ +--- isolinux.asm ++++ isolinux.asm +@@ -19,6 +19,10 @@ + ; **************************************************************************** + + %define IS_ISOLINUX 1 ++ ++%define WITH_GFX 1 ++; %define DEBUG_DISKIO ++ + %include "head.inc" + + ; +@@ -70,6 +74,8 @@ + real_mode_seg equ 2000h + xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem + comboot_seg equ real_mode_seg ; COMBOOT image loading zone ++gfx_menu_seg equ 3000h ; temporary storage to setup menu ++first_free_seg equ 4000h ; end of isolinux used memory + + ; + ; File structure. This holds the information for each currently open file. +@@ -259,6 +265,21 @@ + mov [FirstSecSum],edi + + mov [DriveNumber],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 try a BIOS update.', 13, 10, 0 ++ align 4 ++csum_value dd 0 ++bios_ok: ++ + %ifdef DEBUG_MESSAGES + mov si,startup_msg + call writemsg +@@ -283,6 +304,9 @@ + ; Other nonzero fields + inc word [dsp_sectors] + ++%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 +@@ -303,6 +327,8 @@ + call crlf + %endif + ++%endif ++ + found_drive: + ; Alright, we have found the drive. Now, try to find the + ; boot file itself. If we have a boot info table, life is +@@ -427,6 +453,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 + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +@@ -618,6 +647,7 @@ + mov si,trysbm_msg + call writemsg + jmp .found_drive ; Pray that this works... ++%endif + + fatal_error: + mov si,nothing_msg +@@ -694,10 +724,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] +@@ -724,15 +761,78 @@ + ; 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] + call int13 ++ 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 +- dec byte [RetryCount] ++ ++%if 0 ++ ; eject currently not supported - doesn't work anyway with ++ ; most BIOSes ++ ++ 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 ++%endif ++.noeject: ++ ++ dec byte [RetryCount] + jz .real_error + push ax + mov al,[RetryCount] +@@ -774,6 +874,17 @@ + ; + kaboom: + RESET_STACK_AND_SEGS AX ++ ++ 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 +@@ -825,6 +936,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 ++ + alignb 4, db 0 + MaxTransfer dw 32 ; Max sectors per transfer + +@@ -882,6 +996,9 @@ + ; (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 +@@ -907,10 +1024,15 @@ + ; Look for an isolinux directory, and if found, + ; make it the current directory instead of the root + ; directory. ++ ++ cmp byte [gfx_ok],0 ; don't look at both ++ jnz .gfx ++ + mov di,boot_dir ; Search for /boot/isolinux + mov al,02h + call searchdir_iso + jnz .found_dir ++.gfx: + mov di,isolinux_dir + mov al,02h ; Search for /isolinux + call searchdir_iso +@@ -931,6 +1053,9 @@ + call crlf + %endif + .no_isolinux_dir: ++ ret ++ ++get_fs_struct_done: + + ; + ; Locate the configuration file +@@ -1096,6 +1221,9 @@ + ; 0xFFFF in case we should execute INT 18h ("next device.") + ; + local_boot: ++%ifdef WITH_GFX ++ call gfx_done ++%endif + call vgaclearmode + lss sp,[cs:Stack] ; Restore stack pointer + xor dx,dx +@@ -1113,7 +1241,7 @@ + xor dh,dh + push dx + xor ax,ax ; Reset drive +- call xint13 ++ int 13h ; we don't care about errors here... + mov ax,0201h ; Read one sector + mov cx,0001h ; C/H/S = 0/0/1 (first sector) + mov bx,trackbuf +@@ -1488,6 +1616,9 @@ + %include "rawcon.inc" ; Console I/O w/o using the console functions + %include "adv.inc" ; Auxillary Data Vector + ++%include "gfxboot.inc" ; add gfx things ++ ++ + ; ----------------------------------------------------------------------------- + ; Begin data section + ; ----------------------------------------------------------------------------- +@@ -1499,6 +1630,7 @@ + default_len equ ($-default_str) + boot_dir db '/boot' ; /boot/isolinux + isolinux_dir db '/isolinux', 0 ++zb 64 + config_name db 'isolinux.cfg', 0 + err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 + +--- keywords ++++ keywords +@@ -42,3 +42,5 @@ + f10 + f11 + f12 ++gfxboot ++disksize +--- keywords.inc ++++ keywords.inc +@@ -90,8 +90,15 @@ + %if IS_PXELINUX + keyword ipappend, pc_ipappend + %endif +-%if IS_PXELINUX || IS_ISOLINUX ++%if IS_PXELINUX || IS_ISOLINUX || IS_SYSLINUX + keyword localboot, pc_localboot + %endif + ++%ifdef WITH_GFX ++ keyword gfxboot, pc_filecmd, get_gfx_file ++%if IS_SYSLINUX ++ keyword disksize, pc_disksize, DiskSize ++%endif ++%endif ++ + keywd_count equ ($-keywd_table)/keywd_size +--- layout.inc ++++ layout.inc +@@ -88,7 +88,11 @@ + section .uibss nobits align=16 follows=.adv + + ; Normal bss... ++%if IS_ISOLINUX ++ section .bss1 nobits align=16 follows=.bss2 ++%else + section .bss1 nobits align=16 follows=.uibss ++%endif + + ; Reserve space for stack + section .stack nobits align=16 start=STACK_START +--- ldlinux.asm ++++ ldlinux.asm +@@ -24,6 +24,9 @@ + %ifndef IS_MDSLINUX + %define IS_SYSLINUX 1 + %endif ++ ++%define WITH_GFX 1 ++ + %include "head.inc" + + ; +@@ -82,6 +85,8 @@ + cache_seg equ 2000h ; 64K area for metadata cache + xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem + comboot_seg equ real_mode_seg ; COMBOOT image loading zone ++gfx_menu_seg equ 4000h ; temporary storage to setup menu ++first_free_seg equ 5000h ; end of syslinux used memory + + ; + ; File structure. This holds the information for each currently open file. +@@ -357,6 +362,8 @@ + add eax,[bsHidden] ; Add partition offset + xor edx,edx ; Zero-extend LBA (eventually allow 64 bits) + ++.patch: jmp strict near .jmp ++ + .jmp: jmp strict short getlinsec_cbios + + ; +@@ -906,6 +913,48 @@ + ; + %include "ui.inc" + ++; Boot a specified local disk. AX specifies the BIOS disk number; or ++; 0xFFFF in case we should execute INT 18h ("next device.") ++; ++local_boot: ++%ifdef WITH_GFX ++ call gfx_done ++%endif ++ call vgaclearmode ++ lss sp,[cs:Stack] ; Restore stack pointer ++ xor dx,dx ++ mov ds,dx ++ mov es,dx ++ mov fs,dx ++ mov gs,dx ++ mov si,localboot_msg ++ call cwritestr ++ cmp ax,-1 ++ je .int18 ++ ++ ; Load boot sector from the specified BIOS device and jump to it. ++ mov dl,al ++ xor dh,dh ++ push dx ++ xor ax,ax ; Reset drive ++ int 13h ++ mov ax,0201h ; Read one sector ++ mov cx,0001h ; C/H/S = 0/0/1 (first sector) ++ mov bx,trackbuf ++ int 13h ++ pop dx ++ cli ; Abandon hope, ye who enter here ++ mov si,trackbuf ++ mov di,07C00h ++ mov cx,512 ; Probably overkill, but should be safe ++ rep movsd ++ mov ss,cx ++ mov sp,7c00h ++ jmp 0:07C00h ; Jump to new boot sector ++.int18: ++ int 18h ; Hope this does the right thing... ++ jmp kaboom ; If we returned, oh boy... ++ + ; + ; allocate_file: Allocate a file structure + ; +@@ -1126,6 +1175,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 + cmp byte [kaboom.again+1],18h ; INT 18h version? +@@ -1530,6 +1588,8 @@ + %include "cache.inc" ; Metadata disk cache + %include "adv.inc" ; Auxillary Data Vector + ++%include "gfxboot.inc" ; add gfx things ++ + ; ----------------------------------------------------------------------------- + ; Begin data section + ; ----------------------------------------------------------------------------- +@@ -1539,6 +1599,8 @@ + db 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 ++localboot_msg db 'Booting from local disk...', CR, LF, 0 + syslinux_cfg1 db '/boot' ; /boot/syslinux/syslinux.cfg + syslinux_cfg2 db '/syslinux' ; /syslinux/syslinux.cfg + syslinux_cfg3 db '/' ; /syslinux.cfg +--- loadhigh.inc ++++ loadhigh.inc +@@ -47,7 +47,12 @@ + .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 .no_message ++%endif + call bx ++.no_message: + push bx ; <AA> Pausebird function + + push eax ; <A> Total bytes to transfer +@@ -63,7 +68,15 @@ + push edi ; <C> Target buffer + mov cx,ax + xor bx,bx ; ES:0 ++ ++%ifdef WITH_GFX ++ call gfx_progress_update ++%endif ++ ++ push dx + call getfssec ; Load the data into xfer_buf_seg ++ ; getfssec destroys dx! ++ pop dx + pop edi ; <C> Target buffer + pop ecx ; <B> Byte count this round + push ecx ; <B> Byte count this round +--- parsecmd.inc ++++ parsecmd.inc +@@ -107,6 +107,14 @@ + FKeyName resb MAX_FKEYS*FILENAME_MAX ; File names for F-key help + KernelCNameLen resw 1 ; Length of unmangled kernel name + InitRDCNameLen resw 1 ; Length of unmangled initrd name ++ ++%if IS_ISOLINUX ++%ifdef DEBUG_MESSAGES ++; we need to rearrange memory a bit to make isolinux-debug.bin fit ++ section .bss ++%endif ++%endif ++ + %if IS_SYSLINUX + KernelName resb FILENAME_MAX+1 ; Mangled name for kernel + KernelCName resb FILENAME_MAX+2 ; Unmangled kernel name +--- parseconfig.inc ++++ parseconfig.inc +@@ -81,7 +81,7 @@ + ; + ; "localboot" command (PXELINUX, ISOLINUX) + ; +-%if IS_PXELINUX || IS_ISOLINUX ++%if IS_PXELINUX || IS_ISOLINUX || IS_SYSLINUX + pc_localboot: call getint + cmp byte [VKernel],0 ; ("label" section only) + je .err +@@ -286,6 +286,25 @@ + mov [SerialPort], word 0 + ret + ++%ifdef WITH_GFX ++%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 [getlinsec.patch+1], getlinsec3 - getlinsec.patch - 3 ++ or bx,bx ++ jz .err ++ call cache_metadata ++.err: ret ++%endif ++%endif ++ + ; + ; "F"-key command + ; +--- pxelinux.asm ++++ pxelinux.asm +@@ -846,6 +846,9 @@ + ; AX contains the appropriate return code. + ; + local_boot: ++%ifdef WITH_GFX ++ call gfx_done ++%endif + push cs + pop ds + mov [LocalBootType],ax +--- runkernel.inc ++++ runkernel.inc +@@ -206,6 +206,15 @@ + pop ds + sub si,cmd_line_here + mov [CmdLineLen],si ; Length including final null ++ ++%ifdef WITH_GFX ++ mov eax,[KernelSects] ++ mov esi,ds ++ shl esi,4 ++ add esi,KernelCName ++ call gfx_progress_init ++%endif ++ + ; + ; Now check if we have a large kernel, which needs to be loaded high + ; +@@ -312,6 +321,19 @@ + jz nk_noinitrd + call parse_load_initrd + nk_noinitrd: ++ ++%ifdef WITH_GFX ++ call gfx_progress_done ++ ++ cmp byte [gfx_cd_changed],0 ++ jz .no_cd_change ++ mov al,6 ++ xor si,si ++ xor di,di ++ call gfx_infobox ++.no_cd_change: ++%endif ++ + ; + ; Abandon hope, ye that enter here! We do no longer permit aborts. + ; +@@ -320,6 +342,10 @@ + mov si,ready_msg + call cwritestr + ++%ifdef WITH_GFX ++ call gfx_done ++%endif ++ + call vgaclearmode ; We can't trust ourselves after this + + UNLOAD_PREP ; Module-specific hook +@@ -552,6 +578,34 @@ + + .got_start: + push si ++ ++%ifdef WITH_GFX ++ cmp byte [si],'+' ++ jnz .got_start_10 ++ mov byte [cs:gfx_cd_changed],1 ++ inc si ++ push es ++ push ds ++ push si ++ push cs ++ pop es ++ mov cx,100h ++ mov di,trackbuf ++ push di ++ rep movsb ++ mov byte [es:di],0 ++ pop si ++ xor di,di ++ mov al,5 ; ask for cd change ++ push cs ++ pop ds ++ call gfx_infobox ++ pop si ++ pop ds ++ pop es ++.got_start_10: ++%endif ++ + mov di,InitRD ; Target buffer for mangled name + call mangle_name + call loadinitrd +@@ -645,6 +699,20 @@ + ret + + .notthere: ++ ++%ifdef WITH_GFX ++ cmp byte [gfx_ok],0 ++ jz .nogfx ++ mov si,InitRDCName ++ xor di,di ++ mov al,2 ++ call gfx_infobox ++ call gfx_progress_done ++ mov si,no_msg ++ jmp abort_load ++.nogfx: ++%endif ++ + mov si,err_noinitrd + call cwritestr + mov si,InitRDCName +@@ -653,7 +721,21 @@ + jmp abort_load + + no_high_mem: ; Error routine ++ ++%ifdef WITH_GFX ++ cmp byte [gfx_ok],0 ++ jz .nogfx + mov si,err_nohighmem ++ xor di,di ++ mov al,0 ++ call gfx_infobox ++ call gfx_progress_done ++ mov si,no_msg ++ jmp abort_load ++.nogfx: ++%endif ++ ++ mov si,err_nohighmem + jmp abort_load + + ret +@@ -666,7 +748,8 @@ + ready_msg db 'ready.', CR, LF, 0 + err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' + db 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 + + boot_image db 'BOOT_IMAGE=' +--- ui.inc ++++ ui.inc +@@ -44,6 +44,11 @@ + + .no_bootonce: + ++%ifdef WITH_GFX ++ ; build gfx menu ++ call gfx_setup_menu ++%endif ++ + ; + ; Check whether or not we are supposed to display the boot prompt. + ; +@@ -57,6 +62,21 @@ + cmp word [NoEscape],0 ; If NOESCAPE, no prompt, + jne auto_boot ; always run default cmd + ++%ifdef WITH_GFX ++ cmp byte [gfx_ok],0 ++ jz .nogfx ++ mov edi,ds ++ shl edi,4 ++ add edi,command_line ++ mov ecx,max_cmd_len ++ xor eax,eax ++ xchg eax,[KbdTimeout] ; only the first time ++ call gfx_input ++ cmp ax,1 ++ jnz load_kernel ++.nogfx: ++%endif ++ + mov si,boot_prompt + call cwritestr + +@@ -323,9 +343,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 + mov di,KernelName +@@ -343,7 +375,7 @@ + mov al, [VKernelBuf+vk_type] + mov [KernelType], al + +-%if IS_PXELINUX || IS_ISOLINUX ++%if IS_PXELINUX || IS_ISOLINUX || IS_SYSLINUX + ; Is this a "localboot" pseudo-kernel? + %if IS_PXELINUX + cmp byte [VKernelBuf+vk_rname+4], 0 +@@ -421,6 +453,19 @@ + 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 si ++ xor di,di ++ mov al,2 ++ call gfx_infobox ++ mov si,no_msg ++ jmp abort_load ++.nogfx: ++%endif ++ + call cwritestr + pop si ; KernelCName + call cwritestr +--- gfxboot.inc ++++ gfxboot.inc +@@ -417,8 +417,10 @@ + shr eax,20 + cmp ax,16 + jb gfx_init_40 ; at least 16MB +- mov word [gfx_xmem_0],81h ; 1MB at 8MB ++ mov word [gfx_xmem_0], 81h ; 1MB at 8MB + mov word [gfx_xmem_1],0a1h ; 1MB at 10MB ++ mov word [gfx_xmem_2],0c1h ; 1MB at 12MB ++ mov word [gfx_xmem_3],0e1h ; 1MB at 14MB + + mov dword [gfx_save_area1],7f0000h ; 8MB-64k + gfx_init_40: diff --git a/patches/syslinux-3.82/01_isolinux_mount_chdir.diff b/patches/syslinux-3.82/01_isolinux_mount_chdir.diff new file mode 100644 index 0000000..3881586 --- /dev/null +++ b/patches/syslinux-3.82/01_isolinux_mount_chdir.diff @@ -0,0 +1,175 @@ +diff --git a/core/isolinux.asm b/core/isolinux.asm +index 2627c2d..a0910fb 100644 +--- a/core/isolinux.asm ++++ b/core/isolinux.asm +@@ -1135,73 +1135,23 @@ all_read: + ; (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. + ; +-get_fs_structures: +- mov eax,[bi_pvd] +- mov bx,trackbuf +- call getonesec +- +- mov eax,[trackbuf+156+2] +- mov [RootDir+dir_lba],eax +- mov [CurrentDir+dir_lba],eax +-%ifdef DEBUG_MESSAGES +- mov si,dbg_rootdir_msg +- call writemsg +- call writehex8 +- call crlf +-%endif +- mov eax,[trackbuf+156+10] +- mov [RootDir+dir_len],eax +- mov [CurrentDir+dir_len],eax +- add eax,SECTOR_SIZE-1 +- shr eax,SECTOR_SHIFT +- mov [RootDir+dir_clust],eax +- mov [CurrentDir+dir_clust],eax +- +- ; Look for an isolinux directory, and if found, +- ; make it the current directory instead of the root +- ; directory. +- ; Also copy the name of the directory to CurrentDirName +- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName ++ call iso_mount + mov di,boot_dir ; Search for /boot/isolinux +- mov al,02h +- push di +- call searchdir_iso +- pop di +- jnz .found_dir +- mov di,isolinux_dir +- mov al,02h ; Search for /isolinux +- push di +- call searchdir_iso +- pop di +- jz .no_isolinux_dir ++ call setcwd ++ jnc .found_dir ++ mov di,isolinux_dir ; Search for /isolinux ++ call setcwd + .found_dir: +- ; Copy current directory name to CurrentDirName +- push si +- push di +- mov si,di +- mov di,CurrentDirName +- call strcpy +- mov byte [di],0 ;done in case it's not word aligned +- dec di +- mov byte [di],'/' +- pop di +- pop si + +- mov [CurrentDir+dir_len],eax +- mov eax,[si+file_left] +- mov [CurrentDir+dir_clust],eax +- xor eax,eax ; Free this file pointer entry +- xchg eax,[si+file_sector] +- mov [CurrentDir+dir_lba],eax + %ifdef DEBUG_MESSAGES + push si + mov si,dbg_isodir_msg + call writemsg + pop si ++ mov eax,[CurrentDir+dir_lba] + call writehex8 + call crlf + %endif +-.no_isolinux_dir: + + ; + ; Locate the configuration file +@@ -1706,6 +1656,90 @@ getfssec: + TRACER 'f' + ret + ++; ++; setcwd: Set current working directory. ++; ++; On entry: ++; DI -> directory name ++; On exit: ++; CF = 1 -> error ++; ++; On error, the old working directory is kept. ++; ++setcwd: ++ mov al,02h ++ push di ++ call searchdir_iso ++ pop di ++ stc ++ jz .err ++ mov [CurrentDir+dir_len],eax ++ mov eax,[si+file_left] ++ mov [CurrentDir+dir_clust],eax ++ xor eax,eax ++ xchg eax,[si+file_sector] ++ mov [CurrentDir+dir_lba],eax ++ mov si,di ++ mov di,CurrentDirName ++ cmp si,di ++ jz .ok ++ mov cx,FILENAME_MAX ++ push ds ++ pop es ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ mov byte [di-1],0 ++ jnz .err ++.ok: ++ clc ++.err: ++ ret ++ ++; ++; Read fs meta data and setup RootDir and CurrentDir. ++; ++; On exit: ++; CF = 1 -> error ++; ++iso_mount: ++ mov eax,[bi_pvd] ++ mov bx,trackbuf ++ call getonesec ++ ++ mov eax,[trackbuf+156+10] ++ mov [RootDir+dir_len],eax ++ add eax,SECTOR_SIZE-1 ++ shr eax,SECTOR_SHIFT ++ mov [RootDir+dir_clust],eax ++ mov eax,[trackbuf+156+2] ++ mov [RootDir+dir_lba],eax ++ ++ push ds ++ pop es ++ mov si,RootDir ++ mov di,CurrentDir ++ mov cx,dir_t_size ++ rep movsb ++ ++%ifdef DEBUG_MESSAGES ++ mov si,dbg_rootdir_msg ++ call writemsg ++ call writehex8 ++ call crlf ++%endif ++ ++ mov di,CurrentDirName ++ call setcwd ++ jnc .ok ++ mov word [CurrentDirName],ROOT_DIR_WORD ++.ok: ++ clc ++ ret ++ ++ + ; ----------------------------------------------------------------------------- + ; Common modules + ; ----------------------------------------------------------------------------- diff --git a/patches/syslinux-3.82/02_comboot_hooks.diff b/patches/syslinux-3.82/02_comboot_hooks.diff new file mode 100644 index 0000000..52c9465 --- /dev/null +++ b/patches/syslinux-3.82/02_comboot_hooks.diff @@ -0,0 +1,117 @@ +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 8bfc8b8..f458fc7 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -228,6 +228,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 +@@ -319,6 +321,9 @@ load_initrd: + ; + call abort_check ; Last chance!! + ++ mov al,6 ++ call [comboot_hook] ++ + mov si,ready_msg + call writestr_qchk + +@@ -489,6 +494,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: +@@ -613,6 +620,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 1b40717..9413f16 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -402,8 +402,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 + +@@ -468,6 +472,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 +@@ -510,7 +516,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/patches/syslinux-3.82/03_comboot_ne_real_mode_seg.diff b/patches/syslinux-3.82/03_comboot_ne_real_mode_seg.diff new file mode 100644 index 0000000..fe319bf --- /dev/null +++ b/patches/syslinux-3.82/03_comboot_ne_real_mode_seg.diff @@ -0,0 +1,44 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index cdba16d..1a1dbfe 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -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 8c2e248..ca95d2b 100644 +--- a/core/layout.inc ++++ b/core/layout.inc +@@ -123,4 +123,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/patches/syslinux-3.82/04_new_quiet_flag.diff b/patches/syslinux-3.82/04_new_quiet_flag.diff new file mode 100644 index 0000000..b63ed99 --- /dev/null +++ b/patches/syslinux-3.82/04_new_quiet_flag.diff @@ -0,0 +1,43 @@ +diff --git a/core/runkernel.inc b/core/runkernel.inc +index f458fc7..f6ed644 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -165,7 +165,7 @@ opt_mem: + ret + + opt_quiet: +- mov byte [QuietBoot],1 ++ or byte [QuietBoot],1 + ret + + %if IS_PXELINUX +@@ -634,7 +634,7 @@ loadinitrd: + ; assumes CS == DS + ; + writestr_qchk: +- test byte [QuietBoot],01h ++ test byte [QuietBoot],03h + jz writestr + ret + +@@ -689,4 +689,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 9413f16..353d59a 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -600,7 +600,7 @@ kernel_good: + ; + xor ax,ax + mov [InitRDPtr],ax +- mov [QuietBoot],al ++ and byte [QuietBoot],~1 + %if IS_PXELINUX + mov [KeepPXE],al + %endif diff --git a/patches/syslinux-3.82/05_variable_kernel_address.diff b/patches/syslinux-3.82/05_variable_kernel_address.diff new file mode 100644 index 0000000..a494529 --- /dev/null +++ b/patches/syslinux-3.82/05_variable_kernel_address.diff @@ -0,0 +1,42 @@ +diff --git a/core/runkernel.inc b/core/runkernel.inc +index f6ed644..286c9c8 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -259,7 +259,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 + +@@ -431,7 +431,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] +@@ -439,9 +439,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 + +@@ -692,3 +696,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/patches/syslinux-3.82/06_comboot_new_api.diff b/patches/syslinux-3.82/06_comboot_new_api.diff new file mode 100644 index 0000000..2cea657 --- /dev/null +++ b/patches/syslinux-3.82/06_comboot_new_api.diff @@ -0,0 +1,189 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index 1a1dbfe..1923308 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -962,6 +962,45 @@ comapi_shufraw: + mov ecx,P_ECX + jmp shuffle_and_boot_raw + ++ ++; ++; INT 22h AX=0025h Set current working directory ++; ++%if IS_ISOLINUX ++comapi_setcwd: ++ mov si,P_BX ++ mov di,TmpDirName ++ mov cx,FILENAME_MAX ++ mov ds,P_ES ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ push cs ++ pop ds ++ stc ++ jnz .err ++ mov di,TmpDirName ++ call setcwd ++.err: ++ ret ++%else ++comapi_setcwd equ comapi_err ++%endif ++ ++ ++; ++; INT 22h AX=0026h Read filesystem meta data ++; ++%if IS_ISOLINUX ++comapi_mount: ++; call iso_mount ++ ret ++%else ++comapi_mount equ comapi_err ++%endif ++ + section .data + + %macro int21 2 +@@ -969,6 +1008,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 +@@ -1021,8 +1163,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 + APIKeyFlag db 0 + +@@ -1041,8 +1191,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/patches/syslinux-3.82/07_no_append.diff b/patches/syslinux-3.82/07_no_append.diff new file mode 100644 index 0000000..f06b3b4 --- /dev/null +++ b/patches/syslinux-3.82/07_no_append.diff @@ -0,0 +1,45 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index 1923308..f39bfb1 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1043,12 +1043,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 + +@@ -1172,6 +1174,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 353d59a..e37f2a7 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -379,9 +379,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/patches/syslinux-3.82/08_kernel_size.diff b/patches/syslinux-3.82/08_kernel_size.diff new file mode 100644 index 0000000..e6b868d --- /dev/null +++ b/patches/syslinux-3.82/08_kernel_size.diff @@ -0,0 +1,36 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index f39bfb1..0874526 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1088,6 +1088,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 e37f2a7..6137dc9 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -616,7 +616,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 +@@ -637,6 +641,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/patches/syslinux-3.82/09_doc.diff b/patches/syslinux-3.82/09_doc.diff new file mode 100644 index 0000000..6f8a8cf --- /dev/null +++ b/patches/syslinux-3.82/09_doc.diff @@ -0,0 +1,43 @@ +diff --git a/doc/comboot.txt b/doc/comboot.txt +index f5fefda..1450021 100644 +--- a/doc/comboot.txt ++++ b/doc/comboot.txt +@@ -955,3 +955,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. ++ ++ ++AX=0025h [3.84] Set current working directory ++ Input: AX 00025h ++ ES:BX null-terminated directory name string ++ Output: None ++ ++ Sets the current working directory. For SYSLINUX, ISOLINUX, ++ and PXELINUX, this will be an absolute path. ++ ++ ++AX=0026h [3.84] Read file system metadata [ISOLINUX] ++ Input: AX 00026h ++ Output: None ++ ++ 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/patches/syslinux-3.82/10_gfxboot_c.diff b/patches/syslinux-3.82/10_gfxboot_c.diff new file mode 100644 index 0000000..1c0d251 --- /dev/null +++ b/patches/syslinux-3.82/10_gfxboot_c.diff @@ -0,0 +1,2099 @@ +diff --git a/modules/Makefile b/modules/Makefile +index 80eb995..65661a4 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -19,6 +19,11 @@ include $(topdir)/MCONFIG.embedded + + INCLUDES = -I$(com32)/include + ++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 + + 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 <libio.h> ++ ++#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/patches/syslinux-3.83/01_isolinux_mount_chdir.diff b/patches/syslinux-3.83/01_isolinux_mount_chdir.diff new file mode 100644 index 0000000..3881586 --- /dev/null +++ b/patches/syslinux-3.83/01_isolinux_mount_chdir.diff @@ -0,0 +1,175 @@ +diff --git a/core/isolinux.asm b/core/isolinux.asm +index 2627c2d..a0910fb 100644 +--- a/core/isolinux.asm ++++ b/core/isolinux.asm +@@ -1135,73 +1135,23 @@ all_read: + ; (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. + ; +-get_fs_structures: +- mov eax,[bi_pvd] +- mov bx,trackbuf +- call getonesec +- +- mov eax,[trackbuf+156+2] +- mov [RootDir+dir_lba],eax +- mov [CurrentDir+dir_lba],eax +-%ifdef DEBUG_MESSAGES +- mov si,dbg_rootdir_msg +- call writemsg +- call writehex8 +- call crlf +-%endif +- mov eax,[trackbuf+156+10] +- mov [RootDir+dir_len],eax +- mov [CurrentDir+dir_len],eax +- add eax,SECTOR_SIZE-1 +- shr eax,SECTOR_SHIFT +- mov [RootDir+dir_clust],eax +- mov [CurrentDir+dir_clust],eax +- +- ; Look for an isolinux directory, and if found, +- ; make it the current directory instead of the root +- ; directory. +- ; Also copy the name of the directory to CurrentDirName +- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName ++ call iso_mount + mov di,boot_dir ; Search for /boot/isolinux +- mov al,02h +- push di +- call searchdir_iso +- pop di +- jnz .found_dir +- mov di,isolinux_dir +- mov al,02h ; Search for /isolinux +- push di +- call searchdir_iso +- pop di +- jz .no_isolinux_dir ++ call setcwd ++ jnc .found_dir ++ mov di,isolinux_dir ; Search for /isolinux ++ call setcwd + .found_dir: +- ; Copy current directory name to CurrentDirName +- push si +- push di +- mov si,di +- mov di,CurrentDirName +- call strcpy +- mov byte [di],0 ;done in case it's not word aligned +- dec di +- mov byte [di],'/' +- pop di +- pop si + +- mov [CurrentDir+dir_len],eax +- mov eax,[si+file_left] +- mov [CurrentDir+dir_clust],eax +- xor eax,eax ; Free this file pointer entry +- xchg eax,[si+file_sector] +- mov [CurrentDir+dir_lba],eax + %ifdef DEBUG_MESSAGES + push si + mov si,dbg_isodir_msg + call writemsg + pop si ++ mov eax,[CurrentDir+dir_lba] + call writehex8 + call crlf + %endif +-.no_isolinux_dir: + + ; + ; Locate the configuration file +@@ -1706,6 +1656,90 @@ getfssec: + TRACER 'f' + ret + ++; ++; setcwd: Set current working directory. ++; ++; On entry: ++; DI -> directory name ++; On exit: ++; CF = 1 -> error ++; ++; On error, the old working directory is kept. ++; ++setcwd: ++ mov al,02h ++ push di ++ call searchdir_iso ++ pop di ++ stc ++ jz .err ++ mov [CurrentDir+dir_len],eax ++ mov eax,[si+file_left] ++ mov [CurrentDir+dir_clust],eax ++ xor eax,eax ++ xchg eax,[si+file_sector] ++ mov [CurrentDir+dir_lba],eax ++ mov si,di ++ mov di,CurrentDirName ++ cmp si,di ++ jz .ok ++ mov cx,FILENAME_MAX ++ push ds ++ pop es ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ mov byte [di-1],0 ++ jnz .err ++.ok: ++ clc ++.err: ++ ret ++ ++; ++; Read fs meta data and setup RootDir and CurrentDir. ++; ++; On exit: ++; CF = 1 -> error ++; ++iso_mount: ++ mov eax,[bi_pvd] ++ mov bx,trackbuf ++ call getonesec ++ ++ mov eax,[trackbuf+156+10] ++ mov [RootDir+dir_len],eax ++ add eax,SECTOR_SIZE-1 ++ shr eax,SECTOR_SHIFT ++ mov [RootDir+dir_clust],eax ++ mov eax,[trackbuf+156+2] ++ mov [RootDir+dir_lba],eax ++ ++ push ds ++ pop es ++ mov si,RootDir ++ mov di,CurrentDir ++ mov cx,dir_t_size ++ rep movsb ++ ++%ifdef DEBUG_MESSAGES ++ mov si,dbg_rootdir_msg ++ call writemsg ++ call writehex8 ++ call crlf ++%endif ++ ++ mov di,CurrentDirName ++ call setcwd ++ jnc .ok ++ mov word [CurrentDirName],ROOT_DIR_WORD ++.ok: ++ clc ++ ret ++ ++ + ; ----------------------------------------------------------------------------- + ; Common modules + ; ----------------------------------------------------------------------------- diff --git a/patches/syslinux-3.83/02_comboot_hooks.diff b/patches/syslinux-3.83/02_comboot_hooks.diff new file mode 100644 index 0000000..52c9465 --- /dev/null +++ b/patches/syslinux-3.83/02_comboot_hooks.diff @@ -0,0 +1,117 @@ +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 8bfc8b8..f458fc7 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -228,6 +228,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 +@@ -319,6 +321,9 @@ load_initrd: + ; + call abort_check ; Last chance!! + ++ mov al,6 ++ call [comboot_hook] ++ + mov si,ready_msg + call writestr_qchk + +@@ -489,6 +494,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: +@@ -613,6 +620,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 1b40717..9413f16 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -402,8 +402,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 + +@@ -468,6 +472,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 +@@ -510,7 +516,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/patches/syslinux-3.83/03_comboot_ne_real_mode_seg.diff b/patches/syslinux-3.83/03_comboot_ne_real_mode_seg.diff new file mode 100644 index 0000000..fe319bf --- /dev/null +++ b/patches/syslinux-3.83/03_comboot_ne_real_mode_seg.diff @@ -0,0 +1,44 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index cdba16d..1a1dbfe 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -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 8c2e248..ca95d2b 100644 +--- a/core/layout.inc ++++ b/core/layout.inc +@@ -123,4 +123,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/patches/syslinux-3.83/04_new_quiet_flag.diff b/patches/syslinux-3.83/04_new_quiet_flag.diff new file mode 100644 index 0000000..b63ed99 --- /dev/null +++ b/patches/syslinux-3.83/04_new_quiet_flag.diff @@ -0,0 +1,43 @@ +diff --git a/core/runkernel.inc b/core/runkernel.inc +index f458fc7..f6ed644 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -165,7 +165,7 @@ opt_mem: + ret + + opt_quiet: +- mov byte [QuietBoot],1 ++ or byte [QuietBoot],1 + ret + + %if IS_PXELINUX +@@ -634,7 +634,7 @@ loadinitrd: + ; assumes CS == DS + ; + writestr_qchk: +- test byte [QuietBoot],01h ++ test byte [QuietBoot],03h + jz writestr + ret + +@@ -689,4 +689,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 9413f16..353d59a 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -600,7 +600,7 @@ kernel_good: + ; + xor ax,ax + mov [InitRDPtr],ax +- mov [QuietBoot],al ++ and byte [QuietBoot],~1 + %if IS_PXELINUX + mov [KeepPXE],al + %endif diff --git a/patches/syslinux-3.83/05_variable_kernel_address.diff b/patches/syslinux-3.83/05_variable_kernel_address.diff new file mode 100644 index 0000000..a494529 --- /dev/null +++ b/patches/syslinux-3.83/05_variable_kernel_address.diff @@ -0,0 +1,42 @@ +diff --git a/core/runkernel.inc b/core/runkernel.inc +index f6ed644..286c9c8 100644 +--- a/core/runkernel.inc ++++ b/core/runkernel.inc +@@ -259,7 +259,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 + +@@ -431,7 +431,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] +@@ -439,9 +439,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 + +@@ -692,3 +696,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/patches/syslinux-3.83/06_comboot_new_api.diff b/patches/syslinux-3.83/06_comboot_new_api.diff new file mode 100644 index 0000000..2cea657 --- /dev/null +++ b/patches/syslinux-3.83/06_comboot_new_api.diff @@ -0,0 +1,189 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index 1a1dbfe..1923308 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -962,6 +962,45 @@ comapi_shufraw: + mov ecx,P_ECX + jmp shuffle_and_boot_raw + ++ ++; ++; INT 22h AX=0025h Set current working directory ++; ++%if IS_ISOLINUX ++comapi_setcwd: ++ mov si,P_BX ++ mov di,TmpDirName ++ mov cx,FILENAME_MAX ++ mov ds,P_ES ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ push cs ++ pop ds ++ stc ++ jnz .err ++ mov di,TmpDirName ++ call setcwd ++.err: ++ ret ++%else ++comapi_setcwd equ comapi_err ++%endif ++ ++ ++; ++; INT 22h AX=0026h Read filesystem meta data ++; ++%if IS_ISOLINUX ++comapi_mount: ++; call iso_mount ++ ret ++%else ++comapi_mount equ comapi_err ++%endif ++ + section .data + + %macro int21 2 +@@ -969,6 +1008,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 +@@ -1021,8 +1163,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 + APIKeyFlag db 0 + +@@ -1041,8 +1191,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/patches/syslinux-3.83/07_no_append.diff b/patches/syslinux-3.83/07_no_append.diff new file mode 100644 index 0000000..f06b3b4 --- /dev/null +++ b/patches/syslinux-3.83/07_no_append.diff @@ -0,0 +1,45 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index 1923308..f39bfb1 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1043,12 +1043,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 + +@@ -1172,6 +1174,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 353d59a..e37f2a7 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -379,9 +379,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/patches/syslinux-3.83/08_kernel_size.diff b/patches/syslinux-3.83/08_kernel_size.diff new file mode 100644 index 0000000..e6b868d --- /dev/null +++ b/patches/syslinux-3.83/08_kernel_size.diff @@ -0,0 +1,36 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index f39bfb1..0874526 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -1088,6 +1088,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 e37f2a7..6137dc9 100644 +--- a/core/ui.inc ++++ b/core/ui.inc +@@ -616,7 +616,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 +@@ -637,6 +641,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/patches/syslinux-3.83/09_doc.diff b/patches/syslinux-3.83/09_doc.diff new file mode 100644 index 0000000..6f8a8cf --- /dev/null +++ b/patches/syslinux-3.83/09_doc.diff @@ -0,0 +1,43 @@ +diff --git a/doc/comboot.txt b/doc/comboot.txt +index f5fefda..1450021 100644 +--- a/doc/comboot.txt ++++ b/doc/comboot.txt +@@ -955,3 +955,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. ++ ++ ++AX=0025h [3.84] Set current working directory ++ Input: AX 00025h ++ ES:BX null-terminated directory name string ++ Output: None ++ ++ Sets the current working directory. For SYSLINUX, ISOLINUX, ++ and PXELINUX, this will be an absolute path. ++ ++ ++AX=0026h [3.84] Read file system metadata [ISOLINUX] ++ Input: AX 00026h ++ Output: None ++ ++ 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/patches/syslinux-3.83/10_gfxboot_c.diff b/patches/syslinux-3.83/10_gfxboot_c.diff new file mode 100644 index 0000000..4383445 --- /dev/null +++ b/patches/syslinux-3.83/10_gfxboot_c.diff @@ -0,0 +1,2099 @@ +diff --git a/modules/Makefile b/modules/Makefile +index 77020ea..e6e7905 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -19,6 +19,11 @@ include $(topdir)/MCONFIG.embedded + + INCLUDES = -I$(com32)/include + ++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 <libio.h> ++ ++#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/patches/syslinux-3.86/01_isolinux_mount_chdir.diff b/patches/syslinux-3.86/01_isolinux_mount_chdir.diff new file mode 100644 index 0000000..3e11cb3 --- /dev/null +++ b/patches/syslinux-3.86/01_isolinux_mount_chdir.diff @@ -0,0 +1,175 @@ +diff --git a/core/isolinux.asm b/core/isolinux.asm +index 23429bd..54f2e19 100644 +--- a/core/isolinux.asm ++++ b/core/isolinux.asm +@@ -1135,73 +1135,23 @@ all_read: + ; (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. + ; +-get_fs_structures: +- mov eax,[bi_pvd] +- mov bx,trackbuf +- call getonesec +- +- mov eax,[trackbuf+156+2] +- mov [RootDir+dir_lba],eax +- mov [CurrentDir+dir_lba],eax +-%ifdef DEBUG_MESSAGES +- mov si,dbg_rootdir_msg +- call writemsg +- call writehex8 +- call crlf +-%endif +- mov eax,[trackbuf+156+10] +- mov [RootDir+dir_len],eax +- mov [CurrentDir+dir_len],eax +- add eax,SECTOR_SIZE-1 +- shr eax,SECTOR_SHIFT +- mov [RootDir+dir_clust],eax +- mov [CurrentDir+dir_clust],eax +- +- ; Look for an isolinux directory, and if found, +- ; make it the current directory instead of the root +- ; directory. +- ; Also copy the name of the directory to CurrentDirName +- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName ++ call iso_mount + mov di,boot_dir ; Search for /boot/isolinux +- mov al,02h +- push di +- call searchdir_iso +- pop di +- jnz .found_dir +- mov di,isolinux_dir +- mov al,02h ; Search for /isolinux +- push di +- call searchdir_iso +- pop di +- jz .no_isolinux_dir ++ call setcwd ++ jnc .found_dir ++ mov di,isolinux_dir ; Search for /isolinux ++ call setcwd + .found_dir: +- ; Copy current directory name to CurrentDirName +- push si +- push di +- mov si,di +- mov di,CurrentDirName +- call strcpy +- mov byte [di],0 ;done in case it's not word aligned +- dec di +- mov byte [di],'/' +- pop di +- pop si + +- mov [CurrentDir+dir_len],eax +- mov eax,[si+file_left] +- mov [CurrentDir+dir_clust],eax +- xor eax,eax ; Free this file pointer entry +- xchg eax,[si+file_sector] +- mov [CurrentDir+dir_lba],eax + %ifdef DEBUG_MESSAGES + push si + mov si,dbg_isodir_msg + call writemsg + pop si ++ mov eax,[CurrentDir+dir_lba] + call writehex8 + call crlf + %endif +-.no_isolinux_dir: + + ; + ; Locate the configuration file +@@ -1706,6 +1656,90 @@ getfssec: + TRACER 'f' + ret + ++; ++; setcwd: Set current working directory. ++; ++; On entry: ++; DI -> directory name ++; On exit: ++; CF = 1 -> error ++; ++; On error, the old working directory is kept. ++; ++setcwd: ++ mov al,02h ++ push di ++ call searchdir_iso ++ pop di ++ stc ++ jz .err ++ mov [CurrentDir+dir_len],eax ++ mov eax,[si+file_left] ++ mov [CurrentDir+dir_clust],eax ++ xor eax,eax ++ xchg eax,[si+file_sector] ++ mov [CurrentDir+dir_lba],eax ++ mov si,di ++ mov di,CurrentDirName ++ cmp si,di ++ jz .ok ++ mov cx,FILENAME_MAX ++ push ds ++ pop es ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ mov byte [di-1],0 ++ jnz .err ++.ok: ++ clc ++.err: ++ ret ++ ++; ++; Read fs meta data and setup RootDir and CurrentDir. ++; ++; On exit: ++; CF = 1 -> error ++; ++iso_mount: ++ mov eax,[bi_pvd] ++ mov bx,trackbuf ++ call getonesec ++ ++ mov eax,[trackbuf+156+10] ++ mov [RootDir+dir_len],eax ++ add eax,SECTOR_SIZE-1 ++ shr eax,SECTOR_SHIFT ++ mov [RootDir+dir_clust],eax ++ mov eax,[trackbuf+156+2] ++ mov [RootDir+dir_lba],eax ++ ++ push ds ++ pop es ++ mov si,RootDir ++ mov di,CurrentDir ++ mov cx,dir_t_size ++ rep movsb ++ ++%ifdef DEBUG_MESSAGES ++ mov si,dbg_rootdir_msg ++ call writemsg ++ call writehex8 ++ call crlf ++%endif ++ ++ mov di,CurrentDirName ++ call setcwd ++ jnc .ok ++ mov word [CurrentDirName],ROOT_DIR_WORD ++.ok: ++ clc ++ ret ++ ++ + ; ----------------------------------------------------------------------------- + ; Common modules + ; ----------------------------------------------------------------------------- diff --git a/patches/syslinux-3.86/02_comboot_new_api.diff b/patches/syslinux-3.86/02_comboot_new_api.diff new file mode 100644 index 0000000..af3c263 --- /dev/null +++ b/patches/syslinux-3.86/02_comboot_new_api.diff @@ -0,0 +1,70 @@ +diff --git a/core/comboot.inc b/core/comboot.inc +index f8a7853..37bd0f2 100644 +--- a/core/comboot.inc ++++ b/core/comboot.inc +@@ -970,6 +970,45 @@ comapi_shufraw: + mov ecx,P_ECX + jmp shuffle_and_boot_raw + ++ ++; ++; INT 22h AX=0025h Set current working directory ++; ++%if IS_ISOLINUX ++comapi_setcwd: ++ mov si,P_BX ++ mov di,TmpDirName ++ mov cx,FILENAME_MAX ++ mov ds,P_ES ++.copy: ++ lodsb ++ stosb ++ or al,al ++ loopnz .copy ++ push cs ++ pop ds ++ stc ++ jnz .err ++ mov di,TmpDirName ++ call setcwd ++.err: ++ ret ++%else ++comapi_setcwd equ comapi_err ++%endif ++ ++ ++; ++; INT 22h AX=0026h Read filesystem meta data ++; ++%if IS_ISOLINUX ++comapi_mount: ++; call iso_mount ++ ret ++%else ++comapi_mount equ comapi_err ++%endif ++ + section .data + + %macro int21 2 +@@ -1029,6 +1068,8 @@ 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) + int22_count equ ($-int22_table)/2 + + APIKeyWait db 0 +@@ -1049,8 +1090,9 @@ 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 + DOSErrTramp resd 33 ; Error trampolines ++TmpDirName resb FILENAME_MAX + ConfigName resb FILENAME_MAX + CurrentDirName resb FILENAME_MAX diff --git a/patches/syslinux-3.86/03_doc.diff b/patches/syslinux-3.86/03_doc.diff new file mode 100644 index 0000000..ca4d37a --- /dev/null +++ b/patches/syslinux-3.86/03_doc.diff @@ -0,0 +1,25 @@ +diff --git a/doc/comboot.txt b/doc/comboot.txt +index eb43708..13d18f6 100644 +--- a/doc/comboot.txt ++++ b/doc/comboot.txt +@@ -949,3 +949,20 @@ 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. ++ ++ ++AX=0025h [3.84] Set current working directory ++ Input: AX 00025h ++ ES:BX null-terminated directory name string ++ Output: None ++ ++ Sets the current working directory. For SYSLINUX, ISOLINUX, ++ and PXELINUX, this will be an absolute path. ++ ++ ++AX=0026h [3.84] Read file system metadata [ISOLINUX] ++ Input: AX 00026h ++ Output: None ++ ++ Reads filesystem data (e.g. after a CDROM change). ++ diff --git a/patches/syslinux-3.86/04_no_gfxboot_com.diff b/patches/syslinux-3.86/04_no_gfxboot_com.diff new file mode 100644 index 0000000..032713f --- /dev/null +++ b/patches/syslinux-3.86/04_no_gfxboot_com.diff @@ -0,0 +1,13 @@ +diff --git a/modules/Makefile b/modules/Makefile +index 77020ea..f318364 100644 +--- a/modules/Makefile ++++ b/modules/Makefile +@@ -19,7 +19,7 @@ include $(topdir)/MCONFIG.embedded + + INCLUDES = -I$(com32)/include + +-BINS = pxechain.com gfxboot.com poweroff.com int18.com ++BINS = pxechain.com poweroff.com int18.com + + all: $(BINS) + |