• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            string

            string
            posts - 27, comments - 177, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            深入UEFI內核(一)ResetVector

            Posted on 2015-07-12 10:17 djx_zh 閱讀(30020) 評論(3)  編輯 收藏 引用

            深入UEFI內核

            前面通過《UEFI原理與編程》一書介紹了如何使用UEFI編寫應用程序和驅動,編程一書是從上層應用和驅動開發者的角度認識UEFI的,UEFI就像一個黑盒子,書中詳細介紹了這個黑盒子的表面(即UEFI提供給上層開發者的接口和服務)。接口通過Protocol呈現給開發者。主要的Protocol包括控制臺輸入輸出Protocol;文件及硬盤Protocol;操作外部設備的Protocol(PciIo等);驅動框架Protocol;人機交互接口Protocol;網絡Protocol。服務通過啟動服務和運行時服務提供,主要包括Protocol服務,內存管理服務,事件管理服務等。UEFI雖然龐大,但它通過模塊化被很清晰的組織在一起,當逐步掌握了這些主要的Protocol和服務之后,UEFI也就變得簡單起來,那么是時候深入到這個盒子內部,了解UEFI內核的運行機制了。 
            下面將以系統啟動過程為主線介紹UEFI內核。

            第一條指令(ResetVector)

            先說結論:X86 CPU啟動后,將從地址0xFFFFFFF0處開始執行(此地址并非內存地址。此時,內存還遠遠沒有初始化。)。這一章來看X86系統是如何實現這一點的。 
            加電或者RESET針腳被激發(Assert)后[ref intel] CPU會經歷如下幾個過程: 
            1. CPU首先會進行硬件初始化(hardware reset)。 
            2. 然后是可選的自檢過程(BIST built-in self-test)。 
            3. CPU開始執行第一條指令。從此開始CPU進入軟件初始化過程。

            1.CPU硬件初始化

            CPU硬件初始化完成后,CPU被設置為實地址模式,地址無分頁。所有寄存器被初始化為特定的值, Cache、TLB(Translation Lookup Table)、BLB(Branch Target Buffer)這三個部件的內容被清空(Invalidate)。

            2.自檢

            CPU硬件初始化過程中,硬件可能請求執行自檢。如果執行自檢,自檢完成后,EAX的值為自檢錯誤碼,0表示沒有任何錯誤;

            3.第一條指令

            現在,完事俱備,CPU已經準備好,迫不及待地要執行第一條指令了。且慢,這是一個重要的時刻,此刻決定了CPU能否正常指令,讓我們詳細了解一下CPU目前的狀態。 
            表1-1 CPU初始化后的寄存器(部分)

            RegisterPentium 4 and Intel Xeon ProcessorP6 Family Processor Including DisplayFamily = 06H)Pentium Processor
            EFLAGS100000002H00000002H00000002H
            EIP0000FFF0H0000FFF0H0000FFF0H
            CR060000010H60000010H60000010H
            CR2, CR3, CR400000000H00000000H00000000H
            CSSelector = F000H 
            Base = FFFF0000H 
            Limit = FFFFH 
            AR = Present, R/W, Accessed
            Selector = F000H
            Base = FFF0000H
            Limit = FFFFH
            AR = Present, R/W, Accessed
            Selector = F000H
            Base = FFFF0000H
            Limit = FFFFH
            AR = Present, R/W, Accessed
            SS, DS, ES, FS, GSSelector = 0000H
            Base = 00000000H
            Limit = FFFFH
            AR = Present, R/W, Accessed
            Selector = 0000H
            Base = 00000000H 
            Limit = FFFFH
            AR = Present, R/W, Accessed
            Selector = 0000H
            Base = 00000000H
            Limit = FFFFH
            AR = Present, R/W, Accessed
            EDX00000FxxH000n06xxH000005xxH
            EAX000
            EBX, ECX, ESI, EDI, EBP,ESP00000000H00000000H00000000H

            此處我們最關心的是指令執行相關的兩個寄存器EIP(Instruction Pointer)、CS(Code Segment)。 
            在實地址模式下(寄存器字長為16位),指令的物理地址是CS << 4 + EIP。段寄存器CS左移四位作為基址,再加上作為偏移的EIP,最終形成指令的物理地址。現代CPU中為了加速指令地址的計算,為每個段寄存器增加了兩個寄存器:Base和Limit。Base存放基址,Limit存放最大偏移值。Base和Limit寄存器不能通過指令直接讀寫,他們的值是在寫段寄存器時由CPU自動設置的。通常Base等于段寄存器左移四位,如果CS的值為0xF000,CS的Base寄存器則為0xF0000,但CPU初始化時例外。從表1-1可以看出CS的值為0xF000, 但其Base為0xFFFF0000,EIP為0xFFF0,此時對應的指令地址為0xFFFF0000+0xFFF0 = 0xFFFFFFF0。0xFFFFFFF0就是CPU將要執行的第一條指令。這造成這樣一個有趣的事實,16位程序眼中的指令地址空間0x0000~0xFFFF(大小為64K)被CPU翻譯到物理地址空間(0xFFFF0000~0xFFFFFFFF)。也就是說,從CPU初始化,到段寄存器被重寫(通過跨段跳轉指令)前,指令空間0x0000~0xFFFF通過段寄存器被映射到物理地址空間0xFFFF0000~0xFFFFFFFF。 
            前面講到第一條指令地址為0xFFFFFFF0,X86系統初始化時會將ROM中的固件映射的(0xFFFFFFFF-固件大小)~0xFFFFFFFF的地址空間。故而0xFFFFFFF0對應ROM中的某條指令,無論ROM中存放的是傳統的BIOS固件,還是存放的UEFI固件,這個規則都是一樣的。下面將從這天指令開始繼續CPU初始化之旅。 
            開始講0xFFFFFFF0對應的指令之前,還要熟悉UEFI ROM的的結構。 
            ROM固件(Flash Device binary image)由一個或多個Firmware volume(FV)構成,每個FV里存放了FFS Image(EFI Firmware File system),FFS Image則由多個EFI Section構成,EFI Section包含了PE32/PE32+/Coff Image文件。 
            欲熟悉UEFI ROM的結構,先來看.fdf文件的格式。.fdf(Flash Description File)用于生成固件鏡像,它由[Defines]、[FD]、[FV]等幾個部分組成。

            [Defines]

            在[Defines]部分可以通過DEFINE定義本文件將要用到的宏,通過SET定義PCD的值。例如OvmfPkg的OvmfPkgX64.fdf文件的[Defines]為

            1. [Defines]
            2. !if $(TARGET) == RELEASE
            3. !ifndef $(FD_SIZE_2MB)
            4. DEFINE FD_SIZE_1MB=
            5. !endif
            6. !endif
            7. !include OvmfPkg.fdf.inc

            !ifdef, !ifndef, !if, !elseif, !else and !endif 用于編寫條件語句。$(TARGET)是EDK預定義的宏,其值為build命令-b選項的值。可以看出,編譯Release版本時,通過DEFINE定義了FD_SIZE_1MB宏。 
            然后通過!include包含了OvmfPkg.fdf.inc文件,OvmfPkg.fdf.inc內容如下

            1. DEFINE BLOCK_SIZE = 0x1000
            2. DEFINE VARS_SIZE = 0x20000
            3. DEFINE VARS_BLOCKS = 0x20
            4. !ifdef $(FD_SIZE_1MB)
            5. DEFINE FW_BASE_ADDRESS = 0xFFF00000
            6. DEFINE FW_SIZE = 0x00100000
            7. DEFINE FW_BLOCKS = 0x100
            8. DEFINE CODE_BASE_ADDRESS = 0xFFF20000
            9. DEFINE CODE_SIZE = 0x000E0000
            10. DEFINE CODE_BLOCKS = 0xE0
            11. DEFINE FVMAIN_SIZE = 0x000CC000
            12. DEFINE SECFV_OFFSET = 0x000EC000
            13. DEFINE SECFV_SIZE = 0x14000
            14. !else
            15. DEFINE FW_BASE_ADDRESS = 0xFFE00000
            16. DEFINE FW_SIZE = 0x00200000
            17. DEFINE FW_BLOCKS = 0x200
            18. DEFINE CODE_BASE_ADDRESS = 0xFFE20000
            19. DEFINE CODE_SIZE = 0x001E0000
            20. DEFINE CODE_BLOCKS = 0x1E0
            21. DEFINE FVMAIN_SIZE = 0x001AC000
            22. DEFINE SECFV_OFFSET = 0x001CC000
            23. DEFINE SECFV_SIZE = 0x34000
            24. !endif
            25. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress = $(FW_BASE_ADDRESS)
            26. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize = $(FW_SIZE)
            27. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize = $(BLOCK_SIZE)
            28. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase = $(FW_BASE_ADDRESS)
            29. SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize = 0xE000
            30. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
            31. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize = $(BLOCK_SIZE)
            32. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize
            33. SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(BLOCK_SIZE)
            34. SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
            35. SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = 0x1000

            通過OvmfPkg.fdf.inc可以看出,編譯RELEASE版本的OVMF時, FW_BASE_ADDRESS(固件基址)被定義為0xFFF00000, FW_SIZE被定義為0x00100000(1 M)。

            [FD]

            每個[FD]定義一個flash device image。flash device image可以是一個移動介質的可啟動Image,或者系統ROM Image,也可以是用于更新系統ROM的Update("Capsule") Image。 
            每個.inf文件可以有多個[FD],每個[FD]生成一個.fd鏡像文件。例如OvmfPkgX64.fdf文件定義了[FD.OVMF]、[FD.OVMF_VARS]、[FD.OVMF_CODE]、[FD.MEMFD],編譯后會生成OVMF.FD、OVMF_VARS.FD、OVMF_CODE.FD、MEMFD.FD四個鏡像文件。

            TOKEN

            [FD]塊以TOKEN語句開始,用于定義本FD的基本屬性,每一行定義一個Token,基本語法如下:

            1. Token = VALUE [| PcdName]

            有效的Token包括以下5個

            Token用途
            BaseAddressFLASH Device的基址
            SizeFLASH Device的大小
            ErasePolarity
            BlockSize
            NumBlocks默認值為1

            BlockSize可以出現多次,ni=0BlockSizeiNumBlocksi必須等于Size。 
            例如Nt32PKG.fdf文件中

            1. [FD.Nt32]
            2. BaseAddress = 0x0|gEfiNt32PkgTokenSpaceGuid.PcdWinNtFdBaseAddress
            3. Size = 0x002a0000
            4. ErasePolarity = 1
            5. BlockSize = 0x10000
            6. NumBlocks = 0x2a

            NT32PKG生成的NT32.fd基址為0,在程序中可以通過PCD的gEfiNt32PkgTokenSpaceGuid.PcdWinNtFdBaseAddress訪問這個值。大小為0x002a0000 = 0x10000 * 0x2a。 
            再如下例,Size(0x102000) = 0x10000 * 16 + 0x1000 * 2

            1. [FD.FdMain]
            2. BaseAddress = 0xFFF00000 | \
            3. gEfiMyPlatformTokenSpaceGuid.PcdFlashAreaBaseAddress
            4. Size = 0x102000
            5. ErasePolarity = 1
            6. BlockSize = 0x10000
            7. NumBlocks = 16
            8. BlockSize = 0x1000
            9. NumBlocks = 2

            接著Token的是可選的DEFINE和SET定義,用于定義本[FD]塊內有效的宏和PCD。 
            然后是Region列表,每個Region定義了位置、大小及其中的內容,格式為

            1. Offset|Size
            2. [TokenSpaceGuidCName.PcdOffsetCName|TokenSpaceGuidCName.PcdSizeCName]?
            3. [RegionType]?

            第一行定義了本Region的偏移位置和大小。 
            第二行和第三行為可選項。 
            第二行定義對應的PCD值,相當于 
            SET TokenSpaceGuidCName.PcdOffsetCName = Offset 
            SET TokenSpaceGuidCName.PcdSizeCName = Size 
            第三行定義本Region包含的內容。內容可以為數據(Data),也可以是FV(Firmware Volume)。 
            所有的Region必須按偏移地址升序排列,Region之間不得重疊。 
            例如OvmfPkg.fdf.inc文件的[FD.OVMF]塊:

            1. [FD.OVMF]
            2. BaseAddress = $(FW_BASE_ADDRESS)
            3. Size = $(FW_SIZE)
            4. ErasePolarity = 1
            5. BlockSize = $(BLOCK_SIZE)
            6. NumBlocks = $(FW_BLOCKS)
            7. !include VarStore.fdf.inc
            8. $(VARS_SIZE)|$(FVMAIN_SIZE)
            9. FV = FVMAIN_COMPACT
            10. $(SECFV_OFFSET)|$(SECFV_SIZE)
            11. FV = SECFV

            通過!include VarStore.fdf.inc引入了數據Region,數據Reigon后是兩個Fv。編譯Release版本OVMF時,這兩個Region為

            1. 0x20000|0x000CC000
            2. FV = FVMAIN_COMPACT
            3. 0x000EC000|0x14000
            4. FV = SECFV

            1M的ovmf.fd內容組織如下:

            地址區間內容
            0x00000 ~ 0x01FFFFData
            0x20000 ~ 0x0EBFFFFVMAIN_COMPACT
            0xEC000 ~ 0x100000SECFV

            再來看OVMF.FD的數據區,定義在文件VarStore.fdf.inc中,詳細大家已經掌握了其格式。

            1. 0x00000000|0x0000e000
            2. #NV_VARIABLE_STORE
            3. DATA = {
            4. ## This is the EFI_FIRMWARE_VOLUME_HEADER
            5. # ZeroVector []
            6. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            7. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            8. # FileSystemGuid: gEfiSystemNvDataFvGuid =
            9. # { 0xFFF12B8D, 0x7696, 0x4C8B,
            10. # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
            11. 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
            12. 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
            13. # FvLength: 0x20000
            14. 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
            15. # Signature "_FVH" # Attributes
            16. 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
            17. # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
            18. 0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02,
            19. # Blockmap[0]: 0x20 Blocks * 0x1000 Bytes / Block
            20. 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
            21. # Blockmap[1]: End
            22. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            23. ## This is the VARIABLE_STORE_HEADER
            24. !if $(SECURE_BOOT_ENABLE) == TRUE
            25. # Signature: gEfiAuthenticatedVariableGuid =
            26. # { 0xaaf32c78, 0x947b, 0x439a,
            27. # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
            28. 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
            29. 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
            30. !else
            31. # Signature: gEfiVariableGuid =
            32. # { 0xddcf3616, 0x3275, 0x4164,
            33. # { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }}
            34. 0x16, 0x36, 0xcf, 0xdd, 0x75, 0x32, 0x64, 0x41,
            35. 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d,
            36. !endif
            37. # Size: 0xe000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
            38. # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0xdfb8
            39. # This can speed up the Variable Dispatch a bit.
            40. 0xB8, 0xDF, 0x00, 0x00,
            41. # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
            42. 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            43. }
            44. 0x0000e000|0x00001000
            45. #NV_EVENT_LOG
            46. 0x0000f000|0x00001000
            47. #NV_FTW_WORKING
            48. DATA = {
            49. # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
            50. # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
            51. 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
            52. 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
            53. # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
            54. 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
            55. # WriteQueueSize: UINT64
            56. 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
            57. }
            58. 0x00010000|0x00010000
            59. #NV_FTW_SPAR

            [FV]

            下面來看在FD中作為Region的FV(Firmare Volume)。一個FV定義了一個固件卷,其內容包含一些列二進制Image,這些Image按[FV]中排列的順序排列在最終生成固件中。 
            [FV.UiFvName]中UiFvName用于標示這個FV,通過 FV = UiFvName可以在其他FV和FD中引用UiFvName。 
            先睹為快,下面是[FV.SECFV]

            1. [FV.SECFV]
            2. BlockSize = 0x1000
            3. FvAlignment = 16
            4. ERASE_POLARITY = 1
            5. MEMORY_MAPPED = TRUE
            6. STICKY_WRITE = TRUE
            7. LOCK_CAP = TRUE
            8. LOCK_STATUS = TRUE
            9. WRITE_DISABLED_CAP = TRUE
            10. WRITE_ENABLED_CAP = TRUE
            11. WRITE_STATUS = TRUE
            12. WRITE_LOCK_CAP = TRUE
            13. WRITE_LOCK_STATUS = TRUE
            14. READ_DISABLED_CAP = TRUE
            15. READ_ENABLED_CAP = TRUE
            16. READ_STATUS = TRUE
            17. READ_LOCK_CAP = TRUE
            18. READ_LOCK_STATUS = TRUE
            19. #
            20. # SEC Phase modules
            21. #
            22. INF OvmfPkg/Sec/SecMain.inf
            23. INF RuleOverride=RESET_VECTOR OvmfPkg/ResetVector/ResetVector.inf

            [FV]首先是Token,定義了本FV的基本屬性,例如BlockSize等。 
            然后可以通過DEFINE 定義宏,通過SET定義PCD。 
            在然后就是內容列表了。內容可以通過INF、FILE定義,也可以通過SECTION、APRIORI包含一系列內容。

            INF

            通過INF包含一個模塊,其語法如下

            1. INF [Options] PathAndInfFileName

            例如【FV.SECFV]中,通過INF 定義了SecMain.inf、ResetVector.inf,這兩個模塊將會按順序存放在這個FV中。編譯ResetVector.inf模塊時將會按RESET_VECTOR指定的規則生成.efi文件。

            FILE

            通過FILE包含文件的語法有兩種,一種是包含單個文件,一種表示包含多個文件

            1. FILE Type $(NAMED_GUID) [Options] FileName
            2. 或者
            3. FILE Type = $(NAMED_GUID) [Options] {
            4. SECTION SECTION_TYPE = FileName
            5. SECTION SECTION_TYPE = FileName
            6. }

            例如[FV.DXEFV]有如下內容。

            1. #Type為FREEFORM,表示二進制內容。
            2. FILE FREEFORM = PCD(gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile) {
            3. SECTION RAW = MdeModulePkg/Logo/Logo.bmp
            4. }
            5. FILE DRIVER = 5D695E11-9B3F-4b83-B25F-4A8D5D69BE07 {
            6. SECTION PE32 = Intel3.5/EFIX64/E3507X2.EFI
            7. }

            可用的Type包括:

            TYPE
            RAW
            FREEFORM
            SEC
            PEI_CORE
            DXE_CORE
            PEIM
            DRIVER
            COMBO_PEIM_DRIVER
            SMM_CORE
            DXE_SMM_DRIVER
            APPLICATION
            FV_IMAGE
            DISPOSABLE
            0x00~0xFF

            通過分析[FD.OVMF]及[FV.SECFV]可以知道,在生成的OVMF.FD文件中位于文件最后的是ResetVector.inf模塊。OVMF.FD可以燒到系統ROM中作為系統固件。前面已經講過開機時ROM將被映射到0xFFFFFFFF最靠后的內存中。那么第一條指令對應地址0xFFFFFFF0將位于ResetVector.inf模塊。 
            ResetVector.inf內容如下:

            1. [Defines]
            2. INF_VERSION = 0x00010005
            3. BASE_NAME = ResetVector
            4. FILE_GUID = 1BA0062E-C779-4582-8566-336AE8F78F09
            5. MODULE_TYPE = SEC
            6. VERSION_STRING = 1.1
            7. [Sources]
            8. ResetVector.nasmb
            9. [Packages]
            10. MdePkg/MdePkg.dec
            11. UefiCpuPkg/UefiCpuPkg.dec
            12. [BuildOptions]
            13. *_*_IA32_NASMB_FLAGS = -I$(WORKSPACE)/UefiCpuPkg/ResetVector/Vtf0/
            14. *_*_X64_NASMB_FLAGS = -I$(WORKSPACE)/UefiCpuPkg/ResetVector/Vtf0/

            ResetVector.inf包含了源文件ResetVector.nasmb,內容如下:

            1. %ifndef ARCH_IA32
            2. %ifndef ARCH_X64
            3. #include <Base.h>
            4. #if defined (MDE_CPU_IA32)
            5. %define ARCH_IA32
            6. #elif defined (MDE_CPU_X64)
            7. %define ARCH_X64
            8. #endif
            9. %endif
            10. %endif
            11. %ifdef ARCH_IA32
            12. %ifdef ARCH_X64
            13. %error "Only one of ARCH_IA32 or ARCH_X64 can be defined."
            14. %endif
            15. %elifdef ARCH_X64
            16. %else
            17. %error "Either ARCH_IA32 or ARCH_X64 must be defined."
            18. %endif
            19. %include "CommonMacros.inc"
            20. %include "PostCodes.inc"
            21. %ifdef DEBUG_PORT80
            22. %include "Port80Debug.asm"
            23. %elifdef DEBUG_SERIAL
            24. %include "SerialDebug.asm"
            25. %else
            26. %include "DebugDisabled.asm"
            27. %endif
            28. %include "Ia32/SearchForBfvBase.asm"
            29. %include "Ia32/SearchForSecEntry.asm"
            30. %ifdef ARCH_X64
            31. %include "Ia32/Flat32ToFlat64.asm"
            32. %include "Ia32/PageTables64.asm"
            33. %endif
            34. %include "Ia16/Real16ToFlat32.asm"
            35. %include "Ia16/Init16.asm"
            36. %include "Main.asm"
            37. %include "Ia16/ResetVectorVtf0.asm"

            位于最后的是ResetVectorVtf0.asm,其內容如下:

            1. BITS 16
            2. ALIGN 16
            3. %ifdef ALIGN_TOP_TO_4K_FOR_PAGING
            4. TIMES (0x1000 - ($ - EndOfPageTables) - 0x20) DB 0
            5. %endif
            6. applicationProcessorEntryPoint:
            7. jmp EarlyApInitReal16
            8. ALIGN 8
            9. DD 0
            10. vtfSignature:
            11. DB 'V', 'T', 'F', 0
            12. ALIGN 16
            13. resetVector:
            14. ; This is where the processor will begin execution
            15. ;
            16. nop
            17. nop
            18. jmp EarlyBspInitReal16
            19. ALIGN 16
            20. fourGigabytes:

            位于0xFFFFFFF0(fourGigabytes-16)處的是指標resetVector:,從此處開始的第一條有效指令是 jmp EarlyBspInitReal16。 
            可以通過反匯編OVMF.fd驗證, 
            OVMF.FD最后16字節為

            1. 0x000FFFF0 90 90 E9 AB FF 90 90 90 90 90 90 90 90 90 90 90

            指令碼90對應的指令正是nop,E9 AB FF對應的指令是 jmp FFAB, 跳轉到EIP+(FFAB)處執行, E9 AB FF對應的EIP為0x000FFFF2,那么下一條指令的EIP為0x000FFFF5, FFAB是-0x55, 0x000FFFF5 - 0x55 = 0xFFFA0. 0xFFFA0正是EarlyBspInitReal16。編譯后的匯編碼位于OvmfX64\RELEASE_VS2010x86\X64\OvmfPkg\ResetVector\ResetVector\OUTPUT\ResetVector.lst文件中。

            1. <1> EarlyBspInitReal16:
            2. BF4250 <1> mov di, 'BP'
            3. EB0B <1> jmp short Main16

            OVMF.FD中偏移0xFFFA0處的地址碼為:

            1. 0x00FFFA0 BF 42 50 EB 0B BF 41 50 EB 06 66 89 C4 E9 03 00

            BF 42 50正是mov di, 'BP'對應的指令碼。 
            再往后就是CPU軟件初始化的過程了。

            Feedback

            # re: 深入UEFI內核(一)ResetVector  回復  更多評論   

            2015-07-13 11:01 by PlayBoy
            不明覺厲

            # re: 深入UEFI內核(一)ResetVector  回復  更多評論   

            2015-07-13 22:45 by 胡俊杰
            深度好文,期待樓主這個系列下一篇大作

            # re: 深入UEFI內核(一)ResetVector  回復  更多評論   

            2015-08-26 09:29 by winux
            對于BUILD編譯NT32PKG生成的secMain.exe與OVMF.pkg編譯出來的OVMF固件有什么區別?我編譯出來的grub.efi,通過qemu虛擬機,加載ovmf.fd的固件啟動,能夠運行虛擬盤里的grub.efi。可是secMain.exe執行后,進入到fs0:后,運行拷貝在secMain.exe同目錄的grub.efi時,卻直接退出了。我理解secMain.exe應該也可以模擬呀,需要怎么操作呢?
            久久91精品国产91久久麻豆| 久久精品国产亚洲Aⅴ蜜臀色欲| 久久精品aⅴ无码中文字字幕不卡 久久精品aⅴ无码中文字字幕重口 | 国产精品免费久久久久影院| 亚洲国产成人精品91久久久 | 青青青伊人色综合久久| 亚州日韩精品专区久久久| 精品一区二区久久| 怡红院日本一道日本久久 | 久久青草国产精品一区| 色综合久久久久综合99| 国产69精品久久久久777| 亚洲午夜精品久久久久久app| 国内精品久久久久伊人av| 四虎影视久久久免费| 国产高潮久久免费观看| 久久ww精品w免费人成| 国产亚洲美女精品久久久2020| 99久久夜色精品国产网站| 亚洲午夜久久久影院伊人| 久久免费视频一区| 国产成人无码精品久久久久免费 | 国内精品久久人妻互换| 欧美精品国产综合久久| 久久亚洲欧洲国产综合| 国产精品久久久久一区二区三区| 久久亚洲精品国产精品| 亚洲精品无码成人片久久| 日本WV一本一道久久香蕉| 久久精品二区| 久久久久一本毛久久久| 久久久久国色AV免费观看| 国内精品久久久久国产盗摄| 国产一级持黄大片99久久| 国产亚洲美女精品久久久2020| 99久久做夜夜爱天天做精品| 久久久久久毛片免费看| 久久亚洲色一区二区三区| 2020国产成人久久精品| 中文精品久久久久人妻不卡| 久久精品国产亚洲αv忘忧草 |