aarch32_cpu/generic_timer/
el1.rs

1//! Code and types for Generic Timer support at EL1 on Armv8-R.
2
3use crate::register;
4
5use super::{El0PhysicalTimer, El0VirtualTimer, GenericTimer};
6
7/// Represents our Physical Timer when we are running at EL1.
8pub struct El1PhysicalTimer(pub(crate) El0PhysicalTimer);
9
10impl El1PhysicalTimer {
11    /// Create an EL1 Generic Timer handle
12    ///
13    /// # Safety
14    ///
15    /// Only create one of these at any given time, as they access shared
16    /// mutable state within the processor and do read-modify-writes on that state.
17    pub unsafe fn new() -> El1PhysicalTimer {
18        unsafe { El1PhysicalTimer(El0PhysicalTimer::new()) }
19    }
20
21    /// Control whether user code at EL0 can access the physical counter.
22    pub fn el0_access_physical_counter(&mut self, access: bool) {
23        register::Cntkctl::modify(|r| {
24            r.set_el0pcten(access);
25        });
26    }
27
28    /// Control whether user code at EL0 can access the physical timer.
29    pub fn el0_access_physical_timer(&mut self, access: bool) {
30        register::Cntkctl::modify(|r| {
31            r.set_el0pten(access);
32        });
33    }
34}
35
36impl GenericTimer for El1PhysicalTimer {
37    fn frequency_hz(&self) -> u32 {
38        self.0.frequency_hz()
39    }
40
41    fn counter(&self) -> u64 {
42        self.0.counter()
43    }
44
45    fn counter_compare(&self) -> u64 {
46        self.0.counter_compare()
47    }
48
49    fn counter_compare_set(&mut self, value: u64) {
50        self.0.counter_compare_set(value)
51    }
52
53    fn countdown(&self) -> u32 {
54        self.0.countdown()
55    }
56
57    fn countdown_set(&mut self, duration_ticks: u32) {
58        self.0.countdown_set(duration_ticks)
59    }
60
61    fn enabled(&self) -> bool {
62        self.0.enabled()
63    }
64
65    fn enable(&self, enabled: bool) {
66        self.0.enable(enabled)
67    }
68
69    fn interrupt_masked(&self) -> bool {
70        self.0.interrupt_masked()
71    }
72
73    fn interrupt_mask(&mut self, mask: bool) {
74        self.0.interrupt_mask(mask)
75    }
76
77    fn interrupt_status(&self) -> bool {
78        self.0.interrupt_status()
79    }
80}
81
82/// Represents our Virtual Timer when we are running at EL1.
83pub struct El1VirtualTimer(El0VirtualTimer);
84
85impl El1VirtualTimer {
86    /// Create an EL1 Generic Timer handle
87    ///
88    /// # Safety
89    ///
90    /// Only create one of these at any given time, as they access shared
91    /// mutable state within the processor and do read-modify-writes on that state.
92    pub unsafe fn new() -> El1VirtualTimer {
93        unsafe { El1VirtualTimer(El0VirtualTimer::new()) }
94    }
95
96    /// Control whether user code at EL0 can access the virtual counter.
97    pub fn el0_access_virtual_counter(&mut self, access: bool) {
98        register::Cntkctl::modify(|r| {
99            r.set_el0vcten(access);
100        });
101    }
102
103    /// Control whether user code at EL0 can access the virtual timer.
104    pub fn el0_access_virtual_timer(&mut self, access: bool) {
105        register::Cntkctl::modify(|r| {
106            r.set_el0vten(access);
107        });
108    }
109
110    /// Configure an event stream from the virtual counter.
111    ///
112    /// The event stream is tied to one of the bottom 16 bits of the virtual
113    /// counter. If you select the bottom (0th) bit, the event fires every
114    /// counter tick. If you select the 3rd bit, the event fires every 2^3 = 8
115    /// counter ticks.
116    ///
117    /// This is useful if you want to ensure that a WFE instruction can never
118    /// wait forever; effectively it allows you to put a timeout on a WFE.
119    ///
120    /// Pass None to disable.
121    pub fn virtual_event_stream_configure(&mut self, event_config: Option<&super::EventConfig>) {
122        if let Some(event_config) = event_config {
123            register::Cntkctl::modify(|r| {
124                r.set_evnti(arbitrary_int::u4::from_u8(event_config.rate as u8));
125                r.set_evntdir(event_config.evntdir == super::EventDir::HighLow);
126                r.set_evnten(true);
127            });
128        } else {
129            register::Cntkctl::modify(|r| {
130                r.set_evnten(false);
131            });
132        }
133    }
134}
135
136impl GenericTimer for El1VirtualTimer {
137    fn frequency_hz(&self) -> u32 {
138        self.0.frequency_hz()
139    }
140
141    fn counter(&self) -> u64 {
142        self.0.counter()
143    }
144
145    fn counter_compare(&self) -> u64 {
146        self.0.counter_compare()
147    }
148
149    fn counter_compare_set(&mut self, value: u64) {
150        self.0.counter_compare_set(value)
151    }
152
153    fn countdown(&self) -> u32 {
154        self.0.countdown()
155    }
156
157    fn countdown_set(&mut self, duration_ticks: u32) {
158        self.0.countdown_set(duration_ticks)
159    }
160
161    fn enabled(&self) -> bool {
162        self.0.enabled()
163    }
164
165    fn enable(&self, enabled: bool) {
166        self.0.enable(enabled)
167    }
168
169    fn interrupt_masked(&self) -> bool {
170        self.0.interrupt_masked()
171    }
172
173    fn interrupt_mask(&mut self, mask: bool) {
174        self.0.interrupt_mask(mask)
175    }
176
177    fn interrupt_status(&self) -> bool {
178        self.0.interrupt_status()
179    }
180}