forked from pool/syslinux
Copy from system:install:head/syslinux based on submit request 24528 from user snwint OBS-URL: https://build.opensuse.org/request/show/24528 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/syslinux?expand=0&rev=21
1081 lines
26 KiB
Diff
1081 lines
26 KiB
Diff
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
|
|
+
|