带EFI支持的GRUB2安装全记录

版权归作者所有,任何形式转载请联系作者。
作者:keenshoes(来自豆瓣)
来源:https://www.douban.com/note/210077866/
 
关键词:
EFI
GRUB2
efibootmgr
Gentoo LINUX
Windows 7
Mac OS X
multiboot

    做为对传统引导程序grub的升级版本, Grub2的功能非凡, 他的不俗表现, 至少有两方面, 1, Grub2可以识别当前使用的大多数文件系统, 无论在GPT还是MBR格式的.2, Grub2可以采用更灵活的模块和脚本来引导大部分操作系统和ISO. 不过Grub2在提供更大的便利的同时, 也失去了自己编辑启动文件的可能, 任何变动都需要通过grub2来更新.
     本文将对grub2从编译到安装,配置更方面进行详细描述.  平台为Gentoo Linux.

1,   编译带EFI支持的Grub2
      echo 'sys-boot/grub:2' >> /etc/portage/package.unmask     #unmask grub:2
      export GRUB_PLATFORMS="emu efi-32 efi-64 pc coreboot multiboot qemu"
      USE="x86_64-efi-64" emerge -v grub:2      #采用带64位EFI支持的USE进行编译.

2,   安装Grub2
      首先需要准备EFI分区.  在这里, Windows 7安装的EFI分区, 可以直接使用, 有关Windows7的信息不会被复写.
      启动Gentoo Linux或者其他Linux Live CD并chroot到本地硬盘
       mkdir -p /boot    # 创建mount点
       mount /dev/sda2   /mnt/efi # 假设EFI分区为sda2, 将它挂在/mnt/efi目录下.

      执行Grub2安装命令, 为了文件管理方便, 直接将文件安装在EFI分区的/grub2目录下.
     # grub2-install --directory=/usr/lib64/grub/x86_64-efi --target=x86_64-efi --root-directory=/mnt/efi --boot-directory=/mnt/efi --bootloader-id=GRUB2 --removable  sda1
       --directory     #定义了grub2安装的源文件位置, 缺省为/usr/lib64/grub/x86_64-efi
       --target         #定义了目标文件格式, 比如是64或32位EFI模式, 还是GRUB2-BIOS模式.
       --root-directory  #定义文件复制目标位置.  复制到哪里去?
       -- boot-directory  #定义启动目录, 缺省带/boot/grub2的prefix, 所以我们直接定义/就可以.
                     但是,如果安装到EFI的系统上, 直接把EFI的mount点写上去。

=====2016-02-26========
新版的grub2已经找不到boot-directory这个参数了,特别时EFI安装时,需要变更为--efi-directory,不然会cannot find EFI directory的错误。
grub2-install --directory=/usr/lib64/grub/x86_64-efi --target=x86_64-efi --efi-directory=/mnt/efi --boot-directory=/mnt/efi --bootloader-id=GRUB2 --removable sda1
======================

       该操作将复制所需要各种的mod, pf2字体, theme主题到指定位置, 因此不再需要手工安装复制.

       将grub2安装到EFI分区时, 同时会自动创建一个grub.efi的文件。理论上要求root/boot-directory都直接写这个mount点, 重新启动时就能自动挂起来。如果想先安装在系统的根或其他目录,然后再复制到EFI分区,就会出现grub rescue, prefix not set,unknown filesystem或者没菜单等各种蛋疼的问题,这是因为前面生成的EFI只把相关linux分区格式加起来了,而且指定去那个目录查找grub.cfg文件。 太智能了,但是手册也不写明白,让人恶心。

3,    创建启动映像或bootloader.
       对于EFI分区, 这个东西可以做,也可以不做。但是如果做不好的话,生成的EFI文件会一直报prefix not set, 然后卡死在那里。 还不如直接用系统生成的呢。
       #grub2-mkimage -d /usr/lib64/grub/x86_64-efi -O x86_64-efi -p /grub2 -o /boot/grub/grub2-x86_64-efi.efi part_gpt part_msdos gpt hfs hfsplus btrfs fat ext2 iso9660 reiserfs scsi normal configfile chain appleldr configfile linux multiboot boot efi_gop apple linux echo cpio sh cat cpio hexdump ls date minicmd
        -d  定义源文件位置.  缺省为/usr/lib64/grub/{ARCH}
        -O 定义输出格式, 也就是所谓的Target, 可以通过{TARGET}来定义调用
        -p  定义配置文件和mod文件的位置(在EFI分区的相对位置),  -p是个很蛋疼的参数。在grub.cfg里一定要设置。不然麻烦的很。
        -o  定义本次编译的文件名字和位置.
        后面附加的是将要编译进bootloader的模块, 将一些常用的模块编译进就可以了, 不常用的模块, 在使用时可以通过insmod直接调用.  boot halt reboot help fshelp minicmd echo等常用功能建议编译进去. 这样在EFI启动模式可以方便的关机重启.
      想编译MBR格式的将输出定义为  -O gr2ldr 就可以了. gr2ldr可以被其他bootloader调用.

      注意: 因为编译的EFI/gr2ldr对地址都是硬编码的, 所以关联文件的位置就比较重要, 不然启动的时候会出现加载不上模块, 或者显示不出菜单等问题.

4,  创建启动配置文件
     #grub2-mkconfig -o /boot/grub2/grub.cfg
     将启动文件复制到EFI分区的/grub2目录下. GRUB 2 配置文件默认位置是 /boot/grub/grub.cfg。也有些 Linux 软件包使用 /boot/grub2/grub.cfg,同时启用 GRUB Legacy 和 GRUB 2 安装程序。这里需要自己了解, 到底哪个文件是grub2使用的.
      在gentoo下, grub:2只使用grub2下的grub.cfg
     
5,  创建自定义启动配置文件
     自定义启动文件需要在/etc/grub.d/之下, 进行编辑, 复制一个模版, 修改完成后, 再调用grub2-mkconfig就可以将文件加进去了.
     因为grub.cfg对格式有一定要求, 因此自行修改grub.cfg文件, 可能会出现菜单不显示, grub引导不成功等问题. 另外直接修改的grub.cfg, 在下次调用mkconfig后就会被自动覆盖掉, 所以一定要及时备份.
     自定义的cfg文件, 行尾一定不能有空格等空字符.
      grub2对格式检查很严格, 所有的custom文件, 必须以有exec tail的内容在首.
     所有的grub2配置命令 ,都可以在grub>模式下调试

例子:
通过GRUB2调用EFI启动Windows 7
# grub2-probe --target=fs_uuid /boot/efi/efi/Microsoft/Boot/bootmgfw.efi
E1A8-BA25
# grub2-probe --target=hints_string /boot/efi/efi/Microsoft/Boot/bootmgfw.efi
--hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2
#这个参数hints_string在新版本的Grub2-probe中已经废弃.

在获得Windows 7的UUID和hints_string后, 可以直接编写cfg.
menuentry "Microsoft Windows x86_64 UEFI-GPT" {
    insmod part_gpt
    insmod fat
    insmod search_fs_uuid
    insmod chain
    search --fs-uuid --no-floppy --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 E1A8-BA25
    chainloader /efi/Microsoft/Boot/bootmgfw.efi
}

另Windows 7带EFI有更简单的启动模式,  可以启动. 但chainloader +1的模式需要MBR的boot code配合, 在GPT的系统里不工作.
menuentry "Windows 7" {
        set root='(hd0,gpt2)'
        chainloader /EFI/microsoft/BOOT/bootmgfw.efi
}

通过grub2引导Gentoo Linux
menuentry 'Gentoo GNU/Linux' {
    load_video
    insmod gzio
    insmod part_gpt
    insmod fat
    set root='hd0,gpt7'
    linux    /root/kernel-3.1.12-gentoo root=/dev/sda7 ro  
}

通过Grub2生成的代码也可以引导Mac OSX, 但这也许还是和磁盘格式, 或者机器类型有关. 也许只有纯种的Mac机器才支持这代码. 否则大部分生成的代码都不运行的.

=====以下命令,未曾在gentoo下测试====
引导ISO文件是非常容易了, 但也并不是想象的那么方便. 因为ISO文件本身千变万化, 千差万别. 无论你通过什么方式引导ISO,都要包含一定的逻辑, 将系统的控制权转交出去. 引导ISO是个技术货, 每个ISO都有自己不同的引导参数和机制.
引导基于Linux的系统, 至少要有两个方面的工作要处理. 1), 定义iso文件的位置, 并传递给被引导系统, 以便在系统引导起来后, 可以把这个iso做为cdrom看待. 这个定义通常是在initrd中进行定义(/proc/cmdline). 每种系统定义的方法和方式都有所不同 2),  需要传递给内核系统的启动参数, 这可以通过查看光盘的启动文件比如grub.cfg, syslinux.cfg来确认.
menuentry "Rescure Linux ISO" {
  insmod loopback
  insmod part_gpt
  loopback loop (hd0,1)/rescure/rescure-linux.iso
  linux    (loop)/boot/rescure/linux26 isofrom=/dev/sda1/rescure/rescure-linux.iso boot=live quiet vga=791 noeject noprompt
  initrd   (loop)/boot/grmlsmall/initrd.gz
}

没有核心的类DOS盘直接用chainloader去挂.  
menuentry "Ghost for Dos" {
        loopback loop (hd0,0)/images/ghost.iso
        chainloader (loop)
}

还有一种格式的叫MEMDISK (仿真磁盘),就是把映像直接读到内存去, 然后在启动一些传统的系统. 这类磁盘包括软盘映像img , iso映像, 还有一些是硬盘分区映像等. 都通过linux16创建memdisk, 然后传递给initrd16来处理用. 适用于通过INT 13进行调用的实模式系统, 如DOS和大部分bootloader. 这里调用的磁盘映像文件可以是zip或gzip压缩格式文件, 诸如WinPE盘等。

menuentry "Boot Hardware Detection Tool from iso" {
   linux16 /memdisk iso
   initrd16 /hdt.iso
   #append iso raw
 }

menuentry 'WinPE boot system ISO' {
  set root='(hd1,gpt3)'
  echo 'Loading Memdisk...'
  insmod memdisk
  linux16 /images/memdisk iso raw
  echo 'Loading ISO...'
  initrd16 /os-set/winpe/Win10PE.iso
}
====Win10PE引导,经过验证,是成功的======



6,  将编译好的EFI添加到EFI的启动列表中, 让efi自动执行.
      efibootmgr --create --gpt --disk /dev/sda --part 1 --write-signature --label "GRUB2" --loader "\\efi\\grub2\\grub.efi"
      当然, 不修改,问题也不大, 现在大部分机器都有Boot from efi file功能, 直接选文件启动就可以了.

7,   常见问题
      a, 启动时, 看不到菜单. 有两种可能
      .系统只有一个menuentry, 系统不显示菜单, 直接引导进入, 按shift可以调出菜单.
      .配置文件位置不对, grub2找不到菜单, 会直接停在grub>的窗口.
       b, insmod提示找不到文件
        模块文件不在指定位置. 需要手工或按说明操作, 把模块文件放在EFI编码的特定位置.
       c,执行EFI文件, 没任何反应, 直接退出.
         连字体文件都没有了,  环境变量没了, 什么都跑不下去了.
       d, 编辑了grub.cfg文件, 但在菜单里看不到变化.
          编辑错了文件位置, 检查一下系统调用的是grub还是grub2下的配置文件.
       e,  通过chain0, tboot等方式引导, 进不了Mac OS X
           在GPT模式下, 所有基于MBR的东西都跑不起来, 这个系统里没有他们需要的MBR分区表, 给不了他们文件位置.
       f, 执行gptsync后, 系统分区表不见了, 数据丢失.
          活该, 在纯粹的GPT表上, 执行什么和MBR同步的命令?

8, grub rescue>的恢复
       如果grub.cfg里的配置有问题,会在启动时进入rescue模式,此时可以通过重新设置变量的方式调出grub的启动菜单。

在grub的菜单出来后,依然会有root定义错误导致系统无法启动。可以选择c或者e,对启动表项修改后进行启动。。。

9,  grub启动时,无法加载themes和background图片,进去后提示:error:no video mode activated.
      进入grub命令行
grub> videoinfo
List of supported video modes:
Legend: mask/position=red/green/blue/reserved
Adapter 'EFI GOP driver':
 0x00 1280 x 1024 x 32 (5120) Direct color ......
EDID version: 1.4
     preferred mode: 1920x1080
grub> gfxmode=1280x1024x32
grub> videotest
顺利调出图像。
由此可知,因为gfxmode设置不对,导致grub进入text模式,导致themes之类的都不正确。修改grub.cfg中的gfxmode即可。

说明:  很多人反馈, 通过grub2-mkconfig生成的Mac OSX配置, 可以直接启动机器. 估计这和机器的配置等有关系,比如MBR内容, Mac的版本等.并不是100%成功的. 猜测成功的模式和磁盘的分区格式有关, 大凡用MBR或混合磁盘格式的, 因为都含有boot123代码, 基本上都能成功.
      grub2可以引导ISO文件, 但都是带kernel的非仿真光盘. 带有特定引导扇区的实模式iso文件如何引导, 在研究中.
       对于Mac OSX在GPT盘上的引导, 有人通过打33185 patch的方式, 可以实现appleloader直接启动.  patch名字为appleloader_macbook_7_1.patch
       http://savannah.gnu.org/bugs/index.php?33185
 
        grub2里还有一个高级功能,可以把所有需要的模块,文件等放到一个文件系统映像里,然后加到core.img里。比如说,你可以把command.lst,fs.lst,grub.cfg, normal.mod和其他需要的mod文件打包到一个cpio文档里,然后用以下的命令生成core.img:
grub-mkimage -d . -o core.img -p (memdisk)/ -m cpio_image memdisk cpio
启动后,文档里的内容可以用(memdisk)来访问。

 注: 通过GRUB2引导操作系统,与硬件本身还有很大的关系。比如Pmagic,  WinPE等iso, 在新的机器上引导成功的指令,换到旧的电脑上就不成功。可能与主板本身有关系,也可能和系统启动时的内存大小有关。总会有一款适合自己,不再深究了。
===OVER====

经测试可以执行启动操作的 Linux or LiveCD,  就是有这样那样的问题, 都是细节了, 可以以后慢慢调整.
1, pmagic livecd
复制livecd里pmagic目录到/boot下, 包括bzImage, initrd.img, pmagic-VERSION.sqfs文件.
root=/dev/sda7  定义了iso文件所在分区
directory=/boot   定义pmagic-VERSION.sqfs所在位置 (具体为/boot/pmagic/pmodules/pmagic-VERSION.sqfs)
menuentry "loopback-pmagic from harddisk (ISO = pmagic-4.4.iso)" {
  loopback loop (hd0,gpt7)/images/pmagic-4.4.iso
  linux (loop)/pmagic/bzImage isofrom=/dev/sda5/pmagic-4.4.iso root=/dev/sda7 directory=boot edd=off noapic load_ramdisk=1 prompt_ramdisk=0 rw loglevel=9 max_loop=256
  initrd (loop)/pmagic/initrd.img
}

for i in $(cat /proc/cmdline); do
   case $i in
      directory=*)     directory=$(get_opt $i) ;;
      iso_location=*)  iso_location=$(get_opt $i)  ;;
      iso_filename=*)  ISO_VERSION=$(get_opt $i) ;;
      root=*)          root=$(get_opt $i)  ;;
      label=*)         label=$(get_opt $i)  ;;
      uuid=*)          uuid=$(get_opt $i) ;;
   esac
done
仔细研究pmagic文件查找逻辑, 就会发现除了directory, 还有一个iso_location的方式可以用来做为sqfs文件查找的替代方法. 这个iso_location就是在pmagic里定义查找ISO的一种方法, 和其他的grml的findiso, ubuntu的iso-scan/filename一样, 都是在initrd自行定义的.
menuentry "Parted Magic" {
    set isofile="/boot/isos/pmagic.iso"
    loopback loop $isofile
    linux (loop)/pmagic/bzImage iso_filename=$isofile edd=off noapic load_ramdisk=1 prompt_ramdisk=0 rwnomce sleep=10 loglevel=0
    initrd (loop)/pmagic/initramfs
}

pmagic的directory定义是这样的  $directory/pmagic/pmodules/PMAGIC-$VERSION.SQFS,因此定义directory时,直接定义上级目录就可以了。不过这里还有一个超级大坑,就是搜索的文件都是大写。而windows下复制文件又无法区分大小,因此经常会引起PMAGIC-$VERSION.SQFS not found的问题。只能引导到linux下重新改下文件名。

======20190401=引导Pmagic的三种模式===========
模式一: 2019版,将pmagic.sqfs打包到files.cgz模式
menuentry "Pmagic-2019-01-03-pxe from sda5)" {
  insmod ntfs
  insmod loopback
  set root=(hd1,gpt3)
  linux  /images/pmagic/bzImage64  edd=on vga=normal
  initrd /images/pmagic/initrd.img /images/pmagic/fu.img /images/pmagic/m64.img /images/pmagic/files.cgz
}
pmagic20190103版本通过加载files.cgz实现sqfs文件的加载。file.cgz为cpio格式的gz压缩包,这样可以直接引导,方便了很多很多。
解包:
#gunzip files.cgz
#cpio -idmv < files.cpio
#ls
pmagic/pmodules/PMAGIC-$VERSION.sqfs
压缩:
 find ./* | cpio -H newc -o > files.cpio (或者 find ./* | cpio -H tar -o > files.cpio)

模式二: 将pmagic解包到本地文件方式
menuentry "Pmagic-2016-10-18.iso from sda5)" {
  insmod ntfs
  insmod loopback
  set root=(hd1,gpt3)
  linux  /images/pmagic2016/pmagic/bzImage64 root=/dev/ram0 directory=images/pmagic2016 edd=on vga=normal boot=live eject=no noapic load_ramdisk=1 prompt_ramdisk=0 rw loglevel=9 max_loop=256
  initrd /images/pmagic2016/pmagic/initrd.img /images/pmagic2016/pmagic/fu.img /images/pmagic2016/pmagic/m64.img
}
回头来看pmagic2016, 就会发现在initrd启动时,会自动在directory目录下搜索pmagic/pmodules/PMAGIC-$VERSION的版本,因此在早期格式里定义的loopfile根本就是个多余的东西,直接删除。

模式三: 直接引导Pmagic LiveCD模式
menuentry "Pmagic-2016-10-18-LiveCD from sda5)" {
  insmod ntfs
  insmod loopback
  insmod png
  set root=(hd1,gpt3)
  background_image /images/pmagic/pmagic.png
  loopback loop (hd1,gpt3)/images/pmagic_2016_10_18.iso
  linux  (loop)/pmagic/bzImage64  edd=on vga=normal
  initrd (loop)/pmagic/initrd.img (loop)/pmagic/fu.img (loop)/pmagic/m64.img
}
==============================

2, Tinycore Linux
menuentry "Tinycore" {
    set isofile="/boot/isos/tinycore.iso"
    loopback loop $isofile
    linux (loop)/boot/vmlinuz loglevel=3 cde waitusb=10 linux repo=hd:/dev/disk/by-uuid/${USBUUID}:/
    initrd (loop)/boot/tinycore.gz
}
这个版本的tinycore在我机器上黑屏, 什么都看不到, 不认识我的gpt盘?

3, CDLinux 0.9.7.1
loopback loop (hd0,gpt7)/images/cdlinux/cdlinux-0.9.7.1.iso
linux (loop)/CDlinux/bzImage root=/dev/ram0 livecd quiet vga=773 noeject noprompt sleep=0 load_ramdisk=1 prompt_ramdisk=0
initrd (loop)/CDlinux/initrd
图象出来就挂了.

4, Gentoo
menuentry "...   2 - Gentoo 11 Live DVD" {
    set isofile="/livedvd-x86-amd64-32ul-2012.iso"
    search --set -f $isofile
    loopback loop $isofile
    echo    'Chargement du noyau Linux ...'
    linux (loop)/boot/gentoo64 root=/dev/ram0 looptype=squashfs loop=/image.squashfs cdroot isoboot=$isofile splash=silent,theme:livecd-10
    echo    'Chargement du disque mémoire initial ...'
    initrd (loop)/boot/gentoo64.igz
}

5, CloneZilla
menuentry "CloneZilla amd64 (800x600)" {
set isofile="/boot/clonezilla-live-1.2.6-24-amd64.iso"
loopback loop $isofile
linux (loop)/live/vmlinuz boot=live live-config noswap nolocales edd=on nomodeset ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_keymap="" ocs_live_batch="no" ocs_lang="" gfxpayload=800x600x16,800x600 ip=frommedia nosplash toram=filesystem.squashfs findiso=$isofile
initrd (loop)/live/initrd.img
}

6,  Fedora
menuentry ".. Fedora 15 Desktop AMD64 (extracted)" {
    linux /boot/iso/LiveCD-FC15/isolinux/vmlinuz0 root=UUID=8816-2C13 live_dir=/boot/iso/LiveCD-FC15/LiveOS/ rootfstype=auto ro liveimg quiet  rhgb rd.luks=0 rd.md=0 rd.dm=0 locale=fr_FR bootkbd=fr console-setup/layoutcode=fr
    initrd /boot/iso/LiveCD-FC15/isolinux/initrd0.img
}

 在grub2引导硬盘iso文件后,进入操作系统后,需要卸载它,不然会出现分区表问题。
代码: sudo umount -l /isodevice

a,   使用GRUB2引导(硬盘安装) Gentoo LiveCD 的ISO文件?

以"install-amd64-minimal-*.iso"为例。
第一步,将ISO中的'/isolinux/{gentoo,gentoo.igz}'、'/image.squashfs'三个文件放到'(hd0,gpt3)/os/gentoo/'目录中;
第二步,将ISO中的'/livecd'放到相同分区(hd0,gpt3)的根目录下;
最后,在'grub.cfg'中加入如下菜单项:
menuentry "Gentoo Minimal Install LiveCD" --unrestricted {
    linux  (hd0,gpt3)/os/gentoo/gentoo cdroot looptype=squashfs loop=/os/gentoo/image.squashfs
    initrd (hd0,gpt3)/os/gentoo/gentoo.igz
}
[提示]'livecd'是寻找'image.squashfs'所在磁盘分区的关键。
[提示] Gentoo LiveCD 亦可使用与其他Linux发行版的LiveCD类似的方法启动(也就是使用"isoboot="参数)。

b,  使用GRUB2引导(硬盘安装)各种 Linux LiveCD 的ISO文件?
这里给出的方法,只适用于提供了"img_loop="或"iso-scan/filename="或"fromiso="或"isoboot="或"isoloop="之类参数的LiveCD。
下面以 Ubuntu 的 LiveCD 为例说明。首先,假定你将ISO文件放在'(hd0,gpt3)/ISO/Ubuntu.iso';然后,在'grub.cfg'中加入如下菜单项:
menuentry "Ubuntu LiveCD" --unrestricted {
    loopback loop0 (hd0,gpt3)/ISO/Ubuntu.iso
    linux  (loop0)/casper/vmlinuz boot=casper iso-scan/filename=/ISO/Ubuntu.iso
    initrd (loop0)/casper/initrd.lz
}
[说明]这里给出的方法,其实就是各种"硬盘安装 XX Linux"的翻版,只不过不再需要将"vmlinuz"与"initrd"从ISO中解压出来而已。

c, bionicpup64, xenialpup64, slacko,   
缺少读iso的函数,无法直接通过iso文件引导。

Reference:
http://doc.ubuntu-fr.org/tutoriel/grub2_lancer_des_images_iso
 https://www.gnu.org/software/grub/manual/html_node/Images.html#Images
https://www.cnblogs.com/f-ck-need-u/archive/2017/06/29/7094693.html


posted @ 2019-10-04 23:31  行方思远  阅读(14132)  评论(1编辑  收藏  举报