Hi, This patch add handler support, the lowest level structure is list, which represent a linked list:
struct grub_list { struct grub_list *next; }; functions to manipulate the list object: grub_list_push, grub_list_pop, grub_list_remove and grub_list_iterate. Another new structure is handler class, which represent a class of handlers: struct grub_handler_class { struct grub_handler_class *next; const char *name; grub_list_t handler_list; struct grub_handler *cur_handler; }; functions: grub_handler_class_register, grub_handler_class_unregister, grub_handler_class_iterate Finally, it's the handler structure: struct grub_handler { struct grub_handler *next; const char *name; grub_err_t (*init) (void); grub_err_t (*fini) (void); }; functions: grub_handler_register, grub_handler_unregister, grub_handler_iterate, grub_handler_set_current, grub_handler_get_current handler class and handler are lists, the register and unregister function calls the list function to do the job. I convert the terminal_input and terminal_output to use the new handler modal, but this can also apply to other parts of grub2. Structure lile fs, partmap, modules, commands are lists, and script engine, menu viewer and so on can be converted to handlers. Using handler method, terminal_input and terminal_output command are not necessary anymore. Instead, we can have a generic handler command: handler [class [handler]] called with no argument, it lists all handler class. called with 1 argument, it lists all handlers in a selected class. called with 2 argument, it set the current handler for a selected class. handler might be better implemented using the object orient features, however, this would be a overkill for grub2. Instead, I use a simpler compiler type checking method. For example, here is a code segment: void grub_handler_register (grub_handler_class_t class, void *handler) { int first_handler = (class->cur_handler == 0); GRUB_ASSERT_IS_LIST (grub_handler); grub_list_push (&class->handler_list, handler); if (first_handler) grub_handler_set_current (class, handler); } the handler type is void*, which allows it to pass pointers around without casting. Inside the function, when we want to use handler as a list object, we call macro GRUB_ASSERT_IS_LIST. This macro confirms that the fields required by grub_list is at the same location as in grub_handler, so we don't run into problem when accessing the structure in lower layout. Likewise, GRUB_ASSERT_IS_HANDLER checks whether a structure, such as grub_term_input_t, can be safely cast as grub_handler_t. The macro runs at compiled time, if no problem is found, it wouldn't generate any extra code. -- Bean
diff --git a/commands/handler.c b/commands/handler.c new file mode 100644 index 0000000..04f89f8 --- /dev/null +++ b/commands/handler.c @@ -0,0 +1,105 @@ +/* handler.c - test module for dynamic loading */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/err.h> +#include <grub/misc.h> +#include <grub/handler.h> + +static grub_err_t +grub_cmd_handler (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + char *find_name; + void *find_result; + void *curr_item = 0; + + auto int list_item (grub_handler_class_t item); + int list_item (grub_handler_class_t item) + { + if (item == curr_item) + grub_putchar ('*'); + + grub_printf ("%s\n", item->name); + + return 0; + } + + auto int find_item (grub_handler_class_t item); + int find_item (grub_handler_class_t item) + { + if (! grub_strcmp (item->name, find_name)) + { + find_result = item; + return 1; + } + + return 0; + } + + if (argc == 0) + { + grub_handler_class_iterate (list_item); + } + else + { + grub_handler_class_t class; + + find_name = args[0]; + find_result = 0; + grub_handler_class_iterate (find_item); + if (! find_result) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found"); + + class = find_result; + + if (argc == 1) + { + curr_item = class->cur_handler; + grub_handler_iterate (find_result, (grub_list_hook_t) list_item); + } + else + { + find_name = args[1]; + find_result = 0; + grub_handler_iterate (class, (grub_list_hook_t) find_item); + + if (! find_result) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found"); + + grub_handler_set_current (class, find_result); + } + } + + return 0; +} + +GRUB_MOD_INIT(handler) +{ + (void)mod; /* To stop warning. */ + grub_register_command ("handler", grub_cmd_handler, GRUB_COMMAND_FLAG_BOTH, + "handler [class [handler]]", + "List or select a handler", 0); +} + +GRUB_MOD_FINI(handler) +{ + grub_unregister_command ("hello"); +} diff --git a/conf/common.rmk b/conf/common.rmk index dfd481a..9a62ac3 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -330,7 +330,7 @@ scsi_mod_CFLAGS = $(COMMON_CFLAGS) scsi_mod_LDFLAGS = $(COMMON_LDFLAGS) # Commands. -pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod \ +pkglib_MODULES += hello.mod boot.mod handler.mod ls.mod \ cmp.mod cat.mod help.mod search.mod \ loopback.mod fs_uuid.mod configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ @@ -346,10 +346,10 @@ boot_mod_SOURCES = commands/boot.c boot_mod_CFLAGS = $(COMMON_CFLAGS) boot_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For terminal.mod. -terminal_mod_SOURCES = commands/terminal.c -terminal_mod_CFLAGS = $(COMMON_CFLAGS) -terminal_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For handler.mod. +handler_mod_SOURCES = commands/handler.c +handler_mod_CFLAGS = $(COMMON_CFLAGS) +handler_mod_LDFLAGS = $(COMMON_LDFLAGS) # For ls.mod. ls_mod_SOURCES = commands/ls.c diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index f26bf4a..d837281 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -17,7 +17,7 @@ kernel_elf_SOURCES = kern/i386/coreboot/startup.S \ kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ - kern/time.c \ + kern/time.c kern/list.c kern/handler.c \ kern/i386/dl.c kern/parser.c kern/partition.c \ kern/i386/tsc.c kern/i386/pit.c \ kern/generic/rtc_get_time_ms.c \ @@ -30,7 +30,7 @@ kernel_elf_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ machine/boot.h machine/console.h machine/init.h \ - machine/memory.h machine/loader.h + machine/memory.h machine/loader.h list.h handler.h kernel_elf_CFLAGS = $(COMMON_CFLAGS) kernel_elf_ASFLAGS = $(COMMON_ASFLAGS) kernel_elf_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x8200,-Bstatic @@ -57,7 +57,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/echo.c commands/help.c \ - commands/terminal.c commands/ls.c commands/test.c \ + commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/i386/cpuid.c \ disk/host.c disk/loopback.c \ diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index dc0547e..fe83f71 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -34,7 +34,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/help.c \ - commands/terminal.c commands/ls.c commands/test.c \ + commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/hexdump.c lib/hexdump.c \ commands/halt.c commands/reboot.c \ commands/i386/cpuid.c \ @@ -87,14 +87,14 @@ kernel_mod_SOURCES = kern/i386/efi/startup.S kern/main.c kern/device.c \ kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ term/efi/console.c disk/efi/efidisk.c \ - kern/time.c \ + kern/time.c kern/list.c kern/handler.c \ kern/i386/tsc.c kern/i386/pit.c \ kern/generic/rtc_get_time_ms.c \ kern/generic/millisleep.c kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ - efi/efi.h efi/time.h efi/disk.h + efi/efi.h efi/time.h efi/disk.h list.h handler.h kernel_mod_CFLAGS = $(COMMON_CFLAGS) kernel_mod_ASFLAGS = $(COMMON_ASFLAGS) kernel_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 90fc2f0..3a8886f 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -20,7 +20,7 @@ kernel_elf_SOURCES = kern/i386/ieee1275/startup.S kern/i386/ieee1275/init.c \ kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ kern/i386/dl.c kern/parser.c kern/partition.c \ kern/env.c \ - kern/time.c \ + kern/time.c kern/list.c kern/handler.c \ kern/generic/millisleep.c \ kern/ieee1275/ieee1275.c \ term/ieee1275/ofconsole.c \ @@ -29,7 +29,8 @@ kernel_elf_SOURCES = kern/i386/ieee1275/startup.S kern/i386/ieee1275/init.c \ kernel_elf_HEADERS = arg.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ - ieee1275/ieee1275.h machine/kernel.h machine/loader.h machine/memory.h + ieee1275/ieee1275.h machine/kernel.h machine/loader.h machine/memory.h \ + list.h handler.h kernel_elf_CFLAGS = $(COMMON_CFLAGS) kernel_elf_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-S,-Ttext,0x10000,-Bstatic @@ -55,7 +56,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/echo.c commands/help.c \ - commands/terminal.c commands/ls.c commands/test.c \ + commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/halt.c commands/reboot.c \ commands/i386/cpuid.c \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 2fd03b5..7abfa58 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -42,7 +42,7 @@ cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \ kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ - kern/time.c \ + kern/time.c kern/list.c kern/handler.c \ kern/i386/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \ kern/parser.c kern/partition.c \ kern/i386/tsc.c kern/i386/pit.c \ @@ -56,7 +56,7 @@ kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \ - machine/kernel.h machine/pxe.h + machine/kernel.h machine/pxe.h list.h handler.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) @@ -114,7 +114,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/echo.c commands/help.c \ - commands/terminal.c commands/ls.c commands/test.c \ + commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ commands/i386/cpuid.c \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index b48f303..17e92bf 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -40,7 +40,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/help.c \ - commands/search.c commands/terminal.c commands/test.c \ + commands/search.c commands/handler.c commands/test.c \ commands/ls.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/halt.c commands/reboot.c \ disk/loopback.c \ diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index ce133e9..3a28e94 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -44,7 +44,7 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-mkimage.c util/misc.c \ # For grub-emu #grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ # commands/configfile.c commands/default.c commands/help.c \ -# commands/search.c commands/terminal.c commands/ls.c \ +# commands/search.c commands/handler.c commands/ls.c \ # commands/timeout.c commands/test.c \ # commands/halt.c commands/reboot.c \ # disk/loopback.c \ @@ -75,8 +75,8 @@ kernel_elf_SOURCES = kern/sparc64/ieee1275/init.c kern/ieee1275/ieee1275.c \ kern/sparc64/ieee1275/openfw.c disk/ieee1275/ofdisk.c \ kern/partition.c kern/env.c kern/sparc64/dl.c symlist.c \ kern/generic/millisleep.c kern/generic/get_time_ms.c \ - kern/sparc64/cache.S kern/parser.c -kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h + kern/sparc64/cache.S kern/parser.c kern/list.c kern/handler.c +kernel_elf_HEADERS = grub/sparc64/ieee1275/ieee1275.h list.h handler.h kernel_elf_CFLAGS = $(COMMON_CFLAGS) kernel_elf_ASFLAGS = $(COMMON_ASFLAGS) kernel_elf_LDFLAGS = -mno-app-regs -nostdlib -Wl,-N,-Ttext,0x200000,-Bstatic,-melf64_sparc @@ -85,7 +85,7 @@ kernel_elf_LDFLAGS = -mno-app-regs -nostdlib -Wl,-N,-Ttext,0x200000,-Bstatic,-me #_linux.mod linux.mod pkglib_MODULES = fat.mod ufs.mod ext2.mod minix.mod \ hfs.mod jfs.mod normal.mod hello.mod font.mod ls.mod \ - boot.mod cmp.mod cat.mod terminal.mod fshelp.mod amiga.mod apple.mod \ + boot.mod cmp.mod cat.mod handler.mod fshelp.mod amiga.mod apple.mod \ pc.mod suspend.mod loopback.mod help.mod reboot.mod halt.mod sun.mod \ configfile.mod search.mod gzio.mod xfs.mod \ affs.mod sfs.mod acorn.mod @@ -185,10 +185,10 @@ boot_mod_SOURCES = commands/boot.c boot_mod_CFLAGS = $(COMMON_CFLAGS) boot_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For terminal.mod. -terminal_mod_SOURCES = commands/terminal.c -terminal_mod_CFLAGS = $(COMMON_CFLAGS) -terminal_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For handler.mod. +handler_mod_SOURCES = commands/handler.c +handler_mod_CFLAGS = $(COMMON_CFLAGS) +handler_mod_LDFLAGS = $(COMMON_LDFLAGS) # For ls.mod. ls_mod_SOURCES = commands/ls.c diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 973260b..66b3d1a 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -36,7 +36,7 @@ grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c util/grub-emu.c_DEPENDENCIES = grub_emu_init.h grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ commands/configfile.c commands/help.c \ - commands/terminal.c commands/ls.c commands/test.c \ + commands/handler.c commands/ls.c commands/test.c \ commands/search.c commands/hexdump.c lib/hexdump.c \ commands/halt.c commands/reboot.c \ commands/i386/cpuid.c \ @@ -89,14 +89,14 @@ kernel_mod_SOURCES = kern/x86_64/efi/startup.S kern/x86_64/efi/callwrap.S \ kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ - kern/time.c \ + kern/time.c kern/list.c kern/handler.c \ kern/i386/tsc.c kern/i386/pit.c \ kern/generic/millisleep.c kern/generic/rtc_get_time_ms.c \ term/efi/console.c disk/efi/efidisk.c kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ - efi/efi.h efi/time.h efi/disk.h machine/loader.h + efi/efi.h efi/time.h efi/disk.h machine/loader.h list.h handler.h kernel_mod_CFLAGS = $(COMMON_CFLAGS) kernel_mod_ASFLAGS = $(COMMON_ASFLAGS) kernel_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/include/grub/handler.h b/include/grub/handler.h new file mode 100644 index 0000000..26c98d3 --- /dev/null +++ b/include/grub/handler.h @@ -0,0 +1,69 @@ +/* handler.h - header for grub handler */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_HANDLER_HEADER +#define GRUB_HANDLER_HEADER 1 + +#include <grub/list.h> +#include <grub/err.h> + +struct grub_handler +{ + struct grub_handler *next; + const char *name; + grub_err_t (*init) (void); + grub_err_t (*fini) (void); +}; +typedef struct grub_handler *grub_handler_t; + +struct grub_handler_class +{ + struct grub_handler_class *next; + const char *name; + grub_list_t handler_list; + struct grub_handler *cur_handler; +}; +typedef struct grub_handler_class *grub_handler_class_t; + +void EXPORT_FUNC(grub_handler_class_register) (grub_handler_class_t class); +void EXPORT_FUNC(grub_handler_class_unregister) (grub_handler_class_t class); +void EXPORT_FUNC(grub_handler_class_iterate) (int (*hook) + (grub_handler_class_t item)); + +void EXPORT_FUNC(grub_handler_register) (grub_handler_class_t class, + void *handler); +void EXPORT_FUNC(grub_handler_unregister) (grub_handler_class_t class, + void *handler); +void EXPORT_FUNC(grub_handler_iterate) (grub_handler_class_t class, + grub_list_hook_t hook); +grub_err_t EXPORT_FUNC(grub_handler_set_current) (grub_handler_class_t class, + void *handler); +void * EXPORT_FUNC(grub_handler_get_current) (grub_handler_class_t class); + +#define GRUB_ASSERT_IS_HANDLER(type) \ + { \ + struct type t1; \ + struct grub_handler t2; \ + GRUB_ASSERT_CHECK_FIELD (next); \ + GRUB_ASSERT_CHECK_FIELD (name); \ + GRUB_ASSERT_CHECK_FIELD (init); \ + GRUB_ASSERT_CHECK_FIELD (fini); \ + } + +#endif /* ! GRUB_HANDLER_HEADER */ diff --git a/include/grub/list.h b/include/grub/list.h new file mode 100644 index 0000000..7620937 --- /dev/null +++ b/include/grub/list.h @@ -0,0 +1,56 @@ +/* list.h - header for grub list */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_LIST_HEADER +#define GRUB_LIST_HEADER 1 + +#include <grub/symbol.h> +#include <grub/types.h> + +struct grub_list +{ + struct grub_list *next; +}; +typedef struct grub_list *grub_list_t; + +typedef int (*grub_list_hook_t) (grub_list_t item); + +void EXPORT_FUNC(grub_list_push) (grub_list_t *head, void *item); +void * EXPORT_FUNC(grub_list_pop) (grub_list_t *head); +void EXPORT_FUNC(grub_list_remove) (grub_list_t *head, void *item); +void EXPORT_FUNC(grub_list_iterate) (grub_list_t head, + grub_list_hook_t hook); + +/* This function doesn't exist, so if assertion is false for some reason, the + linker would fail. */ +extern void grub_assert_fail (void); + +#define GRUB_ASSERT_CHECK_FIELD(field) \ + if ((char *) &t1. field - (char *) &t1 != \ + (char *) &t2. field - (char *) &t2) \ + grub_assert_fail (); + +#define GRUB_ASSERT_IS_LIST(type) \ + { \ + struct type t1; \ + struct grub_list t2; \ + GRUB_ASSERT_CHECK_FIELD (next); \ + } + +#endif /* ! GRUB_LIST_HEADER */ diff --git a/include/grub/term.h b/include/grub/term.h index 13835bb..fbe890d 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -38,6 +38,7 @@ #include <grub/err.h> #include <grub/symbol.h> #include <grub/types.h> +#include <grub/handler.h> /* These are used to represent the various color states we use. */ typedef enum @@ -139,6 +140,9 @@ grub_term_color_state; struct grub_term_input { + /* The next terminal. */ + struct grub_term_input *next; + /* The terminal name. */ const char *name; @@ -153,14 +157,14 @@ struct grub_term_input /* Get a character. */ int (*getkey) (void); - - /* The next terminal. */ - struct grub_term_input *next; }; typedef struct grub_term_input *grub_term_input_t; struct grub_term_output { + /* The next terminal. */ + struct grub_term_output *next; + /* The terminal name. */ const char *name; @@ -208,24 +212,9 @@ struct grub_term_output /* The feature flags defined above. */ grub_uint32_t flags; - - /* The next terminal. */ - struct grub_term_output *next; }; typedef struct grub_term_output *grub_term_output_t; -void EXPORT_FUNC(grub_term_register_input) (grub_term_input_t term); -void EXPORT_FUNC(grub_term_register_output) (grub_term_output_t term); -void EXPORT_FUNC(grub_term_unregister_input) (grub_term_input_t term); -void EXPORT_FUNC(grub_term_unregister_output) (grub_term_output_t term); -void EXPORT_FUNC(grub_term_iterate_input) (int (*hook) (grub_term_input_t term)); -void EXPORT_FUNC(grub_term_iterate_output) (int (*hook) (grub_term_output_t term)); - -grub_err_t EXPORT_FUNC(grub_term_set_current_input) (grub_term_input_t term); -grub_err_t EXPORT_FUNC(grub_term_set_current_output) (grub_term_output_t term); -grub_term_input_t EXPORT_FUNC(grub_term_get_current_input) (void); -grub_term_output_t EXPORT_FUNC(grub_term_get_current_output) (void); - void EXPORT_FUNC(grub_putchar) (int c); void EXPORT_FUNC(grub_putcode) (grub_uint32_t code); grub_ssize_t EXPORT_FUNC(grub_getcharwidth) (grub_uint32_t code); @@ -248,6 +237,15 @@ void EXPORT_FUNC(grub_set_more) (int onoff); /* For convenience. */ #define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) +extern struct grub_handler_class EXPORT_VAR(grub_term_input_class); +extern struct grub_handler_class EXPORT_VAR(grub_term_output_class); + +#define grub_cur_term_input \ + ((grub_term_input_t) grub_term_input_class.cur_handler) + +#define grub_cur_term_output \ + ((grub_term_output_t) grub_term_output_class.cur_handler) + #endif /* ! ASM_FILE */ #endif /* ! GRUB_TERM_HEADER */ diff --git a/kern/handler.c b/kern/handler.c new file mode 100644 index 0000000..203d7b0 --- /dev/null +++ b/kern/handler.c @@ -0,0 +1,88 @@ +/* handler.c - grub handler function*/ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/handler.h> + +static grub_list_t grub_handler_class_list; + +void +grub_handler_class_register (grub_handler_class_t class) +{ + GRUB_ASSERT_IS_LIST (grub_handler_class); + grub_list_push (&grub_handler_class_list, class); +} + +void +grub_handler_class_unregister (grub_handler_class_t class) +{ + grub_list_remove (&grub_handler_class_list, class); +} + +void +grub_handler_class_iterate (int (*hook) (grub_handler_class_t item)) +{ + grub_list_iterate (grub_handler_class_list, (grub_list_hook_t) hook); +} + +void +grub_handler_register (grub_handler_class_t class, void *handler) +{ + int first_handler = (class->cur_handler == 0); + + GRUB_ASSERT_IS_LIST (grub_handler); + grub_list_push (&class->handler_list, handler); + + if (first_handler) + grub_handler_set_current (class, handler); +} + +void +grub_handler_unregister (grub_handler_class_t class, void *handler) +{ + grub_list_remove (&class->handler_list, handler); +} + +void +grub_handler_iterate (grub_handler_class_t class, grub_list_hook_t hook) +{ + grub_list_iterate (class->handler_list, hook); +} + +grub_err_t +grub_handler_set_current (grub_handler_class_t class, void *handler) +{ + grub_handler_t new_handler = handler; + + if (class->cur_handler && class->cur_handler->fini) + if ((class->cur_handler->fini) () != GRUB_ERR_NONE) + return grub_errno; + + if (new_handler->init) + if ((new_handler->init) () != GRUB_ERR_NONE) + return grub_errno; + + class->cur_handler = new_handler; + return GRUB_ERR_NONE; +} + +void * +grub_handler_get_current (grub_handler_class_t class) +{ + return class->cur_handler; +} diff --git a/kern/list.c b/kern/list.c new file mode 100644 index 0000000..cdeeecf --- /dev/null +++ b/kern/list.c @@ -0,0 +1,62 @@ +/* list.c - grub list function*/ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/list.h> + +void +grub_list_push (grub_list_t *head, void *item) +{ + ((grub_list_t) item)->next = *head; + *head = item; +} + +void * +grub_list_pop (grub_list_t *head) +{ + grub_list_t item; + + item = *head; + if (item) + *head = item->next; + + return item; +} + +void +grub_list_remove (grub_list_t *head, void *item) +{ + grub_list_t *p, q; + + for (p = head, q = *p; q; p = &(q->next), q = q->next) + if (q == item) + { + *p = q->next; + break; + } +} + +void +grub_list_iterate (grub_list_t head, grub_list_hook_t hook) +{ + grub_list_t p; + + for (p = head; p; p = p->next) + if (hook (p)) + break; +} diff --git a/kern/main.c b/kern/main.c index 40300b2..000374c 100644 --- a/kern/main.c +++ b/kern/main.c @@ -27,6 +27,7 @@ #include <grub/device.h> #include <grub/env.h> #include <grub/mm.h> +#include <grub/handler.h> void grub_module_iterate (int (*hook) (struct grub_module_header *header)) @@ -60,7 +61,7 @@ grub_load_modules (void) { /* Not an ELF module, skip. */ if (header->type != OBJ_TYPE_ELF) - return 0; + return 0; if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header), (header->size - sizeof (struct grub_module_header)))) @@ -126,6 +127,12 @@ grub_load_normal_mode (void) void grub_main (void) { + /* Register handler classes. */ + GRUB_ASSERT_IS_HANDLER(grub_term_input); + GRUB_ASSERT_IS_HANDLER(grub_term_output); + grub_handler_class_register (&grub_term_input_class); + grub_handler_class_register (&grub_term_output_class); + /* First of all, initialize the machine. */ grub_machine_init (); diff --git a/kern/misc.c b/kern/misc.c index 641bd7a..97a61f2 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -1063,11 +1063,11 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, void grub_abort (void) { - if (grub_term_get_current_output ()) + if (grub_cur_term_output) { grub_printf ("\nAborted."); - if (grub_term_get_current_input ()) + if (grub_cur_term_input) { grub_printf (" Press any key to exit."); grub_getkey (); diff --git a/kern/term.c b/kern/term.c index 8d5a23b..524b79d 100644 --- a/kern/term.c +++ b/kern/term.c @@ -21,14 +21,17 @@ #include <grub/mm.h> #include <grub/misc.h> #include <grub/env.h> +#include <grub/handler.h> -/* The list of terminals. */ -static grub_term_input_t grub_term_list_input; -static grub_term_output_t grub_term_list_output; +struct grub_handler_class grub_term_input_class = + { + .name = "input" + }; -/* The current terminal. */ -static grub_term_input_t grub_cur_term_input; -static grub_term_output_t grub_cur_term_output; +struct grub_handler_class grub_term_output_class = + { + .name = "output" + }; /* The amount of lines counted by the pager. */ static int grub_more_lines; @@ -39,112 +42,6 @@ static int grub_more; /* The current cursor state. */ static int cursor_state = 1; -void -grub_term_register_input (grub_term_input_t term) -{ - term->next = grub_term_list_input; - grub_term_list_input = term; - if (! grub_cur_term_input) - grub_term_set_current_input (term); -} - -void -grub_term_register_output (grub_term_output_t term) -{ - term->next = grub_term_list_output; - grub_term_list_output = term; - if (! grub_cur_term_output) - grub_term_set_current_output (term); -} - -void -grub_term_unregister_input (grub_term_input_t term) -{ - grub_term_input_t *p, q; - - for (p = &grub_term_list_input, q = *p; q; p = &(q->next), q = q->next) - if (q == term) - { - *p = q->next; - break; - } -} - -void -grub_term_unregister_output (grub_term_output_t term) -{ - grub_term_output_t *p, q; - - for (p = &grub_term_list_output, q = *p; q; p = &(q->next), q = q->next) - if (q == term) - { - *p = q->next; - break; - } -} - -void -grub_term_iterate_input (int (*hook) (grub_term_input_t term)) -{ - grub_term_input_t p; - - for (p = grub_term_list_input; p; p = p->next) - if (hook (p)) - break; -} - -void -grub_term_iterate_output (int (*hook) (grub_term_output_t term)) -{ - grub_term_output_t p; - - for (p = grub_term_list_output; p; p = p->next) - if (hook (p)) - break; -} - -grub_err_t -grub_term_set_current_input (grub_term_input_t term) -{ - if (grub_cur_term_input && grub_cur_term_input->fini) - if ((grub_cur_term_input->fini) () != GRUB_ERR_NONE) - return grub_errno; - - if (term->init) - if ((term->init) () != GRUB_ERR_NONE) - return grub_errno; - - grub_cur_term_input = term; - return GRUB_ERR_NONE; -} - -grub_err_t -grub_term_set_current_output (grub_term_output_t term) -{ - if (grub_cur_term_output && grub_cur_term_output->fini) - if ((grub_cur_term_output->fini) () != GRUB_ERR_NONE) - return grub_errno; - - if (term->init) - if ((term->init) () != GRUB_ERR_NONE) - return grub_errno; - - grub_cur_term_output = term; - return GRUB_ERR_NONE; -} - -grub_term_input_t -grub_term_get_current_input (void) -{ - return grub_cur_term_input; -} - -grub_term_output_t -grub_term_get_current_output (void) -{ - return grub_cur_term_output; -} - /* Put a Unicode character. */ void grub_putcode (grub_uint32_t code) diff --git a/term/efi/console.c b/term/efi/console.c index 0bf2449..0974fdf 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -366,13 +366,13 @@ grub_console_init (void) return; } - grub_term_register_input (&grub_console_term_input); - grub_term_register_output (&grub_console_term_output); + grub_handler_register (&grub_term_output_class, &grub_console_term_output); + grub_handler_register (&grub_term_input_class, &grub_console_term_input); } void grub_console_fini (void) { - grub_term_unregister_input (&grub_console_term_input); - grub_term_unregister_output (&grub_console_term_output); + grub_handler_unregister (&grub_term_input_class, &grub_console_term_input); + grub_handler_unregister (&grub_term_output_class, &grub_console_term_output); } diff --git a/term/gfxterm.c b/term/gfxterm.c index abb1b9e..ad2edec 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -1164,7 +1164,7 @@ static struct grub_term_output grub_video_term = GRUB_MOD_INIT(term_gfxterm) { my_mod = mod; - grub_term_register_output (&grub_video_term); + grub_handler_register (&grub_term_output_class, &grub_video_term); grub_register_command ("background_image", grub_gfxterm_background_image_cmd, @@ -1177,5 +1177,5 @@ GRUB_MOD_INIT(term_gfxterm) GRUB_MOD_FINI(term_gfxterm) { grub_unregister_command ("bgimage"); - grub_term_unregister_output (&grub_video_term); + grub_handler_unregister (&grub_term_output_class, &grub_video_term); } diff --git a/term/i386/pc/at_keyboard.c b/term/i386/pc/at_keyboard.c index ff5246d..5b67303 100644 --- a/term/i386/pc/at_keyboard.c +++ b/term/i386/pc/at_keyboard.c @@ -226,10 +226,10 @@ static struct grub_term_input grub_at_keyboard_term = GRUB_MOD_INIT(at_keyboard) { - grub_term_register_input (&grub_at_keyboard_term); + grub_handler_register (&grub_term_input_class, &grub_at_keyboard_term); } GRUB_MOD_FINI(at_keyboard) { - grub_term_unregister_input (&grub_at_keyboard_term); + grub_handler_unregister (&grub_term_input_class, &grub_at_keyboard_term); } diff --git a/term/i386/pc/console.c b/term/i386/pc/console.c index 6c6be46..5769fd8 100644 --- a/term/i386/pc/console.c +++ b/term/i386/pc/console.c @@ -46,8 +46,8 @@ static struct grub_term_output grub_console_term_output = void grub_console_init (void) { - grub_term_register_output (&grub_console_term_output); - grub_term_register_input (&grub_console_term_input); + grub_handler_register (&grub_term_output_class, &grub_console_term_output); + grub_handler_register (&grub_term_input_class, &grub_console_term_input); } void @@ -55,8 +55,8 @@ grub_console_fini (void) { /* This is to make sure the console is restored to text mode before we boot. */ - grub_term_set_current_output (&grub_console_term_output); + grub_handler_set_current (&grub_term_output_class, &grub_console_term_output); - grub_term_unregister_input (&grub_console_term_input); - grub_term_unregister_output (&grub_console_term_output); + grub_handler_unregister (&grub_term_input_class, &grub_console_term_input); + grub_handler_unregister (&grub_term_output_class, &grub_console_term_output); } diff --git a/term/i386/pc/serial.c b/term/i386/pc/serial.c index 03a46ba..5368188 100644 --- a/term/i386/pc/serial.c +++ b/term/i386/pc/serial.c @@ -577,8 +577,8 @@ grub_cmd_serial (struct grub_arg_list *state, /* Register terminal if not yet registered. */ if (registered == 0) { - grub_term_register_input (&grub_serial_term_input); - grub_term_register_output (&grub_serial_term_output); + grub_handler_register (&grub_term_input_class, &grub_serial_term_input); + grub_handler_register (&grub_term_output_class, &grub_serial_term_output); registered = 1; } } @@ -593,8 +593,8 @@ grub_cmd_serial (struct grub_arg_list *state, if (serial_hw_init () != GRUB_ERR_NONE) { /* If unable to restore settings, unregister terminal. */ - grub_term_unregister_input (&grub_serial_term_input); - grub_term_unregister_output (&grub_serial_term_output); + grub_handler_unregister (&grub_term_input_class, &grub_serial_term_input); + grub_handler_unregister (&grub_term_output_class, &grub_serial_term_output); registered = 0; } } @@ -621,7 +621,7 @@ GRUB_MOD_FINI(serial) grub_unregister_command ("serial"); if (registered == 1) /* Unregister terminal only if registered. */ { - grub_term_unregister_input (&grub_serial_term_input); - grub_term_unregister_output (&grub_serial_term_output); + grub_handler_unregister (&grub_term_input_class, &grub_serial_term_input); + grub_handler_unregister (&grub_term_output_class, &grub_serial_term_output); } } diff --git a/term/i386/pc/vga.c b/term/i386/pc/vga.c index d32c86e..2f22c5d 100644 --- a/term/i386/pc/vga.c +++ b/term/i386/pc/vga.c @@ -510,10 +510,10 @@ GRUB_MOD_INIT(vga) #ifndef GRUB_UTIL my_mod = mod; #endif - grub_term_register_output (&grub_vga_term); + grub_handler_register (&grub_term_output_class, &grub_vga_term); } GRUB_MOD_FINI(vga) { - grub_term_unregister_output (&grub_vga_term); + grub_handler_unregister (&grub_term_output_class, &grub_vga_term); } diff --git a/term/i386/pc/vga_text.c b/term/i386/pc/vga_text.c index e067ed6..c292cd5 100644 --- a/term/i386/pc/vga_text.c +++ b/term/i386/pc/vga_text.c @@ -168,10 +168,10 @@ static struct grub_term_output grub_vga_text_term = GRUB_MOD_INIT(vga_text) { - grub_term_register_output (&grub_vga_text_term); + grub_handler_register (&grub_term_output_class, &grub_vga_text_term); } GRUB_MOD_FINI(vga_text) { - grub_term_unregister_output (&grub_vga_text_term); + grub_handler_unregister (&grub_term_output_class, &grub_vga_text_term); } diff --git a/term/ieee1275/ofconsole.c b/term/ieee1275/ofconsole.c index 70fda9a..54bc2cc 100644 --- a/term/ieee1275/ofconsole.c +++ b/term/ieee1275/ofconsole.c @@ -420,13 +420,13 @@ static struct grub_term_output grub_ofconsole_term_output = void grub_console_init (void) { - grub_term_register_input (&grub_ofconsole_term_input); - grub_term_register_output (&grub_ofconsole_term_output); + grub_handler_register (&grub_term_output_class, &grub_ofconsole_term_output); + grub_handler_register (&grub_term_input_class, &grub_ofconsole_term_input); } void grub_console_fini (void) { - grub_term_unregister_input (&grub_ofconsole_term_input); - grub_term_unregister_output (&grub_ofconsole_term_output); + grub_handler_unregister (&grub_term_input_class, &grub_ofconsole_term_input); + grub_handler_unregister (&grub_term_output_class, &grub_ofconsole_term_output); } diff --git a/util/grub-editenv.c b/util/grub-editenv.c index 475d12d..18f5725 100644 --- a/util/grub-editenv.c +++ b/util/grub-editenv.c @@ -21,6 +21,7 @@ #include <grub/types.h> #include <grub/util/misc.h> #include <grub/lib/envblk.h> +#include <grub/term.h> #include <stdio.h> #include <unistd.h> @@ -28,6 +29,9 @@ #include <stdlib.h> #include <getopt.h> +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class; + void grub_putchar (int c) { @@ -40,18 +44,6 @@ grub_refresh (void) fflush (stdout); } -void * -grub_term_get_current_input (void) -{ - return 0; -} - -void * -grub_term_get_current_output (void) -{ - return 0; -} - int grub_getkey (void) { diff --git a/util/grub-fstest.c b/util/grub-fstest.c index ca25425..720734a 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -41,6 +41,9 @@ #include <stdlib.h> #include <getopt.h> +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class; + void grub_putchar (int c) { @@ -53,18 +56,6 @@ grub_getkey (void) return -1; } -grub_term_input_t -grub_term_get_current_input (void) -{ - return 0; -} - -grub_term_output_t -grub_term_get_current_output (void) -{ - return 0; -} - void grub_refresh (void) { diff --git a/util/grub-probe.c b/util/grub-probe.c index 402b758..d2b5128 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -54,6 +54,9 @@ enum { int print = PRINT_FS; static unsigned int argument_is_device = 0; +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class; + void grub_putchar (int c) { @@ -66,18 +69,6 @@ grub_getkey (void) return -1; } -grub_term_input_t -grub_term_get_current_input (void) -{ - return 0; -} - -grub_term_output_t -grub_term_get_current_output (void) -{ - return 0; -} - void grub_refresh (void) { diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index ccbb465..3b8f446 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -62,6 +62,9 @@ struct boot_blocklist grub_uint16_t segment; } __attribute__ ((packed)); +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class; + void grub_putchar (int c) { @@ -74,18 +77,6 @@ grub_getkey (void) return -1; } -grub_term_input_t -grub_term_get_current_input (void) -{ - return 0; -} - -grub_term_output_t -grub_term_get_current_output (void) -{ - return 0; -} - void grub_refresh (void) {
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel