aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-03-13 09:37:57 +0000
committerMatt Fleming <matt.fleming@intel.com>2012-03-23 16:56:15 +0000
commit3a316db137afe3b4c9d7f04fcf47921f509ef36c (patch)
treea9dff7c812d2414ce52ce3f311132e5ad6b997a1
parent8e0ed96bff75801f7430da88d83ea1b52827b123 (diff)
downloadsyslinux-3a316db137afe3b4c9d7f04fcf47921f509ef36c.tar.gz
syslinux-3a316db137afe3b4c9d7f04fcf47921f509ef36c.tar.xz
syslinux-3a316db137afe3b4c9d7f04fcf47921f509ef36c.zip
ldlinux: Loading a config file should cause re-initialisation
There are a number of initialisation steps that need to be performed *every* time a config file is loaded. Reload ldlinux.c32 so that we can re-initialise the environment whenever a new config file is loaded. This involves unloading all the modules that have been loaded since ldlinux.c32. Luckily the list of loaded modules is sorted by load order, which means it's trivial to "pop" them from the front of the list. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--com32/elflink/ldlinux/execute.c14
-rw-r--r--com32/elflink/ldlinux/ldlinux.c6
-rw-r--r--com32/include/linux/list.h13
-rw-r--r--com32/include/sys/module.h6
-rw-r--r--com32/lib/sys/module/elf_module.c4
-rw-r--r--core/elflink/config.c41
-rw-r--r--core/elflink/load_env32.c48
7 files changed, 82 insertions, 50 deletions
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 2b265a11..c01d63f4 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -19,6 +19,7 @@
#include <sys/exec.h>
#include "core.h"
#include "menu.h"
+#include "fs.h"
/* Must match enum kernel_type */
const char *const kernel_types[] = {
@@ -74,8 +75,10 @@ void execute(const char *cmdline, enum kernel_type type)
/* 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 (!strcmp(kernel + 1, *pp)) {
+ /* Strip the type specifier and retry */
+ execute(p, type);
+ }
}
}
@@ -88,9 +91,12 @@ void execute(const char *cmdline, enum kernel_type type)
* the assembly runkernel.inc any more */
new_linux_kernel(kernel, cmdline);
} else if (type == KT_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);
+
+ start_ldlinux("ldlinux.c32", 1, argv);
} else {
/* process the image need int 22 support */
if (type == KT_LOCALBOOT) {
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 03e2f60d..6c306ad5 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -118,10 +118,14 @@ int main(int argc, char **argv)
com32sys_t ireg, oreg;
uint8_t *adv;
int count = 0;
+ char *config_argv[2] = { NULL, NULL };
openconsole(&dev_rawcon_r, &dev_ansiserial_w);
- parse_configs(NULL);
+ if (ConfigName[0])
+ config_argv[0] = ConfigName;
+
+ parse_configs(config_argv);
__syslinux_init();
adv = syslinux_getadv(ADV_BOOTONCE, &count);
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index 3b92e254..afe89808 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -338,6 +338,19 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+* @pos: the type * to use as a loop cursor.
+* @n: another type * to use as temporary storage
+* @head: the head for your list.
+* @member: the name of the list_struct within the struct.
+*/
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index d10eae9c..a9ddb60d 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -199,6 +199,12 @@ extern struct list_head modules_head;
#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
/**
+ * for_each_module - iterator loop through the list of loaded modules safe against removal.
+ */
+#define for_each_module_safe(m, n) \
+ list_for_each_entry_safe(m, n, &modules_head, list)
+
+/**
* modules_init - initialize the module subsystem.
*
* This function must be called before any module operation is to be performed.
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index ffdcd525..6b4d548d 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -5,7 +5,7 @@
* Author: Stefan Bucur <stefanb@zytor.com>
*/
-
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -475,7 +475,7 @@ int module_load(struct elf_module *module) {
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
diff --git a/core/elflink/config.c b/core/elflink/config.c
deleted file mode 100644
index b27aa827..00000000
--- a/core/elflink/config.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2007-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.
- *
- * ----------------------------------------------------------------------- */
-
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
-
-const char *__syslinux_config_file;
-
-void __constructor __syslinux_get_config_file_name(void)
-{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x000e;
- __intcall(0x22, &reg, &reg);
- __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index 7ffe185b..75f56296 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -71,6 +71,50 @@ static void call_constr(void)
(*p) ();
}
+int start_ldlinux(char **argv)
+{
+ int rv;
+
+again:
+ rv = spawn_load(LDLINUX, 1, argv);
+ if (rv == EEXIST) {
+ struct elf_module *m, *mod, *begin = NULL;
+
+ /*
+ * If a COM32 module calls execute() we may need to
+ * unload all the modules loaded since ldlinux.c32,
+ * and restart initialisation. This is especially
+ * important for config files.
+ */
+ for_each_module(mod) {
+ if (!strcmp(mod->name, LDLINUX)) {
+ begin = mod;
+ break;
+ }
+ }
+
+ for_each_module_safe(mod, m) {
+ if (mod == begin)
+ break;
+
+ if (mod != begin)
+ module_unload(mod);
+ }
+
+ /*
+ * Finally unload LDLINUX.
+ *
+ * We'll reload it when we jump to 'again' which will
+ * cause all the initialsation steps to be executed
+ * again.
+ */
+ module_unload(begin);
+ goto again;
+ }
+
+ return rv;
+}
+
/* note to self: do _*NOT*_ use static key word on this function */
void load_env32(com32sys_t * regs)
{
@@ -97,7 +141,7 @@ void load_env32(com32sys_t * regs)
init_module_subsystem(&core_module);
- spawn_load(LDLINUX, 1, argv);
+ start_ldlinux(argv);
/*
* If we failed to load LDLINUX it could be because our
@@ -112,7 +156,7 @@ void load_env32(com32sys_t * regs)
fp = &__file_info[fd];
if (!search_config(&fp->i.fd, search_directories, filenames))
- spawn_load(LDLINUX, 1, argv);
+ start_ldlinux(argv);
}
int create_args_and_load(char *cmdline)