kernel/dynamic_binary_storage.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2024.
4
5//! Dynamic Binary Flasher for application loading and updating at runtime.
6//!
7//! These functions facilitate dynamic application flashing and process creation
8//! during runtime without requiring the user to restart the device.
9
10use core::cell::Cell;
11
12use crate::ErrorCode;
13use crate::Kernel;
14use crate::config;
15use crate::debug;
16use crate::deferred_call::{DeferredCall, DeferredCallClient};
17use crate::hil::nonvolatile_storage::{NonvolatileStorage, NonvolatileStorageClient};
18use crate::platform::chip::Chip;
19use crate::process::{ProcessLoadingAsyncClient, ShortId};
20use crate::process_loading::{
21 PaddingRequirement, ProcessLoadError, SequentialProcessLoaderMachine,
22};
23use crate::process_standard::ProcessStandardDebug;
24use crate::utilities::cells::{OptionalCell, TakeCell};
25use crate::utilities::leasable_buffer::SubSliceMut;
26
27/// Expected buffer length for storing application binaries.
28pub const BUF_LEN: usize = 512;
29
30/// The number of bytes in the TBF header for a padding app.
31const PADDING_TBF_HEADER_LENGTH: usize = 16;
32
33#[derive(Clone, Copy, PartialEq)]
34pub enum State {
35 Idle,
36 Setup,
37 AppWrite,
38 Load,
39 Abort,
40 Unload(Result<(), ErrorCode>, usize),
41 PaddingWrite,
42 Fail,
43}
44
45/// Addresses of where the new process will be stored.
46#[derive(Clone, Copy, Default)]
47struct ProcessLoadMetadata {
48 new_app_start_addr: usize,
49 new_app_length: usize,
50 previous_app_end_addr: usize,
51 next_app_start_addr: usize,
52 padding_requirement: PaddingRequirement,
53 setup_padding: bool,
54}
55
56/// This interface supports flashing binaries at runtime.
57pub trait DynamicBinaryStore {
58 /// Call to request flashing a new binary.
59 ///
60 /// This informs the kernel we want to load a process, and the size of the
61 /// entire process binary. The kernel will try to find a suitable location
62 /// in flash to store said process.
63 ///
64 /// Return value:
65 /// - `Ok(length)`: If there is a place to load the
66 /// process, the function will return `Ok()` with the size of the region
67 /// to store the process.
68 /// - `Err(ErrorCode)`: If there is nowhere to store the process a suitable
69 /// `ErrorCode` will be returned.
70 fn setup(&self, app_length: usize) -> Result<usize, ErrorCode>;
71
72 /// Instruct the kernel to write data to the flash.
73 ///
74 /// `offset` is where to start writing within the region allocated
75 /// for the new process binary from the `setup()` call.
76 ///
77 /// The caller must write the first 8 bytes of the process with valid header
78 /// data. Writes must either be after the first 8 bytes or include the
79 /// entire first 8 bytes.
80 ///
81 /// Returns an error if the write is outside of the permitted region or is
82 /// writing an invalid header.
83 fn write(
84 &self,
85 buffer: SubSliceMut<'static, u8>,
86 offset: usize,
87 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)>;
88
89 /// Signal to the kernel that the requesting process is done writing the new
90 /// binary.
91 fn finalize(&self) -> Result<(), ErrorCode>;
92
93 /// Call to abort the setup/writing process.
94 fn abort(&self) -> Result<(), ErrorCode>;
95
96 /// Sets a client for the SequentialDynamicBinaryStore Object
97 ///
98 /// When the client operation is done, it calls the `setup_done()`,
99 /// `write_done()` and `abort_done()` functions.
100 fn set_storage_client(&self, client: &'static dyn DynamicBinaryStoreClient);
101}
102
103/// The callback for dynamic binary flashing.
104pub trait DynamicBinaryStoreClient {
105 /// Any setup work is done and we are ready to write the process binary.
106 fn setup_done(&self, result: Result<(), ErrorCode>);
107
108 /// The provided app binary buffer has been stored.
109 fn write_done(&self, result: Result<(), ErrorCode>, buffer: &'static mut [u8], length: usize);
110
111 /// The kernel has successfully finished finalizing the new app and is ready
112 /// to move to the `load()` phase.
113 fn finalize_done(&self, result: Result<(), ErrorCode>);
114
115 /// Canceled any setup or writing operation and freed up reserved space.
116 fn abort_done(&self, result: Result<(), ErrorCode>);
117}
118
119/// This interface supports loading processes at runtime.
120pub trait DynamicProcessLoad {
121 /// Call to request kernel to load a new process.
122 fn load(&self) -> Result<(), ErrorCode>;
123
124 /// Sets a client for the SequentialDynamicProcessLoading Object
125 ///
126 /// When the client operation is done, it calls the `load_done()`
127 /// function.
128 fn set_load_client(&self, client: &'static dyn DynamicProcessLoadClient);
129}
130
131/// The callback for dynamic process loading.
132pub trait DynamicProcessLoadClient {
133 /// The new app has been loaded.
134 fn load_done(&self, result: Result<(), ProcessLoadError>);
135}
136
137/// This interface supports unloading processes at runtime.
138pub trait DynamicProcessUnload {
139 /// Call to terminate a process with given ShortId.
140 fn unload(&self, app: ShortId) -> Result<(), ErrorCode>;
141
142 /// Sets a client for the SequentialDynamicProcessUnload Object
143 ///
144 /// When the client operation is done, it calls the `unload_done()`
145 /// function.
146 fn set_unload_client(&self, client: &'static dyn DynamicProcessUnloadClient);
147}
148
149/// The callback for dynamic process unloading.
150pub trait DynamicProcessUnloadClient {
151 /// Terminated app (if running).
152 fn unload_done(&self, result: Result<(), ErrorCode>, app_handle: usize);
153}
154
155/// Dynamic process loading machine.
156pub struct SequentialDynamicBinaryStorage<
157 'a,
158 'b,
159 C: Chip + 'static,
160 D: ProcessStandardDebug + 'static,
161 F: NonvolatileStorage<'b>,
162> {
163 kernel: &'static Kernel,
164 flash_driver: &'b F,
165 loader_driver: &'a SequentialProcessLoaderMachine<'a, C, D>,
166 buffer: TakeCell<'static, [u8]>,
167 storage_client: OptionalCell<&'static dyn DynamicBinaryStoreClient>,
168 load_client: OptionalCell<&'static dyn DynamicProcessLoadClient>,
169 unload_client: OptionalCell<&'static dyn DynamicProcessUnloadClient>,
170 process_metadata: OptionalCell<ProcessLoadMetadata>,
171 state: Cell<State>,
172 deferred_call: DeferredCall,
173}
174
175impl<'a, 'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
176 SequentialDynamicBinaryStorage<'a, 'b, C, D, F>
177{
178 pub fn new(
179 kernel: &'static Kernel,
180 flash_driver: &'b F,
181 loader_driver: &'a SequentialProcessLoaderMachine<'a, C, D>,
182 buffer: &'static mut [u8],
183 ) -> Self {
184 Self {
185 kernel,
186 flash_driver,
187 loader_driver,
188 buffer: TakeCell::new(buffer),
189 storage_client: OptionalCell::empty(),
190 load_client: OptionalCell::empty(),
191 unload_client: OptionalCell::empty(),
192 process_metadata: OptionalCell::empty(),
193 state: Cell::new(State::Idle),
194 deferred_call: DeferredCall::new(),
195 }
196 }
197
198 /// Function to reset variables and states.
199 fn reset_process_loading_metadata(&self) {
200 self.state.set(State::Idle);
201 self.process_metadata.take();
202 }
203
204 /// This function checks whether the new app will fit in the bounds dictated
205 /// by the start address and length provided during the setup phase. This
206 /// function then also computes where in flash the data should be written
207 /// based on whether the call is coming during the app writing phase, or the
208 /// padding phase.
209 ///
210 /// This function returns the physical address in flash where the write is
211 /// supposed to happen.
212 fn compute_address(&self, offset: usize, length: usize) -> Result<usize, ErrorCode> {
213 let mut new_app_len: usize = 0;
214 let mut new_app_addr: usize = 0;
215 if let Some(metadata) = self.process_metadata.get() {
216 new_app_addr = metadata.new_app_start_addr;
217 new_app_len = metadata.new_app_length;
218 }
219
220 match self.state.get() {
221 State::AppWrite => {
222 // Check if there is an overflow while adding length and offset.
223 match offset.checked_add(length) {
224 Some(result) => {
225 // Check if the new app is trying to write beyond
226 // the bounds of the flash region allocated to it.
227 if result > new_app_len {
228 // This means the app is out of bounds.
229 Err(ErrorCode::INVAL)
230 } else {
231 // We compute the new address to write the app
232 // binary segment.
233 Ok(offset + new_app_addr)
234 }
235 }
236 None => Err(ErrorCode::INVAL),
237 }
238 }
239 // If we are going to write the padding header, we already know
240 // where to write in flash, so we don't have to add the start
241 // address
242 State::Setup | State::Load | State::PaddingWrite | State::Abort => Ok(offset),
243 // We aren't supposed to be able to write unless we are in one of
244 // the first two write states
245 _ => Err(ErrorCode::FAIL),
246 }
247 }
248
249 /// Compute the physical address where we should write the data and then
250 /// write it.
251 fn write_buffer(
252 &self,
253 user_buffer: SubSliceMut<'static, u8>,
254 offset: usize,
255 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
256 let length = user_buffer.len();
257
258 let physical_address = match self.compute_address(offset, length) {
259 Ok(addr) => addr,
260 Err(e) => return Err((e, user_buffer)),
261 };
262
263 // The kernel needs to check if the app is trying to write/overwrite the
264 // header. So the app can only write to the first 8 bytes if the app is
265 // writing all 8 bytes. Else, the kernel must raise an error. The app is
266 // not allowed to write from say, offset 4 because we have to ensure the
267 // validity of the header.
268 //
269 // This means the app is trying to manipulate the space where the TBF
270 // header should go. Ideally, we want the app to only write the complete
271 // set of 8 bytes which is used to determine if the header is valid. We
272 // don't want apps to do this, so we return an error.
273 if (offset == 0 && length < 8) || (offset != 0 && offset < 8) {
274 return Err((ErrorCode::INVAL, user_buffer));
275 }
276
277 // Check if we are writing the start of the TBF header.
278 //
279 // The app is not allowed to manipulate parts of the TBF header, so if
280 // it is trying to write at the very beginning of the promised flash
281 // region, we require the app writes the entire 8 bytes of the header.
282 // This header is then checked for validity.
283 //
284 // We validate through a borrow of `user_buffer` here (rather than
285 // consuming it via `take()`) so that we still own it and can return
286 // it back to the caller on every error path.
287 if offset == 0 {
288 // Pass the first eight bytes of the tbf header to parse out the
289 // length of the header and app. We then use those values to see if
290 // the app is going to be valid.
291 let test_header_slice = match user_buffer.as_slice().get(0..8) {
292 Some(slice) => slice,
293 None => {
294 return Err((ErrorCode::INVAL, user_buffer));
295 }
296 };
297 let header = match test_header_slice.try_into() {
298 Ok(header) => header,
299 Err(_) => {
300 return Err((ErrorCode::FAIL, user_buffer));
301 }
302 };
303 let (_version, _header_length, entry_length) =
304 match tock_tbf::parse::parse_tbf_header_lengths(header) {
305 Ok((v, hl, el)) => (v, hl, el),
306 Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(_entry_length)) => {
307 // If we have an invalid header, so we return an error
308 return Err((ErrorCode::INVAL, user_buffer));
309 }
310 Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
311 // If we could not parse the header, then that's an
312 // issue. We return an Error.
313 return Err((ErrorCode::INVAL, user_buffer));
314 }
315 };
316
317 // Check if the length in the header is matching what the app
318 // requested during the setup phase also check if the kernel
319 // version matches the version indicated in the new application.
320 let mut new_app_len = 0;
321 if let Some(metadata) = self.process_metadata.get() {
322 new_app_len = metadata.new_app_length;
323 }
324 if entry_length as usize != new_app_len {
325 return Err((ErrorCode::INVAL, user_buffer));
326 }
327 }
328
329 // Take the buffer to write with.
330 let buffer = user_buffer.take();
331 self.flash_driver
332 .write(buffer, physical_address, length)
333 .map_err(|(e, buf)| (e, SubSliceMut::new(buf)))
334 }
335
336 /// Function to generate the padding header to append after the new app.
337 /// This header is created and written to ensure the integrity of the
338 /// processes linked list
339 fn write_padding_app(&self, padding_app_length: usize, offset: usize) -> Result<(), ErrorCode> {
340 // Write the header into the array
341 self.buffer.map(|buffer| {
342 // First two bytes are the TBF version (2).
343 buffer[0] = 2;
344 buffer[1] = 0;
345
346 // The next two bytes are the header length (fixed to 16 bytes for
347 // padding).
348 buffer[2] = (PADDING_TBF_HEADER_LENGTH & 0xff) as u8;
349 buffer[3] = ((PADDING_TBF_HEADER_LENGTH >> 8) & 0xff) as u8;
350
351 // The next 4 bytes are the total app length including the header.
352 buffer[4] = (padding_app_length & 0xff) as u8;
353 buffer[5] = ((padding_app_length >> 8) & 0xff) as u8;
354 buffer[6] = ((padding_app_length >> 16) & 0xff) as u8;
355 buffer[7] = ((padding_app_length >> 24) & 0xff) as u8;
356
357 // We set the flags to 0.
358 for i in 8..12 {
359 buffer[i] = 0x00_u8;
360 }
361
362 // xor of the previous values
363 buffer[12] = buffer[0] ^ buffer[4] ^ buffer[8];
364 buffer[13] = buffer[1] ^ buffer[5] ^ buffer[9];
365 buffer[14] = buffer[2] ^ buffer[6] ^ buffer[10];
366 buffer[15] = buffer[3] ^ buffer[7] ^ buffer[11];
367 });
368
369 self.buffer.take().map_or(Err(ErrorCode::BUSY), |buffer| {
370 match self
371 .loader_driver
372 .check_if_within_flash_bounds(offset, PADDING_TBF_HEADER_LENGTH)
373 {
374 true => {
375 // Write the header only if there are more than 16 bytes.
376 // available in the flash.
377 let mut padding_slice = SubSliceMut::new(buffer);
378 padding_slice.slice(..PADDING_TBF_HEADER_LENGTH);
379 // We are only writing the header, so 16 bytes is enough.
380 self.write_buffer(padding_slice, offset)
381 .map_err(|(e, buf)| {
382 self.buffer.replace(buf.take());
383 e
384 })
385 }
386 false => Err(ErrorCode::NOMEM),
387 }
388 })
389 }
390}
391
392impl<'b, C: Chip, D: ProcessStandardDebug, F: NonvolatileStorage<'b>> DeferredCallClient
393 for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
394{
395 fn handle_deferred_call(&self) {
396 // We use deferred call to signal the completion of finalize or unload
397 match self.state.get() {
398 State::Load => {
399 self.storage_client.map(|client| {
400 client.finalize_done(Ok(()));
401 });
402 }
403 State::Unload(result, app_handle) => {
404 self.reset_process_loading_metadata();
405
406 self.unload_client.map(|client| {
407 client.unload_done(result, app_handle);
408 });
409 }
410 _ => {}
411 }
412 }
413
414 fn register(&'static self) {
415 self.deferred_call.register(self);
416 }
417}
418
419/// This is the callback client for the underlying physical storage driver.
420impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
421 NonvolatileStorageClient for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
422{
423 fn read_done(&self, _buffer: &'static mut [u8], _length: usize) {
424 // We will never use this, but we need to implement this anyway.
425 unimplemented!();
426 }
427
428 fn write_done(&self, buffer: &'static mut [u8], length: usize) {
429 match self.state.get() {
430 State::AppWrite => {
431 self.state.set(State::AppWrite);
432 // Switch on which user generated this callback and trigger
433 // client callback.
434 self.storage_client.map(|client| {
435 client.write_done(Ok(()), buffer, length);
436 });
437 }
438 State::PaddingWrite => {
439 // Replace the buffer after the padding is written.
440 self.reset_process_loading_metadata();
441 self.buffer.replace(buffer);
442 }
443 State::Fail => {
444 // If we failed at any of writing, we want to set the state to
445 // PaddingWrite so that the callback after writing the padding
446 // app will get triggererd.
447 self.buffer.replace(buffer);
448 if let Some(metadata) = self.process_metadata.get() {
449 let _ = self
450 .write_padding_app(metadata.new_app_length, metadata.new_app_start_addr);
451 }
452 // Clear all metadata specific to this load.
453 self.reset_process_loading_metadata();
454 }
455 State::Setup => {
456 // We have finished writing the post app padding.
457 self.buffer.replace(buffer);
458
459 if let Some(mut metadata) = self.process_metadata.get() {
460 if !metadata.setup_padding {
461 // Write padding header to the beginning of the new app address.
462 // This ensures that the linked list is not broken in the event of a
463 // powercycle before the app is fully written and loaded.
464 metadata.setup_padding = true;
465 let _ = self.write_padding_app(
466 metadata.new_app_length,
467 metadata.new_app_start_addr,
468 );
469 self.process_metadata.set(metadata);
470 } else {
471 self.state.set(State::AppWrite);
472 // Let the client know we are done setting up.
473 self.storage_client.map(|client| {
474 client.setup_done(Ok(()));
475 });
476 }
477 }
478 }
479 State::Load => {
480 // We finished writing pre-padding and we need to Load the app.
481 self.buffer.replace(buffer);
482 self.storage_client.map(|client| {
483 client.finalize_done(Ok(()));
484 });
485 }
486 State::Abort => {
487 self.buffer.replace(buffer);
488 // Reset metadata and let client know we are done aborting.
489 self.reset_process_loading_metadata();
490 self.storage_client.map(|client| {
491 client.abort_done(Ok(()));
492 });
493 }
494 State::Unload(_, _) => {
495 self.buffer.replace(buffer);
496 }
497 State::Idle => {
498 self.buffer.replace(buffer);
499 }
500 }
501 }
502}
503
504/// Callback client for the async process loader
505impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
506 ProcessLoadingAsyncClient for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
507{
508 fn process_loaded(&self, result: Result<(), ProcessLoadError>) {
509 self.load_client.map(|client| {
510 client.load_done(result);
511 });
512 }
513
514 fn process_loading_finished(&self) {
515 self.load_client.map(|client| {
516 client.load_done(Ok(()));
517 });
518 }
519}
520
521/// Storage interface exposed to the app_loader capsule
522impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
523 DynamicBinaryStore for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
524{
525 fn set_storage_client(&self, client: &'static dyn DynamicBinaryStoreClient) {
526 self.storage_client.set(client);
527 }
528
529 fn setup(&self, app_length: usize) -> Result<usize, ErrorCode> {
530 self.process_metadata.set(ProcessLoadMetadata::default());
531
532 if self.state.get() == State::Idle {
533 self.state.set(State::Setup);
534 match self.loader_driver.check_flash_for_new_address(app_length) {
535 Ok((
536 new_app_start_address,
537 padding_requirement,
538 previous_app_end_addr,
539 next_app_start_addr,
540 )) => {
541 if let Some(mut metadata) = self.process_metadata.get() {
542 metadata.new_app_start_addr = new_app_start_address;
543 metadata.new_app_length = app_length;
544 metadata.previous_app_end_addr = previous_app_end_addr;
545 metadata.next_app_start_addr = next_app_start_addr;
546 metadata.padding_requirement = padding_requirement;
547 self.process_metadata.set(metadata);
548 }
549
550 match padding_requirement {
551 // If we decided we need to write a padding app after
552 // the new app, we go ahead and do it.
553 PaddingRequirement::PostPad | PaddingRequirement::PreAndPostPad => {
554 // Calculating the distance between our app and
555 // either the next app.
556 let new_app_end_address = new_app_start_address + app_length;
557 let post_pad_length = next_app_start_addr - new_app_end_address;
558
559 let padding_result =
560 self.write_padding_app(post_pad_length, new_app_end_address);
561 let _ = match padding_result {
562 Ok(()) => Ok(()),
563 Err(e) => {
564 // This means we were unable to write the
565 // padding app.
566 self.reset_process_loading_metadata();
567 Err(e)
568 }
569 };
570 }
571 // Otherwise we let the client know we are done with the
572 // setup, and we are ready to write the app to flash.
573 PaddingRequirement::None | PaddingRequirement::PrePad => {
574 if let Some(mut metadata) = self.process_metadata.get() {
575 if !metadata.setup_padding {
576 // Write padding header to the beginning of the new app address.
577 // This ensures that the linked list is not broken in the event of a
578 // powercycle before the app is fully written and loaded.
579
580 metadata.setup_padding = true;
581 let _ = self.write_padding_app(
582 metadata.new_app_length,
583 metadata.new_app_start_addr,
584 );
585 self.process_metadata.set(metadata);
586 }
587 }
588 }
589 }
590 Ok(app_length)
591 }
592 Err(_err) => {
593 // Reset the state to None because we did not find any
594 // available address for this app.
595 self.reset_process_loading_metadata();
596 Err(ErrorCode::FAIL)
597 }
598 }
599 } else {
600 // We are in the wrong mode of operation. Ideally we should never reach
601 // here, but this error exists as a failsafe. The capsule should send
602 // a busy error out to the userland app.
603 Err(ErrorCode::INVAL)
604 }
605 }
606
607 fn write(
608 &self,
609 buffer: SubSliceMut<'static, u8>,
610 offset: usize,
611 ) -> Result<(), (ErrorCode, SubSliceMut<'static, u8>)> {
612 match self.state.get() {
613 State::AppWrite => {
614 let res = self.write_buffer(buffer, offset);
615 match res {
616 Ok(()) => Ok(()),
617 Err((e, buffer)) => {
618 // If we fail here, let us erase the app we just wrote.
619 self.state.set(State::Fail);
620 Err((e, buffer))
621 }
622 }
623 }
624 _ => {
625 // We are in the wrong mode of operation. Ideally we should never reach
626 // here, but this error exists as a failsafe. The capsule should send
627 // a busy error out to the userland app.
628 Err((ErrorCode::INVAL, buffer))
629 }
630 }
631 }
632
633 fn finalize(&self) -> Result<(), ErrorCode> {
634 match self.state.get() {
635 State::AppWrite => {
636 if let Some(metadata) = self.process_metadata.get() {
637 match metadata.padding_requirement {
638 // If we decided we need to write a padding app before the new
639 // app, we go ahead and do it.
640 PaddingRequirement::PrePad | PaddingRequirement::PreAndPostPad => {
641 // Calculate the distance between our app and the previous
642 // app.
643 let previous_app_end_addr = metadata.previous_app_end_addr;
644 let pre_pad_length =
645 metadata.new_app_start_addr - previous_app_end_addr;
646 self.state.set(State::Load);
647 let padding_result =
648 self.write_padding_app(pre_pad_length, previous_app_end_addr);
649 match padding_result {
650 Ok(()) => {
651 if config::CONFIG.debug_load_processes {
652 debug!("Successfully writing prepadding app");
653 }
654 Ok(())
655 }
656 Err(_e) => {
657 // This means we were unable to write the padding
658 // app.
659 self.reset_process_loading_metadata();
660 Err(ErrorCode::FAIL)
661 }
662 }
663 }
664 // We should never reach here if we are not writing a prepad
665 // app.
666 PaddingRequirement::None | PaddingRequirement::PostPad => {
667 if config::CONFIG.debug_load_processes {
668 debug!("No PrePad app to write.");
669 }
670 self.state.set(State::Load);
671 self.deferred_call.set();
672 Ok(())
673 }
674 }
675 } else {
676 Err(ErrorCode::INVAL)
677 }
678 }
679 _ => Err(ErrorCode::INVAL),
680 }
681 }
682
683 fn abort(&self) -> Result<(), ErrorCode> {
684 match self.state.get() {
685 State::Setup | State::AppWrite => {
686 self.state.set(State::Abort);
687 if let Some(metadata) = self.process_metadata.get() {
688 // Write padding header to the beginning of the new app address.
689 // This ensures that the flash space is reclaimed for future use.
690 match self
691 .write_padding_app(metadata.new_app_length, metadata.new_app_start_addr)
692 {
693 Ok(()) => Ok(()),
694 // If abort() returns ErrorCode::BUSY,
695 // the userland app is expected to retry abort.
696 Err(_) => Err(ErrorCode::BUSY),
697 }
698 } else {
699 Err(ErrorCode::FAIL)
700 }
701 }
702 _ => {
703 // We are in the wrong mode of operation. Ideally we should never reach
704 // here, but this error exists as a failsafe. The capsule should send
705 // a busy error out to the userland app.
706 Err(ErrorCode::INVAL)
707 }
708 }
709 }
710}
711
712/// Loading interface exposed to the app_loader capsule
713impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
714 DynamicProcessLoad for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
715{
716 fn set_load_client(&self, client: &'static dyn DynamicProcessLoadClient) {
717 self.load_client.set(client);
718 }
719
720 fn load(&self) -> Result<(), ErrorCode> {
721 // We have finished writing the last user data segment, next step is to
722 // load the process.
723 match self.state.get() {
724 State::Load => {
725 if let Some(metadata) = self.process_metadata.get() {
726 let _ = match self.loader_driver.load_new_process_binary(
727 metadata.new_app_start_addr,
728 metadata.new_app_length,
729 ) {
730 Ok(()) => Ok::<(), ProcessLoadError>(()),
731 Err(_e) => {
732 self.reset_process_loading_metadata();
733 return Err(ErrorCode::FAIL);
734 }
735 };
736 } else {
737 self.reset_process_loading_metadata();
738 return Err(ErrorCode::FAIL);
739 }
740 self.reset_process_loading_metadata();
741 Ok(())
742 }
743 _ => Err(ErrorCode::INVAL),
744 }
745 }
746}
747
748/// Loading interface exposed to the app_loader capsule
749impl<'b, C: Chip + 'static, D: ProcessStandardDebug + 'static, F: NonvolatileStorage<'b>>
750 DynamicProcessUnload for SequentialDynamicBinaryStorage<'_, 'b, C, D, F>
751{
752 fn set_unload_client(&self, client: &'static dyn DynamicProcessUnloadClient) {
753 self.unload_client.set(client);
754 }
755
756 fn unload(&self, app: ShortId) -> Result<(), ErrorCode> {
757 match self.state.get() {
758 State::Idle => {
759 self.state.set(State::Unload(Err(ErrorCode::BUSY), 0)); // To ensure the state machine knows not to service other apps
760
761 let (result, _app_handle) = match self
762 .kernel
763 .remove_process_from_active_processes(app, |proc| {
764 proc.get_addresses().flash_start
765 }) {
766 Ok(id) => {
767 let res = Ok(());
768 let handle = id;
769
770 self.state.set(State::Unload(res, handle));
771 self.deferred_call.set();
772
773 (res, handle)
774 }
775 Err(()) => (Err(ErrorCode::INVAL), 0),
776 };
777
778 result
779 }
780 _ => {
781 // We are in the wrong mode of operation. Ideally we should never reach
782 // here, but this error exists as a failsafe. The capsule should send
783 // a busy error out to the userland app.
784 Err(ErrorCode::BUSY)
785 }
786 }
787 }
788}