# GRUB (简体中文)

翻译状态： 本文是英文页面 GRUB 的翻译，最后翻译时间：2013-11-15，点击这里可以查看翻译后英文页面的改动。

相关文章

- Burg
- GRUB Legacy
- GRUB EFI Examples

GRUB2 是下一代 GRand Unified Bootloader (GRUB,请不要和Grub Legacy混淆了)。 它来自下一代 GRUB 研究项目 PUPA，代码全部重写，实现了模块化和增强了移植性。[1].

简单的说,Boot Loader是电脑启动时运行的第一个程序,它负责装载内核并将控制权转交。内核再初始化操作系统的其它部分。

## 前言

- 官方所称的GRUB代表的是本软件的第二版,即GRUB2,请参考[2].如果你是在找有关Grub Legacy的文章,请参考GRUB Legacy.
- GRUB2支持由zlib或者LZO压缩过的Btrfs格式的根目录,如果使用Btrfs,不需要单独的`/boot`分区.
- GRUB2 不支持F2fs格式的根目录,所以你需要为`/boot`分区单独设置一个支持的文件系统.

### 使用GRUB Legacy的用户请注意

- 从GRUB Legacy升级到GRUB2和新安装一个GRUB2差不多.请参考这里
- GRUB Legacy 和 GRUB2 的内置命令有所不同(例如 "find" 已经变成 "search")，详情可见： GRUB2 命令
- GRUB2 已经模块化，不再需要"stage 1.5"。所以，启动引导器就不需要那么多功能 -- 按需从硬盘导入模块以扩展功能即可。(例如LVM 或 RAID 支持)。
- GRUB Legacy 和 GRUB2 的分区命名有变化。现在分区从1开始编号，并以分区类型开始，原来是从0开始编号。例如，`/dev/sda1`应该是 `(hd0,msdos1)` (用于MBR) 或 `(hd0,gpt1)` (用于 GPT)。注意：磁盘还是从 0 编号。
- GRUB2比GRUB Legacy更大,一般需要在`/boot`上占用约13MB空间.如果`/boot`分区小于32MB,你启动的时候就会遇到空间问题,pacman会拒绝安装新内核.

#### 备份重要资料

尽管从Grub Legacy到GRUB2的升级过程很平滑,我们还是建议在升级到GRUB2之前备份Grub Legacy配置文件.

    # mv /boot/grub /boot/grub-legacy

备份MBR(使用你的磁盘路径来代替`/dev/sd"X"`):

    # dd if=/dev/sdX of=/path/to/backup/mbr_backup bs=512 count=1

MBR的前446字节存储了启动程序,后面的64字节存储的是分区表.如果想在恢复之后保持之前的分区状况,强烈建议只备份启动程序

    # dd if=/dev/sdX of=/path/to/backup/bootcode_backup bs=446 count=1

如果没有成功安装GRUB2,请参考恢复GRUB Legacy.

### GRUB2 所需条件

#### BIOS 系统

##### GPT专用指令

BIOS-GPT方案中的GRUB2需要一个启动分区以便植入core.img,因为 GPT 分区系统中 MBR 后面没有了 32 KiB 的空间(已经被 GPT 主头部和主分区表占据).此分区仅在 BIOS-GPT 配置中有用.MBR方案中没有这种分区类型.UEFI也无需这个分区,因为其中并没有嵌入启动扇区. GPT分区方案也会创建一个受保护的MBR分区以防未知程序修改它.你可能需要将这个分区设为可启动的,否则系统可能会无法启动. 对于BIOS-GPT方案,使用gdisk(cgdisk或者GNU Parted)在磁盘最见面建立一个1007KiB的无文件系统的分区.1007KiB的大小会让后面的分区自动对齐到1024KiB的位置.如果需要,这个分区也可以位于磁盘上的任何位置,不过需要在前2TiB的空间内.在gdisk(cgdisk)里面将这个分区的类型设为ef02,如果使用GNU Parted,需要设置BOOT_PART_NUM bios_grub选项.

Note:

- 这个分区应该在grub-install或者grub-setup运行前建立
- 如果你在其他分区建立以后再建立此分区,gdisk只允许将这个分区建立在浪费空间最小的位置上(sector 34-2047).因为gdisk会尽可能的将分区对齐到2048号扇区上.

##### MBR专用指令

一般来说,如果使用兼容DOS的分区对齐模式,MBR后面空间(post-MBR gap)的大小都是31KiB(MBR和第一个分区之间的空间).不过,为了提供足够的空间嵌入GRUB的`core.img`文件(FS#24103),建议将这个空间设置到1到2Mib.最好使用支持1MiB分区对齐的分区软件来分区,因为这样也能满足非512B扇区磁盘分区的需求.

#### UEFI 系统

Note: 建议阅读并理解UEFI, GPT and UEFI Bootloaders

##### Check if you have GPT and an ESP检查你是否使用GPT和ESP

如果想要使用EFI在某个磁盘上进行启动,那么就需要对这个磁盘进行EFI系统分区(EFI System Partition,即ESP),GPT倒不是必须的,不过我们还是高度建议使用GTP,并且这也是本篇文章当前支持的方法.如果你在一个支持EFI,并且已经有操作系统的电脑上安装Arch(比如Windows 8),那么你已经有了ESP了.可以通过`parted`来列出启动磁盘上的分区表以检查其是否支持GPT和ESP(假设这个启动磁盘是/dev/sda)

    # parted /dev/sda print

如果使用GPT,那么会出现"分区表:GPT".如果使用EFI,那么会有一个文件系统为vfat的小分区(一般小于512MiB)并且被标志为启动分区.在这个小分区上,应该有一个名为EFI的文件夹.如果这些条件都满足,那么这就是ESP了.注意分区序号,因为之后安装GRUB2时你需要mount它.

##### 建立ESP

如果你没有ESP,请参考UEFI#EFI System Partition的引导来创建它

## 安装

### BIOS系统

可以使用pacman从官方仓库安装grub包.安装完成后它会代替grub-legacy.

Note: 简单的安装Grub包并不会更新`/boot/grub/i386-pc/core.img`和`/boot/grub/i386-pc`里的GRUB模组.需要使用下面介绍的`grub-install`来手动更新它们.

#### 安装Boot文件

有三种方式安装GRUB Boot文件:

- 安装到磁盘上 (推荐方式)
- 安装到分区或者无分区磁盘上 (不推荐)
- 只生成core.img文件 (最安全的方法, 但是需要另外的bootloader,比如Syslinux来进行链式加载`/boot/grub/i386-pc/core.img`)

Note: 请参考http://www.gnu.org/software/grub/manual/html_node/BIOS-installation.html 获取更详尽的资料

##### 安装到磁盘上

Note: 这种方法只限于将GRUB安装到可分区磁盘(MBR或GPT)
,GRUB 文件会被安装到`/boot/grub`,1st stage code会被安装到MBR的启动代码区域(以便和MBR分区表分开).对于无分区磁盘,请参考#Install to partition or partitionless disk}}

以下命令会将`grub`安装到MBR的启动代码区域,填充`/boot/grub`文件夹,生成`/boot/grub/i386-pc/core.img`,将其嵌入post-MBR gap或者放入BIOS boot partition中(分别对应MBR分区表和GPT分区表):

    # grub-install --target=i386-pc --recheck --debug /dev/sda

Note:

- `/dev/sda` 只是示例.
- `--target=i386-pc`指示`grub-install`是为使用BIOS的系统安装. 推荐一直标明这点以防混淆.

如果你使用LVM来进行启动,你可以将GRUB安装在多个物理磁盘上. 执行`grub-install`并不会生成GRUB配置文件,请移至#生成GRUB配置文件一节

##### 安装到分区上或者无分区磁盘上

Note: GRUB并不推荐将其安装到分区启动扇区或者无分区磁盘上(Grub Legacy和syslinux相反).这种安装方式不安全,当升级时可能会损坏.Arch开发人员也不支持这种方式

下面的命令将会将GRUB2安装到分区扇区或者无分区磁盘上(比如闪存上):

    # chattr -i /boot/grub/i386-pc/core.img
    # grub-install --target=i386-pc --recheck --debug --force /dev/sdaX
    # chattr +i /boot/grub/i386-pc/core.img

Note:

- `/dev/sda` 只是示例.
- `--target=i386-pc`指示`grub-install`是为使用BIOS的系统安装. 推荐一直标明这点以防混淆.

必须使用`--force`选项来启用对blocklists(块列表)的支持,不应使用`--grub-setup=/bin/true`(这个选项的效果类似于只生成`core.img`) `grub-install` will give out warnings like which should give you the idea of what might go wrong with this approach: `grub-install`会生成以下警告,你可以通过这些警告判断发生了什么问题:

    /sbin/grub-setup: warn: Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.
    /sbin/grub-setup: warn: Embedding is not possible. GRUB can only be installed in this setup by using blocklists.
                            However, blocklists are UNRELIABLE and their use is discouraged.

如果不指定`--force`选项,会出现以下错误,并且不会将启动代码安装到启动扇区上:

    /sbin/grub-setup: error: will not proceed with blocklists

而指定了`--force`,会出现:

    Installation finished. No error reported.

`grub-setup`不默认允许这种情况的原因是,在分区或者无分区磁盘上,`grub`依赖于嵌入分区引导扇区的块列表(blocklists)来定位`/boot/grub/i386-pc/core.img`和`/boot/grub`.而`core.img`在分区上的扇区位置很有可能随着分区文件系统的更改而变化(复制文件,删除文件等).详情请参考https://bugzilla.redhat.com/show_bug.cgi?id=728742 和 https://bugzilla.redhat.com/show_bug.cgi?id=730915.

临时解决方案是给`/boot/grub/i386-pc/core.img`文件加"不可变"(immutable)标志.只有当将`grub`安装到分区启动扇区或者无分区磁盘上时才需要给core.img加"不可变"标志. 执行`grub-install`并不会生成GRUB配置文件,请移至#生成GRUB配置文件一节

##### 只生成core.img

通过添加`--grub-setup=/bin/true`选项,`grub-install`命令会填充`/boot/grub`文件夹并生成`/boot/grub/i386-pc/core.img`,但是不会将grub启动引导代码嵌入到MBR,post-MBR gap和分区引导扇区中:

    # grub-install --target=i386-pc --grub-setup=/bin/true --recheck --debug /dev/sda

Note:

- `/dev/sda` 只是示例.
- `--target=i386-pc`指示`grub-install`是为使用BIOS的系统安装. 推荐一直标明这点以防混淆.

生成后,Grub Legacy或者syslinux就可以通过链式加载GRUB2的`core.img`来间接加载Linux内核或者多启动内核了.

#### 生成GRUB配置文件

最后,生成GRUB2所需的配置文件(在配置章节会详述):

    # grub-mkconfig -o /boot/grub/grub.cfg

Note: 文件路径是`/boot/grub/grub.cfg`, 而不是`/boot/grub/i386-pc/grub.cfg`.

如果GRUB在启动时报错"no suitable mode found",请参考#"No suitable mode found" error.

如果`grub-mkconfig`执行失败,可以通过如下方式将`/boot/grub/menu.lst`文件转化为`/boot/grub/grub.cfg`

Note: 这种方法只适合BIOS,不适合UEFI

    # grub-menulst2cfg /boot/grub/menu.lst /boot/grub/grub.cfg

示例如下:

    /boot/grub/menu.lst

    default=0
    timeout=5

    title  Arch Linux Stock Kernel
    root   (hd0,0)
    kernel /vmlinuz-linux root=/dev/sda2 ro
    initrd /initramfs-linux.img

    title  Arch Linux Stock Kernel Fallback
    root   (hd0,0)
    kernel /vmlinuz-linux root=/dev/sda2 ro
    initrd /initramfs-linux-fallback.img

    /boot/grub/grub.cfg

    set default='0'; if [ x"$default" = xsaved ]; then load_env; set default="$saved_entry"; fi
    set timeout=5

    menuentry 'Arch Linux Stock Kernel' {
      set root='(hd0,1)'; set legacy_hdbias='0'
      legacy_kernel   '/vmlinuz-linux' '/vmlinuz-linux' 'root=/dev/sda2' 'ro'
      legacy_initrd '/initramfs-linux.img' '/initramfs-linux.img'

    }

    menuentry 'Arch Linux Stock Kernel Fallback' {
      set root='(hd0,1)'; set legacy_hdbias='0'
      legacy_kernel   '/vmlinuz-linux' '/vmlinuz-linux' 'root=/dev/sda2' 'ro'
      legacy_initrd '/initramfs-linux-fallback.img' '/initramfs-linux-fallback.img'
    }

如果你忘记创建GRUB配置文件`/boot/grub/grub.cfg`,然后直接重启到了GRUB命令行界面,输入以下命令:

    sh:grub> insmod legacycfg
    sh:grub> legacy_configfile ${prefix}/menu.lst

选择启动到Arch下然后再重新创建合适的GRUB配置文件`/boot/grub/grub.cfg`

#### 多系统启动

为了实现多系统启动,需要安装os-prober.安装后,再执行`grub-mkconfig -o /boot/grub/grub.cfg`.如果执行失败,可能就需要手动添加启动条目了.(后面有指导)

Note: 如果找不到Windows,可以将其boot partition挂载后再试

##### 在BIOS-MBR模式下安装的Microsoft Windows

Note: GRUB支持直接从`bootmgr`启动,现在不再需要链式加载分区启动扇区了
Warning: `bootmgr`位于系统分区(system partition),而不是Windows系统所在的分区(比如C盘).在uuid-卷名列表中,系统分区是那个名为`LABEL="SYSTEM RESERVED"` o或 `LABEL="SYSTEM"`的项,而且这个分区一般只有100到200MB大(和Arch的启动分区差不多).请参考Wikipedia:System partition and boot partition

本节假设你的Windows分区是`/dev/sda1`.首先,找到Windows系统分区的UUID(Windows's SYSTEM PARTITION,`bootmgr存放其上`).如果Windows `bootmgr`的位置是`/media/SYSTEM_RESERVED/bootmgr`,对于 Windows Vista/7/8,执行:

    # grub-probe --target=fs_uuid /media/SYSTEM_RESERVED/bootmgr
    69B235F6749E84CE

    # grub-probe --target=hints_string /media/SYSTEM_RESERVED/bootmgr
    --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1

Note: 对于Windows XP, 请在上面的命令中用`NTLDR`替代`bootmgr`. 注意,可能`NTLDR`不是在名为"SYSTEM_RESERVED"的分区上,请在XP系统所在的分区上寻找 `NTLDR`

接着,将下面的代码添加到`/etc/grub.d/40_custom` 或者`/boot/grub/custom.cfg`中.然后,使用`grub-mkconfig`重新生成`grub.cfg`,这样就能在BIOS-MBR配置下使用GRUB2引导启动Windows系统了:

对于 Windows Vista/7/8

    if [ "${grub_platform}" == "pc" ]; then
      menuentry "Microsoft Windows Vista/7/8 BIOS-MBR" {
        insmod part_msdos
        insmod ntfs
        insmod search_fs_uuid
        insmod ntldr
        search --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 69B235F6749E84CE
        ntldr /bootmgr
      }
    fi

对于Windows XP

    if [ "${grub_platform}" == "pc" ]; then
      menuentry "Microsoft Windows XP" {
        insmod part_msdos
        insmod ntfs
        insmod search_fs_uuid
        insmod ntldr
        search --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 69B235F6749E84CE
        ntldr /bootmgr
      }
    fi

Note: 在某些情况下,可能在安装Windows 8之前就已经安装了GRUB.启动Windows时可能会`\boot\bcd`报错(错误代码为`0xc000000f`).可以通过Wondows Recovery Console来修复这个错误:

    x:\> "bootrec.exe /fixboot"
    x:\> "bootrec.exe /RebuildBcd".

不要使用`bootrec.exe /Fixmbr`,因为那会将GRUB清除掉

`/etc/grub.d/40_custom`可以做为创建`/etc/grub.d/nn_custom`的模板.`nn`定义了脚本执行的优先级.脚本执行的顺序又决定了grub引导启动目录的内容.

Note: `nn` 应该比06大,这样才能确保必要的脚本被优先执行

### UEFI系统

Note: 众所周知,不同的主板厂商的UEFI实现方式也不一样.我们鼓励用户将其配置过程中遇到的问题及其细节分享出来.为了保证GRUB页面的简洁,请参考GRUB EFI Examples

首先,安装grub, dosfstools, efibootmgr(后面两个包是为了让GRUB支持EFI).然后按下面的指导进行配置.

Note: 简单的安装这些包并不会更新`core.efi`和ESP中的GRUB模组.请按下面的指导手动进行配置

#### 安装boot文件

##### 推荐方法

Note:

- 下面的命令是假设你正在为`x86_64-efi`安装GRUB.(如果是为`IA32-efi`安装GRUB,请用`i386-efi`代替`x86_64-efi`)
- 如果要成功执行下面的命令,你需要使用UEFI启动而不是BIOS.如果你从USB驱动器中的ISO文件启动系统,那么可以判断,你已经是从BIOS启动了.你需要建立一个UEFI可启动USB磁盘,然后重启,否则grub-install会报错.

首先,将ESP挂载上(一般挂在到`/boot/efi`上,然后将其路径赋值到$esp).如果是第一次安装GRUB,你可能需要建立`/boot/efi`文件夹 然后,将GRUB UEFI应用安装到`$esp/EFI/grub`,将其模组安装到`/boot/grub/x86_64-efi`:

    # grub-install --target=x86_64-efi --efi-directory=$esp --bootloader-id=grub --recheck --debug

Note:

- 如果grub-install在sysfs和procfs上运行的时候报错"modprobe efivars",尝试Unified_Extensible_Firmware_Interface#Switch_to_efivarfs.
- 如果没有`--target` 或`--directory` 选项,grub-install就不能决定安装哪种固件.在这个情况下,grub-install会报错`source_dir does not exist. Please specify --target or --directory`.
- `--efi-directory` and `--bootloader-id`是只适用于GRUB UEFI的选项.`--efi-directory`替代`--root-directory`指定ESP的挂载点.`--bootloader-id`指定存放`grubx64.efi`文件的目录名
- 可能你会注意到,不像安装GRUB到BIOS那样,在`grub-install`命令后没有<device_path>选项(例如`/dev/sda`).哪怕提供了<device_path>,也会被安装脚本忽略.因为UEFI bootloader不使用MBR或者分区启动扇区.

现在GRUB已经安装好了.请移至配置一节继续.

##### 其他方法

如果你想将所有的GRUB boot 文件放在ESP中,请给grub-install命令添加`--boot-directory=$esp/EFI`选项:

    # grub-install --target=x86_64-efi --efi-directory=$esp --bootloader-id=grub --boot-directory=$esp/EFI --recheck --debug

下面的命令会将GRUB模组文件放在`$esp/EFI/grub`中.使用这个方法,grub.cfg也会被放在ESP中,所以请确保grub-mkconfig指向了正确的地方:

    # grub-mkconfig -o $esp/EFI/grub/grub.cfg

配置档和BIOS-GRUB是一样的.

#### 在固件启动管理器中创建GRUB条目

`grub-install`会自动尝试在启动管理器中创建GRUB条目.如果没有成功,请参考Beginners' guide#GRUB,里面有关于使用`efibootmgr`创建启动目录条目的介绍.一般来说,这个问题都是因为你没有以UEFI模式启动CD/USB造成的.请参考UEFI#Create UEFI bootable USB from ISO.

#### 创建GRUB Standalone模式的UEFI应用程序

可以建立一个`grubx64_standalone.efi`,这个应用将所有的模组嵌入自身的memdisk中,所以就不需要使用单独的目录来存放GRUB UEFI模组和其他相关文件了,使用grub包里的`grub-mkstandalone`可以实现这个功能.

最简单的的方法就是使用`grub-mkstandalone`,不过,我们还可以指定嵌入哪些模组:

    # grub-mkstandalone --directory="/usr/lib/grub/x86_64-efi/" --format="x86_64-efi" --compression="xz" \
    --output="$esp/EFI/grub/grubx64_standalone.efi" <你想嵌入的模组>

`grubx64_standalone.efi`文件要求将`grub.cfg`放置到`(memdisk)/boot/grub`中,而这个memdisk是嵌入到EFI应用当中的.`grub-mkstandlone`脚本允许传递将要嵌入memdisk的文件列表.(上面命令里的"<你想嵌入的模组>")

如果你的`grub.cfg`的路径是`/home/user/Desktop/grub.cfg`,那么需要创建一个临时的`/home/user/Desktop/boot/grub/`目录,然后将grub.cfg复制到其中并进入这个目录并运行:

    # grub-mkstandalone --directory="/usr/lib/grub/x86_64-efi/" --format="x86_64-efi" --compression="xz" \
    --output="$esp/EFI/grub/grubx64_standalone.efi" "boot/grub/grub.cfg"

进入`/home/user/Desktop/boot/grub/`但是传递`boot/grub/grub.cfg`参数(请注意是`boot/`而不是`/boot/`)的原因是`grub-mkstandalone`会自动将boot/grub/grub.cfg处理为`/(memdisk)/boot/grub/grub.cfg`

如果你传递`/home/user/Desktop/grub.cfg`,那么处理后的结果会是`(memdisk)/home/user/Desktop/grub.cfg`.如果传递`/home/user/Desktop/boot/grub/grub.cfg`,那么结果就是`(memdisk)/home/user/Desktop/boot/grub/grub.cfg`.所以需要进入`/home/user/Desktop/boot/grub/`并传递`boot/grub/grub.cfg`参数,因为这样才能生成`grub.efi`需要的`(memdisk)/boot/grub/grub.cfg`.

如果需要为`$esp/EFI/arch_grub/grubx64_standalone.efi`创建一个UEFI启动器条目,使用`efibootmgr`.#Create GRUB entry in the Firmware Boot Manager里有介绍

## 配置

可以自动生成配置档,也可以手动编辑`grub.cfg`.

Note:

- 对于EFI系统,如果在安装GRUB时使用 `--boot-directory=$esp/EFI`了选项,`grub.cfg`文件必须和`grubx64.efi`放在同一文件夹.如果没有使用这个选项,那么`grub.cfg`应当在`/boot/grub/`下,和GRUB BIOS系统一样.
- 在这里可以找到关于如何配置GRUB的完整描述.

### 使用grub-mkconfig自动生成配置档

和GRUB Legacy配置文件`menu.lst`对应的GRUB配置文件是`/etc/default/grub` 和`/etc/grub.d/*`.`grub-mkconfig`使用这些文件来生成`grub.cfg`.grub-mkconfig默认输出至stdout.以下命令可以生成一个`grub.cfg`文件:

    # grub-mkconfig -o /boot/grub/grub.cfg

`/etc/grub.d/10_linux`会自动为Arch Linux设置启动项.其他操作系统的话,可能需要手动在`/etc/grub.d/40_custom`或`/boot/grub/custom.cfg`中设置.

Note: 如果你在一个chroot环境中或者systemd-nspawn容器里执行这些操作,可能完全不会成功,因为grub-probe不能获取'/dev/sdaX'这样的典型路径.这种情况下,可以尝试使用arch-chroot.

#### 额外的参数

在`/etc/default/grub`中设置`GRUB_CMDLINE_LINUX`和`GRUB_CMDLINE_LINUX_DEFAULT`变量可以实现将向Linux镜像传递额外的参数.生成`grub.cfg`时,如果遇到普通启动项,这两个参数会一起使用,遇到recovery启动项,就只使用`GRUB_CMDLINE_LINUX`参数.

没有必要两者一起使用.这两个参数很有用.比如,如果要系统支持休眠后恢复,需要使用`GRUB_CMDLINE_LINUX_DEFAULT="resume=/dev/sdaX quiet"` (`sdaX`是交换分区).这个选项会生成一个recovery启动项,这个启动项没有resume和quiet参数.其他的普通启动项也可能使用它们.(GRUB会为每个内核生成两个启动项,一个默认的一个recovery的,GRUB_CMDLINE_LINUX指定的参数会传递给这两个启动项.GRUB_CMDLINE_LINUX_DEFAULT指定的参数只会传递给默认启动项)

当生成GRUB recovery启动项时,你必须在`/etc/default/grub`中将`#GRUB_DISABLE_RECOVERY=true` 注释掉.

你也可以使用`GRUB_CMDLINE_LINUX="resume=/dev/disk/by-uuid/${swap_uuid}"`, `${swap_uuid}` 是交换分区的UUID

不同的启动项使用双引号引起来并用空格隔开.所以,对于即想使用resume又想使用systemd的用户来说,这个参数的设置可能是: `GRUB_CMDLINE_LINUX="resume=/dev/sdaX init=/usr/lib/systemd/systemd"` 更多信息请参考Kernel parameters.

### 手动创建 grub.cfg

Warning: 不推荐编辑这个文件.这个文件由`grub-mkconfig`生成,最好编辑`/etc/default/grub`和`/etc/grub.d`文件夹下的脚本以实现修改.

基本的GRUB配置文件使用如下选项:

- `(hdX,Y)` 是X磁盘的Y分区,分区从1开始计数,磁盘从0开始计数.
- `set default=N`设定用户选择超时时间过后的默认启动项
- `set timeout=M`设定用户选择超时时间(秒).
- `menuentry "title" {entry options}`设置一个名为`title`的启动项
- `set root=(hdX,Y)`设定启动分区(kernel和GRUB模组所在磁盘),/boot没被要求独占一个分区,有可能就是root分区下的一个文件夹

示例配置如下:

    /boot/grub/grub.cfg

    # Config file for GRUB - The GNU GRand Unified Bootloader
    # /boot/grub/grub.cfg

    # DEVICE NAME CONVERSIONS
    #
    #  Linux           Grub
    # -------------------------
    #  /dev/fd0        (fd0)
    #  /dev/sda        (hd0)
    #  /dev/sdb2       (hd1,2)
    #  /dev/sda3       (hd0,3)
    #

    # Timeout for menu
    set timeout=5

    # Set default boot entry as Entry 0
    set default=0

    # (0) Arch Linux
    menuentry "Arch Linux" {
      set root=(hd0,1)
      linux /vmlinuz-linux root=/dev/sda3 ro
      initrd /initramfs-linux.img
    }

    ## (1) Windows
    #menuentry "Windows" {
    #  set root=(hd0,3)
    #  chainloader +1
    #}

### 双启动

Note: 如果你希望GRUB自动搜寻其他系统, 可以安装os-prober.

#### 使用/etc/grub.d/40_custom 和 grub-mkconfig自动生成

添加其他启动项的最好方法是编辑`/etc/grub.d/40_custom`或`/boot/grub/custom.cfg`.运行`grub-mkconfig`后,这些文件中的启动项会被自动添加到grub.cfg中. 更新了这些文件后,运行:

    # grub-mkconfig -o /boot/grub/grub.cfg

在UEFI-GPT模式下,运行:

    # grub-mkconfig -o /boot/efi/EFI/GRUB/grub.cfg

这样会更新`grub.cfg`

一个典型`/etc/grub.d/40_custom`文件类似于下面这个为HP Pavilion 15-e056sl Notebook PC|预装WIN8的HP Pavilion 15-e056sl Notebook PC而作的配置.每个启动项的结构都应该和下面的类似.请注意UEFI分区`/dev/sda2` 被命名为`hd0,gpt2` 和`ahci0,gpt2`(请参考here获取更多信息)

/etc/grub.d/40_custom:

    #!/bin/sh
    exec tail -n +3 $0
    # This file provides an easy way to add custom menu entries.  Simply type the
    # menu entries you want to add after this comment.  Be careful not to change
    # the 'exec tail' line above.

    menuentry "HP / Microsoft Windows 8.1" {
    	echo "Loading HP / Microsoft Windows 8.1..."
    	insmod part_gpt
    	insmod fat
    	insmod search_fs_uuid
    	insmod chain
    	search --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 763A-9CB6
    	chainloader (${root})/EFI/Microsoft/Boot/bootmgfw.efi
    }

    menuentry "HP / Microsoft Control Center" {
    	echo "Loading HP / Microsoft Control Center..."
    	insmod part_gpt
    	insmod fat
    	insmod search_fs_uuid
    	insmod chain
    	search --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 763A-9CB6
    	chainloader (${root})/EFI/HP/boot/bootmgfw.efi
    }

    menuentry "System shutdown" {
    	echo "System shutting down..."
    	halt
    }

    menuentry "System restart" {
    	echo "System rebooting..."
    	reboot
    }

##### GNU/Linux 启动项

假设另一个发行版位于`sda2`:

    menuentry "Other Linux" {
    	set root=(hd0,2)
    	linux /boot/vmlinuz (add other options here as required)
    	initrd /boot/initrd.img (if the other kernel uses/needs one)
    }

##### FreeBSD 启动项

要求FreeBSD以UFS格式被安装在单独的分区上,假设安装在`sda4`上:

    menuentry "FreeBSD" {
    	set root=(hd0,4)
    	chainloader +1
    }

##### Windows XP 启动项

假设Windows分区是`sda3`.请记住需要将root设置到Windows安装时建立的启动分区上,然后链式加载它,而不是Windows系统所在分区.下面的例子就是假设启动分区就是`sda3`.

    # (2) Windows XP
    menuentry "Windows XP" {
    	set root="(hd0,3)"
    	chainloader +1
    }

如果Windows的bootloader和GRUB不在一个硬盘上,那么需要让Windows认为它是在第一硬盘上.使用`drivemap`可以实现这点.假设GRUB在`hd0`而windows在`hd2`上,需要在设定root后执行:

    drivemap -s hd0 hd2

##### UEFI-GPT 模式下安装的Windows的启动项

    if [ "${grub_platform}" == "efi" ]; then
    	menuentry "Microsoft Windows Vista/7/8 x86_64 UEFI-GPT" {
    		insmod part_gpt
    		insmod fat
    		insmod search_fs_uuid
    		insmod chain
    		search --fs-uuid --set=root $hints_string $uuid
    		chainloader /EFI/Microsoft/Boot/bootmgfw.efi
    	}
    fi

`$hints_string` 和 `$uuid`可以通过以下命令获取:

`$uuid`:

    # grub-probe --target=fs_uuid $esp/EFI/Microsoft/Boot/bootmgfw.efi
    1ce5-7f28

`$hints_string`:

    # grub-probe --target=hints_string $esp/EFI/Microsoft/Boot/bootmgfw.efi
     --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1

这两个命令都是假设ESP挂载在`$esp`上.当然,Windows的EFI文件路径可能有变,因为这就是Windows....

##### "Shutdown" 启动项

    menuentry "System shutdown" {
    	echo "System shutting down..."
    	halt
    }

##### "Restart" 启动项

    menuentry "System restart" {
    	echo "System rebooting..."
    	reboot
    }

#### 通过EasyBCD NeoGRUB 和Windows共存

现在EasyBCD的NeoGRUB还不能识别GRUB的目录格式,在 `C:\NST\menu.lst` 中添加如下行以链式加载到GRUB:

    default 0
    timeout 1

    title       Chainload into GRUB v2
    root        (hd0,7)
    kernel      /boot/grub/i386-pc/core.img

最后,使用`grub-mkconfig`重建`grub.cfg`

### 可视化配置

GRUB默认就支持定制启动目录的外观.不过要确保使用合适的视频模式初始化GRUB的图形化终端gfxterm.在#"No suitable mode found" error一节中有介绍.GRUB通过'gfxpayload'来将视频模式传递给linux内核,所以任何可视化配置都需要这个模式的信息以正确工作.

#### 设定帧缓冲的分辨率

GRUB既可以为自己,也可以为内核设定帧缓冲.现在已经不使用老的`vga=`配置了.推荐方法是在`/etc/default/grub`进行如下编辑:

    GRUB_GFXMODE=1024x768x32
    GRUB_GFXPAYLOAD_LINUX=keep

运行以下命令使配置生效:

    # grub-mkconfig -o /boot/grub/grub.cfg

`gfxpayload`属性会确保内核也保持这个分辨率

Note:

- 如果示例不起作用,请尝试用`vbemode="0x105"`代替`gfxmode="1024x768x32"`.请使用适合你屏幕的分辨率.
- 可以通过`# hwinfo --framebuffer`命令来显示所有可以使用的分辨率模式(hwinfo在community里),在GRUB命令行下,可以使用`vbeinfo` 命令

这种方法不管用的话,可以试试老的`vga=`方法.将它添加到`"GRUB_CMDLINE_LINUX_DEFAULT="`里面就行了,比如 `"GRUB_CMDLINE_LINUX_DEFAULT="quiet splash vga=792"` 这会将系统的分辨率设定为1024*768

可以选择以下分辨率中的一种:`640×480`, `800×600`, `1024×768`, `1280×1024`, `1600×1200`, `1920×1200`

#### 915resolution hack

有些时候,Intel显卡无法通过`# hwinfo --framebuffer` 或`vbeinfo`显示你需要的分辨率.这种情况下,你可以使用`915resolution hack`.915resolution hack会临时性的修改显卡BIOS来添加所需的分辨率.详情请参考915resolution's home page

首先,找一个你想要替代的视频模式.例如在GRUB命令行模式下运行:

    sh:grub> 915resolution -l

    Intel 800/900 Series VBIOS Hack : version 0.5.3
    [...]
    Mode 30 : 640x480, 8 bits/pixel
    [...]

然后,使用`1440x900` 分辨率覆盖`Mode 30`

    /etc/grub.d/00_header

    [...]
    915resolution 30 1440 900  # Inserted line
    set gfxmode=${GRUB_GFXMODE}
    [...]

最后,设置`GRUB_GFXMODE`,重新生成GRUB配置文件,重启并测试是否生效:

    # grub-mkconfig -o /boot/grub/grub.cfg
    # reboot

#### 背景图像和点阵字体

GRUB原生支持设置背景图像和点阵字体(以pf2格式).grub包含unifont字体,名为`unicode.pf2`.(也有可能只包含名为`ascii.pf2`的ASCII字符字体)

GRUB支持的图像格式有tga,png,jpeg.所支持的最大图像分辨率跟硬件有关.

Make sure you have set up the proper framebuffer resolution. 请确保你已经设定了合适的帧缓冲分辨率

编辑`/etc/default/grub`:

    GRUB_BACKGROUND="/boot/grub/myimage"
    #GRUB_THEME="/path/to/gfxtheme"
    GRUB_FONT="/path/to/font.pf2"

Note: 如果你将GRUB安装在单独的分区上, `/boot/grub/myimage` 应该改为 `/grub/myimage`.

重新生成配置文件:

    # grub-mkconfig -o /boot/grub/grub.cfg

如果成功的添加了背景图片,那么用户会在命令行中看到`"Found background image..."`. 如果没有看到`"Found background image..."`,图像信息就可能没有嵌入`grub.cfg`中了.

如果图像没有正确显示,执行如下检查:

- 在`/etc/default/grub`里,图像的路径和名字是否正确
- 图像的大小和格式是否合适(tga,png,8-bit jpg)
- 图像是不是以RGB模式存储,是不是没有索引
- `/etc/default/grub`里面是不是没有开启console模式
- 是否执行`grub-mkconfig`以重新生成配置文件

#### 主题

下面的例子将展示如何使用GRUB包重的starfield主题:

编辑 `/etc/default/grub`

    GRUB_THEME="/usr/share/grub/themes/starfield/theme.txt"

重生成配置:

    # grub-mkconfig -o /boot/grub/grub.cfg

配置成功的话,在重生成配置过程中,会出现`Found theme: /usr/share/grub/themes/starfield/theme.txt`.使用主题就不会使用之前的背景图像

#### 目录颜色

GRUB支持设置目录颜色.可使用的颜色能从the GRUB Manual里面找到.示例如下:

编辑`/etc/default/grub`:

    GRUB_COLOR_NORMAL="light-blue/black"
    GRUB_COLOR_HIGHLIGHT="light-cyan/blue"

重建配置档:

    # grub-mkconfig -o /boot/grub/grub.cfg

#### 隐藏目录

GRUB特性之一就是支持隐藏/跳过目录,同时支持按`Esc`来打断隐藏/跳过.同时还支持设置是否显示timeout计时器 下面的例子设置5s钟内没有按Esc键就启动默认的启动项,并且在屏幕上显示倒计时:

编辑`/etc/default/grub`:

    GRUB_HIDDEN_TIMEOUT=5
    GRUB_HIDDEN_TIMEOUT_QUIET=false

重建配置档:

    # grub-mkconfig -o /boot/grub/grub.cfg

#### 禁用framebuffer

Users who use NVIDIA proprietary driver might wish to disable GRUB's framebuffer as it can cause problems with the binary driver. 使用NVIDIA私有驱动的用户可能希望禁用GRUB的framebuffer,因为会导致驱动错误.

在`/etc/default/grub`中添加(如果已经有背注释掉的这行,就取消注释):

    GRUB_TERMINAL_OUTPUT=console

重建配置档:

    # grub-mkconfig -o /boot/grub/grub.cfg

如果你想保留GRUB的framebuffer,解决方法是在GRUB载入内核前进入文字模式.可以通过在`/etc/default/grub`设置如下:

    GRUB_GFXPAYLOAD_LINUX=text

然后重建配置档.

### 其他选项

#### LVM

如果使用LVM做为启动设备,那么在启动项里添加:

    insmod lvm

然后在启动项里指定root:

    set root=lvm/lvm_group_name-lvm_logical_boot_partition_name

示例如下:

    # (0) Arch Linux
    menuentry "Arch Linux" {
      insmod lvm
      set root=lvm/VolumeGroup-lv_boot
      # you can only set following two lines
      linux /vmlinuz-linux root=/dev/mapper/VolumeGroup-root ro
      initrd /initramfs-linux.img
    }

#### 阵列

通过添加`insmod mdraid`,GRUB能够很方便的处理磁盘阵列.比如`/dev/md0`:

    set root=(md0)

阵列上的分区(比如`/dev/md0p1`)则为:

    set root=(md0,1)

如果启动分区在raid1上,想要安装grub,只需要在两个磁盘上分别运行grub-install即可:

    grub-install --target=i386-pc --recheck --debug /dev/sda && grub-install --target=i386-pc --recheck --debug /dev/sdb

这时/dev/sda和/dev/sdb就都有了raid1的启动文件夹/boot了

#### 持久块设备命名法

持久块设备命名法(Persistent block device naming)的一个目的是使用全局的UUID来区分分区,而不是用老的`/dev/sd*`表示法.好处显而易见.

GRUB默认使用持久块设备命名法

Note: 每次文件系统调整过后,就需要用新的UUID来更新`/boot/grub.cfg`.通过Live-CD调整分区和文件系统后要特别注意这点

是否使用UUID由`/etc/default/grub`里的这个选项控制:

    # GRUB_DISABLE_LINUX_UUID=true

无论如何,变更配置后请重建配置档:

    # grub-mkconfig -o /boot/grub/grub.cfg

#### 使用卷标

GRUB支持以卷标识别文件系统(通过`search`命令的`--label参数`).

首先,给文件系统设置一个卷标:

    # tune2fs -L LABEL PARTITION

然后在启动项中使用这个卷标:

    menuentry "Arch Linux, session texte" {
      search --label --set=root archroot
      linux /boot/vmlinuz-linux root=/dev/disk/by-label/archroot ro
      initrd /boot/initramfs-linux.img
    }

#### 调用之前的启动项

GRUB能够记住你当前使用的启动项并且在下次启动时将其作为默认项.当你使用多个内核或操作系统时,这个特性很有用. 编辑`/etc/default/grub`中的`GRUB_DEFAULT`选项:

    GRUB_DEFAULT=saved

上面的命令会告诉GRUB使用记住的启动项为默认启动项. 将下面的行添加到`/etc/default/grub`会让GRUB记住当前的启动项:

    GRUB_SAVEDEFAULT=true

Note: 手动添加启动项到`/etc/grub.d/40_custom`或`/boot/grub/custom.cfg`中,比如Windows启动项,需要添加`savedefault`

请记住重建配置档.

#### 改变默认启动项

可以通过修改`/etc/default/grub`中的`GRUB_DEFAULT`值来改变默认启动项

    GRUB_DEFAULT=0

GRUB启动项序号从0开始计数.0代表第一个启动项.

除了使用启动项序号,也可以使用启动项名:

    GRUB_DEFAULT='Arch Linux, with Linux core repo kernel'

Note: 请记住重建配置档

#### 安全

如果你想禁止其他人改变启动参数或者使用GRUB命令行,可以给GRUB配置添加用户名/密码. 运行 `grub-mkpasswd-pbkdf2`,输入密码:

    grub-mkpasswd-pbkdf2

    [...]
    Your PBKDF2 is grub.pbkdf2.sha512.10000.C8ABD3E93C4DFC83138B0C7A3D719BC650E6234310DA069E6FDB0DD4156313DA3D0D9BFFC2846C21D5A2DDA515114CF6378F8A064C94198D0618E70D23717E82.509BFA8A4217EAD0B33C87432524C0B6B64B34FBAD22D3E6E6874D9B101996C5F98AB1746FE7C7199147ECF4ABD8661C222EEEDB7D14A843261FFF2C07B1269A

然后将下面的内容添加到`/etc/grub.d/00_header`:

    /etc/grub.d/00_header

    cat << EOF

    set superusers="username"
    password_pbkdf2 username <password>

    EOF

Note: 不能直接将

set superusers="username" password_pbkdf2 username <password> 添加到/etc/grub.d/00_header中去,而必须使用上述方法.否则会报错 password_pbkdf2: not found

`<password>`是`grub-mkpasswd_pbkdf2`生成的那个加密过后密码.

然后重建配置档.其他用户没有密码就不能变更GRUB配置或者使用GRUB命令行了.

可以参考the GRUB manual中的"Security"部分来进行更多的客制化安全设定

#### root加密

将`cryptdevice=/dev/yourdevice:label`添加到`/etc/default/grub`中的`GRUB_CMDLINE_LINUX`配置项,可以让GRUB传递参数给内核,让内核对root加密:

Tip: 如果你使用从GRUB Legacy升级而来,检查`/boot/grub/menu.lst.pacsave`以获取正确的device/label. 在`kernel /vmlinuz-linux`后去找label.

将root映射到`/dev/mapper/root`:

    GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda2:root"

当然,需要在rootfs上禁用UUID:

    GRUB_DISABLE_LINUX_UUID=true

Regenerate the configuration.

#### 设定下次启动的启动项(一次性,非持久)

命令`grub-reboot`可以设置下次启动时启动哪个启动项而不必修改配置文件或者在启动时手动选择.这个设置是一次性的,即不会改变GRUB的默认启动项.

Note: 需要在`/etc/default/grub`中设定 `GRUB_DEFAULT=saved`,然后重建配置档.在手动生成的 `grub.cfg`中, 使用 `set default="${saved_entry}"`.

#### 启动时隐藏GRUB界面,除非按着SHIFT键

为了获取更快的启动速度,而不用等GRUB倒计时,可以命令GRUB在启动时隐藏目录,除非SHIFT被按着. 将如下行添加到`/etc/default/grub`:

     GRUB_FORCE_HIDDEN_MENU="true"

然后创建如下文件:

    /etc/grub.d/31_hold_shift

    #! /bin/sh
    set -e

    # grub-mkconfig helper script.
    # 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/>.

    prefix="/usr"
    exec_prefix="${prefix}"
    datarootdir="${prefix}/share"

    export TEXTDOMAIN=grub
    export TEXTDOMAINDIR="${datarootdir}/locale"
    source "${datarootdir}/grub/grub-mkconfig_lib"

    found_other_os=

    make_timeout () {

      if [ "x${GRUB_FORCE_HIDDEN_MENU}" = "xtrue" ] ; then
        if [ "x${1}" != "x" ] ; then
          if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
        verbose=
          else
        verbose=" --verbose"
          fi

          if [ "x${1}" = "x0" ] ; then
        cat <<EOF
    if [ "x\${timeout}" != "x-1" ]; then
      if keystatus; then
        if keystatus --shift; then
          set timeout=-1
        else
          set timeout=0
        fi
      else
        if sleep$verbose --interruptible 3 ; then
          set timeout=0
        fi
      fi
    fi
    EOF
          else
        cat << EOF
    if [ "x\${timeout}" != "x-1" ]; then
      if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT} ; then
        set timeout=0
      fi
    fi
    EOF
          fi
        fi
      fi
    }

    adjust_timeout () {
      if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
        cat <<EOF
    if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
    EOF
        make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}"
        echo else
        make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
        echo fi
      else
        make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
      fi
    }

      adjust_timeout

        cat <<EOF
    if [ "x\${timeout}" != "x-1" ]; then
      if keystatus; then
        if keystatus --shift; then
          set timeout=-1
        else
          set timeout=0
        fi
      else
        if sleep$verbose --interruptible 3 ; then
          set timeout=0
        fi
      fi
    fi
    EOF

### 在GRUB中直接从ISO启动

编辑`/etc/grub.d/40_custom` 或 `/boot/grub/custom.cfg`,给目标ISO添加一个启动项.然后使用`grub-mkconfig -o /boot/grub/grub.cfg`更新配置档

#### Arch ISO

Note: 下面的例子都是假设ISO文件位于`hd0,6`分区上的`/archives`文件夹里
Tip: For thumbdrives, use something like `(hd1,$partition)` and either `/dev/sdbY` for the `img_dev` parameter or a persistent name, e.g. `img_dev=/dev/disk/by-label/CORSAIR`.
Tip: 对于闪存,使用`(hd1,$partition)`或`/dev/sdbY`作为`img_dev`参数的值,或者使用持久块设备命名法命名的设备,比如`img_dev=/dev/disk/by-label/CORSAIR`.

##### x86_64

    menuentry "Archlinux-2013.05.01-dual.iso" --class iso {
      set isofile="/archives/archlinux-2013.05.01-dual.iso"
      set partition="6"
      loopback loop (hd0,$partition)/$isofile
      linux (loop)/arch/boot/x86_64/vmlinuz archisolabel=ARCH_201305 img_dev=/dev/sda$partition img_loop=$isofile earlymodules=loop
      initrd (loop)/arch/boot/x86_64/archiso.img
    }

##### i686

    menuentry "Archlinux-2013.05.01-dual.iso" --class iso {
      set isofile="/archives/archlinux-2013.05.01-dual.iso"
      set partition="6"
      loopback loop (hd0,$partition)/$isofile
      linux (loop)/arch/boot/i686/vmlinuz archisolabel=ARCH_201305 img_dev=/dev/sda$partition img_loop=$isofile earlymodules=loop
      initrd (loop)/arch/boot/i686/archiso.img
    }

#### Ubuntu ISO

Note: 下面的例子都是假设ISO文件位于`hd0,6`分区上的`/archives`文件夹里. 用户需要根据自己系统的实际情况调整.

    menuentry "ubuntu-13.04-desktop-amd64.iso" {
      set isofile="/archives/ubuntu-13.04-desktop-amd64.iso"
      loopback loop (hd0,6)/$isofile
      linux (loop)/casper/vmlinuz.efi boot=casper iso-scan/filename=$isofile quiet noeject noprompt splash --
      initrd (loop)/casper/initrd.lz
    }

    menuentry "ubuntu-12.04-desktop-amd64.iso" {
      set isofile="/archives/ubuntu-12.04-desktop-amd64.iso"
      loopback loop (hd0,6)/$isofile
      linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile quiet noeject noprompt splash --
      initrd (loop)/casper/initrd.lz
    }

#### Other ISOs

可从这里获取其他ISO的配置.

## 使用GRUB命令行

MBR太小,所以不足以存储所有的GRUB模组.MBR里面只有启动目录配置和一些很基本的命令.GRUB的主要功能通过`/boot/grub`里的模组实现,而且可以按需加载.出现错误时,GRUB可能不能引导启动(比如,磁盘分区发生了变化).这时候,一般会出现命令行界面.

GRUB不止提供一个shell.如果GRUB不能读取到启动目录配置,但是能找到磁盘,你很可能需要进入"normal" shell:

    sh:grub>

如果有更严重的问题(比如,GRUB找不到必须的文件了),你就可能需要进入"rescue" shell:

    grub rescue>

"rescue" shell是"normal" shell的一个子集,其支持的功能更少.如果不幸进入了"rescue" shell里,首先记载"normal"模组,然后启动"normal" shell:

    grub rescue> set prefix=(hdX,Y)/boot/grub
    grub rescue> insmod (hdX,Y)/boot/grub/i386-pc/normal.mod
    rescue:grub> normal

### 分页支持

GRUB支持对长输出进行分页(比如运行`help`的输出).不过只有normal shell支持分页,而rescue shell不支持.开启分页支持的方法如下:

    sh:grub> set pager=1

### 使用命令行引导操作系统

    grub>

可以使用GRUB命令行引导操作系统,一个典型的应用场景是通过chainloading来引导另一个Windows或Linux

ChainLoading的意思是用当前的bootloader去载入另一个bootloader,所以叫做链式加载.这个bootloader可能位于MBR,也可能在另一个分区的引导扇区上.

#### 链式加载一个分区

    set root=(hdX,Y)
    chainloader +1
    boot

X=0,1,2... Y=1,2,3...

比如链式加载一个位于首磁盘,首分区上的Windows:

    set root=(hd0,1)
    chainloader +1
    boot

也可以使用GRUB链式加载另一个分区引导扇区上的GRUB.

#### 链式加载磁盘

    set root=hdX
    chainloader +1
    boot

#### 正常载入

请参考#使用应急命令行

## 图形化配置工具

- grub-customizer — 定制bootloader(GRUB or BURG)

  https://launchpad.net/grub-customizer || grub-customizer

- grub2-editor — KDE4上配置GRUB的控制模组

  http://kde-apps.org/content/show.php?content=139643 || grub2-editor

- kcm-grub2 — 可以管理大部分常用GRUB配置的kcm模组

  http://kde-apps.org/content/show.php?content=137886 || kcm-grub2

- startupmanager — GRUB Legacy, GRUB, Usplash and Splashy的图形化配置工具(abandonned)

  http://sourceforge.net/projects/startup-manager/ || startupmanager

## parttool

如果你安装了Windows 9x系列操作系统,而它们隐藏了磁盘(比如C盘),GRUB能够使用parttool来设置是否隐藏.比如,想从三个Windows 9x系统的第三个启动,可以这样:

    parttool hd0,1 hidden+ boot-
    parttool hd0,2 hidden+ boot-
    parttool hd0,3 hidden- boot+
    set root=hd0,3
    chainloader +1
    boot

## 使用应急命令行

请先阅读#使用GRUB命令行.如果无法进入命令行,请尝试使用Live CD或者其他rescue磁盘引导,然后修正错误.不过有些时候我们手上没有此类rescue磁盘,这时,应急命令行(rescue console)就可以派上用场了.

GRUB应急命令行里可用的命令有`insmod`, `ls`, `set`, `unset`.可以使用set/unset修改变量,使用insmod来载入模组.

首先,用户必须知道启动分区(`/boot`所在位置然后设置:

    grub rescue> set prefix=(hdX,Y)/boot/grub

通过加载`linux`模组来扩展命令行的功能:

    grub rescue> insmod (hdX,Y)/boot/grub/linux.mod

Note: 如果/boot是在单独的分区上,请从路径中移除/boot.(即. 输入 `set prefix=(hdX,Y)/grub` 然后`insmod (hdX,Y)/grub/linux.mod`)

这个模组会启动对我们熟悉的`linux` 和 `initrd` 命令的支持 (请参考#配置).

比如:

    set root=(hd0,5)
    linux /boot/vmlinuz-linux root=/dev/sda5
    initrd /boot/initramfs-linux.img
    boot

如果/boot在单独分区上:

    set root=(hd0,5)
    linux /vmlinuz-linux root=/dev/sda6
    initrd /initramfs-linux.img
    boot

成功启动Arch后,用户可以修正配置的错误或者重新安装GRUB.

关于修正配置和重新安装GRUB,请参考#配置和#安装章节.

## 使用UUID的基础脚本

如果你想要使用UUID来避免不可靠的BIOS设备命名或者正在研究GRUB语法,这里有个使用UUID的示例性的启动项配置脚本.如果你想要将其移植到自己的系统上,只需要修改UUID就行了.这个例子假设系统的boot和root文件系统是在不同的分区上.如果你还有其他分区,请做相应修改.

     menuentry "Arch Linux 64" {
             # Set the UUIDs for your boot and root partition respectively
             set the_boot_uuid=ece0448f-bb08-486d-9864-ac3271bd8d07
             set the_root_uuid=c55da16f-e2af-4603-9e0b-03f5f565ec4a

             # (Note: This may be the same as your boot partition)

             # Get the boot/root devices and set them in the root and grub_boot variables
             search --fs-uuid $the_root_uuid --set=root
             search --fs-uuid $the_boot_uuid --set=grub_boot

             # Check to see if boot and root are equal.
             # If they are, then append /boot to $grub_boot (Since $grub_boot is actually the root partition)
             if [ $the_boot_uuid == $the_root_uuid ] ; then
                 set grub_boot=($grub_boot)/boot
             else
                 set grub_boot=($grub_boot)
             fi

             # $grub_boot now points to the correct location, so the following will properly find the kernel and initrd
             linux $grub_boot/vmlinuz-linux root=/dev/disk/by-uuid/$the_root_uuid ro
             initrd $grub_boot/initramfs-linux.img
     }

## 异常处理

### Intel BIOS不能引导GPT

一些Intel的BIOS要求至少要一个可启动的分区(MBR方案下的),导致GTP方案下的分区GRUB无法启动.

可以通过fdisk来将一个GPT分区标志为'boot'((最好就设在你为GRUB创建的那个1007KiB分区上)),这样就可以绕过这个问题了:

    1.对目标磁盘(比如/dev/sda)运行fdisk
    2.按a键,然后选择想要设置'boot'标志的分区
    3.最后按w键,将变更写入磁盘

Note: 必须使用fdisk或者类似于它的工具来设置'boot flag',不能用Gparted等,因为它们不会在MBR里面设置'boot flag'.

请参考 http://www.rodsbooks.com/gdisk/bios.html

### 启用调试信息

在`grub.cfg`里添加:

    set pager=1
    set debug=all

### "No suitable mode found" error

启动时可能出现如下提示信息:

    error: no suitable mode found
    Booting however

然后你需要以合适的视频模式(`gfxmode`)启动 GRUB 图形化终端(`gfxterm`).视频模式由GRUB通过'gfxpayload'变量传递给linux内核.在UEFI系统下,如果没有初始化视频模式的值,终端上就不会显示内核启动消息(至少直到KMS开始运行)

将`/usr/share/grub/unicode.pf2`复制到 ${GRUB_PREFIX_DIR}(`/boot/grub/` .如果GRUB UEFI安装时设定了`--boot-directory=$esp/EFI`,那么复制的目的文件夹是`$esp/EFI/grub/`:

    # cp /usr/share/grub/unicode.pf2 ${GRUB_PREFIX_DIR}

如果`/usr/share/grub/unicode.pf2` 不存在, 安装bdf-unifont, 创建 `unifont.pf2` 文件然后将其复制到 `${GRUB_PREFIX_DIR}`:

    # grub-mkfont -o unicode.pf2 /usr/share/fonts/misc/unifont.bdf

然后,在`grub.cfg`文件中添加如下行: (会给linux内核传递合适的视频模式,否则你只会得到一个黑屏,虽然系统还是会启动成功) BIOS 系统:

    insmod vbe

UEFI 系统:

    insmod efi_gop
    insmod efi_uga

在这些行后添加(BIOS&&UEFI):

    insmod font

    if loadfont ${prefix}/fonts/unicode.pf2
    then
        insmod gfxterm
        set gfxmode=auto
        set gfxpayload=keep
        terminal_output gfxterm
    fi

如果要gfxterm(图形化终端)工作正常,`${GRUB_PREFIX_DIR}`文件夹里面应该要有`unicode.pf2` .

### 出现"msdos-style"错误消息

以下错误可能出现在你将GRUB安装到VMware上时.请阅读相关链接.这种情况是因为首分区直接从MBR后开始(即第64个扇区),而不是和正常的那样有1到2M post-MBR gap.请参阅#MBR专用指令

    grub-setup: warn: This msdos-style partition label has no post-MBR gap; embedding will not be possible!
    grub-setup: warn: Embedding is not possible. GRUB can only be installed in this setup by using blocklists.
                However, blocklists are UNRELIABLE and its use is discouraged.
    grub-setup: error: If you really want blocklists, use --force.

### GRUB UEFI 启动到了rescue shell下

如果GRUB直接就启动到了rescue shell下,而且没报错,这可能是因为`grub.cfg`丢失或者位置不对.如果GRUB UEFI 安装时设定了`--boot-directory`参数,而`grub.cfg`文件丢失,会出现这个问题.如果启动分区的分区号发生了变化(这个分区号会被直接编码到`grubx64.efi`文件中),也会出现这个问题.

### GRUB UEFI 无法被载入

下面是一个EFI启动项信息示例:

    # efibootmgr -v

    BootCurrent: 0000
    Timeout: 3 seconds
    BootOrder: 0000,0001,0002
    Boot0000* Grub	HD(1,800,32000,23532fbb-1bfa-4e46-851a-b494bfe9478c)File(\efi\grub\grub.efi)
    Boot0001* Shell	HD(1,800,32000,23532fbb-1bfa-4e46-851a-b494bfe9478c)File(\EfiShell.efi)
    Boot0002* Festplatte	BIOS(2,0,00)P0: SAMSUNG HD204UI

如果启动后,屏幕直接变黑,几秒后就跳到了下一个启动项,根据相关链接的说法是,将GRUB移动到root分区上可能会解决这个问题.必须先删除启动项,然后重建,变化如下:

    Boot0000* Grub	HD(1,800,32000,23532fbb-1bfa-4e46-851a-b494bfe9478c)File(\grub.efi)

### "Invalid signature"错误

如果在启动Windows时出现了"invalid signature"错误(比如在重新分区或者添加了新硬盘后),删除GRUB的磁盘mapping,然后重建:

    # mv /boot/grub/device.map /boot/grub/device.map-old
    # grub-mkconfig -o /boot/grub/grub.cfg

`grub-mkconfig`此时就应该生成了新的启动项了,包括Windows.确认能启动成功后,再将备份文件`/boot/grub/device.map-old`删除.

### 引导过程卡死

如果在GRUB载入内核并初始化ramdisk后引导过程卡死了,请尝试移除`add_efi_memmap`这个内核参数

### 回滚到 GRUB Legacy

- 将GRUB2相关文件改名以为备份:

    # mv /boot/grub /boot/grub.nonfunctional

- 将GRUB Legacy 移回`/boot`:

    # cp -af /boot/grub-legacy /boot/grub

- 恢复备份的MBR

Warning: 这个命令同时会恢复分区表,所以请要非常注意.

    # dd if=/path/to/backup/first-sectors of=/dev/sdX bs=512 count=1

安全的方法是只恢复MBR中的启动代码:

    # dd if=/path/to/backup/mbr-boot-code of=/dev/sdX bs=446 count=1

### 其他系统不能自动发现Arch Linux

有人发现有些发行版不能使用`os-prober`自动发现Arch Linux.据称先使用`/etc/lsb-release`可能会解决这个问题.相关文件和工具可以在 官方仓库的lsb-release包中找到

## 参阅

1. 官方 GRUB Manual - https://www.gnu.org/software/grub/manual/grub.html
2. Ubuntu GRUB wiki - https://help.ubuntu.com/community/Grub2
3. 描述为UEFI系统编译GRUB的WIKI - https://help.ubuntu.com/community/UEFIBooting
4. Wikipedia BIOS Boot partition

Category:

- Boot loaders (简体中文)