Skip to main content

aarch32_cpu/generic_timer/
el0.rs

1//! Code and types for Generic Timer support at EL0 on Armv8-R.
2
3use core::marker::PhantomData;
4
5use crate::register;
6
7/// Represents our Generic Physical Timer when we are running at EL0.
8///
9/// Note that for most of these APIs to work, EL0 needs to have been granted
10/// access using methods like
11/// [El1PhysicalTimer::el0_access_physical_counter](crate::generic_timer::El1PhysicalTimer::el0_access_physical_counter).
12///
13/// This type is not [Send] because it is a per-core type and should not be moved across
14/// cores on an SMP system.
15pub struct El0PhysicalTimer {
16    _phantom: PhantomData<*const u8>,
17}
18
19impl El0PhysicalTimer {
20    /// Create an EL0 Timer handle for the Physical Timer.
21    ///
22    /// EL2/EL1 has to grant permission for EL0 to use the Physical Timer, so
23    /// check they did that.
24    ///
25    /// # Safety
26    ///
27    /// Only create one Physical Timer handle (at any EL) at any given time, as
28    /// they access shared mutable state within the processor and do
29    /// read-modify-writes on that state.
30    pub unsafe fn new() -> El0PhysicalTimer {
31        El0PhysicalTimer {
32            _phantom: PhantomData,
33        }
34    }
35}
36
37impl super::GenericTimer for El0PhysicalTimer {
38    fn frequency_hz(&self) -> u32 {
39        register::Cntfrq::read().0
40    }
41
42    fn counter(&self) -> u64 {
43        register::CntPct::read().0
44    }
45
46    fn counter_compare(&self) -> u64 {
47        register::CntpCval::read().0
48    }
49
50    fn counter_compare_set(&mut self, value: u64) {
51        register::CntpCval::write(register::CntpCval(value))
52    }
53
54    fn countdown(&self) -> u32 {
55        register::CntpTval::read().0
56    }
57
58    fn countdown_set(&mut self, duration_ticks: u32) {
59        register::CntpTval::write(register::CntpTval(duration_ticks))
60    }
61
62    fn enabled(&self) -> bool {
63        register::CntpCtl::read().enable()
64    }
65
66    fn enable(&self, enabled: bool) {
67        register::CntpCtl::modify(|r| {
68            r.set_enable(enabled);
69        });
70    }
71
72    fn interrupt_masked(&self) -> bool {
73        register::CntpCtl::read().imask()
74    }
75
76    fn interrupt_mask(&mut self, mask: bool) {
77        register::CntpCtl::modify(|r| {
78            r.set_imask(mask);
79        });
80    }
81
82    fn interrupt_status(&self) -> bool {
83        register::CntpCtl::read().istatus()
84    }
85}
86
87/// Represents our Generic Virtual Timer when we are running at EL0.
88///
89/// Note that for most of these APIs to work, EL0 needs to have been granted
90/// access using methods like
91/// [El1VirtualTimer::el0_access_virtual_counter](crate::generic_timer::El1VirtualTimer::el0_access_virtual_counter).
92///
93/// This type is not [Send] because it is a per-core type and should not be moved across
94/// cores on an SMP system.
95pub struct El0VirtualTimer {
96    _phantom: PhantomData<*const u8>,
97}
98
99impl El0VirtualTimer {
100    /// Create an EL0 Timer handle for the Virtual Timer.
101    ///
102    /// # Safety
103    ///
104    /// Only create one Virtual Timer handle (at any EL) at any given time, as
105    /// they access shared mutable state within the processor and do
106    /// read-modify-writes on that state.
107    pub unsafe fn new() -> El0VirtualTimer {
108        El0VirtualTimer {
109            _phantom: PhantomData,
110        }
111    }
112}
113
114impl super::GenericTimer for El0VirtualTimer {
115    fn frequency_hz(&self) -> u32 {
116        register::Cntfrq::read().0
117    }
118
119    fn counter(&self) -> u64 {
120        register::CntVct::read().0
121    }
122
123    fn counter_compare(&self) -> u64 {
124        register::CntvCval::read().0
125    }
126
127    fn counter_compare_set(&mut self, value: u64) {
128        register::CntvCval::write(register::CntvCval(value))
129    }
130
131    fn countdown(&self) -> u32 {
132        register::CntvTval::read().0
133    }
134
135    fn countdown_set(&mut self, duration_ticks: u32) {
136        register::CntvTval::write(register::CntvTval(duration_ticks))
137    }
138
139    fn enabled(&self) -> bool {
140        register::CntvCtl::read().enable()
141    }
142
143    fn enable(&self, enabled: bool) {
144        register::CntvCtl::modify(|r| {
145            r.set_enable(enabled);
146        });
147    }
148
149    fn interrupt_masked(&self) -> bool {
150        register::CntvCtl::read().imask()
151    }
152
153    fn interrupt_mask(&mut self, mask: bool) {
154        register::CntvCtl::modify(|r| {
155            r.set_imask(mask);
156        });
157    }
158
159    fn interrupt_status(&self) -> bool {
160        register::CntvCtl::read().istatus()
161    }
162}