【UEFI基础】第一条指令

Reset Vector

本文讲述Intel x86系统启动后执行的最初的指令。在Intel提供的软件开发者手册《64 ia 32 architectures softerware developer manual》中,有一个小节”First Instruction Executed“专门讲述系统中第一条指令的位置。
在这里插入图片描述
上面的文字简单来说阐明了以下的几点:

  1. 第一条指令在的位置是0xFFFFFFF0(这个地址有个专有的名称Reset Vector);
  2. 解释了CPU起来后是实地址模式为什么能够访问到这么高的位置;
  3. 因为2的原因,在最初的代码中不应该有far jump等改变CS值的操作。

具体代码

Reset Vector的位置确定后,就可以在这个位置放上我们需要执行的代码。CPU将这个位置映射到了某些非易失介质上了,比如SpiFlash,而这个介质里面保存着BIOS二进制。(前面这种说法不知道是哪里看来的,准确性不可考了,或者是以前的BIOS的特性。目前的UEFI来说,一般是TXE加载非易失性介质中的BIOS的起始代码部分到SRAM中,而SRAM映射到了从4G往下的一段区域中,这同样保证了Reset Vector 的位置是在0xFFFFFFF0)

这里以UEFI代码为例。UEFI代码按照一定的格式放在二进制中,在Reset Vector指向的位置,放的是SEC阶段的代码,它们是未经过压缩的机器码,CPU可以直接拿来执行。对应到具体代码,如下:

%ifndef ARCH_IA32
  %ifndef ARCH_X64
    <span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><Base.h></span></span>
    <span class="hljs-meta">#<span class="hljs-keyword">if</span> defined (MDE_CPU_IA32)</span>
      %define ARCH_IA32
    <span class="hljs-meta">#<span class="hljs-keyword">elif</span> defined (MDE_CPU_X64)</span>
      %define ARCH_X64
    <span class="hljs-meta">#<span class="hljs-keyword">endif</span></span>
  %endif
%endif

%ifdef ARCH_IA32
  %ifdef ARCH_X64
    %error <span class="hljs-string">"Only one of ARCH_IA32 or ARCH_X64 can be defined."</span>
  %endif
%elifdef ARCH_X64
%<span class="hljs-keyword">else</span>
  %error <span class="hljs-string">"Either ARCH_IA32 or ARCH_X64 must be defined."</span>
%endif

%include <span class="hljs-string">"CommonMacros.inc"</span>

%include <span class="hljs-string">"PostCodes.inc"</span>

%ifdef DEBUG_PORT80
  %include <span class="hljs-string">"Port80Debug.asm"</span>
%elifdef DEBUG_SERIAL
  %include <span class="hljs-string">"SerialDebug.asm"</span>
%<span class="hljs-keyword">else</span>
  %include <span class="hljs-string">"DebugDisabled.asm"</span>
%endif

%include <span class="hljs-string">"Ia32/SearchForBfvBase.asm"</span>
%include <span class="hljs-string">"Ia32/SearchForSecEntry.asm"</span>

%ifdef ARCH_X64
%include <span class="hljs-string">"Ia32/Flat32ToFlat64.asm"</span>
%include <span class="hljs-string">"Ia32/PageTables64.asm"</span>
%endif

%include <span class="hljs-string">"Ia16/Real16ToFlat32.asm"</span>
%include <span class="hljs-string">"Ia16/Init16.asm"</span>

%include <span class="hljs-string">"Main.asm"</span>

%include <span class="hljs-string">"Ia16/ResetVectorVtf0.asm"</span>

上面的代码是用nasm写的汇编。实际上这里也没有涉及到具体的执行代码,真正重要的是ResetVectorVtf0.asm,其中有这样的代码:

resetVector:
;
; Reset Vector
;
; This is where the processor will begin execution
;
    nop
    nop
    jmp     EarlyBspInitReal16

ALIGN   <span class="hljs-number">16</span>

这段代码被写到了UEFI二进制的最后一行,刚好对应0xFFFFFFF0的位置,下面是实际二进制中的值:

90 90 E9 AB FF 90 90 90 90 90 90 90 90 90 90 90

前面的90h就是nop的机器码,而后面的E9h ABh FFh是跳转指令的机器码。跳转到EarlyBspInintReal16的代码去执行。UEFI的执行过程一般被分为SEC、PEI、DXE和BDS四个阶段。而这里的代码实际上还在SEC阶段之前,它最终会知道SEC entry并跳入,之后大部分就是C语言代码了。

以上是BIOS开机代码的简单介绍。下面就使用实际使用的BIOS ROM来解析印证一下。

ROM文件解析

Step 1:

Reference Code生成的Master Rom大小为32MB,下图是Master Rom布局(用UEFITool打开Master ROM),其中BIOS块位于Master Rom的尾部:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
这4个Section都可以被提取(选中Item–右键–“Extract body”–save),特别的TE image被提取后可以被IDA识别.提取TE image section和最后一个raw section.
在这里插入图片描述
使用IDA解析TE部分
在这里插入图片描述
它和SecEntry.asm文件开头部份的代码几乎一致(内容不便贴出)。

UEFI启动的第一阶段是SEC阶段,SecEntry.asm文件名中虽然含有"SecEntry"字眼,但是它并不是开机执行的第一个Section,更谈不上开机时执行的第一条指令。前面谈到Master Rom最后16字节(即物理地址0xFFFFFFF0)的OPCode形如"0x90 0x90 0xE9"
我们再来用IDA开刚刚保存的最后一个raw section盲盒。
在这里插入图片描述
我们可以看到最后确实是在FFFFFFF0的位置执行了
nop
nop
jmp
指令,理论和实践对齐了。而且跳到B590的位置,刚好是secentry的入口。

打开整个bios 文件瞅瞅:
在这里插入图片描述

参考文档
原文链接:https://blog.csdn.net/lixiangminghate/article/details/105752322
原文链接:https://blog.csdn.net/jiangwei0512/article/details/51622727/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值