summaryrefslogtreecommitdiffstats
path: root/grub-core/kern/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/kern/main.c')
-rw-r--r--grub-core/kern/main.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
new file mode 100644
index 0000000..73967e2
--- /dev/null
+++ b/grub-core/kern/main.c
@@ -0,0 +1,316 @@
+/* main.c - the kernel main routine */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2008,2009 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 <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/symbol.h>
+#include <grub/dl.h>
+#include <grub/term.h>
+#include <grub/file.h>
+#include <grub/device.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/reader.h>
+#include <grub/parser.h>
+#include <grub/verify.h>
+
+#ifdef GRUB_MACHINE_PCBIOS
+#include <grub/machine/memory.h>
+#endif
+
+grub_addr_t
+grub_modules_get_end (void)
+{
+ struct grub_module_info *modinfo;
+
+ modinfo = (struct grub_module_info *) grub_modbase;
+
+ /* Check if there are any modules. */
+ if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
+ return grub_modbase;
+
+ return grub_modbase + modinfo->size;
+}
+
+/* Load all modules in core. */
+static void
+grub_load_modules (void)
+{
+ struct grub_module_header *header;
+ FOR_MODULES (header)
+ {
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_ELF)
+ continue;
+
+ if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
+ (header->size - sizeof (struct grub_module_header))))
+ grub_fatal ("%s", grub_errmsg);
+
+ if (grub_errno)
+ grub_print_error ();
+ }
+}
+
+static char *load_config;
+
+static void
+grub_load_config (void)
+{
+ struct grub_module_header *header;
+ FOR_MODULES (header)
+ {
+ /* Not an embedded config, skip. */
+ if (header->type != OBJ_TYPE_CONFIG)
+ continue;
+
+ load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1);
+ if (!load_config)
+ {
+ grub_print_error ();
+ break;
+ }
+ grub_memcpy (load_config, (char *) header +
+ sizeof (struct grub_module_header),
+ header->size - sizeof (struct grub_module_header));
+ load_config[header->size - sizeof (struct grub_module_header)] = 0;
+ break;
+ }
+}
+
+/* Write hook for the environment variables of root. Remove surrounding
+ parentheses, if any. */
+static char *
+grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ /* XXX Is it better to check the existence of the device? */
+ grub_size_t len = grub_strlen (val);
+
+ if (val[0] == '(' && val[len - 1] == ')')
+ return grub_strndup (val + 1, len - 2);
+
+ return grub_strdup (val);
+}
+
+static void
+grub_set_prefix_and_root (void)
+{
+ char *device = NULL;
+ char *path = NULL;
+ char *fwdevice = NULL;
+ char *fwpath = NULL;
+ char *prefix = NULL;
+ struct grub_module_header *header;
+
+ FOR_MODULES (header)
+ if (header->type == OBJ_TYPE_PREFIX)
+ prefix = (char *) header + sizeof (struct grub_module_header);
+
+ grub_register_variable_hook ("root", 0, grub_env_write_root);
+
+ grub_machine_get_bootlocation (&fwdevice, &fwpath);
+
+ if (fwdevice)
+ {
+ char *cmdpath;
+
+ cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
+ if (cmdpath)
+ {
+ grub_env_set ("cmdpath", cmdpath);
+ grub_env_export ("cmdpath");
+ grub_free (cmdpath);
+ }
+ }
+
+ if (prefix)
+ {
+ char *pptr = NULL;
+ if (prefix[0] == '(')
+ {
+ pptr = grub_strrchr (prefix, ')');
+ if (pptr)
+ {
+ device = grub_strndup (prefix + 1, pptr - prefix - 1);
+ pptr++;
+ }
+ }
+ if (!pptr)
+ pptr = prefix;
+ if (pptr[0])
+ path = grub_strdup (pptr);
+ }
+
+ if (!device && fwdevice)
+ device = fwdevice;
+ else if (fwdevice && (device[0] == ',' || !device[0]))
+ {
+ /* We have a partition, but still need to fill in the drive. */
+ char *comma, *new_device;
+
+ for (comma = fwdevice; *comma; )
+ {
+ if (comma[0] == '\\' && comma[1] == ',')
+ {
+ comma += 2;
+ continue;
+ }
+ if (*comma == ',')
+ break;
+ comma++;
+ }
+ if (*comma)
+ {
+ char *drive = grub_strndup (fwdevice, comma - fwdevice);
+ new_device = grub_xasprintf ("%s%s", drive, device);
+ grub_free (drive);
+ }
+ else
+ new_device = grub_xasprintf ("%s%s", fwdevice, device);
+
+ grub_free (fwdevice);
+ grub_free (device);
+ device = new_device;
+ }
+ else
+ grub_free (fwdevice);
+ if (fwpath && !path)
+ {
+ grub_size_t len = grub_strlen (fwpath);
+ while (len > 1 && fwpath[len - 1] == '/')
+ fwpath[--len] = 0;
+ if (len >= sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1
+ && grub_memcmp (fwpath + len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1), GRUB_TARGET_CPU "-" GRUB_PLATFORM,
+ sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1) == 0)
+ fwpath[len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1)] = 0;
+ path = fwpath;
+ }
+ else
+ grub_free (fwpath);
+ if (device)
+ {
+ char *prefix_set;
+
+ prefix_set = grub_xasprintf ("(%s)%s", device, path ? : "");
+ if (prefix_set)
+ {
+ grub_env_set ("prefix", prefix_set);
+ grub_free (prefix_set);
+ }
+ grub_env_set ("root", device);
+ }
+
+ grub_free (device);
+ grub_free (path);
+ grub_print_error ();
+}
+
+/* Load the normal mode module and execute the normal mode if possible. */
+static void
+grub_load_normal_mode (void)
+{
+ /* Load the module. */
+ grub_dl_load ("normal");
+
+ /* Print errors if any. */
+ grub_print_error ();
+ grub_errno = 0;
+
+ grub_command_execute ("normal", 0, 0);
+}
+
+static void
+reclaim_module_space (void)
+{
+ grub_addr_t modstart, modend;
+
+ if (!grub_modbase)
+ return;
+
+#ifdef GRUB_MACHINE_PCBIOS
+ modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR;
+#else
+ modstart = grub_modbase;
+#endif
+ modend = grub_modules_get_end ();
+ grub_modbase = 0;
+
+#if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
+ grub_mm_init_region ((void *) modstart, modend - modstart);
+#else
+ (void) modstart;
+ (void) modend;
+#endif
+}
+
+/* The main routine. */
+void __attribute__ ((noreturn))
+grub_main (void)
+{
+ /* First of all, initialize the machine. */
+ grub_machine_init ();
+
+ grub_boot_time ("After machine init.");
+
+ /* Hello. */
+ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+ grub_printf ("Welcome to GRUB!\n\n");
+ grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+
+ /* Init verifiers API. */
+ grub_verifiers_init ();
+
+ grub_load_config ();
+
+ grub_boot_time ("Before loading embedded modules.");
+
+ /* Load pre-loaded modules and free the space. */
+ grub_register_exported_symbols ();
+#ifdef GRUB_LINKER_HAVE_INIT
+ grub_arch_dl_init_linker ();
+#endif
+ grub_load_modules ();
+
+ grub_boot_time ("After loading embedded modules.");
+
+ /* It is better to set the root device as soon as possible,
+ for convenience. */
+ grub_set_prefix_and_root ();
+ grub_env_export ("root");
+ grub_env_export ("prefix");
+
+ /* Reclaim space used for modules. */
+ reclaim_module_space ();
+
+ grub_boot_time ("After reclaiming module space.");
+
+ grub_register_core_commands ();
+
+ grub_boot_time ("Before execution of embedded config.");
+
+ if (load_config)
+ grub_parser_execute (load_config);
+
+ grub_boot_time ("After execution of embedded config. Attempt to go to normal mode");
+
+ grub_load_normal_mode ();
+ grub_rescue_run ();
+}