3rd Bootloader
給 Pi 使用的 3rd Bootloader,這個 Bootloader 的功能是能夠執行 loadimg 這個指令,在電腦端透過 UART 直接將 image 傳到實體機上,免去插拔記憶卡的困擾。
先備知識
x86 開機流程
- Waiting power supply to settle to nominal state
- Fetch BIOS from ROM
BIOS:
- Power-On Self-Test
- Load boot configuration (e.g. boot order)
- Load the Stage 1 bootloader
Stage 1 Bootloader:
- Read MBR on disk
- Setup a stack
- Load the Stage 2 bootloader
Stage 2 bootloader:
- Read configuration file to startup a boot selection menu (e.g. GRUB)
- Load kernel
Linux
Linux 的啟動及初始化包含以下步驟:
- BIOS
- GRUB2 Stage 1 boot loader
- GRUB2 Stage 1.5 boot loader
- GRUB2 Stage 2 boot loader
- Kernel
- Init (systemd), the parent of all processes
搬家
因為 Bootloader 有可能在載入 image 的過程就把自己給蓋掉了,所以在載入 image 前要先將自己搬到不會被蓋過去的地方,再進行載入。
Spec 有一條是指定說可以載入到記憶體的任意位置,所以理論上應該是在準備載入前,要拿到欲載入 image 的大小,算 offset 看是要把自己搬到前面或是後面,但我這邊偷懶,在寫完 3rd Bootloader 後確定 size 不會超過 16KB 後,一開場就把自己搬家到記憶體最後面 0x3B3FC000 (VC Core Base 位址: 0x3B400000 - 16KB)。
P.S 幫我 DEMO 的助教人很好算我對 XD
linker.ld
linker script 把搬家的程式放在 .text.relocate section 裡。
| |
start.s
一開機進行初始化,然後跳到 relocate.c 裡面的 relocate function。
| |
relocate.c
把從 linker script 裡面定義的 _begin 到 _end 的內容複製到 __boot_loader 後,然後 branch 到 __boot_loader 這個記憶體位置上。
| |
載入 Image
main.c
一樣跑一個 shell 當讀到 loadimg 指令時來載入 image。
loadimg.c
一開始讀要寫到哪個記憶體位址,接著就看要怎麼和外面的 script 搭配,我自己是設計成一開始傳一個大小還有一個 image 的 checksum,傳輸如果成功就會跳到指定的位置。
| |
sendimg.py
| |
載入速度估算
$$ (\frac{1}{115200} \times 10) \times 10 \times 1024 \times 1024 = 910.22 \text{(s)} $$Calculate how long will it take for loading a 10MB kernel image by UART if baud rate is 115200.