带EFI支持的GRUB2安装全记录
关键词: EFI GRUB2 efibootmgr Gentoo LINUX Windows 7 Mac OS X multiboot ==2020-05-29 修订===== 做为对传统引导程序grub的升级版本, Grub2的功能非凡, 他的不俗表现, 至少有两方面, 1, Grub2可以识别当前使用的大多数文件系统, 无论在GPT还是MBR格式的.2, Grub2可以采用更灵活的模块和脚本来引导大部分操作系统和ISO. 不过Grub2在提供更大的便利的同时, 也失去了自己编辑启动文件的可能, 任何变动都需要通过grub2来更新. 本文将对grub2从编译到安装,配置更方面进行详细描述. 平台为Gentoo Linux. 1, 编译带EFI支持的Grub2 export GRUB_PLATFORMS="emu efi-32 efi-64 pc coreboot multiboot qemu" USE="device-mapper doc efiemu fonts -libzfs mount multislot nls sdl static -test themes truetype" emerge -v grub #采用带64位EFI支持的USE进行编译. linux大多数都是64位的了,所有Platforms可以视情况把32位平台全关闭。 2, 安装Grub2 首先需要准备EFI分区. 在这里, Windows 7安装的EFI分区, 可以直接使用, 有关Windows7的信息不会被复写. 启动Gentoo Linux或者其他Linux Live CD并chroot到本地硬盘 mkdir -p /boot # 创建mount点, 主要用来mount本地系统 mount /dev/sda1 /mnt/efi # 假设EFI分区为sda1, 将它挂在/mnt/efi目录下. 执行Grub2安装命令, 为了文件管理方便, 直接将文件安装在EFI分区的/grub2目录下. # grub-install --directory=/usr/lib/grub/x86_64-efi --target=x86_64-efi --root-directory=/mnt/efi --efi-directory=/mnt/efi --bootloader-id=grub2 --removable sda1 --directory #定义了grub2安装的源文件位置, 缺省为/usr/lib64/grub/x86_64-efi --target #定义了目标文件格式, 比如是64或32位EFI模式, 还是GRUB2-BIOS模式. --root-directory #定义文件复制目标位置. 复制到哪里去? -- efi-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 /usr/sbin/grub-install --directory=/usr/lib/grub/x86_64-efi --target=x86_64-efi --efi-directory=/mnt/efi --boot-directory=/mnt/efi --bootloader-id=GRUB2 --removable sda1 Installing for x86_64-efi platform. Installation finished. No error reported. 该操作将复制所需要各种的mod, pf2字体, theme主题到/mnt/efi/grub下, 因此不再需要手工安装复制. 将grub2安装到EFI分区时, 同时会自动创建一个grub.efi的文件。理论上要求root/efi-directory都直接写这个mount点, 重新启动时就能自动挂起来。如果想先安装在系统的根或其他目录,然后再复制到EFI分区,就会出现grub rescue, prefix not set,unknown filesystem或者没菜单等各种蛋疼的问题,这是因为前面生成的EFI只把相关linux分区格式加起来了,而且指定去那个目录查找grub.cfg文件。 太智能了,但是手册也不写明白,让人恶心。 3, (可选步骤) 创建启动映像或bootloader. 对于EFI分区, 这个东西可以做,也可以不做。但是如果做不好的话,生成的EFI文件会一直报prefix not set, 然后卡死在那里。 还不如直接用系统生成的呢。 #grub-mkimage -d /usr/lib/grub/x86_64-efi -O x86_64-efi -p /grub -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/lib/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, 创建启动配置文件 #grub-mkconfig -o /boot/grub/grub.cfg 将启动文件复制到EFI分区的/grub目录下. GRUB 2 配置文件默认位置是 /boot/grub/grub.cfg。也有些 Linux 软件包使用 /boot/grub2/grub.cfg,同时启用 GRUB Legacy 和 GRUB 2 安装程序。这里需要自己了解, 到底哪个文件是grub2使用的. 在gentoo下, grub:2只使用安装目录,如/grub下的grub.cfg 5, 创建自定义启动配置文件 自定义启动文件需要在/etc/grub.d/之下, 进行编辑, 复制一个模版, 修改完成后, 再调用grub-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