/* boot.c - command to boot an operating system */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2002,2003,2004,2005,2007,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 VAS_EBOOT_MOD_LICENSE ("GPLv3+"); static VasEBoot_err_t (*VasEBoot_loader_boot_func) (void *context); static VasEBoot_err_t (*VasEBoot_loader_unload_func) (void *context); static void *VasEBoot_loader_context; static int VasEBoot_loader_flags; struct VasEBoot_simple_loader_hooks { VasEBoot_err_t (*boot) (void); VasEBoot_err_t (*unload) (void); }; /* Don't heap allocate this to avoid making VasEBoot_loader_set() fallible. */ static struct VasEBoot_simple_loader_hooks simple_loader_hooks; struct VasEBoot_preboot { VasEBoot_err_t (*preboot_func) (int); VasEBoot_err_t (*preboot_rest_func) (void); VasEBoot_loader_preboot_hook_prio_t prio; struct VasEBoot_preboot *next; struct VasEBoot_preboot *prev; }; static int VasEBoot_loader_loaded; static struct VasEBoot_preboot *preboots_head = 0, *preboots_tail = 0; static VasEBoot_err_t VasEBoot_simple_boot_hook (void *context) { struct VasEBoot_simple_loader_hooks *hooks; hooks = (struct VasEBoot_simple_loader_hooks *) context; return hooks->boot (); } static VasEBoot_err_t VasEBoot_simple_unload_hook (void *context) { struct VasEBoot_simple_loader_hooks *hooks; VasEBoot_err_t ret; hooks = (struct VasEBoot_simple_loader_hooks *) context; ret = hooks->unload (); VasEBoot_memset (hooks, 0, sizeof (*hooks)); return ret; } int VasEBoot_loader_is_loaded (void) { return VasEBoot_loader_loaded; } /* Register a preboot hook. */ struct VasEBoot_preboot * VasEBoot_loader_register_preboot_hook (VasEBoot_err_t (*preboot_func) (int flags), VasEBoot_err_t (*preboot_rest_func) (void), VasEBoot_loader_preboot_hook_prio_t prio) { struct VasEBoot_preboot *cur, *new_preboot; if (! preboot_func && ! preboot_rest_func) return 0; new_preboot = (struct VasEBoot_preboot *) VasEBoot_malloc (sizeof (struct VasEBoot_preboot)); if (! new_preboot) return 0; new_preboot->preboot_func = preboot_func; new_preboot->preboot_rest_func = preboot_rest_func; new_preboot->prio = prio; for (cur = preboots_head; cur && cur->prio > prio; cur = cur->next); if (cur) { new_preboot->next = cur; new_preboot->prev = cur->prev; cur->prev = new_preboot; } else { new_preboot->next = 0; new_preboot->prev = preboots_tail; preboots_tail = new_preboot; } if (new_preboot->prev) new_preboot->prev->next = new_preboot; else preboots_head = new_preboot; return new_preboot; } void VasEBoot_loader_unregister_preboot_hook (struct VasEBoot_preboot *hnd) { struct VasEBoot_preboot *preb = hnd; if (preb->next) preb->next->prev = preb->prev; else preboots_tail = preb->prev; if (preb->prev) preb->prev->next = preb->next; else preboots_head = preb->next; VasEBoot_free (preb); } void VasEBoot_loader_set_ex (VasEBoot_err_t (*boot) (void *context), VasEBoot_err_t (*unload) (void *context), void *context, int flags) { if (VasEBoot_loader_loaded && VasEBoot_loader_unload_func) VasEBoot_loader_unload_func (VasEBoot_loader_context); VasEBoot_loader_boot_func = boot; VasEBoot_loader_unload_func = unload; VasEBoot_loader_context = context; VasEBoot_loader_flags = flags; VasEBoot_loader_loaded = 1; } void VasEBoot_loader_set (VasEBoot_err_t (*boot) (void), VasEBoot_err_t (*unload) (void), int flags) { VasEBoot_loader_set_ex (VasEBoot_simple_boot_hook, VasEBoot_simple_unload_hook, &simple_loader_hooks, flags); simple_loader_hooks.boot = boot; simple_loader_hooks.unload = unload; } void VasEBoot_loader_unset(void) { if (VasEBoot_loader_loaded && VasEBoot_loader_unload_func) VasEBoot_loader_unload_func (VasEBoot_loader_context); VasEBoot_loader_boot_func = 0; VasEBoot_loader_unload_func = 0; VasEBoot_loader_context = 0; VasEBoot_loader_loaded = 0; } VasEBoot_err_t VasEBoot_loader_boot (void) { VasEBoot_err_t err = VAS_EBOOT_ERR_NONE; struct VasEBoot_preboot *cur; if (! VasEBoot_loader_loaded) return VasEBoot_error (VAS_EBOOT_ERR_NO_KERNEL, N_("you need to load the kernel first")); VasEBoot_machine_fini (VasEBoot_loader_flags); for (cur = preboots_head; cur; cur = cur->next) { err = cur->preboot_func (VasEBoot_loader_flags); if (err) { for (cur = cur->prev; cur; cur = cur->prev) cur->preboot_rest_func (); return err; } } err = (VasEBoot_loader_boot_func) (VasEBoot_loader_context); for (cur = preboots_tail; cur; cur = cur->prev) if (! err) err = cur->preboot_rest_func (); else cur->preboot_rest_func (); return err; } /* boot */ static VasEBoot_err_t VasEBoot_cmd_boot (struct VasEBoot_command *cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused))) { return VasEBoot_loader_boot (); } static VasEBoot_command_t cmd_boot; VAS_EBOOT_MOD_INIT(boot) { cmd_boot = VasEBoot_register_command ("boot", VasEBoot_cmd_boot, 0, N_("Boot an operating system.")); } VAS_EBOOT_MOD_FINI(boot) { VasEBoot_unregister_command (cmd_boot); }