Accurately representing a per-processor, fixed-address MMIO device
⚓ Rust 📅 2026-04-12 👤 surdeus 👁️ 1Hello,
I am writing a bare-metal operating system, currently working on the x86_64 implementation. I am dealing with the local APIC, which is a per-processor interrupt delivery device that is wired to the same MMIO address on each processor. To me, this is most easily represented with a static structure that contains a pointer to the memory, e.g.:
pub struct LocalApic(NonNull<u32>);
pub static LOCAL_APIC: Lazy<LocalApic> = Lazy::new(...);
impl LocalApic {
pub fn set_enable(&mut self, enable: bool) { ... }
My concern with this is the mutability semantics. Given the structure is static, taking self by exclusive borrow is not possible. I would, however, like to be able to do this, as it more accurately represents some of the operations I may perform on the local APIC. I see two ways to overcome this:
- A mutex or other sync mechanism (which would be semantically pointless, given the memory is processor-local).
- Lying to the compiler by taking
selfby shared borrow, and then usingNonNull::as_mut.
I lean towards option 2, but I fear that taking self by shared borrow will allow some kind of unsafe behavior in-place. For instance, if I return a type that references the lifetime of self, e.g.:
pub struct LvtTimer<'a>(&'a mut LocalApic);
impl LocalApic {
fn get_lvt_timer<'a>(&'a self) -> LvtTimer<'a> { ... }
… then I suspect (but I do not know for sure) that I could somehow violate a safety rule somewhere without noticing.
Any input on how to neatly solve this is greatly appreciated.
Thanks.
2 posts - 2 participants
🏷️ Rust_feed