1

为什么CPU重启之后第一条指令是啥也不干的NOP?为啥还是接连两条?

 2 years ago
source link: https://zhuanlan.zhihu.com/p/427138019
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为什么CPU重启之后第一条指令是啥也不干的NOP?为啥还是接连两条?

中央处理器 (CPU)话题下的优秀答主

大家都知道x86的CPU重启动后第一条指令位于地址0xFFFFFFF0,这个地址位于BIOS的高端空间。借助位于南桥的SPI Controller的直接读取模式,BIOS的高端地址空间映射到这个神秘的地址。那么藏在这里的第一条指令具体是什么呢?

它的内容不是秘密,UEFI基础代码EDK2开源了许久,我们可以在EDK2[1]的UefiCpuPkg里面找到这段地址里面的内容:

;
; For IA32, the reset vector must be at 0xFFFFFFF0, i.e., 4G-16 byte
; Execution starts here upon power-on/platform-reset.
;
ResetHandler:
    nop
    nop
ApStartup:
    ;
    ; Jmp Rel16 instruction
    ; Use machine code directly in case of the assembler optimization
    ; SEC entry point relative address will be fixed up by some build tool.
    ;
    ; Typically, SEC entry point is the function _ModuleEntryPoint() defined in
    ; SecEntry.asm
    ;
    DB      0e9h
    DW      -3

提示:0xe9是near JMP对应的机器码

可以看出,重启的指令是两个啥也不干的NOP和一个短跳转,跳转到附近一个64KB范围内的地址去。那么问题来了:

1.为啥开局是啥用也没有(有时候作为占位符和微调timing用)的NOP,而不是直接有用的JMP开局。

2.为啥一个NOP不够,而要两个?

3. JMP后面的占位符是谁Fixed UP的?

我们今天就简单了解一下原因。

为啥NOP开局?

虽然我加入Intel的时候这个代码已经是这样,但据我了解它的原因出自IA32 SDM[2]

来源:IA32手册

简单来说就是内核可以顺利执行NOP,的变成BSP;而其他的变成AP,被放在wait-for-SIPI的状态,等待BSP调度。

为啥有两个NOP?

第二个NOP是占位符,为了让随后的JMP可以16位地址对齐,这样性能高一些。

JMP后面的占位符是谁填的?

这里实际是要跳转到UEFI的SEC Core中去,但在写代码时候是不知道SEC Core在Flash哪里的,所以这里仅仅占位两个字节。其后,UEFI的BaseTools在产生FV的时候会找到SEC Core的入口,然后填写一个相对地址在这里。具体在Edk2\BaseTools\Source\C\GenFv\GenFvInternalLib.c

    //
    // Write SecCore Entry point relative address into the jmp instruction in reset vector.
    //
    Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);

    Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));
    if (Ia32SecEntryOffset <= -65536) {
      Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
      return STATUS_ERROR;
    }

是不是感觉没有用的知识又增加了?如果你还不满足,那么还有一个思考题。我们看到JMP后面跟了一个短跳转,只能在64KB的范围内寻址。那么问题来了,如果SEC Core不在64KB范围呢?EDK2有没有解决方法呢?欢迎大家留言讨论。

欢迎大家关注本专栏和用微信扫描下方二维码加入微信公众号"UEFIBlog",在那里有最新的文章。关注公众号,留言“资料”,有一些公开芯片资料供下载。

v2-91d380fba0955ebce85e5bf264d63cf6_720w.jpg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK