Warning fixed in the patch. If nobody objects I commit it tomorrow On Wed, Apr 15, 2009 at 10:40 AM, John Stanley <jpsinthe...@verizon.net>wrote:
> The way it looks to me is that preboot_func is the function to be executed > a preboot time, whereas preboot_rest_func is a cleanup function to be > called to "restore" things to the pre-preboot_func state. Something like > this anyway.. its not yet real clear to me either. > > phcoder wrote: > >> Yoshinori K. Okuji wrote: >> >> - I don't understand how preboot_func and preboot_rest_func are >>> different. At least, not obvious. Can you elaborate on them? >>> >> preboot_rest_func is a function which should undo any action taken by >> preboot_func. It's used if either loader aborts due to an error or returns >> (which is possible on some platforms) >> >>> >>> _______________________________________________ >>> Grub-devel mailing list >>> Grub-devel@gnu.org >>> http://lists.gnu.org/mailman/listinfo/grub-devel >>> >> >> >> ------------------------------------------------------------------------ >> >> _______________________________________________ >> Grub-devel mailing list >> Grub-devel@gnu.org >> http://lists.gnu.org/mailman/listinfo/grub-devel >> > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel > -- Regards Vladimir 'phcoder' Serbinenko
diff --git a/ChangeLog b/ChangeLog index e5b3086..2f2afc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-04-26 Vladimir Serbinenko <phco...@gmail.com> + + Preboot hooks support + + * commands/boot.c (struct grub_preboot_t): new declaration + (preboots_head): new variable + (preboots_tail): likewise + (grub_loader_register_preboot_hook): new function + (grub_loader_unregister_preboot_hook): likewise + (grub_loader_set): launch preboot hooks + * include/grub/loader.h (grub_loader_register_preboot_hook): + new declaration + (grub_loader_unregister_preboot_hook): likewise + 2009-04-26 David S. Miller <da...@davemloft.net> * util/grub-mkdevicemap.c (make_device_map): Add missing diff --git a/commands/boot.c b/commands/boot.c index 9a08fea..c8bd030 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -22,12 +22,24 @@ #include <grub/misc.h> #include <grub/loader.h> #include <grub/kernel.h> +#include <grub/mm.h> static grub_err_t (*grub_loader_boot_func) (void); static grub_err_t (*grub_loader_unload_func) (void); static int grub_loader_noreturn; +struct grub_preboot_t +{ + grub_err_t (*preboot_func) (int); + grub_err_t (*preboot_rest_func) (void); + grub_loader_preboot_hook_prio_t prio; + struct grub_preboot_t *next; + struct grub_preboot_t *prev; +}; + static int grub_loader_loaded; +static struct grub_preboot_t *preboots_head = 0, + *preboots_tail = 0; int grub_loader_is_loaded (void) @@ -35,6 +47,68 @@ grub_loader_is_loaded (void) return grub_loader_loaded; } +/* Register a preboot hook. */ +void * +grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noreturn), + grub_err_t (*preboot_rest_func) (void), + grub_loader_preboot_hook_prio_t prio) +{ + struct grub_preboot_t *cur, *new_preboot; + + if (! preboot_func && ! preboot_rest_func) + return 0; + + new_preboot = (struct grub_preboot_t *) + grub_malloc (sizeof (struct grub_preboot_t)); + if (! new_preboot) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "hook not added"); + 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 +grub_loader_unregister_preboot_hook (void *hnd) +{ + struct grub_preboot_t *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; + + grub_free (preb); +} + void grub_loader_set (grub_err_t (*boot) (void), grub_err_t (*unload) (void), @@ -65,15 +139,35 @@ grub_loader_unset(void) grub_err_t grub_loader_boot (void) { + grub_err_t err = GRUB_ERR_NONE; + struct grub_preboot_t *cur; + if (! grub_loader_loaded) return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel"); if (grub_loader_noreturn) grub_machine_fini (); - - return (grub_loader_boot_func) (); -} + for (cur = preboots_head; cur; cur = cur->next) + { + err = cur->preboot_func (grub_loader_noreturn); + if (err) + { + for (cur = cur->prev; cur; cur = cur->prev) + cur->preboot_rest_func (); + return err; + } + } + err = (grub_loader_boot_func) (); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) + err = cur->preboot_rest_func (); + else + cur->preboot_rest_func (); + + return err; +} /* boot */ static grub_err_t diff --git a/include/grub/loader.h b/include/grub/loader.h index 185d297..319f3c5 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -41,4 +41,26 @@ void grub_loader_unset (void); depending on the setting by grub_loader_set. */ grub_err_t grub_loader_boot (void); +/* The space between numbers is intentional for the simplicity of adding new + values even if external modules use them. */ +typedef enum { + /* A preboot hook which can use everything and turns nothing off. */ + GRUB_LOADER_PREBOOT_HOOK_PRIO_NORMAL = 400, + /* A preboot hook which can't use disks and may stop disks. */ + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK = 300, + /* A preboot hook which can't use disks or console and may stop console. */ + GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE = 200, + /* A preboot hook which can't use disks or console, can't modify memory map + and may stop memory services or finalize memory map. */ + GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY = 100, +} grub_loader_preboot_hook_prio_t; + +/* Register a preboot hook. */ +void *grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noret), + grub_err_t (*preboot_rest_func) (void), + grub_loader_preboot_hook_prio_t prio); + +/* Unregister given preboot hook. */ +void grub_loader_unregister_preboot_hook (void *hnd); + #endif /* ! GRUB_LOADER_HEADER */
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel