GRUB

来自osdev
跳到导航 跳到搜索

这篇文章写得像个教程。请 编辑它以添加更多信息和文档,而不仅仅是示例代码和分步说明。

GRUB 是GNU项目的bootloader。(译者注:以后计划不再翻译Bootloader,英文来看是一个很明确的名词,但是翻译成“引导加载程序”以后像一个动词开头,译者的脑子经常要额外反应一下。) 当前版本2系列具有比 GRUB 0.97 (通常称为 “GRUB Legacy”) 更完整的功能集。

历史

GRUB版本2以 PUPA (PUPA也有蛹的意思) 研究项目开始了它的生命,并从头开始重写。 从那时起,GRUB 2 (实际上在更新1.97时) 已经变得更加稳定,甚至是业余操作系统更多使用新的bootloader而不是GRUB Legacy。

特性

  • 基本脚本支持
  • 图形用户界面 (更好的bootsplash支持,自定义颜色,自定义主题,...)
  • 内存管理
  • 更清洁的设计
  • 更好的便携性
  • 国际化
  • 救援模式

完整的功能列表可以在GNU邮件列表中找到 [1]

使用GRUB引导你的操作系统

使用GRUB引导操作系统的完整示例代码可以在 Bare Bones tutorial中找到。 一般的想法是,你要创建一个具有multiboot标头的文件,GRUB可以将该文件程序标识为内核并引导它。

从GRUB Legacy升级

警告: 这些步骤还没有经过很好的测试。 使用风险自负!

由于现代GRUB 2与GRUB Legacy非常不同,因此启动和运行内核的方式不同。 现代GRUB与GRUB Legacy的不同之处在于,要实现除最基本功能外的所有功能,用户必须加载所谓的 “模块(modules)”: 通过少量代码添加组件(例如,不同的文件系统或VGA字体)。 本节概述了要让GRUB 2加载内核时需要经历的过程。 创建一个GRUB 2映像 (假设你已经构建或安装了GRUB 2) 实际上相当简单:

ISO 指导

已经有很多尝试想要使GRUB2与ISO配合良好,但大多数都失败了。 唯一似乎有效的命令组合如下。

首先创建一个名为 “iso” 的目录树,在那里你把你的内核 (以及任何其他需要的文件) 放在这里。 然后在boot/grub子目录中创建grub.cfg文件,这是你的配置。

现在运行:

grub-mkrescue -o bootable.iso iso

确保你的grub.cfg在语法上是正确的。 一个常见的错误是将menuentry括号放在换行符上。 它必须像这样:

menuentry "Place your os name here" {
}

grub-mkrescue 依赖版本为 “0.5.6或更高” 的 “xorriso” 程序。

如果你无法将其作为二进制文件获取 (可能来自名为 “libisoburn” 的软件包) 可以从 GNU xorriso主页 获取all-in-one源tar包。 GNU xorriso可以在原构建位置使用,无需进一步安装:

 grub-mkrescue --xorriso=/...full.path.../xorriso/xorriso -o bootable.iso iso

软盘指导

mkdir tmp
grub-mkimage -p /boot -o tmp/core.img multiboot sh fat # 我希望这应该行得通... :D

解释

让我们来看看这些 grub-mkimage 选项:

-p 默认情况下,GRUB 2在 /boot/grub 中查找其配置文件。-p 更改此选项。
-o 与许多其他GNU工具一样,grub-mkimage 使用 -o 设置输出文件。默认情况下,它是 stdout
multiboot 需要此模块来加载兼容多重引导(multiboot-compliant)的内核。
biosdisk GRUB 2需要此模块才能从LiveCD引导。
iso9660/fat 允许GRUB 2在映像上查找不同的文件。
sh 该模块允许GRUB解析配置文件。

GRUB 2和GRUB Legacy一样,需要一个配置文件来找到你的内核。 在GRUB Legacy中,它被称为 menu.lst' ,但在GRUB2中,它被称为 grub.cfg'。 配置文件的语法也有点不同。

这是一个示例配置文件 (注意: 此文件应放置在磁盘映像的 /boot/grub 文件夹中,并命名为 'grub.cfg' ):

set timeout=15
set default=0 # 设置默认菜单项

menuentry "OS Name" {
   multiboot /boot/kernel-file   # multiboot命令取代了内核命令
   boot
}

基本上就是这样。 将这些文件复制到磁盘映像中,将其放入模拟器,你就完成了!

仔细检查是否将花括号放在 “menuentry” 的同一行上。 它不可以在新的一行上。 这不是C。

USB 指导

如今,拥有软盘控制器的系统越来越少,但是在所有系统上都可以找到USB端口。 现代BIOS可以从USB设备启动,还通常需要在启动时按下一些特殊的键。

将GRUB 2放在可启动的USB存储设备上是在不同计算机上尝试操作系统的好方法。 下面是你如何设置 (使用Linux):

1. 创建一个不带多个分区的FAT32格式U盘:

警告: 以下命令使用超级用户权限 (sudo)。 仅键入错误的X字符可能会给你当前的系统带来严重的麻烦

sudo mkfs.vfat -F 32-n YourLabel -I /dev/sdX

(其中sdX是你的USB设备)

需要 “-I” 选项,因为我们的目标是无分区设备

2. 卸下USB设备,然后重新插入。 操作系统上的自动安装程序现在应该检测到它。

3. 调用grub-install (在某些系统上,此命令被称为grub2-install,位于/usr/sbin或/usr/local/sbin下)

sudo grub-install --root-directory=/media/YourLabel --no-floppy --recheck --force /dev/sdX

重要的是要以root (或sudo) 的身份执行此操作,否则生成的device.map列出可用的引导设备可能为空。 /media/YourLabel 是Fedora 16下的挂载点,其他发行版可能有所不同。

4.为你的内核创建一个grub.cfg (请参见上文),并将其复制到新的可启动USB磁盘中

磁盘映像指导

有关更详细的教程,请参见可引导磁盘来创建。

爱好者操作系统在虚拟机上运行时不必使用真实设备 (尽管可以,而且通常速度更快)。 创建可引导的GRUB磁盘映像类似于将其安装在USB设备上,但是在这里,你可以立即使用映像本身和分区设备。

1. 创建新的磁盘映像文件

$ dd if=/dev/zero of=disk.img bs=512 count=131072
131072+0 records in
131072+0 records out
67108864 bytes (67 MB) copied, 0.349436 s, 192 MB/s

2. 为你的文件系统创建带有可引导项的新DOS分区表

$ fdisk disk.img

添加新分区,从1MB (第2048个扇区) 开始。 这比GRUB实际需要的空间更大。

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-131071, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-131071, default 131071): 
Using default value 131071

使其可引导启动

Command (m for help): a 
Partition number (1-4): 1

将新的分区表写入磁盘

Command (m for help): w
The partition table has been altered!

Syncing disks.

3. 设置两个回环(loop)设备。 一个将用于将GRUB及其附加代码写入MBR,第二个将用于安装操作系统的文件系统。

$ sudo losetup /dev/loop0 disk.img
$ sudo losetup /dev/loop1 disk.img -o 1048576

-o 选项定义从文件开始的偏移量。数字 “1048576” 实际上是 “1024 ^ 2 = 1MB”,这是分区的开始。

4. 格式化分区 你可以简单地使用 [任何受支持的文件系统],如ext2或FAT32。

$ sudo mke2fs /dev/loop1
$ sudo mkdosfs -F32 -f 2 /dev/loop1

5. 挂载你新格式化的分区

$ sudo mount /dev/loop1 /mnt

请注意,如果你试图挂载没有任何偏移设置的首个回环设备,你将被要求指定文件系统,即使你这样做了,你也不会得到预期的结果。

7. 使用 “grub-install” 安装grub

sudo grub-install --root-directory=/mnt --no-floppy --modules="normal part_msdos ext2 multiboot biosdev" /dev/loop0

如果你错误地使用了 “/dev/loop1” (指向你的分区) 而不是 “/dev/loop0” (指向你的MBR),你将收到 “grub-install” 不能使用 'embedding' 的消息 (因为它没有空间),并且它希望使用 'block lists',不推荐这么做。

处理挂载磁盘映像上的文件时,不要忘记刷新文件系统缓冲区。 在类Unix的系统上,这可以简单地通过在你的shell中执行 sync 程序来完成。

OS X用户的硬盘映像指导

为HDD创建映像文件可能会很有用; 以下说明可帮助你使用MBR分区映射创建HDD。 根据#osdev上的<palk>信息,创建HDD映像比你预期的要稍微复杂一些。

此信息可能不适用于Linux用户,他们很可能更想使用loopback设备。 这是针对OS X上的开发人员的,它没有loopback设备,并且具有挑剔的映像安装程序。

1. 首先,用DD创建一个空白的原始映像,大小符合要求。 在这里,我将制作一个80MB的图像 --163840个扇区,每个大小为512字节。

dd if=/dev/zero of=disk.img count=163840 bs=512

2. 有关从LBA/大小计算CHS值的解释,请参见 Floppy_Disk_Controller#CHS

   由于我们有一个80MB的磁盘,CHS值分别为78、32和63。

3. 启动FDISK(或你选择的工具) -- 我在这里使用的是OS X版本,所以命令可能有所不同。 概念基本上是相同的。

屏幕上显示的内容(指OSX中)在左侧,你输入的内容在右侧。

fdisk -e disk.img


The signature for this MBR is invalid.
Would you like to initialize the partition table? [y]           Yes
fdisk:*1>                                                       disk
Disk: disk.img	geometry: 650/4/63 [16340 sectors]
Change disk geometry? [n]                                       No



fdisk:*1>                                                       edit 1
Partition id ('0' to disable)  [0 - FF]: [B] (? for help)       0B
Do you wish to edit in CHS mode? [n]                            No
Partition offset [0 - 163840]: [63]                             2047
Partition size [1 - 161793]: [161793]                           <Enter>


fdisk:*1>                                                       write
fdisk:*1>                                                       quit

4.现在已经初始化了MBR分区表,你将需要在磁盘上创建一个文件系统。但首先。

   这里,我们分离MBR位和实际的FS位。
dd if=disk.img of=mbr.img bs=512 count=2047
dd if=disk.img of=fs.img bs=512 skip=2047

5.因为我们使用的是OS X,所以需要先附加(attach)磁盘镜像,而不是实际挂载(mounting)。

hdiutil attach -nomount fs.img

6.使用 “diskutil list” 找出你的映像是哪个设备,请使用下面的设备。

7. 现在,在FS.img磁盘上创建一个FAT12/16/32文件系统。记住,使用FS.img——不是disk.img

newfs_msdos -F 32 /dev/diskX

8.现在你需要卸载(unmount)它,然后重新组合两个映像,然后安装GRUB。

hdiutil detach /dev/diskX
cat mbr.img fs.img > disk.img

hdiutil attach disk.img
# note the mount point here (/Volumes/NO NAME, probably)

grub-install --modules="part_msdos biosdisk fat multiboot configfile" --root-directory="/Volumes/NO NAME" disk.img
Installation finished. No error reported.

就到这里! 你知道我有一个disk.img,这将安装GRUB2,准备就绪。 只需双击(或使用mount命令),就可以在OS X中挂载它。 玩的开心!

其他有用的选项

无论你使用的是哪种设备,你都可能希望有一个PC分区表,并在GRUB支持的文件系统之一中创建格式化的分区。如果这样做,请确保在GRUB-INSTALL参数中添加以下选项:

--modules="part_msdos"

一般来说,如果GRUB 2恰好无法完成你想要的任务,并且你怀疑它需要一些缺少的功能,那么只需尝试在--modules参数中添加一个你认为具有所需功能的模块名。 模块文件通常位于/boot/GRUB/i386-pc/。

多重引导(Multiboot)

与GRUB-legacy将它们加载到低内存(low memory,译者注:指内存地址值大小)相比,GRUB 2的某些版本喜欢将multipot模块放在相对较高的物理内存地址中。 在让内核使用GRUB2时要小心,它没有对多多重引导模块将出现在哪里做出任何假设。

当你的内核获得控制权时,机器状态定义如下:多重引导机器状态。 你的代码应该对该初始状态具有最小的依赖性; 例如,定义你自己的GDT,而不是依赖GRUB的GDT设置。

标头

正如GRUB 2手册所说:

模板:Quote

但是旧版本的GRUB2使用的多重引导标头(字段出现在GRUB1.99和更新版本中)包括多重引导1.6规范 中指定的header_length字段。

GRUB2还支持旧的Multiboot0.6.96规范。 可以同时包含两个标头。

在OS X上安装GRUB 2

在OS X上安装GRUB 2有点棘手。 最新发布的2.00版本(截至2014年10月7日)似乎不支持任何配置。 开发人员团队在较新的修订版本中修复了此问题。

重要提醒: 要构建GRUB2,以便它可以为你的输出目标生成bootloader,你需要有一个用于该目标的编译器。 因此,例如,如果你想要i386-elf的bootloader (如在裸机中建议的那样),则需要Binutils该目标的编译器。 这在OS X上是必需的,因为内置LLVM不知道如何生成i386-elf二进制文件。 因此,你可以针对你的目标平台构建交叉编译器创建特定于操作系统的工具链(推荐)。 在步骤4中,你将需要GCC,objcopy,strip,nm和ranlib的交叉版本。

1. 复制开发人员版本的源代码:

git clone git://git.savannah.gnu.org/grub.git

(该测试版本为:77063f4cb672f423272db7e21ca448cf3de98dcf)

2.需要名为objconv的工具,请从以下位置获取:

https://github.com/vertis/objconv

下载源代码,编译 (有关详细信息,请参见网站) 并在你的路径中提供。

3. 在GRUB sources文件夹中运行“autogen.sh”

4. 创建一个单独的构建目录,切换到该目录,然后运行GRUB的配置脚本 (insert your target-specific tools!)

../grub/configure --disable-werror TARGET_CC=i386-elf-gcc TARGET_OBJCOPY=i386-elf-objcopy \
TARGET_STRIP=i386-elf-strip TARGET_NM=i386-elf-nm TARGET_RANLIB=i386-elf-ranlib --target=i386-elf

5. 运行 “make” 和 “make install”

现在,你已经有了一个正在工作的GRUB 2,它具有构建在i386平台上启动的映像所需的文件。

UEFI的GRUB

编译GRUB

较老的GRUB版本充满了令人讨厌的BUG。 这些版本可能还存在在你的包管理器中,因此你应该从源代码编译GRUB。 在为UEFI编译时,你应该传递适当的标志以进行配置。 示例调用可能如下所示:

../grub-2.02~rc2/configure --prefix="$HOME/opt/grub" --target=x86_64 --with-platform=efi

完成构建后,GRUB拒绝执行任何操作,因为它缺少字体文件。 要解决这个问题,请运行

bin/grub-mkfont -o share/grub/unicode.pf2 /usr/share/fonts/truetype/unifont/unifont.ttf

GRUB可能会警告你有关share/locale/丢失的信息。 解决方案是创建缺少的目录。

构建GRUB UEFI二进制文件(BOOTX64.EFI)

此方法构建一个独立的GRUB二进制文件,你可以将其复制到FAT分区。 然而,请注意,一些UEFI实现假定它位于 /EFI/BOOT/BOOTX64.EFI 针对x86_64平台。

通常,所有编译的模块都包含在此二进制文件中; 如果要缩小其大小,则可以指定要包含的模块。

此方法使用两个单独的配置文件; 这是必需的,因为所有GRUB数据都位于该二进制文件中,但我们将围绕这个二进制文件工作。 二进制文件包含一个memdisk,它也用作前缀。 据我所知,没有办法直接解决这个问题。 但是,我们可以使用memdisk grub.cfg从磁盘加载配置文件。 这样,我们就不必为每次配置更改重新创建二进制文件。

从创建memdisk grub.cfg开始。 我将其保存在build/grub.cfg(我们稍后需要此路径):

insmod part_msdos
configfile (hd0,msdos1)/boot/grub/grub.cfg

所有这些就是加载用于读取磁盘分区的模块 (第1行),并从磁盘加载配置文件 (第2行)。 注意,它不必位于/boot/grub/grub.cfg;你可以将磁盘上的此路径更改为任何你喜欢的路径,只需记住将更改应用于memdisk grub.cfg。

第二个grub.cfg(磁盘上的那个)基本上由你决定,只是你必须加载part_msdos模块并设置根目录(默认情况下是memdisk):

insmod part_msdos
set root=(hd0,msdos1)

set root 行下方添加常规GRUB2配置。

最后,剩下的就是创建二进制文件。 请注意,你必须指定要在Memdisk中的路径下包含哪个文件:

bin/grub-mkstandalone -O x86_64-efi -o BOOTX64.EFI "boot/grub/grub.cfg=build/grub.cfg"

Blessing macOS上的二进制文件

Mac要求可引导的二进制文件由'blesse'工具处理:

bless --verbose --folder=/Volumes/EFI --file=/Volumes/EFI/EFI/BOOT/BOOTX64.EFI --setBoot

另见

文章

外部链接

de:Grand_Unified_Bootloader