Step to UEFI (138) Shell 下 BootOrder 的研究

对于普通用户来说,启动顺序显而易见,因此是重要的功能,比如:希望使用U盘安装系统,就必须能从U盘上引导起来。

在 Legacy 的时代,关于启动部分只有一份BBS specification可供参考,这个规范看起来非常生涩,缺点是理解不同,好处也是理解不同。很多年前,我遇到过一个客户报告的问题。他们使用IDE光驱,如果启动 失败并不会直接跳转到下一个启动设备而是显示 Boot Failure。板子上的南桥是 Intel最新推出的 ICH6, 刚好这一代南桥取消了IDE接口,为了兼容板子上使用了一颗 SATA转IDE 的JMicron 的芯片,启动的时候BIOS首先会 Load他们的Option ROM来完成初始化之类的工作。
问题确切,一时也找不到原因,我拿着BBS Spec翻来翻去,最终看懂了上面提到:报告不同种类设备(BEV 或者BCV)的启动 fail 有 Int 18 和 Int 19 的差别。于是,做了一个大胆的猜测:光驱启动失败之后,他们使用了某一种错误的报告错误方式,以至于我们在期待的点上没有办法“捕捉”到。接下来用十六进制工具,将 JMicron Option ROM 中的 INT 18 (CD 18)全都修改为 INT 19 (CD 19)。在重新编译BIOS的时间里顺便祈祷一番,然后烧录,实验成功故障消失。有了这样的结果,按照BBS 解读,再就去和 JMicron 理论了,最终他们重新给我们出了一个ROM问题解决。

时至今日,BIOS 已进化为 UEFI,启动引导有了统一的标准,使用上方便很多。理论部分可以在 UEFI Specification中的第三章 “3 Boot Manager”中看到,有兴趣的朋友可以仔细研读。

本文介绍如何在 Shell 下面查看启动顺序之类的设定,并且给出了一个实现查看的Application,资料和代码来自【参考1】 ,在此特别鸣谢。

先介绍一下原理,其实我是先看【参考2】的代码才理解的,如果下面讲述有误,也请读者朋友直接查看后面的代码,能否正常工作才是检验一切猜测的真理标准。

1. 启动设备的顺序设定
UEFI 下面的启动顺序是存储在 variable 中,放在 NVRAM 中的。使用 gRT->GetVariable ,参数为 “BootOrder”, GUID 如下即可取得设定的顺序
#define EFI_GLOBAL_VARIABLE
{0x8BE4DF61,0x93CA,0x11d2,0xAA,0x0D,0x00,0xE0,0x98,0x03,0x2B,0x8C}
取得的结果是一串数字(起初我以为有结构体,但是查找之后发现就是2个BYTE一组组成的)。
例如:实体机上,在 Shell 下 dmpstore 的结果如下:
Variable NV+RT+BS '8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootOrder' DataSize = 0x0C
00000000: 04 00 00 00 01 00 02 00-03 00 05 00 *............*
意思是 UEFI 会首先尝试0004设备, 然后是 0000设备,然后是 0001设备一直到最后,其中的 0004设备指的就是 BOOT0004

2.BOOTXXXX设备
在variable 中,还有 Boot0004这样的定义,例如:

Variable NV+RT+BS '8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0002' DataSize = 0x4A
00000000: 09 01 00 00 2C 00 45 00-6E 00 74 00 65 00 72 00 *....,.E.n.t.e.r.*
00000010: 20 00 53 00 65 00 74 00-75 00 70 00 00 00 04 07 * .S.e.t.u.p.....*
00000020: 14 00 67 D5 81 A8 B0 6C-EE 4E 84 35 2E 72 D3 3E *..g....l.N.5.r.>*
00000030: 45 B5 04 06 14 00 21 AA-2C 46 14 76 03 45 83 6E *E.....!.,F.v.E.n*
00000040: 8A B6 F4 66 23 31 7F FF-04 00 *...f#1....*

对应内容是一个结构体:
so
so2

Attributes中有一个项目是 LOAD_OPTION_ACTIVE,用来标记这个设备是否可以启动,如果设置起来,系统会尝试从它上面进行引导。如果你不想让这个设备启动,可以直接清楚该标志。这样无需增减项目就可以实现控制。
比较有趣的是其中的 Description,给出了一个人类易读的说明,比如上面的Boot0004 设备说明即为”Enter Setup”

3.当前启动设备

“BootCurrent”变量,可以用来指出当前的引导设备。比如:当前我直接启动到了 Shell 下,BootCurrent 记录的启动设备就是 Boot0000,即Internal EDK Shell
Variable NV+RT+BS '8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0000' DataSize = 0x58
00000000: 01 00 00 00 2C 00 49 00-6E 00 74 00 65 00 72 00 *....,.I.n.t.e.r.*
00000010: 6E 00 61 00 6C 00 20 00-45 00 44 00 4B 00 20 00 *n.a.l. .E.D.K. .*
00000020: 53 00 68 00 65 00 6C 00-6C 00 00 00 04 07 14 00 *S.h.e.l.l.......*
00000030: 22 F3 2C B9 FA 8A A4 4A-B9 46 00 5D F1 D6 97 78 *".,....J.F.]...x*
00000040: 04 06 14 00 B7 D6 7A C5-15 05 A8 40 9D 21 55 16 *......z....@.!U.*
00000050: 52 85 4E 37 7F FF 04 00- *R.N7....*
下面是来自【参考2】的Shell Application,可以显示和设定当前的启动顺序:

运行结果:
so3

X64 UEFI Application 下载  bttest

源代码下载:bootmgr

最后顺便说一下,JMicron 后来推出了新的Sata转 IDE 芯片,无需Option ROM 了,也就没有BIOS什么事情了。

参考:
1. http://kurtqiao.github.io/uefi/2015/01/13/uefi-boot-manager.html
2. https://github.com/kurtqiao/MyPkg/tree/master/Application/bootmgr

Step to UEFI (138) Shell 下 BootOrder 的研究》上有 1 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注