diff options
Diffstat (limited to 'com32/elflink')
-rw-r--r-- | com32/elflink/Makefile | 8 | ||||
-rw-r--r-- | com32/elflink/ldlinux/Makefile | 7 | ||||
-rw-r--r-- | com32/elflink/ldlinux/adv.c | 6 | ||||
-rw-r--r-- | com32/elflink/ldlinux/chainboot.c | 157 | ||||
-rw-r--r-- | com32/elflink/ldlinux/cli.c | 103 | ||||
-rw-r--r-- | com32/elflink/ldlinux/config.h | 7 | ||||
-rw-r--r-- | com32/elflink/ldlinux/eprintf.c | 1 | ||||
-rw-r--r-- | com32/elflink/ldlinux/execute.c | 102 | ||||
-rw-r--r-- | com32/elflink/ldlinux/get_key.c | 10 | ||||
-rw-r--r-- | com32/elflink/ldlinux/ipappend.c | 48 | ||||
-rw-r--r-- | com32/elflink/ldlinux/kernel.c | 54 | ||||
-rw-r--r-- | com32/elflink/ldlinux/ldlinux.c | 235 | ||||
-rw-r--r-- | com32/elflink/ldlinux/loadhigh.c | 112 | ||||
-rw-r--r-- | com32/elflink/ldlinux/readconfig.c | 47 |
14 files changed, 630 insertions, 267 deletions
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile index aca37438..fce1be8c 100644 --- a/com32/elflink/Makefile +++ b/com32/elflink/Makefile @@ -19,8 +19,8 @@ test_memalign.elf : test_memalign.o $(LIBS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ test_com32.elf: CFLAGS += -DELF_DEBUG -test_com32.elf: test_com32.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC) - $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map +test_com32.elf: test_com32.o ../lib/libcom32min.a $(LIBGCC) + $(LD) -n $(LDFLAGS) -o $@ test_com32.o $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map tidy dist: rm -f *.o *.lo *.a *.lst *.elf .*.d *.map @@ -31,8 +31,6 @@ clean: tidy spotless: clean rm -f *~ \#* -install: all - mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR) - install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR) +install: -include .*.d diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index 5927e500..dc48ca97 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -15,13 +15,14 @@ MAKEDIR = $(topdir)/mk include $(MAKEDIR)/elf.mk CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include +LIBS = --whole-archive $(com32)/lib/libcom32min.a all: ldlinux.c32 ldlinux_lnx.a ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \ - adv.o ipappend.o execute.o kernel.o get_key.o \ - advwrite.o setadv.o eprintf.o - $(LD) $(LDFLAGS) -o $@ $^ + adv.o execute.o chainboot.o kernel.o get_key.o \ + advwrite.o setadv.o eprintf.o loadhigh.o + $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) LNXLIBOBJS = get_key.lo ldlinux_lnx.a: $(LNXLIBOBJS) diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c index cf02d129..ae473908 100644 --- a/com32/elflink/ldlinux/adv.c +++ b/com32/elflink/ldlinux/adv.c @@ -33,8 +33,12 @@ #include <syslinux/adv.h> #include <syslinux/firmware.h> +#include <klibc/compiler.h> -void __syslinux_init(void) +void *__syslinux_adv_ptr; +size_t __syslinux_adv_size; + +void __constructor __syslinux_init(void) { firmware->adv_ops->init(); } diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c new file mode 100644 index 00000000..4a4a2e1a --- /dev/null +++ b/com32/elflink/ldlinux/chainboot.c @@ -0,0 +1,157 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2012 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., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * chainbooting - replace the current bootloader completely. This + * is BIOS-specific. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <dprintf.h> + +#include <com32.h> +#include <sys/exec.h> +#include <sys/io.h> +#include "core.h" +#include "menu.h" +#include "fs.h" +#include "config.h" +#include "localboot.h" +#include "bios.h" + +#include <syslinux/boot.h> +#include <syslinux/bootrm.h> +#include <syslinux/movebits.h> +#include <syslinux/config.h> + +void chainboot_file(const char *file, uint32_t type) +{ + uint8_t keeppxe = 0; + const union syslinux_derivative_info *sdi; + struct syslinux_rm_regs regs; + struct syslinux_movelist *fraglist = NULL; + struct syslinux_memmap *mmap = NULL; + struct com32_filedata fd; + com32sys_t reg; + char *stack; + void *buf; + int rv, max, size; + + max = 0xA0000; /* Maximum load */ + buf = malloc(max); + if (!buf) + goto bail; + + rv = open_file(file, &fd); + if (rv == -1) { + free(buf); + goto bail; + } + + reg.eax.l = max; + reg.ebx.l = 0; + reg.edx.w[0] = 0; + reg.edi.l = (uint32_t)buf; + reg.ebp.l = -1; /* XXX: limit? */ + reg.esi.w[0] = rv; + + pm_load_high(®); + + size = reg.edi.l - (unsigned long)buf; + if (size > 0xA0000 - 0x7C00) { + printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n"); + goto bail; + } + + mmap = syslinux_memory_map(); + if (!mmap) + goto bail; + + sdi = syslinux_derivative_info(); + + memset(®s, 0, sizeof(regs)); + regs.ip = 0x7c00; + + if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX || + sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) { + if (syslinux_add_movelist(&fraglist, 0x800 - 18, + (addr_t)sdi->r.esbx, 16)) + goto bail; + + /* DS:SI points to partition info */ + regs.esi.l = 0x800 - 18; + } + + /* + * For a BSS boot sector we have to transfer the + * superblock. + */ + if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX && + type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf)) + goto bail; + + if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) { + keeppxe = 0x03; /* Chainloading + keep PXE */ + stack = (char *)sdi->r.fssi; + + /* + * Set up the registers with their initial values + */ + + regs.eax.l = *(uint32_t *)&stack[36]; + regs.ecx.l = *(uint32_t *)&stack[32]; + regs.edx.l = *(uint32_t *)&stack[28]; + regs.ebx.l = *(uint32_t *)&stack[24]; + regs.esp.l = sdi->rr.r.esi.w[0] + 44; + regs.ebp.l = *(uint32_t *)&stack[16]; + regs.esi.l = *(uint32_t *)&stack[12]; + regs.edi.l = *(uint32_t *)&stack[8]; + regs.es = *(uint16_t *)&stack[4]; + regs.ss = sdi->rr.r.fs; + regs.ds = *(uint16_t *)&stack[6]; + regs.fs = *(uint16_t *)&stack[2]; + regs.gs = *(uint16_t *)&stack[0]; + } else { + const uint16_t *esdi = (const uint16_t *)sdi->disk.esdi_ptr; + + regs.esp.l = (uint16_t)(unsigned long)StackBuf + 44; + + /* + * DON'T DO THIS FOR PXELINUX... + * For PXE, ES:BX -> PXENV+, and this would + * corrupt that use. + * + * Restore ES:DI -> $PnP (if we were ourselves + * called that way...) + */ + regs.edi.w[0] = esdi[0]; /* New DI */ + regs.es = esdi[2]; /* New ES */ + + regs.edx.l = sdi->rr.r.edx.b[0]; /* Drive number -> DL */ + } + + if (syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size)) + goto bail; + + syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, ®s); + +bail: + if (fraglist) + syslinux_free_movelist(fraglist); + if (mmap) + syslinux_free_memmap(mmap); + if (buf) + free(buf); + return; +} diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c index 7b2da880..a1cf50cc 100644 --- a/com32/elflink/ldlinux/cli.c +++ b/com32/elflink/ldlinux/cli.c @@ -19,8 +19,6 @@ #include "cli.h" #include "config.h" -static jmp_buf timeout_jump; - static struct list_head cli_history_head; void clear_screen(void) @@ -29,71 +27,37 @@ void clear_screen(void) fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout); } -static int __get_key(void) -{ - unsigned char buffer[KEY_MAXLEN]; - int another; - int nc, rv; - int code; - - nc = 0; - do { - buffer[nc++] = getchar(); - - another = 0; - rv = get_key_decode(buffer, nc, &code); - if (!rv) - return code; - else if (rv == 1) - another = 1; - - } while (another); - - /* We got an unrecognized sequence; return the first character */ - /* We really should remember this and return subsequent characters later */ - return buffer[0]; -} - -int mygetkey(clock_t timeout) +static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto) { - clock_t t0, t; - clock_t tto, to; + clock_t t0, t1; int key; - //dprintf("enter"); - if (!totaltimeout) - return __get_key(); - - for (;;) { - tto = min(totaltimeout, INT_MAX); - to = timeout ? min(tto, timeout) : tto; + t0 = times(NULL); + key = get_key(stdin, *kbd_to ? *kbd_to : *tto); - t0 = 0; - key = __get_key(); - t = 0 - t0; + /* kbdtimeout only applies to the first character */ + if (*kbd_to) + *kbd_to = 0; - if (totaltimeout <= t) - longjmp(timeout_jump, 1); + t1 = times(NULL) - t0; + if (*tto) { + /* Timed out. */ + if (*tto <= (long long)t1) + key = KEY_NONE; + else { + /* Did it wrap? */ + if (*tto > totaltimeout) + key = KEY_NONE; - totaltimeout -= t; - - if (key != KEY_NONE) { - //dprintf("get key 0x%x", key); - return key; - } - - if (timeout) { - if (timeout <= t) { - //dprintf("timeout"); - return KEY_NONE; - } - - timeout -= t; + *tto -= t1; } } + + return key; } -static const char * cmd_reverse_search(int *cursor) +static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to, + clock_t *tto) { int key; int i = 0; @@ -108,7 +72,7 @@ static const char * cmd_reverse_search(int *cursor) eprintf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m"); while (1) { - key = mygetkey(0); + key = mygetkey_timeout(kbd_to, tto); if (key == KEY_CTRL('C')) { return NULL; @@ -124,7 +88,7 @@ static const char * cmd_reverse_search(int *cursor) break; } - while (last_found != &cli_history_head) { + while (!list_is_last(&last_found->list, &cli_history_head)) { p = strstr(last_found->command, buf); if (p) break; @@ -164,7 +128,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , bool done = false; const char *ret; int width = 0; - struct cli_command *comm_counter; + struct cli_command *comm_counter = NULL; + clock_t kbd_to = kbdtimeout; + clock_t tto = totaltimeout; if (!width) { int height; @@ -199,7 +165,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , eprintf("\033[?7l\033[?25l"); if (y) eprintf("\033[%dA", y); - eprintf("\033[1G\033[1;36m%s \033[0m", input); + eprintf("\033[1G%s ", input); x = strlen(input); y = 0; @@ -230,9 +196,13 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , redraw = 0; } - key = mygetkey(0); + key = mygetkey_timeout(&kbd_to, &tto); switch (key) { + case KEY_NONE: + /* We timed out. */ + return NULL; + case KEY_CTRL('L'): redraw = 2; break; @@ -406,7 +376,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , * Handle this case in another function, since it's * a kind of special. */ - const char *p = cmd_reverse_search(&cursor); + const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto); if (p) { strcpy(cmdline, p); len = strlen(cmdline); @@ -479,17 +449,14 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , return len ? ret : NULL; } -static int cli_init(void) +static int __constructor cli_init(void) { INIT_LIST_HEAD(&cli_history_head); return 0; } -static void cli_exit(void) +static void __destructor cli_exit(void) { /* Nothing to do */ } - -MODULE_INIT(cli_init); -MODULE_EXIT(cli_exit); diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h index c34b2cc6..45832022 100644 --- a/com32/elflink/ldlinux/config.h +++ b/com32/elflink/ldlinux/config.h @@ -35,9 +35,16 @@ extern short nohalt; //idle.inc extern const char *default_cmd; //"default" command line extern const char *onerror; //"onerror" command line +extern const char *ontimeout; //"ontimeout" command line extern void cat_help_file(int key); +extern struct menu_entry *find_label(const char *str); +extern void print_labels(const char *prefix, size_t len); extern void eprintf(const char *filename, ...); +extern int new_linux_kernel(char *okernel, char *ocmdline); + +extern void pm_load_high(com32sys_t *regs); + #endif /* __CONFIG_H__ */ diff --git a/com32/elflink/ldlinux/eprintf.c b/com32/elflink/ldlinux/eprintf.c index d8858ff9..f15edc6e 100644 --- a/com32/elflink/ldlinux/eprintf.c +++ b/com32/elflink/ldlinux/eprintf.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> +#include <core.h> #define BUFFER_SIZE 4096 diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index 2b265a11..77d268c8 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -17,31 +17,39 @@ #include <com32.h> #include <sys/exec.h> +#include <sys/io.h> #include "core.h" #include "menu.h" - -/* Must match enum kernel_type */ -const char *const kernel_types[] = { - "none", - "localboot", - "kernel", - "linux", - "boot", - "bss", - "pxe", - "fdimage", - "comboot", - "com32", - "config", - NULL +#include "fs.h" +#include "config.h" +#include "localboot.h" +#include "bios.h" + +#include <syslinux/bootrm.h> +#include <syslinux/movebits.h> +#include <syslinux/config.h> +#include <syslinux/boot.h> + +const struct image_types image_boot_types[] = { + { "localboot", IMAGE_TYPE_LOCALBOOT }, + { "kernel", IMAGE_TYPE_KERNEL }, + { "linux", IMAGE_TYPE_LINUX }, + { "boot", IMAGE_TYPE_BOOT }, + { "bss", IMAGE_TYPE_BSS }, + { "pxe", IMAGE_TYPE_PXE }, + { "fdimage", IMAGE_TYPE_FDIMAGE }, + { "comboot", IMAGE_TYPE_COMBOOT }, + { "com32", IMAGE_TYPE_COM32 }, + { "config", IMAGE_TYPE_CONFIG }, + { NULL, 0 }, }; extern int create_args_and_load(char *); -void execute(const char *cmdline, enum kernel_type type) +void execute(const char *cmdline, uint32_t type) { - const char *p, *const *pp; const char *kernel, *args; + const char *p; com32sys_t ireg; char *q; @@ -70,46 +78,44 @@ void execute(const char *cmdline, enum kernel_type type) dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type); - if (kernel[0] == '.' && type == KT_NONE) { + if (kernel[0] == '.') { /* It might be a type specifier */ - enum kernel_type type = KT_NONE; - for (pp = kernel_types; *pp; pp++, type++) { - if (!strcmp(kernel + 1, *pp)) - execute(p, type); /* Strip the type specifier and retry */ + const struct image_types *t; + for (t = image_boot_types; t->name; t++) { + if (!strcmp(kernel + 1, t->name)) { + /* Strip the type specifier and retry */ + execute(p, t->type); + return; + } } } - if (type == KT_COM32) { + if (type == IMAGE_TYPE_COM32) { /* new entry for elf format c32 */ - lfree(kernel); - create_args_and_load(cmdline); - } else if (type == KT_KERNEL) { - /* Need add one item for kernel load, as we don't use - * the assembly runkernel.inc any more */ - new_linux_kernel(kernel, cmdline); - } else if (type == KT_CONFIG) { + create_args_and_load((char *)cmdline); + } else if (type == IMAGE_TYPE_CONFIG) { + char *argv[] = { "ldlinux.c32", NULL }; + /* kernel contains the config file name */ - char *spawn_load_param[2] = { args, NULL }; - spawn_load(kernel, 1, spawn_load_param); + realpath(ConfigName, kernel, FILENAME_MAX); + + /* If we got anything on the command line, do a chdir */ + if (*args) + mangle_name(config_cwd, args); + + start_ldlinux(argv); + } else if (type == IMAGE_TYPE_LOCALBOOT) { + local_boot(strtoul(kernel, NULL, 0)); + } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS || + type == IMAGE_TYPE_BOOT) { + chainboot_file(kernel, type); } else { - /* process the image need int 22 support */ - if (type == KT_LOCALBOOT) { - ireg.eax.w[0] = 0x0014; /* Local boot */ - ireg.edx.w[0] = strtoul(kernel, NULL, 0); - } else { - ireg.eax.w[0] = 0x0016; /* Run kernel image */ - ireg.esi.w[0] = OFFS(kernel); - ireg.ds = SEG(kernel); - ireg.ebx.w[0] = OFFS(args); - ireg.es = SEG(args); - ireg.edx.l = type - KT_KERNEL; - /* ireg.ecx.l = 0; *//* We do ipappend "manually" */ - } - - __intcall(0x22, &ireg, NULL); + /* Need add one item for kernel load, as we don't use + * the assembly runkernel.inc any more */ + new_linux_kernel((char *)kernel, (char *)cmdline); } - lfree(kernel); + lfree((void *)kernel); /* If this returns, something went bad; return to menu */ } diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c index 42ff5c12..0be06b98 100644 --- a/com32/elflink/ldlinux/get_key.c +++ b/com32/elflink/ldlinux/get_key.c @@ -148,10 +148,10 @@ int get_key_decode(char *buffer, int nc, int *code) int get_key(FILE * f, clock_t timeout) { - unsigned char buffer[KEY_MAXLEN]; - int nc, i, rv; + char buffer[KEY_MAXLEN]; + int nc, rv; int another; - unsigned char ch; + char ch; clock_t start; int code; @@ -167,7 +167,7 @@ int get_key(FILE * f, clock_t timeout) clock_t lateness = times(NULL) - start; if (nc && lateness > 1 + KEY_TIMEOUT) { if (nc == 1) - return buffer[0]; /* timeout in sequence */ + return (unsigned char)buffer[0]; /* timeout */ else if (timeout && lateness > timeout) return KEY_NONE; } else if (!nc && timeout && lateness > timeout) @@ -194,5 +194,5 @@ int get_key(FILE * f, clock_t timeout) /* We got an unrecognized sequence; return the first character */ /* We really should remember this and return subsequent characters later */ - return buffer[0]; + return (unsigned char)buffer[0]; } diff --git a/com32/elflink/ldlinux/ipappend.c b/com32/elflink/ldlinux/ipappend.c deleted file mode 100644 index 45e2c3a7..00000000 --- a/com32/elflink/ldlinux/ipappend.c +++ /dev/null @@ -1,48 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2008 H. Peter Anvin - All Rights Reserved - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall - * be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * ----------------------------------------------------------------------- */ - -/* - * syslinux/ipappend.c - * - * Get ipappend strings - */ - -#include <syslinux/firmware.h> -#include <syslinux/config.h> - -struct syslinux_ipappend_strings __syslinux_ipappend_strings; - -void __syslinux_get_ipappend_strings(void) -{ - char *list; - int count; - - if (firmware->ipappend_strings(&list, &count)) { - __syslinux_ipappend_strings.count = count; - __syslinux_ipappend_strings.ptr = list; - } -} diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c index bdcd3cb1..b8f9cb8d 100644 --- a/com32/elflink/ldlinux/kernel.c +++ b/com32/elflink/ldlinux/kernel.c @@ -15,15 +15,14 @@ const char *append = NULL; /* Will be called from readconfig.c */ int new_linux_kernel(char *okernel, char *ocmdline) { - const char *kernel_name; - struct initramfs *initramfs; + const char *kernel_name = NULL; + struct initramfs *initramfs = NULL; char *temp; void *kernel_data; size_t kernel_len; bool opt_quiet = false; char initrd_name[256]; char cmdline_buf[256], *cmdline; - int i; dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline); @@ -98,36 +97,41 @@ int new_linux_kernel(char *okernel, char *ocmdline) if (!opt_quiet) printf("ok\n"); - /* Initialize the initramfs chain */ - initramfs = initramfs_init(); - if (!initramfs) - goto bail; - /* Find and load initramfs */ temp = strstr(cmdline, "initrd="); if (temp) { - char *p; + /* Initialize the initramfs chain */ + initramfs = initramfs_init(); + if (!initramfs) + goto bail; - temp += strlen("initrd="); + temp += 6; /* strlen("initrd") */ do { - p = strchr(temp, ','); - if (p) - *p = '\0'; - - if (initramfs_load_archive(initramfs, temp)) { - printf("failed!\n"); - goto bail; - } - - if (p) - *p++ = ','; - } while ((temp = p)); - } + char *p = initrd_name; + + temp++; /* Skip = or , */ - //dprintf("loading initrd done"); + while (*temp != ' ' && *temp != ',' && *temp) + *p++ = *temp++; + *p = '\0'; + + if (!opt_quiet) + printf("Loading %s...", initrd_name); + + if (initramfs_load_archive(initramfs, initrd_name)) { + if (opt_quiet) + printf("Loading %s ", initrd_name); + printf("failed!\n"); + goto bail; + } + + if (!opt_quiet) + printf("ok\n"); + } while (*temp == ','); + } /* This should not return... */ - syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline); + syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, cmdline); bail: printf("Kernel load failure (insufficient memory?)\n"); diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c index 53604179..073f1116 100644 --- a/com32/elflink/ldlinux/ldlinux.c +++ b/com32/elflink/ldlinux/ldlinux.c @@ -1,16 +1,135 @@ #include <linux/list.h> #include <sys/times.h> +#include <fcntl.h> #include <stdbool.h> +#include <string.h> #include <core.h> +#include <fs.h> #include "cli.h" #include "console.h" #include "com32.h" #include "menu.h" #include "config.h" #include "syslinux/adv.h" +#include "syslinux/boot.h" #include <sys/module.h> +struct file_ext { + const char *name; + enum kernel_type type; +}; + +static const struct file_ext file_extensions[] = { + { ".com", IMAGE_TYPE_COMBOOT }, + { ".cbt", IMAGE_TYPE_COMBOOT }, + { ".c32", IMAGE_TYPE_COM32 }, + { ".img", IMAGE_TYPE_FDIMAGE }, + { ".bss", IMAGE_TYPE_BSS }, + { ".bin", IMAGE_TYPE_BOOT }, + { ".bs", IMAGE_TYPE_BOOT }, + { ".0", IMAGE_TYPE_PXE }, + { NULL, 0 }, +}; + +/* + * Return a pointer to one byte after the last character of the + * command. + */ +static inline const char *find_command(const char *str) +{ + const char *p; + + p = str; + while (*p && !my_isspace(*p)) + p++; + return p; +} + +uint32_t parse_image_type(const char *kernel) +{ + const struct file_ext *ext; + const char *p; + int len; + + /* Find the end of the command */ + p = find_command(kernel); + len = p - kernel; + + for (ext = file_extensions; ext->name; ext++) { + int elen = strlen(ext->name); + + if (!strncmp(kernel + len - elen, ext->name, elen)) + return ext->type; + } + + /* use IMAGE_TYPE_KERNEL as default */ + return IMAGE_TYPE_KERNEL; +} + +/* + * Returns the kernel name with file extension if one wasn't present. + */ +static const char *get_extension(const char *kernel) +{ + const struct file_ext *ext; + const char *p; + int len; + + /* Find the end of the command */ + p = find_command(kernel); + len = p - kernel; + + for (ext = file_extensions; ext->name; ext++) { + char *str; + int elen = strlen(ext->name); + int fd; + + str = malloc(len + elen + 1); + + strncpy(str, kernel, len); + strncpy(str + len, ext->name, elen); + str[len + elen] = '\0'; + + fd = searchdir(str); + free(str); + + if (fd >= 0) + return ext->name; + } + + return NULL; +} + +static const char *apply_extension(const char *kernel, const char *ext) +{ + const char *p; + char *k; + int len = strlen(kernel); + int elen = strlen(ext); + + k = malloc(len + elen + 1); + if (!k) + return NULL; + + p = find_command(kernel); + + len = p - kernel; + + /* Copy just the kernel name */ + memcpy(k, kernel, len); + + /* Append the extension */ + memcpy(k + len, ext, elen); + + /* Copy the rest of the command line */ + strcpy(k + len + elen, p); + + k[len + elen + strlen(p)] = '\0'; + + return k; +} + /* * Attempt to load a kernel after deciding what type of image it is. * @@ -18,21 +137,21 @@ * the the kernel. If we return the caller should call enter_cmdline() * so that the user can help us out. */ -static void load_kernel(const char *kernel) +void load_kernel(const char *command_line) { struct menu_entry *me; - enum kernel_type type; - const char *cmdline, *p; - int len; + const char *cmdline; + const char *kernel; + uint32_t type; + + kernel = strdup(command_line); + if (!kernel) + goto bad_kernel; /* Virtual kernel? */ me = find_label(kernel); if (me) { - enum kernel_type type = KT_KERNEL; - - /* cmdline contains type specifier */ - if (me->cmdline[0] == '.') - type = KT_NONE; + type = parse_image_type(me->cmdline); execute(me->cmdline, type); /* We shouldn't return */ @@ -42,33 +161,37 @@ static void load_kernel(const char *kernel) if (!allowimplicit) goto bad_implicit; - p = kernel; - /* Find the end of the command */ - while (*p && !my_isspace(*p)) - p++; + /* Insert a null character to ignore any user-specified options */ + if (!allowoptions) { + char *p = (char *)find_command(kernel); + *p = '\0'; + } - len = p - kernel; - if (!strncmp(kernel + len - 4, ".c32", 4)) { - type = KT_COM32; - } else if (!strncmp(kernel + len - 2, ".0", 2)) { - type = KT_PXE; - } else if (!strncmp(kernel + len - 3, ".bs", 3)) { - type = KT_BOOT; - } else if (!strncmp(kernel + len - 4, ".img", 4)) { - type = KT_FDIMAGE; - } else if (!strncmp(kernel + len - 4, ".bin", 4)) { - type = KT_BOOT; - } else if (!strncmp(kernel + len - 4, ".bss", 4)) { - type = KT_BSS; - } else if (!strncmp(kernel + len - 4, ".com", 4) || - !strncmp(kernel + len - 4, ".cbt", 4)) { - type = KT_COMBOOT; + type = parse_image_type(kernel); + if (type == IMAGE_TYPE_KERNEL) { + const char *ext; + + /* + * Automatically lookup the extension if one wasn't + * supplied by the user. + */ + ext = get_extension(kernel); + if (ext) { + const char *k; + + k = apply_extension(kernel, ext); + if (!k) + goto bad_kernel; + + free((void *)kernel); + kernel = k; + + type = parse_image_type(kernel); + } } - /* use KT_KERNEL as default */ - else - type = KT_KERNEL; execute(kernel, type); + free((void *)kernel); bad_implicit: bad_kernel: @@ -78,7 +201,7 @@ bad_kernel: */ if (onerrorlen) { rsprintf(&cmdline, "%s %s", onerror, default_cmd); - execute(cmdline, KT_COM32); + execute(cmdline, IMAGE_TYPE_COM32); } } @@ -88,43 +211,41 @@ static void enter_cmdline(void) /* Enter endless command line prompt, should support "exit" */ while (1) { - cmdline = edit_cmdline("syslinux$", 1, NULL, cat_help_file); - if (!cmdline) - continue; - - /* return if user only press enter */ - if (cmdline[0] == '\0') { - printf("\n"); - continue; - } + cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file); printf("\n"); + /* return if user only press enter or we timed out */ + if (!cmdline || cmdline[0] == '\0') + return; + load_kernel(cmdline); } } -int main(int argc, char **argv) +int main(int argc __unused, char **argv __unused) { - com32sys_t ireg, oreg; - uint8_t *adv; - int count = 0; + const void *adv; + const char *cmdline; + size_t count = 0; + char *config_argv[2] = { NULL, NULL }; openconsole(&dev_rawcon_r, &dev_ansiserial_w); - __syslinux_get_ipappend_strings(); - parse_configs(NULL); + if (ConfigName[0]) + config_argv[0] = ConfigName; + + parse_configs(config_argv); - __syslinux_init(); adv = syslinux_getadv(ADV_BOOTONCE, &count); if (adv && count) { /* * We apparently have a boot-once set; clear it and * then execute the boot-once. */ - uint8_t *src, *dst, *cmdline; - int i; + char *src, *dst; + size_t i; - src = adv; + src = (char *)adv; cmdline = dst = malloc(count + 1); if (!dst) { printf("Failed to allocate memory for ADV\n"); @@ -148,12 +269,14 @@ int main(int argc, char **argv) if (forceprompt) goto cmdline; + cmdline = default_cmd; +auto_boot: /* * Auto boot */ if (defaultlevel || noescape) { if (defaultlevel) { - load_kernel(default_cmd); /* Shouldn't return */ + load_kernel(cmdline); /* Shouldn't return */ } else { printf("No DEFAULT or UI configuration directive found!\n"); @@ -163,8 +286,12 @@ int main(int argc, char **argv) } cmdline: - /* Should never return */ + /* Only returns if the user pressed enter or input timed out */ enter_cmdline(); + cmdline = ontimeoutlen ? ontimeout : default_cmd; + + goto auto_boot; + return 0; } diff --git a/com32/elflink/ldlinux/loadhigh.c b/com32/elflink/ldlinux/loadhigh.c new file mode 100644 index 00000000..0f2f8428 --- /dev/null +++ b/com32/elflink/ldlinux/loadhigh.c @@ -0,0 +1,112 @@ +/* + * ----------------------------------------------------------------------- + * + * Copyright 1994-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 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. + * + * ----------------------------------------------------------------------- */ + +/* + * loadhigh.c + * + * An alternate interface to getfssec. + * + * Inputs: SI = file handle/cluster pointer + * EDI = target address in high memory + * EAX = maximum number of bytes to load + * DX = zero-padding mask (e.g. 0003h for pad to dword) + * BX = 16-bit subroutine to call at the top of each loop + * (to print status and check for abort) + * EBP = maximum load address + * + * Outputs: SI = file handle/cluster pointer + * EBX = first untouched address (not including padding) + * EDI = first untouched address (including padding) + * CF = reached EOF + * OF = ran out of high memory + */ + +#include <com32.h> +#include <minmax.h> +#include "core.h" +#include "fs.h" + +#define MAX_CHUNK (1UL << 20) /* 1 MB */ + +void pm_load_high(com32sys_t *regs) +{ + struct fs_info *fs; + uint32_t bytes; + uint32_t zero_mask; + bool have_more; + uint32_t bytes_read; + char *buf, *limit; + struct file *file; + uint32_t sector_mask; + size_t pad; + uint32_t retflags = 0; + + bytes = regs->eax.l; + zero_mask = regs->edx.w[0]; + buf = (char *)regs->edi.l; + limit = (char *)(regs->ebp.l & ~zero_mask); + file = handle_to_file(regs->esi.w[0]); + fs = file->fs; + + sector_mask = SECTOR_SIZE(fs) - 1; + + while (bytes) { + uint32_t sectors; + uint32_t chunk; + + if (buf + SECTOR_SIZE(fs) > limit) { + /* Can't fit even one more sector in... */ + retflags = EFLAGS_OF; + break; + } + + chunk = bytes; + + if (regs->ebx.w[0]) { + call16((void (*)(void))(size_t)regs->ebx.w[0], &zero_regs, NULL); + chunk = min(chunk, MAX_CHUNK); + } + + if (chunk > (((char *)limit - buf) & ~sector_mask)) + chunk = ((char *)limit - buf) & ~sector_mask; + + sectors = (chunk + sector_mask) >> SECTOR_SHIFT(fs); + bytes_read = fs->fs_ops->getfssec(file, buf, sectors, &have_more); + + if (bytes_read > chunk) + bytes_read = chunk; + + buf += bytes_read; + bytes -= bytes_read; + + if (!have_more) { + /* + * If we reach EOF, the filesystem driver will have already closed + * the underlying file... this really should be cleaner. + */ + _close_file(file); + regs->esi.w[0] = 0; + retflags = EFLAGS_CF; + break; + } + } + + pad = (size_t)buf & zero_mask; + if (pad) + memset(buf, 0, pad); + + regs->ebx.l = (size_t)buf; + regs->edi.l = (size_t)buf + pad; + set_flags(regs, retflags); +} diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c index 564cbeff..1db397a1 100644 --- a/com32/elflink/ldlinux/readconfig.c +++ b/com32/elflink/ldlinux/readconfig.c @@ -52,6 +52,22 @@ const struct menu_parameter mparm[NPARAMS] = { [P_HIDDEN_ROW] = {"hiddenrow", -2}, }; +/* Must match enum kernel_type */ +static const char *const kernel_types[] = { + "none", + "localboot", + "kernel", + "linux", + "boot", + "bss", + "pxe", + "fdimage", + "comboot", + "com32", + "config", + NULL +}; + short uappendlen = 0; //bytes in append= command short ontimeoutlen = 0; //bytes in ontimeout command short onerrorlen = 0; //bytes in onerror command @@ -68,6 +84,7 @@ short nohalt = 1; //idle.inc const char *default_cmd = NULL; //"default" command line const char *onerror = NULL; //"onerror" command line +const char *ontimeout = NULL; //"ontimeout" command line /* Empty refstring */ const char *empty_string; @@ -79,6 +96,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu; int shiftkey = 0; /* Only display menu if shift key pressed */ int hiddenmenu = 0; long long totaltimeout = 0; +unsigned int kbdtimeout = 0; /* Keep track of global default */ static int has_ui = 0; /* DEFAULT only counts if UI is found */ @@ -1081,13 +1099,14 @@ do_include: //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type); } } else if (looking_at(p, "timeout")) { - m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10; + kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10; } else if (looking_at(p, "totaltimeout")) { totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10; } else if (looking_at(p, "ontimeout")) { - m->ontimeout = refstrdup(skipspace(p + 9)); + ontimeout = refstrdup(skipspace(p + 9)); + ontimeoutlen = strlen(ontimeout); } else if (looking_at(p, "allowoptions")) { - m->allowedit = !!atoi(skipspace(p + 12)); + allowoptions = !!atoi(skipspace(p + 12)); } else if (looking_at(p, "ipappend")) { if (ld.label) ld.ipappend = atoi(skipspace(p + 8)); @@ -1121,7 +1140,8 @@ do_include: * display/font/kbdmap are rather similar, open a file then do sth */ else if (looking_at(p, "display")) { - char *filename, *dst = KernelName; + const char *filename; + char *dst = KernelName; size_t len = FILENAME_MAX - 1; filename = refstrdup(skipspace(p + 7)); @@ -1133,7 +1153,8 @@ do_include: get_msg_file(KernelName); refstr_put(filename); } else if (looking_at(p, "font")) { - char *filename, *dst = KernelName; + const char *filename; + char *dst = KernelName; size_t len = FILENAME_MAX - 1; filename = refstrdup(skipspace(p + 4)); @@ -1145,8 +1166,8 @@ do_include: loadfont(KernelName); refstr_put(filename); } else if (looking_at(p, "kbdmap")) { - com32sys_t reg; - char *filename, *dst = KernelName; + const char *filename; + char *dst = KernelName; size_t len = FILENAME_MAX - 1; filename = refstrdup(skipspace(p + 4)); @@ -1189,7 +1210,6 @@ do_include: /* serial setting, bps, flow control */ else if (looking_at(p, "serial")) { - com32sys_t ireg; uint16_t port, flow; uint32_t baud; @@ -1309,18 +1329,20 @@ do_include: eprintf("%s\n", p+4); } else if (looking_at(p, "path")) { /* PATH-based lookup */ - char *new_path, *_p; + const char *new_path; + char *_p; size_t len, new_len; new_path = refstrdup(skipspace(p + 4)); len = strlen(PATH); new_len = strlen(new_path); - _p = realloc(PATH, len + new_len + 2); + _p = malloc(len + new_len + 2); if (_p) { strncpy(_p, PATH, len); _p[len++] = ':'; strncpy(_p + len, new_path, new_len); _p[len + new_len] = '\0'; + free(PATH); PATH = _p; } else eprintf("Failed to realloc PATH\n"); @@ -1345,6 +1367,11 @@ static int parse_one_config(const char *filename) f = fdopen(fd, mode); parse_config_file(f); + if (config_cwd[0]) { + chdir(config_cwd); + config_cwd[0] = '\0'; + } + return 0; } |