Skip to main content

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