summaryrefslogtreecommitdiffstats
path: root/grub-core/kern/emu/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/kern/emu/main.c')
-rw-r--r--grub-core/kern/emu/main.c286
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;
+}