vaseboot/VasEBoot-core/kern/main.c

316 lines
8.0 KiB
C

/* main.c - the kernel main routine */
/*
* VasEBoot -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
*
* VasEBoot 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.
*
* VasEBoot 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 VasEBoot. If not, see <http://www.gnu.org/licenses/>.
*/
#include <VasEBoot/kernel.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>
#ifdef VasEBoot_MACHINE_PCBIOS
#include <VasEBoot/machine/memory.h>
#endif
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 != VasEBoot_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;
VasEBoot_env_set ("cmddevice", fwdevice);
VasEBoot_env_export ("cmddevice");
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 (VasEBoot_TARGET_CPU "-" VasEBoot_PLATFORM) - 1
&& VasEBoot_memcmp (fwpath + len - (sizeof (VasEBoot_TARGET_CPU "-" VasEBoot_PLATFORM) - 1), VasEBoot_TARGET_CPU "-" VasEBoot_PLATFORM,
sizeof (VasEBoot_TARGET_CPU "-" VasEBoot_PLATFORM) - 1) == 0)
fwpath[len - (sizeof (VasEBoot_TARGET_CPU "-" VasEBoot_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);
}
static void
reclaim_module_space (void)
{
VasEBoot_addr_t modstart, modend;
if (!VasEBoot_modbase)
return;
#ifdef VasEBoot_MACHINE_PCBIOS
modstart = VasEBoot_MEMORY_MACHINE_DECOMPRESSION_ADDR;
#else
modstart = VasEBoot_modbase;
#endif
modend = VasEBoot_modules_get_end ();
VasEBoot_modbase = 0;
#if VasEBoot_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)
{
/* First of all, initialize the machine. */
VasEBoot_machine_init ();
VasEBoot_boot_time ("After machine init.");
/* Hello. */
VasEBoot_setcolorstate (VasEBoot_TERM_COLOR_HIGHLIGHT);
VasEBoot_printf ("Welcome to VasEBoot!\n\n");
VasEBoot_setcolorstate (VasEBoot_TERM_COLOR_STANDARD);
VasEBoot_load_config ();
VasEBoot_boot_time ("Before loading embedded modules.");
/* Load pre-loaded modules and free the space. */
VasEBoot_register_exported_symbols ();
#ifdef VasEBoot_LINKER_HAVE_INIT
VasEBoot_arch_dl_init_linker ();
#endif
VasEBoot_load_modules ();
VasEBoot_boot_time ("After loading embedded modules.");
/* 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 ();
}