diff options
Diffstat (limited to 'grub-core/kern/emu/main.c')
-rw-r--r-- | grub-core/kern/emu/main.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c new file mode 100644 index 0000000..425bb96 --- /dev/null +++ b/grub-core/kern/emu/main.c @@ -0,0 +1,286 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB 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, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <config-util.h> + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> + +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/setjmp.h> +#include <grub/fs.h> +#include <grub/emu/hostdisk.h> +#include <grub/time.h> +#include <grub/emu/console.h> +#include <grub/emu/misc.h> +#include <grub/kernel.h> +#include <grub/normal.h> +#include <grub/emu/getroot.h> +#include <grub/env.h> +#include <grub/partition.h> +#include <grub/i18n.h> +#include <grub/loader.h> +#include <grub/util/misc.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + +#include "progname.h" +#include <argp.h> + +#define ENABLE_RELOCATABLE 0 + +/* Used for going back to the main function. */ +static jmp_buf main_env; + +/* Store the prefix specified by an argument. */ +static char *root_dev = NULL, *dir = NULL; + +grub_addr_t grub_modbase = 0; + +void +grub_reboot (void) +{ + longjmp (main_env, 1); + grub_fatal ("longjmp failed"); +} + +void +grub_exit (void) +{ + grub_reboot (); +} + +void +grub_machine_init (void) +{ +} + +void +grub_machine_get_bootlocation (char **device, char **path) +{ + *device = root_dev; + *path = dir; +} + +void +grub_machine_fini (int flags) +{ + if (flags & GRUB_LOADER_FLAG_NORETURN) + grub_console_fini (); +} + + + +#define OPT_MEMDISK 257 + +static struct argp_option options[] = { + {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, + {"device-map", 'm', N_("FILE"), 0, + /* TRANSLATORS: There are many devices in device map. */ + N_("use FILE as the device map [default=%s]"), 0}, + {"memdisk", OPT_MEMDISK, N_("FILE"), 0, + /* TRANSLATORS: There are many devices in device map. */ + N_("use FILE as memdisk"), 0}, + {"directory", 'd', N_("DIR"), 0, + N_("use GRUB files in the directory DIR [default=%s]"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case 'd': + return xasprintf (text, DEFAULT_DIRECTORY); + case 'm': + return xasprintf (text, DEFAULT_DEVICE_MAP); + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +struct arguments +{ + const char *dev_map; + const char *mem_disk; + int hold; +}; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; + + switch (key) + { + case OPT_MEMDISK: + arguments->mem_disk = arg; + break; + case 'r': + free (root_dev); + root_dev = xstrdup (arg); + break; + case 'd': + free (dir); + dir = xstrdup (arg); + break; + case 'm': + arguments->dev_map = arg; + break; + case 'H': + arguments->hold = (arg ? atoi (arg) : -1); + break; + case 'v': + verbosity++; + break; + + case ARGP_KEY_ARG: + { + /* Too many arguments. */ + fprintf (stderr, _("Unknown extra argument `%s'."), arg); + fprintf (stderr, "\n"); + argp_usage (state); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, NULL, + N_("GRUB emulator."), + NULL, help_filter, NULL +}; + + + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + +int +main (int argc, char *argv[]) +{ + struct arguments arguments = + { + .dev_map = DEFAULT_DEVICE_MAP, + .hold = 0, + .mem_disk = 0, + }; + volatile int hold = 0; + size_t total_module_size = sizeof (struct grub_module_info), memdisk_size = 0; + struct grub_module_info *modinfo; + void *mods; + + grub_util_host_init (&argc, &argv); + + dir = xstrdup (DEFAULT_DIRECTORY); + + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (arguments.mem_disk) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (arguments.mem_disk), 512); + total_module_size += memdisk_size + sizeof (struct grub_module_header); + } + + mods = xmalloc (total_module_size); + modinfo = grub_memset (mods, 0, total_module_size); + mods = (char *) (modinfo + 1); + + modinfo->magic = GRUB_MODULE_MAGIC; + modinfo->offset = sizeof (struct grub_module_info); + modinfo->size = total_module_size; + + if (arguments.mem_disk) + { + struct grub_module_header *header = (struct grub_module_header *) mods; + header->type = OBJ_TYPE_MEMDISK; + header->size = memdisk_size + sizeof (*header); + mods = header + 1; + + grub_util_load_image (arguments.mem_disk, mods); + mods = (char *) mods + memdisk_size; + } + + grub_modbase = (grub_addr_t) modinfo; + + hold = arguments.hold; + /* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */ + if (hold && verbosity > 0) + /* TRANSLATORS: In this case GRUB tells user what he has to do. */ + printf (_("Run `gdb %s %d', and set ARGS.HOLD to zero.\n"), + program_name, (int) getpid ()); + while (hold) + { + if (hold > 0) + hold--; + + sleep (1); + } + + signal (SIGINT, SIG_IGN); + grub_console_init (); + grub_host_init (); + + /* XXX: This is a bit unportable. */ + grub_util_biosdisk_init (arguments.dev_map); + + grub_init_all (); + + grub_hostfs_init (); + + /* Make sure that there is a root device. */ + if (! root_dev) + root_dev = grub_strdup ("host"); + + dir = xstrdup (dir); + + /* Start GRUB! */ + if (setjmp (main_env) == 0) + grub_main (); + + grub_fini_all (); + grub_hostfs_fini (); + grub_host_fini (); + + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + + return 0; +} |