capsules_extra/
cycle_count.rs1use capsules_core::driver;
18pub const DRIVER_NUM: usize = driver::NUM::CycleCount as usize;
19
20use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
21use kernel::syscall::{CommandReturn, SyscallDriver};
22use kernel::utilities::cells::OptionalCell;
23use kernel::{hil, ErrorCode, ProcessId};
24
25#[derive(Default)]
26pub struct App;
27
28pub struct CycleCount<'a, P: hil::hw_debug::CycleCounter> {
29    counters: &'a P,
30    apps: Grant<App, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
31    controlling_app: OptionalCell<ProcessId>,
32}
33
34impl<'a, P: hil::hw_debug::CycleCounter> CycleCount<'a, P> {
35    pub fn new(
36        counters: &'a P,
37        grant: Grant<App, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
38    ) -> Self {
39        Self {
40            counters,
41            apps: grant,
42            controlling_app: OptionalCell::empty(),
43        }
44    }
45}
46
47impl<P: hil::hw_debug::CycleCounter> SyscallDriver for CycleCount<'_, P> {
48    fn command(
58        &self,
59        command_num: usize,
60        _data: usize,
61        _: usize,
62        processid: ProcessId,
63    ) -> CommandReturn {
64        let try_claim_driver = || {
65            let match_or_empty_or_nonexistant =
66                self.controlling_app.map_or(true, |controlling_app| {
67                    self.apps
68                        .enter(controlling_app, |_, _| controlling_app == processid)
69                        .unwrap_or(true)
70                });
71            if match_or_empty_or_nonexistant {
72                self.controlling_app.set(processid);
73                true
74            } else {
75                false
76            }
77        };
78        match command_num {
79            0 => CommandReturn::success(),
80
81            1 => {
82                if try_claim_driver() {
83                    self.counters.start();
84                    CommandReturn::success()
85                } else {
86                    CommandReturn::failure(ErrorCode::RESERVE)
87                }
88            }
89            2 => CommandReturn::success_u64(self.counters.count()),
90            3 => {
91                if try_claim_driver() {
92                    self.counters.reset();
93                    CommandReturn::success()
94                } else {
95                    CommandReturn::failure(ErrorCode::RESERVE)
96                }
97            }
98            4 => {
99                if try_claim_driver() {
100                    self.counters.stop();
101                    CommandReturn::success()
102                } else {
103                    CommandReturn::failure(ErrorCode::RESERVE)
104                }
105            }
106            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
107        }
108    }
109
110    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
111        self.apps.enter(processid, |_, _| {})
112    }
113}