12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
+ use safe_mmio:: fields:: { ReadPure , ReadPureWrite , WriteOnly } ;
16
+ use safe_mmio:: { field, field_shared, UniqueMmioPointer } ;
17
+
15
18
// ANCHOR: solution
16
19
#[ repr( C , align( 4 ) ) ]
17
- struct Registers {
20
+ pub struct Registers {
18
21
/// Data register
19
- dr : u32 ,
22
+ dr : ReadPure < u32 > ,
20
23
/// Match register
21
- mr : u32 ,
24
+ mr : ReadPureWrite < u32 > ,
22
25
/// Load register
23
- lr : u32 ,
26
+ lr : ReadPureWrite < u32 > ,
24
27
/// Control register
25
- cr : u8 ,
28
+ cr : ReadPureWrite < u8 > ,
26
29
_reserved0 : [ u8 ; 3 ] ,
27
30
/// Interrupt Mask Set or Clear register
28
- imsc : u8 ,
31
+ imsc : ReadPureWrite < u8 > ,
29
32
_reserved1 : [ u8 ; 3 ] ,
30
33
/// Raw Interrupt Status
31
- ris : u8 ,
34
+ ris : ReadPure < u8 > ,
32
35
_reserved2 : [ u8 ; 3 ] ,
33
36
/// Masked Interrupt Status
34
- mis : u8 ,
37
+ mis : ReadPure < u8 > ,
35
38
_reserved3 : [ u8 ; 3 ] ,
36
39
/// Interrupt Clear Register
37
- icr : u8 ,
40
+ icr : WriteOnly < u8 > ,
38
41
_reserved4 : [ u8 ; 3 ] ,
39
42
}
40
43
41
44
/// Driver for a PL031 real-time clock.
42
45
#[ derive( Debug ) ]
43
- pub struct Rtc {
44
- registers : * mut Registers ,
46
+ pub struct Rtc < ' a > {
47
+ registers : UniqueMmioPointer < ' a , Registers > ,
45
48
}
46
49
47
- impl Rtc {
50
+ impl < ' a > Rtc < ' a > {
48
51
/// 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 }
58
55
}
59
56
60
57
/// Reads the current RTC value.
61
58
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 ( )
65
60
}
66
61
67
62
/// Writes a match value. When the RTC value matches this then an interrupt
68
63
/// will be generated (if it is enabled).
69
64
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) ;
73
66
}
74
67
75
68
/// Returns whether the match register matches the RTC value, whether or not
76
69
/// the interrupt is enabled.
77
70
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 ( ) ;
81
72
( ris & 0x01 ) != 0
82
73
}
83
74
@@ -86,10 +77,8 @@ impl Rtc {
86
77
/// This should be true if and only if `matched` returns true and the
87
78
/// interrupt is masked.
88
79
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
93
82
}
94
83
95
84
/// Sets or clears the interrupt mask.
@@ -98,19 +87,11 @@ impl Rtc {
98
87
/// interrupt is disabled.
99
88
pub fn enable_interrupt ( & mut self , mask : bool ) {
100
89
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) ;
104
91
}
105
92
106
93
/// Clears a pending interrupt, if any.
107
94
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 ) ;
111
96
}
112
97
}
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