vaseboot/VasEBoot-core/kern/main.c

371 lines
9.1 KiB
C

/* main.c - the kernel main routine */
/*
* VAS_EBOOT -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
*
* VAS_EBOOT 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.
*
* VAS_EBOOT 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 VAS_EBOOT. If not, see <http://www.gnu.org/licenses/>.
*/
#include <VasEBoot/kernel.h>
#include <VasEBoot/stack_protector.h>
#include <VasEBoot/misc.h>
#include <VasEBoot/symbol.h>
#include <VasEBoot/dl.h>
#include <VasEBoot/term.h>
#include <VasEBoot/file.h>
#include <VasEBoot/device.h>
#include <VasEBoot/env.h>
#include <VasEBoot/mm.h>
#include <VasEBoot/command.h>
#include <VasEBoot/reader.h>
#include <VasEBoot/parser.h>
#include <VasEBoot/verify.h>
#include <VasEBoot/types.h>
#ifdef VAS_EBOOT_MACHINE_PCBIOS
#include <VasEBoot/machine/memory.h>
#endif
static bool cli_disabled = false;
static bool cli_need_auth = false;
VasEBoot_addr_t
VasEBoot_modules_get_end (void)
{
struct VasEBoot_module_info *modinfo;
modinfo = (struct VasEBoot_module_info *) VasEBoot_modbase;
/* Check if there are any modules. */
if ((modinfo == 0) || modinfo->magic != VAS_EBOOT_MODULE_MAGIC)
return VasEBoot_modbase;
return VasEBoot_modbase + modinfo->size;
}
/* Load all modules in core. */
static void
VasEBoot_load_modules (void)
{
struct VasEBoot_module_header *header;
FOR_MODULES (header)
{
/* Not an ELF module, skip. */
if (header->type != OBJ_TYPE_ELF)
continue;
if (! VasEBoot_dl_load_core ((char *) header + sizeof (struct VasEBoot_module_header),
(header->size - sizeof (struct VasEBoot_module_header))))
VasEBoot_fatal ("%s", VasEBoot_errmsg);
if (VasEBoot_errno)
VasEBoot_print_error ();
}
}
static char *load_config;
static void
VasEBoot_load_config (void)
{
struct VasEBoot_module_header *header;
FOR_MODULES (header)
{
/* Not an embedded config, skip. */
if (header->type != OBJ_TYPE_CONFIG)
continue;
load_config = VasEBoot_malloc (header->size - sizeof (struct VasEBoot_module_header) + 1);
if (!load_config)
{
VasEBoot_print_error ();
break;
}
VasEBoot_memcpy (load_config, (char *) header +
sizeof (struct VasEBoot_module_header),
header->size - sizeof (struct VasEBoot_module_header));
load_config[header->size - sizeof (struct VasEBoot_module_header)] = 0;
break;
}
}
/* Write hook for the environment variables of root. Remove surrounding
parentheses, if any. */
static char *
VasEBoot_env_write_root (struct VasEBoot_env_var *var __attribute__ ((unused)),
const char *val)
{
/* XXX Is it better to check the existence of the device? */
VasEBoot_size_t len = VasEBoot_strlen (val);
if (val[0] == '(' && val[len - 1] == ')')
return VasEBoot_strndup (val + 1, len - 2);
return VasEBoot_strdup (val);
}
static void
VasEBoot_set_prefix_and_root (void)
{
char *device = NULL;
char *path = NULL;
char *fwdevice = NULL;
char *fwpath = NULL;
char *prefix = NULL;
struct VasEBoot_module_header *header;
FOR_MODULES (header)
if (header->type == OBJ_TYPE_PREFIX)
prefix = (char *) header + sizeof (struct VasEBoot_module_header);
VasEBoot_register_variable_hook ("root", 0, VasEBoot_env_write_root);
VasEBoot_machine_get_bootlocation (&fwdevice, &fwpath);
if (fwdevice)
{
char *cmdpath;
cmdpath = VasEBoot_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
if (cmdpath)
{
VasEBoot_env_set ("cmdpath", cmdpath);
VasEBoot_env_export ("cmdpath");
VasEBoot_free (cmdpath);
}
}
if (prefix)
{
char *pptr = NULL;
if (prefix[0] == '(')
{
pptr = VasEBoot_strrchr (prefix, ')');
if (pptr)
{
device = VasEBoot_strndup (prefix + 1, pptr - prefix - 1);
pptr++;
}
}
if (!pptr)
pptr = prefix;
if (pptr[0])
path = VasEBoot_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 = VasEBoot_strndup (fwdevice, comma - fwdevice);
new_device = VasEBoot_xasprintf ("%s%s", drive, device);
VasEBoot_free (drive);
}
else
new_device = VasEBoot_xasprintf ("%s%s", fwdevice, device);
VasEBoot_free (fwdevice);
VasEBoot_free (device);
device = new_device;
}
else
VasEBoot_free (fwdevice);
if (fwpath && !path)
{
VasEBoot_size_t len = VasEBoot_strlen (fwpath);
while (len > 1 && fwpath[len - 1] == '/')
fwpath[--len] = 0;
if (len >= sizeof (VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM) - 1
&& VasEBoot_memcmp (fwpath + len - (sizeof (VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM) - 1), VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM,
sizeof (VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM) - 1) == 0)
fwpath[len - (sizeof (VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM) - 1)] = 0;
path = fwpath;
}
else
VasEBoot_free (fwpath);
if (device)
{
char *prefix_set;
prefix_set = VasEBoot_xasprintf ("(%s)%s", device, path ? : "");
if (prefix_set)
{
VasEBoot_env_set ("prefix", prefix_set);
VasEBoot_free (prefix_set);
}
VasEBoot_env_set ("root", device);
}
VasEBoot_free (device);
VasEBoot_free (path);
VasEBoot_print_error ();
}
/* Load the normal mode module and execute the normal mode if possible. */
static void
VasEBoot_load_normal_mode (void)
{
/* Load the module. */
VasEBoot_dl_load ("normal");
/* Print errors if any. */
VasEBoot_print_error ();
VasEBoot_errno = 0;
VasEBoot_command_execute ("normal", 0, 0);
}
bool
VasEBoot_is_cli_disabled (void)
{
return cli_disabled;
}
bool
VasEBoot_is_cli_need_auth (void)
{
return cli_need_auth;
}
void VasEBoot_cli_set_auth_needed (void)
{
cli_need_auth = true;
}
static void
check_is_cli_disabled (void)
{
struct VasEBoot_module_header *header;
header = 0;
FOR_MODULES (header)
{
if (header->type == OBJ_TYPE_DISABLE_CLI)
{
cli_disabled = true;
return;
}
}
}
static void
reclaim_module_space (void)
{
VasEBoot_addr_t modstart, modend;
if (!VasEBoot_modbase)
return;
#ifdef VAS_EBOOT_MACHINE_PCBIOS
modstart = VAS_EBOOT_MEMORY_MACHINE_DECOMPRESSION_ADDR;
#else
modstart = VasEBoot_modbase;
#endif
modend = VasEBoot_modules_get_end ();
VasEBoot_modbase = 0;
#if VAS_EBOOT_KERNEL_PRELOAD_SPACE_REUSABLE
VasEBoot_mm_init_region ((void *) modstart, modend - modstart);
#else
(void) modstart;
(void) modend;
#endif
}
/* The main routine. */
void __attribute__ ((noreturn))
VasEBoot_main (void)
{
#ifdef VAS_EBOOT_STACK_PROTECTOR
/*
* This call should only be made from a function that does not return because
* functions that return will get instrumented to check that the stack cookie
* does not change and this call will change the stack cookie. Thus a stack
* guard failure will be triggered.
*/
VasEBoot_update_stack_guard ();
#endif
/* First of all, initialize the machine. */
VasEBoot_machine_init ();
VasEBoot_boot_time ("After machine init.");
/* This breaks flicker-free boot on EFI systems, so disable it there. */
#ifndef VAS_EBOOT_MACHINE_EFI
/* Hello. */
VasEBoot_setcolorstate (VAS_EBOOT_TERM_COLOR_HIGHLIGHT);
VasEBoot_printf ("Welcome to VAS_EBOOT!\n\n");
VasEBoot_setcolorstate (VAS_EBOOT_TERM_COLOR_STANDARD);
#endif
/* Init verifiers API. */
VasEBoot_verifiers_init ();
VasEBoot_load_config ();
VasEBoot_boot_time ("Before loading embedded modules.");
/* Load pre-loaded modules and free the space. */
VasEBoot_register_exported_symbols ();
#ifdef VAS_EBOOT_LINKER_HAVE_INIT
VasEBoot_arch_dl_init_linker ();
#endif
VasEBoot_load_modules ();
VasEBoot_boot_time ("After loading embedded modules.");
/* Check if the CLI should be disabled */
check_is_cli_disabled ();
/* It is better to set the root device as soon as possible,
for convenience. */
VasEBoot_set_prefix_and_root ();
VasEBoot_env_export ("root");
VasEBoot_env_export ("prefix");
/* Reclaim space used for modules. */
reclaim_module_space ();
VasEBoot_boot_time ("After reclaiming module space.");
VasEBoot_register_core_commands ();
VasEBoot_boot_time ("Before execution of embedded config.");
if (load_config)
VasEBoot_parser_execute (load_config);
VasEBoot_boot_time ("After execution of embedded config. Attempt to go to normal mode");
VasEBoot_load_normal_mode ();
VasEBoot_rescue_run ();
}