Arm64-UEFI 啟動Linux內核-Image文件-PE格式


 

背景介紹:

參考:

http://www.wowotech.net/linux_kenrel/UEFI.html

1、UEFI是什么鬼?

BIOS實際上就是IBM PC兼容機(多么古老的一個詞匯啊)主板上的固件(firmware),這些固件可以在系統啟動過程中初始化硬件,self test,加載bootloader或者OS kernel,並且能為OS提供一些基礎的服務。

Intel提出來EFI(Extensible Firmware Interface)來取代BIOS interface。2005年,Intel終止了EFI規范的開發,替代它的是Unified EFI Forum負責的UEFI

 

2、UEFI關ARM什么事?

如果ARM僅僅是將目光放在移動(嵌入式)市場,那么UEFI當然不關ARM什么事情。

但是,在推出ARMv8以及64 bit架構的的處理器之后,ARM的野心已經不滿足在移動市場上稱王了。

 

3、UEFI如何定義系統的啟動過程?

在UEFI規范中定義了BOOT manager,它會根據保存在NVRAM中的參數來決定如何加載 EFI Application

EFI Application 是 PE(Portable Executable )格式的文件。

PE格式 是一種二進制可執行文件的格式(在linux世界中,我們多半熟悉的是ELF格式),由微軟開發,廣泛應用在Windows平台上。

 

uefi 的boot manager --> PE 格式的 bootloader (Uboot) --> linux kernel ?  這樣不夠直觀。PE 格式的 uboot 只是轉接信息。

因此,linux kernel image自身也可以包裝成一個EFI  application image,由boot manager直接加載,完成啟動過程。

uefi 的boot manager --> PE 格式的 linux kernel .

 

PE格式-Linux內核Image

PE 格式

下面的圖片是一個PE文件格式的示意圖:

 

 

 

arm64 kernel image 生成PE格式

MS DOS頭里面的內容,由 arch/arm64/kernel/head.S 填充。

head.S 內容

        __HEAD
_head:
        /*
         * DO NOT MODIFY. Image header expected by Linux boot-loaders.
         */
#ifdef CONFIG_EFI
        /*
         * This add instruction has no meaningful effect except that
         * its opcode forms the magic "MZ" signature required by UEFI.
         */
        add     x13, x18, #0x16
        b       primary_entry
#else
        b       primary_entry                   // branch to kernel start, magic
        .long   0                               // reserved
#endif
        .quad   0                               // Image load offset from start of RAM, little-endian
        le64sym _kernel_size_le                 // Effective size of kernel image, little-endian
        le64sym _kernel_flags_le                // Informative flags, little-endian
        .quad   0                               // reserved
        .quad   0                               // reserved
        .quad   0                               // reserved
        .ascii  ARM64_IMAGE_MAGIC               // Magic number
#ifdef CONFIG_EFI
        .long   pe_header - _head               // Offset to the PE header.

pe_header:
        __EFI_PE_HEADER
#else
        .long   0                               // reserved
#endif

其中 ARM64_IMAGE_MAGIC 是一個魔數,4 個字節, 其定義如下(代碼位於arch/arm64/include/asm/image.h

#define ARM64_IMAGE_MAGIC    "ARM\x64"

上面,從 _head 到 pe_header 之間有  7*8 bytes + 4 bytes + 4bytes 

 

MS DOS 結構體

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // MZ標記 0x5a4d             2 byte
    WORD   e_cblp;                      // 最后(部分)頁中的字節數  2 byte
    WORD   e_cp;                        // 文件中的全部和部分頁數  2 byte
    WORD   e_crlc;                      // 重定位表中的指針數   2 byte
    
    WORD   e_cparhdr;                   // 頭部尺寸以段落為單位   2 byte
    WORD   e_minalloc;                  // 所需的最小附加段  2 byte
    WORD   e_maxalloc;                  // 所需的最大附加段        2 byte
    WORD   e_ss;                        // 初始的SS值(相對偏移量)         2 byte
    
    
    
    WORD   e_sp;                        // 初始的SP值  2 byte
    WORD   e_csum;                      // 補碼校驗值   2 byte
    WORD   e_ip;                        // 初始的IP值       2 byte
    WORD   e_cs;                        // 初始的SS值          2 byte
    
    
    
    
    WORD   e_lfarlc;                    // 重定位表的字節偏移量     2 byte
    WORD   e_ovno;                      // 覆蓋號                     2 byte
    
    WORD   e_res[4];                    // 保留字                    8 bytes
    WORD   e_oemid;                     // OEM標識符(相對m_oeminfo)   2 byte
    WORD   e_oeminfo;                   // OEM信息                    2 byte
    
    
    WORD   e_res2[10];                  // 保留字                     10 * 2 bytes

    LONG   e_lfanew;                    // NT頭(PE標記)相對於文件的偏移地址

  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

這一結構體有  4 + 4 + 2*8 + 2* 8 + 3*8 = 7*8 + 4 + 4 個字節 

 

head.S 的 7*8 + 4 + 4 個字節 可以和 結構體的  7*8 + 4 + 4 個字節 一一匹配。 主要就是  e_lfanew 對應到 head.S 里面的 

 .long   pe_header - _head

 

pe header 和 arch/arm64/kernel/efi-header.S 內容

 

head.S 中 pe_header 后面跟的 __EFI_PE_HEADER 是一個宏定義,在  arch/arm64/kernel/efi-header.S 中,里面的內容和 PE 文件格式一一對應

        .macro  __EFI_PE_HEADER
        .long   PE_MAGIC
coff_header:
        .short  IMAGE_FILE_MACHINE_ARM64                // Machine
        .short  section_count                           // NumberOfSections
        .long   0                                       // TimeDateStamp
        .long   0                                       // PointerToSymbolTable
        .long   0                                       // NumberOfSymbols
        .short  section_table - optional_header         // SizeOfOptionalHeader
        .short  IMAGE_FILE_DEBUG_STRIPPED | \
                IMAGE_FILE_EXECUTABLE_IMAGE | \
                IMAGE_FILE_LINE_NUMS_STRIPPED           // Characteristics

optional_header:
        .short  PE_OPT_MAGIC_PE32PLUS                   // PE32+ format
        .byte   0x02                                    // MajorLinkerVersion
        .byte   0x14                                    // MinorLinkerVersion
        .long   __initdata_begin - efi_header_end       // SizeOfCode
        .long   __pecoff_data_size                      // SizeOfInitializedData
        .long   0                                       // SizeOfUninitializedData
        .long   __efistub_efi_pe_entry - _head          // AddressOfEntryPoint
        .long   efi_header_end - _head                  // BaseOfCode

extra_header_fields:
        .quad   0                                       // ImageBase
        .long   SEGMENT_ALIGN                           // SectionAlignment

……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM