--- /dev/null
--- /dev/null
++/* handler.c - commands to list or select handlers */
++/*
++ * 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/dl.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/term.h>
++#include <grub/handler.h>
++#include <grub/command.h>
++
++static grub_err_t
++grub_cmd_handler (struct grub_command *cmd,
++ int argc, char **args)
++{
++ char *class_name;
++ void *curr_item = 0;
++ grub_handler_class_t head;
++
++ auto int list_item (grub_named_list_t item);
++ int list_item (grub_named_list_t item)
++ {
++ if (item == curr_item)
++ grub_putchar ('*');
++
++ grub_printf ("%s\n", item->name);
++
++ return 0;
++ }
++
++ class_name = (grub_strcmp (cmd->name, "handler")) ? (char *) cmd->name : 0;
++
++ head = grub_handler_class_list;
++ if ((argc == 0) && (class_name == 0))
++ {
++ grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_item);
++ }
++ else
++ {
++ grub_handler_class_t class;
++
++ if (class_name == 0)
++ {
++ class_name = args[0];
++ argc--;
++ args++;
++ }
++
++ class = grub_named_list_find (GRUB_AS_NAMED_LIST (head), class_name);
++ if (! class)
++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found");
++
++ if (argc == 0)
++ {
++ curr_item = class->cur_handler;
++ grub_list_iterate (GRUB_AS_LIST (class->handler_list),
++ (grub_list_hook_t) list_item);
++ }
++ else
++ {
++ grub_handler_t handler;
++
++ handler =
++ grub_named_list_find (GRUB_AS_NAMED_LIST (class->handler_list),
++ args[0]);
++
++ if (! handler)
++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found");
++
++ grub_handler_set_current (class, handler);
++ }
++ }
++
++ return 0;
++}
++
++static grub_command_t cmd_handler, cmd_terminal_input, cmd_terminal_output;
++
++GRUB_MOD_INIT(handler)
++{
++ cmd_handler =
++ grub_register_command ("handler", grub_cmd_handler,
++ "[class [handler]]",
++ "List or select a handler.");
++ cmd_terminal_input =
++ grub_register_command ("terminal_input", grub_cmd_handler,
++ "[handler]",
++ "List or select an input terminal.");
++ cmd_terminal_output =
++ grub_register_command ("terminal_output", grub_cmd_handler,
++ "[handler]",
++ "List or select an output terminal.");
++}
++
++GRUB_MOD_FINI(handler)
++{
++ grub_unregister_command (cmd_handler);
++ grub_unregister_command (cmd_terminal_input);
++ grub_unregister_command (cmd_terminal_output);
++}
--- /dev/null
-FUNC_NAME (const char *key, const char *var, int no_floppy)
+ /* search.c - search devices based on a file or a filesystem label */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,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/types.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/err.h>
+ #include <grub/dl.h>
+ #include <grub/device.h>
+ #include <grub/file.h>
+ #include <grub/env.h>
+ #include <grub/command.h>
+ #include <grub/search.h>
+ #include <grub/i18n.h>
+
+ void
- grub_device_iterate (iterate_device);
++FUNC_NAME (const char *key, const char *var, int no_floppy,
++ const char **hints, unsigned nhints)
+ {
+ int count = 0;
+ grub_fs_autoload_hook_t saved_autoload;
+
+ auto int iterate_device (const char *name);
+ int iterate_device (const char *name)
+ {
+ int found = 0;
+
+ /* Skip floppy drives when requested. */
+ if (no_floppy &&
+ name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9')
+ return 0;
+
+ #ifdef DO_SEARCH_FILE
+ {
+ char *buf;
+ grub_file_t file;
+
+ buf = grub_xasprintf ("(%s)%s", name, key);
+ if (! buf)
+ return 1;
+
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (buf);
+ if (file)
+ {
+ found = 1;
+ grub_file_close (file);
+ }
+ grub_free (buf);
+ }
+ #else
+ {
+ /* SEARCH_FS_UUID or SEARCH_LABEL */
+ grub_device_t dev;
+ grub_fs_t fs;
+ char *quid;
+
+ dev = grub_device_open (name);
+ if (dev)
+ {
+ fs = grub_fs_probe (dev);
+
+ #ifdef DO_SEARCH_FS_UUID
+ #define compare_fn grub_strcasecmp
+ #define read_fn uuid
+ #else
+ #define compare_fn grub_strcmp
+ #define read_fn label
+ #endif
+
+ if (fs && fs->read_fn)
+ {
+ fs->read_fn (dev, &quid);
+
+ if (grub_errno == GRUB_ERR_NONE && quid)
+ {
+ if (compare_fn (quid, key) == 0)
+ found = 1;
+
+ grub_free (quid);
+ }
+ }
+
+ grub_device_close (dev);
+ }
+ }
+ #endif
+
+ if (found)
+ {
+ count++;
+ if (var)
+ grub_env_set (var, name);
+ else
+ grub_printf (" %s", name);
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+ return (found && var);
+ }
+
++ auto void try (void);
++ void try (void)
++ {
++ unsigned i;
++ for (i = 0; i < nhints; i++)
++ if (iterate_device (hints[i]))
++ return;
++ grub_device_iterate (iterate_device);
++ }
++
+ /* First try without autoloading if we're setting variable. */
+ if (var)
+ {
+ saved_autoload = grub_fs_autoload_hook;
+ grub_fs_autoload_hook = 0;
- grub_device_iterate (iterate_device);
++ try ();
+
+ /* Restore autoload hook. */
+ grub_fs_autoload_hook = saved_autoload;
+
+ /* Retry with autoload if nothing found. */
+ if (grub_errno == GRUB_ERR_NONE && count == 0)
- grub_device_iterate (iterate_device);
++ try ();
+ }
+ else
- FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0);
++ try ();
+
+ if (grub_errno == GRUB_ERR_NONE && count == 0)
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key);
+ }
+
+ static grub_err_t
+ grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc,
+ char **args)
+ {
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified");
+
- N_("NAME [VARIABLE]"),
++ FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (const char **) (args + 2),
++ argc > 2 ? argc - 2 : 0);
+
+ return grub_errno;
+ }
+
+ static grub_command_t cmd;
+
+ #ifdef DO_SEARCH_FILE
+ GRUB_MOD_INIT(search_fs_file)
+ #elif defined (DO_SEARCH_FS_UUID)
+ GRUB_MOD_INIT(search_fs_uuid)
+ #else
+ GRUB_MOD_INIT(search_label)
+ #endif
+ {
+ cmd =
+ grub_register_command (COMMAND_NAME, grub_cmd_do_search,
++ N_("NAME [VARIABLE] [HINTS]"),
+ HELP_MESSAGE);
+ }
+
+ #ifdef DO_SEARCH_FILE
+ GRUB_MOD_FINI(search_fs_file)
+ #elif defined (DO_SEARCH_FS_UUID)
+ GRUB_MOD_FINI(search_fs_uuid)
+ #else
+ GRUB_MOD_FINI(search_label)
+ #endif
+ {
+ grub_unregister_command (cmd);
+ }
--- /dev/null
- grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set);
+ /* search.c - search devices based on a file or a filesystem label */
+ /*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2005,2007,2008,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/types.h>
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/err.h>
+ #include <grub/dl.h>
+ #include <grub/env.h>
+ #include <grub/extcmd.h>
+ #include <grub/search.h>
+ #include <grub/i18n.h>
+
+ static const struct grub_arg_option options[] =
+ {
+ {"file", 'f', 0, N_("Search devices by a file."), 0, 0},
+ {"label", 'l', 0, N_("Search devices by a filesystem label."),
+ 0, 0},
+ {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."),
+ 0, 0},
+ {"set", 's', GRUB_ARG_OPTION_OPTIONAL,
+ N_("Set a variable to the first device found."), "VAR", ARG_TYPE_STRING},
+ {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+ enum options
+ {
+ SEARCH_FILE,
+ SEARCH_LABEL,
+ SEARCH_FS_UUID,
+ SEARCH_SET,
+ SEARCH_NO_FLOPPY,
+ };
+
+ static grub_err_t
+ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
+ {
+ struct grub_arg_list *state = ctxt->state;
+ const char *var = 0;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified");
+
+ if (state[SEARCH_SET].set)
+ var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root";
+
+ if (state[SEARCH_LABEL].set)
- grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set);
++ grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set,
++ (const char **) (args + 1), argc - 1);
+ else if (state[SEARCH_FS_UUID].set)
- grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set);
++ grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set,
++ (const char **) (args + 1), argc - 1);
+ else if (state[SEARCH_FILE].set)
- N_("search [-f|-l|-u|-s|-n] NAME"),
++ grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set,
++ (const char **) (args + 1), argc - 1);
+ else
+ return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
+
+ return grub_errno;
+ }
+
+ static grub_extcmd_t cmd;
+
+ GRUB_MOD_INIT(search)
+ {
+ cmd =
+ grub_register_extcmd ("search", grub_cmd_search,
+ GRUB_COMMAND_FLAG_BOTH,
++ N_("[-f|-l|-u|-s|-n] NAME [HINTS]"),
+ N_("Search devices by file, filesystem label"
+ " or filesystem UUID."
+ " If --set is specified, the first device found is"
+ " set to a variable. If no variable name is"
+ " specified, \"root\" is used."),
+ options);
+ }
+
+ GRUB_MOD_FINI(search)
+ {
+ grub_unregister_extcmd (cmd);
+ }
--- /dev/null
--- /dev/null
++gcc -c -m32 -DELF32 -o efiemu32.o ./efiemu.c -Wall -Werror -nostdlib -O2 -I. -I../../include
++gcc -c -m64 -DELF64 -o efiemu64_c.o ./efiemu.c -Wall -Werror -mcmodel=large -O2 -I. -I../../include
++gcc -c -m64 -DELF64 -o efiemu64_s.o ./efiemu.S -Wall -Werror -mcmodel=large -O2 -I. -I../../include
++ld -o efiemu64.o -r efiemu64_s.o efiemu64_c.o -nostdlib
--- /dev/null
--- /dev/null
++/* 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>
++
++grub_handler_class_t grub_handler_class_list;
++
++void
++grub_handler_register (grub_handler_class_t class, grub_handler_t handler)
++{
++ int first_handler = (class->handler_list == 0);
++
++ grub_list_push (GRUB_AS_LIST_P (&class->handler_list),
++ GRUB_AS_LIST (handler));
++
++ if (first_handler)
++ {
++ grub_list_push (GRUB_AS_LIST_P (&grub_handler_class_list),
++ GRUB_AS_LIST (class));
++ grub_handler_set_current (class, handler);
++ }
++}
++
++void
++grub_handler_unregister (grub_handler_class_t class, grub_handler_t handler)
++{
++ grub_list_remove (GRUB_AS_LIST_P (&class->handler_list),
++ GRUB_AS_LIST (handler));
++
++ if (class->handler_list == 0)
++ grub_list_remove (GRUB_AS_LIST_P (&grub_handler_class_list),
++ GRUB_AS_LIST (class));
++}
++
++grub_err_t
++grub_handler_set_current (grub_handler_class_t class, grub_handler_t handler)
++{
++ if (class->cur_handler && class->cur_handler->fini)
++ if ((class->cur_handler->fini) () != GRUB_ERR_NONE)
++ return grub_errno;
++
++ if (handler->init)
++ if ((handler->init) () != GRUB_ERR_NONE)
++ return grub_errno;
++
++ class->cur_handler = handler;
++ return GRUB_ERR_NONE;
++}
--- /dev/null
--- /dev/null
++/* init.c -- Initialize GRUB on Open Firmware. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2003,2004,2005,2007,2008 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/types.h>
++#include <grub/cache.h>
++
++void grub_stop_floppy (void);
++
++void
++grub_stop_floppy (void)
++{
++}
++
++void
++grub_arch_sync_caches (void *address __attribute__ ((unused)),
++ grub_size_t len __attribute__ ((unused)))
++{
++}
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 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/>.
++ */
++
++
++/*
++ * Note: These functions defined in this file may be called from C.
++ * Be careful of that you must not modify some registers. Quote
++ * from gcc-2.95.2/gcc/config/i386/i386.h:
++
++ 1 for registers not available across function calls.
++ These must include the FIXED_REGISTERS and also any
++ registers that can be used without being saved.
++ The latter must include the registers where values are returned
++ and the register where structure-value addresses are passed.
++ Aside from that, you can include as many other registers as you like.
++
++ ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
++{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
++ */
++
++/*
++ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
++ * So the first three arguments are passed in %eax, %edx, and %ecx,
++ * respectively, and if a function has a fixed number of arguments
++ * and the number if greater than three, the function must return
++ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
++ */
++
++/*
++ * This is the area for all of the special variables.
++ */
++
++ .p2align 2 /* force 4-byte alignment */
++
++/*
++ * void grub_linux_boot_zimage (void)
++ */
++VARIABLE(grub_linux_prot_size)
++ .long 0
++VARIABLE(grub_linux_tmp_addr)
++ .long 0
++VARIABLE(grub_linux_real_addr)
++ .long 0
++VARIABLE(grub_linux_is_bzimage)
++ .long 0
++
++FUNCTION(grub_linux16_boot)
++ /* Must be done before zImage copy. */
++ call EXT_C(grub_dl_unload_all)
++
++ movl EXT_C(grub_linux_is_bzimage), %ebx
++ test %ebx, %ebx
++ jne bzimage
++
++ /* copy the kernel */
++ movl EXT_C(grub_linux_prot_size), %ecx
++ addl $3, %ecx
++ shrl $2, %ecx
++ movl $GRUB_LINUX_BZIMAGE_ADDR, %esi
++ movl $GRUB_LINUX_ZIMAGE_ADDR, %edi
++ cld
++ rep
++ movsl
++
++bzimage:
++ movl EXT_C(grub_linux_real_addr), %ebx
++
++ /* copy the real mode code */
++ movl EXT_C(grub_linux_tmp_addr), %esi
++ movl %ebx, %edi
++ movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx
++ cld
++ rep
++ movsb
++
++ /* change %ebx to the segment address */
++ shrl $4, %ebx
++ movl %ebx, %eax
++ addl $0x20, %eax
++ movw %ax, linux_setup_seg
++
++ /* XXX new stack pointer in safe area for calling functions */
++ movl $0x4000, %esp
++ call EXT_C(grub_stop_floppy)
++
++ /* final setup for linux boot */
++ call prot_to_real
++ .code16
++
++ cli
++ movw %bx, %ss
++ movw $GRUB_LINUX_SETUP_STACK, %sp
++
++ movw %bx, %ds
++ movw %bx, %es
++ movw %bx, %fs
++ movw %bx, %gs
++
++ /* ljmp */
++ .byte 0xea
++ .word 0
++linux_setup_seg:
++ .word 0
++ .code32
++
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 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/symbol.h>
++
++ .text
++/*
++ * This call is special... it never returns... in fact it should simply
++ * hang at this point!
++ */
++FUNCTION(grub_stop)
++ cli
++1: hlt
++ jmp 1b
--- /dev/null
--- /dev/null
++/* reader.c - reader support */
++/*
++ * 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/types.h>
++#include <grub/mm.h>
++#include <grub/reader.h>
++#include <grub/parser.h>
++
++struct grub_handler_class grub_reader_class =
++ {
++ .name = "reader"
++ };
++
++grub_err_t
++grub_reader_loop (grub_reader_getline_t getline)
++{
++ while (1)
++ {
++ char *line;
++ grub_reader_getline_t func;
++
++ /* Print an error, if any. */
++ grub_print_error ();
++ grub_errno = GRUB_ERR_NONE;
++
++ func = (getline) ? : grub_reader_get_current ()->read_line;
++ if ((func (&line, 0)) || (! line))
++ return grub_errno;
++
++ grub_parser_get_current ()->parse_line (line, func);
++ grub_free (line);
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008, 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/symbol.h>
++
++ .p2align 2
++
++
++ .code32
++
++/*
++ * Use cdecl calling convention for *BSD kernels.
++ */
++
++FUNCTION(grub_unix_real_boot)
++
++ /* Interrupts should be disabled. */
++ cli
++
++ /* Discard `grub_unix_real_boot' return address. */
++ popl %eax
++
++ /* Fetch `entry' address ... */
++ popl %eax
++
++ /*
++ * ... and put our return address in its place. The kernel will
++ * ignore it, but it expects %esp to point to it.
++ */
++ call *%eax
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
++ * 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/>.
++ */
++
++/* Based on the code from FreeBSD originally distributed under the
++ following terms: */
++
++/*-
++ * Copyright (c) 2003 Peter Wemm <peter@FreeBSD.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ *
++ * $FreeBSD$
++ */
++
++
++#define MSR_EFER 0xc0000080
++#define EFER_LME 0x00000100
++#define CR4_PAE 0x00000020
++#define CR4_PSE 0x00000010
++#define CR0_PG 0x80000000
++
++#include <grub/symbol.h>
++
++ .p2align 2
++
++ .code32
++
++
++VARIABLE(grub_bsd64_trampoline_start)
++
++ /* Discard `grub_unix_real_boot' return address. */
++ popl %eax
++
++ /* entry */
++ popl %edi
++
++ /* entry_hi */
++ popl %esi
++
++ cli
++
++ /* Turn on EFER.LME. */
++ movl $MSR_EFER, %ecx
++ rdmsr
++ orl $EFER_LME, %eax
++ wrmsr
++
++ /* Turn on PAE. */
++ movl %cr4, %eax
++ orl $(CR4_PAE | CR4_PSE), %eax
++ movl %eax, %cr4
++
++ /* Set %cr3 for PT4. */
++ popl %eax
++ movl %eax, %cr3
++
++ /* Push a dummy return address. */
++ pushl %eax
++
++ /* Turn on paging (implicitly sets EFER.LMA). */
++ movl %cr0, %eax
++ orl $CR0_PG, %eax
++ movl %eax, %cr0
++
++ /* Now we're in compatibility mode. set %cs for long mode. */
++ /* lgdt */
++ .byte 0x0f
++ .byte 0x01
++ .byte 0x15
++VARIABLE (grub_bsd64_trampoline_gdt)
++ .long 0x0
++
++ /* ljmp */
++ .byte 0xea
++VARIABLE (grub_bsd64_trampoline_selfjump)
++ .long 0x0
++ .word 0x08
++
++ .code64
++
++bsd64_longmode:
++ /* We're still running V=P, jump to entry point. */
++ movl %esi, %eax
++ salq $32, %rax
++ orq %rdi, %rax
++ pushq %rax
++ ret
++VARIABLE(grub_bsd64_trampoline_end)
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2006,2007,2008,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/loader.h>
++#include <grub/machine/loader.h>
++#include <grub/file.h>
++#include <grub/disk.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/cpu/linux.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/uga_draw.h>
++#include <grub/pci.h>
++#include <grub/command.h>
++#include <grub/memory.h>
++
++#define GRUB_LINUX_CL_OFFSET 0x1000
++#define GRUB_LINUX_CL_END_OFFSET 0x2000
++
++#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
++
++static grub_dl_t my_mod;
++
++static grub_size_t linux_mem_size;
++static int loaded;
++static void *real_mode_mem;
++static void *prot_mode_mem;
++static void *initrd_mem;
++static grub_efi_uintn_t real_mode_pages;
++static grub_efi_uintn_t prot_mode_pages;
++static grub_efi_uintn_t initrd_pages;
++static void *mmap_buf;
++
++static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
++ {
++ /* NULL. */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ /* Reserved. */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ /* Code segment. */
++ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
++ /* Data segment. */
++ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
++ };
++
++struct gdt_descriptor
++{
++ grub_uint16_t limit;
++ void *base;
++} __attribute__ ((packed));
++
++static struct gdt_descriptor gdt_desc =
++ {
++ sizeof (gdt) - 1,
++ gdt
++ };
++
++struct idt_descriptor
++{
++ grub_uint16_t limit;
++ void *base;
++} __attribute__ ((packed));
++
++static struct idt_descriptor idt_desc =
++ {
++ 0,
++ 0
++ };
++
++static inline grub_size_t
++page_align (grub_size_t size)
++{
++ return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
++}
++
++/* Find the optimal number of pages for the memory map. Is it better to
++ move this code to efi/mm.c? */
++static grub_efi_uintn_t
++find_mmap_size (void)
++{
++ static grub_efi_uintn_t mmap_size = 0;
++
++ if (mmap_size != 0)
++ return mmap_size;
++
++ mmap_size = (1 << 12);
++ while (1)
++ {
++ int ret;
++ grub_efi_memory_descriptor_t *mmap;
++ grub_efi_uintn_t desc_size;
++
++ mmap = grub_malloc (mmap_size);
++ if (! mmap)
++ return 0;
++
++ ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
++ grub_free (mmap);
++
++ if (ret < 0)
++ grub_fatal ("cannot get memory map");
++ else if (ret > 0)
++ break;
++
++ mmap_size += (1 << 12);
++ }
++
++ /* Increase the size a bit for safety, because GRUB allocates more on
++ later, and EFI itself may allocate more. */
++ mmap_size += (1 << 12);
++
++ return page_align (mmap_size);
++}
++
++static void
++free_pages (void)
++{
++ if (real_mode_mem)
++ {
++ grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages);
++ real_mode_mem = 0;
++ }
++
++ if (prot_mode_mem)
++ {
++ grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);
++ prot_mode_mem = 0;
++ }
++
++ if (initrd_mem)
++ {
++ grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
++ initrd_mem = 0;
++ }
++}
++
++/* Allocate pages for the real mode code and the protected mode code
++ for linux as well as a memory map buffer. */
++static int
++allocate_pages (grub_size_t prot_size)
++{
++ grub_efi_uintn_t desc_size;
++ grub_efi_memory_descriptor_t *mmap, *mmap_end;
++ grub_efi_uintn_t mmap_size, tmp_mmap_size;
++ grub_efi_memory_descriptor_t *desc;
++ grub_size_t real_size;
++
++ /* Make sure that each size is aligned to a page boundary. */
++ real_size = GRUB_LINUX_CL_END_OFFSET;
++ prot_size = page_align (prot_size);
++ mmap_size = find_mmap_size ();
++
++ grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
++ (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
++
++ /* Calculate the number of pages; Combine the real mode code with
++ the memory map buffer for simplicity. */
++ real_mode_pages = ((real_size + mmap_size) >> 12);
++ prot_mode_pages = (prot_size >> 12);
++
++ /* Initialize the memory pointers with NULL for convenience. */
++ real_mode_mem = 0;
++ prot_mode_mem = 0;
++
++ /* Read the memory map temporarily, to find free space. */
++ mmap = grub_malloc (mmap_size);
++ if (! mmap)
++ return 0;
++
++ tmp_mmap_size = mmap_size;
++ if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
++ grub_fatal ("cannot get memory map");
++
++ mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
++
++ /* First, find free pages for the real mode code
++ and the memory map buffer. */
++ for (desc = mmap;
++ desc < mmap_end;
++ desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++ {
++ /* Probably it is better to put the real mode code in the traditional
++ space for safety. */
++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
++ && desc->physical_start <= 0x90000
++ && desc->num_pages >= real_mode_pages)
++ {
++ grub_efi_physical_address_t physical_end;
++ grub_efi_physical_address_t addr;
++
++ physical_end = desc->physical_start + (desc->num_pages << 12);
++ if (physical_end > 0x90000)
++ physical_end = 0x90000;
++
++ grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
++ (unsigned) desc->physical_start,
++ (unsigned) physical_end);
++ addr = physical_end - real_size - mmap_size;
++ if (addr < 0x10000)
++ continue;
++
++ grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
++ (unsigned) real_mode_pages, (unsigned long) addr);
++ real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
++ if (! real_mode_mem)
++ grub_fatal ("cannot allocate pages");
++
++ desc->num_pages -= real_mode_pages;
++ break;
++ }
++ }
++
++ if (! real_mode_mem)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
++ goto fail;
++ }
++
++ mmap_buf = (void *) ((char *) real_mode_mem + real_size);
++
++ /* Next, find free pages for the protected mode code. */
++ /* XXX what happens if anything is using this address? */
++ prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1);
++ if (! prot_mode_mem)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY,
++ "cannot allocate protected mode pages");
++ goto fail;
++ }
++
++ grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
++ "prot_mode_mem = %lx, prot_mode_pages = %x\n",
++ (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
++ (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
++
++ grub_free (mmap);
++ return 1;
++
++ fail:
++ grub_free (mmap);
++ free_pages ();
++ return 0;
++}
++
++static void
++grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
++ grub_uint64_t start, grub_uint64_t size,
++ grub_uint32_t type)
++{
++ int n = *e820_num;
++
++ if (n >= GRUB_E820_MAX_ENTRY)
++ grub_fatal ("Too many e820 memory map entries");
++
++ if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
++ (e820_map[n - 1].type == type))
++ e820_map[n - 1].size += size;
++ else
++ {
++ e820_map[n].addr = start;
++ e820_map[n].size = size;
++ e820_map[n].type = type;
++ (*e820_num)++;
++ }
++}
++
++#ifdef __x86_64__
++extern grub_uint8_t grub_linux_trampoline_start[];
++extern grub_uint8_t grub_linux_trampoline_end[];
++#endif
++
++static grub_err_t
++grub_linux_boot (void)
++{
++ struct linux_kernel_params *params;
++ grub_efi_uintn_t mmap_size;
++ grub_efi_uintn_t map_key;
++ grub_efi_uintn_t desc_size;
++ grub_efi_uint32_t desc_version;
++ int e820_num;
++
++ params = real_mode_mem;
++
++ grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n",
++ (unsigned) params->code32_start,
++ (unsigned long) &(idt_desc.limit),
++ (unsigned long) &(gdt_desc.limit));
++ grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n",
++ (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
++ (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
++
++ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
++ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
++ {
++ switch (type)
++ {
++ case GRUB_MACHINE_MEMORY_AVAILABLE:
++ grub_e820_add_region (params->e820_map, &e820_num,
++ addr, size, GRUB_E820_RAM);
++ break;
++
++#ifdef GRUB_MACHINE_MEMORY_ACPI
++ case GRUB_MACHINE_MEMORY_ACPI:
++ grub_e820_add_region (params->e820_map, &e820_num,
++ addr, size, GRUB_E820_ACPI);
++ break;
++#endif
++
++#ifdef GRUB_MACHINE_MEMORY_NVS
++ case GRUB_MACHINE_MEMORY_NVS:
++ grub_e820_add_region (params->e820_map, &e820_num,
++ addr, size, GRUB_E820_NVS);
++ break;
++#endif
++
++#ifdef GRUB_MACHINE_MEMORY_CODE
++ case GRUB_MACHINE_MEMORY_CODE:
++ grub_e820_add_region (params->e820_map, &e820_num,
++ addr, size, GRUB_E820_EXEC_CODE);
++ break;
++#endif
++
++ default:
++ grub_e820_add_region (params->e820_map, &e820_num,
++ addr, size, GRUB_E820_RESERVED);
++ }
++ return 0;
++ }
++
++ e820_num = 0;
++ grub_mmap_iterate (hook);
++ params->mmap_size = e820_num;
++
++ mmap_size = find_mmap_size ();
++ if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
++ &desc_size, &desc_version) <= 0)
++ grub_fatal ("cannot get memory map");
++
++ if (! grub_efi_exit_boot_services (map_key))
++ grub_fatal ("cannot exit boot services");
++
++ /* Note that no boot services are available from here. */
++
++ /* Pass EFI parameters. */
++ if (grub_le_to_cpu16 (params->version) >= 0x0206)
++ {
++ params->v0206.efi_mem_desc_size = desc_size;
++ params->v0206.efi_mem_desc_version = desc_version;
++ params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
++ params->v0206.efi_mmap_size = mmap_size;
++#ifdef __x86_64__
++ params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
++#endif
++ }
++ else if (grub_le_to_cpu16 (params->version) >= 0x0204)
++ {
++ params->v0204.efi_mem_desc_size = desc_size;
++ params->v0204.efi_mem_desc_version = desc_version;
++ params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
++ params->v0204.efi_mmap_size = mmap_size;
++ }
++
++#ifdef __x86_64__
++
++ grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12),
++ grub_linux_trampoline_start,
++ grub_linux_trampoline_end - grub_linux_trampoline_start);
++
++ ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem
++ + (prot_mode_pages << 12)))
++ (params->code32_start, real_mode_mem);
++
++#else
++
++ /* Hardware interrupts are not safe any longer. */
++ asm volatile ("cli" : : );
++
++ /* Load the IDT and the GDT for the bootstrap. */
++ asm volatile ("lidt %0" : : "m" (idt_desc));
++ asm volatile ("lgdt %0" : : "m" (gdt_desc));
++
++ /* Pass parameters. */
++ asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start));
++ asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
++
++ asm volatile ("xorl %%ebx, %%ebx" : : );
++
++ /* Enter Linux. */
++ asm volatile ("jmp *%%ecx" : : );
++
++#endif
++
++ /* Never reach here. */
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_linux_unload (void)
++{
++ free_pages ();
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ return GRUB_ERR_NONE;
++}
++
++static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
++
++
++#define RGB_MASK 0xffffff
++#define RGB_MAGIC 0x121314
++#define LINE_MIN 800
++#define LINE_MAX 4096
++#define FBTEST_STEP (0x10000 >> 2)
++#define FBTEST_COUNT 8
++
++static int
++find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
++ int i;
++
++ for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
++ {
++ if ((*base & RGB_MASK) == RGB_MAGIC)
++ {
++ int j;
++
++ for (j = LINE_MIN; j <= LINE_MAX; j++)
++ {
++ if ((base[j] & RGB_MASK) == RGB_MAGIC)
++ {
++ *fb_base = (grub_uint32_t) (grub_target_addr_t) base;
++ *line_len = j << 2;
++
++ return 1;
++ }
++ }
++
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static int
++find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ int found = 0;
++
++ auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
++ grub_pci_id_t pciid);
++
++ int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
++ grub_pci_id_t pciid)
++ {
++ grub_pci_address_t addr;
++
++ addr = grub_pci_make_address (dev, 2);
++ if (grub_pci_read (addr) >> 24 == 0x3)
++ {
++ int i;
++
++ grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
++ grub_pci_get_bus (dev), grub_pci_get_device (dev),
++ grub_pci_get_function (dev), pciid);
++ addr += 8;
++ for (i = 0; i < 6; i++, addr += 4)
++ {
++ grub_uint32_t old_bar1, old_bar2, type;
++ grub_uint64_t base64;
++
++ old_bar1 = grub_pci_read (addr);
++ if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
++ continue;
++
++ type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ if (i == 5)
++ break;
++
++ old_bar2 = grub_pci_read (addr + 4);
++ }
++ else
++ old_bar2 = 0;
++
++ base64 = old_bar2;
++ base64 <<= 32;
++ base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
++
++ grub_printf ("%s(%d): 0x%llx\n",
++ ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
++ "VMEM" : "MMIO"), i,
++ (unsigned long long) base64);
++
++ if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
++ {
++ *fb_base = base64;
++ if (find_line_len (fb_base, line_len))
++ found++;
++ }
++
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ i++;
++ addr += 4;
++ }
++ }
++ }
++
++ return found;
++ }
++
++ grub_pci_iterate (find_card);
++ return found;
++}
++
++static int
++grub_linux_setup_video (struct linux_kernel_params *params)
++{
++ grub_efi_uga_draw_protocol_t *c;
++ grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
++ int ret;
++
++ c = grub_efi_locate_protocol (&uga_draw_guid, 0);
++ if (! c)
++ return 1;
++
++ if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
++ return 1;
++
++ grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
++
++ grub_efi_set_text_mode (0);
++ pixel = RGB_MAGIC;
++ efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
++ GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
++ ret = find_framebuf (&fb_base, &line_len);
++ grub_efi_set_text_mode (1);
++
++ if (! ret)
++ {
++ grub_printf ("Can\'t find frame buffer address\n");
++ return 1;
++ }
++
++ grub_printf ("Frame buffer base: 0x%x\n", fb_base);
++ grub_printf ("Video line length: %d\n", line_len);
++
++ params->lfb_width = width;
++ params->lfb_height = height;
++ params->lfb_depth = depth;
++ params->lfb_line_len = line_len;
++
++ params->lfb_base = fb_base;
++ params->lfb_size = (line_len * params->lfb_height + 65535) >> 16;
++
++ params->red_mask_size = 8;
++ params->red_field_pos = 16;
++ params->green_mask_size = 8;
++ params->green_field_pos = 8;
++ params->blue_mask_size = 8;
++ params->blue_field_pos = 0;
++ params->reserved_mask_size = 8;
++ params->reserved_field_pos = 24;
++
++ params->have_vga = GRUB_VIDEO_TYPE_VLFB;
++ params->vid_mode = 0x338; /* 1024x768x32 */
++
++ return 0;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ struct linux_kernel_header lh;
++ struct linux_kernel_params *params;
++ grub_uint8_t setup_sects;
++ grub_size_t real_size, prot_size;
++ grub_ssize_t len;
++ int i;
++ char *dest;
++
++ grub_dl_ref (my_mod);
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++ goto fail;
++ }
++
++ file = grub_file_open (argv[0]);
++ if (! file)
++ goto fail;
++
++ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++ {
++ grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header");
++ goto fail;
++ }
++
++ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
++ {
++ grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
++ goto fail;
++ }
++
++ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
++ {
++ grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
++ goto fail;
++ }
++
++ /* EFI support is quite new, so reject old versions. */
++ if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
++ || grub_le_to_cpu16 (lh.version) < 0x0203)
++ {
++ grub_error (GRUB_ERR_BAD_OS, "too old version");
++ goto fail;
++ }
++
++ /* I'm not sure how to support zImage on EFI. */
++ if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
++ {
++ grub_error (GRUB_ERR_BAD_OS, "zImage is not supported");
++ goto fail;
++ }
++
++ setup_sects = lh.setup_sects;
++
++ /* If SETUP_SECTS is not set, set it to the default (4). */
++ if (! setup_sects)
++ setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
++
++ real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
++ prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
++
++ if (! allocate_pages (prot_size))
++ goto fail;
++
++ params = (struct linux_kernel_params *) real_mode_mem;
++ grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET);
++ grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
++
++ params->ps_mouse = params->padding10 = 0;
++
++ len = 0x400 - sizeof (lh);
++ if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++ goto fail;
++ }
++
++ /* XXX Linux assumes that only elilo can boot Linux on EFI!!! */
++ params->type_of_loader = (LINUX_LOADER_ID_ELILO << 4);
++
++ params->cl_magic = GRUB_LINUX_CL_MAGIC;
++ params->cl_offset = 0x1000;
++ params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000;
++ params->ramdisk_image = 0;
++ params->ramdisk_size = 0;
++
++ params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
++ params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
++
++ /* These are not needed to be precise, because Linux uses these values
++ only to raise an error when the decompression code cannot find good
++ space. */
++ params->ext_mem = ((32 * 0x100000) >> 10);
++ params->alt_mem = ((32 * 0x100000) >> 10);
++
++ params->video_cursor_x = grub_getxy () >> 8;
++ params->video_cursor_y = grub_getxy () & 0xff;
++ params->video_page = 0; /* ??? */
++ params->video_mode = grub_efi_system_table->con_out->mode->mode;
++ params->video_width = (grub_getwh () >> 8);
++ params->video_ega_bx = 0;
++ params->video_height = (grub_getwh () & 0xff);
++ params->have_vga = 0;
++ params->font_size = 16; /* XXX */
++
++ if (grub_le_to_cpu16 (params->version) >= 0x0206)
++ {
++ params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
++ params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
++#ifdef __x86_64__
++ params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
++#endif
++ }
++ else if (grub_le_to_cpu16 (params->version) >= 0x0204)
++ {
++ params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
++ params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
++ }
++
++#if 0
++ /* The structure is zeroed already. */
++
++ /* No VBE on EFI. */
++ params->lfb_width = 0;
++ params->lfb_height = 0;
++ params->lfb_depth = 0;
++ params->lfb_base = 0;
++ params->lfb_size = 0;
++ params->lfb_line_len = 0;
++ params->red_mask_size = 0;
++ params->red_field_pos = 0;
++ params->green_mask_size = 0;
++ params->green_field_pos = 0;
++ params->blue_mask_size = 0;
++ params->blue_field_pos = 0;
++ params->reserved_mask_size = 0;
++ params->reserved_field_pos = 0;
++ params->vesapm_segment = 0;
++ params->vesapm_offset = 0;
++ params->lfb_pages = 0;
++ params->vesa_attrib = 0;
++
++ /* No APM on EFI. */
++ params->apm_version = 0;
++ params->apm_code_segment = 0;
++ params->apm_entry = 0;
++ params->apm_16bit_code_segment = 0;
++ params->apm_data_segment = 0;
++ params->apm_flags = 0;
++ params->apm_code_len = 0;
++ params->apm_data_len = 0;
++
++ /* XXX is there any way to use SpeedStep on EFI? */
++ params->ist_signature = 0;
++ params->ist_command = 0;
++ params->ist_event = 0;
++ params->ist_perf_level = 0;
++
++ /* Let the kernel probe the information. */
++ grub_memset (params->hd0_drive_info, 0, sizeof (params->hd0_drive_info));
++ grub_memset (params->hd1_drive_info, 0, sizeof (params->hd1_drive_info));
++
++ /* No MCA on EFI. */
++ params->rom_config_len = 0;
++
++ /* No need to fake the BIOS's memory map. */
++ params->mmap_size = 0;
++
++ /* Let the kernel probe the information. */
++ params->ps_mouse = 0;
++
++ /* Clear padding for future compatibility. */
++ grub_memset (params->padding1, 0, sizeof (params->padding1));
++ grub_memset (params->padding2, 0, sizeof (params->padding2));
++ grub_memset (params->padding3, 0, sizeof (params->padding3));
++ grub_memset (params->padding4, 0, sizeof (params->padding4));
++ grub_memset (params->padding5, 0, sizeof (params->padding5));
++ grub_memset (params->padding6, 0, sizeof (params->padding6));
++ grub_memset (params->padding7, 0, sizeof (params->padding7));
++ grub_memset (params->padding8, 0, sizeof (params->padding8));
++ grub_memset (params->padding9, 0, sizeof (params->padding9));
++
++#endif
++
++ /* The other EFI parameters are filled when booting. */
++
++ grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
++
++ /* XXX there is no way to know if the kernel really supports EFI. */
++ grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
++ (unsigned) real_size, (unsigned) prot_size);
++
++ grub_linux_setup_video (params);
++
++ /* Detect explicitly specified memory size, if any. */
++ linux_mem_size = 0;
++ for (i = 1; i < argc; i++)
++ if (grub_memcmp (argv[i], "mem=", 4) == 0)
++ {
++ char *val = argv[i] + 4;
++
++ linux_mem_size = grub_strtoul (val, &val, 0);
++
++ if (grub_errno)
++ {
++ grub_errno = GRUB_ERR_NONE;
++ linux_mem_size = 0;
++ }
++ else
++ {
++ int shift = 0;
++
++ switch (grub_tolower (val[0]))
++ {
++ case 'g':
++ shift += 10;
++ case 'm':
++ shift += 10;
++ case 'k':
++ shift += 10;
++ default:
++ break;
++ }
++
++ /* Check an overflow. */
++ if (linux_mem_size > (~0UL >> shift))
++ linux_mem_size = 0;
++ else
++ linux_mem_size <<= shift;
++ }
++ }
++ else if (grub_memcmp (argv[i], "video=efifb", 11) == 0)
++ {
++ if (params->have_vga)
++ params->have_vga = GRUB_VIDEO_TYPE_EFI;
++ }
++
++ /* Specify the boot file. */
++ dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
++ "BOOT_IMAGE=");
++ dest = grub_stpcpy (dest, argv[0]);
++
++ /* Copy kernel parameters. */
++ for (i = 1;
++ i < argc
++ && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem
++ + GRUB_LINUX_CL_END_OFFSET);
++ i++)
++ {
++ *dest++ = ' ';
++ dest = grub_stpcpy (dest, argv[i]);
++ }
++
++ len = prot_size;
++ if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++
++ if (grub_errno == GRUB_ERR_NONE)
++ {
++ grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
++ loaded = 1;
++ }
++
++ fail:
++
++ if (file)
++ grub_file_close (file);
++
++ if (grub_errno != GRUB_ERR_NONE)
++ {
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ }
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ grub_ssize_t size;
++ grub_addr_t addr_min, addr_max;
++ grub_addr_t addr;
++ grub_efi_uintn_t mmap_size;
++ grub_efi_memory_descriptor_t *desc;
++ grub_efi_uintn_t desc_size;
++ struct linux_kernel_header *lh;
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
++ goto fail;
++ }
++
++ if (! loaded)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
++ goto fail;
++ }
++
++ file = grub_file_open (argv[0]);
++ if (! file)
++ goto fail;
++
++ size = grub_file_size (file);
++ initrd_pages = (page_align (size) >> 12);
++
++ lh = (struct linux_kernel_header *) real_mode_mem;
++
++ addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
++ if (linux_mem_size != 0 && linux_mem_size < addr_max)
++ addr_max = linux_mem_size;
++
++ /* Linux 2.3.xx has a bug in the memory range check, so avoid
++ the last page.
++ Linux 2.2.xx has a bug in the memory range check, which is
++ worse than that of Linux 2.3.xx, so avoid the last 64kb. */
++ addr_max -= 0x10000;
++
++ /* Usually, the compression ratio is about 50%. */
++ addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
++ + page_align (size);
++
++ /* Find the highest address to put the initrd. */
++ mmap_size = find_mmap_size ();
++ if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
++ grub_fatal ("cannot get memory map");
++
++ addr = 0;
++ for (desc = mmap_buf;
++ desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
++ desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++ {
++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
++ && desc->num_pages >= initrd_pages)
++ {
++ grub_efi_physical_address_t physical_end;
++
++ physical_end = desc->physical_start + (desc->num_pages << 12);
++ if (physical_end > addr_max)
++ physical_end = addr_max;
++
++ if (physical_end < page_align (size))
++ continue;
++
++ physical_end -= page_align (size);
++
++ if ((physical_end >= addr_min) &&
++ (physical_end >= desc->physical_start) &&
++ (physical_end > addr))
++ addr = physical_end;
++ }
++ }
++
++ if (addr == 0)
++ {
++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
++ goto fail;
++ }
++
++ initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
++ if (! initrd_mem)
++ grub_fatal ("cannot allocate pages");
++
++ if (grub_file_read (file, initrd_mem, size) != size)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++ goto fail;
++ }
++
++ grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n",
++ (unsigned) addr, (unsigned) size);
++
++ lh->ramdisk_image = addr;
++ lh->ramdisk_size = size;
++ lh->root_dev = 0x0100; /* XXX */
++
++ fail:
++ if (file)
++ grub_file_close (file);
++
++ return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linux)
++{
++ cmd_linux = grub_register_command ("linux", grub_cmd_linux,
++ 0, "Load Linux.");
++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
++ 0, "Load initrd.");
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI(linux)
++{
++ grub_unregister_command (cmd_linux);
++ grub_unregister_command (cmd_initrd);
++}
--- /dev/null
--- /dev/null
++/*
++ * 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/env.h>
++#include <grub/xnu.h>
++#include <grub/cpu/xnu.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/uga_draw.h>
++#include <grub/pci.h>
++#include <grub/misc.h>
++
++/* Setup video for xnu. Big parts are copied from linux.c. */
++
++static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
++
++#define RGB_MASK 0xffffff
++#define RGB_MAGIC 0x121314
++#define LINE_MIN 800
++#define LINE_MAX 4096
++#define FBTEST_STEP (0x10000 >> 2)
++#define FBTEST_COUNT 8
++
++static int
++find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
++ int i;
++
++ for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
++ {
++ if ((*base & RGB_MASK) == RGB_MAGIC)
++ {
++ int j;
++
++ for (j = LINE_MIN; j <= LINE_MAX; j++)
++ {
++ if ((base[j] & RGB_MASK) == RGB_MAGIC)
++ {
++ *fb_base = (grub_uint32_t) (grub_target_addr_t) base;
++ *line_len = j << 2;
++
++ return 1;
++ }
++ }
++
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static int
++find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ int found = 0;
++
++ auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
++ grub_pci_id_t pciid);
++
++ int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev,
++ grub_pci_id_t pciid)
++ {
++ grub_pci_address_t addr;
++
++ addr = grub_pci_make_address (dev, 2);
++ if (grub_pci_read (addr) >> 24 == 0x3)
++ {
++ int i;
++
++ grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
++ grub_pci_get_bus (dev), grub_pci_get_device (dev),
++ grub_pci_get_function (dev), pciid);
++ addr += 8;
++ for (i = 0; i < 6; i++, addr += 4)
++ {
++ grub_uint32_t old_bar1, old_bar2, type;
++ grub_uint64_t base64;
++
++ old_bar1 = grub_pci_read (addr);
++ if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
++ continue;
++
++ type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ if (i == 5)
++ break;
++
++ old_bar2 = grub_pci_read (addr + 4);
++ }
++ else
++ old_bar2 = 0;
++
++ base64 = old_bar2;
++ base64 <<= 32;
++ base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
++
++ grub_printf ("%s(%d): 0x%llx\n",
++ ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
++ "VMEM" : "MMIO"), i,
++ (unsigned long long) base64);
++
++ if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
++ {
++ *fb_base = base64;
++ if (find_line_len (fb_base, line_len))
++ found++;
++ }
++
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ i++;
++ addr += 4;
++ }
++ }
++ }
++
++ return found;
++ }
++
++ grub_pci_iterate (find_card);
++ return found;
++}
++
++grub_err_t
++grub_xnu_set_video (struct grub_xnu_boot_params *params)
++{
++ grub_efi_uga_draw_protocol_t *c;
++ grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
++ int ret;
++
++ c = grub_efi_locate_protocol (&uga_draw_guid, 0);
++ if (! c)
++ return grub_error (GRUB_ERR_IO, "couldn't find UGADraw");
++
++ if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
++ return grub_error (GRUB_ERR_IO, "couldn't retrieve video mode");
++
++ grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
++
++ grub_efi_set_text_mode (0);
++ pixel = RGB_MAGIC;
++ efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
++ GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
++ ret = find_framebuf (&fb_base, &line_len);
++ grub_efi_set_text_mode (1);
++
++ if (! ret)
++ return grub_error (GRUB_ERR_IO, "can\'t find frame buffer address");
++
++ grub_printf ("Frame buffer base: 0x%x\n", fb_base);
++ grub_printf ("Video line length: %d\n", line_len);
++
++ params->lfb_width = width;
++ params->lfb_height = height;
++ params->lfb_depth = depth;
++ params->lfb_line_len = line_len;
++ params->lfb_mode = GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
++ params->lfb_base = fb_base;
++ return GRUB_ERR_NONE;
++}
--- /dev/null
--- /dev/null
++/* linux.c - boot Linux zImage or bzImage */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 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/loader.h>
++#include <grub/machine/loader.h>
++#include <grub/machine/memory.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/disk.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/dl.h>
++#include <grub/env.h>
++#include <grub/term.h>
++#include <grub/cpu/linux.h>
++#include <grub/ieee1275/ieee1275.h>
++#include <grub/command.h>
++
++#define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000
++#define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000
++#define GRUB_OFW_LINUX_INITRD_ADDR 0x800000
++
++#define GRUB_OFW_LINUX_CL_OFFSET 0x1e00
++#define GRUB_OFW_LINUX_CL_LENGTH 0x100
++
++static grub_dl_t my_mod;
++
++static grub_size_t kernel_size;
++static char *kernel_addr, *kernel_cmdline;
++static grub_size_t initrd_size;
++
++static grub_err_t
++grub_linux_unload (void)
++{
++ grub_free (kernel_cmdline);
++ grub_free (kernel_addr);
++ kernel_cmdline = 0;
++ kernel_addr = 0;
++ initrd_size = 0;
++
++ grub_dl_unref (my_mod);
++
++ return GRUB_ERR_NONE;
++}
++
++/*
++static int
++grub_ieee1275_debug (void)
++{
++ struct enter_args
++ {
++ struct grub_ieee1275_common_hdr common;
++ }
++ args;
++
++ INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0);
++
++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
++ return -1;
++
++ return 0;
++}
++*/
++
++static grub_err_t
++grub_linux_boot (void)
++{
++ struct linux_kernel_params *params;
++ struct linux_kernel_header *lh;
++ char *prot_code;
++ char *bootpath;
++ grub_ssize_t len;
++
++ bootpath = grub_env_get ("root");
++ if (bootpath)
++ grub_ieee1275_set_property (grub_ieee1275_chosen,
++ "bootpath", bootpath,
++ grub_strlen (bootpath) + 1,
++ &len);
++
++ params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR;
++ lh = (struct linux_kernel_header *) params;
++
++ grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
++
++ params->alt_mem = grub_mmap_get_upper () >> 10;
++ params->ext_mem = params->alt_mem;
++
++ lh->cmd_line_ptr = (char *)
++ (GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET);
++
++ params->cl_magic = GRUB_LINUX_CL_MAGIC;
++ params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET;
++
++ params->video_width = (grub_getwh () >> 8);
++ params->video_height = (grub_getwh () & 0xff);
++ params->font_size = 16;
++
++ params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
++ params->ofw_num_items = 1;
++ params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
++ params->ofw_idt = 0;
++
++ if (initrd_size)
++ {
++ lh->type_of_loader = 1;
++ lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR;
++ lh->ramdisk_size = initrd_size;
++ }
++
++ if (kernel_cmdline)
++ grub_strcpy (lh->cmd_line_ptr, kernel_cmdline);
++
++ prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR;
++ grub_memcpy (prot_code, kernel_addr, kernel_size);
++
++ asm volatile ("movl %0, %%esi" : : "m" (params));
++ asm volatile ("movl %%esi, %%esp" : : );
++ asm volatile ("movl %0, %%ecx" : : "m" (prot_code));
++ asm volatile ("xorl %%ebx, %%ebx" : : );
++ asm volatile ("jmp *%%ecx" : : );
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ struct linux_kernel_header lh;
++ grub_uint8_t setup_sects;
++ grub_size_t real_size, prot_size;
++ int i;
++ char *dest;
++
++ grub_dl_ref (my_mod);
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++ goto fail;
++ }
++
++ file = grub_file_open (argv[0]);
++ if (! file)
++ goto fail;
++
++ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++ {
++ grub_error (GRUB_ERR_READ_ERROR, "cannot read the linux header");
++ goto fail;
++ }
++
++ if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ||
++ (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)))
++ {
++ grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
++ goto fail;
++ }
++
++ setup_sects = lh.setup_sects;
++ if (! setup_sects)
++ setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
++
++ real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
++ prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
++
++ grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
++ "bzImage", real_size, prot_size);
++
++ grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
++ if (grub_errno)
++ goto fail;
++
++ kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH);
++ if (! kernel_cmdline)
++ goto fail;
++
++ dest = kernel_cmdline;
++ for (i = 1;
++ i < argc
++ && dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline
++ + GRUB_OFW_LINUX_CL_LENGTH);
++ i++)
++ {
++ *dest++ = ' ';
++ dest = grub_stpcpy (dest, argv[i]);
++ }
++
++ kernel_addr = grub_malloc (prot_size);
++ if (! kernel_addr)
++ goto fail;
++
++ kernel_size = prot_size;
++ if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size)
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++
++ if (grub_errno == GRUB_ERR_NONE)
++ grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
++
++fail:
++
++ if (file)
++ grub_file_close (file);
++
++ if (grub_errno != GRUB_ERR_NONE)
++ {
++ grub_free (kernel_cmdline);
++ grub_free (kernel_addr);
++ kernel_cmdline = 0;
++ kernel_addr = 0;
++
++ grub_dl_unref (my_mod);
++ }
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
++ goto fail;
++ }
++
++ if (! kernel_addr)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first");
++ goto fail;
++ }
++
++ file = grub_file_open (argv[0]);
++ if (! file)
++ goto fail;
++
++ initrd_size = grub_file_size (file);
++ if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR,
++ initrd_size) != (int) initrd_size)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++ goto fail;
++ }
++
++fail:
++ if (file)
++ grub_file_close (file);
++
++ return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linux)
++{
++ cmd_linux = grub_register_command ("linux", grub_cmd_linux,
++ 0, "Load Linux.");
++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
++ 0, "Load initrd.");
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI(linux)
++{
++ grub_unregister_command (cmd_linux);
++ grub_unregister_command (cmd_initrd);
++}
--- /dev/null
--- /dev/null
++/*
++ * 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/symbol.h>
++
++
++ .p2align 4 /* force 16-byte alignment */
++VARIABLE(grub_linux_trampoline_start)
++ cli
++ /* %rdi contains protected memory start and %rsi
++ contains real memory start. */
++
++ mov %rsi, %rbx
++
++ call base
++base:
++ pop %rsi
++
++#ifdef APPLE_CC
++ lea (cont1 - base) (%esi, 1), %rax
++ mov %eax, (jump_vector - base) (%esi, 1)
++
++ lea (gdt - base) (%esi, 1), %rax
++ mov %rax, (gdtaddr - base) (%esi, 1)
++
++ /* Switch to compatibility mode. */
++
++ lidt (idtdesc - base) (%esi, 1)
++ lgdt (gdtdesc - base) (%esi, 1)
++
++ /* Update %cs. Thanks to David Miller for pointing this mistake out. */
++ ljmp *(jump_vector - base) (%esi, 1)
++#else
++ lea (cont1 - base) (%rsi, 1), %rax
++ mov %eax, (jump_vector - base) (%rsi, 1)
++
++ lea (gdt - base) (%rsi, 1), %rax
++ mov %rax, (gdtaddr - base) (%rsi, 1)
++
++ /* Switch to compatibility mode. */
++
++ lidt (idtdesc - base) (%rsi, 1)
++ lgdt (gdtdesc - base) (%rsi, 1)
++
++ /* Update %cs. Thanks to David Miller for pointing this mistake out. */
++ ljmp *(jump_vector - base) (%rsi, 1)
++#endif
++
++cont1:
++ .code32
++
++ /* Update other registers. */
++ mov $0x18, %eax
++ mov %eax, %ds
++ mov %eax, %es
++ mov %eax, %fs
++ mov %eax, %gs
++ mov %eax, %ss
++
++ /* Disable paging. */
++ mov %cr0, %eax
++ and $0x7fffffff, %eax
++ mov %eax, %cr0
++
++ /* Disable amd64. */
++ mov $0xc0000080, %ecx
++ rdmsr
++ and $0xfffffeff, %eax
++ wrmsr
++
++ /* Turn off PAE. */
++ movl %cr4, %eax
++ and $0xffffffcf, %eax
++ mov %eax, %cr4
++
++ jmp cont2
++cont2:
++ .code32
++
++ mov %ebx, %esi
++
++ jmp *%edi
++
++ /* GDT. */
++ .p2align 4
++gdt:
++ /* NULL. */
++ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++
++ /* Reserved. */
++ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++
++ /* Code segment. */
++ .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
++
++ /* Data segment. */
++ .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
++
++gdtdesc:
++ .word 31
++gdtaddr:
++ .quad gdt
++
++idtdesc:
++ .word 0
++idtaddr:
++ .quad 0
++
++ .p2align 4
++jump_vector:
++ /* Jump location. Is filled by the code */
++ .long 0
++ .long 0x10
++VARIABLE(grub_linux_trampoline_end)
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,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/symbol.h>
++#include <multiboot.h>
++#include <multiboot2.h>
++
++ .p2align 2 /* force 4-byte alignment */
++
++/*
++ * This starts the multiboot 2 kernel.
++ */
++
++FUNCTION(grub_multiboot2_real_boot)
++ /* Push the entry address on the stack. */
++ pushl %eax
++ /* Move the address of the multiboot information structure to ebx. */
++ movl %edx,%ebx
++
++ /* Interrupts should be disabled. */
++ cli
++
++ /* Move the magic value into eax and jump to the kernel. */
++ movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax
++ popl %ecx
++
++ cld
++ jmp *%ecx
--- /dev/null
--- /dev/null
++/* multiboot2.c - boot a multiboot 2 OS image. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2007,2008 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/multiboot2.h>
++#include <multiboot2.h>
++#include <grub/elf.h>
++#include <grub/err.h>
++#include <grub/machine/loader.h>
++#include <grub/mm.h>
++#include <grub/multiboot.h>
++#include <grub/cpu/multiboot.h>
++
++grub_err_t
++grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr,
++ grub_addr_t *addr __attribute__ ((unused)),
++ int *do_load)
++{
++ Elf32_Addr paddr = phdr->p_paddr;
++
++ if (phdr->p_type != PT_LOAD)
++ {
++ *do_load = 0;
++ return 0;
++ }
++ *do_load = 1;
++
++ if ((paddr < grub_os_area_addr)
++ || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
++ return grub_error(GRUB_ERR_OUT_OF_RANGE,"address 0x%x is out of range",
++ paddr);
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr,
++ grub_addr_t *addr __attribute__ ((unused)),
++ int *do_load)
++{
++ Elf64_Addr paddr = phdr->p_paddr;
++
++ if (phdr->p_type != PT_LOAD)
++ {
++ *do_load = 0;
++ return 0;
++ }
++ *do_load = 1;
++
++ if ((paddr < grub_os_area_addr)
++ || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range",
++ paddr);
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
++{
++ grub_addr_t modaddr;
++
++ modaddr = (grub_addr_t) grub_memalign (MULTIBOOT2_MOD_ALIGN, size);
++ if (! modaddr)
++ return grub_errno;
++
++ *addr = modaddr;
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_arch_module_free (grub_addr_t addr,
++ grub_size_t size __attribute__ ((unused)))
++{
++ grub_free((void *) addr);
++ return GRUB_ERR_NONE;
++}
++
++void
++grub_mb2_arch_boot (grub_addr_t entry, void *tags)
++{
++ grub_multiboot2_real_boot (entry, tags);
++}
++
++void
++grub_mb2_arch_unload (struct multiboot2_tag_header *tags)
++{
++ struct multiboot2_tag_header *tag;
++
++ /* Free all module memory in the tag list. */
++ for_each_tag (tag, tags)
++ {
++ if (tag->key == MULTIBOOT2_TAG_MODULE)
++ {
++ struct multiboot2_tag_module *module =
++ (struct multiboot2_tag_module *) tag;
++ grub_free((void *) module->addr);
++ }
++ }
++}
++
++grub_err_t
++grub_mb2_tags_arch_create (void)
++{
++ /* XXX Create boot device et al. */
++ return GRUB_ERR_NONE;
++}
--- /dev/null
--- /dev/null
++/*
++ * 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/env.h>
++#include <grub/misc.h>
++#include <grub/xnu.h>
++#include <grub/mm.h>
++#include <grub/cpu/xnu.h>
++#include <grub/video_fb.h>
++
++#define min(a,b) (((a) < (b)) ? (a) : (b))
++#define max(a,b) (((a) > (b)) ? (a) : (b))
++
++#define DEFAULT_VIDEO_MODE "1024x768x32,800x600x32,640x480x32"
++
++static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)),
++ struct grub_video_mode_info *info)
++{
++ if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
++ return 0;
++
++ return 1;
++}
++
++/* Setup video for xnu. */
++grub_err_t
++grub_xnu_set_video (struct grub_xnu_boot_params *params)
++{
++ struct grub_video_mode_info mode_info;
++ int ret;
++ char *tmp, *modevar;
++ void *framebuffer;
++ grub_err_t err;
++
++ modevar = grub_env_get ("gfxpayload");
++ if (! modevar || *modevar == 0)
++ err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook);
++ else
++ {
++ tmp = grub_malloc (grub_strlen (modevar)
++ + sizeof (DEFAULT_VIDEO_MODE) + 1);
++ if (! tmp)
++ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++ "couldn't allocate temporary storag");
++ grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar);
++ err = grub_video_set_mode (tmp, video_hook);
++ grub_free (tmp);
++ }
++
++ if (err)
++ return err;
++
++ if (grub_xnu_bitmap)
++ {
++ int x, y;
++
++ x = mode_info.width - grub_xnu_bitmap->mode_info.width;
++ x /= 2;
++ y = mode_info.height - grub_xnu_bitmap->mode_info.height;
++ y /= 2;
++ err = grub_video_blit_bitmap (grub_xnu_bitmap,
++ GRUB_VIDEO_BLIT_REPLACE,
++ x > 0 ? x : 0,
++ y > 0 ? y : 0,
++ x < 0 ? -x : 0,
++ y < 0 ? -y : 0,
++ min (grub_xnu_bitmap->mode_info.width,
++ mode_info.width),
++ min (grub_xnu_bitmap->mode_info.height,
++ mode_info.height));
++ if (err)
++ {
++ grub_print_error ();
++ grub_errno = GRUB_ERR_NONE;
++ grub_xnu_bitmap = 0;
++ }
++ err = GRUB_ERR_NONE;
++ }
++
++ ret = grub_video_get_info_and_fini (&mode_info, &framebuffer);
++ if (ret)
++ return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters");
++
++ params->lfb_width = mode_info.width;
++ params->lfb_height = mode_info.height;
++ params->lfb_depth = mode_info.bpp;
++ params->lfb_line_len = mode_info.pitch;
++
++ params->lfb_base = PTR_TO_UINT32 (framebuffer);
++ params->lfb_mode = grub_xnu_bitmap
++ ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
++
++ return GRUB_ERR_NONE;
++}
++
--- /dev/null
--- /dev/null
++/* multiboot.c - boot a multiboot 2 OS image. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2007 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/loader.h>
++#include <grub/ieee1275/ieee1275.h>
++#include <grub/multiboot2.h>
++#include <multiboot2.h>
++#include <grub/err.h>
++#include <grub/elf.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/machine/kernel.h>
++#include <grub/machine/loader.h>
++#ifdef __i386__
++#include <grub/cpu/multiboot.h>
++#endif
++
++typedef void (*kernel_entry_t) (unsigned long, void *, int (void *),
++ unsigned long, unsigned long);
++
++/* Claim the memory occupied by the multiboot kernel. */
++grub_err_t
++grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr,
++ grub_addr_t *addr __attribute__((unused)),
++ int *do_load)
++{
++ int rc;
++
++ if (phdr->p_type != PT_LOAD)
++ {
++ *do_load = 0;
++ return 0;
++ }
++ *do_load = 1;
++
++ rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
++ if (rc)
++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, "couldn't claim %x - %x",
++ phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
++
++ grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr,
++ phdr->p_paddr + phdr->p_memsz);
++
++ return GRUB_ERR_NONE;
++}
++
++/* Claim the memory occupied by the multiboot kernel. */
++grub_err_t
++grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr,
++ grub_addr_t *addr __attribute__((unused)),
++ int *do_load)
++{
++ int rc;
++
++ if (phdr->p_type != PT_LOAD)
++ {
++ *do_load = 0;
++ return 0;
++ }
++ *do_load = 1;
++
++ rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
++ if (rc)
++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, "couldn't claim 0x%lx - 0x%lx",
++ phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
++
++ grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n",
++ (unsigned long) phdr->p_paddr,
++ (unsigned long) (phdr->p_paddr + phdr->p_memsz));
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
++{
++ int rc;
++
++ /* XXX Will need to map on some firmwares. */
++ rc = grub_ieee1275_claim (0, size, MULTIBOOT2_MOD_ALIGN, addr);
++ if (rc)
++ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++ "firmware couldn't allocate memory (size 0x%lx)", size);
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size)
++{
++ grub_ieee1275_release (addr, size);
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_mb2_tags_arch_create (void)
++{
++ /* Nothing special. */
++ return GRUB_ERR_NONE;
++}
++
++/* Release the memory we claimed from Open Firmware above. */
++void
++grub_mb2_arch_unload (struct multiboot2_tag_header *tags)
++{
++ struct multiboot2_tag_header *tag;
++
++ /* Free all module memory in the tag list. */
++ for_each_tag (tag, tags)
++ {
++ if (tag->key == MULTIBOOT2_TAG_MODULE)
++ {
++ struct multiboot2_tag_module *module =
++ (struct multiboot2_tag_module *) tag;
++ grub_ieee1275_release (module->addr, module->size);
++ }
++ }
++}
++
++void
++grub_mb2_arch_boot (grub_addr_t entry_addr, void *tags)
++{
++#if defined(__powerpc__)
++ kernel_entry_t entry = (kernel_entry_t) entry_addr;
++ entry (MULTIBOOT2_BOOTLOADER_MAGIC, tags, grub_ieee1275_entry_fn, 0, 0);
++#elif defined(__i386__)
++ grub_multiboot2_real_boot (entry_addr, tags);
++#else
++#error
++#endif
++}
--- /dev/null
--- /dev/null
++/* multiboot2.c - boot a multiboot 2 OS image. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2007 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/loader.h>
++#include <grub/machine/loader.h>
++#include <grub/multiboot2.h>
++#include <multiboot2.h>
++#include <grub/elfload.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/gzio.h>
++
++static grub_addr_t entry;
++extern grub_dl_t my_mod;
++
++static char *grub_mb2_tags;
++static char *grub_mb2_tags_pos;
++static grub_size_t grub_mb2_tags_len;
++static int grub_mb2_tags_count;
++
++static void
++grub_mb2_tags_free (void)
++{
++ grub_dprintf ("loader", "Freeing all tags...\n");
++ grub_free (grub_mb2_tags);
++ grub_mb2_tags = 0;
++ grub_mb2_tags_pos = 0;
++ grub_mb2_tags_len = 0;
++ grub_mb2_tags_count = 0;
++}
++
++grub_err_t
++grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len)
++{
++ struct multiboot2_tag_header *tag;
++ grub_size_t used;
++ grub_size_t needed;
++
++ grub_dprintf ("loader", "Allocating tag: key 0x%x, size 0x%lx.\n",
++ key, (unsigned long) len);
++
++ used = grub_mb2_tags_pos - grub_mb2_tags;
++ len = ALIGN_UP (len, sizeof (multiboot2_word));
++
++ needed = used + len;
++
++ if (needed > grub_mb2_tags_len)
++ {
++ /* Allocate new buffer. */
++ grub_size_t newsize = needed * 2;
++ char *newarea;
++
++ grub_dprintf ("loader", "Reallocating tag buffer (new size 0x%lx).\n",
++ (unsigned long) newsize);
++
++ newarea = grub_malloc (newsize);
++ if (! newarea)
++ return grub_errno;
++ grub_memcpy (newarea, grub_mb2_tags, grub_mb2_tags_len);
++ grub_free (grub_mb2_tags);
++
++ grub_mb2_tags_len = newsize;
++ grub_mb2_tags = newarea;
++ grub_mb2_tags_pos = newarea + used;
++ }
++
++ tag = (struct multiboot2_tag_header *) grub_mb2_tags_pos;
++ grub_mb2_tags_pos += len;
++
++ tag->key = key;
++ tag->len = len;
++
++ if (addr)
++ *addr = (grub_addr_t) tag;
++
++ grub_mb2_tags_count++;
++
++ grub_dprintf ("loader", "Allocated tag %u at %p.\n", grub_mb2_tags_count, tag);
++
++ return 0;
++}
++
++static grub_err_t
++grub_mb2_tag_start_create (void)
++{
++ return grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_START,
++ sizeof (struct multiboot2_tag_start));
++}
++
++static grub_err_t
++grub_mb2_tag_name_create (void)
++{
++ struct multiboot2_tag_name *name;
++ grub_addr_t name_addr;
++ grub_err_t err;
++ const char *grub_version = PACKAGE_STRING;
++
++ err = grub_mb2_tag_alloc (&name_addr, MULTIBOOT2_TAG_NAME,
++ sizeof (struct multiboot2_tag_name) +
++ sizeof (grub_version) + 1);
++ if (err)
++ return err;
++
++ name = (struct multiboot2_tag_name *) name_addr;
++ grub_strcpy (name->name, grub_version);
++
++ return GRUB_ERR_NONE;
++}
++
++typedef grub_err_t (*tag_create_t) (void);
++static tag_create_t grub_mb2_tag_creators[] = {
++ grub_mb2_tag_start_create,
++ grub_mb2_tag_name_create,
++ grub_mb2_tags_arch_create,
++ 0,
++};
++
++static grub_err_t
++grub_mb2_tags_create (void)
++{
++ tag_create_t *creator;
++ grub_err_t err;
++
++ for (creator = grub_mb2_tag_creators; *creator != 0; creator++)
++ {
++ err = (*creator) ();
++ if (err)
++ goto error;
++ }
++
++ return GRUB_ERR_NONE;
++
++error:
++ grub_error_push ();
++ grub_mb2_tags_free ();
++ grub_error_pop ();
++ return err;
++}
++
++static grub_err_t
++grub_mb2_tags_finish (void)
++{
++ struct multiboot2_tag_start *start;
++ grub_err_t err;
++
++ /* Create the `end' tag. */
++ err = grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_END,
++ sizeof (struct multiboot2_tag_end));
++ if (err)
++ goto error;
++
++ /* We created the `start' tag first. Update it now. */
++ start = (struct multiboot2_tag_start *) grub_mb2_tags;
++ start->size = grub_mb2_tags_pos - grub_mb2_tags;
++ return GRUB_ERR_NONE;
++
++error:
++ grub_error_push ();
++ grub_mb2_tags_free ();
++ grub_error_pop ();
++ return err;
++}
++
++static grub_err_t
++grub_mb2_boot (void)
++{
++ grub_mb2_tags_finish ();
++
++ grub_dprintf ("loader", "Tags at %p\n", grub_mb2_tags);
++ grub_mb2_arch_boot (entry, grub_mb2_tags);
++
++ /* Not reached. */
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_mb2_unload (void)
++{
++ struct multiboot2_tag_header *tag;
++ struct multiboot2_tag_header *tags =
++ (struct multiboot2_tag_header *) grub_mb2_tags;
++
++ /* Free all module memory in the tag list. */
++ for_each_tag (tag, tags)
++ {
++ if (tag->key == MULTIBOOT2_TAG_MODULE)
++ {
++ struct multiboot2_tag_module *module =
++ (struct multiboot2_tag_module *) tag;
++ grub_free ((void *) module->addr);
++ }
++ }
++
++ /* Allow architecture to un-reserve memory. */
++ grub_mb2_arch_unload (tags);
++
++ /* Free the tags themselves. */
++ grub_mb2_tags_free ();
++
++ grub_dl_unref (my_mod);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_mb2_load_other (grub_file_t file __attribute__ ((unused)),
++ void *buffer __attribute__ ((unused)))
++{
++ /* XXX Create module tag here. */
++ return grub_error (GRUB_ERR_UNKNOWN_OS, "currently only ELF is supported");
++}
++
++/* Create the tag containing the cmdline and the address of the module data. */
++static grub_err_t
++grub_mb2_tag_module_create (grub_addr_t modaddr, grub_size_t modsize,
++ char *type, int key, int argc, char *argv[])
++{
++ struct multiboot2_tag_module *module;
++ grub_ssize_t argslen = 0;
++ grub_err_t err;
++ char *p;
++ grub_addr_t module_addr;
++ int i;
++
++ /* Allocate enough space for the arguments and spaces between them. */
++ for (i = 0; i < argc; i++)
++ argslen += grub_strlen (argv[i]) + 1;
++
++ /* Note: includes implicit 1-byte cmdline. */
++ err = grub_mb2_tag_alloc (&module_addr, key,
++ sizeof (struct multiboot2_tag_module) + argslen);
++ if (err)
++ return grub_errno;
++
++ module = (struct multiboot2_tag_module *) module_addr;
++ module->addr = modaddr;
++ module->size = modsize;
++ grub_strcpy(module->type, type);
++
++ /* Fill in the command line. */
++ p = module->cmdline;
++ for (i = 0; i < argc; i++)
++ {
++ p = grub_stpcpy (p, argv[i]);
++ *p++ = ' ';
++ }
++ module->cmdline[argslen] = '\0';
++
++ return GRUB_ERR_NONE;
++}
++
++/* Load ELF32 or ELF64. */
++static grub_err_t
++grub_mb2_load_elf (grub_elf_t elf, int argc, char *argv[])
++{
++ grub_addr_t kern_base;
++ grub_size_t kern_size;
++ grub_err_t err;
++
++ if (grub_elf_is_elf32 (elf))
++ {
++ entry = elf->ehdr.ehdr32.e_entry;
++ err = grub_elf32_load (elf, grub_mb2_arch_elf32_hook, &kern_base,
++ &kern_size);
++ }
++ else if (grub_elf_is_elf64 (elf))
++ {
++ entry = elf->ehdr.ehdr64.e_entry;
++ err = grub_elf64_load (elf, grub_mb2_arch_elf64_hook, &kern_base,
++ &kern_size);
++ }
++ else
++ err = grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class");
++
++ if (err)
++ goto fail;
++
++ grub_dprintf ("loader", "Entry point is 0x%lx.\n", (unsigned long) entry);
++
++ grub_mb2_tag_module_create (kern_base, kern_size, "kernel",
++ MULTIBOOT2_TAG_MODULE, argc, argv);
++
++fail:
++ return err;
++}
++
++void
++grub_multiboot2 (int argc, char *argv[])
++{
++ char *buffer;
++ grub_file_t file = 0;
++ grub_elf_t elf = 0;
++ struct multiboot2_header *header = 0;
++ char *p;
++ grub_ssize_t len;
++ grub_err_t err;
++ int header_found = 0;
++
++ grub_loader_unset ();
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++ goto fail;
++ }
++
++ file = grub_gzfile_open (argv[0], 1);
++ if (! file)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
++ goto fail;
++ }
++
++ buffer = grub_malloc (MULTIBOOT2_HEADER_SEARCH);
++ if (! buffer)
++ return;
++
++ len = grub_file_read (file, buffer, MULTIBOOT2_HEADER_SEARCH);
++ if (len < 32)
++ {
++ grub_error (GRUB_ERR_BAD_OS, "file too small");
++ goto fail;
++ }
++
++ /* Look for the multiboot header in the buffer. The header should
++ be at least 8 bytes and aligned on a 8-byte boundary. */
++ for (p = buffer; p <= buffer + len - 8; p += 8)
++ {
++ header = (struct multiboot2_header *) p;
++ if (header->magic == MULTIBOOT2_HEADER_MAGIC)
++ {
++ header_found = 1;
++ break;
++ }
++ }
++
++ if (! header_found)
++ grub_dprintf ("loader", "No multiboot 2 header found.\n");
++
++
++ /* Create the basic tags. */
++ grub_dprintf ("loader", "Creating multiboot 2 tags\n");
++ grub_mb2_tags_create ();
++
++ /* Load the kernel and create its tag. */
++ elf = grub_elf_file (file);
++ if (elf)
++ {
++ grub_dprintf ("loader", "Loading ELF multiboot 2 file.\n");
++ err = grub_mb2_load_elf (elf, argc-1, &argv[1]);
++ grub_elf_close (elf);
++ }
++ else
++ {
++ grub_errno = 0;
++ grub_dprintf ("loader", "Loading non-ELF multiboot 2 file.\n");
++
++ if (header)
++ err = grub_mb2_load_other (file, header);
++ else
++ err = grub_error (GRUB_ERR_BAD_OS,
++ "need multiboot 2 header to load non-ELF files");
++ grub_file_close (file);
++ }
++
++ grub_free (buffer);
++
++ if (err)
++ goto fail;
++
++ /* Good to go. */
++ grub_loader_set (grub_mb2_boot, grub_mb2_unload, 1);
++ return;
++
++fail:
++ grub_mb2_tags_free ();
++ grub_dl_unref (my_mod);
++}
++
++void
++grub_module2 (int argc, char *argv[])
++{
++ grub_file_t file;
++ grub_addr_t modaddr = 0;
++ grub_ssize_t modsize = 0;
++ grub_err_t err;
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified");
++ return;
++ }
++
++ if (argc == 1)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no module type specified");
++ return;
++ }
++
++ if (entry == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT,
++ "you need to load the multiboot kernel first");
++ return;
++ }
++
++ /* Load module data. */
++ file = grub_gzfile_open (argv[0], 1);
++ if (! file)
++ goto out;
++
++ modsize = grub_file_size (file);
++ err = grub_mb2_arch_module_alloc (modsize, &modaddr);
++ if (err)
++ goto out;
++
++ grub_dprintf ("loader", "Loading module at 0x%x - 0x%x\n", modaddr,
++ modaddr + modsize);
++ if (grub_file_read (file, (void *) modaddr, modsize) != modsize)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file");
++ goto out;
++ }
++
++ /* Create the module tag. */
++ err = grub_mb2_tag_module_create (modaddr, modsize,
++ argv[1], MULTIBOOT2_TAG_MODULE,
++ argc-2, &argv[2]);
++ if (err)
++ goto out;
++
++out:
++ grub_error_push ();
++
++ if (file)
++ grub_file_close (file);
++
++ if (modaddr)
++ grub_mb2_arch_module_free (modaddr, modsize);
++
++ grub_error_pop ();
++}
--- /dev/null
--- /dev/null
++/* multiboot_loader.c - boot multiboot 1 or 2 OS image */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2007,2008 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/multiboot.h>
++#include <grub/multiboot2.h>
++#include <multiboot2.h>
++#include <grub/elf.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/gzio.h>
++#include <grub/command.h>
++
++grub_dl_t my_mod;
++
++/* This tracks which version of multiboot to use when using
++ * the module command. By default use multiboot version 1.
++ * values:
++ * 1 - Multiboot version 1
++ * 2 - Multiboot version 2
++ */
++
++static unsigned int module_version_status = 1;
++
++static int
++find_multi_boot1_header (grub_file_t file)
++{
++ struct multiboot_header *header;
++ char buffer[MULTIBOOT_SEARCH];
++ int found_status = 0;
++ grub_ssize_t len;
++
++ len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
++ if (len < 32)
++ return found_status;
++
++ /* Look for the multiboot header in the buffer. The header should
++ be at least 12 bytes and aligned on a 4-byte boundary. */
++ for (header = (struct multiboot_header *) buffer;
++ ((char *) header <= buffer + len - 12) || (header = 0);
++ header = (struct multiboot_header *) ((char *) header + 4))
++ {
++ if (header->magic == MULTIBOOT_HEADER_MAGIC
++ && !(header->magic + header->flags + header->checksum))
++ {
++ found_status = 1;
++ break;
++ }
++ }
++
++ return found_status;
++}
++
++static int
++find_multi_boot2_header (grub_file_t file)
++{
++ struct multiboot_header *header;
++ char buffer[MULTIBOOT_SEARCH];
++ int found_status = 0;
++ grub_ssize_t len;
++
++ len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
++ if (len < 32)
++ return found_status;
++
++ /* Look for the multiboot header in the buffer. The header should
++ be at least 8 bytes and aligned on a 8-byte boundary. */
++ for (header = (struct multiboot_header *) buffer;
++ ((char *) header <= buffer + len - 8) || (header = 0);
++ header = (struct multiboot_header *) ((char *) header + 8))
++ {
++ if (header->magic == MULTIBOOT2_HEADER_MAGIC)
++ {
++ found_status = 1;
++ break;
++ }
++ }
++
++ return found_status;
++}
++
++static grub_err_t
++grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ int header_multi_ver_found = 0;
++
++ grub_dl_ref (my_mod);
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
++ goto fail;
++ }
++
++ file = grub_gzfile_open (argv[0], 1);
++ if (! file)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
++ goto fail;
++ }
++
++ /* find which header is in the file */
++ if (find_multi_boot1_header (file))
++ header_multi_ver_found = 1;
++ else if (find_multi_boot2_header (file))
++ header_multi_ver_found = 2;
++ else
++ {
++ grub_error (GRUB_ERR_BAD_OS, "multiboot header not found");
++ goto fail;
++ }
++
++ /* close file before calling functions */
++ if (file)
++ grub_file_close (file);
++
++ /* Launch multi boot with header */
++
++ /* XXX Find a better way to identify this.
++ This is for i386-pc */
++#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \
++ defined(GRUB_MACHINE_QEMU)
++ if (header_multi_ver_found == 1)
++ {
++ grub_dprintf ("multiboot_loader",
++ "Launching multiboot 1 grub_multiboot() function\n");
++ grub_multiboot (argc, argv);
++ module_version_status = 1;
++ }
++#endif
++ if (header_multi_ver_found == 0 || header_multi_ver_found == 2)
++ {
++ grub_dprintf ("multiboot_loader",
++ "Launching multiboot 2 grub_multiboot2() function\n");
++ grub_multiboot2 (argc, argv);
++ module_version_status = 2;
++ }
++
++ return grub_errno;
++
++fail:
++ if (file)
++ grub_file_close (file);
++
++ grub_dl_unref (my_mod);
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_module_loader (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++
++#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_COREBOOT) || \
++ defined(GRUB_MACHINE_QEMU)
++ if (module_version_status == 1)
++ {
++ grub_dprintf("multiboot_loader",
++ "Launching multiboot 1 grub_module() function\n");
++ grub_module (argc, argv);
++ }
++#endif
++ if (module_version_status == 2)
++ {
++ grub_dprintf("multiboot_loader",
++ "Launching multiboot 2 grub_module2() function\n");
++ grub_module2 (argc, argv);
++ }
++
++ return grub_errno;
++}
++
++static grub_command_t cmd_multiboot, cmd_module;
++
++GRUB_MOD_INIT(multiboot)
++{
++ cmd_multiboot =
++ grub_register_command ("multiboot", grub_cmd_multiboot_loader,
++ 0, "Load a multiboot kernel.");
++ cmd_module =
++ grub_register_command ("module", grub_cmd_module_loader,
++ 0, "Load a multiboot module.");
++
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI(multiboot)
++{
++ grub_unregister_command (cmd_multiboot);
++ grub_unregister_command (cmd_module);
++}
--- /dev/null
--- /dev/null
++/* handler.c - support handler 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/dl.h>
++#include <grub/mm.h>
++#include <grub/err.h>
++#include <grub/env.h>
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/handler.h>
++#include <grub/normal.h>
++
++struct grub_handler_list
++{
++ struct grub_handler_list *next;
++ char *name;
++ grub_command_t cmd;
++};
++
++static grub_list_t handler_list;
++
++static grub_err_t
++grub_handler_cmd (struct grub_command *cmd,
++ int argc __attribute__ ((unused)),
++ char **args __attribute__ ((unused)))
++{
++ char *p;
++ grub_handler_class_t class;
++ grub_handler_t handler;
++
++ p = grub_strchr (cmd->name, '.');
++ if (! p)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid command name");
++
++ if (cmd->data)
++ {
++ if (! grub_dl_get (cmd->data))
++ {
++ grub_dl_t mod;
++
++ mod = grub_dl_load (cmd->data);
++ if (mod)
++ grub_dl_ref (mod);
++ else
++ return grub_errno;
++ }
++ grub_free (cmd->data);
++ cmd->data = 0;
++ }
++
++ *p = 0;
++ class = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_handler_class_list),
++ cmd->name);
++ *p = '.';
++
++ if (! class)
++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found");
++
++
++ handler = grub_named_list_find (GRUB_AS_NAMED_LIST (class->handler_list),
++ p + 1);
++ if (! handler)
++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found");
++
++ grub_handler_set_current (class, handler);
++
++ return 0;
++}
++
++static void
++insert_handler (char *name, char *module)
++{
++ struct grub_handler_list *item;
++ char *data;
++
++ if (grub_command_find (name))
++ return;
++
++ item = grub_malloc (sizeof (*item));
++ if (! item)
++ return;
++
++ item->name = grub_strdup (name);
++ if (! item->name)
++ {
++ grub_free (item);
++ return;
++ }
++
++ if (module)
++ {
++ data = grub_strdup (module);
++ if (! data)
++ {
++ grub_free (item->name);
++ grub_free (item);
++ return;
++ }
++ }
++ else
++ data = 0;
++
++ item->cmd = grub_register_command (item->name, grub_handler_cmd, 0,
++ "Set active handler.");
++ if (! item->cmd)
++ {
++ grub_free (data);
++ grub_free (item->name);
++ grub_free (item);
++ return;
++ }
++
++ item->cmd->data = data;
++ grub_list_push (&handler_list, GRUB_AS_LIST (item));
++}
++
++/* Read the file handler.lst for auto-loading. */
++void
++read_handler_list (void)
++{
++ const char *prefix;
++ static int first_time = 1;
++ const char *class_name;
++
++ auto int iterate_handler (grub_handler_t handler);
++ int iterate_handler (grub_handler_t handler)
++ {
++ char name[grub_strlen (class_name) + grub_strlen (handler->name) + 2];
++
++ grub_strcpy (name, class_name);
++ grub_strcat (name, ".");
++ grub_strcat (name, handler->name);
++
++ insert_handler (name, 0);
++
++ return 0;
++ }
++
++ auto int iterate_class (grub_handler_class_t class);
++ int iterate_class (grub_handler_class_t class)
++ {
++ class_name = class->name;
++ grub_list_iterate (GRUB_AS_LIST (class->handler_list),
++ (grub_list_hook_t) iterate_handler);
++
++ return 0;
++ }
++
++ /* Make sure that this function does not get executed twice. */
++ if (! first_time)
++ return;
++ first_time = 0;
++
++ prefix = grub_env_get ("prefix");
++ if (prefix)
++ {
++ char *filename;
++
++ filename = grub_malloc (grub_strlen (prefix) + sizeof ("/handler.lst"));
++ if (filename)
++ {
++ grub_file_t file;
++
++ grub_sprintf (filename, "%s/handler.lst", prefix);
++ file = grub_file_open (filename);
++ if (file)
++ {
++ char *buf = NULL;
++ for (;; grub_free (buf))
++ {
++ char *p;
++
++ buf = grub_file_getline (file);
++
++ if (! buf)
++ break;
++
++ if (! grub_isgraph (buf[0]))
++ continue;
++
++ p = grub_strchr (buf, ':');
++ if (! p)
++ continue;
++
++ *p = '\0';
++ while (*++p == ' ')
++ ;
++
++ insert_handler (buf, p);
++ }
++ grub_file_close (file);
++ }
++ grub_free (filename);
++ }
++ }
++
++ grub_list_iterate (GRUB_AS_LIST (grub_handler_class_list),
++ (grub_list_hook_t) iterate_class);
++
++ /* Ignore errors. */
++ grub_errno = GRUB_ERR_NONE;
++}
++
++void
++free_handler_list (void)
++{
++ struct grub_handler_list *item;
++
++ while ((item = grub_list_pop (&handler_list)) != 0)
++ {
++ grub_free (item->cmd->data);
++ grub_unregister_command (item->cmd);
++ grub_free (item->name);
++ grub_free (item);
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * 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/mm.h>
++#include <grub/misc.h>
++#include <grub/env.h>
++#include <grub/menu_viewer.h>
++#include <grub/menu.h>
++#include <grub/auth.h>
++
++/* The list of menu viewers. */
++static grub_menu_viewer_t menu_viewer_list;
++
++void
++grub_menu_viewer_register (grub_menu_viewer_t viewer)
++{
++ viewer->next = menu_viewer_list;
++ menu_viewer_list = viewer;
++}
++
++static grub_menu_viewer_t get_current_menu_viewer (void)
++{
++ const char *selected_name = grub_env_get ("menuviewer");
++
++ /* If none selected, pick the last registered one. */
++ if (selected_name == 0)
++ return menu_viewer_list;
++
++ grub_menu_viewer_t cur;
++ for (cur = menu_viewer_list; cur; cur = cur->next)
++ {
++ if (grub_strcmp (cur->name, selected_name) == 0)
++ return cur;
++ }
++
++ /* Fall back to the first entry (or null). */
++ return menu_viewer_list;
++}
++
++grub_err_t
++grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
++{
++ grub_menu_viewer_t cur = get_current_menu_viewer ();
++ grub_err_t err1, err2;
++ if (!cur)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menu viewer available");
++
++ while (1)
++ {
++ err1 = cur->show_menu (menu, nested);
++ grub_print_error ();
++
++ err2 = grub_auth_check_authentication (NULL);
++ if (err2)
++ {
++ grub_print_error ();
++ grub_errno = GRUB_ERR_NONE;
++ continue;
++ }
++
++ break;
++ }
++
++ return err1;
++}
++
--- /dev/null
--- /dev/null
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2005,2007,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/>.
++ */
++
++// TODO: Deprecated and broken. Scheduled for removal as there is VBE driver in Video subsystem.
++
++#include <grub/machine/memory.h>
++#include <grub/machine/vga.h>
++#include <grub/machine/vbe.h>
++#include <grub/machine/console.h>
++#include <grub/term.h>
++#include <grub/types.h>
++#include <grub/dl.h>
++#include <grub/misc.h>
++#include <grub/normal.h>
++#include <grub/font.h>
++#include <grub/mm.h>
++#include <grub/env.h>
++
++#define DEFAULT_CHAR_WIDTH 8
++#define DEFAULT_CHAR_HEIGHT 16
++
++#define DEFAULT_FG_COLOR 0xa
++#define DEFAULT_BG_COLOR 0x0
++
++struct grub_colored_char
++{
++ /* An Unicode codepoint. */
++ grub_uint32_t code;
++
++ /* Color indexes. */
++ unsigned char fg_color;
++ unsigned char bg_color;
++
++ /* The width of this character minus one. */
++ unsigned char width;
++
++ /* The column index of this character. */
++ unsigned char index;
++};
++
++struct grub_virtual_screen
++{
++ /* Dimensions of the virtual screen. */
++ grub_uint32_t width;
++ grub_uint32_t height;
++
++ /* Offset in the display. */
++ grub_uint32_t offset_x;
++ grub_uint32_t offset_y;
++
++ /* TTY Character sizes. */
++ grub_uint32_t char_width;
++ grub_uint32_t char_height;
++
++ /* Virtual screen TTY size. */
++ grub_uint32_t columns;
++ grub_uint32_t rows;
++
++ /* Current cursor details. */
++ grub_uint32_t cursor_x;
++ grub_uint32_t cursor_y;
++ grub_uint8_t cursor_state;
++ grub_uint8_t fg_color;
++ grub_uint8_t bg_color;
++
++ /* Text buffer for virtual screen. Contains (columns * rows) number
++ of entries. */
++ struct grub_colored_char *text_buffer;
++};
++
++/* Make sure text buffer is not marked as allocated. */
++static struct grub_virtual_screen virtual_screen =
++ {
++ .text_buffer = 0
++ };
++
++static unsigned char *vga_font = 0;
++static grub_uint32_t old_mode = 0;
++
++static struct grub_vbe_mode_info_block mode_info;
++static grub_uint8_t *framebuffer = 0;
++static grub_uint32_t bytes_per_scan_line = 0;
++
++static void
++grub_virtual_screen_free (void)
++{
++ /* If virtual screen has been allocated, free it. */
++ if (virtual_screen.text_buffer != 0)
++ grub_free (virtual_screen.text_buffer);
++
++ /* Reset virtual screen data. */
++ grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
++}
++
++static grub_err_t
++grub_virtual_screen_setup (grub_uint32_t width,
++ grub_uint32_t height)
++{
++ /* Free old virtual screen. */
++ grub_virtual_screen_free ();
++
++ /* Initialize with default data. */
++ virtual_screen.width = width;
++ virtual_screen.height = height;
++ virtual_screen.offset_x = 0;
++ virtual_screen.offset_y = 0;
++ virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
++ virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
++ virtual_screen.cursor_x = 0;
++ virtual_screen.cursor_y = 0;
++ virtual_screen.cursor_state = 1;
++ virtual_screen.fg_color = DEFAULT_FG_COLOR;
++ virtual_screen.bg_color = DEFAULT_BG_COLOR;
++
++ /* Calculate size of text buffer. */
++ virtual_screen.columns = virtual_screen.width / virtual_screen.char_width;
++ virtual_screen.rows = virtual_screen.height / virtual_screen.char_height;
++
++ /* Allocate memory for text buffer. */
++ virtual_screen.text_buffer =
++ (struct grub_colored_char *) grub_malloc (virtual_screen.columns
++ * virtual_screen.rows
++ * sizeof (*virtual_screen.text_buffer));
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_vesafb_mod_init (void)
++{
++ grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE;
++ struct grub_vbe_info_block controller_info;
++ char *modevar;
++
++ /* Use fonts from VGA bios. */
++ vga_font = grub_vga_get_font ();
++
++ /* Check if we have VESA BIOS installed. */
++ if (grub_vbe_probe (&controller_info) != GRUB_ERR_NONE)
++ return grub_errno;
++
++ /* Check existence of vbe_mode environment variable. */
++ modevar = grub_env_get ("vbe_mode");
++
++ if (modevar != 0)
++ {
++ unsigned long value;
++
++ value = grub_strtoul (modevar, 0, 0);
++ if (grub_errno == GRUB_ERR_NONE)
++ use_mode = value;
++ }
++
++ /* Store initial video mode. */
++ if (grub_vbe_get_video_mode (&old_mode) != GRUB_ERR_NONE)
++ return grub_errno;
++
++ /* Setup desired graphics mode. */
++ if (grub_vbe_set_video_mode (use_mode, &mode_info) != GRUB_ERR_NONE)
++ return grub_errno;
++
++ /* Determine framebuffer and bytes per scan line. */
++ framebuffer = (grub_uint8_t *) mode_info.phys_base_addr;
++
++ if (controller_info.version >= 0x300)
++ bytes_per_scan_line = mode_info.lin_bytes_per_scan_line;
++ else
++ bytes_per_scan_line = mode_info.bytes_per_scan_line;
++
++ /* Create virtual screen. */
++ if (grub_virtual_screen_setup (mode_info.x_resolution,
++ mode_info.y_resolution) != GRUB_ERR_NONE)
++ {
++ grub_vbe_set_video_mode (old_mode, 0);
++ return grub_errno;
++ }
++
++ /* Make sure frame buffer is black. */
++ grub_memset (framebuffer,
++ 0,
++ bytes_per_scan_line * mode_info.y_resolution);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_vesafb_mod_fini (void)
++{
++ grub_virtual_screen_free ();
++
++ grub_vbe_set_video_mode (old_mode, 0);
++
++ return GRUB_ERR_NONE;
++}
++
++static int
++grub_virtual_screen_get_glyph (grub_uint32_t code,
++ unsigned char bitmap[32],
++ unsigned *width)
++{
++ if (code > 0x7f)
++ {
++ /* Map some unicode characters to the VGA font, if possible. */
++ switch (code)
++ {
++ case 0x2190: /* left arrow */
++ code = 0x1b;
++ break;
++ case 0x2191: /* up arrow */
++ code = 0x18;
++ break;
++ case 0x2192: /* right arrow */
++ code = 0x1a;
++ break;
++ case 0x2193: /* down arrow */
++ code = 0x19;
++ break;
++ case 0x2501: /* horizontal line */
++ code = 0xc4;
++ break;
++ case 0x2503: /* vertical line */
++ code = 0xb3;
++ break;
++ case 0x250F: /* upper-left corner */
++ code = 0xda;
++ break;
++ case 0x2513: /* upper-right corner */
++ code = 0xbf;
++ break;
++ case 0x2517: /* lower-left corner */
++ code = 0xc0;
++ break;
++ case 0x251B: /* lower-right corner */
++ code = 0xd9;
++ break;
++
++ default:
++ return grub_font_get_glyph_any (code, bitmap, width);
++ }
++ }
++
++ /* TODO This is wrong for the new font module. Should it be fixed? */
++ if (bitmap)
++ grub_memcpy (bitmap,
++ vga_font + code * virtual_screen.char_height,
++ virtual_screen.char_height);
++ *width = 1;
++ return 1;
++}
++
++static void
++grub_virtual_screen_invalidate_char (struct grub_colored_char *p)
++{
++ p->code = 0xFFFF;
++
++ if (p->width)
++ {
++ struct grub_colored_char *q;
++
++ for (q = p + 1; q <= p + p->width; q++)
++ {
++ q->code = 0xFFFF;
++ q->width = 0;
++ q->index = 0;
++ }
++ }
++
++ p->width = 0;
++}
++
++static void
++write_char (void)
++{
++ struct grub_colored_char *p;
++ unsigned char bitmap[32];
++ unsigned width;
++ unsigned y;
++ unsigned offset;
++
++ p = (virtual_screen.text_buffer
++ + virtual_screen.cursor_x
++ + (virtual_screen.cursor_y * virtual_screen.columns));
++
++ p -= p->index;
++
++ if (! grub_virtual_screen_get_glyph (p->code, bitmap, &width))
++ {
++ grub_virtual_screen_invalidate_char (p);
++ width = 0;
++ }
++
++ for (y = 0, offset = 0;
++ y < virtual_screen.char_height;
++ y++, offset++)
++ {
++ unsigned i;
++
++ for (i = 0;
++ (i < width * virtual_screen.char_width) && (offset < 32);
++ i++)
++ {
++ unsigned char color;
++
++ if (bitmap[offset] & (1 << (8-i)))
++ {
++ color = p->fg_color;
++ }
++ else
++ {
++ color = p->bg_color;
++ }
++
++ grub_vbe_set_pixel_index(i + (virtual_screen.cursor_x
++ * virtual_screen.char_width),
++ y + (virtual_screen.cursor_y
++ * virtual_screen.char_height),
++ color);
++ }
++ }
++}
++
++static void
++write_cursor (void)
++{
++ grub_uint32_t x;
++ grub_uint32_t y;
++
++ for (y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
++ y < ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 1;
++ y++)
++ {
++ for (x = virtual_screen.cursor_x * virtual_screen.char_width;
++ x < (virtual_screen.cursor_x + 1) * virtual_screen.char_width;
++ x++)
++ {
++ grub_vbe_set_pixel_index(x, y, 10);
++ }
++ }
++}
++
++static void
++scroll_up (void)
++{
++ grub_uint32_t i;
++
++ /* Scroll text buffer with one line to up. */
++ grub_memmove (virtual_screen.text_buffer,
++ virtual_screen.text_buffer + virtual_screen.columns,
++ sizeof (*virtual_screen.text_buffer)
++ * virtual_screen.columns
++ * (virtual_screen.rows - 1));
++
++ /* Clear last line in text buffer. */
++ for (i = virtual_screen.columns * (virtual_screen.rows - 1);
++ i < virtual_screen.columns * virtual_screen.rows;
++ i++)
++ {
++ virtual_screen.text_buffer[i].code = ' ';
++ virtual_screen.text_buffer[i].fg_color = 0;
++ virtual_screen.text_buffer[i].bg_color = 0;
++ virtual_screen.text_buffer[i].width = 0;
++ virtual_screen.text_buffer[i].index = 0;
++ }
++
++ /* Scroll framebuffer with one line to up. */
++ grub_memmove (framebuffer,
++ framebuffer
++ + bytes_per_scan_line * virtual_screen.char_height,
++ bytes_per_scan_line
++ * (mode_info.y_resolution - virtual_screen.char_height));
++
++ /* Clear last line in framebuffer. */
++ grub_memset (framebuffer
++ + (bytes_per_scan_line
++ * (mode_info.y_resolution - virtual_screen.char_height)),
++ 0,
++ bytes_per_scan_line * virtual_screen.char_height);
++}
++
++static void
++grub_vesafb_putchar (grub_uint32_t c)
++{
++ if (c == '\a')
++ /* FIXME */
++ return;
++
++ if (c == '\b' || c == '\n' || c == '\r')
++ {
++ /* Erase current cursor, if any. */
++ if (virtual_screen.cursor_state)
++ write_char ();
++
++ switch (c)
++ {
++ case '\b':
++ if (virtual_screen.cursor_x > 0)
++ virtual_screen.cursor_x--;
++ break;
++
++ case '\n':
++ if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
++ scroll_up ();
++ else
++ virtual_screen.cursor_y++;
++ break;
++
++ case '\r':
++ virtual_screen.cursor_x = 0;
++ break;
++ }
++
++ if (virtual_screen.cursor_state)
++ write_cursor ();
++ }
++ else
++ {
++ unsigned width;
++ struct grub_colored_char *p;
++
++ grub_virtual_screen_get_glyph (c, 0, &width);
++
++ if (virtual_screen.cursor_x + width > virtual_screen.columns)
++ grub_putchar ('\n');
++
++ p = (virtual_screen.text_buffer +
++ virtual_screen.cursor_x +
++ virtual_screen.cursor_y * virtual_screen.columns);
++ p->code = c;
++ p->fg_color = virtual_screen.fg_color;
++ p->bg_color = virtual_screen.bg_color;
++ p->width = width - 1;
++ p->index = 0;
++
++ if (width > 1)
++ {
++ unsigned i;
++
++ for (i = 1; i < width; i++)
++ {
++ p[i].code = ' ';
++ p[i].width = width - 1;
++ p[i].index = i;
++ }
++ }
++
++ write_char ();
++
++ virtual_screen.cursor_x += width;
++ if (virtual_screen.cursor_x >= virtual_screen.columns)
++ {
++ virtual_screen.cursor_x = 0;
++
++ if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
++ scroll_up ();
++ else
++ virtual_screen.cursor_y++;
++ }
++
++ if (virtual_screen.cursor_state)
++ write_cursor ();
++ }
++}
++
++static grub_ssize_t
++grub_vesafb_getcharwidth (grub_uint32_t c)
++{
++ unsigned width;
++
++ if (! grub_virtual_screen_get_glyph (c, 0, &width))
++ return 0;
++
++ return width;
++}
++
++static grub_uint16_t
++grub_virtual_screen_getwh (void)
++{
++ return (virtual_screen.columns << 8) | virtual_screen.rows;
++}
++
++static grub_uint16_t
++grub_virtual_screen_getxy (void)
++{
++ return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
++}
++
++static void
++grub_vesafb_gotoxy (grub_uint8_t x, grub_uint8_t y)
++{
++ if (x >= virtual_screen.columns || y >= virtual_screen.rows)
++ {
++ grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)",
++ (unsigned) x, (unsigned) y);
++ return;
++ }
++
++ if (virtual_screen.cursor_state)
++ write_char ();
++
++ virtual_screen.cursor_x = x;
++ virtual_screen.cursor_y = y;
++
++ if (virtual_screen.cursor_state)
++ write_cursor ();
++}
++
++static void
++grub_virtual_screen_cls (void)
++{
++ grub_uint32_t i;
++
++ for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
++ {
++ virtual_screen.text_buffer[i].code = ' ';
++ virtual_screen.text_buffer[i].fg_color = 0;
++ virtual_screen.text_buffer[i].bg_color = 0;
++ virtual_screen.text_buffer[i].width = 0;
++ virtual_screen.text_buffer[i].index = 0;
++ }
++
++ virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
++}
++
++static void
++grub_vesafb_cls (void)
++{
++ grub_virtual_screen_cls ();
++
++ grub_memset (framebuffer,
++ 0,
++ mode_info.y_resolution * bytes_per_scan_line);
++}
++
++static void
++grub_virtual_screen_setcolorstate (grub_term_color_state state)
++{
++ switch (state)
++ {
++ case GRUB_TERM_COLOR_STANDARD:
++ case GRUB_TERM_COLOR_NORMAL:
++ virtual_screen.fg_color = DEFAULT_FG_COLOR;
++ virtual_screen.bg_color = DEFAULT_BG_COLOR;
++ break;
++ case GRUB_TERM_COLOR_HIGHLIGHT:
++ virtual_screen.fg_color = DEFAULT_BG_COLOR;
++ virtual_screen.bg_color = DEFAULT_FG_COLOR;
++ break;
++ default:
++ break;
++ }
++}
++
++static void
++grub_vesafb_setcursor (int on)
++{
++ if (virtual_screen.cursor_state != on)
++ {
++ if (virtual_screen.cursor_state)
++ write_char ();
++ else
++ write_cursor ();
++
++ virtual_screen.cursor_state = on;
++ }
++}
++
++static struct grub_term_output grub_vesafb_term =
++ {
++ .name = "vesafb",
++ .init = grub_vesafb_mod_init,
++ .fini = grub_vesafb_mod_fini,
++ .putchar = grub_vesafb_putchar,
++ .getcharwidth = grub_vesafb_getcharwidth,
++ .getwh = grub_virtual_screen_getwh,
++ .getxy = grub_virtual_screen_getxy,
++ .gotoxy = grub_vesafb_gotoxy,
++ .cls = grub_vesafb_cls,
++ .setcolorstate = grub_virtual_screen_setcolorstate,
++ .setcursor = grub_vesafb_setcursor,
++ .flags = 0,
++ };
++
++GRUB_MOD_INIT(vesafb)
++{
++ grub_term_register_output ("vesafb", &grub_vesafb_term);
++}
++
++GRUB_MOD_FINI(vesafb)
++{
++ grub_term_unregister_output (&grub_vesafb_term);
++}