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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#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 +