如何使用 uefi 代码在 mbr 磁盘中加载旧版操作系统

如何使用 uefi 代码在 mbr 磁盘中加载旧版操作系统

我正在使用 EDK2 进行编程,我想在 UEFI 模式下使用我的 UEFI 应用程序加载旧版操作系统。

固件支持 UEFI/Legacy。如果我什么都不做,旧版操作系统 win7 将启动。如果我选​​择使用 efi shell 从 fat32 usb 块设备启动,efi shell 将启动。

我已经阅读了 UDK2014\IntelFrameworkModulePkg\Library\GenericBdsLib 中的源代码(UDK2014 是我的 edk2 工作区),EFI_LEGACY_BIOS_PROTOCOL 中的 LegacyBoot 函数不起作用,即使链接到 GenericBdsLib 我再次失败,我不知道我忽略了哪个细节。寻求帮助!!!

答案1

第一的:何必呢?这听起来可能像是一种讽刺和轻蔑的评论,但这是一个严肃的问题。在基于 EFI 的计算机上启动 BIOS 模式操作系统有正当理由,但您的问题没有提出这样做​​的动机。从编程的角度来看,这项任务很麻烦;正如您所说,目标操作系统是支持 EFI 模式启动的 Windows 7,我甚至不清楚这是否值得付出努力。此外,目前有三种方法可以做到这一点,无需编写新代码……

第一种方法是使用计算机的内置启动管理器。它应该提供启动您安装的任何 EFI 模式操作系统或 BIOS/CSM/传统模式的选项。不过,如何访问此菜单的细节因计算机而异,菜单上显示的内容的细节也会有所不同。最常见的是,从磁盘启动的 BIOS 模式由磁盘的制造商或型号标识,而 EFI 模式条目则被赋予与操作系统相关联的名称,例如Windows boot manager。使用此方法的结果不会完全符合您的描述(即从您自己的 EFI 应用程序启动 Windows),但它可能足以满足您的需求。

第二种方法是使用我的rEFInd 启动管理器。与计算机的内置启动管理器一样,rEFInd 允许您启动 BIOS 模式或 EFI 模式的启动加载程序(前提是固件支持这两种模式)。需要注意的是,在基于 UEFI 的 PC 上,此功能默认处于禁用状态;您必须编辑refind.conf以取消注释该scanfor行并确保该hdbios行在选项中。(如果目标 BIOS 模式操作系统位于外部磁盘或 CD 上,则还有其他关键字 - 有关详细信息,请参阅文件中的注释refind.conf。)与内置启动管理器一样,此解决方案不会确切地按照你说的做,但这可能就足够了。此外,您可以让您的应用程序启动 rEFInd,您可以配置一个短暂的超时时间,以默认启动 BIOS 模式操作系统。这种方法将产生您想要的效果,尽管 rEFInd 会带来很大的开销,因此这是一个相当不优雅的解决方案。

rEFInd 也与您的问题相关,因为它包含执行您想要的操作的代码。您应该关注refind/legacy.cEfiLib/legacy.c源代码文件。但请注意,rEFInd 包含两个截然不同的BIOS/CSM/legacy-mode 启动路径,一个用于 Mac,一个用于基于 UEFI 的 PC。由于您特别提到 UEFI,因此您很可能想要后者,而不是前者。在文件中refind/legacy.c,UEFI 代码主要位于名称包含字符串的函数中UEFI;其他函数用于 Mac。该EfiLib/legacy.c文件仅包含 UEFI 路径代码;但这些函数中的大多数都取自 TianoCore EDK2,因此您可能不需要复制它们。(由于 rEFInd 设计为使用 EDK2 或 GNU-EFI 构建,因此我最终提取了大量 EDK2 代码,以便可以使用 GNU-EFI 构建它。)另一方面,这些函数可能已从其 EDK2 来源进行了修改,因此如果您使用 EDK2 原件,您可能需要做更多调整才能使其正常工作。请注意,rEFInd 使用 GPLv3,因此如果您打算分发您的程序,使用 rEFInd 代码将需要使用 GPLv3 或兼容许可证。

完成这项工作的第三种方法是使用Clover 启动管理器。这是一个 Hackintosh 启动管理器,与 rEFInd 类似,部分源自较旧的(现已废弃)rEFIt 启动管理器。与 rEFInd 一样,Clover 包含启动 BIOS 模式操作系统的代码;但是,它执行此操作的方式与 rEFInd 不同。您可以像使用 rEFInd 一样使用 Clover,将其作为启动路径的一部分,或作为示例代码提取并合并到您自己的程序中。虽然 Clover 的 Sourceforge 页面说它使用 BSD 许可证,但这并不完全正确;一些源代码文件指定它使用 GPL。

不幸的是,如果您开始阅读 rEFInd 或 Clover 的代码,您很快就会发现,从 EFI 启动 BIOS 模式引导加载程序并非易事;我不能只是给您几行代码。另外,请注意,这段代码不是我自己写的;rEFInd 的代码是由其他人贡献给该项目的,虽然我阅读了 Clover 的代码,但我不能声称自己理解了它。我修改了 rEFInd 的 BIOS 模式引导代码,但我可能无法为您提供很多帮助,让您将其适应您自己的程序。

答案2

最后我成功地用 UEFI 代码启动了传统操作系统或 UEFI 操作系统,传统操作系统是指 MBR 磁盘中的操作系统,UEFI 操作系统是指 efi 应用程序(这是一种加载映像的简单方法,我们可以忽略它)。

导致我无法启动旧版操作系统的原因是缺少选项。我使用 BdsCreateOneLegacyBootOption 创建了一个选项并更新了 L"BootOrder",然后如果我选择由 BdsCreateOneLegacyBootOption 创建的启动选项,EFI_LEGACY_BIOS_PROTOCOL 中的 LegacyBoot 就会运行。LegacyBoot 需要一个 Devictpath,我从由 BdsCreateOneLegacyBootOption 创建的启动选项中提取了 DevicePath,并从由 BdsCreateOneLegacyBootOption 创建的启动选项中提取了选项数据。如果我在启动菜单中选择启动选项,我会失败,因为设备路径和选项数据不同。重启后启动选项发生了变化,也许主板做了一些我不知道的事情。

PS:BdsCreateOneLegacyBootOption 函数需要一个 BBSTable,并且导出一个 bootorder 列表,我们需要在变量 L"BootOrder" 中更新 bootorder 列表。BBSTables 可以通过 EFI_LEGACY_BIOS_PROTOCOL 中的 GetBbsInfo 来构建。

答案3

如果我什么都不做,旧版操作系统 win7 将启动。

太好了。那么,有问题吗?

我想我会关注问题的标题:如何使用 UEFI 代码在 MBR 磁盘中加载旧版操作系统......

噗,算了。

(U)EFI 本质上是计算机开机时启动的基本软件。那么,如果 (U)EFI 做同样的事情,那么我们为什么不把它称为“基本输入/输出系统”,就像以前用于启动这些旧操作系统的软件一样?

我们给 (U)EFI 起了新名字,是因为它不兼容。它是一个从头设计的新系统。

或者,实际上,它不兼容。我最近注意到有一些与“旧版”支持相关的新设置。因此,也许较新的版本已经添加了一些与旧版兼容的支持。但是,如果您选择禁用提供与旧版支持兼容的功能,则不能指望运行旧版软件。

BIOS 最著名的功能是执行 POST 等操作,并在操作系统启动时为操作系统提供一些与硬件交互的基本方法。但是,至少有些操作系统在运行了很长时间之后仍会继续与 BIOS 交互。例如,当计算机尝试访问驱动器以访问数据时,操作系统可能会使用其自己的代码,或者操作系统可能只是将一些请求传递给 BIOS 中的某些编程代码。(细节可能取决于您使用的操作系统以及您使用的驱动程序等细节。)

如果您要使用依赖于 BIOS 的操作系统,则需要使用实际的 BIOS 启动芯片或某种 (U)EFI 旧功能来提供与 BIOS 兼容的编程代码。如果没有旧功能支持,您就无法使用 (U)EFI;这就是 (U)EFI 被赋予新名称的原因。

基本上,(U)EFI 最初设计为支持 GPT,而不是依赖 MBR。

相关内容