ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

comprehensive-rust 裸机实战:基于 aarch64-rt 编写 AArch64 异常处理器(Exception Handlers)

comprehensive-rust 裸机实战:基于 aarch64-rt 编写 AArch64 异常处理器(Exception Handlers) 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),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表