aboutsummaryrefslogtreecommitdiffstats
path: root/com32
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@linux.intel.com>2011-04-08 13:21:51 +0100
committerMatt Fleming <matt.fleming@linux.intel.com>2011-04-26 09:53:31 +0100
commit43d7cbaa55806ecb33b0cc5aa56e97b0f8027c45 (patch)
treebfe0b4d22649c6e4859fe85cbe46063c4436b3b0 /com32
parent990e7e1df3dc6fa456ff7cdaec7d239977557c8d (diff)
downloadsyslinux-43d7cbaa55806ecb33b0cc5aa56e97b0f8027c45.tar.gz
syslinux-43d7cbaa55806ecb33b0cc5aa56e97b0f8027c45.tar.xz
syslinux-43d7cbaa55806ecb33b0cc5aa56e97b0f8027c45.zip
elflink: Move more code from core/ into ldlinux
ldlinux now contains all the code necessary to load and execute modules, none is contained in the core. This change also allows us to change the spawn_load() prototype and to push the job of processing arguments to executable functions (e.g. the contents of char *argv[] as passed to a module's main function) into ldlinux/execute.c instead of doing it in spawn_load(). Moving it into ldlinux/ makes sense because the only core user of spawn_load() is load_env32() and we don't require any sort of argument processing in that path. Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
Diffstat (limited to 'com32')
-rw-r--r--com32/elflink/ldlinux/Makefile2
-rw-r--r--com32/elflink/ldlinux/execute.c171
-rw-r--r--com32/elflink/ldlinux/kernel.c128
-rw-r--r--com32/include/sys/exec.h3
-rw-r--r--com32/lib/sys/module/exec.c47
5 files changed, 327 insertions, 24 deletions
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 6fbe1b16..09aa4af4 100644
--- a/com32/elflink/ldlinux/Makefile
+++ b/com32/elflink/ldlinux/Makefile
@@ -19,7 +19,7 @@ CFLAGS += -I../modules -I$(topdir)/core/elflink -I$(topdir)/core/include
all: ldlinux.c32
ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
- adv.o ipappend.o
+ adv.o ipappend.o execute.o kernel.o
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
new file mode 100644
index 00000000..f67d707b
--- /dev/null
+++ b/com32/elflink/ldlinux/execute.c
@@ -0,0 +1,171 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dprintf.h>
+
+#include <com32.h>
+#include <sys/exec.h>
+#include "core.h"
+#include "core-elf.h"
+
+/* Must match enum kernel_type */
+const char *const kernel_types[] = {
+ "none",
+ "localboot",
+ "kernel",
+ "linux",
+ "boot",
+ "bss",
+ "pxe",
+ "fdimage",
+ "comboot",
+ "com32",
+ "config",
+ NULL
+};
+
+static inline int my_isspace(char c)
+{
+ return (unsigned char)c <= ' ';
+}
+
+void execute(const char *cmdline, enum kernel_type type)
+{
+ const char *p, *const *pp;
+ const char *kernel, *args;
+ com32sys_t ireg;
+ char *q;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ /* for parameter will be passed to __intcall, we need use
+ * lmalloc a block of low memory */
+ q = lmalloc(128);
+ if (!q) {
+ printf("%s(): Fail to lmalloc a buffer to exec %s\n",
+ __func__, cmdline);
+ return;
+ }
+
+ kernel = q;
+ p = cmdline;
+ while (*p && !my_isspace(*p))
+ *q++ = *p++;
+ *q++ = '\0';
+
+ args = q;
+ while (*p && my_isspace(*p))
+ p++;
+
+ strcpy(q, p);
+
+ dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type);
+
+ if (kernel[0] == '.' && type == KT_NONE) {
+ /* 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 */
+ }
+ }
+
+ if (type == KT_COM32) {
+ /* new entry for elf format c32 */
+ char **argv;
+ int i, argc;
+
+ q = args;
+ for (argc = 0; *q; q++) {
+ argc++;
+
+ /* Find the end of this arg */
+ while(*q && !my_isspace(*q))
+ q++;
+
+ /*
+ * Now skip all whitespace between arguments.
+ */
+ while (*q && my_isspace(*q))
+ q++;
+ }
+
+ /*
+ * Generate a copy of argv on the stack as this is
+ * traditionally where process arguments go.
+ *
+ * argv[0] must be the command name, so bump argc to
+ * include argv[0].
+ */
+ argc += 1;
+ argv = alloca(argc * sizeof(char *));
+ argv[0] = kernel;
+
+ for (q = args, i = 1; i < argc - 1; i++) {
+ char *start;
+ int len = 0;
+
+ start = q;
+
+ /* Find the end of this arg */
+ while(*q && !my_isspace(*q)) {
+ q++;
+ len++;
+ }
+
+ argv[i] = malloc(len + 1);
+ strncpy(argv[i], start, len);
+ argv[i][len] = '\0';
+
+ /*
+ * Now skip all whitespace between arguments.
+ */
+ while (*q && my_isspace(*q))
+ q++;
+ }
+
+ argv[argc] = NULL;
+ module_load_dependencies(kernel, "modules.dep");
+ spawn_load(kernel, argc, argv);
+ } 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) {
+ /* kernel contains the config file name */
+ char *spawn_load_param[2] = { args, NULL };
+ module_load_dependencies("ui.c32", "modules.dep");
+ spawn_load(kernel, 1, spawn_load_param);
+ } 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);
+ }
+ 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);
+ }
+
+ lfree(kernel);
+
+ /* If this returns, something went bad; return to menu */
+}
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
new file mode 100644
index 00000000..3ce2358d
--- /dev/null
+++ b/com32/elflink/ldlinux/kernel.c
@@ -0,0 +1,128 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <dprintf.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/linux.h>
+#include <syslinux/pxe.h>
+#include "core.h"
+#include "core-elf.h"
+
+const char *globaldefault = NULL;
+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;
+ 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);
+
+ cmdline = cmdline_buf;
+
+ temp = cmdline;
+ /*
+ strcpy(temp, "BOOT_IMAGE=");
+ temp += 11;
+ */
+
+ if (okernel)
+ kernel_name = okernel;
+ else if (globaldefault)
+ kernel_name = globaldefault;
+
+ strcpy(temp, kernel_name);
+ temp += strlen(kernel_name);
+
+ /* in elflink branch, KernelCName no more exist */
+ /*
+ else {
+ strcpy(temp, KernelCName);
+ temp += strlen(KernelCName);
+ kernel_name = KernelCName;
+ }
+ */
+
+ *temp = ' ';
+ temp++;
+ if (ocmdline)
+ strcpy(temp, ocmdline);
+ else if (append)
+ strcpy(temp, append);
+ /*
+ else if (*(char *)CmdOptPtr)
+ strcpy(temp, (char *)CmdOptPtr);
+ else if (AppendLen) {
+ for (i = 0; i < AppendLen; i++)
+ *temp++ = AppendBuf[i];
+ *temp = '\0';
+ }
+ */
+
+ printf("cmdline = %s\n", cmdline);
+ /*
+ printf("VkernelEnd = %x\n", VKernelEnd);
+ printf("HighMemSize = %x\n", __com32.cs_memsize);
+ */
+
+ /* "keeppxe" handling */
+#if IS_PXELINUX
+ extern char KeepPXE;
+
+ if (strstr(cmdline, "keeppxe"))
+ KeepPXE |= 1;
+#endif
+
+ if (strstr(cmdline, "quiet"))
+ opt_quiet = true;
+
+ if (!opt_quiet)
+ printf("Loading %s... ", kernel_name);
+
+ if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
+ if (opt_quiet)
+ printf("Loading %s ", kernel_name);
+ printf("failed!\n");
+ goto bail;
+ }
+
+ 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) {
+ i = 0;
+
+ temp += strlen("initrd=");
+ while (*temp != ' ' && *temp)
+ initrd_name[i++] = *temp++;
+ initrd_name[i] = '\0';
+
+ initramfs_load_archive(initramfs, initrd_name);
+ }
+
+ //dprintf("loading initrd done");
+
+ /* This should not return... */
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+
+bail:
+ printf("Kernel load failure (insufficient memory?)\n");
+ return 1;
+}
diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h
index 31b62beb..656f8e2a 100644
--- a/com32/include/sys/exec.h
+++ b/com32/include/sys/exec.h
@@ -33,6 +33,7 @@
* spawn_load - Load a library module or executes an executable one
* @name the name of the library/executable to use, including the extension
* (e.g. 'sort.c32')
+ * @argc: the number of string arguments in @argv
* @argv: a NULL-terminated vector of string arguments, starting with
* the program name.
*
@@ -40,7 +41,7 @@
* kind of module it is ( executable or library ), after which is performs the
* appropriate action, either spawning or simply loading the module into memory.
*/
-extern int spawn_load(const char *name,const char **argv);
+extern int spawn_load(const char *name, int argc, char **argv);
extern int module_load_dependencies(const char*name,const char*dep_file);
diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c
index 78df72e9..1ed3263b 100644
--- a/com32/lib/sys/module/exec.c
+++ b/com32/lib/sys/module/exec.c
@@ -220,12 +220,25 @@ int spawnl(const char *name, const char *arg, ...)
struct elf_module *cur_module;
-int spawn_load(const char *name,const char **argv)
+/*
+ * Load a module and runs its start function.
+ *
+ * For library modules the start function is module->init_func and for
+ * executable modules its module->main_func.
+ *
+ * "name" is the name of the module to load.
+ *
+ * "argv" and "argc" are only passed to module->main_func, for library
+ * modules these arguments can be NULL and 0, respectively.
+ *
+ * "argv" is an array of arguments to pass to module->main_func.
+ * argv[0] must be a pointer to "name" and argv[argc] must be NULL.
+ *
+ * "argc" is the number of arguments in "argv".
+ */
+int spawn_load(const char *name, int argc, char **argv)
{
int res, ret_val = 0;
- const char **arg;
- int argc;
- char **argp, **args;
struct elf_module *previous;
//malloc_tag_t prev_mem_tag;
struct elf_module *module = module_alloc(name);
@@ -238,6 +251,11 @@ int spawn_load(const char *name,const char **argv)
if (module == NULL)
return -1;
+ if (get_module_type(module) == EXEC_MODULE) {
+ if (!argc || !argv || strcmp(argv[0], name))
+ return -1;
+ }
+
if (!strcmp(cur_module->name, module->name)) {
dprintf("We is running this module %s already!", module->name);
@@ -295,21 +313,6 @@ int spawn_load(const char *name,const char **argv)
__syslinux_current = module;
//__mem_set_tag_global((malloc_tag_t)module);
- // Generate a new process copy of argv (on the stack)
- argc = 0;
- for (arg = argv; *arg; arg++)
- argc++;
-
- args = alloca((argc+1) * sizeof(char *));
-
- for (arg = argv, argp = args; *arg; arg++, argp++) {
- size_t l = strlen(*arg)+1;
- *argp = alloca(l);
- memcpy(*argp, *arg, l);
- }
-
- *args = NULL;
-
// Execute the program
ret_val = setjmp(module->u.x.process_exit);
@@ -318,7 +321,7 @@ int spawn_load(const char *name,const char **argv)
else if (!module->main_func)
ret_val = -1;
else
- exit((module->main_func)(argc, args)); /* Actually run! */
+ exit((module->main_func)(argc, argv)); /* Actually run! */
// Clean up the allocation context
@@ -468,13 +471,13 @@ int module_load_dependencies(const char *name,const char *dep_file)
i++; /* skip a space */
if (strlen(temp_name)) {
- char *argv[2] = { NULL, NULL };
+ char *argv[2] = { temp_name, NULL };
int ret;
ret = module_load_dependencies(temp_name,
MODULES_DEP);
if (!ret) {
- if (spawn_load(temp_name, argv) < 0)
+ if (spawn_load(temp_name, 1, argv) < 0)
continue;
}
}