Skip to main content

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