capsules_core/virtualizers/
virtual_flash.rs
1use core::cell::Cell;
34
35use kernel::collections::list::{List, ListLink, ListNode};
36use kernel::hil;
37use kernel::utilities::cells::{OptionalCell, TakeCell};
38use kernel::ErrorCode;
39
40pub struct MuxFlash<'a, F: hil::flash::Flash + 'static> {
47 flash: &'a F,
48 users: List<'a, FlashUser<'a, F>>,
49 inflight: OptionalCell<&'a FlashUser<'a, F>>,
50}
51
52impl<F: hil::flash::Flash> hil::flash::Client<F> for MuxFlash<'_, F> {
53 fn read_complete(
54 &self,
55 pagebuffer: &'static mut F::Page,
56 result: Result<(), hil::flash::Error>,
57 ) {
58 self.inflight.take().map(move |user| {
59 user.read_complete(pagebuffer, result);
60 });
61 self.do_next_op();
62 }
63
64 fn write_complete(
65 &self,
66 pagebuffer: &'static mut F::Page,
67 result: Result<(), hil::flash::Error>,
68 ) {
69 self.inflight.take().map(move |user| {
70 user.write_complete(pagebuffer, result);
71 });
72 self.do_next_op();
73 }
74
75 fn erase_complete(&self, result: Result<(), hil::flash::Error>) {
76 self.inflight.take().map(move |user| {
77 user.erase_complete(result);
78 });
79 self.do_next_op();
80 }
81}
82
83impl<'a, F: hil::flash::Flash> MuxFlash<'a, F> {
84 pub const fn new(flash: &'a F) -> MuxFlash<'a, F> {
85 MuxFlash {
86 flash,
87 users: List::new(),
88 inflight: OptionalCell::empty(),
89 }
90 }
91
92 fn do_next_op(&self) {
95 if self.inflight.is_none() {
96 let mnode = self
97 .users
98 .iter()
99 .find(|node| node.operation.get() != Op::Idle);
100 mnode.map(|node| {
101 node.buffer.take().map_or_else(
102 || {
103 if let Op::Erase(page_number) = node.operation.get() {
105 let _ = self.flash.erase_page(page_number);
106 }
107 },
108 |buf| {
109 match node.operation.get() {
110 Op::Write(page_number) => {
111 if let Err((_, buf)) = self.flash.write_page(page_number, buf) {
112 node.buffer.replace(buf);
113 }
114 }
115 Op::Read(page_number) => {
116 if let Err((_, buf)) = self.flash.read_page(page_number, buf) {
117 node.buffer.replace(buf);
118 }
119 }
120 Op::Erase(page_number) => {
121 let _ = self.flash.erase_page(page_number);
122 }
123 Op::Idle => {} }
125 },
126 );
127 node.operation.set(Op::Idle);
128 self.inflight.set(node);
129 });
130 }
131 }
132}
133
134#[derive(Copy, Clone, PartialEq)]
135enum Op {
136 Idle,
137 Write(usize),
138 Read(usize),
139 Erase(usize),
140}
141
142pub struct FlashUser<'a, F: hil::flash::Flash + 'static> {
149 mux: &'a MuxFlash<'a, F>,
150 buffer: TakeCell<'static, F::Page>,
151 operation: Cell<Op>,
152 next: ListLink<'a, FlashUser<'a, F>>,
153 client: OptionalCell<&'a dyn hil::flash::Client<FlashUser<'a, F>>>,
154}
155
156impl<'a, F: hil::flash::Flash> FlashUser<'a, F> {
157 pub fn new(mux: &'a MuxFlash<'a, F>) -> FlashUser<'a, F> {
158 FlashUser {
159 mux,
160 buffer: TakeCell::empty(),
161 operation: Cell::new(Op::Idle),
162 next: ListLink::empty(),
163 client: OptionalCell::empty(),
164 }
165 }
166}
167
168impl<'a, F: hil::flash::Flash, C: hil::flash::Client<Self>> hil::flash::HasClient<'a, C>
169 for FlashUser<'a, F>
170{
171 fn set_client(&'a self, client: &'a C) {
172 self.mux.users.push_head(self);
173 self.client.set(client);
174 }
175}
176
177impl<F: hil::flash::Flash> hil::flash::Client<F> for FlashUser<'_, F> {
178 fn read_complete(
179 &self,
180 pagebuffer: &'static mut F::Page,
181 result: Result<(), hil::flash::Error>,
182 ) {
183 self.client.map(move |client| {
184 client.read_complete(pagebuffer, result);
185 });
186 }
187
188 fn write_complete(
189 &self,
190 pagebuffer: &'static mut F::Page,
191 result: Result<(), hil::flash::Error>,
192 ) {
193 self.client.map(move |client| {
194 client.write_complete(pagebuffer, result);
195 });
196 }
197
198 fn erase_complete(&self, result: Result<(), hil::flash::Error>) {
199 self.client.map(move |client| {
200 client.erase_complete(result);
201 });
202 }
203}
204
205impl<'a, F: hil::flash::Flash> ListNode<'a, FlashUser<'a, F>> for FlashUser<'a, F> {
206 fn next(&'a self) -> &'a ListLink<'a, FlashUser<'a, F>> {
207 &self.next
208 }
209}
210
211impl<F: hil::flash::Flash> hil::flash::Flash for FlashUser<'_, F> {
212 type Page = F::Page;
213
214 fn read_page(
215 &self,
216 page_number: usize,
217 buf: &'static mut Self::Page,
218 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
219 self.buffer.replace(buf);
220 self.operation.set(Op::Read(page_number));
221 self.mux.do_next_op();
222 Ok(())
223 }
224
225 fn write_page(
226 &self,
227 page_number: usize,
228 buf: &'static mut Self::Page,
229 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
230 self.buffer.replace(buf);
231 self.operation.set(Op::Write(page_number));
232 self.mux.do_next_op();
233 Ok(())
234 }
235
236 fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
237 self.operation.set(Op::Erase(page_number));
238 self.mux.do_next_op();
239 Ok(())
240 }
241}