mirror of
https://git.proxmox.com/git/grub2
synced 2025-10-05 16:26:50 +00:00

If this option is enabled, then do all of the following: Don't display introductory message about line editing unless we're actually offering a shell prompt. (This is believed to be a workaround for a different bug. We'll go with this for now, but will drop this in favour of a better fix upstream if somebody figures out what that is.) Don't clear the screen just before booting if we never drew the menu in the first place. Remove verbose messages printed before reading configuration. In some ways this is awkward because it makes debugging harder, but it's a requirement for a smooth-looking boot process; we may be able to do better in future. Upstream doesn't want this, though. Disable the cursor as well, for similar reasons of tidiness. Suppress kernel/initrd progress messages, except in recovery mode. Suppress "GRUB loading" message unless Shift is held down. Upstream doesn't want this, as it makes debugging harder. Ubuntu wants it to provide a cleaner boot experience. Author: Will Thompson <will@willthompson.co.uk> Bug-Ubuntu: https://bugs.launchpad.net/bugs/386922 Bug-Ubuntu: https://bugs.launchpad.net/bugs/861048 Forwarded: (partial) http://lists.gnu.org/archive/html/grub-devel/2009-09/msg00056.html Last-Update: 2019-06-24 Patch-Name: maybe-quiet.patch
330 lines
7.7 KiB
C
330 lines
7.7 KiB
C
/* 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>
|
|
|
|
#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)
|
|
{
|
|
#if QUIET_BOOT
|
|
struct grub_term_output *term;
|
|
#endif
|
|
|
|
/* First of all, initialize the machine. */
|
|
grub_machine_init ();
|
|
|
|
grub_boot_time ("After machine init.");
|
|
|
|
#if QUIET_BOOT
|
|
/* Disable the cursor until we need it. */
|
|
FOR_ACTIVE_TERM_OUTPUTS(term)
|
|
grub_term_setcursor (term, 0);
|
|
#else
|
|
/* Hello. */
|
|
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
|
|
grub_printf ("Welcome to GRUB!\n\n");
|
|
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
|
|
#endif
|
|
|
|
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 ();
|
|
|
|
#if QUIET_BOOT
|
|
/* If we have to enter rescue mode, enable the cursor again. */
|
|
FOR_ACTIVE_TERM_OUTPUTS(term)
|
|
grub_term_setcursor (term, 1);
|
|
#endif
|
|
|
|
grub_rescue_run ();
|
|
}
|