mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-22 18:30:33 +02:00
Use safe-mmio in RTC exercise solution.
This commit is contained in:
parent
cb94a34cbf
commit
5fa060546b
2
src/exercises/bare-metal/rtc/Cargo.lock
generated
2
src/exercises/bare-metal/rtc/Cargo.lock
generated
@ -157,8 +157,10 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"chrono",
|
"chrono",
|
||||||
"log",
|
"log",
|
||||||
|
"safe-mmio",
|
||||||
"smccc",
|
"smccc",
|
||||||
"spin",
|
"spin",
|
||||||
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -14,5 +14,7 @@ arm-pl011-uart = "0.3.1"
|
|||||||
bitflags = "2.9.0"
|
bitflags = "2.9.0"
|
||||||
chrono = { version = "0.4.41", default-features = false }
|
chrono = { version = "0.4.41", default-features = false }
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
|
safe-mmio = "0.2.5"
|
||||||
smccc = "0.2.1"
|
smccc = "0.2.1"
|
||||||
spin = "0.10.0"
|
spin = "0.10.0"
|
||||||
|
zerocopy = "0.8.25"
|
||||||
|
@ -72,7 +72,8 @@ initial_pagetable!({
|
|||||||
// ANCHOR_END: imports
|
// ANCHOR_END: imports
|
||||||
|
|
||||||
/// Base address of the PL031 RTC.
|
/// Base address of the PL031 RTC.
|
||||||
const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;
|
const PL031_BASE_ADDRESS: NonNull<pl031::Registers> =
|
||||||
|
NonNull::new(0x901_0000 as _).unwrap();
|
||||||
/// The IRQ used by the PL031 RTC.
|
/// The IRQ used by the PL031 RTC.
|
||||||
const PL031_IRQ: IntId = IntId::spi(2);
|
const PL031_IRQ: IntId = IntId::spi(2);
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ fn main(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
|
|||||||
|
|
||||||
// SAFETY: `PL031_BASE_ADDRESS` is the base address of a PL031 device, and
|
// SAFETY: `PL031_BASE_ADDRESS` is the base address of a PL031 device, and
|
||||||
// nothing else accesses that address range.
|
// nothing else accesses that address range.
|
||||||
let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };
|
let mut rtc = unsafe { Rtc::new(UniqueMmioPointer::new(PL031_BASE_ADDRESS)) };
|
||||||
let timestamp = rtc.read();
|
let timestamp = rtc.read();
|
||||||
let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
|
let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();
|
||||||
info!("RTC: {time}");
|
info!("RTC: {time}");
|
||||||
|
@ -12,72 +12,63 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use safe_mmio::fields::{ReadPure, ReadPureWrite, WriteOnly};
|
||||||
|
use safe_mmio::{field, field_shared, UniqueMmioPointer};
|
||||||
|
|
||||||
// ANCHOR: solution
|
// ANCHOR: solution
|
||||||
#[repr(C, align(4))]
|
#[repr(C, align(4))]
|
||||||
struct Registers {
|
pub struct Registers {
|
||||||
/// Data register
|
/// Data register
|
||||||
dr: u32,
|
dr: ReadPure<u32>,
|
||||||
/// Match register
|
/// Match register
|
||||||
mr: u32,
|
mr: ReadPureWrite<u32>,
|
||||||
/// Load register
|
/// Load register
|
||||||
lr: u32,
|
lr: ReadPureWrite<u32>,
|
||||||
/// Control register
|
/// Control register
|
||||||
cr: u8,
|
cr: ReadPureWrite<u8>,
|
||||||
_reserved0: [u8; 3],
|
_reserved0: [u8; 3],
|
||||||
/// Interrupt Mask Set or Clear register
|
/// Interrupt Mask Set or Clear register
|
||||||
imsc: u8,
|
imsc: ReadPureWrite<u8>,
|
||||||
_reserved1: [u8; 3],
|
_reserved1: [u8; 3],
|
||||||
/// Raw Interrupt Status
|
/// Raw Interrupt Status
|
||||||
ris: u8,
|
ris: ReadPure<u8>,
|
||||||
_reserved2: [u8; 3],
|
_reserved2: [u8; 3],
|
||||||
/// Masked Interrupt Status
|
/// Masked Interrupt Status
|
||||||
mis: u8,
|
mis: ReadPure<u8>,
|
||||||
_reserved3: [u8; 3],
|
_reserved3: [u8; 3],
|
||||||
/// Interrupt Clear Register
|
/// Interrupt Clear Register
|
||||||
icr: u8,
|
icr: WriteOnly<u8>,
|
||||||
_reserved4: [u8; 3],
|
_reserved4: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Driver for a PL031 real-time clock.
|
/// Driver for a PL031 real-time clock.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rtc {
|
pub struct Rtc<'a> {
|
||||||
registers: *mut Registers,
|
registers: UniqueMmioPointer<'a, Registers>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rtc {
|
impl<'a> Rtc<'a> {
|
||||||
/// Constructs a new instance of the RTC driver for a PL031 device at the
|
/// Constructs a new instance of the RTC driver for a PL031 device with the
|
||||||
/// given base address.
|
/// given set of registers.
|
||||||
///
|
pub unsafe fn new(registers: UniqueMmioPointer<'a, Registers>) -> Self {
|
||||||
/// # Safety
|
Self { registers }
|
||||||
///
|
|
||||||
/// The given base address must point to the MMIO control registers of a
|
|
||||||
/// PL031 device, which must be mapped into the address space of the process
|
|
||||||
/// as device memory and not have any other aliases.
|
|
||||||
pub unsafe fn new(base_address: *mut u32) -> Self {
|
|
||||||
Self { registers: base_address as *mut Registers }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the current RTC value.
|
/// Reads the current RTC value.
|
||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
field_shared!(self.registers, dr).read()
|
||||||
// of a PL031 device which is appropriately mapped.
|
|
||||||
unsafe { (&raw const (*self.registers).dr).read_volatile() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a match value. When the RTC value matches this then an interrupt
|
/// Writes a match value. When the RTC value matches this then an interrupt
|
||||||
/// will be generated (if it is enabled).
|
/// will be generated (if it is enabled).
|
||||||
pub fn set_match(&mut self, value: u32) {
|
pub fn set_match(&mut self, value: u32) {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
field!(self.registers, mr).write(value);
|
||||||
// of a PL031 device which is appropriately mapped.
|
|
||||||
unsafe { (&raw mut (*self.registers).mr).write_volatile(value) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the match register matches the RTC value, whether or not
|
/// Returns whether the match register matches the RTC value, whether or not
|
||||||
/// the interrupt is enabled.
|
/// the interrupt is enabled.
|
||||||
pub fn matched(&self) -> bool {
|
pub fn matched(&self) -> bool {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
let ris = field_shared!(self.registers, ris).read();
|
||||||
// of a PL031 device which is appropriately mapped.
|
|
||||||
let ris = unsafe { (&raw const (*self.registers).ris).read_volatile() };
|
|
||||||
(ris & 0x01) != 0
|
(ris & 0x01) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +77,8 @@ impl Rtc {
|
|||||||
/// This should be true if and only if `matched` returns true and the
|
/// This should be true if and only if `matched` returns true and the
|
||||||
/// interrupt is masked.
|
/// interrupt is masked.
|
||||||
pub fn interrupt_pending(&self) -> bool {
|
pub fn interrupt_pending(&self) -> bool {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
let mis = field_shared!(self.registers, mis).read();
|
||||||
// of a PL031 device which is appropriately mapped.
|
(mis & 0x01) != 0
|
||||||
let ris = unsafe { (&raw const (*self.registers).mis).read_volatile() };
|
|
||||||
(ris & 0x01) != 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets or clears the interrupt mask.
|
/// Sets or clears the interrupt mask.
|
||||||
@ -98,19 +87,11 @@ impl Rtc {
|
|||||||
/// interrupt is disabled.
|
/// interrupt is disabled.
|
||||||
pub fn enable_interrupt(&mut self, mask: bool) {
|
pub fn enable_interrupt(&mut self, mask: bool) {
|
||||||
let imsc = if mask { 0x01 } else { 0x00 };
|
let imsc = if mask { 0x01 } else { 0x00 };
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
field!(self.registers, imsc).write(imsc);
|
||||||
// of a PL031 device which is appropriately mapped.
|
|
||||||
unsafe { (&raw mut (*self.registers).imsc).write_volatile(imsc) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears a pending interrupt, if any.
|
/// Clears a pending interrupt, if any.
|
||||||
pub fn clear_interrupt(&mut self) {
|
pub fn clear_interrupt(&mut self) {
|
||||||
// SAFETY: We know that self.registers points to the control registers
|
field!(self.registers, icr).write(0x01);
|
||||||
// of a PL031 device which is appropriately mapped.
|
|
||||||
unsafe { (&raw mut (*self.registers).icr).write_volatile(0x01) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `Rtc` just contains a pointer to device memory, which can be
|
|
||||||
// accessed from any context.
|
|
||||||
unsafe impl Send for Rtc {}
|
|
||||||
|
@ -12,6 +12,6 @@ _main.rs_:
|
|||||||
|
|
||||||
_pl031.rs_:
|
_pl031.rs_:
|
||||||
|
|
||||||
```rust
|
```rust,compile_fail
|
||||||
{{#include rtc/src/pl031.rs:solution}}
|
{{#include rtc/src/pl031.rs:solution}}
|
||||||
```
|
```
|
||||||
|
Loading…
x
Reference in New Issue
Block a user