capsules_extra/
app_flash_driver.rs1use core::cmp;
30
31use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
32use kernel::hil;
33use kernel::processbuffer::ReadableProcessBuffer;
34use kernel::syscall::{CommandReturn, SyscallDriver};
35use kernel::utilities::cells::{OptionalCell, TakeCell};
36use kernel::{ErrorCode, ProcessId};
37
38use capsules_core::driver;
40pub const DRIVER_NUM: usize = driver::NUM::AppFlash as usize;
41
42mod upcall {
44 pub const WRITE_DONE: usize = 0;
46 pub const COUNT: u8 = 1;
48}
49
50mod ro_allow {
52 pub const BUFFER: usize = 0;
54 pub const COUNT: u8 = 1;
56}
57
58#[derive(Default)]
59pub struct App {
60 pending_command: bool,
61 flash_address: usize,
62}
63
64pub struct AppFlash<'a> {
65 driver: &'a dyn hil::nonvolatile_storage::NonvolatileStorage<'a>,
66 apps: Grant<
67 App,
68 UpcallCount<{ upcall::COUNT }>,
69 AllowRoCount<{ ro_allow::COUNT }>,
70 AllowRwCount<0>,
71 >,
72 current_app: OptionalCell<ProcessId>,
73 buffer: TakeCell<'static, [u8]>,
74}
75
76impl<'a> AppFlash<'a> {
77 pub fn new(
78 driver: &'a dyn hil::nonvolatile_storage::NonvolatileStorage<'a>,
79 grant: Grant<
80 App,
81 UpcallCount<{ upcall::COUNT }>,
82 AllowRoCount<{ ro_allow::COUNT }>,
83 AllowRwCount<0>,
84 >,
85 buffer: &'static mut [u8],
86 ) -> AppFlash<'a> {
87 AppFlash {
88 driver,
89 apps: grant,
90 current_app: OptionalCell::empty(),
91 buffer: TakeCell::new(buffer),
92 }
93 }
94
95 fn enqueue_write(&self, flash_address: usize, processid: ProcessId) -> Result<(), ErrorCode> {
99 self.apps
100 .enter(processid, |app, kernel_data| {
101 let flash_length = kernel_data
103 .get_readonly_processbuffer(ro_allow::BUFFER)
104 .map_or(0, |buffer| buffer.len());
105 let (app_flash_start, app_flash_end) = processid.get_editable_flash_range();
106 if flash_address < app_flash_start
107 || flash_address >= app_flash_end
108 || flash_address + flash_length >= app_flash_end
109 {
110 return Err(ErrorCode::INVAL);
111 }
112
113 if self.current_app.is_none() {
114 self.current_app.set(processid);
115
116 kernel_data
117 .get_readonly_processbuffer(ro_allow::BUFFER)
118 .and_then(|buffer| {
119 buffer.enter(|app_buffer| {
120 self.buffer
122 .take()
123 .map_or(Err(ErrorCode::RESERVE), |buffer| {
124 let length = cmp::min(buffer.len(), app_buffer.len());
125 let d = &app_buffer[0..length];
126 for (i, c) in buffer[0..length].iter_mut().enumerate() {
127 *c = d[i].get();
128 }
129
130 self.driver.write(buffer, flash_address, length)
131 })
132 })
133 })
134 .unwrap_or(Err(ErrorCode::RESERVE))
135 } else {
136 if app.pending_command {
138 Err(ErrorCode::NOMEM)
139 } else {
140 app.pending_command = true;
141 app.flash_address = flash_address;
142 Ok(())
143 }
144 }
145 })
146 .unwrap_or_else(|err| Err(err.into()))
147 }
148}
149
150impl hil::nonvolatile_storage::NonvolatileStorageClient for AppFlash<'_> {
151 fn read_done(&self, _buffer: &'static mut [u8], _length: usize) {}
152
153 fn write_done(&self, buffer: &'static mut [u8], _length: usize) {
154 self.buffer.replace(buffer);
156
157 self.current_app.take().map(|processid| {
159 let _ = self.apps.enter(processid, |_app, upcalls| {
160 upcalls.schedule_upcall(upcall::WRITE_DONE, (0, 0, 0)).ok();
161 });
162 });
163
164 for cntr in self.apps.iter() {
166 let processid = cntr.processid();
167 let started_command = cntr.enter(|app, kernel_data| {
168 if app.pending_command {
169 app.pending_command = false;
170 self.current_app.set(processid);
171 let flash_address = app.flash_address;
172
173 kernel_data
174 .get_readonly_processbuffer(ro_allow::BUFFER)
175 .and_then(|buffer| {
176 buffer.enter(|app_buffer| {
177 self.buffer.take().is_some_and(|buffer| {
178 if app_buffer.len() != 512 {
179 false
180 } else {
181 let length = cmp::min(buffer.len(), app_buffer.len());
183 let d = &app_buffer[0..length];
184 for (i, c) in buffer[0..length].iter_mut().enumerate() {
185 *c = d[i].get();
186 }
187
188 if let Ok(()) =
189 self.driver.write(buffer, flash_address, length)
190 {
191 true
192 } else {
193 false
194 }
195 }
196 })
197 })
198 })
199 .unwrap_or(false)
200 } else {
201 false
202 }
203 });
204 if started_command {
205 break;
206 }
207 }
208 }
209}
210
211impl SyscallDriver for AppFlash<'_> {
212 fn command(
219 &self,
220 command_num: usize,
221 arg1: usize,
222 _: usize,
223 processid: ProcessId,
224 ) -> CommandReturn {
225 match command_num {
226 0 => CommandReturn::success(),
227
228 1 => {
229 let flash_address = arg1;
231
232 let res = self.enqueue_write(flash_address, processid);
233
234 match res {
235 Ok(()) => CommandReturn::success(),
236 Err(e) => CommandReturn::failure(e),
237 }
238 }
239
240 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
241 }
242 }
243
244 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
245 self.apps.enter(processid, |_, _| {})
246 }
247}