)
comprehensive-rust 裸機實戰基于 aarch64-rt 編寫 AArch64 異常處理器Exception Handlers【免費下載鏈接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.項目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust本篇技術指南來自 Google Android 團隊的 Rust 課程項目 comprehensive-rust 的裸機bare-metal實驗部分聚焦于aarch64-rtcrate 提供的異常處理抽象它用一個ExceptionHandlerstrait 和一個exception_handlers!宏替代手工編寫異常向量表的匯編代碼讓開發者可以純 Rust 地定義同步異常Synchronous、IRQ、FIQ 與 SError 的處理邏輯。讀完本文你將掌握 AArch64 異常向量表的 16 項布局、aarch64-rt的 trait 宏使用范式、RegisterStateRef的底層含義以及如何在 QEMU 上運行完整可驗證的示例。背景AArch64 的 16 項異常向量表在動手使用aarch64-rt之前需要先理解它背后封裝的硬件模型。AArch64 架構定義了一張包含16 個條目的異常向量表由4 種異常類型×4 種來源狀態組合而成異常類型同步異常synchronous、IRQ、FIQ、SError來源狀態當前異常級別current EL使用 SP0當前異常級別使用 SPx當前棧指針低異常級別lower EL使用 AArch64低異常級別使用 AArch32。這一模型在課程文檔 src/bare-metal/aps/exceptions.md 中作了明確說明。課程示例全部運行在EL1Exception Level 1為了保持簡單示例并未區分當前 EL 下的 SP0 與 SPx也沒有區分低 EL 下的 AArch32 與 AArch64——這意味著 16 個條目最終收斂到 8 個不同的處理函數見下文手工實現。異常發生時CPU 會跳轉到向量表中對應條目硬件上下文切換需要保存通用寄存器與elr_el1、spsr_el1等系統寄存器隨后才能安全地進入 Rust 代碼。手工實現回顧匯編 no_mangle函數在引入aarch64-rt之前課程示例用手寫匯編構建了完整的 EL1 異常向量表。匯編文件 src/bare-metal/aps/examples/src/exceptions.S 展示了其核心結構向量表位于.text.vector_table_el1段符號vector_table_el1通過.balign 0x800保證 2 KiB 對齊每個條目通過.balign 0x80保持 128 字節32 條指令間隔save_volatile_to_stack宏用stp指令將 x0–x18、x29、x30 壓棧并用mrs x0, elr_el1/mrs x1, spsr_el1保存返回地址與程序狀態以便支持嵌套異常時的棧回溯current_exception宏將「保存易失寄存器 → 跳轉 Rust 處理函數 → 恢復寄存器 →eret」串成一條流水線整套保存與恢復各占 14 條指令加上跳轉/返回共 30 條指令恰好控制在 32 條指令上限之內。對應的 Rust 端src/bare-metal/aps/examples/src/exceptions.rs則用#[unsafe(no_mangle)] extern C導出 8 個全局處理函數use log::error; use smccc::Hvc; use smccc::psci::system_off; // SAFETY: There is no other global function of this name. #[unsafe(no_mangle)] extern C fn sync_current(_elr: u64, _spsr: u64) { error!(sync_current); system_off::Hvc().unwrap(); } // irq_current / fiq_current / serror_current / sync_lower / irq_lower // fiq_lower / serror_lower 結構相同僅日志文本不同每個函數接收elr_el1與spsr_el1作為前兩個參數由匯編中的mrs指令準備好示例中只是記錄日志并調用 PSCIsystem_off關機——因為課程預期這些異常在實際運行中不會發生。aarch64-rt抽象trait 宏手工方案可行但繁瑣每增加一個處理器都要維護兩處代碼匯編表 Rust 函數。aarch64-rt將這個模式抽象為兩個構件正如核心文檔 src/bare-metal/aps/aarch64-rt/exceptions.md 所述aarch64-rtprovides a trait to define exception handlers, and a macro to generate the assembly code for the exception vector to call them.ExceptionHandlerstrait用于定義異常處理器exception_handlers!宏生成調用這些處理器的異常向量匯編代碼。trait 的每個方法都有默認實現——默認行為是直接panic因此對于預期不會發生的異常可以放心省略對應的方法代碼量大幅精簡。完整代碼示例核心文檔內嵌的示例來自 src/bare-metal/aps/examples/src/exceptions_rt.rs這里給出完整版本use aarch64_rt::{ExceptionHandlers, RegisterStateRef, exception_handlers}; use log::error; use smccc::Hvc; use smccc::psci::system_off; struct Handlers; impl ExceptionHandlers for Handlers { extern C fn sync_current(_state: RegisterStateRef) { error!(sync_current); system_off::Hvc().unwrap(); } extern C fn irq_current(_state: RegisterStateRef) { error!(irq_current); system_off::Hvc().unwrap(); } extern C fn fiq_current(_state: RegisterStateRef) { error!(fiq_current); system_off::Hvc().unwrap(); } extern C fn serror_current(_state: RegisterStateRef) { error!(serror_current); system_off::Hvc().unwrap(); } } exception_handlers!(Handlers);使用要點定義一個空結構體如Handlers為它實現ExceptionHandlers每個方法必須是extern C調用約定參數為RegisterStateRef只覆蓋你關心的異常類型其余繼承默認的 panic 行為最后調用exception_handlers!(Handlers)生成向量表。相比手工版本這里不再需要#[unsafe(no_mangle)]也不用手動約定elr/spsr參數位置宏會負責把匯編層的寄存器狀態包裝好后交給 Rust 方法。底層原理宏如何生成異常向量exception_handlers!宏并非魔法它在背后做了和手工exceptions.S相同的工作。文檔明確指出宏會生成一個global_asm!塊內含完整的異常向量用于跳轉到 Rust 代碼——這與之前手寫的exceptions.S是同一套思路RegisterStateRef是對棧幀的引用封裝——匯編代碼在異常發生時把寄存器值保存到棧上RegisterStateRef就指向這塊保存區。RegisterStateRef的兩種典型用途提取參數當異常來自低 ELlower EL時例如收到一個 SMC安全監控調用或 HVC虛擬機管理調用可以從保存的寄存器棧幀中讀出調用方傳入的參數改寫恢復值在處理函數返回、寄存器從棧上恢復之前修改棧幀中保存的寄存器值從而改變eret返回后 CPU 的狀態——這是實現系統調用參數回寫、返回值注入等功能的基石。也就是說aarch64-rt把「匯編負責保存/恢復、Rust 負責策略」的邊界固定下來RegisterStateRef就是跨越這條邊界的窗口。兩種實現方式對比維度手工實現aarch64-rt實現向量表手寫exceptions.S匯編exception_handlers!宏生成global_asm!Rust 端#[unsafe(no_mangle)] extern C函數impl ExceptionHandlerstrait 方法參數傳遞顯式_elr: u64, _spsr: u64RegisterStateRef寄存器棧幀引用未處理異常必須為全部 16 項提供函數trait 默認實現直接 panic可省略代碼量匯編 8 個函數1 個 impl 塊 1 個宏調用在完整示例中集成entry!與initial_pagetable!異常處理器不是孤立存在的課程示例 src/bare-metal/aps/examples/src/main_rt.rs 展示了它與aarch64-rt其他能力的組合使用。該文件頂部通過mod exceptions_rt;引入上文實現的異常模塊然后用initial_pagetable!宏在 Rust 中定義初始靜態頁表取代此前手工idmap.S的做法把 1 GiB 設備內存、1 GiB 普通內存以及 256 GiB 處的另一塊設備內存放入恒等映射用entry!(main)宏標記入口函數main(x0, x1, x2, x3)接收啟動時由匯編傳入的 4 個參數直接使用arm-pl011-uartcrate 的Uart驅動輸出日志而不是自己實現 PL011panic_handler同樣調用system_off::Hvc()關機。異常處理器、頁表、入口點與 UART 驅動全部由aarch64-rt生態接管這正是該 crate 的設計目標——如 src/bare-metal/aps/aarch64-rt.md 所說它提供了此前手工實現的匯編入口點和異常向量。依賴版本可在 src/bare-metal/aps/examples/Cargo.toml 中確認aarch64-rt 0.4.3、aarch64-paging 0.12.1、arm-pl011-uart 0.5.0、smccc 0.2.3、log 0.4.30。在 QEMU 中運行驗證在src/bare-metal/aps/examples目錄下Makefilesrc/bare-metal/aps/examples/Makefile提供了現成的運行目標make qemu_rt該目標依次執行cargo build→cargo objcopy --bin rt -- -O binary rt.bin→ 啟動 QEMUqemu-system-aarch64 -machine virt -cpu max -serial mon:stdio -display none -kernel rt.bin -s模擬器使用virt機器與maxCPU通過串口輸出日志。在正常運行路徑下程序打印main(...)參數后調用 PSCI 關機若異常被觸發例如訪問非法地址sync_current等處理器會輸出sync_current之類的錯誤日志后再關機——這為驗證異常處理邏輯提供了直接的觀測手段。異常處理器與并發模型Send / Sync 視角文檔還給出了一個重要的思維模型異常處理器與主執行上下文之間的關系可以類比為不同的線程。與線程間通信一樣兩者之間能共享什么數據由Send與Sync決定。舉例來說如果某個值要在異常處理器與程序其他部分之間共享且它是Send但不是Sync例如RefCell這類內部可變但非線程安全的類型就需要把它包裝進Mutex之類的同步原語并放入static中如果異常處理器與主流程并發訪問共享狀態必須保證訪問的原子性否則可能產生數據競爭——這在裸機環境同樣成立因為沒有操作系統替你兜底。記住這一點可以避免寫出在異常上下文中觸發未定義行為的共享邏輯。實踐要點小結只實現需要的異常ExceptionHandlers的默認方法會 panic未預期異常可以整體省略保持extern C約定trait 方法必須標注extern C參數類型為RegisterStateRef用好RegisterStateRef它是讀寫寄存器棧幀的入口是實現 SMC/HVC 參數提取與返回值注入的關鍵向量表對齊與指令預算若你仍需要手寫匯編注意 2 KiB 表對齊、128 字節條目間隔以及 32 條指令上限詳見 src/bare-metal/aps/examples/src/exceptions.S 中的注釋共享狀態考慮 Send/Sync異常上下文近似線程共享數據需要合適的同步原語。aarch64-rt將課程中手工實現的匯編異常向量、入口點、初始頁表一并收編為安全、可組合的 Rust 抽象讓開發者把精力聚焦在異常處理策略本身——這也是在 bare-metal 場景下用 Rust 寫出可維護系統軟件的一條清晰路徑。進一步可閱讀 src/bare-metal/aps/exceptions.md 了解手工方案的完整對比以及 src/bare-metal/aps/aarch64-rt.md 了解該 crate 的入口點與頁表能力。【免費下載鏈接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.項目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考