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 = 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}