aboutsummaryrefslogtreecommitdiff
path: root/core/elflink/load_env32.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/elflink/load_env32.c')
-rw-r--r--core/elflink/load_env32.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
new file mode 100644
index 0000000..492cc09
--- /dev/null
+++ b/core/elflink/load_env32.c
@@ -0,0 +1,253 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <console.h>
+#include <dprintf.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <setjmp.h>
+#include <linux/list.h>
+#include <netinet/in.h>
+#include <sys/cpu.h>
+#include <core.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <fs.h>
+#include <ctype.h>
+#include <alloca.h>
+
+#include <sys/exec.h>
+#include <sys/module.h>
+#include "common.h"
+
+extern char __dynstr_start[];
+extern char __dynstr_end[], __dynsym_end[];
+extern char __dynsym_start[];
+extern char __got_start[];
+extern Elf_Dyn __dynamic_start[];
+extern Elf_Word __gnu_hash_start[];
+extern char __module_start[];
+
+struct elf_module core_module = {
+ .name = "(core)",
+ .shallow = true,
+ .required = LIST_HEAD_INIT((core_module.required)),
+ .dependants = LIST_HEAD_INIT((core_module.dependants)),
+ .list = LIST_HEAD_INIT((core_module.list)),
+ .module_addr = (void *)0x0,
+ .ghash_table = __gnu_hash_start,
+ .str_table = __dynstr_start,
+ .sym_table = __dynsym_start,
+ .got = __got_start,
+ .dyn_table = __dynamic_start,
+ .syment_size = sizeof(Elf_Sym),
+};
+
+/*
+ * Initializes the module subsystem by taking the core module
+ * (preinitialized shallow module) and placing it on top of the
+ * modules_head_list.
+ */
+void init_module_subsystem(struct elf_module *module)
+{
+ list_add(&module->list, &modules_head);
+}
+
+__export int start_ldlinux(int argc, char **argv)
+{
+ int rv;
+
+again:
+ rv = spawn_load(LDLINUX, argc, argv);
+ if (rv == EEXIST) {
+ /*
+ * If a COM32 module calls execute() we may need to
+ * unload all the modules loaded since ldlinux.*,
+ * and restart initialisation. This is especially
+ * important for config files.
+ *
+ * But before we do that, try our best to make sure
+ * that spawn_load() is gonna succeed, e.g. that we
+ * can find LDLINUX it in PATH.
+ */
+ struct elf_module *ldlinux;
+ FILE *f;
+
+ f = findpath(LDLINUX);
+ if (!f)
+ return ENOENT;
+
+ fclose(f);
+ ldlinux = unload_modules_since(LDLINUX);
+
+ /*
+ * 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(ldlinux);
+ goto again;
+ }
+
+ return rv;
+}
+
+/* note to self: do _*NOT*_ use static key word on this function */
+void load_env32(com32sys_t * regs __unused)
+{
+ struct file_info *fp;
+ int fd;
+ char *argv[] = { LDLINUX, NULL };
+ char realname[FILENAME_MAX];
+ size_t size;
+
+ static const char *search_directories[] = {
+ "/boot/isolinux",
+ "/isolinux",
+ "/boot/syslinux",
+ "/syslinux",
+ "/",
+ NULL
+ };
+
+ static const char *filenames[] = {
+ LDLINUX,
+ NULL
+ };
+
+ dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
+
+ if (strlen(CurrentDirName) && !path_add(CurrentDirName)) {
+ printf("Couldn't allocate memory for PATH\n");
+ goto out;
+ }
+
+ size = (size_t)__dynstr_end - (size_t)__dynstr_start;
+ core_module.strtable_size = size;
+ size = (size_t)__dynsym_end - (size_t)__dynsym_start;
+ core_module.symtable_size = size;
+ core_module.base_addr = (Elf_Addr)__module_start;
+
+ init_module_subsystem(&core_module);
+
+ start_ldlinux(1, argv);
+
+ /*
+ * If we failed to load LDLINUX it could be because our
+ * current working directory isn't the install directory. Try
+ * a bit harder to find LDLINUX. If search_dirs() succeeds
+ * in finding LDLINUX it will set the cwd.
+ */
+ fd = opendev(&__file_dev, NULL, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ fp = &__file_info[fd];
+
+ if (!search_dirs(&fp->i.fd, search_directories, filenames, realname)) {
+ char path[FILENAME_MAX];
+
+ /*
+ * search_dirs() sets the current working directory if
+ * it successfully opens the file. Add the directory
+ * in which we found ldlinux.* to PATH.
+ */
+ if (!core_getcwd(path, sizeof(path)))
+ goto out;
+
+ if (!path_add(path)) {
+ printf("Couldn't allocate memory for PATH\n");
+ goto out;
+ }
+
+ start_ldlinux(1, argv);
+ }
+
+out:
+ writestr("\nFailed to load ");
+ writestr(LDLINUX);
+}
+
+static const char *__cmdline;
+__export const char *com32_cmdline(void)
+{
+ return __cmdline;
+}
+
+__export int create_args_and_load(char *cmdline)
+{
+ char *p, **argv;
+ int argc;
+ int i;
+
+ if (!cmdline)
+ return -1;
+
+ for (argc = 0, p = cmdline; *p; argc++) {
+ /* Find the end of this arg */
+ while(*p && !isspace(*p))
+ p++;
+
+ /*
+ * Now skip all whitespace between arguments.
+ */
+ while (*p && isspace(*p))
+ p++;
+ }
+
+ /*
+ * Generate a copy of argv on the stack as this is
+ * traditionally where process arguments go.
+ *
+ * argv[0] must be the command name. Remember to allocate
+ * space for the sentinel NULL.
+ */
+ argv = alloca((argc + 1) * sizeof(char *));
+
+ for (i = 0, p = cmdline; i < argc; i++) {
+ char *start;
+ int len = 0;
+
+ start = p;
+
+ /* Find the end of this arg */
+ while(*p && !isspace(*p)) {
+ p++;
+ len++;
+ }
+
+ argv[i] = malloc(len + 1);
+ strncpy(argv[i], start, len);
+ argv[i][len] = '\0';
+
+ /*
+ * Now skip all whitespace between arguments.
+ */
+ while (*p && isspace(*p))
+ p++;
+
+ /*
+ * Point __cmdline at "argv[1] ... argv[argc-1]"
+ */
+ if (i == 0)
+ __cmdline = p;
+ }
+
+ /* NUL-terminate */
+ argv[argc] = NULL;
+
+ return spawn_load(argv[0], argc, argv);
+}
+
+void pm_env32_run(com32sys_t *regs)
+{
+ char *cmdline;
+
+ cmdline = MK_PTR(regs->es, regs->ebx.w[0]);
+ if (create_args_and_load(cmdline) < 0)
+ printf("Failed to run com32 module\n");
+}