aboutsummaryrefslogtreecommitdiffstats
path: root/com32/elflink/ldlinux
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-07-27 10:41:30 +0100
committerMatt Fleming <matt.fleming@intel.com>2012-07-30 09:51:36 +0100
commit0d6f330878173c7ba45b884f3e41ce40b917c73c (patch)
tree0a887066d35d8b01914330d6ab6818fe015a5a9d /com32/elflink/ldlinux
parent0fcd9a48603497dcc2727570a50a4401bb0fd085 (diff)
parentf0bbf9dd40f37f8c4870a33784996efd56955a75 (diff)
downloadsyslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.tar.gz
syslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.tar.xz
syslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.zip
Merge remote-tracking branch 'mfleming/elflink' into for-hpa/elflink/firmware
Conflicts: Makefile com32/elflink/ldlinux/adv.c com32/elflink/ldlinux/kernel.c com32/elflink/ldlinux/ldlinux.c com32/include/bitsize/stddef.h com32/include/bitsize/stdint.h com32/include/stdint.h com32/include/sys/module.h com32/include/sys/x86_64/bitops.h com32/include/syslinux/linux.h com32/lib/Makefile com32/lib/sys/ansicon_write.c com32/lib/sys/module/elfutils.h com32/lib/sys/vesa/efi/fill.h com32/lib/syslinux/load_linux.c com32/lib/syslinux/serial.c com32/lib/syslinux/shuffle.c core/conio.c core/elflink/config.c core/elflink/load_env32.c core/graphics.c core/include/graphics.h core/init.c core/pxelinux.asm mk/elf.mk mk/lib.mk
Diffstat (limited to 'com32/elflink/ldlinux')
-rw-r--r--com32/elflink/ldlinux/Makefile7
-rw-r--r--com32/elflink/ldlinux/adv.c6
-rw-r--r--com32/elflink/ldlinux/chainboot.c157
-rw-r--r--com32/elflink/ldlinux/cli.c103
-rw-r--r--com32/elflink/ldlinux/config.h7
-rw-r--r--com32/elflink/ldlinux/eprintf.c1
-rw-r--r--com32/elflink/ldlinux/execute.c102
-rw-r--r--com32/elflink/ldlinux/get_key.c10
-rw-r--r--com32/elflink/ldlinux/ipappend.c48
-rw-r--r--com32/elflink/ldlinux/kernel.c54
-rw-r--r--com32/elflink/ldlinux/ldlinux.c235
-rw-r--r--com32/elflink/ldlinux/loadhigh.c112
-rw-r--r--com32/elflink/ldlinux/readconfig.c47
13 files changed, 627 insertions, 262 deletions
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(&reg);
+
+ 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(&regs, 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, &regs);
+
+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;
}