blob: 492cc095ee676434855c30a8b3b29fc2c20ea9ef [file] [log] [blame]
#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");
}