存在UEFI后的启动

最近在做移动硬盘的启动系统,发现UEFI的许多好处,但也发现了一些以前没有注意的问题。
Legacy为传统BIOS,UEFI为新式BIOS
1,无UEFI+MBR硬盘 legacy
2,无UEFI +GPT硬盘 bios中有自己的处理方式UEFI支持,linux采用bios-grub分区(1M左右)来解决
3,UEFI+MBR硬盘
4,UEFI+GPT硬盘
现在的电脑基本都支持UEFI,只是支持的方式不太相同,在bios中也可以做选择。
一般情况下都是Legacy+MBR, UEFI+GPT这两种组合。但Legacy+GPT,UEFI+MBR也可以实现。
在这里插入图片描述CSM(Compatibility support Module)表示兼容模块,该选项专为兼容只能在legacy模式下工作的设备以及不支持或不能完全支持UEFI的操作系统而设置。因此,安装win7系统还需要把Launch CSM设置为Enable,表示支持Legacy引导方式。
对于有些主板来说,只有把Secure Boot Control即安全启动控制设置为Disable的时候才能把Launch CSM选项设置为Legacy
换win7的方法的两个步骤:
(1)、设置BIOS支持Legacy启动,具体目标就是设置secure boot control为Disable,兼容功能CSM选项设置为Enable,启动模式Boot Mode[UEFI/Legacy]设置为Legacy模式。
(2)、将硬盘的分区表类型由GUID变为MBR模式。

常规启动就不说了,Legacy用的是8086汇编,UEFI 99%以上用C,UEFI的APP和Drives可以用C/C++。
64位的UEFI固件是64位的操作系统(少数二合一平板用32位UEFI固件的可以忽略不计),Legacy是16位的。
Legacy是直接针对底层硬件细节,UEFI通过Firmware-OS Interface、Boot Services、Runtime Services为操作系统和引导器屏蔽了底层硬件的细节。
UEFI可以扩展,大多数硬件加载UEFI的驱动模块就可以完成初始化,驱动模块可以放在固件中,也可以放在设备上,比如显卡的GOP,系统启动就自动加载。UEFI中的每个Table和Protocol都有版本号,可以平滑升级。开发者可以自己根据规范开发UEFI应用程序和驱动程序。
UEFI基于time的异步操作,提高了CPU的效率,减少了等待时间。
UEFI舍弃了中断这种外部设备操作方式,仅保留了时钟中断,操作外部设备采用事件+异步操作,启动的时候按需加载外部设备。
UEFI有个安全启动功能,只有当程序的证书被信任才会被执行。
在UEFI模式下启动,启动的是EFI驱动和应用程序,而且只要系统一启动,就直接是64位的了。(少数二合一平板32位的UEFI固件忽略不计)
那么如果选择UEFI模式启动,所有的16位的MS-DOS实用程序,DOS工具包和其它的维护工具以及32位的应用程序都是无法加载和启动的。UEFI必须安装使用64位系统!
所以在UEFI模式下,我们不能引导32位的系统。

GPT分区表位于磁盘的逻辑扇区第2-33号扇区,一共占用32个扇区,能够容纳128 (4*32)个分区表项。每个分区表项大小为128字节,所以Windows系统允许GPT磁盘创建128个主分区。
分区表项中记录着分区的起始,结束地址,分区类型的GUID,分区的名字,分区属性和分区GUID。

GPT也有一个类似于MBR的东西,只不过引导记录是空的,windows磁盘签名有,而且分区表也有,只不过分区格式被定义为了EE,因为这个格式不存在,所以老旧的磁盘分区工具打开这个磁盘就会发现无法识别这个磁盘的格式,进而不会对磁盘进行分区操作。

看到这里,我们就已经明白了,所以说其实分区表也就是那么回事,GPT和MBR只不过是两种分配硬盘数据的方式而已。
GPT分区的0扇区可以写入主引导记录,也可以写入分区表,只不过需要手动换算一下。
所以传统Legacy BIOS启动GPT的分区是完全可行的。
而UEFI呢,本身就是读取硬盘的第一个FAT32分区的\efi\boot\bootx64.efi文件来引导系统的,那么无论分区格式是MBR还是GPT,都不会影响UEFI的正常引导。
这就是我们能够成功让传统BIOS启动GPT磁盘的操作系统;让UEFI启动MBR磁盘的操作系统的理论基础。
UEFI启动MBR,首先MBR分区表一定要有一个FAT32分区,是不是活动分区无所谓,因为UEFI没有活动分区的说法。
只要手动修复一下FAT32分区的BCD文件就行了,用BOOTICE工具编辑一下就OK
传统Legacy BIOS启动GPT,这个有点复杂,确实有点复杂……
其实也有几条技术路线可以选择的。
首先我们需求就是要传统Legacy 能启动gpt分区表的大硬盘。这个很繁琐,技术路线有几条,首先Legacy是可以读取主引导记录的440个字节,但是读了以后无法识别分区格式,所以说就要做一个镜像文件 里面包含需要使用的信息。目前有的是直接做的扇区编辑,jmp到特定的扇区,用这个扇区的信息来引导到目标的,非常繁琐,这个技术太复杂没法推广。
另一种技术路线,就是模拟uefi的方式,这种方式常见于变色龙,三叶草,clover,duet。这个技术路线相对来讲就简单了。如果你有两块硬盘,一块mbr和另一块gpt,这个就很简单了,从mbr磁盘启动,加载模拟uefi,然后再引导gpt磁盘的系统。
可是如果是单一gpt的磁盘,那还是免不了做扇区编辑,前面留空一段空间,然后把镜像用16进制写进去,再加载到内存,然后运行模拟uefi的程序。这就有点复杂,比如说搞电路的,交流变直流 然后整流 降压 再滤波什么的,费很大劲就为了一个看起来很简单的结果。

“EFI 系统分区”是采用 FAT 变种(UEFI 规范定义的变种之一)格式化的任意分区,该分区被赋予特定 GPT 分区类型,以帮助固件识别该分区。此分区的目的如上所述:固件层确实可以读取“普通”磁盘分区中的数据
UEFI 规范试图采用更直观严格的方法——它很少禁止固件执行其他操作。UEFI 规范并不反对编写固件,用于执行以其他格式写成的代码、读取其他类型的分区表,以及读取用UEFI 变种文件系统(非 FAT)格式化的分区。但是 UEFI 兼容固件必须至少能够实现执行 EFI 可执行文件、读取 GPT 分区表、以及读取 ESP,因此如果你正编写操作系统或其他东西,并且想要在 UEFI 兼容固件上运行的话,你也得遵循 UEFI 规范,这就是 EFI 系统分区的概念非常重要的原因:它允许(至少理论上)将 EFI 可执行文件放在以 UEFI FAT 格式化且 GPT 分区类型正确无误的分区上,另外,系统固件要能够读取该分区。这种机制非常严谨,等价于 BIOS 中的“固件能够执行放置在 UEFI 规范为我们提供了三大重要基础,这些重要基础是上层架构正常运行的立足之本:

读取分区表
访问某些特定文件系统中的文件
执行特定格式的代码 

相比 BIOS 固件所提供的功能,UEFI 的功能要丰富得多。但是,为了完成固件层可以处理多重目标(而不仅仅是磁盘)启动的愿景,我们需要其他基础:需要建立一种机制,通过这种机制,固件可以查找各种可能的启动目标,并提供相应的配置方法。 MBR 空间中的启动装载程序代码”。
如果已通过 UEFI 启动 Linux,就可以使用 efibootmgr 工具来完成所有这些操作。Windows 也有相应的工具,但是我对 Windows 下的工具非常不熟悉。我们不妨看一些典型的 efibootmgr 输出,这些是我从 Fedora 论坛转过来的,稍微进行了调整:

[root @system directory]# efibootmgr -v
BootCurrent: 0002
Timeout: 3 seconds
BootOrder: 0003,0002,0000,0004
Boot0000* CD/DVDDrive BIOS(3,0,00)
Boot0001* Hard Drive HD(2,0,00)
Boot0002* Fedora HD(1,800,61800,6d98f360-cb3e-4727-8fed-5ce0c040365d)File(\EFI\fedora\grubx64.efi)
Boot0003* opensuse HD(1,800,61800,6d98f360-cb3e-4727-8fed-5ce0c040365d)File(\EFI\opensuse\grubx64.efi)
Boot0004* Hard Drive BIOS(2,0,00)P0: ST1500DM003-9YN16G .
[root @system directory]#
这个示例非常清晰。我们可以从中观察细节。
第一行表示,目前你从“启动菜单”的哪个项进行了启动。第二行非常明显(如果固件的 UEFI 启动管理器显示了类似启动菜单的界面,那么这一行表示继续启动默认项之前的超时)。BootOrder 是列表中启动项的尝试顺序。其余输出显示了实际的启动项。我们稍后会说明每一个启动项具体作用。
如果完全正常启动 UEFI 固件,而不进行任何调整(我们稍后会讨论),UEFI 固件将按照BootOrder 中列出的顺序,尝试从“启动菜单”中的每个“项”进行启动。因此,在这台计算机上,UEFI 固件将尝试启动名为“opensuse”的项,如果启动失败,然后再尝试启动名为“Fedora”的项,然后再是“CD/DVD Drive”,接着是第二项“Hard Drive”。

“回退路径 (Fallback path)”UEFI 原生启动项

UEFI 规范定义了一种“回退”路径 (Fallback path),用于启动此类启动管理器项,其工作原理类似于 BIOS 驱动器启动:它会在标准位置查找某些启动装载程序代码。但是其中的细节和 BIOS 不同。

当尝试以这种方式启动时,固件真正执行的操作相当简单。固件会遍历磁盘上的每个 EFI 系统分区(按照磁盘上的分区顺序)。在 ESP 内,固件将查找位于特定位置的具有特定名称的文件。在 x86-64 PC 上,固件会查找文件 \EFI\BOOT\BOOTx64.EFI。固件实际查找的是 \EFI\BOOT\BOOT{计算机类型简称}.EFI,其中,“x64”是 x86-64 PC 的“计算机类型简称”。文件名还有可能是 BOOTIA32.EFI (x86-32)、BOOTIA64.EFI (Itanium)、BOOTARM.EFI(AArch32,即32位ARM)和 BOOTAA64.EFI(AArch64,即64位ARM)。然后,固件将执行找到的第一个有效文件(当然,文件需要符合UEFI规范中定义的可执行格 式)。

这种机制的设计目的不在于启动日常使用的操作系统。它的设计目的更像是为了启动可热插拔、与设备无关的介质(如 Live 映像和操作系统介质)。这也是这种机制的常见用途。如果查看 Linux 或其他操作系统的 UEFI 兼容 Live 或安装介质,你会发现其中包含 GPT,以及位于(或靠近)设备起始位置的 FAT 分区,该分区的 GPT 分区类型标识为 EFI 系统分区。在那个分区中,会有一个 \EFI\BOOT 目录,目录中至少包含上述特殊命名的文件之一。当以原生 UEFI 模式启动 Fedora Live 或安装介质时,就会采用这种机制。BOOTx64.EFI(或其他)文件将处理剩余启动过程,从而启动介质上包含的真正操作系统。

Linux发行版使用 efibootmgr 工具处理 UEFI 启动管理器。进行原生 UEFI 安装时,有关启动装载方面,Linux 发行版实际进行的操作相当简单:它会创建一个 EFI 系统分区(如果不存在此分区),使用相应配置将 EFI 启动装载程序(通常为 grub2-efi,但是也有例外)安装到 EFI 系统分区中的正确路径下,然后调用 efibootmgr 添加相应的 UEFI 启动管理器项(指向其启动装载程序)。如果已存在 EFI 系统分区,大部分发行版会使用现有分区(尽管完全可以创建新的 EFI 系统分区并使用这个新分区):我们已经提到过,UEFI 是一种宽松规范,只要在逻辑上遵循其设计,那么有多少个 EFI 系统分区都没问题。

许多固件的启动配置界面较直观。优秀的固件设计至少会显示启动顺序以及其中的各个启动项,允许用户添加/删除项、更改启动顺序或在某次特定启动中忽 略原有启动顺序(仅针对那次启动生效,或直接让固件启动特定菜单项,甚至可以选择让固件以 BIOS 兼容模式或 UEFI“回退 (Fallback)”模式“启动这块磁盘”,我的固件就可以这么操作)。此类界面通常可以仅按名称显示完整的原生 UEFI 启动项(例如我们上文提到的 Fedora 和 OpenSUSE 示例);你需要检查 efibootmgr –v 的输出,以详细了解在调用这些项时,它们具体会尝试并执行哪些操作。

某些固件会尝试对配置进行抽象和简化,最终结果良莠不齐。例如,如果可以选择“启用或禁用”BIOS 兼容模式,固件很有可能会为已连接驱动器的 UEFI 启动管理器配置添加或删除 BIOS 兼容项。如果可以选择“启用或禁用”原生 UEFI 启动,那么在用户“禁用”原生 UEFI 启动时,固件很有可能更改 UEFI 启动管理器配置,从 BootOrder 中删除所有原生UEFI启动项。

原生 UEFI 启动和 BIOS 兼容启动

用户有时会忽略以下事项:

如果以“原生 UEFI”模式启动安装介质,安装介质将以原生 UEFI 模式安装操作系统:它将尝试向 EFI 系统分区写入 EFI 格式的启动装载程序,并尝试向 UEFI 启动管理器的“启动菜单”中添加启动项,用于启动该启动装载程序。
如果以“BIOS 兼容”模式启动安装介质,安装介质将以 BIOS 兼容模式安装操作系统:它将尝试向磁盘上的 MBR 空间写入 MBR 类型的启动装载程序。 

UEFI下Windows引导过程
UEFI BIOS→EFI系统分区→\efi\boot\bootmgfw.efi→efi\Microsoft\Boot\BCD→\Windows\system32\winload.efi
EFI分区里面存放着系统启动所需的文件(bootmgfw.efi、BCD等)

uefi下启动linux

  1. 有两种方式
      1.1 直接从uefi shell启动linux内核
      1.2 从uefi shell启动grub,然后再从grub启动linux内核

  2. 需要哪些东西?
      2.1 linux内核
      2.2 initrd镜像
      2.3 .nsh后缀名的启动脚本(可选,可通过手动键入命令)
        某个.nsh的内容如下:
          Image initrd=\initrd.gz root=/dev/ram0 earlycon=uart
      2.4 BOOTAA64.EFI (这是arm64的EFI固件,可选)
      注: 这些东西需要放在fat文件系统中

  3. uefi shell启动linux内核的操作过程
      3.1 进入目标分区
      Shell> fs0:
      FS0:>
      3.2 启动linux内核
      FS0:>boot.nsh

  4. 从uefi shell启动grub, 然后启动linux内核
      4.1 进入目标分区
      Shell> fs0:
      FS0:>
      4.2. 进入grub
      FS0:>BOOTAA64.EFI
      4.3 在grub中设置临时访问的根节点
      grub> root=(hd0,msdos1) (hd0,msdos1中有linux内核镜像和initrd镜像)
      4.4 启动linux内核
      grub> linux /Image initrd=/initrd.gz earlycon=uart root=(hd0,msdos1) rw rootwait

猜你喜欢

转载自blog.csdn.net/seaship/article/details/111298362