Grub2.04分析

Grub第一阶段总结

一、Grub概念简介

GNU Grub(GRand Unified Bootloader简称“Grub”)是一个来自GNU项目的多操作系统启动程序,允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。引导加载程序是计算机启动时运行的第一个软件程序,它负责加载和传输控制操作系统内核软件,之后内核依次初始化操作系统的其余部分。

使用Grub启动时,可以使用命令行界面(参见命令行界面),也可以使用菜单界面(参见菜单界面)。在菜单中,可以切换到命令行模式,反之亦然。

使用命令行界面,可以手动输入内核的驱动器规范和文件名。

在菜单界面中,该菜单基于预先准备的配置文件(参见configuration),只需使用方向键选择操作系统。

 

图1 图形菜单界面

 

图2 命令行界面

  • Grub使用方法

GNU GRUB 手册 2.06

Grub启动阶段,按c进行shell命令行阶段:

www.gnu.org/software/grub/manual/grub/grub.html#Command_002dline-and-menu-entry-commands

2.1 Grub正常启动

Grub正常启动后,将进入“普通模式”,一般是显示一个菜单(找到了'$prefix/Grub.cfg'),或者直接进入Grub SHELL(没找到'$prefix/Grub.cfg')。

在普通模式中,命令模块[command.lst]与加密模块[crypto.lst]会被自动按需载入(无需使用"insmod"命令),并且可使用完整的Grub脚本功能。但是其他模块则可能需要明确使用"insmod"命令来载入。

2.1.1 Grub在BIOS平台

Grub默认安装在第一个硬盘hd0的MBR上,把引导程序boot.img写入硬盘的MBR,启动时根据MBR提示找到启动分区,加载分区内的Grub核心文件core.img和配置文件Grub.cfg。(hd0,mdsom1)

BIOS --> boot.img[MBR] --> core.img --> 设置"prefix root cmdpath"环境变量 --> 加载"normal.mod"模块[同时还包括依赖的 terminal crypto extcmd boot gettext 模块] --> 执行"normal $prefix/Grub.cfg"命令。

2.1.2 Grub在UEFI平台

UEFI --> core.img[BOOTX64.EFI/BOOTX86.EFI] --> 设置"prefix root cmdpath"环境变量 --> 加载"normal.mod"模块[同时还包括它所依赖的 terminal crypto extcmd boot gettext 模块] --> 执行"normal $prefix/Grub.cfg"命令。

2.2 Grub版本查询

查询ubuntu的Grub版本号:

  1. Grub-install --version
  2. Grub-install -V

 

2.3 Grub菜单加上背景图

首先制作一张PNG格式的图片,分辨率最好是"1024x768"以保证较好的兼容性。然后将这张图片放到"$prefix/themes/1024x768.png"("$prefix"是Grub的安装目录)。然后在'Grub.cfg'中加入如下内容:

set gfxmode=1024x768,auto

insmod gfxterm

insmod png

terminal_output  gfxterm

background_image $prefix/themes/1024x768.png

2.4 Grub显示中文界面(包括显示中文菜单项)

由于Grub在内部使用UTF-8编码,并且所有文本文件(包括'Grub.cfg')也都被假定为使用UTF-8编码,为了避免乱码,请务必以UTF-8编码保存'Grub.cfg'文件。

set gfxterm_font=unicode

set lang=zh_CN

set locale_dir=$prefix/locale

insmod gfxterm

terminal_output  gfxterm

loadfont unicode

2.5 更改Grub的字体

如果默认的unicode字体在1024x768或更高分辨率的屏幕上显得太小,或者默认的字体不好看,可以使用"Grub-mkfont"工具。下面的示例展示了制作一个24px大小的pf2字体:

Grub-mkfont -i1 -n WenQuanYiMicroHeiMono24px -o WenQuanYiMicroHeiMono24px.pf2 -s24 -v wqy-microhei.ttc

将制作好的字体文件(WenQuanYiMicroHeiMono24px.pf2)放到"$prefix/fonts"目录中,修改'Grub.cfg'文件中的两行:

set gfxterm_font=WenQuanYiMicroHeiMono24px

loadfont WenQuanYiMicroHeiMono24px

2.6 Grub-2.0.6版本官方模块

模块间的依赖关系位于"moddep.lst"文件中

2.6.1 命令模块[command.lst]

提供了各种不同的功能,类似标准Unix命令。

insmod module载入名为"module"的Grub模块。

set [envvar=value]将环境变量"envvar"的值设为'value'。如果没有使用参数,则打印出所有环境变量及其值。

help [pattern …]显示内建命令的帮助信息。如果没有指定"pattern",那么将显示所有可用命令的简短描述。如果指定了"pattern",那么将只显示名字以这些"pattern"开头的命令的详细帮助信息。

halt [--no-apm]关闭计算机。如果指定了 --no-apm 选项,表示不执行APM BIOS调用。否则,计算机使用APM关闭。

boot启动已经被载入的OS或链式加载器。仅在运行于交互式命令行的时候才是需要的。在一个菜单项结束时是隐含的。

cat [--dos] file显示文件"file"的内容。如果使用了"--dos"选项,那么"回车/换行符"将被显示为一个简单的换行符。否则,回车符将被显示为一个控制符(<d>)。

ls [arg …]如果不使用参数,那么列出所有对Grub已知的设备。

如果参数是包含在括号内的一个设备名,那么列出该设备根目录下的所有文件。

如果参数是以绝对路径给出的目录,那么列出这个目录的内容。

lsmod列出已经加载的所有模块

normal_exit退出当前的普通模式。如果这个普通模式实例不是嵌套在另一个普通模式里的话,就会返回到救援模式。

2.6.2 加密模块[crypto.lst]

提供了各种数据完整性校验与密码算法支持,一共20多个。例如:gcry_rijndael crc64 gcry_md5 ...

2.6.3 文件系统模块[fs.lst]

提供了访问各种文件系统的功能,一共30多个。例如:btrfs cpio exfat ext2 fat iso9660 ntfs tar xfs zfs ...

2.6.4 分区模块[partmap.lst]

提供了识别各种分区格式的功能,一共10多个。例如:part_bsd part_gpt part_msdos ...

2.6.5 分区工具[parttool.lst]

提供了操作各种分区格式的功能,目前只有 msdospart 这一个。

2.6.6 终端模块[terminal.lst]

提供了各种不同终端的支持,一共不到10个。例如:serial gfxterm vga_text at_keyboard ...

2.6.7 视频模块[video.lst]

提供了各种不同的视频模式支持,一共6个。例如:vga vbe efi_gop efi_uga ...

2.6.8 其他模块

所有未在上述分类文件中列出的模块都归为这一类,一共将近100个。值得关注的有以下几个:

"all_video"可用于一次性加载当前所有可用的视频模块;

"gfxmenu"可用于提供主题支持;

"jpeg png tga"可用于提供特定格式的背景图片支持;

"xzio gzio lzopio"可用于提供特定压缩格式支持(常配合"initrd"命令使用);

2.7 Grub救援模式Rescue

进入救援模式,这意味着Grub由于某种原因未能加载“模块”或者Grub没有在正确的位置读取。

# Inspect the current prefix (and other preset variables):

set    可以输入set查看一下当前信息

# Find out which devices are available:

ls       查看Grub位置

# Set to the correct value, which might be something like this:

set prefix=(hd0)/Grub               

set root=(hd0)

insmod normal

normal     回到引导界面上

  • Grub配置文件

3.1 Grub配置文件生成与更新

Grub-mkconfig脚本自动生成 /boot/Grub/Grub.cfg,不需要手动修改。

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

/etc/Grub.d/脚本包含 Grub 菜单信息和操作系统引导脚本,运行 update-grub 命令时,它会读取 Grub 文件和 Grub.d 脚本的内容,并更新创建Grub.cfg文件。

3.2 Grub配置文件详解

下图为在Linux系统下,/etc/default/Grub内包含的自定义Grub配置文件。

 

(1)Grub_DEFAULT

默认的菜单项,默认值为0。其值可为数值N,表示从0开始计算的第N项是默认菜单

也可以指定对应的title表示该项为默认的菜单项。使用数值比较好,因为使用的title可能包含了容易改变的设备名

(2)Grub_SAVEDEFAULT

默认该key的值未设置。如果该key的值设置为true时,如果选定了某菜单项,则该菜单项将被认为是新的默认菜单项。该key只有在设置了"Grub_DEFAULT=saved"时才有效。

(3)Grub_TIMEOUT

在开机选择菜单项的超时时间,超过该时间将使用默认的菜单项来引导对应的操作系统。

默认值为5秒。等待过程中,按下任意按键都可以中断等待。

设置为0时,将不列出菜单直接使用默认的菜单项引导与之对应的操作系统,设置为"-1"时将永久等待选择。

(4)Grub_TIMEOUT_STYLE

如果该key未设置值或者设置的值为"menu",则列出启动菜单项,并等待"Grub_TIMEOUT"指定的超时时间。

如果设置为"countdown"和"hidden",则不显示启动菜单项,而是直接等待"Grub_TIMEOUT"指定的超时时间。如果超时了则启动默认菜单项并引导对应的操作系统

(5)Grub_BACKGROUND

设置背景图片,背景图片必须是Grub可读的,图片文件名后缀必须是".png"、".tga"、".jpg"、".jpeg",在需要的时候,Grub会按比例缩小图片的大小以适配屏幕大小。

(6)Grub_THEME

设置Grub菜单的主题。

四、Grub源码分析

4.1 Grub源代码下载

Grub源代码下载地址:https://ftp.gnu.org/gnu/Grub/,如下图所示根据系统编译环境选择需要的Grub源代码。

 

4.2 Grub源代码文件简介

本次选择下载Grub-2.06.tar.gz

 

在终端输入 tar zxvf Grub-2.06.tar.gz解压文件,进入Grub-2.06文件夹

 

asm-tests:这里面是几个汇编代码文件;

build-aux:包含了编译时可能用到的脚本;

conf:编译需要用的文件,make的时候会用到;

docs:帮助文件,还有Grub.cfg示例模板;

Grub-core:Grub的主体核心代码;

include:Grub主体的头文件;

m4:包含m4文件,configure的时候会使用到;

po:这个目录下主要由两种文件,一种时.po文件,另一种时.gmo文件。它们是用来支持多语言的,这个文件夹内的东西不要管,只是对代码做一些基本的注释;

tests:一些测试的脚本;

themes:Grub界面的主题;

unicode:Unicode数据;

util:一些工具源的文件。

启动时运行的代码在' Grub-core '的子目录中,在启动完整操作系统后运行的代码在顶层的子目录中。

4.3 Grub核心代码详解

Grub内核在' Grub -core/kern/ '中,它包含一些核心工具,比如设备、磁盘和文件框架、环境变量处理、列表处理等等。

Grub-2.06/Grub-core/kern/main.c  调用其它外部函数(没有在 main.c 中定义的);

Grub-2.06/Grub-core/kern/  目录下的其它源文件,分别提供这些外部函数的定义(实现了这些函数的具体功能);

Grub-2.06/include/Grub/   目录下的头文件,则对应这些外部函数的声明;

Grub-2.06/Grub-core/kern/ 目录下的与这些头文件与同名的 C 源文件;定义main.c 包含的这 12 个头文件,全部位于Grub-2.06/include/Grub/  目录下。

终端实现在' Grub-core/term/ '中。

磁盘访问代码分布在' Grub-core/ Disk / '(用于访问磁盘设备本身)' Grub-core/partmap/ '(用于解释分区表数据),和' Grub-core/fs/ '(用于访问文件系统)。注意,除了一些特殊的例外,Grub只包含从文件系统读取的代码,并试图避免包含任何要写入文件系统的代码;这让我们可以放心地向用户保证,Grub不会导致文件系统损坏。

PCI和USB总线处理在' Grub-core/bus/ '中。

视频处理代码在' Grub-core/ Video / '中,图形化菜单系统大量使用这个功能。

大多数命令都是通过' Grub-core/commands/ '中的文件实现的。

在Grub_main之前,有一段汇编代码:

start:

_start:

         movq        %rcx, EXT_C(Grub_efi_image_handle)(%rip)

         movq        %rdx, EXT_C(Grub_efi_system_table)(%rip)

         andq         $~0xf, %rsp

         call   EXT_C(Grub_main)

进入Grub源代码,执行Grub_main函数。

  • Grub编译与安装

5.1 卸载Grub

卸载掉旧的Grub:apt-get purge Grub-pc。

5.2 UEFI模式下编译生成Grub

Grub使用Autoconf和Automake,大部分Automake输入由Python脚本生成。顶级构建规则在' configuration .ac '中,‘Grub-core / Makefile.core.def’,‘Makefile.util.def’。' *.def '文件中的每个块代表一个构建目标,并指定用于在不同平台上构建该目标的源文件。' *.def '文件被' gentpl.py '处理成Automake输入。

使用configure工具生成Makefile文件时:

./autogen.sh 生成configure文件

./configure --prefix=/usr(安装目录) --with-platform=efi(指定平台pc/uefi)  --target=x86_64(指定目标的处理器架构类型,或i386) --sysconfdir=/etc(配置文件目录) --disable-werror(不把报警归结于错误)

make -j4让make最多允许4个编译命令同时执行,这样可以更有效的利用CPU资源

make install 安装编译生成的文件

Grub-install /dev/sda                 安装到启动盘

sudo update-Grub            更新grub配置文件

5.2.1 制作一个BOOT.EFI可启动镜像

在make install之后

#grub-mkimage -O x86_64-efi -d ./grub-core/ -p /boot/EFI/BOOT/ -o bootx64.EFI boot reboot linux  part_gpt part_msdos disk fat exfat ext2 ntfs xfs  hfs iso9660 normal search_fs_file configfile  chain loopback echo efi_gop  file gfxterm gfxterm_background gfxterm_menu halt help  ls png true

UEFI启动是通过/boot/EFI/BOOT/xxxx.EFI来启动grub引导。

参数解析如下:

-d 表示指定查找模块目录

-p 设置gurb目标文件的文件夹,cfg文件中会调用。

-o 表示生成的目标文件        bootx64.efi

-O 表示集成的平台模块   写 i386-pc  x86_64-efi

BOOTx64.EFI后面全是命令模块,可以根据自己的需求进行添加。

拷贝到指定位置

# cp BOOTx64.EFI /boot/EFI/BOOT/

# reboot

重启就可以使用新编译的BOOTx64.EFI进行引导内核启动了。

grub.cfg修改启动主要配置项解析

配置项     解析

default     指grub启动时默认菜单项,表示默认从哪个菜单启动。默认配置为0。

timeout    指菜单到自动启动系统前停留时间,单位时间为sec。

title           指一个启动操作系统的名称。

root          指相应内核镜像所在目录boot所在的磁盘分区 如:root=‘hd0,msdos1’。

linux          指boot目录下内核镜像的名称。

initrd         指linux的initial ramdisk在boot目录下的名称。

boot          指引导内核进行启动。

gurb2命令说明

命令                                              说明

grub-editenv                                编译环境块工具

grub-mkfont                                 设置grub使用的字体

grub-mkimage                    生成一个gurb的可启动镜像

grub-mkrescue                            生成一个适用于软盘的grub的可启动镜像

grub-install                                   在磁盘上安装grub

grub-mkconfig                    生成grub配置文件

grub-mkdevicemap          生成一个新的device map文件

grub-probe                                   扫描计算机收集磁盘和分区信息

grub-set-default                          配置默认启动项

grub-reboot                                 配置重启之后的默认启动项

5.3 Grub中Makefile的指令

5.3.1 clean

清除当前目录下在 make 过程中产生的文件。它不能删除软件包的配置文件,也不能删除 build 时创建的那些文件。

5.3.2 distclean

类似于"clean",删除当前目录下的的配置文件、build 过程产生的文件。

5.3.3 info

产生必要的 Info 文档。

5.3.4 check 或 test

完成所有的自检功能。在执行检查之前,应确保所有程序已经被创建(但可以尚未安装)。为了进行测试,需要实现在程序没有安装的情况下被执行的测试命令。

5.3.5 install

完成程序的编译并将最终的可执行程序、库文件等拷贝到指定的目录。此种安装一般不对可执行程序进行 strip 操作。

5.3.6 install-strip

和"install"类似,但是会对复制到安装目录下的可执行文件进行 strip 操作。

5.3.7 uninstall

删除所有由"install"安装的文件。

5.3.8 installcheck

执行安装检查。在执行安装检查之前,需要确保所有程序已经被创建并且被安装。

5.3.9 installdirs

创建安装目录及其子目录。它不能更改软件的编译目录,而仅仅是创建程序的安装目录。

5.4 Grub编译

Grub源代码不需要修改makefile文件,添加新的.c和.h文件后,需要修改配置文件。如果添加一个新的模块遵循现有的模式,比如一个新的命令或一个新的文件系统,只需要修改两个文件内容。

此处修改Hello模块命令代码,新增对硬盘文件读取与SM3度量,文件内容为abc。

 

5.4.1 Grub-core/Makefile.core.am

Platfor_PROGRAMS

*************

*.marker:**

5.4.2 Grub-core/Makefile.core.def

添加新的模块

Module = {

Name = cmd;

Common = cmd/cmd.c;

};

5.4.3 hello模块

Grub源代码在发布时候,给出了一个测试指令模块,hello.mod。如果在Grub界面,按c进入命令模式,输入hello,会得到下图:

 

添加类似hello这类命令时,按照上述方式,在Grub-core/目录下添加ptest文件夹,加入ptest.c文件,修改Makefile文件即可添加命令模块。

 

5.4.4 在main函数中新增功能

需要在makefile.core.def中,在126行以后添加到kern中

common = kern/模块.c

会自动将文件与main.c一起编译

  • Grub文件介绍

6.1 /Boot目录

vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux支持虚拟内存,

zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有 gzip解压缩代码。

vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。

initrd是文件系统,“initial ramdisk”的简写,initrd一般被用来临时地引导硬件到实际内核vmlinuz能够接管并继续引导的状态。

System.map是内核符号映射表,顾名思义就是将内核中的符号(也就是内核中的函数)和它的地址能联系起来的一个列表。

6.2 /Boot/Grub目录

[root@study ~]# ls -l /boot/Grub

-rw-r--r--.  device.map            <==Grub 的设备对应文件(下面会谈到)

drwxr-xr-x.  fonts                 <==启动过程中的画面会使用到的字体数据

-rw-r--r--.  Grub.cfg              <==Grub 的主配置文件!相当重要!

-rw-r--r--.  Grubenv               <==一些环境区块的符号

drwxr-xr-x.  i386-pc               <==针对一般 x86 PC所需要的 Grub 的相关模块

drwxr-xr-x.  locale                <==就是语言相关的数据啰

drwxr-xr-x.  themes                <==一些启动主题画面数据

[root@study ~]# ls -l /boot/Grub/i386-pc

-rw-r--r--.  acpi.mod              <==电源管理有关的模块

-rw-r--r--.  ata.mod               <==磁盘有关的模块

-rw-r--r--.  chain.mod             <==进行 loader 控制权移交的相关模块

-rw-r--r--.  command.lst           <==一些指令相关性的列表

-rw-r--r--.  efiemu32.o            <==下面几个则是与 uefi BIOS 相关的模块

-rw-r--r--.  efiemu64.o

-rw-r--r--.  efiemu.mod

-rw-r--r--.  ext2.mod              <==EXT 文件系统家族相关模块

-rw-r--r--.  fat.mod               <==FAT 文件系统模块

-rw-r--r--.  gcry_sha256.mod       <==常见的加密模块

-rw-r--r--.  gcry_sha512.mod

-rw-r--r--.  iso9660.mod           <==光盘文件系统模块

-rw-r--r--.  lvm.mod               <==LVM 文件系统模块

-rw-r--r--.  mdraid09.mod          <==软件磁盘阵列模块

-rw-r--r--.  minix.mod             <==MINIX 相关文件系统模块

-rw-r--r--.  msdospart.mod         <==一般 MBR 分区表

-rw-r--r--.  part_gpt.mod          <==GPT 分区表

-rw-r--r--.  part_msdos.mod        <==MBR 分区表

-rw-r--r--.  scsi.mod              <==SCSI 相关模块

-rw-r--r--.  usb_keyboard.mod      <==下面两个为 USB 相关模块

-rw-r--r--.  usb.mod

-rw-r--r--.  vga.mod               <==VGA 显示适配器相关模块

-rw-r--r--.  xfs.mod               <==XFS 文件系统模块

-rw-r--r--.  hello.mod             <==hello模块,用来做基本的测试

6.3 文件介绍

boot.img

相当与 GRUB 的 stage1 它被写入 MBR或 boot分区,它不能识别任何文件系统

在GRUB2安装时GRUB2内核镜像在磁盘中到位置写入到 boot.img 中

这就使得 boot.img 能够在不能识别文件系统的情况下加载内核镜像

cdboot.img

当从CD引导情况下被写入内核镜像第一个扇区到内容,它负责加载其余的内核镜像到内存。

diskboot.img

当从磁盘引导情况下被写入内核镜像第一个扇区到内容,它负责加载其余的内核镜像到内存。

pxeboot.img

当从网络启动时使用到的。

kernel.img

此镜像包含GRUB2运行时包含的基本工具,框架驱动、文件句柄、环境变量、安全模式命令行解析器等

他可以直接使用但是通常它会被编译进所有的内核镜像中使用。

core.img

这是GRUB2的内核镜像,它由grub-mkimage程序将kernel.img和一些模块动态编译而成,一般情况下他已经包含足够的模块去访问/boot/grub,模块机制使得内核镜像能保持很小的尺寸。在某种程度上,它可以被视为 GRUB 中的 stage2。

*.mod

这是一些可以动态加载的一些模块,当我们需要时,可以将它们可以被动态加载编译进内核镜像

也可以使用insmod手动加载。他们就代替 GRUB 中的 stage1_5 之类到镜像

  • Grub启动解析

UEFI将Bootx64.efi文件Load到内存中加载,第一个运行的函数grub_main(),代码路径位于grub/grub-core/kern/main.c中,整个grub的功能可以说基本上都是在这个函数中完成的。

其主要的代码原理是注册一些命令和对应的回调函数,然后解析grub.cfg去执行对应的命令,一次执行其中的mod。在执行linux命令的时候去加载内核,将内核加载到一个内存地址上,执行initrd命令的时候去加载initrd,将initrd也加载到一个内存地址上,然后执行boot命令,开始解压并解析内核,这个时候拿到内核运行的基地址,并将整个内核拷贝到对应的地址上,并开始运行,这样就开时了操作系统的启动过程。

Grub编程解析

GRUB_MOD_INIT:加载该模块时执行的函数,通常用于初始化模块,注册模块命令,设置环境变量。

GRUB_MOD_FINI:释放该模块时执行的函数,主要用于清理。

grub_register_command函数:用于注册命令,第一个参数为命令名称,第二个参数为该命令执行的函数,第三个参数为该命令的注释。

Grub启动解析

Grub-core/kenner/main.c

grub_machine_init:设备初始化;

这个函数是和体系架构相关的,在Arm、MIPS、x86上的实现都不同,这个函数主要的作用就是初始化在本平台上需要做的必要的操作,例如获取后面grub要执行的每个moudule的基地址,初始化控制台,初始化内存管理系统,grub内部有自己的一套机制来管理内存。社会看门狗,挂载硬盘设备等操作都是在这个函数内做的。

内部函数grub_efi_loongson_init ()函数主要的作用就是获取了内核和固件传参结构中的SMBIOS的那个表,然后通过函数为后面需要传递的整个参数申请内存空间,来存放这数据。

grub_boot_time ("After machine init.");  挂起

grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); 打印信息高亮

grub_printf ("Welcome to GRUB!\n\n"); 打印信息

grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); 打印信息正常

grub_load_config

这个函数的作用就是找到后面要执行的其moudule类型为OBJ_TYPE_CONFIG的moudule,然后将这个moudule拷贝到这里申请的一段内存中。

grub_load_modules

这个函数就是去执行Grub中的命令对应的moudule的入口函数。每一个moudule函数是通过GRUB_MOD_INIT(linux)类似与内核编译的形式编译成每一个section中。然后当运行的时候,就运行对应的这里编译的代码,这里面都是注册的命令的代码,这里面的命令包含Linux、initrd两个命令。这两个命令是在grub.cfg中使用的。当运行这两个命令的时候,就会调用这里面注册的命令的回调函数去运行。这里面只是去注册对应的命令,最后通过boot命令来真正的运行内核。linux命令就是去加载内核,initrd就是其加载initrd。所以grub_load_modules()的作用就是去调用注册的命令的函数,为后面使用的命令做准备。这里面 (mod->init) (mod);这行代码才是真正去执行上面提到的GRUB_MOD_INIT(linux)函数。

函数grub_set_prefix_and_root ()

这个函数是设置环境变量prefix和boot这两个环境变量的,后期我们使用效果如下:

Const char*  prefix_env_path = grub_env_get(“prefix”);   //(hd0,gpt2)/boot/grub

Const char*  root_env_path = grub_env_get(“root”); // hd0,gpt2

Grub_load_measurement_mode()函数

执行度量功能,度量grub.cfg配置文件以及启动可选择的所有内核文件和初始化文件系统。

函数reclaim_module_space ()

这个函数是回收前面运行每个moudule的时候,将moudule加载到内存所占用的内存的地址。

函数grub_register_core_commands ()

这个函数就是注册set命令、unset命令、ls命令和insmod命令的回调函数。具体源代码在corecmd.c文件中,四个命令的回调函数分别为grub_core_cmd_set/unset/ls/insmod。

函数if(load_config)                   grub_parser_execute(load_config)

这个函数的作用就是解析grub.cfg中的内容,并运行对应的命令。

在grub_rescue_parse_line函数中,(cmd->func) (cmd, n - 1, &args[1])去执行对应命令的回调函数。

grub_load_normal_mode ()

这个函数就是执行normal这个命令对应的mod

函数grub_rescue_run

这个函数是防止如果上面的函数grub_parser_execute没有执行,那么就在这里去解析grub.cfg中的命令。

Grub_linux_boot函数

在不同的平台下对应着不同的Grub_linux_boot函数,主要完成了BIOS向内核传递参数和开始运行内核的功能。

这个函数最后return grub_relocatorXX_boot (relocator, state, 0);是跳转到内核开始执行内核代码的函数,前面的几个函数主要是完成给内核传递参数。

在command.c文件中,有注册命令和注销命令两个函数。

函数grub_register_command_prio才是最终将命令注册到全局变量grub_command_t grub_command_list这个链表中的。linux命令注册的时候对应的回调函数就是grub_cmd_linux,而initrd对应的回调函数就是grub_cmd_initrd,这就是在使用这两个命令的时候,去执行的函数就是这两个函数。

grub_register_exported_symbols:导入系统函数符号;

grub_load_modules:导入需要镜像中mod;

reclaim_module_space:释放模块占用的内存空间;

grub_register_core_commands:注册内核命令,set,unset,ls,insmod;

grub_load_normal_mode:执行normal命令,进入normal模块开始执行,grub_cmd_normal(Grub-core/normal/main.c)函数,如果没有配置文件或运行参数,该函数会退出,否则不退出。

grub_rescue_run:进入命令行操作界面

Grub-core/normal/main.c

grub_env_get ("prefix"):获取制作镜像是指定配置文件路径,生成grub.cfg文件的绝对路径,例如:TFTP的为(tftp,192.168.5.1)grub2/grub.cfg;

grub_enter_normal_mode:进入normal模块的grub_normal_execute;

grub_normal_execute:执行read_config_file,读取并执行配置文件;

获取需要从外部导入的命令列表,文件为command.lst,导入对应的模块;

获取需要从外部导入的文件系统列表,文件为fs.lst,导入对应的模块;

获取需要从外部导入的密码列表,文件为crypto.lst,导入对应的模块;

获取需要从外部导入的终端列表,文件为terminal.lst,导入对应的模块;

read_config_file:执行grub_file_open,打开配置文件,文件名为grub.cfg;

grub_file_open:打开配置文件为内存文件;

grub_bufio_open:打开内存文件;

按行执行配置文件;

网络文件系统解析

网络文件操作相关操作

grub_file_open(grub-core/kernel/file.c):第一个参数为文件路径,第二个参数为grub文件类型,函数调用grub_device_open,参数为“tftp,192.168.5.1”;

获取设备名称,调用grub_device_open打开设备,并将返回的设备赋值给grub_file的device字段;

调用grub_fs_probe探测文件系统,赋值给grub_file的fs字段;

调用文件系统fs-open字段函数打开文件,实为grub_net_fs_open函数;

grub_device_open(grub-core/kernel/device.c):

如果设备名称为空,打开环境变量root指定的路径;

首先尝试打开个该文件名的disk,如果打开,则返回该设备;

调用grub_net_open(),打开网络,并将返回的grub_net填入device的net字段。

返回device;

grub_net_open:为全局函数变量,在include/grub/net.h中使用extern进行引用,在net模块初始化函数中使用grub_net_open_real进行赋值。

grub_net_open_real(grub-core/net/net.c):

首先根据参入的名称,查找server的ip地址和协议(protname);

从grub_net_app_level_list链表中查找那个协议与需要的相同(protname),并将找到的protocol赋值给grub_net的protocol字段,同时将grub_net_fs赋值给grub_net的fs字段。

grub_net_app_level_list(全局变量):tftp和http模块在初始化时,调用grub_net_app_level_register(include/grub/net.h)函数将各自的grub_net_app_protocol结构体注册进来。

grub_net_fs_open:

初始化ile->device->net->packs;

调用file->device->net->protocol->open打开文件,实为tftp_open函数;

read_config_file_getline:从grub_file中获取一行数据,调用grub_file_getline;

grub_file_getline:调用grub_file_read读取数据;

grub_file_read:调用file->fs->fs_read读取数据,实际为grub_net_fs_read;

grub_net_fs_read:调用grub_net_fs_read_real执行读取;

grub_net_fs_read_real:从已接收的网络缓冲区中读取数据,如果文件数据不足,调用net->protocol->packets_pulled(实际为tftp_packets_pulled)继续通过网络读取数据。

TCP操作解析

grub_net_tcp_open(grub-core/net/tcp.c):创建一个TCP连接,构建一个SYNC包,并调用grub_net_send_ip_packet发送;

grub_net_send_ip_packet:根据IP类型,选择grub_net_send_ip4_packet发送;

grub_net_send_ip4_packet:添加IP头,调用send_ethernet_packet发送;

send_ethernet_packet:添加MAC头,调用inf->card->driver->send发送,实际为grub_pxe_send(grub-core/net/drivers/i386/pc/pxe.c);

grub_pxe_send:调用grub_pxe_call发送数据包;

grub_net_poll_cards:接收调用receive_packets网络数据包

receive_packets:调用card->driver->recv获取网络数据包,实际为grub_pxe_recv。

receive_packets:调用grub_net_recv_ethernet_packet解析接收的数据包;

grub_net_recv_ethernet_packet:解析出MAC包头,调用grub_net_recv_ip_packets解析IP数据包;

grub_net_recv_ip_packets:调用grub_net_recv_ip4_packets解析IPV4数据包;

grub_net_recv_ip4_packets:解析Ipv4数据包,调用handle_dgram执行;

handle_dgram:根据数据包协议,调用grub_net_recv_tcp_packet解析TCP数据;

grub_net_recv_tcp_packet:处于TCP协议相关交互,如果接收到数据,调用sock->recv_hook返回给客户,该函数为调用grub_net_tcp_open该函数时赋值的接收到数据的回调函数。

foil@foil:~/Downloads$ # 添加32位图形驱动支持 sudo apt install mesa-vulkan-drivers:i386 libgl1-mesa-dri:i386 Reading package lists... Done Building dependency tree... Done Reading state information... Done Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created or been moved out of Incoming. The following information may help to resolve the situation: The following packages have unmet dependencies: apt : Depends: gpgv Depends: libapt-pkg6.0t64 (>= 2.7.14build2) but it is not going to be installed Depends: libsystemd0 but it is not going to be installed bsdutils : PreDepends: libsystemd0 but it is not going to be installed dpkg : PreDepends: liblzma5 (>= 5.4.0) but it is not installable PreDepends: libmd0 (>= 0.0.0) but it is not installable PreDepends: libzstd1 (>= 1.5.5) but it is not installable PreDepends: zlib1g (>= 1:1.1.4) but it is not installable init : PreDepends: systemd-sysv login : PreDepends: libpam-runtime but it is not going to be installed PreDepends: libpam-modules but it is not going to be installed mesa-vulkan-drivers:i386 : Depends: python3:any shim-signed : Depends: grub-efi-amd64-signed (>= 1.191~) but it is not going to be installed or grub-efi-arm64-signed (>= 1.191~) but it is not installable or base-files (< 12.3) Depends: grub-efi-amd64-signed (>= 1.187.2~) but it is not going to be installed or grub-efi-arm64-signed (>= 1.187.2~) but it is not installable Depends: grub2-common (>= 2.04-1ubuntu24) but it is not going to be installed util-linux : PreDepends: libsystemd0 but it is not going to be installed PreDepends: zlib1g (>= 1:1.1.4) but it is not installable E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.
03-26
The following packages have unmet dependencies: apt : Depends: libapt-pkg6.0t64 (>= 2.7.14build2) but it is not going to be installed init : PreDepends: systemd-sysv libdrm-nouveau2:i386 : Depends: libdrm2:i386 (>= 2.4.108) but it is not installable libedit2:i386 : Depends: libbsd0:i386 (>= 0.1.3) but it is not installable libegl1:i386 : Depends: libegl-mesa0:i386 but it is not installable libgbm1 : Breaks: libgbm1:i386 (!= 24.2.8-1ubuntu1~24.04.1) but 24.0.5-1ubuntu1 is to be installed libgbm1:i386 : Depends: libdrm2:i386 (>= 2.4.119) but it is not installable Breaks: libgbm1 (!= 24.0.5-1ubuntu1) but 24.2.8-1ubuntu1~24.04.1 is to be installed libgl1-mesa-dri : Recommends: libgl1-amber-dri but it is not going to be installed Breaks: libgl1-mesa-dri:i386 (!= 24.2.8-1ubuntu1~24.04.1) but 24.0.5-1ubuntu1 is to be installed libgl1-mesa-dri:i386 : Depends: libdrm-amdgpu1:i386 (>= 2.4.119) but it is not installable Depends: libdrm-intel1:i386 (>= 2.4.119) but it is not installable Depends: libdrm-radeon1:i386 (>= 2.4.119) but it is not installable Depends: libdrm2:i386 (>= 2.4.119) but it is not installable Depends: libelf1t64:i386 (>= 0.142) but it is not installable Depends: libglapi-mesa:i386 (= 24.0.5-1ubuntu1) but it is not installable Depends: libzstd1:i386 (>= 1.5.5) but it is not installable Depends: zlib1g:i386 (>= 1:1.1.4) but it is not installable Recommends: libgl1-amber-dri:i386 but it is not installable Breaks: libgl1-mesa-dri (!= 24.0.5-1ubuntu1) but 24.2.8-1ubuntu1~24.04.1 is to be installed libglx0:i386 : Depends: libglx-mesa0:i386 but it is not installable libllvm17t64:i386 : Depends: libzstd1:i386 (>= 1.5.5) but it is not installable Depends: zlib1g:i386 (>= 1:1.2.0) but it is not installable libxdmcp6:i386 : Depends: libbsd0:i386 (>= 0.2.0) but it is not installable libxml2:i386 : Depends: libicu74:i386 (>= 74.1-1~) but it is not installable Depends: liblzma5:i386 (>= 5.1.1alpha+20120614) but it is not installable Depends: zlib1g:i386 (>= 1:1.2.3.3) but it is not installable shim-signed : Depends: grub-efi-amd64-signed (>= 1.191~) but it is not going to be installed or grub-efi-arm64-signed (>= 1.191~) but it is not installable or base-files (< 12.3) Depends: grub-efi-amd64-signed (>= 1.187.2~) but it is not going to be installed or grub-efi-arm64-signed (>= 1.187.2~) but it is not installable Depends: grub2-common (>= 2.04-1ubuntu24) but it is not going to be installed steam-libs-amd64 : Depends: libudev1 but it is not installable or libudev0 but it is not going to be installed Recommends: libasound2-plugins but it is not going to be installed steam-libs-i386:i386 : Depends: libgpg-error0:i386 (>= 1.10) but it is not installable Recommends: libasound2-plugins:i386 but it is not installable Recommends: libfontconfig1:i386 but it is not installable Recommends: libnm0:i386 but it is not installable Recommends: libva-drm2:i386 but it is not installable Recommends: libva-glx2:i386 but it is not installable Recommends: libva-x11-2:i386 but it is not installable Recommends: mesa-vulkan-drivers:i386 but it is not installable util-linux : PreDepends: libudev1 (>= 183) but it is not installable E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages. foil@foil:~/Downloads$
03-26
sudo apt install -y wine32 正在解析依赖... 有错误! 有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是 因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件 包尚未被创建或是它们已被从新到(Incoming)目录移出。 下列信息可能会对解决问题有所帮助: 无法满足的依赖关系: apt : 依赖: sqv 但是它将不会被安装 依赖: libapt-pkg7.0 (>= 2.9.33+kali1) 但是它将不会被安装 依赖: libssl3t64 (>= 3.0.0) 但无法安装它 依赖: libstdc++6 (>= 13.1) 但无法安装它 推荐: ca-certificates 但是它将不会被安装 coreutils : 预依赖: libgmp10 (>= 2:6.3.0+dfsg) 但无法安装它 预依赖: libssl3t64 (>= 3.0.0) 但无法安装它 dpkg : 预依赖: zlib1g (>= 1:1.1.4) 但无法安装它 libgcc-s1 : 依赖: gcc-14-base (= 14.2.0-17) 但无法安装它 破坏: libgcc-s1:i386 (!= 14.2.0-17) 但是 14.2.0-4ubuntu2 正要被安装 libgcc-s1:i386 : 破坏: libgcc-s1 (!= 14.2.0-4ubuntu2) 但是 14.2.0-17 正要被安装 python3 : 预依赖: python3-minimal (= 3.13.1-2) 但是它将不会被安装 依赖: python3.13 (>= 3.13.1-1~) 但是它将不会被安装 依赖: libpython3-stdlib (= 3.13.1-2) 但是它将不会被安装 shim-signed : 依赖: grub-efi-amd64-signed (>= 1.204~) 但是它将不会被安装 或 grub-efi-arm64-signed (>= 1.204~) 但无法安装它 依赖: grub2-common (>= 2.04-1ubuntu24) 但是它将不会被安装 依赖: mokutil (>= 0.3.0+1538710437.fb6250f-0ubuntu2) 但是它将不会被安装 依赖: sbsigntool 但是它将不会被安装 推荐: secureboot-db 但是它将不会被安装 错误: 错误,pkgProblemResolver::Resolve 发生故障,这可能是有软件包被要求保持现状的缘故。 错误: The following information from --solver 3.0 may provide additional context: Unable to satisfy dependencies. Reached two conflicting decisions: 1. libc6:i386 is selected for install because: 1. wine32:i386=9.0~repack-4build3 is selected for install 2. wine32:i386 依赖 libc6:i386 (>= 2.38) 2. libc6:i386 依赖 libgcc-s1:i386 but none of the choices are installable: - libgcc-s1:i386 is not selected for install because: 1. libgcc-s1:amd64 is selected for install 2. libgcc-s1:i386 破坏 libgcc-s1 (!= 14.2.0-4ubuntu2) For context, additional choices that could not be installed: * In libgcc-s1:amd64 -> | libgcc-s1:amd64=14.2.0-17 | libgcc-s
03-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值