# Lab 0: Environment ## Hardware | hardware | 型號與架構 | 描述 | |---|---|---| | mather board | BCM2837 | SoC(System on a chip),這樣的主機板透過 memory-mapped register 去使用所有的裝置 | - 與週邊裝置溝通: 透過 [BCM2837 ARM Peripherals manual](https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf) 查詢每個裝置的 devices register 中的位元代表什麼意思,device register 只有 32bit >[!Important] **手冊中的 base address 為 `0x7E000000` ,但是我們卻使用 `0x3F000000`** > >Broadcom SoC 使用 VideoCore(GPU) 作為主要管理核心,GPU 是系統初始化時的主控方,透過**匯流排(bus)** 存取各種外設。所以 SoC 的文件、register map、peripheral base address 都以 GPU 為基準。 >在這個架構中: >- GPU sees peripherals(週邊設備) at `0x7E000000` >- ARM CPU sees peripherals at `0x3F000000`(Pi 2/3) > >Raspberry Pi 在啟動時(透過 bootloader 或 firmware)會把 peripheral 的 bus address 映射(memory map)到 ARM CPU 的實體記憶體空間。 - UART: UART(Universal asynchronous receiver-transmitter) 是一種異步序列通信協定: - Asynchronous 異步:傳輸資料時不需要時脈線(clock),靠雙方約定好的 baud rate(傳輸速率)。 - 序列:一個位元一個位元地送(不像 I²C 或 SPI 一次幾位)。 - Universal 通用:幾乎所有嵌入式裝置都支援 UART。 ## Cross Compiler :::success **:bulb: Todo: Install a cross compiler on your host computer.** ::: 1. [下載 corss compiler](https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz) - Host platform : x86_64 Linux - target platform : AArch64 ELF bare-metal --- [Arm 官方釋出的交叉編譯器套件](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) 網頁中的下載選項: - Hosted platform (在哪裡執行 compiler): | Hosted platform | 說明 | | ------------------- | -------------------------------- | | Windows(如 mingw-w64-i686)| 表示這個編譯器是在 32 位元 Windows 上執行的 | | x86_64 Linux | 在 64 位元 Linux 上執行 | | AArch64 Linux | 在 64 位元 ARM Linux 上執行(例如某些伺服器或高階 SBC) | | 部分 | 意思 | | --------- | -------------------------------------------------------------------- | | mingw | MinGW(Minimalist GNU for Windows)提供 GNU 工具鏈在 Windows 上的移植版本 ,老版本,僅支援 32-bit Windows,功能較少| | mingw-w64 | mingw 的延伸版本,支援 64 位元(x86\_64)與 32 位元(i686)Windows,並提供更完整的 API 標頭檔與功能,新版,支援 32-bit 與 64-bit,且功能更完整| - Target platform (編譯出來的程式要跑在哪裡): GNU 工具鏈(如 GCC、binutils)用來指定 **「目標平台」** 的四元組(也可算三元組 + ABI)格式,語法大致為`<目標架構>-<廠商>-<目標作業系統>-<ABI>` 如 `aarch64-none-linux-gnu` 。 *(ABI(Application Binary Interface,應用程式二進位介面)是一種規範,它定義了「已編譯程式碼之間如何互相溝通」。例如,假設設寫了一個 C 程式,呼叫了系統的 printf ,你的程式和 glibc 的 printf 必須使用相同的 ABI,否則在編譯時沒問題,但執行會錯誤或當機。)* | ABI 名稱 | 說明 | | ------------------- | -------------------------------- | | eabi | ARM 的嵌入式二進位介面(Embedded ABI) | | gnueabi | 使用 glibc 並遵循 eabi 的 Linux 工具鏈 | | gnueabihf | 與上面相同,但支援「硬體浮點」 | | ms\_abi / sysv\_abi | x86\_64 Windows vs Linux 的呼叫規則差異 | | elf | 強調產出格式是 ELF(用於裸機、kernel、bootloader),但不特指某個 ABI 標準 | | 架構 | 位元數 | 意義 (代表 CPU) | | ------ | --- | -----| | x86 | 32 | 統稱 32-bit x86 架構, 可包含 i386~i686 | | x86-64 | 64 | 又叫做 AMD64、Intel 64、x64, 現代主流桌機與筆電使用 | | i386 | 32 | 早期 x86 32 位元,支援最廣泛的 32-bit 平台 ,(Intel 80386(1985), 最早期支援 32-bit 的處理器 | | i686 | 32 | 向後相容舊 32-bit 軟體,(Pentium Pro/Pentium II/III), 更現代的 32-bit 處理器,效能較佳 | | AArch64 | 64 | 64-bit ARM 架構 | ## Emulate Raspberry Pi :::success :bulb: **Todo: Install `qemu-system-aarch64`** ::: 1. Download QEMU ```bash apt-get install qemu-system ``` ## From Source Code to Kernel Image :::success **:bulb: Todo: Build your first kernel image, and check it on QEMU.** ::: 1. Create boot stub `a.S`, linker `linker.ld` - `a.S` ```asm .section ".text" .global _start _start: wfe b _start ``` - `_start` 是執行起點(entry point),會在系統加電後第一時間被 CPU 執行。 - `wfe` 讓 CPU 進入低功耗等待模式,arm 特有指令。 - `b _start` 則形成一個無限迴圈,防止程式結束(裸機程式一旦結束沒有地方可去,會 crash)。 - `linker.ld` ```linker SECTIONS { . = 0x80000; .text : { *(.text) } } ``` - `SECTIONS { ... }` 這是連結器腳本的主體,用來描述各段(如 .text、.data、.bss)如何放入目標映像中。 - `. = 0x80000` 這行設定 當前輸出位址(location counter) 為 0x80000,即將以下定義的段(這裡是 .text)從記憶體位址 0x80000 開始放置。*(硬體的記憶體空間有實體限制與特殊用途,例如 0x00000000 是 ROM,0x80000000 是 RAM。)* - `.text : { *(.text) }` 建立一個 .text 段。段的內容是來自所有輸入檔案中 .text 段的合併(透過萬用字元 * 表示所有檔案) - **在 Raspberry Pi 或大多數嵌入式平台開機順序如下:** [ROM code (SoC 內建)] → [Firmware (如 rpi bootcode.bin)] → [Bootloader (可選,例如 U-Boot)] → [Boot Stub (kernel image 的起點)] → [Kernel main 或裸機程式] - **Boot Stub vs Bootloader 差異比較** | 特徵 | Boot Stub | Bootloader | | ---- | ------------------------ | -------------------------------- | | 對象 | 是你編譯出來 binary 的最前面幾行 | 是獨立一個 binary,通常在 boot ROM/SD 卡前段| | 負責項目 | 設定 stack、清除 BSS、跳 main | 初始化硬體、載入 kernel、跳轉 | | 大小 | 通常很小(數十 Bytes) | 可從幾 KB 到數百 KB | | 進階功能 | 沒有,純粹初始化與跳轉 | 有(Console、下載、載入 image、設定環境變數)| | 語言 | 通常組語 | 可使用 C 語言(stage2) | | 例子 | `_start:` in `startup.S` | U-Boot、rpi-boot、TF-A | 2. From Source Code to Object Files ```bash aarch64-none-elf-gcc -c a.S ``` 3. From Object Files to ELF ```bash aarch64-none-elf-ld -T linker.ld -o kernel8.elf a.o ``` - kernel8 意思是 ARMv8 4. From ELF to Kernel Image ```bash aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img ``` 5. Check on QEMU ```bash qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -d in_asm ``` - `-d in_asm` 啟用 debug trace 輸出模式,這裡選擇 in_asm,表示顯示 CPU 執行的指令反組譯(disassembly)