diff options
author | Matt Fleming <matt.fleming@linux.intel.com> | 2011-04-08 13:21:51 +0100 |
---|---|---|
committer | Matt Fleming <matt.fleming@linux.intel.com> | 2011-04-26 09:53:31 +0100 |
commit | 43d7cbaa55806ecb33b0cc5aa56e97b0f8027c45 (patch) | |
tree | bfe0b4d22649c6e4859fe85cbe46063c4436b3b0 /com32 | |
parent | 990e7e1df3dc6fa456ff7cdaec7d239977557c8d (diff) | |
download | syslinux-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/Makefile | 2 | ||||
-rw-r--r-- | com32/elflink/ldlinux/execute.c | 171 | ||||
-rw-r--r-- | com32/elflink/ldlinux/kernel.c | 128 | ||||
-rw-r--r-- | com32/include/sys/exec.h | 3 | ||||
-rw-r--r-- | com32/lib/sys/module/exec.c | 47 |
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; } } |