GRUB EFI builds are now often used in combination with flicker-free boot, but this breaks with upstream GRUB because the "Welcome to GRUB!" message will kick the EFI fb into text mode and show the msg, breaking the flicker-free experience. EFI systems are so fast, that when the menu or the countdown are enabled the message will be immediately overwritten, so in these cases not printing the message does not matter. And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN, the user has asked GRUB to be quiet (for example to allow flickfree boot) and thus the message should not be printed. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Robbie Harwood <rharwood@redhat.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
320 lines
7.5 KiB
C
320 lines
7.5 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>
|
|
#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.");
|
|
|
|
/* This breaks flicker-free boot on EFI systems, so disable it there. */
|
|
#ifndef GRUB_MACHINE_EFI
|
|
/* Hello. */
|
|
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
|
|
grub_printf ("Welcome to GRUB!\n\n");
|
|
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
|
|
#endif
|
|
|
|
/* 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 ();
|
|
}
|