Skip to content

Commit b583093

Browse files
committed
Use safe-mmio in RTC exercise solution.
1 parent 3703d79 commit b583093

File tree

4 files changed

+32
-46
lines changed

4 files changed

+32
-46
lines changed

src/exercises/bare-metal/rtc/Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/exercises/bare-metal/rtc/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ arm-pl011-uart = "0.3.1"
1414
bitflags = "2.9.0"
1515
chrono = { version = "0.4.41", default-features = false }
1616
log = "0.4.27"
17+
safe-mmio = "0.2.5"
1718
smccc = "0.2.1"
1819
spin = "0.10.0"
20+
zerocopy = "0.8.25"

src/exercises/bare-metal/rtc/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ initial_pagetable!({
7272
// ANCHOR_END: imports
7373

7474
/// Base address of the PL031 RTC.
75-
const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
75+
const PL031_BASE_ADDRESS: NonNull<pl031::Registers> =
76+
NonNull::new(0x901_0000 as _).unwrap();
7677
/// The IRQ used by the PL031 RTC.
7778
const PL031_IRQ: IntId = IntId::spi(2);
7879

@@ -96,7 +97,7 @@ fn main(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
9697

9798
// SAFETY: `PL031_BASE_ADDRESS` is the base address of a PL031 device, and
9899
// nothing else accesses that address range.
99-
let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
100+
let mut rtc = unsafe { Rtc::new(UniqueMmioPointer::new(PL031_BASE_ADDRESS)) };
100101
let timestamp = rtc.read();
101102
let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
102103
info!("RTC: {time}");

src/exercises/bare-metal/rtc/src/pl031.rs

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,72 +12,63 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use safe_mmio::fields::{ReadPure, ReadPureWrite, WriteOnly};
16+
use safe_mmio::{field, field_shared, UniqueMmioPointer};
17+
1518
// ANCHOR: solution
1619
#[repr(C, align(4))]
17-
struct Registers {
20+
pub struct Registers {
1821
/// Data register
19-
dr: u32,
22+
dr: ReadPure<u32>,
2023
/// Match register
21-
mr: u32,
24+
mr: ReadPureWrite<u32>,
2225
/// Load register
23-
lr: u32,
26+
lr: ReadPureWrite<u32>,
2427
/// Control register
25-
cr: u8,
28+
cr: ReadPureWrite<u8>,
2629
_reserved0: [u8; 3],
2730
/// Interrupt Mask Set or Clear register
28-
imsc: u8,
31+
imsc: ReadPureWrite<u8>,
2932
_reserved1: [u8; 3],
3033
/// Raw Interrupt Status
31-
ris: u8,
34+
ris: ReadPure<u8>,
3235
_reserved2: [u8; 3],
3336
/// Masked Interrupt Status
34-
mis: u8,
37+
mis: ReadPure<u8>,
3538
_reserved3: [u8; 3],
3639
/// Interrupt Clear Register
37-
icr: u8,
40+
icr: WriteOnly<u8>,
3841
_reserved4: [u8; 3],
3942
}
4043

4144
/// Driver for a PL031 real-time clock.
4245
#[derive(Debug)]
43-
pub struct Rtc {
44-
registers: *mut Registers,
46+
pub struct Rtc<'a> {
47+
registers: UniqueMmioPointer<'a, Registers>,
4548
}
4649

47-
impl Rtc {
50+
impl<'a> Rtc<'a> {
4851
/// Constructs a new instance of the RTC driver for a PL031 device at the
49-
/// given base address.
50-
///
51-
/// # Safety
52-
///
53-
/// The given base address must point to the MMIO control registers of a
54-
/// PL031 device, which must be mapped into the address space of the process
55-
/// as device memory and not have any other aliases.
56-
pub unsafe fn new(base_address: *mut u32) -> Self {
57-
Self { registers: base_address as *mut Registers }
52+
/// given set of registers.
53+
pub unsafe fn new(registers: UniqueMmioPointer<'a, Registers>) -> Self {
54+
Self { registers }
5855
}
5956

6057
/// Reads the current RTC value.
6158
pub fn read(&self) -> u32 {
62-
// SAFETY: We know that self.registers points to the control registers
63-
// of a PL031 device which is appropriately mapped.
64-
unsafe { (&raw const (*self.registers).dr).read_volatile() }
59+
field_shared!(self.registers, dr).read()
6560
}
6661

6762
/// Writes a match value. When the RTC value matches this then an interrupt
6863
/// will be generated (if it is enabled).
6964
pub fn set_match(&mut self, value: u32) {
70-
// SAFETY: We know that self.registers points to the control registers
71-
// of a PL031 device which is appropriately mapped.
72-
unsafe { (&raw mut (*self.registers).mr).write_volatile(value) }
65+
field!(self.registers, mr).write(value);
7366
}
7467

7568
/// Returns whether the match register matches the RTC value, whether or not
7669
/// the interrupt is enabled.
7770
pub fn matched(&self) -> bool {
78-
// SAFETY: We know that self.registers points to the control registers
79-
// of a PL031 device which is appropriately mapped.
80-
let ris = unsafe { (&raw const (*self.registers).ris).read_volatile() };
71+
let ris = field_shared!(self.registers, ris).read();
8172
(ris & 0x01) != 0
8273
}
8374

@@ -86,10 +77,8 @@ impl Rtc {
8677
/// This should be true if and only if `matched` returns true and the
8778
/// interrupt is masked.
8879
pub fn interrupt_pending(&self) -> bool {
89-
// SAFETY: We know that self.registers points to the control registers
90-
// of a PL031 device which is appropriately mapped.
91-
let ris = unsafe { (&raw const (*self.registers).mis).read_volatile() };
92-
(ris & 0x01) != 0
80+
let mis = field_shared!(self.registers, mis).read();
81+
(mis & 0x01) != 0
9382
}
9483

9584
/// Sets or clears the interrupt mask.
@@ -98,19 +87,11 @@ impl Rtc {
9887
/// interrupt is disabled.
9988
pub fn enable_interrupt(&mut self, mask: bool) {
10089
let imsc = if mask { 0x01 } else { 0x00 };
101-
// SAFETY: We know that self.registers points to the control registers
102-
// of a PL031 device which is appropriately mapped.
103-
unsafe { (&raw mut (*self.registers).imsc).write_volatile(imsc) }
90+
field!(self.registers, imsc).write(imsc);
10491
}
10592

10693
/// Clears a pending interrupt, if any.
10794
pub fn clear_interrupt(&mut self) {
108-
// SAFETY: We know that self.registers points to the control registers
109-
// of a PL031 device which is appropriately mapped.
110-
unsafe { (&raw mut (*self.registers).icr).write_volatile(0x01) }
95+
field!(self.registers, icr).write(0x01);
11196
}
11297
}
113-
114-
// SAFETY: `Rtc` just contains a pointer to device memory, which can be
115-
// accessed from any context.
116-
unsafe impl Send for Rtc {}

0 commit comments

Comments
 (0)