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