| /* ----------------------------------------------------------------------- * |
| * |
| * 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 <sys/io.h> |
| #include <sys/module.h> |
| #include "core.h" |
| #include "menu.h" |
| #include "fs.h" |
| #include "config.h" |
| #include "localboot.h" |
| #include "bios.h" |
| |
| #include <syslinux/bootrm.h> |
| #include <syslinux/movebits.h> |
| #include <syslinux/config.h> |
| #include <syslinux/boot.h> |
| |
| const struct image_types image_boot_types[] = { |
| { "localboot", IMAGE_TYPE_LOCALBOOT }, |
| { "kernel", IMAGE_TYPE_KERNEL }, |
| { "linux", IMAGE_TYPE_LINUX }, |
| { "boot", IMAGE_TYPE_BOOT }, |
| { "bss", IMAGE_TYPE_BSS }, |
| { "pxe", IMAGE_TYPE_PXE }, |
| { "fdimage", IMAGE_TYPE_FDIMAGE }, |
| { "com32", IMAGE_TYPE_COM32 }, |
| { "config", IMAGE_TYPE_CONFIG }, |
| { NULL, 0 }, |
| }; |
| |
| extern int create_args_and_load(char *); |
| |
| __export void execute(const char *cmdline, uint32_t type, bool sysappend) |
| { |
| const char *kernel, *args; |
| const char *p; |
| com32sys_t ireg; |
| char *q, ch; |
| |
| memset(&ireg, 0, sizeof ireg); |
| |
| if (strlen(cmdline) >= MAX_CMDLINE_LEN) { |
| printf("cmdline too long\n"); |
| return; |
| } |
| |
| q = malloc(MAX_CMDLINE_LEN); |
| if (!q) { |
| printf("%s(): Fail to malloc 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++; |
| |
| do { |
| *q++ = ch = *p++; |
| } while (ch); |
| |
| if (sysappend) { |
| /* If we've seen some args, insert a space */ |
| if (--q != args) |
| *q++ = ' '; |
| |
| do_sysappend(q); |
| } |
| |
| dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type); |
| |
| if (kernel[0] == '.') { |
| /* It might be a type specifier */ |
| const struct image_types *t; |
| for (t = image_boot_types; t->name; t++) { |
| if (!strcmp(kernel + 1, t->name)) { |
| /* |
| * Strip the type specifier, apply the |
| * filename extension if COM32 and |
| * retry. |
| */ |
| p = args; |
| if (t->type == IMAGE_TYPE_COM32) { |
| p = apply_extension(p, ".c32"); |
| if (!p) |
| return; |
| } |
| |
| execute(p, t->type, sysappend); |
| return; |
| } |
| } |
| } |
| |
| if (type == IMAGE_TYPE_COM32) { |
| /* |
| * We may be called with the console in an unknown |
| * state, so initialise it. |
| */ |
| ldlinux_console_init(); |
| |
| /* new entry for elf format c32 */ |
| if (create_args_and_load((char *)cmdline)) |
| printf("Failed to load COM32 file %s\n", kernel); |
| |
| /* |
| * 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); |
| |
| /* Restore the console */ |
| ldlinux_console_init(); |
| |
| ldlinux_enter_command(); |
| } else if (type == IMAGE_TYPE_CONFIG) { |
| char *argv[] = { LDLINUX, NULL, NULL }; |
| char *config; |
| int rv; |
| |
| /* kernel contains the config file name */ |
| config = malloc(FILENAME_MAX); |
| if (!config) |
| goto out; |
| |
| realpath(config, kernel, FILENAME_MAX); |
| |
| /* If we got anything on the command line, do a chdir */ |
| if (*args) |
| mangle_name(config_cwd, args); |
| |
| argv[1] = config; |
| rv = start_ldlinux(2, argv); |
| printf("Failed to exec %s: %s\n", LDLINUX, strerror(rv)); |
| } else if (type == IMAGE_TYPE_LOCALBOOT) { |
| local_boot(strtoul(kernel, NULL, 0)); |
| } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS || |
| type == IMAGE_TYPE_BOOT) { |
| chainboot_file(kernel, type); |
| } else { |
| /* Need add one item for kernel load, as we don't use |
| * the assembly runkernel.inc any more */ |
| new_linux_kernel((char *)kernel, (char *)args); |
| } |
| |
| out: |
| free((void *)kernel); |
| |
| /* If this returns, something went bad; return to menu */ |
| } |