text: of an OS plumber
  Most GNU/Linux distributions utilize GNU GRUB (GRand Unified Bootloader) to boot the Linux kernel. GRUB was conceived and initially developed by Erich Boleyn. It became part of the GNU project in 1999 but was never officially released. The last development snapshot was v0.97 which was released in 2005. In spite of the fact that it was never officially released, it is used on millions of computers worldwide.
  The v0.97 codebase is now known as GRUB Legacy. Supposedly it is still in maintenance mode but no fixes have occurred in the last few years. As a result, vendors such as Red Hat maintain their own branches of GRUB Legacy. Currently the Fedora Project applies 25 patches to the v0.97 release of which 7 or 8 patches relate to the addition of EFI support. Other forks of GRUB Legacy include the bootloader used by Oracle to boot Solaris on IA32 and X64 platforms.
  Many years ago the GRUB developers decided that a complete rewrite was required. The goal was to make a more robust, portable and powerful version of GRUB which has support for a scripting language, internationalization and localization. GRUB 2 is derived from PUPA which was a research project funded by the Information-technology Promotion Agency of Japan to investigate the next generation of GRUB.
  For some time, I have been EFI-booting one of my X64 systems which runs Fedora 12 and experimenting with the TianoCore EFI shell and various EFI utilities. The system boots into an EFI shell and I then use Fedora’s EFI-enabled version of GRUB Legacy to boot into various Fedora kernels.
  Recently I decided to download the latest version of the GRUB 2 sources (currently v1.98), build GRUB2 as an X64 EFI image and install it in parallel with the GRUB Legacy bootloader on the ESP (EFI System Partition) so that I could experiment with the new facilities available in the GRUB2 bootloader.
  Building the EFI version of GRUB2 was not an issue. As usual, the first requirement is to configure the build. Here is a copy of the configuration options I choose:
  $ ./configure --with-platform=efi --enable-grub-fstest=no
  --enable-grub-mkfont=no --disable-nls --enable-efiemu=no
  As you can see I disabled EFI emulation, NLS support and various debugging utilities (fstest and mkfont.) The Makefile includes ../conf/x86_64-efi.mk which is where most of the build is specified. The default Makefile has a dependency on Ruby but this is easily worked around. The header ../include/grub/i18n also has a minor error. The fix is to change the syntax of the ENABLE_NLS guard from #if to #ifdef.
  After you have successfully run make, you have to generate the grub.efi image using the grub-mkimage utility.
  $ ./grub-mkimage -d . -o grub.efi boot linux part_gpt \
  fat ext2 normal sh configfile lspci ls reboot datetime
  loadenv search lvm help quit
  GRUB2 is a very modular bootloader. You can include whichever modules you need into the image using grub-mkimage or you can load them from the GRUB2 shell. The boot module is mandatory, the linux module is the loader for Linux images, the help module displays help information, and the remaining modules, except for quit are explained in Erich Boleyn’s commands summary page.
  Here is a list of the modules which were built:
  acpi.mod efi_gop.mod gcry_whirlpool.mod mmap.mod scsi.mod
  affs.mod efi_uga.mod gettext.mod msdospart.mod search_fs_file.mod
  afs_be.mod elf.mod gfxmenu.mod multiboot2.mod search_fs_uuid.mod
  afs.mod ext2.mod gfxterm.mod multiboot.mod search_label.mod
  appleldr.mod extcmd.mod gptsync.mod normal.mod search.mod
  ata.mod fat.mod gzio.mod ntfscomp.mod setjmp.mod
  at_keyboard.mod fixvideo.mod halt.mod ntfs.mod setpci.mod
  befs_be.mod font.mod handler.mod part_acorn.mod sfs.mod
  befs.mod fshelp.mod hashsum.mod part_amiga.mod sh.mod
  bitmap.mod functional_test.mod help.mod part_apple.mod sleep.mod
  bitmap_scale.mod gcry_arcfour.mod hexdump.mod part_gpt.mod tar.mod
  blocklist.mod gcry_blowfish.mod hfs.mod part_msdos.mod terminal.mod
  boot.mod gcry_camellia.mod hfsplus.mod part_sun.mod terminfo.mod
  bufio.mod gcry_cast5.mod iso9660.mod parttool.mod test.mod
  cat.mod gcry_crc.mod jfs.mod password.mod tga.mod
  chain.mod gcry_des.mod jpeg.mod password_pbkdf2.mod trig.mod
  charset.mod gcry_md4.mod keystatus.mod pbkdf2.mod true.mod
  cmp.mod gcry_md5.mod linux.mod pci.mod udf.mod
  configfile.mod gcry_rfc2268.mod loadbios.mod png.mod ufs1.mod
  cpio.mod gcry_rijndael.mod loadenv.mod probe.mod ufs2.mod
  cpuid.mod gcry_rmd160.mod loopback.mod quit.mod vga_text.mod
  crc.mod gcry_seed.mod ls.mod raid5rec.mod video_fb.mod
  crypto.mod gcry_serpent.mod lspci.mod raid6rec.mod video.mod
  datehook.mod gcry_sha1.mod lvm.mod raid.mod videotest.mod
  date.mod gcry_sha256.mod mdraid.mod read.mod xfs.mod
  datetime.mod gcry_sha512.mod memrw.mod reboot.mod xnu.mod
  dm_nv.mod gcry_tiger.mod minicmd.mod reiserfs.mod xnu_uuid.mod
  echo.mod gcry_twofish.mod minix.mod relocator.mod
  After building the grub.efi image I moved it to its home on the ESP and created a very basic GRUB2 configuration file which must be called grub.cfg. Here is a copy of my initial grub.cfg
  # FPM 3/18/10 manual edit
  timeout=10
  default=0
  }
  Stanzas are phrased slightly differently and cannot be copied directly from a GRUB Legacy configuration file. They are pretty close though and no explanation of the required changes should be necessary. Note that the command kernel has been superseded by linux. Note also that GRUB2 partition numbers start at 1 not 0 but drives still start at 0. Thus the second partition of the first drive is hd(0,2) in GRUB2 but (hd0,1) in GRUB Legacy.
  When I switched to GRUB2 to experiment using it to EFI-boot Fedora 12, I immediately noticed that the time from when I hit the Enter key until I saw a Plymouth theme went from about 10 second to over 3 minutes. It took me a while to track down the cause of this delay as the GRUB2 codebase is significantly larger and more complex than the GRUB Legacy codebase and EFI-related code is in numerous subdirectories.
  After a number of false starts, I finally tracked the issue down to the size of the disk cache. See the caching algorithm in get_disk_read() in the source file ../kern/disk.c. I probably could have bypassed the disk cache altogether, but found that increasing the cache size from 8 sectors to 8192 sectors reduced the time to read the kernel and initrd image files to less than a few seconds. Here are the changes to make in ../include/grub/disk.h.
  /* The size of a disk cache in sector units. */
  #ifdef GRUB_MACHINE_EFI
  #define GRUB_DISK_CACHE_SIZE 8192
  #define GRUB_DISK_CACHE_BITS 13
  #else
  #define GRUB_DISK_CACHE_SIZE 8
  #define GRUB_DISK_CACHE_BITS 3
  #endif
  Note that I used the guard GRUB_MACHINE_EFI to guard any EFI-specific code in common source files.
  One useful feature of GRUB2 are the reboot and halt modules. You can use these modules to add menu options to either reboot or halt your system or you invoke these commands from the GRUB2 command line. For example. here is a reboot menu option.
  menuentry "Reboot" {
  reboot
  }
  Currently, no command is available to quit out of GRUB2 and go back to the EFI shell. For non-EFI platforms this is not a useful option but for EFI-based platforms it provides great flexibility. I therefore decided to develop such a command and used the source code for the reboot command as my template. In case anybody else wants to create such a GRUB2 command, here are the relevant details.
  Create a file named quit.c in the ../commands subdirectory of your build tree which contains the following source code:
  /* quit.c - command to return to EFI shell */
  /*
  * GRUB -- GRand Unified Bootloader
  *
  * <>.
  */
  #include <grub/dl.h>
  #include <grub/command.h>
  #include <grub/misc.h>
  #include <grub/i18n.h>
  #include <grub/term.h>
  #include <grub/efi/efi.h>
  #include <grub/efi/api.h>
  #include <grub/efi/console.h>
  static grub_err_t
  grub_cmd_quit (grub_command_t cmd __attribute__ ((unused)),
  int argc __attribute__ ((unused)),
  char **args __attribute__ ((unused)))
  {
  grub_efi_simple_text_output_interface_t *o;
  static grub_uint8_t efi_console_stdcolor =
  GRUB_EFI_TEXT_ATTR (GRUB_EFI_YELLOW,
  GRUB_EFI_BACKGROUND_BLACK);
  o = grub_efi_system_table->con_out;
  efi_call_2 (o->set_attributes, o, efi_console_stdcolor);
  efi_call_1 (o->clear_screen, o);
  grub_exit ();
  return 0;
  }
  static grub_command_t cmd;
  GRUB_MOD_INIT(quit)
  {
  cmd = grub_register_command ("quit", grub_cmd_quit,
  0, N_("Return to EFI shell."));
  }
  GRUB_MOD_FINI(quit)
  {
  grub_unregister_command (cmd);
  }
  The contents of this file should be self-explanatory to an experienced programmer. The two efi_calls invoke the appropriate EFI protocol calls to set the screen text-mode foreground and background colors and clear the screen.
  Next add the following make directives to ../conf/x86_64-efi.mk which is the EFI-specific Makefile:
  # For quit.mod.
  quit_mod_SOURCES = commands/quit.c
  clean-module-quit.mod.1:
  rm -f quit.mod mod-quit.o mod-quit.c pre-quit.o quit_mod-commands_quit.o und-quit.lst
  CLEAN_MODULE_TARGETS += clean-module-quit.mod.1
  clean-module-quit.mod-symbol.1:
  rm -f def-quit.lst
  CLEAN_MODULE_TARGETS += clean-module-quit.mod-symbol.1
  DEFSYMFILES += def-quit.lst
  mostlyclean-module-quit.mod.1:
  rm -f quit_mod-commands_quit.d
  MOSTLYCLEAN_MODULE_TARGETS += mostlyclean-module-quit.mod.1
  UNDSYMFILES += und-quit.lst
  ifneq ($(TARGET_APPLE_CC),1)
  quit.mod: pre-quit.o mod-quit.o $(TARGET_OBJ2ELF)
  -rm -f $@
  $(TARGET_CC) $(quit_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ pre-quit.o mod-quit.o
  if test ! -z "$(TARGET_OBJ2ELF)"; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi
  $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@
  else
  quit.mod: pre-quit.o mod-quit.o $(TARGET_OBJ2ELF)
  -rm -f $@
  -rm -f $@.bin
  $(TARGET_CC) $(quit_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin pre-quit.o mod-quit.o
  $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@
  -rm -f $@.bin
  endif
  pre-quit.o: $(quit_mod_DEPENDENCIES) quit_mod-commands_quit.o
  -rm -f $@
  $(TARGET_CC) $(quit_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ quit_mod-commands_quit.o
  mod-quit.o: mod-quit.c
  $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -c -o $@ $<
  mod-quit.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
  sh $(srcdir)/genmodsrc.sh 'quit' $< > $@ || (rm -f $@; exit 1)
  ifneq ($(TARGET_APPLE_CC),1)
  def-quit.lst: pre-quit.o
  $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 quit/' > $@
  else
  def-quit.lst: pre-quit.o
  $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed 's/^\([^ ]*\).*/\1 quit/' > $@
  endif
  und-quit.lst: pre-quit.o
  echo 'quit' > $@
  $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
  quit_mod-commands_quit.o: commands/quit.c $(commands/quit.c_DEPENDENCIES)
  $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -MD -c -o $@ $<
  -include quit_mod-commands_quit.d
  clean-module-quit_mod-commands_quit-extra.1:
  rm -f cmd-quit_mod-commands_quit.lst fs-quit_mod-commands_quit.lst partmap-quit_mod-commands_quit.lst handler-quit_mod-commands_quit.lst parttool-quit_mod-commands_quit.lst video-quit_mod-commands_quit.lst terminal-quit_mod-commands_quit.lst
  CLEAN_MODULE_TARGETS += clean-module-quit_mod-commands_quit-extra.1
  COMMANDFILES += cmd-quit_mod-commands_quit.lst
  FSFILES += fs-quit_mod-commands_quit.lst
  PARTTOOLFILES += parttool-quit_mod-commands_quit.lst
  PARTMAPFILES += partmap-quit_mod-commands_quit.lst
  HANDLERFILES += handler-quit_mod-commands_quit.lst
  TERMINALFILES += terminal-quit_mod-commands_quit.lst
  VIDEOFILES += video-quit_mod-commands_quit.lst
  cmd-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) gencmdlist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh quit > $@ || (rm -f $@; exit 1)
  fs-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genfslist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh quit > $@ || (rm -f $@; exit 1)
  parttool-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genparttoollist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genparttoollist.sh quit > $@ || (rm -f $@; exit 1)
  partmap-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genpartmaplist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genpartmaplist.sh quit > $@ || (rm -f $@; exit 1)
  handler-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genhandlerlist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genhandlerlist.sh quit > $@ || (rm -f $@; exit 1)
  terminal-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genterminallist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genterminallist.sh quit > $@ || (rm -f $@; exit 1)
  video-quit_mod-commands_quit.lst: commands/quit.c $(commands/quit.c_DEPENDENCIES) genvideolist.sh
  set -e; $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(quit_mod_CFLAGS) -E $< | sh $(srcdir)/genvideolist.sh quit > $@ || (rm -f $@; exit 1)
  quit_mod_CFLAGS = $(COMMON_CFLAGS)
  quit_mod_LDFLAGS = $(COMMON_LDFLAGS)
  You should now be able to build quit.mod by invoking make quit.mod from the root of your GRUB2 build tree. Then use the grub-mkimage utility to incorporate the quit module into your grub.efi image. After placing the newly created grub.efi image in the ESP, you should be able to use the quit command from the GRUB2 shell or via a stanza in grub.cfg.
  The current linux loader does not reset the screen text-mode foreground and background colors to their defaults. For EFI shells these are yellow and black respectively. Instead the GRUB2 foreground and background colors propagate onto text outputted by the loader module. Here are the diffs to the loader file ../loader/i386/efi/linux.c to correct this problem and add informative messages similar to those outputted by GRUB Legacy.
  37a38,41
  > #include <grub/efi/console.h>
  > #include <grub/i386/vga_common.h>
  >
  >
  240a245,247
  > grub_printf("Trying to allocate %u pages for VMLINUZ\n",
  > (unsigned) prot_mode_pages);
  >
  608a616,622
  > /* set color colors to EFI default */
  > grub_efi_simple_text_output_interface_t *o;
  > static grub_uint8_t efi_console_standard_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_YELLOW, GRUB_EFI_BACKGROUND_BLACK);
  >
  > o = grub_efi_system_table->con_out;
  > efi_call_2 (o->set_attributes, o, efi_console_standard_color);
  >
  809c823,824
  < grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n",
  ---
  >
  > grub_printf ("[Linux-EFI, setup=0x%x, size=0x%x]\n",
  Once I had GRUB2 up and running, I decided to look at how to support a full-screen background image. This is one of the areas where GRUB Legacy has major limitations. It only supports a background image with a maximum of 16 colors and a maximum resolution of 640×480.
  To test support for a background image in GRUB2, l took a Fedora 12 background image and converted it into TGA format using GIMP. Why TGA? No particular reason. I could have just as easily used JPEG or PNG formats. I placed this image in the ESP GRUB2 subdirectory.
  Next I needed to obtain a suitable glyph (font) file for displaying characters when in graphics mode. GRUB2 uses PFF2 bitmap fonts. Rather than going to the trouble of creating my own PFF2 file, I simply extracted the font file unicode.pf2 from the Debian grub-common_1.98 package.
  Finally, as shown below, I modified grub.cfg to load and configure the appropriate modules and display the background image.
  #
  # FPM 3/19/10
  #
  timeout=20
  default=0
  if loadfont /efi/grub2/unicode.pf2
  then
  set gfxmode="1024x768x32"
  set gfxpayload=keep
  insmod gfxterm
  insmod efi_gop
  terminal_output gfxterm
  terminal gfxterm
  fi
  use_bg=true
  backgound_image /efi/grub2/fedora.tga
  }
  menuentry "Reboot" {
  reboot
  }
  menuentry "Exit to EFI Shell" {
  quit
  }
  You will notice that GRUB2 supports a rudimentary scripting language. Here I test that the font file /efi/grud2/unicode.pf2 is loaded before the gfxterm and efi_gop modules are loaded and configured. When I rebooted the system and invoked GRUB2 from the EFI shell, the specified Fedora backgound image covered the whole screen without a border and characters were correctly displayed.
  Is GRUB2 a viable option for EFI-booting Fedora 12 at this time? Yes, provided that it is modified to minimize the load delay caused by the default small disk caches. Do I like GRUB2? Yes. Actually I love the flexibility and additional functionality it provides. Broadening the question further, is GRUB2 ready for primetime use and should Fedora switch to GRUB2 in the near future? The Ubuntu, Gentoo and Debian distributions of GNU/Linux certainly think so and their latest releases utilize it as the default bootloader. My answer to both questions is probably no. I personally think GRUB2 requires some work to harden the product – especially for EFI-booting. Other reasons include a lack of accurate, up-to-date and complete end-user documentation and an over-complex product. By over-complex product, I mean the large number of modules and other files. Many of the modules, for example minix.mod, are of no use to users of Fedora on an IA32 or X64 platform and should not be distributed as part of a Fedora RPM.
  There is a GRUB2 RPM available for Fedora 12. However it contains all the available loadable modules irrespective of whether they are of any use to Fedora users. Worse still, it installs all the modules under /usr/lib/grub2/i386-pc/. Why not just put them under /usr/lib/grub2? What value does the extra i386-pc add? I am on an x86-64 platform; I do not expect to find modules that I need in a directory called i386-pc. Yes, I understand that the GRUB2 boatloader always uses 32-bit modules but that fact does not need to be embedded in a subdirectory name. In addition, two important files are missing from the RPM, i.e. the font files unicode.pf2 and ascii.pf2. Without these files, background images are not possible.
  Should Fedora switch to using GRUB2 in the long term? Certainly. The extra features such as loadable modules, scripting and localization support are frankly very compelling.
  Thanks for the information. It’s nice to know I’m doing something right!
  Nice to read your blog. I have “old” MacBook 2.1 and run smoothly Fedora 12 i386. I used netinst CD to set up the fedora, but netinst amd64 can not boot on the machine. The Fedora 12 boot fast (3 seconds) with built-in grub-efi, my machine is single boot fedora 12.
  On other disk I setup gentoo amd64. all installation went well but I faced anoying “long” booting before Grub “face” appear, about 40 seconds :=))
  Once I have time I will follow your tutorial on your blog. Thanks for appoint good clue
  rgds
  sts
  Nice article. I use tianocore.sourceforge.net EDK DUET UEFI64 (UEFI 2.1 x86_64) firmware booting from 1 GB USB pendrive (). I have both Windows 7 x64 Pro (UEFI-GPT) and Archlinux x86_64 booting using GRUB2 UEFI and GRUB2 BIOS (compile scripts – GRUB2 UEFI and GRUB2 BIOS ).
  You should actually mention all this in grub-devel mailing list () for grub2 devs to take notice.
  I hve a problem booting Archlinux in GRUB2 UEFI x86_64. Before Archlinux I had Fedora 12 x86_64. When Fedora 13 released, I changed over to Arch for its rolling release system. Arch boots fine in GRUB2 BIOS, but in GRUB2 UEFI I get “VFS cannot open root device” and “append correct root= option” errors and a kernel panic with CAPS LOCK blinking and unresponsive keyboard and touchpad (bug-grub report and Archlinux bug report ).
  It seems like the initramfs is loaded in the memory but not correctly passed to Archlinux kernel. Fedora boots fine because of all required disk controller drivers and FS drivers built-in in the kernel. But in Archlinux, except the very basic requirements, all disk controller and FS support are compiled as external modules. So it is impossible to boot Archlinux without initramfs. Archlinux uses BSD style init framework.
  Do you know what is actually wrong? The culprit might be (grub2-source-dir)/loader/i386/efi/linux.c . Fedora’s grub-legacy grub.efi (extracted using p7zip from x86_64 rpm) boots Archlinux without any errors, so I guess the problem is with grub2. I am not a programmer but I like to tinker a lot. Any help would be appreciated. Thank you.
  Can you send your quit.mod source to grub-devel mailing list, if signing copyright assignment to FSF is okay?
  […] […]
  thanks for this post….very helpfull…
  going to bookmark your site!!!!!!!
  Enter your email address