Driver Architecture and Design
Relevant source files
This page documents the internal architecture and design principles of the arm_pl031
RTC driver, focusing on the core Rtc
struct, register layout, and hardware abstraction patterns. The material covers how the driver translates hardware register operations into safe Rust APIs while maintaining minimal overhead.
For hardware interface details and MMIO operations, see Hardware Interface and MMIO. For register-specific operations and meanings, see Register Operations.
Core Driver Structure
The driver architecture centers around two primary components: the Registers
struct that defines the hardware memory layout, and the Rtc
struct that provides the safe API interface.
Driver Components and Relationships
flowchart TD subgraph subGraph3["Hardware Layer"] MMIO["Memory-Mapped I/O"] PL031["PL031 RTC Hardware"] end subgraph subGraph2["Unsafe Operations Layer"] VolatileOps["Volatile Operationsread_volatile()write_volatile()"] PtrOps["Pointer Operationsaddr_of!()addr_of_mut!()"] end subgraph subGraph1["Hardware Abstraction Layer"] Registers["Registers struct"] RegisterFields["Register Fieldsdr: u32mr: u32lr: u32cr: u8imsc: u8ris: u8mis: u8icr: u8"] end subgraph subGraph0["Driver API Layer"] Rtc["Rtc struct"] PublicMethods["Public Methodsget_unix_timestamp()set_unix_timestamp()set_match_timestamp()matched()interrupt_pending()enable_interrupt()clear_interrupt()"] end MMIO --> PL031 PtrOps --> MMIO PublicMethods --> Registers RegisterFields --> VolatileOps Registers --> RegisterFields Rtc --> PublicMethods Rtc --> Registers VolatileOps --> PtrOps
Sources: src/lib.rs(L42 - L44) src/lib.rs(L15 - L39) src/lib.rs(L46 - L121)
Register Memory Layout
The Registers
struct provides a direct mapping to the PL031 hardware register layout, ensuring proper alignment and padding for hardware compatibility.
flowchart TD subgraph subGraph0["Memory Layout (repr C, align 4)"] DR["dr: u32Offset: 0x00Data Register"] MR["mr: u32Offset: 0x04Match Register"] LR["lr: u32Offset: 0x08Load Register"] CR["cr: u8Offset: 0x0CControl Register"] PAD1["_reserved0: [u8; 3]Offset: 0x0D-0x0F"] IMSC["imsc: u8Offset: 0x10Interrupt Mask"] PAD2["_reserved1: [u8; 3]Offset: 0x11-0x13"] RIS["ris: u8Offset: 0x14Raw Interrupt Status"] PAD3["_reserved2: [u8; 3]Offset: 0x15-0x17"] MIS["mis: u8Offset: 0x18Masked Interrupt Status"] PAD4["_reserved3: [u8; 3]Offset: 0x19-0x1B"] ICR["icr: u8Offset: 0x1CInterrupt Clear"] PAD5["_reserved4: [u8; 3]Offset: 0x1D-0x1F"] end
Sources: src/lib.rs(L15 - L39)
Driver Design Principles
Safety Boundary Architecture
The driver implements a clear safety boundary where all unsafe operations are contained within method implementations, exposing only safe APIs to users.
Component | Safety Level | Responsibility |
---|---|---|
Rtc::new() | Unsafe | Initial pointer validation and construction |
Public methods | Safe | High-level operations with safety guarantees |
Volatile operations | Unsafe (internal) | Direct hardware register access |
Pointer arithmetic | Unsafe (internal) | Register address calculation |
State Management Design
The Rtc
struct follows a stateless design pattern, storing only the base pointer to hardware registers without caching any hardware state.
flowchart TD subgraph subGraph2["Operation Pattern"] Read["Read OperationsDirect volatile readsNo local caching"] Write["Write OperationsDirect volatile writesImmediate effect"] end subgraph subGraph1["Hardware State"] HardwareRegs["PL031 Hardware RegistersAll state lives in hardware"] end subgraph subGraph0["Rtc State"] BasePtr["registers: *mut RegistersBase pointer to MMIO region"] end BasePtr --> HardwareRegs Read --> HardwareRegs Write --> HardwareRegs
Sources: src/lib.rs(L42 - L44) src/lib.rs(L63 - L66) src/lib.rs(L70 - L73)
Method Organization and Patterns
Functional Categories
The driver methods are organized into distinct functional categories, each following consistent patterns for hardware interaction.
Category | Methods | Pattern | Register Access |
---|---|---|---|
Time Management | get_unix_timestamp(),set_unix_timestamp() | Read/Write DR/LR | Direct timestamp operations |
Alarm Management | set_match_timestamp(),matched() | Write MR, Read RIS | Match register operations |
Interrupt Management | enable_interrupt(),interrupt_pending(),clear_interrupt() | Read/Write IMSC/MIS/ICR | Interrupt control flow |
Memory Access Pattern
All hardware access follows a consistent volatile operation pattern using addr_of!
and addr_of_mut!
macros for safe pointer arithmetic.
flowchart TD ReadAddr --> ReadVolatile ReadStart --> ReadAddr ReadVolatile --> ReadReturn WriteAddr --> WriteVolatile WriteStart --> WriteAddr WriteVolatile --> WriteComplete
Sources: src/lib.rs(L63 - L66) src/lib.rs(L70 - L73) src/lib.rs(L108 - L112)
Concurrency and Thread Safety
Send and Sync Implementation
The driver implements Send
and Sync
traits with explicit safety documentation, enabling safe usage across thread boundaries.
flowchart TD subgraph subGraph2["Usage Patterns"] SharedRead["Shared Read AccessMultiple &Rtc referencesConcurrent timestamp reading"] ExclusiveWrite["Exclusive Write AccessSingle &mut Rtc referenceSerialized configuration changes"] end subgraph subGraph1["Safety Guarantees"] DeviceMemory["Device Memory PropertiesHardware provides atomicityNo local state to corrupt"] ReadSafety["Concurrent Read SafetyMultiple readers allowedHardware state remains consistent"] end subgraph subGraph0["Thread Safety Design"] SendImpl["unsafe impl Send for RtcDevice memory accessible from any context"] SyncImpl["unsafe impl Sync for RtcRead operations safe from multiple threads"] end DeviceMemory --> ExclusiveWrite DeviceMemory --> SharedRead ReadSafety --> SharedRead SendImpl --> DeviceMemory SyncImpl --> ReadSafety
Sources: src/lib.rs(L123 - L128)
Construction and Initialization
The driver construction follows an unsafe initialization pattern that requires explicit safety contracts from the caller.
Initialization Requirements
The new()
method establishes the safety contract for proper driver operation:
- Base address must point to valid PL031 MMIO registers
- Memory must be mapped as device memory
- No other aliases to the memory region
- 4-byte alignment requirement
Sources: src/lib.rs(L46 - L60)