mirror of
https://git.proxmox.com/git/grub2
synced 2025-10-04 15:29:30 +00:00

Given no core functions on i386-pc would require verifiers to work and the only consumer of the verifier API is the pgp module, it looks good to me that we can move the verifiers out of the kernel image and let moddep.lst to auto-load it when pgp is loaded on i386-pc platform. This helps to reduce the size of core image and thus can relax the tension of exploding on some i386-pc system with very short MBR gap size. See also a very comprehensive summary from Colin [1] about the details. [1] https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00240.html V2: Drop COND_NOT_i386_pc and use !COND_i386_pc. Add comment in kern/verifiers.c to help understanding what's going on without digging into the commit history. Reported-by: Colin Watson <cjwatson@debian.org> Reviewed-by: Colin Watson <cjwatson@debian.org> Signed-off-by: Michael Chang <mchang@suse.com> Origin: other, https://lists.gnu.org/archive/html/grub-devel/2021-03/msg00251.html Bug-Debian: https://bugs.debian.org/984488 Bug-Debian: https://bugs.debian.org/985374 Last-Update: 2021-09-24 Patch-Name: pc-verifiers-module.patch
338 lines
7.9 KiB
C
338 lines
7.9 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>
|
|
#ifndef GRUB_MACHINE_PCBIOS
|
|
#include <grub/verify.h>
|
|
#endif
|
|
|
|
#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
|
|
|
|
#ifndef GRUB_MACHINE_PCBIOS
|
|
/* Init verifiers API. */
|
|
grub_verifiers_init ();
|
|
#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 ();
|
|
}
|