Skip to main content

aarch32_cpu/generic_timer/
el2.rs

1//! Code and types for Generic Timer support at EL2 on Armv8-R.
2
3use core::marker::PhantomData;
4
5use crate::register;
6
7use super::{El1PhysicalTimer, El1VirtualTimer, GenericTimer};
8
9/// Represents our Physical Timer when we are running at EL2.
10///
11/// This works exactly like [El1PhysicalTimer], but it gives you extra methods
12/// for functionality that only processors running at EL2 can access.
13///
14/// This type is not [Send] because it is a per-core type and should not be moved across
15/// cores on an SMP system.
16pub struct El2PhysicalTimer(El1PhysicalTimer);
17
18impl El2PhysicalTimer {
19    /// Create an EL2 Physical Timer handle
20    ///
21    /// # Safety
22    ///
23    /// Only create one Physical Timer handle (at any EL) at any given time, as
24    /// they access shared mutable state within the processor and do
25    /// read-modify-writes on that state.
26    pub unsafe fn new() -> El2PhysicalTimer {
27        unsafe { El2PhysicalTimer(El1PhysicalTimer::new()) }
28    }
29
30    /// Set frequency
31    ///
32    /// Sets the frequency, in Hz, that the counters are incrementing at. You
33    /// might need to call this if your system doesn't initialise the frequency
34    /// value to something appropriate, or if you change the clock speed of the
35    /// timer.
36    pub fn frequency_hz_set(&mut self, new_frequency_hz: u32) {
37        register::Cntfrq::write(register::Cntfrq(new_frequency_hz))
38    }
39}
40
41impl GenericTimer for El2PhysicalTimer {
42    fn frequency_hz(&self) -> u32 {
43        self.0.frequency_hz()
44    }
45
46    fn counter(&self) -> u64 {
47        self.0.counter()
48    }
49
50    fn counter_compare(&self) -> u64 {
51        self.0.counter_compare()
52    }
53
54    fn counter_compare_set(&mut self, value: u64) {
55        self.0.counter_compare_set(value)
56    }
57
58    fn countdown(&self) -> u32 {
59        self.0.countdown()
60    }
61
62    fn countdown_set(&mut self, duration_ticks: u32) {
63        self.0.countdown_set(duration_ticks)
64    }
65
66    fn enabled(&self) -> bool {
67        self.0.enabled()
68    }
69
70    fn enable(&self, enabled: bool) {
71        self.0.enable(enabled)
72    }
73
74    fn interrupt_masked(&self) -> bool {
75        self.0.interrupt_masked()
76    }
77
78    fn interrupt_mask(&mut self, mask: bool) {
79        self.0.interrupt_mask(mask)
80    }
81
82    fn interrupt_status(&self) -> bool {
83        self.0.interrupt_status()
84    }
85}
86
87/// Represents our Virtual Timer when we are running at EL1.
88///
89/// This works exactly like [El1VirtualTimer], but it gives you extra methods
90/// for functionality that only processors running at EL2 can access.
91///
92/// This type is not [Send] because it is a per-core type and should not be moved
93/// across cores on an SMP system.
94pub struct El2VirtualTimer(El1VirtualTimer);
95
96impl El2VirtualTimer {
97    /// Create an EL2 Virtual Timer handle
98    ///
99    /// # Safety
100    ///
101    /// Only create one Virtual Timer handle (at any EL) at any given time, as
102    /// they access shared mutable state within the processor and do
103    /// read-modify-writes on that state.
104    pub unsafe fn new() -> El2VirtualTimer {
105        unsafe { El2VirtualTimer(El1VirtualTimer::new()) }
106    }
107
108    /// Set frequency
109    ///
110    /// Sets the frequency, in Hz, that the counters are incrementing at. You
111    /// might need to call this if your system doesn't initialise the frequency
112    /// value to something appropriate, or if you change the clock speed of the
113    /// timer.
114    pub fn frequency_hz_set(&mut self, new_frequency_hz: u32) {
115        register::Cntfrq::write(register::Cntfrq(new_frequency_hz))
116    }
117}
118
119impl GenericTimer for El2VirtualTimer {
120    fn frequency_hz(&self) -> u32 {
121        self.0.frequency_hz()
122    }
123
124    fn counter(&self) -> u64 {
125        self.0.counter()
126    }
127
128    fn counter_compare(&self) -> u64 {
129        self.0.counter_compare()
130    }
131
132    fn counter_compare_set(&mut self, value: u64) {
133        self.0.counter_compare_set(value)
134    }
135
136    fn countdown(&self) -> u32 {
137        self.0.countdown()
138    }
139
140    fn countdown_set(&mut self, duration_ticks: u32) {
141        self.0.countdown_set(duration_ticks)
142    }
143
144    fn enabled(&self) -> bool {
145        self.0.enabled()
146    }
147
148    fn enable(&self, enabled: bool) {
149        self.0.enable(enabled)
150    }
151
152    fn interrupt_masked(&self) -> bool {
153        self.0.interrupt_masked()
154    }
155
156    fn interrupt_mask(&mut self, mask: bool) {
157        self.0.interrupt_mask(mask)
158    }
159
160    fn interrupt_status(&self) -> bool {
161        self.0.interrupt_status()
162    }
163}
164
165/// Represents our Hypervisor-specific Physical Timer.
166///
167/// This is designed for use by a hypervisor, whilst an EL1 application
168/// concurrently uses the Physical Timer and/or the Virtual Timer.
169///
170/// This type is not [Send] because it is a per-core type and should not be moved across
171/// cores on an SMP system.
172pub struct El2HypPhysicalTimer {
173    _phantom: PhantomData<*const u8>,
174}
175
176impl El2HypPhysicalTimer {
177    /// Create a Timer handle for the EL2-specific Hyp Physical Timer.
178    ///
179    /// # Safety
180    ///
181    /// Only create one of these at any given time, as they access shared
182    /// mutable state within the processor and do read-modify-writes on that
183    /// state. This timer is distinct from the Physical Timer and the Virtual
184    /// Timer, and so can exist concurrently.
185    pub unsafe fn new() -> El2HypPhysicalTimer {
186        El2HypPhysicalTimer {
187            _phantom: PhantomData,
188        }
189    }
190}
191
192impl super::GenericTimer for El2HypPhysicalTimer {
193    fn frequency_hz(&self) -> u32 {
194        register::Cntfrq::read().0
195    }
196
197    fn counter(&self) -> u64 {
198        register::CntPct::read().0
199    }
200
201    fn counter_compare(&self) -> u64 {
202        register::CnthpCval::read().0
203    }
204
205    fn counter_compare_set(&mut self, value: u64) {
206        register::CnthpCval::write(register::CnthpCval(value))
207    }
208
209    fn countdown(&self) -> u32 {
210        register::CnthpTval::read().0
211    }
212
213    fn countdown_set(&mut self, duration_ticks: u32) {
214        register::CnthpTval::write(register::CnthpTval(duration_ticks))
215    }
216
217    fn enabled(&self) -> bool {
218        register::CnthpCtl::read().enable()
219    }
220
221    fn enable(&self, enabled: bool) {
222        register::CnthpCtl::modify(|r| {
223            r.set_enable(enabled);
224        });
225    }
226
227    fn interrupt_masked(&self) -> bool {
228        register::CnthpCtl::read().imask()
229    }
230
231    fn interrupt_mask(&mut self, mask: bool) {
232        register::CnthpCtl::modify(|r| {
233            r.set_imask(mask);
234        });
235    }
236
237    fn interrupt_status(&self) -> bool {
238        register::CnthpCtl::read().istatus()
239    }
240}