]> git.proxmox.com Git - grub2.git/commitdiff
merge mainline into hints
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 13 Sep 2010 00:22:10 +0000 (02:22 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 13 Sep 2010 00:22:10 +0000 (02:22 +0200)
24 files changed:
1  2 
grub-core/commands/handler.c
grub-core/commands/search.c
grub-core/commands/search_wrap.c
grub-core/efiemu/runtime/efiemu.sh
grub-core/kern/handler.c
grub-core/kern/i386/ieee1275/init.c
grub-core/kern/i386/loader.S
grub-core/kern/i386/misc.S
grub-core/kern/reader.c
grub-core/loader/i386/bsd_helper.S
grub-core/loader/i386/bsd_trampoline.S
grub-core/loader/i386/efi/linux.c
grub-core/loader/i386/efi/xnu.c
grub-core/loader/i386/ieee1275/linux.c
grub-core/loader/i386/linux_trampoline.S
grub-core/loader/i386/multiboot_helper.S
grub-core/loader/i386/pc/multiboot2.c
grub-core/loader/i386/pc/xnu.c
grub-core/loader/ieee1275/multiboot2.c
grub-core/loader/multiboot2.c
grub-core/loader/multiboot_loader.c
grub-core/normal/handler.c
grub-core/normal/menu_viewer.c
grub-core/term/i386/pc/vesafb.c

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..09b8ff5d0d12a510dcc74f86fe21142a40c61629
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,115 @@@
++/* 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);
++}
index 0000000000000000000000000000000000000000,8a646b452f34abbda3bd9bf1be852675682737f8..9b693e76f4dc9f5fc4cb3c0180b43b123aa3a957
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,175 +1,187 @@@
 -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);
+ }
index 0000000000000000000000000000000000000000,fff3fb47a153b37650c75c2d4e648b8e14a31bb2..14028bec7fc6609442d1f611923e5f6c0852666a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,95 +1,98 @@@
 -    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);
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5a492dc2f995c7f3dae6a1d7094abf6842fbe81f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2bf85313cfa1d8b393807fbb677dc3453c91593e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,64 @@@
++/* 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;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7658ee1a7bb866ebedf6955cfb1a387d0c19a936
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++/*  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)))
++{
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e9c713273e524bc06caf0439aca75b480f4c61e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,120 @@@
++/*
++ *  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
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7d57df9b9541f4d9a77beba52b30dd63c30c8c43
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ *  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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..271a90f5a5bccd43b000b9739304fb5819fe3377
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,49 @@@
++/* 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);
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25aee3a8051be06101e64ff611fab3ab3a99fdaf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++/*
++ *  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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a568fff4d25fbd292aac64b1d7aa48668d90021d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ *  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)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c256e377d3a8688824758f4378eaf70ad8ee44c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1002 @@@
++/*
++ *  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 (&params->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);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a7ede1960f84fed36c11c0f24bdbe9139e88ee1c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,178 @@@
++/*
++ *  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;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b577de964633640b9d0129387782a9cdd1a1cc08
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,289 @@@
++/* 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);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4acea7b1161a2cd415e976760f6815ef307f249a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,129 @@@
++/*
++ *  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)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2f9af778b9614c3b1e775b85d3679fb4c9c3930c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,43 @@@
++/*
++ *  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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9bfe5d248f8f35b0f0db16b7150b4d3c956d56ab
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,122 @@@
++/* 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;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ebb176bb41951ecbe20d465493903ef9bb5e00c9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,110 @@@
++/*
++ *  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;
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8c0bc09ecb213337e19077c0879ffa1c5028e4d8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,147 @@@
++/* 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
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dbdee9c87a8b13e453a2c5f9e86dbbd75cd5ee7f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,461 @@@
++/* 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 ();
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..24c0c5eacd5457817c24a69ec3ba4766b525d53a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,212 @@@
++/* 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);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b44dc7a68f11eee1041099c7a9ece25cc9bf5300
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,232 @@@
++/* 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);
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f870ccd53e6e42884decc57a6d530f39d42bddbb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,81 @@@
++/*
++ *  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;
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..52694ed104027149c332bca14fe836542a29ab72
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,606 @@@
++/*
++ *  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);
++}