英語

RISC-V 核心啟動要求和約束

作者:

Alexandre Ghiti <alexghiti@rivosinc.com>

日期:

2023 年 5 月 23 日

本文件描述了 RISC-V 核心對引導載入程式和韌體的期望,以及任何開發人員在接觸早期啟動過程時必須牢記的約束。 就本文件而言,早期啟動過程 是指在最終虛擬對映設定之前執行的任何程式碼。

核心前的要求和約束

RISC-V 核心對引導載入程式和平臺韌體有以下期望

暫存器狀態

RISC-V 核心期望

  • $a0 包含當前核心的 hartid。

  • $a1 包含記憶體中裝置樹的地址。

CSR 狀態

RISC-V 核心期望

  • $satp = 0: MMU(如果存在)必須停用。

為駐留韌體保留記憶體

RISC-V 核心不得在直接對映中對映任何駐留記憶體或受 PMP 保護的記憶體,因此韌體必須根據裝置樹規範和/或 UEFI 規範正確標記這些區域。

核心位置

RISC-V 核心希望放置在 PMD 邊界(rv64 為 2MB 對齊,rv32 為 4MB 對齊)。 請注意,如果不是這種情況,EFI stub 將在物理上重新定位核心。

硬體描述

韌體可以將裝置樹或 ACPI 表傳遞給 RISC-V 核心。

裝置樹要麼使用 $a1 暫存器從上一階段直接傳遞給核心,要麼在使用 UEFI 啟動時,可以使用 EFI 配置表傳遞。

ACPI 表使用 EFI 配置表傳遞給核心。 在這種情況下,仍然由 EFI stub 建立一個小的裝置樹。 有關此裝置樹的詳細資訊,請參閱下面的“EFI stub 和裝置樹”部分。

核心入口

在 SMP 系統上,有兩種方法進入核心

  • RISCV_BOOT_SPINWAIT:韌體釋放核心中的所有 hart,一個 hart 贏得彩票並執行早期啟動程式碼,而其他 hart 則停放在那裡等待初始化完成。 此方法主要用於支援沒有 SBI HSM 擴充套件和 M 模式 RISC-V 核心的舊韌體。

  • 有序啟動:韌體僅釋放一個將執行初始化階段的 hart,然後使用 SBI HSM 擴充套件啟動所有其他 hart。 有序啟動方法是啟動 RISC-V 核心的首選啟動方法,因為它支援 CPU 熱插拔和 kexec。

UEFI

UEFI 記憶體對映

使用 UEFI 啟動時,RISC-V 核心將僅使用 EFI 記憶體對映來填充系統記憶體。

UEFI 韌體必須解析 /reserved-memory 裝置樹節點的子節點,並遵守裝置樹規範,以將這些子節點的屬性(no-mapreusable)轉換為其正確的 EFI 等效項(請參閱裝置樹規範 v0.4-rc1 的“3.5.4 /reserved-memory 和 UEFI”部分)。

RISCV_EFI_BOOT_PROTOCOL

使用 UEFI 啟動時,EFI stub 需要啟動 hartid,以便將其傳遞給 $a1 中的 RISC-V 核心。 EFI stub 使用以下方法之一檢索啟動 hartid

  • RISCV_EFI_BOOT_PROTOCOL (首選)。

  • boot-hartid 裝置樹子節點 (已棄用)。

任何新韌體都必須實現 RISCV_EFI_BOOT_PROTOCOL,因為現在基於裝置樹的方法已棄用。

早期啟動要求和約束

RISC-V 核心的早期啟動過程在以下約束下執行

EFI stub 和裝置樹

使用 UEFI 啟動時,裝置樹由 EFI stub 補充(或建立),其引數與 arm64 相同,如 統一可擴充套件韌體介面 (UEFI) 中的“ARM 上的 UEFI 核心支援”段落中所述。

虛擬對映安裝

虛擬對映的安裝在 RISC-V 核心中分 2 步完成

  1. setup_vm()early_pg_dir 中安裝臨時核心對映,允許發現系統記憶體。 此時僅對映核心文字/資料。 建立此對映時,無法進行分配(因為系統記憶體尚未知),因此靜態分配 early_pg_dir 頁表(每級僅使用一個表)。

  2. setup_vm_final()swapper_pg_dir 中建立最終核心對映,並利用發現的系統記憶體來建立線性對映。 建立此對映時,核心可以分配記憶體但無法直接訪問它(因為直接對映尚不存在),因此它使用 fixmap 區域中的臨時對映來訪問新分配的頁表級別。

為了使 virt_to_phys()phys_to_virt() 能夠正確地將直接對映地址轉換為物理地址,它們需要知道 DRAM 的起始位置。 這發生在步驟 1 之後,就在步驟 2 安裝直接對映之前(請參閱 arch/riscv/mm/init.c 中的 setup_bootmem() 函式)。 在安裝最終虛擬對映之前,必須仔細檢查這些宏的任何用法。

透過 fixmap 對映裝置樹

由於 reserved_mem 陣列使用由 setup_vm() 建立的虛擬地址初始化,並與由 setup_vm_final() 建立的對映一起使用,因此 RISC-V 核心使用 fixmap 區域來對映裝置樹。 這確保了裝置樹仍然可以透過兩種虛擬對映訪問。

MMU 前執行

甚至在建立第一個虛擬對映之前,都需要執行一些程式碼。 這些是第一個虛擬對映本身的安裝、早期備選項的修補以及核心命令列早期解析。 該程式碼必須非常小心地編譯為

  • -fno-pie:這對於使用 -fPIE 的可重定位核心是必需的,因為否則,對全域性符號的任何訪問都將透過僅虛擬重定位的 GOT。

  • -mcmodel=medany:對全域性符號的任何訪問都必須是 PC 相關的,以避免在 MMU 設定之前發生任何重定位。

  • 所有 檢測也必須停用(包括 KASAN、ftrace 和其他)。

由於從不同的編譯單元使用符號需要使用這些標誌編譯該單元,因此我們建議儘可能不要使用外部符號。