capsules_extra/
read_only_state.rs1use core::cell::Cell;
36use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
37use kernel::hil::time::{Ticks, Time};
38use kernel::platform::ContextSwitchCallback;
39use kernel::process::{self, ProcessId};
40use kernel::processbuffer::{UserspaceReadableProcessBuffer, WriteableProcessBuffer};
41use kernel::syscall::{CommandReturn, SyscallDriver};
42use kernel::ErrorCode;
43
44pub const DRIVER_NUM: usize = capsules_core::driver::NUM::ReadOnlyState as usize;
46const VERSION: u32 = 1;
47
48pub struct ReadOnlyStateDriver<'a, T: Time> {
49 timer: &'a T,
50
51 apps: Grant<App, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
52}
53
54impl<'a, T: Time> ReadOnlyStateDriver<'a, T> {
55 pub fn new(
56 timer: &'a T,
57 grant: Grant<App, UpcallCount<0>, AllowRoCount<0>, AllowRwCount<0>>,
58 ) -> ReadOnlyStateDriver<'a, T> {
59 ReadOnlyStateDriver { timer, apps: grant }
60 }
61}
62
63impl<T: Time> ContextSwitchCallback for ReadOnlyStateDriver<'_, T> {
64 fn context_switch_hook(&self, process: &dyn process::Process) {
65 let processid = process.processid();
66 let pending_tasks = process.pending_tasks();
67
68 self.apps
69 .enter(processid, |app, _| {
70 let count = app.count.get();
71
72 let _ = app.mem_region.mut_enter(|buf| {
73 if buf.len() >= 4 {
74 buf[0..4].copy_from_slice(&count.to_le_bytes());
75 }
76 if buf.len() >= 8 {
77 buf[4..8].copy_from_slice(&(pending_tasks as u32).to_le_bytes());
78 }
79 if buf.len() >= 16 {
80 let now = self.timer.now().into_usize() as u64;
81 buf[8..16].copy_from_slice(&now.to_le_bytes());
82 }
83 });
84
85 app.count.set(count.wrapping_add(1));
86 })
87 .unwrap();
88 }
89}
90
91impl<T: Time> SyscallDriver for ReadOnlyStateDriver<'_, T> {
92 fn allow_userspace_readable(
99 &self,
100 processid: ProcessId,
101 which: usize,
102 mut slice: UserspaceReadableProcessBuffer,
103 ) -> Result<UserspaceReadableProcessBuffer, (UserspaceReadableProcessBuffer, ErrorCode)> {
104 if which == 0 {
105 let res = self.apps.enter(processid, |data, _| {
106 core::mem::swap(&mut data.mem_region, &mut slice);
107 });
108 match res {
109 Ok(()) => Ok(slice),
110 Err(e) => Err((slice, e.into())),
111 }
112 } else {
113 Err((slice, ErrorCode::NOSUPPORT))
114 }
115 }
116
117 fn command(
124 &self,
125 command_number: usize,
126 _target_id: usize,
127 _: usize,
128 _processid: ProcessId,
129 ) -> CommandReturn {
130 match command_number {
131 0 => CommandReturn::success(),
133
134 1 => CommandReturn::success_u32(VERSION),
136
137 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
139 }
140 }
141
142 fn allocate_grant(&self, processid: ProcessId) -> Result<(), process::Error> {
143 self.apps.enter(processid, |_, _| {})
144 }
145}
146
147#[derive(Default)]
148pub struct App {
149 mem_region: UserspaceReadableProcessBuffer,
150 count: Cell<u32>,
151}