/* 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef VAS_EBOOT_MACHINE_PCBIOS #include #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 (); }