iT邦幫忙

2021 iThome 鐵人賽

DAY 2
0
Software Development

閱讀 Linux Kernel 文件系列 第 2

# Day2 Boot image header in RISC-V Linux

${linux}/Documentation/arch 裡面有 5 篇文件,前面這幾天,大概都會是從這幾篇文件著墨;昨天的第 1 篇是描述 riscv-linux 的維護守則,今天來看的是,Boot image header in RISC-V Linux!描述的是一個 RISC-V 啟動影像檔,該要包含什麼樣的標頭,才可以被辨識為正確的啟動影像檔。

文件

============================
RISC-V Linux 的啟動影像檔標頭
============================

:Author: Atish Patra <atish.patra@wdc.com>
:Date:   20 May 2019

這份文件僅描述 RISC-V Linux 啟動影像檔標頭的詳細訊息。

待完成:
  寫一份完整的啟動流程指南。
  
解壓縮後的 Linux 核心影像檔中會含有以下 64 位元組的標頭::

    u32 code0;                /* 可執行程式碼 */
    u32 code1;                /* 可執行程式碼 */
    u64 text_offset;          /* 載入影像的偏移量  */
    u64 image_size;           /* 有效影像大小,小端序 */
    u64 flags;                /* 核心旗標,小端序 */
    u32 version;              /* 標頭版本 */
    u32 res1 = 0;             /* 保留 */
    u64 res2 = 0;             /* 保留 */
    u64 magic = 0x5643534952; /* 魔術數字,小端序,"RISCV" */
    u32 magic2 = 0x05435352;  /* 魔術數字 2,小端序,"RSC\x05" */
    u32 res3;                 /* 保留 PE COFF 的偏移量 */

這種標頭格式是深受 ARM64 標頭的影響並且相容於 PE/COFF 標頭。
因此,將來可以將 ARM64 和 RISC-V 標頭合併為一個通用標頭。

註
==
- 將來,這個標頭還可用來支援 RISC-V 的 EFI 模擬實作。 EFI 規範需要核心影像開頭的 PE/COFF 影像標頭,以便將其視作 EFI 應用程式來運行。為了支援 EFI 模擬,code0 應替換為 "MZ" 魔術字串,res3(偏移量 0x3c)應指向 PE/COFF 標頭的其餘部分。

- 版本欄位標示的是版本號

    ==========  =====
    位元 0:15   小版號
    位元 16:31  大版號
    ==========  =====

  這樣可以保證新、舊版本間的相容性。
  目前的版本被定義為 0.2。

- 自 0.2 版後,"magic" 欄位已不適用。在未來的版本中,它可能會被刪除。這本來應該和 ARM64 標頭 "magic" 欄位相符,但不幸的是沒有。 "magic 2" 欄位是用來替換 "magic" 的,並且與 ARM64 標頭相符。

- 在目前的標頭中,旗標欄位僅只有一個欄位。

    ======  ===============================================
    位元 0   核心的位元組順序。 小端序,則為 1;大端序,則為 0。
    ======  ===============================================

- 啟動載入程式會需要核心影像檔案的大小資訊,否則啟動程序將會失敗。

我的理解

  • 一般來說,開機流程都會由一個 Boot Loader 來把 Kernel 安置在一個理想的位置,再把控制權轉交過去;而 header 的用處,就是讓 Boot Loader 確認這個他看到的檔案,是一個正確的影像檔,舉例來說,RISC-V 的 Kernel 影像檔。
  • 以 u-boot 來說,在 booti 指令實作中,就有針對 header 的檢查:
booti 的使用方式: $ booti <kernel image addr> - <fdt addr>

/* ${uboot}/arch/riscv/lib/image.c */
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
        bool force_reloc)
{
    struct linux_image_h *lhdr;

    lhdr = (struct linux_image_h *)map_sysmem(image, 0);  // booti 指令中 kernel image 的 addr

    if (lhdr->magic != LINUX_RISCV_IMAGE_MAGIC) {         // 比對 magic 2 的欄位
        puts("Bad Linux RISCV Image magic!\n");
        return -EINVAL;
    }

    if (lhdr->image_size == 0) {                          // 確認 image_size 不為零
        puts("Image lacks image_size field, error!\n");
        return -EINVAL;
    }
    *size = lhdr->image_size;
    ...
}
  • 在 Kernel 中,則是在 ${linux}/arch/riscv/kernel/head.S 中,把 Kernel Image 的 header 加上去的
__HEAD                                                 /* MACRO --> .head.text */
ENTRY(_start)
    /*
     * Image header expected by Linux boot-loaders. The image header data
     * structure is described in asm/image.h.
     * Do not modify it without modifying the structure and all bootloaders
     * that expects this header format!!
     */
    /* jump to start kernel */
    j _start_kernel                                    /* 可執行程式碼 */
    /* reserved */
    .word 0                                            /* 可執行程式碼 */
    .balign 8
#if __riscv_xlen == 64
    /* Image load offset(2MB) from start of RAM */
    .dword 0x200000                                    /* 載入影像的偏移量 */
#else
    /* Image load offset(4MB) from start of RAM */
    .dword 0x400000                                    /* 載入影像的偏移量 */
#endif
    /* Effective size of kernel image */
    .dword _end - _start                               /* 有效影像大小,小端序 */
    .dword __HEAD_FLAGS                                /* 核心旗標,小端序 */
    .word RISCV_HEADER_VERSION                         /* 標頭版本 */
    .word 0                                            /* 保留 */
    .dword 0                                           /* 保留 */
    .ascii RISCV_IMAGE_MAGIC                           /* 魔術數字,小端序,"RISCV" */
    .balign 4
    .ascii RISCV_IMAGE_MAGIC2                          /* 魔術數字 2,小端序,"RSC\x05" */
    .word 0                                            /* 保留 PE COFF 的偏移量 */
  • 可以透過 xxdhexdump 等工具來檢視
$ xxd ${linux}/arch/riscv/boot/Image |less
0000000: 6f10 0000 0000 0000 0000 2000 0000 0000  o......... .....
0000010: 3c30 7701 0000 0000 0000 0000 0000 0000  <0w.............
0000020: 0200 0000 0000 0000 0000 0000 0000 0000  ................
0000030: 5249 5343 5600 0000 5253 4305 0000 0000  RISCV...RSC.....
...

Patch Time

不免俗地來送個 patch 吧!

$ git send-email --to corbet@lwn.net \
                 --to src.res@email.cn \
                 --to linux-kernel@vger.kernel.org \
                 --to linux-doc@vger.kernel.org \
                 --to linux-doc-tw-discuss@lists.sourceforge.net \
                 --cc ycliang@cs.nctu.edu.tw \
                 --cc ycliang@andestech.com \
                 0001-docs-zh_TW-Add-translation-for-riscv-boot-image-head.patch

後記

原來持續的 output 會這麼累啊,才寫 2 篇文章,就筋疲力盡的感覺~XDD
感謝各位收看,讓我重整旗鼓,我們明日再戰!


上一篇
# Day1 簡介
下一篇
# Day3 Virtual Memory Layout on RISC-V Linux
系列文
閱讀 Linux Kernel 文件30

尚未有邦友留言

立即登入留言