ldlinux: Return to command prompt after loading COM32
authorMatt Fleming <matt.fleming@intel.com>
Thu, 2 Aug 2012 08:26:54 +0000 (09:26 +0100)
committerMatt Fleming <matt.fleming@intel.com>
Thu, 2 Aug 2012 08:26:54 +0000 (09:26 +0100)
The old COM32 loading code would drop the user at a command prompt
once execution returned from the COM32 amodule. We need to replicate
this because most callers of execute() don't expect it to return.

This bug was noticed when loading a COM32 module from
vesamenu.c32. Once execution returned from the COM32 module the
display became garbled because no code exists to reinitialise the
screen for VGA.

Signed-off-by: Matt Fleming <matt.fleming@intel.com>
com32/elflink/ldlinux/config.h
com32/elflink/ldlinux/execute.c
com32/elflink/ldlinux/ldlinux.c
com32/include/sys/module.h
com32/lib/sys/module/common.c
core/elflink/load_env32.c

index 4583202..ea4736e 100644 (file)
@@ -47,4 +47,6 @@ extern int new_linux_kernel(char *okernel, char *ocmdline);
 
 extern void pm_load_high(com32sys_t *regs);
 
+extern void ldlinux_enter_command(bool prompt);
+
 #endif /* __CONFIG_H__ */
index 77d268c..e7969c2 100644 (file)
@@ -18,6 +18,7 @@
 #include <com32.h>
 #include <sys/exec.h>
 #include <sys/io.h>
+#include <sys/module.h>
 #include "core.h"
 #include "menu.h"
 #include "fs.h"
@@ -93,6 +94,15 @@ void execute(const char *cmdline, uint32_t type)
        if (type == IMAGE_TYPE_COM32) {
                /* new entry for elf format c32 */
                create_args_and_load((char *)cmdline);
+
+               /*
+                * The old COM32 module code would run the module then
+                * drop the user back at the command prompt,
+                * irrespective of how the COM32 module was loaded,
+                * e.g. from vesamenu.c32.
+                */
+               unload_modules_since("ldlinux.c32");
+               ldlinux_enter_command(!noescape);
        } else if (type == IMAGE_TYPE_CONFIG) {
                char *argv[] = { "ldlinux.c32", NULL };
 
index 073f111..ade161f 100644 (file)
@@ -222,6 +222,35 @@ static void enter_cmdline(void)
        }
 }
 
+void ldlinux_enter_command(bool prompt)
+{
+       const char *cmdline = default_cmd;
+
+       if (prompt)
+               goto cmdline;
+auto_boot:
+       /*
+        * Auto boot
+        */
+       if (defaultlevel || noescape) {
+               if (defaultlevel) {
+                       load_kernel(cmdline); /* Shouldn't return */
+               } else {
+                       printf("No DEFAULT or UI configuration directive found!\n");
+
+                       if (noescape)
+                               kaboom();
+               }
+       }
+
+cmdline:
+       /* Only returns if the user pressed enter or input timed out */
+       enter_cmdline();
+
+       cmdline = ontimeoutlen ? ontimeout : default_cmd;
+
+       goto auto_boot;
+}
 int main(int argc __unused, char **argv __unused)
 {
        const void *adv;
@@ -249,7 +278,7 @@ int main(int argc __unused, char **argv __unused)
                cmdline = dst = malloc(count + 1);
                if (!dst) {
                        printf("Failed to allocate memory for ADV\n");
-                       goto cmdline;
+                       ldlinux_enter_command(true);
                }
 
                for (i = 0; i < count; i++)
@@ -261,37 +290,11 @@ int main(int argc __unused, char **argv __unused)
                        syslinux_adv_write();
 
                load_kernel(cmdline); /* Shouldn't return */
-               goto cmdline;
+               ldlinux_enter_command(true);
        }
 
        /* TODO: Check KbdFlags? */
 
-       if (forceprompt)
-               goto cmdline;
-
-       cmdline = default_cmd;
-auto_boot:
-       /*
-        * Auto boot
-        */
-       if (defaultlevel || noescape) {
-               if (defaultlevel) {
-                       load_kernel(cmdline); /* Shouldn't return */
-               } else {
-                       printf("No DEFAULT or UI configuration directive found!\n");
-
-                       if (noescape)
-                               kaboom();
-               }
-       }
-
-cmdline:
-       /* Only returns if the user pressed enter or input timed out */
-       enter_cmdline();
-
-       cmdline = ontimeoutlen ? ontimeout : default_cmd;
-
-       goto auto_boot;
-
+       ldlinux_enter_command(forceprompt);
        return 0;
 }
index eabc9e0..095eb97 100644 (file)
@@ -138,6 +138,14 @@ struct module_dep {
 };
 
 
+/**
+ * Unload all modules that have been loaded since @name.
+ *
+ * Returns the struct elf_module * for @name or %NULL if no modules
+ * have been loaded since @name.
+ */
+extern struct elf_module *unload_modules_since(const char *name);
+
 
 #ifdef DYNAMIC_MODULE
 
index 002b733..b120bc7 100644 (file)
@@ -422,6 +422,30 @@ int module_unload(struct elf_module *module) {
        return _module_unload(module);
 }
 
+struct elf_module *unload_modules_since(const char *name) {
+       struct elf_module *m, *mod, *begin = NULL;
+
+       for_each_module(mod) {
+               if (!strcmp(mod->name, name)) {
+                       begin = mod;
+                       break;
+               }
+       }
+
+       if (!begin)
+               return begin;
+
+       for_each_module_safe(mod, m) {
+               if (mod == begin)
+                       break;
+
+               if (mod != begin)
+                       module_unload(mod);
+       }
+
+       return begin;
+}
+
 static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
        unsigned long h = elf_hash((const unsigned char*)name);
        Elf32_Word *cr_word = module->hash_table;
index b15cdbb..8e124a0 100644 (file)
@@ -66,28 +66,15 @@ int start_ldlinux(char **argv)
 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;
-                       }
-               }
+               struct elf_module *ldlinux;
 
-               for_each_module_safe(mod, m) {
-                       if (mod == begin)
-                               break;
-
-                       if (mod != begin)
-                               module_unload(mod);
-               }
+               ldlinux = unload_modules_since(LDLINUX);
 
                /*
                 * Finally unload LDLINUX.
@@ -96,7 +83,7 @@ again:
                 * cause all the initialsation steps to be executed
                 * again.
                 */
-               module_unload(begin);
+               module_unload(ldlinux);
                goto again;
        }