探索 Linux bootloader 的目的才不是為了多重開機或讓自己陷於一堆無趣的指令操作,重點在於:
- 理解 bootloader 的行為模式
- 思考 Linux boot process
- 創作或移植 bootloader
- 以 bootloader 為基礎,創造更大的價值
之前的 blog [Micromonitor 簡介] 提過服務於 Lucent 的 [Ed Sutter] 詳盡介紹 Firmware 相關技術與指導如何使用並移植 MicroMonitor 的大作,不過如果要更深入探索,一定要拜讀 Christopher Hallinan 的大作《Embedded Linux Primer》裡面的第七章〈Bootloaders〉。Christopher Hallinan 大名鼎鼎,我想也不需多加介紹,MontaVista software 有太多創作是出自此大師之手,同時,也感謝 Christopher Hallinan 願意將〈Chapter 7: Bootloaders〉開放下載,請參考以下資訊:
- [LinuxDevices.com 的複本] (PDF 格式)
- [] (PDF 格式)
- bootloader 扮演的角色
- bootloader 設計上的挑戰
- 通用性 bootloader 實做: Das U-Boot
- 移植 U-Boot
- 其他 bootloader
-
既然 bootloader 是 loader for booting,為何又要大費周章地把 Kernel 載入呢?為何不能直接寫入對應硬體的線性位址呢?
許多入門書籍總是以一系列的方塊圖,悄悄帶過 bootloader 的原理,好似 kernel 載入前那段「美好時光」中發生的變化、當試著以機械語文與電腦硬體對話時,只是哲學性地闡述海德格的名言:「語言乃存在之家園」,不,黑格爾告訴我們:「存在必合理」。Christopher Hallinan 一針見血指出 boot loader 設計上面臨的挑戰:
-
Even a simple "Hello World" program written in C requires significant hardware and software resources. The application developer does not need to know or care much about these details because the C runtime environment transparently provides this infrastructure. A bootloader developer has no such luxury. Every resource that a bootloader requires must be carefully initialized and allocated before it is used. One of the most visible examples of this is Dynamic Random Access Memory (DRAM).
問題才要開始,"7.2.3 Image Complexity" 指出許多經典的議題,C compiler & linker 怎麼去安排機械碼與目的輸出,一般而言,程式設計師不需要太花時間思索,不過對 bootloader 的設計可全然不是這麼一回事。這夢魘的開端就是 C runtime stack,於是作者指出:
-
The bootloader must create this execution context before any C functions are called. When the bootloader is compiled and linked, the developer must exercise complete control over how the image is constructed and linked. This is especially true if the bootloader is to relocate itself from Flash to RAM. The compiler and linker must be passed a handful of parameters defining the characteristics and layout of the final executable image. Two primary characteristics conspire to add complexity to the final binary executable image.
-
For example, the AMCC PowerPC 405GP processor seeks its first machine instructions from a hard-coded address of 0xFFFF_FFFC. Other processors use similar methods with different details. Some processors are configurable at power-on to seek code from one of several predefined locations, depending on hardware configuration signals.
-
Indeed, most processors have no DRAM available at startup for temporary storage of variables or, worse, for a stack that is required to use C program calling conventions. If you were forced to write a "Hello World" program with no DRAM and, therefore, no stack, it would be quite different from the traditional "Hello World" example.
-
This limitation places significant challenges on the initial body of code designed to initialize the hardware. As a result, one of the first tasks the bootloader performs on startup is to configure enough of the hardware to enable at least some minimal amount of RAM. Some processors designed for embedded use have small amounts of on-chip static RAM available. This is the case with the PPC 405GP we've been discussing. When RAM is available, a stack can be allocated using part of that RAM, and a proper context can be constructed to run higher-level languages such as C. This allows the rest of the processor and platform initialization to be written in something other than assembly language.
另外,大陸網友詹榮開三年前在 IBM developerWorks 發表了一篇文章 [嵌入式系統 Boot Loader 技術內幕] 也很值得一看,建議可搭配以上兩篇文章閱讀,其中有許多圖文恰好可互補,又其中一者談 [] ,另一者談 [],真是恰到好處。有了上述的基礎後,再回頭研讀 ARM-Linux hacker - Vincent Sanders - 的經典作品 [],就可得心應手。