kernel/
process_loading.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 2022.
4
5//! Helper functions and machines for loading process binaries into in-memory
6//! Tock processes.
7//!
8//! Process loaders are responsible for parsing the binary formats of Tock
9//! processes, checking whether they are allowed to be loaded, and if so
10//! initializing a process structure to run it.
11//!
12//! This module provides multiple process loader options depending on which
13//! features a particular board requires.
14
15use core::cell::Cell;
16use core::fmt;
17
18use crate::capabilities::ProcessManagementCapability;
19use crate::config;
20use crate::debug;
21use crate::deferred_call::{DeferredCall, DeferredCallClient};
22use crate::kernel::Kernel;
23use crate::platform::chip::Chip;
24use crate::process::{Process, ShortId};
25use crate::process_binary::{ProcessBinary, ProcessBinaryError};
26use crate::process_checker::AcceptedCredential;
27use crate::process_checker::{AppIdPolicy, ProcessCheckError, ProcessCheckerMachine};
28use crate::process_policies::ProcessFaultPolicy;
29use crate::process_policies::ProcessStandardStoragePermissionsPolicy;
30use crate::process_standard::ProcessStandard;
31use crate::process_standard::{ProcessStandardDebug, ProcessStandardDebugFull};
32use crate::utilities::cells::{MapCell, OptionalCell};
33
34/// Errors that can occur when trying to load and create processes.
35pub enum ProcessLoadError {
36    /// Not enough memory to meet the amount requested by a process. Modify the
37    /// process to request less memory, flash fewer processes, or increase the
38    /// size of the region your board reserves for process memory.
39    NotEnoughMemory,
40
41    /// A process was loaded with a length in flash that the MPU does not
42    /// support. The fix is probably to correct the process size, but this could
43    /// also be caused by a bad MPU implementation.
44    MpuInvalidFlashLength,
45
46    /// The MPU configuration failed for some other, unspecified reason. This
47    /// could be of an internal resource exhaustion, or a mismatch between the
48    /// (current) MPU constraints and process requirements.
49    MpuConfigurationError,
50
51    /// A process specified a fixed memory address that it needs its memory
52    /// range to start at, and the kernel did not or could not give the process
53    /// a memory region starting at that address.
54    MemoryAddressMismatch {
55        actual_address: u32,
56        expected_address: u32,
57    },
58
59    /// There is nowhere in the `PROCESSES` array to store this process.
60    NoProcessSlot,
61
62    /// Process loading failed because parsing the binary failed.
63    BinaryError(ProcessBinaryError),
64
65    /// Process loading failed because checking the process failed.
66    CheckError(ProcessCheckError),
67
68    /// Process loading error due (likely) to a bug in the kernel. If you get
69    /// this error please open a bug report.
70    InternalError,
71}
72
73impl fmt::Debug for ProcessLoadError {
74    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        match self {
76            ProcessLoadError::NotEnoughMemory => {
77                write!(f, "Not able to provide RAM requested by app")
78            }
79
80            ProcessLoadError::MpuInvalidFlashLength => {
81                write!(f, "App flash length not supported by MPU")
82            }
83
84            ProcessLoadError::MpuConfigurationError => {
85                write!(f, "Configuring the MPU failed")
86            }
87
88            ProcessLoadError::MemoryAddressMismatch {
89                actual_address,
90                expected_address,
91            } => write!(
92                f,
93                "App memory does not match requested address Actual:{:#x}, Expected:{:#x}",
94                actual_address, expected_address
95            ),
96
97            ProcessLoadError::NoProcessSlot => {
98                write!(f, "Nowhere to store the loaded process")
99            }
100
101            ProcessLoadError::BinaryError(binary_error) => {
102                writeln!(f, "Error parsing process binary")?;
103                write!(f, "{:?}", binary_error)
104            }
105
106            ProcessLoadError::CheckError(check_error) => {
107                writeln!(f, "Error checking process")?;
108                write!(f, "{:?}", check_error)
109            }
110
111            ProcessLoadError::InternalError => write!(f, "Error in kernel. Likely a bug."),
112        }
113    }
114}
115
116////////////////////////////////////////////////////////////////////////////////
117// SYNCHRONOUS PROCESS LOADING
118////////////////////////////////////////////////////////////////////////////////
119
120/// Load processes into runnable process structures.
121///
122/// Load processes (stored as TBF objects in flash) into runnable process
123/// structures stored in the `procs` array and mark all successfully loaded
124/// processes as runnable. This method does not check the cryptographic
125/// credentials of TBF objects. Platforms for which code size is tight and do
126/// not need to check TBF credentials can call this method because it results in
127/// a smaller kernel, as it does not invoke the credential checking state
128/// machine.
129///
130/// This function is made `pub` so that board files can use it, but loading
131/// processes from slices of flash an memory is fundamentally unsafe. Therefore,
132/// we require the `ProcessManagementCapability` to call this function.
133// Mark inline always to reduce code size. Since this is only called in one
134// place (a board's main.rs), by inlining the load_*processes() functions, the
135// compiler can elide many checks which reduces code size appreciably. Note,
136// however, these functions require a rather large stack frame, which may be an
137// issue for boards small kernel stacks.
138#[inline(always)]
139pub fn load_processes<C: Chip>(
140    kernel: &'static Kernel,
141    chip: &'static C,
142    app_flash: &'static [u8],
143    app_memory: &'static mut [u8],
144    mut procs: &'static mut [Option<&'static dyn Process>],
145    fault_policy: &'static dyn ProcessFaultPolicy,
146    _capability_management: &dyn ProcessManagementCapability,
147) -> Result<(), ProcessLoadError> {
148    load_processes_from_flash::<C, ProcessStandardDebugFull>(
149        kernel,
150        chip,
151        app_flash,
152        app_memory,
153        &mut procs,
154        fault_policy,
155    )?;
156
157    if config::CONFIG.debug_process_credentials {
158        debug!("Checking: no checking, load and run all processes");
159    }
160    for proc in procs.iter() {
161        proc.map(|p| {
162            if config::CONFIG.debug_process_credentials {
163                debug!("Running {}", p.get_process_name());
164            }
165        });
166    }
167    Ok(())
168}
169
170/// Helper function to load processes from flash into an array of active
171/// processes. This is the default template for loading processes, but a board
172/// is able to create its own `load_processes()` function and use that instead.
173///
174/// Processes are found in flash starting from the given address and iterating
175/// through Tock Binary Format (TBF) headers. Processes are given memory out of
176/// the `app_memory` buffer until either the memory is exhausted or the
177/// allocated number of processes are created. This buffer is a non-static slice,
178/// ensuring that this code cannot hold onto the slice past the end of this function
179/// (instead, processes store a pointer and length), which necessary for later
180/// creation of `ProcessBuffer`s in this memory region to be sound.
181/// A reference to each process is stored in the provided `procs` array.
182/// How process faults are handled by the
183/// kernel must be provided and is assigned to every created process.
184///
185/// Returns `Ok(())` if process discovery went as expected. Returns a
186/// `ProcessLoadError` if something goes wrong during TBF parsing or process
187/// creation.
188#[inline(always)]
189fn load_processes_from_flash<C: Chip, D: ProcessStandardDebug + 'static>(
190    kernel: &'static Kernel,
191    chip: &'static C,
192    app_flash: &'static [u8],
193    app_memory: &'static mut [u8],
194    procs: &mut &'static mut [Option<&'static dyn Process>],
195    fault_policy: &'static dyn ProcessFaultPolicy,
196) -> Result<(), ProcessLoadError> {
197    if config::CONFIG.debug_load_processes {
198        debug!(
199            "Loading processes from flash={:#010X}-{:#010X} into sram={:#010X}-{:#010X}",
200            app_flash.as_ptr() as usize,
201            app_flash.as_ptr() as usize + app_flash.len() - 1,
202            app_memory.as_ptr() as usize,
203            app_memory.as_ptr() as usize + app_memory.len() - 1
204        );
205    }
206
207    let mut remaining_flash = app_flash;
208    let mut remaining_memory = app_memory;
209    // Try to discover up to `procs.len()` processes in flash.
210    let mut index = 0;
211    let num_procs = procs.len();
212    while index < num_procs {
213        let load_binary_result = discover_process_binary(remaining_flash);
214
215        match load_binary_result {
216            Ok((new_flash, process_binary)) => {
217                remaining_flash = new_flash;
218
219                let load_result = load_process::<C, D>(
220                    kernel,
221                    chip,
222                    process_binary,
223                    remaining_memory,
224                    ShortId::LocallyUnique,
225                    index,
226                    fault_policy,
227                    &(),
228                );
229                match load_result {
230                    Ok((new_mem, proc)) => {
231                        remaining_memory = new_mem;
232                        match proc {
233                            Some(p) => {
234                                if config::CONFIG.debug_load_processes {
235                                    debug!("Loaded process {}", p.get_process_name())
236                                }
237                                procs[index] = proc;
238                                index += 1;
239                            }
240                            None => {
241                                if config::CONFIG.debug_load_processes {
242                                    debug!("No process loaded.");
243                                }
244                            }
245                        }
246                    }
247                    Err((new_mem, err)) => {
248                        remaining_memory = new_mem;
249                        if config::CONFIG.debug_load_processes {
250                            debug!("Processes load error: {:?}.", err);
251                        }
252                    }
253                }
254            }
255            Err((new_flash, err)) => {
256                remaining_flash = new_flash;
257                match err {
258                    ProcessBinaryError::NotEnoughFlash | ProcessBinaryError::TbfHeaderNotFound => {
259                        if config::CONFIG.debug_load_processes {
260                            debug!("No more processes to load: {:?}.", err);
261                        }
262                        // No more processes to load.
263                        break;
264                    }
265
266                    ProcessBinaryError::TbfHeaderParseFailure(_)
267                    | ProcessBinaryError::IncompatibleKernelVersion { .. }
268                    | ProcessBinaryError::IncorrectFlashAddress { .. }
269                    | ProcessBinaryError::NotEnabledProcess
270                    | ProcessBinaryError::Padding => {
271                        if config::CONFIG.debug_load_processes {
272                            debug!("Unable to use process binary: {:?}.", err);
273                        }
274
275                        // Skip this binary and move to the next one.
276                        continue;
277                    }
278                }
279            }
280        }
281    }
282    Ok(())
283}
284
285////////////////////////////////////////////////////////////////////////////////
286// HELPER FUNCTIONS
287////////////////////////////////////////////////////////////////////////////////
288
289/// Find a process binary stored at the beginning of `flash` and create a
290/// `ProcessBinary` object if the process is viable to run on this kernel.
291fn discover_process_binary(
292    flash: &'static [u8],
293) -> Result<(&'static [u8], ProcessBinary), (&'static [u8], ProcessBinaryError)> {
294    if config::CONFIG.debug_load_processes {
295        debug!(
296            "Looking for process binary in flash={:#010X}-{:#010X}",
297            flash.as_ptr() as usize,
298            flash.as_ptr() as usize + flash.len() - 1
299        );
300    }
301
302    // If this fails, not enough remaining flash to check for an app.
303    let test_header_slice = flash
304        .get(0..8)
305        .ok_or((flash, ProcessBinaryError::NotEnoughFlash))?;
306
307    // Pass the first eight bytes to tbfheader to parse out the length of
308    // the tbf header and app. We then use those values to see if we have
309    // enough flash remaining to parse the remainder of the header.
310    //
311    // Start by converting [u8] to [u8; 8].
312    let header = test_header_slice
313        .try_into()
314        .or(Err((flash, ProcessBinaryError::NotEnoughFlash)))?;
315
316    let (version, header_length, app_length) =
317        match tock_tbf::parse::parse_tbf_header_lengths(header) {
318            Ok((v, hl, el)) => (v, hl, el),
319            Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(app_length)) => {
320                // If we could not parse the header, then we want to skip over
321                // this app and look for the next one.
322                (0, 0, app_length)
323            }
324            Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
325                // Since Tock apps use a linked list, it is very possible the
326                // header we started to parse is intentionally invalid to signal
327                // the end of apps. This is ok and just means we have finished
328                // loading apps.
329                return Err((flash, ProcessBinaryError::TbfHeaderNotFound));
330            }
331        };
332
333    // Now we can get a slice which only encompasses the length of flash
334    // described by this tbf header.  We will either parse this as an actual
335    // app, or skip over this region.
336    let app_flash = flash
337        .get(0..app_length as usize)
338        .ok_or((flash, ProcessBinaryError::NotEnoughFlash))?;
339
340    // Advance the flash slice for process discovery beyond this last entry.
341    // This will be the start of where we look for a new process since Tock
342    // processes are allocated back-to-back in flash.
343    let remaining_flash = flash
344        .get(app_flash.len()..)
345        .ok_or((flash, ProcessBinaryError::NotEnoughFlash))?;
346
347    let pb = ProcessBinary::create(app_flash, header_length as usize, version, true)
348        .map_err(|e| (remaining_flash, e))?;
349
350    Ok((remaining_flash, pb))
351}
352
353/// Load a process stored as a TBF process binary with `app_memory` as the RAM
354/// pool that its RAM should be allocated from. Returns `Ok` if the process
355/// object was created, `Err` with a relevant error if the process object could
356/// not be created.
357fn load_process<C: Chip, D: ProcessStandardDebug>(
358    kernel: &'static Kernel,
359    chip: &'static C,
360    process_binary: ProcessBinary,
361    app_memory: &'static mut [u8],
362    app_id: ShortId,
363    index: usize,
364    fault_policy: &'static dyn ProcessFaultPolicy,
365    storage_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
366) -> Result<(&'static mut [u8], Option<&'static dyn Process>), (&'static mut [u8], ProcessLoadError)>
367{
368    if config::CONFIG.debug_load_processes {
369        debug!(
370            "Loading: process flash={:#010X}-{:#010X} ram={:#010X}-{:#010X}",
371            process_binary.flash.as_ptr() as usize,
372            process_binary.flash.as_ptr() as usize + process_binary.flash.len() - 1,
373            app_memory.as_ptr() as usize,
374            app_memory.as_ptr() as usize + app_memory.len() - 1
375        );
376    }
377
378    // Need to reassign remaining_memory in every iteration so the compiler
379    // knows it will not be re-borrowed.
380    // If we found an actual app header, try to create a `Process`
381    // object. We also need to shrink the amount of remaining memory
382    // based on whatever is assigned to the new process if one is
383    // created.
384
385    // Try to create a process object from that app slice. If we don't
386    // get a process and we didn't get a loading error (aka we got to
387    // this point), then the app is a disabled process or just padding.
388    let (process_option, unused_memory) = unsafe {
389        ProcessStandard::<C, D>::create(
390            kernel,
391            chip,
392            process_binary,
393            app_memory,
394            fault_policy,
395            storage_policy,
396            app_id,
397            index,
398        )
399        .map_err(|(e, memory)| (memory, e))?
400    };
401
402    process_option.map(|process| {
403        if config::CONFIG.debug_load_processes {
404            debug!(
405                "Loading: {} [{}] flash={:#010X}-{:#010X} ram={:#010X}-{:#010X}",
406                process.get_process_name(),
407                index,
408                process.get_addresses().flash_start,
409                process.get_addresses().flash_end,
410                process.get_addresses().sram_start,
411                process.get_addresses().sram_end - 1,
412            );
413        }
414    });
415
416    Ok((unused_memory, process_option))
417}
418
419////////////////////////////////////////////////////////////////////////////////
420// ASYNCHRONOUS PROCESS LOADING
421////////////////////////////////////////////////////////////////////////////////
422
423/// Client for asynchronous process loading.
424///
425/// This supports a client that is notified after trying to load each process in
426/// flash. Also there is a callback for after all processes have been
427/// discovered.
428pub trait ProcessLoadingAsyncClient {
429    /// A process was successfully found in flash, checked, and loaded into a
430    /// `ProcessStandard` object.
431    fn process_loaded(&self, result: Result<(), ProcessLoadError>);
432
433    /// There are no more processes in flash to be loaded.
434    fn process_loading_finished(&self);
435}
436
437/// Asynchronous process loading.
438///
439/// Machines which implement this trait perform asynchronous process loading and
440/// signal completion through `ProcessLoadingAsyncClient`.
441///
442/// Various process loaders may exist. This includes a loader from a MCU's
443/// integrated flash, or a loader from an external flash chip.
444pub trait ProcessLoadingAsync<'a> {
445    /// Set the client to receive callbacks about process loading and when
446    /// process loading has finished.
447    fn set_client(&self, client: &'a dyn ProcessLoadingAsyncClient);
448
449    /// Set the credential checking policy for the loader.
450    fn set_policy(&self, policy: &'a dyn AppIdPolicy);
451
452    /// Start the process loading operation.
453    fn start(&self);
454}
455
456/// Operating mode of the loader.
457#[derive(Clone, Copy)]
458enum SequentialProcessLoaderMachineState {
459    /// Phase of discovering `ProcessBinary` objects in flash.
460    DiscoverProcessBinaries,
461    /// Phase of loading `ProcessBinary`s into `Process`es.
462    LoadProcesses,
463}
464
465/// Operating mode of the sequential process loader.
466///
467/// The loader supports loading processes from flash at boot, and loading processes
468/// that were written to flash dynamically at runtime. Most of the internal logic is the
469/// same (and therefore reused), but we need to track which mode of operation the
470/// loader is in.
471#[derive(Clone, Copy)]
472enum SequentialProcessLoaderMachineRunMode {
473    /// The loader was called by a board's main function at boot.
474    BootMode,
475    /// The loader was called by a dynamic process loader at runtime.
476    RuntimeMode,
477}
478
479/// Enum to hold the padding requirements for a new application.
480#[derive(Clone, Copy, PartialEq, Default)]
481pub enum PaddingRequirement {
482    #[default]
483    None,
484    PrePad,
485    PostPad,
486    PreAndPostPad,
487}
488
489/// A machine for loading processes stored sequentially in a region of flash.
490///
491/// Load processes (stored as TBF objects in flash) into runnable process
492/// structures stored in the `procs` array. This machine scans the footers in
493/// the TBF for cryptographic credentials for binary integrity, passing them to
494/// the checker to decide whether the process has sufficient credentials to run.
495pub struct SequentialProcessLoaderMachine<'a, C: Chip + 'static, D: ProcessStandardDebug + 'static>
496{
497    /// Client to notify as processes are loaded and process loading finishes after boot.
498    boot_client: OptionalCell<&'a dyn ProcessLoadingAsyncClient>,
499    /// Client to notify as processes are loaded and process loading finishes during runtime.
500    runtime_client: OptionalCell<&'a dyn ProcessLoadingAsyncClient>,
501    /// Machine to use to check process credentials.
502    checker: &'static ProcessCheckerMachine,
503    /// Array of stored process references for loaded processes.
504    procs: MapCell<&'static mut [Option<&'static dyn Process>]>,
505    /// Array to store `ProcessBinary`s after checking credentials.
506    proc_binaries: MapCell<&'static mut [Option<ProcessBinary>]>,
507    /// Total available flash for process binaries on this board.
508    flash_bank: Cell<&'static [u8]>,
509    /// Flash memory region to load processes from.
510    flash: Cell<&'static [u8]>,
511    /// Memory available to assign to applications.
512    app_memory: Cell<&'static mut [u8]>,
513    /// Mechanism for generating async callbacks.
514    deferred_call: DeferredCall,
515    /// Reference to the kernel object for creating Processes.
516    kernel: &'static Kernel,
517    /// Reference to the Chip object for creating Processes.
518    chip: &'static C,
519    /// The policy to use when determining ShortIds and process uniqueness.
520    policy: OptionalCell<&'a dyn AppIdPolicy>,
521    /// The fault policy to assign to each created Process.
522    fault_policy: &'static dyn ProcessFaultPolicy,
523    /// The storage permissions policy to assign to each created Process.
524    storage_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
525    /// Current mode of the loading machine.
526    state: OptionalCell<SequentialProcessLoaderMachineState>,
527    /// Current operating mode of the loading machine.
528    run_mode: OptionalCell<SequentialProcessLoaderMachineRunMode>,
529}
530
531impl<'a, C: Chip, D: ProcessStandardDebug> SequentialProcessLoaderMachine<'a, C, D> {
532    /// This function is made `pub` so that board files can use it, but loading
533    /// processes from slices of flash an memory is fundamentally unsafe.
534    /// Therefore, we require the `ProcessManagementCapability` to call this
535    /// function.
536    pub fn new(
537        checker: &'static ProcessCheckerMachine,
538        procs: &'static mut [Option<&'static dyn Process>],
539        proc_binaries: &'static mut [Option<ProcessBinary>],
540        kernel: &'static Kernel,
541        chip: &'static C,
542        flash: &'static [u8],
543        app_memory: &'static mut [u8],
544        fault_policy: &'static dyn ProcessFaultPolicy,
545        storage_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
546        policy: &'static dyn AppIdPolicy,
547        _capability_management: &dyn ProcessManagementCapability,
548    ) -> Self {
549        Self {
550            deferred_call: DeferredCall::new(),
551            checker,
552            boot_client: OptionalCell::empty(),
553            runtime_client: OptionalCell::empty(),
554            run_mode: OptionalCell::empty(),
555            procs: MapCell::new(procs),
556            proc_binaries: MapCell::new(proc_binaries),
557            kernel,
558            chip,
559            flash_bank: Cell::new(flash),
560            flash: Cell::new(flash),
561            app_memory: Cell::new(app_memory),
562            policy: OptionalCell::new(policy),
563            fault_policy,
564            storage_policy,
565            state: OptionalCell::empty(),
566        }
567    }
568
569    /// Set the runtime client to receive callbacks about process loading and when
570    /// process loading has finished.
571    pub fn set_runtime_client(&self, client: &'a dyn ProcessLoadingAsyncClient) {
572        self.runtime_client.set(client);
573    }
574
575    /// Find the current active client based on the operation mode.
576    fn get_current_client(&self) -> Option<&dyn ProcessLoadingAsyncClient> {
577        match self.run_mode.get()? {
578            SequentialProcessLoaderMachineRunMode::BootMode => self.boot_client.get(),
579            SequentialProcessLoaderMachineRunMode::RuntimeMode => self.runtime_client.get(),
580        }
581    }
582
583    /// Find a slot in the `PROCESSES` array to store this process.
584    fn find_open_process_slot(&self) -> Option<usize> {
585        self.procs.map_or(None, |procs| {
586            for (i, p) in procs.iter().enumerate() {
587                if p.is_none() {
588                    return Some(i);
589                }
590            }
591            None
592        })
593    }
594
595    /// Find a slot in the `PROCESS_BINARIES` array to store this process.
596    fn find_open_process_binary_slot(&self) -> Option<usize> {
597        self.proc_binaries.map_or(None, |proc_bins| {
598            for (i, p) in proc_bins.iter().enumerate() {
599                if p.is_none() {
600                    return Some(i);
601                }
602            }
603            None
604        })
605    }
606
607    fn load_and_check(&self) {
608        let ret = self.discover_process_binary();
609        match ret {
610            Ok(pb) => match self.checker.check(pb) {
611                Ok(()) => {}
612                Err(e) => {
613                    self.get_current_client().map(|client| {
614                        client.process_loaded(Err(ProcessLoadError::CheckError(e)));
615                    });
616                }
617            },
618            Err(ProcessBinaryError::NotEnoughFlash)
619            | Err(ProcessBinaryError::TbfHeaderNotFound) => {
620                // These two errors occur when there are no more app binaries in
621                // flash. Now we can move to actually loading process binaries
622                // into full processes.
623
624                self.state
625                    .set(SequentialProcessLoaderMachineState::LoadProcesses);
626                self.deferred_call.set();
627            }
628            Err(e) => {
629                if config::CONFIG.debug_load_processes {
630                    debug!("Loading: unable to create ProcessBinary: {:?}", e);
631                }
632
633                // Other process binary errors indicate the process is not
634                // compatible. Signal error and try the next item in flash.
635                self.get_current_client().map(|client| {
636                    client.process_loaded(Err(ProcessLoadError::BinaryError(e)));
637                });
638
639                self.deferred_call.set();
640            }
641        }
642    }
643
644    /// Try to parse a process binary from flash.
645    ///
646    /// Returns the process binary object or an error if a valid process
647    /// binary could not be extracted.
648    fn discover_process_binary(&self) -> Result<ProcessBinary, ProcessBinaryError> {
649        let flash = self.flash.get();
650
651        if config::CONFIG.debug_load_processes {
652            debug!(
653                "Looking for process binary in flash={:#010X}-{:#010X}",
654                flash.as_ptr() as usize,
655                flash.as_ptr() as usize + flash.len() - 1
656            );
657        }
658
659        // If this fails, not enough remaining flash to check for an app.
660        let test_header_slice = flash.get(0..8).ok_or(ProcessBinaryError::NotEnoughFlash)?;
661
662        // Pass the first eight bytes to tbfheader to parse out the length of
663        // the tbf header and app. We then use those values to see if we have
664        // enough flash remaining to parse the remainder of the header.
665        //
666        // Start by converting [u8] to [u8; 8].
667        let header = test_header_slice
668            .try_into()
669            .or(Err(ProcessBinaryError::NotEnoughFlash))?;
670
671        let (version, header_length, app_length) =
672            match tock_tbf::parse::parse_tbf_header_lengths(header) {
673                Ok((v, hl, el)) => (v, hl, el),
674                Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(app_length)) => {
675                    // If we could not parse the header, then we want to skip over
676                    // this app and look for the next one.
677                    (0, 0, app_length)
678                }
679                Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
680                    // Since Tock apps use a linked list, it is very possible the
681                    // header we started to parse is intentionally invalid to signal
682                    // the end of apps. This is ok and just means we have finished
683                    // loading apps.
684                    return Err(ProcessBinaryError::TbfHeaderNotFound);
685                }
686            };
687
688        // Now we can get a slice which only encompasses the length of flash
689        // described by this tbf header.  We will either parse this as an actual
690        // app, or skip over this region.
691        let app_flash = flash
692            .get(0..app_length as usize)
693            .ok_or(ProcessBinaryError::NotEnoughFlash)?;
694
695        // Advance the flash slice for process discovery beyond this last entry.
696        // This will be the start of where we look for a new process since Tock
697        // processes are allocated back-to-back in flash.
698        let remaining_flash = flash
699            .get(app_flash.len()..)
700            .ok_or(ProcessBinaryError::NotEnoughFlash)?;
701        self.flash.set(remaining_flash);
702
703        let pb = ProcessBinary::create(app_flash, header_length as usize, version, true)?;
704
705        Ok(pb)
706    }
707
708    /// Create process objects from the discovered process binaries.
709    ///
710    /// This verifies that the discovered processes are valid to run.
711    fn load_process_objects(&self) -> Result<(), ()> {
712        let proc_binaries = self.proc_binaries.take().ok_or(())?;
713        let proc_binaries_len = proc_binaries.len();
714
715        // Iterate all process binary entries.
716        for i in 0..proc_binaries_len {
717            // We are either going to load this process binary or discard it, so
718            // we can use `take()` here.
719            if let Some(process_binary) = proc_binaries[i].take() {
720                // We assume the process can be loaded. This is not the case
721                // if there is a conflicting process.
722                let mut ok_to_load = true;
723
724                // Start by iterating all other process binaries and seeing
725                // if any are in conflict (same AppID with newer version).
726                for proc_bin in proc_binaries.iter() {
727                    match proc_bin {
728                        Some(other_process_binary) => {
729                            let blocked = self
730                                .is_blocked_from_loading_by(&process_binary, other_process_binary);
731
732                            if blocked {
733                                ok_to_load = false;
734                                break;
735                            }
736                        }
737                        None => {}
738                    }
739                }
740
741                // Go to next ProcessBinary if we cannot load this process.
742                if !ok_to_load {
743                    continue;
744                }
745
746                // Now scan the already loaded processes and make sure this
747                // doesn't conflict with any of those. Since those processes
748                // are already loaded, we just need to check if this process
749                // binary has the same AppID as an already loaded process.
750                self.procs.map(|procs| {
751                    for proc in procs.iter() {
752                        match proc {
753                            Some(p) => {
754                                let blocked =
755                                    self.is_blocked_from_loading_by_process(&process_binary, *p);
756
757                                if blocked {
758                                    ok_to_load = false;
759                                    break;
760                                }
761                            }
762                            None => {}
763                        }
764                    }
765                });
766
767                if !ok_to_load {
768                    continue;
769                }
770
771                // If we get here it is ok to load the process.
772                match self.find_open_process_slot() {
773                    Some(index) => {
774                        // Calculate the ShortId for this new process.
775                        let short_app_id = self.policy.map_or(ShortId::LocallyUnique, |policy| {
776                            policy.to_short_id(&process_binary)
777                        });
778
779                        // Try to create a `Process` object.
780                        let load_result = load_process(
781                            self.kernel,
782                            self.chip,
783                            process_binary,
784                            self.app_memory.take(),
785                            short_app_id,
786                            index,
787                            self.fault_policy,
788                            self.storage_policy,
789                        );
790                        match load_result {
791                            Ok((new_mem, proc)) => {
792                                self.app_memory.set(new_mem);
793                                match proc {
794                                    Some(p) => {
795                                        if config::CONFIG.debug_load_processes {
796                                            debug!(
797                                                "Loading: Loaded process {}",
798                                                p.get_process_name()
799                                            )
800                                        }
801
802                                        // Store the `ProcessStandard` object in the `PROCESSES`
803                                        // array.
804                                        self.procs.map(|procs| {
805                                            procs[index] = proc;
806                                        });
807                                        // Notify the client the process was loaded
808                                        // successfully.
809                                        self.get_current_client().map(|client| {
810                                            client.process_loaded(Ok(()));
811                                        });
812                                    }
813                                    None => {
814                                        if config::CONFIG.debug_load_processes {
815                                            debug!("No process loaded.");
816                                        }
817                                    }
818                                }
819                            }
820                            Err((new_mem, err)) => {
821                                self.app_memory.set(new_mem);
822                                if config::CONFIG.debug_load_processes {
823                                    debug!("Could not load process: {:?}.", err);
824                                }
825                                self.get_current_client().map(|client| {
826                                    client.process_loaded(Err(err));
827                                });
828                            }
829                        }
830                    }
831                    None => {
832                        // Nowhere to store the process.
833                        self.get_current_client().map(|client| {
834                            client.process_loaded(Err(ProcessLoadError::NoProcessSlot));
835                        });
836                    }
837                }
838            }
839        }
840        self.proc_binaries.put(proc_binaries);
841
842        // We have iterated all discovered `ProcessBinary`s and loaded what we
843        // could so now we can signal that process loading is finished.
844        self.get_current_client().map(|client| {
845            client.process_loading_finished();
846        });
847
848        self.state.clear();
849        Ok(())
850    }
851
852    /// Check if `pb1` is blocked from running by `pb2`.
853    ///
854    /// `pb2` blocks `pb1` if:
855    ///
856    /// - They both have the same AppID or they both have the same ShortId, and
857    /// - `pb2` has a higher version number.
858    fn is_blocked_from_loading_by(&self, pb1: &ProcessBinary, pb2: &ProcessBinary) -> bool {
859        let same_app_id = self
860            .policy
861            .map_or(false, |policy| !policy.different_identifier(pb1, pb2));
862        let same_short_app_id = self.policy.map_or(false, |policy| {
863            policy.to_short_id(pb1) == policy.to_short_id(pb2)
864        });
865        let other_newer = pb2.header.get_binary_version() > pb1.header.get_binary_version();
866
867        let blocks = (same_app_id || same_short_app_id) && other_newer;
868
869        if config::CONFIG.debug_process_credentials {
870            debug!(
871                "Loading: ProcessBinary {}({:#02x}) does{} block {}({:#02x})",
872                pb2.header.get_package_name().unwrap_or(""),
873                pb2.flash.as_ptr() as usize,
874                if blocks { " not" } else { "" },
875                pb1.header.get_package_name().unwrap_or(""),
876                pb1.flash.as_ptr() as usize,
877            );
878        }
879
880        blocks
881    }
882
883    /// Check if `pb` is blocked from running by `process`.
884    ///
885    /// `process` blocks `pb` if:
886    ///
887    /// - They both have the same AppID, or
888    /// - They both have the same ShortId
889    ///
890    /// Since `process` is already loaded, we only have to enforce the AppID and
891    /// ShortId uniqueness guarantees.
892    fn is_blocked_from_loading_by_process(
893        &self,
894        pb: &ProcessBinary,
895        process: &dyn Process,
896    ) -> bool {
897        let same_app_id = self.policy.map_or(false, |policy| {
898            !policy.different_identifier_process(pb, process)
899        });
900        let same_short_app_id = self.policy.map_or(false, |policy| {
901            policy.to_short_id(pb) == process.short_app_id()
902        });
903
904        let blocks = same_app_id || same_short_app_id;
905
906        if config::CONFIG.debug_process_credentials {
907            debug!(
908                "Loading: Process {}({:#02x}) does{} block {}({:#02x})",
909                process.get_process_name(),
910                process.get_addresses().flash_start,
911                if blocks { " not" } else { "" },
912                pb.header.get_package_name().unwrap_or(""),
913                pb.flash.as_ptr() as usize,
914            );
915        }
916
917        blocks
918    }
919
920    ////////////////////////////////////////////////////////////////////////////////
921    // DYNAMIC PROCESS LOADING HELPERS
922    ////////////////////////////////////////////////////////////////////////////////
923
924    /// Scan the entire flash to populate lists of existing binaries addresses.
925    fn scan_flash_for_process_binaries(
926        &self,
927        flash: &'static [u8],
928        process_binaries_start_addresses: &mut [usize],
929        process_binaries_end_addresses: &mut [usize],
930    ) -> Result<(), ()> {
931        fn inner_function(
932            flash: &'static [u8],
933            process_binaries_start_addresses: &mut [usize],
934            process_binaries_end_addresses: &mut [usize],
935        ) -> Result<(), ProcessBinaryError> {
936            let flash_end = flash.as_ptr() as usize + flash.len() - 1;
937            let mut addresses = flash.as_ptr() as usize;
938            let mut index: usize = 0;
939
940            while addresses < flash_end {
941                let flash_offset = addresses - flash.as_ptr() as usize;
942
943                let test_header_slice = flash
944                    .get(flash_offset..flash_offset + 8)
945                    .ok_or(ProcessBinaryError::NotEnoughFlash)?;
946
947                let header = test_header_slice
948                    .try_into()
949                    .or(Err(ProcessBinaryError::NotEnoughFlash))?;
950
951                let (_version, header_length, app_length) =
952                    match tock_tbf::parse::parse_tbf_header_lengths(header) {
953                        Ok((v, hl, el)) => (v, hl, el),
954                        Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(app_length)) => {
955                            (0, 0, app_length)
956                        }
957                        Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
958                            return Ok(());
959                        }
960                    };
961
962                let app_flash = flash
963                    .get(flash_offset..flash_offset + app_length as usize)
964                    .ok_or(ProcessBinaryError::NotEnoughFlash)?;
965
966                let app_header = flash
967                    .get(flash_offset..flash_offset + header_length as usize)
968                    .ok_or(ProcessBinaryError::NotEnoughFlash)?;
969
970                let remaining_flash = flash
971                    .get(flash_offset + app_flash.len()..)
972                    .ok_or(ProcessBinaryError::NotEnoughFlash)?;
973
974                // Get the rest of the header. The `remaining_header` variable
975                // will continue to hold the remainder of the header we have
976                // not processed.
977                let remaining_header = app_header
978                    .get(16..)
979                    .ok_or(ProcessBinaryError::NotEnoughFlash)?;
980
981                if remaining_header.len() == 0 {
982                    // This is a padding app.
983                    if config::CONFIG.debug_load_processes {
984                        debug!("Is padding!");
985                    }
986                } else {
987                    // This is an app binary, add it to the pb arrays.
988                    process_binaries_start_addresses[index] = app_flash.as_ptr() as usize;
989                    process_binaries_end_addresses[index] =
990                        app_flash.as_ptr() as usize + app_length as usize;
991
992                    if config::CONFIG.debug_load_processes {
993                        debug!(
994                            "[Metadata] Process binary start address at index {}: {:#010x}, with end_address {:#010x}",
995                            index,
996                            process_binaries_start_addresses[index],
997                            process_binaries_end_addresses[index]
998                        );
999                    }
1000                    index += 1;
1001                    if index > process_binaries_start_addresses.len() - 1 {
1002                        return Err(ProcessBinaryError::NotEnoughFlash);
1003                    }
1004                }
1005                addresses = remaining_flash.as_ptr() as usize;
1006            }
1007
1008            Ok(())
1009        }
1010
1011        inner_function(
1012            flash,
1013            process_binaries_start_addresses,
1014            process_binaries_end_addresses,
1015        )
1016        .or(Err(()))
1017    }
1018
1019    /// Helper function to find the next potential aligned address for the
1020    /// new app with size `app_length` assuming Cortex-M alignment rules.
1021    fn find_next_cortex_m_aligned_address(&self, address: usize, app_length: usize) -> usize {
1022        let remaining = address % app_length;
1023        if remaining == 0 {
1024            address
1025        } else {
1026            address + (app_length - remaining)
1027        }
1028    }
1029
1030    /// Function to compute the address for a new app with size `app_size`.
1031    fn compute_new_process_binary_address(
1032        &self,
1033        app_size: usize,
1034        process_binaries_start_addresses: &mut [usize],
1035        process_binaries_end_addresses: &mut [usize],
1036    ) -> usize {
1037        let mut start_count = 0;
1038        let mut end_count = 0;
1039
1040        // Remove zeros from addresses in place.
1041        for i in 0..process_binaries_start_addresses.len() {
1042            if process_binaries_start_addresses[i] != 0 {
1043                process_binaries_start_addresses[start_count] = process_binaries_start_addresses[i];
1044                start_count += 1;
1045            }
1046        }
1047
1048        for i in 0..process_binaries_end_addresses.len() {
1049            if process_binaries_end_addresses[i] != 0 {
1050                process_binaries_end_addresses[end_count] = process_binaries_end_addresses[i];
1051                end_count += 1;
1052            }
1053        }
1054
1055        // If there is only one application in flash:
1056        if start_count == 1 {
1057            let potential_address = self
1058                .find_next_cortex_m_aligned_address(process_binaries_end_addresses[0], app_size);
1059            return potential_address;
1060        }
1061
1062        // Otherwise, iterate through the sorted start and end addresses to find gaps for the new app.
1063        for i in 0..start_count - 1 {
1064            let gap_start = process_binaries_end_addresses[i];
1065            let gap_end = process_binaries_start_addresses[i + 1];
1066
1067            // Ensure gap_end is valid (skip zeros - these indicate there are no process binaries).
1068            if gap_end == 0 {
1069                continue;
1070            }
1071
1072            // If there is a valid gap, i.e., (gap_end > gap_start), check alignment.
1073            if gap_end > gap_start {
1074                let potential_address =
1075                    self.find_next_cortex_m_aligned_address(gap_start, app_size);
1076                if potential_address + app_size < gap_end {
1077                    return potential_address;
1078                }
1079            }
1080        }
1081        // If no gaps found, check after the last app.
1082        let last_app_end_address = process_binaries_end_addresses[end_count - 1];
1083        let potential_address =
1084            self.find_next_cortex_m_aligned_address(last_app_end_address, app_size);
1085        potential_address
1086    }
1087
1088    /// This function checks if there is a need to pad either before or after
1089    /// the new app to preserve the linked list.
1090    ///
1091    /// When do we pad?
1092    ///
1093    /// 1. When there is a binary  located in flash after the new app but
1094    ///    not immediately after, we need to add padding between the new
1095    ///    app and the existing app.
1096    /// 2. Due to MPU alignment, the new app may be similarly placed not
1097    ///    immediately after an existing process, in that case, we need to add
1098    ///    padding between the previous app and the new app.
1099    /// 3. If both the above conditions are met, we add both a prepadding and a
1100    ///    postpadding.
1101    /// 4. If either of these conditions are not met, we don't pad.
1102    ///
1103    /// Change checks against process binaries instead of processes?
1104    fn compute_padding_requirement_and_neighbors(
1105        &self,
1106        new_app_start_address: usize,
1107        app_length: usize,
1108        process_binaries_start_addresses: &[usize],
1109        process_binaries_end_addresses: &[usize],
1110    ) -> (PaddingRequirement, usize, usize) {
1111        // The end address of our newly loaded application.
1112        let new_app_end_address = new_app_start_address + app_length;
1113        // To store the address until which we need to write the padding app.
1114        let mut next_app_start_addr = 0;
1115        // To store the address from which we need to write the padding app.
1116        let mut previous_app_end_addr = 0;
1117        let mut padding_requirement: PaddingRequirement = PaddingRequirement::None;
1118
1119        // We compute the closest neighbor to our app such that:
1120        //
1121        // 1. If the new app is placed in between two existing binaries, we
1122        //    compute the closest located binaries.
1123        // 2. Once we compute these values, we determine if we need to write a
1124        //    pre pad header, or a post pad header, or both.
1125        // 3. If there are no apps after ours in the process binary array, we don't
1126        //    do anything.
1127
1128        // Postpad requirement.
1129        if let Some(next_closest_neighbor) = process_binaries_start_addresses
1130            .iter()
1131            .filter(|&&x| x > new_app_end_address - 1)
1132            .min()
1133        {
1134            // We found the next closest app in flash.
1135            next_app_start_addr = *next_closest_neighbor;
1136            if next_app_start_addr != 0 {
1137                padding_requirement = PaddingRequirement::PostPad;
1138            }
1139        } else {
1140            if config::CONFIG.debug_load_processes {
1141                debug!("No App Found after the new app so not adding post padding.");
1142            }
1143        }
1144
1145        // Prepad requirement.
1146        if let Some(previous_closest_neighbor) = process_binaries_end_addresses
1147            .iter()
1148            .filter(|&&x| x < new_app_start_address + 1)
1149            .max()
1150        {
1151            // We found the previous closest app in flash.
1152            previous_app_end_addr = *previous_closest_neighbor;
1153            if new_app_start_address - previous_app_end_addr != 0 {
1154                if padding_requirement == PaddingRequirement::PostPad {
1155                    padding_requirement = PaddingRequirement::PreAndPostPad;
1156                } else {
1157                    padding_requirement = PaddingRequirement::PrePad;
1158                }
1159            }
1160        } else {
1161            if config::CONFIG.debug_load_processes {
1162                debug!("No Previous App Found, so not padding before the new app.");
1163            }
1164        }
1165        (
1166            padding_requirement,
1167            previous_app_end_addr,
1168            next_app_start_addr,
1169        )
1170    }
1171
1172    /// This function scans flash, checks for, and returns an address that follows alignment rules given
1173    /// an app size of `new_app_size`.
1174    fn check_flash_for_valid_address(
1175        &self,
1176        new_app_size: usize,
1177        pb_start_address: &mut [usize],
1178        pb_end_address: &mut [usize],
1179    ) -> Result<usize, ProcessBinaryError> {
1180        let total_flash = self.flash_bank.get();
1181        let total_flash_start = total_flash.as_ptr() as usize;
1182        let total_flash_end = total_flash_start + total_flash.len() - 1;
1183
1184        match self.scan_flash_for_process_binaries(total_flash, pb_start_address, pb_end_address) {
1185            Ok(()) => {
1186                if config::CONFIG.debug_load_processes {
1187                    debug!("Successfully scanned flash");
1188                }
1189                let new_app_address = self.compute_new_process_binary_address(
1190                    new_app_size,
1191                    pb_start_address,
1192                    pb_end_address,
1193                );
1194                if new_app_address + new_app_size - 1 > total_flash_end {
1195                    Err(ProcessBinaryError::NotEnoughFlash)
1196                } else {
1197                    Ok(new_app_address)
1198                }
1199            }
1200            Err(()) => Err(ProcessBinaryError::NotEnoughFlash),
1201        }
1202    }
1203
1204    /// Function to check if the object with address `offset` of size `length` lies
1205    /// within flash bounds.
1206    pub fn check_if_within_flash_bounds(&self, offset: usize, length: usize) -> bool {
1207        let flash = self.flash_bank.get();
1208        let flash_end = flash.as_ptr() as usize + flash.len() - 1;
1209
1210        (flash_end - offset) >= length
1211    }
1212
1213    /// Function to compute an available address for the new application binary.
1214    pub fn check_flash_for_new_address(
1215        &self,
1216        new_app_size: usize,
1217    ) -> Result<(usize, PaddingRequirement, usize, usize), ProcessBinaryError> {
1218        const MAX_PROCS: usize = 10;
1219        let mut pb_start_address: [usize; MAX_PROCS] = [0; MAX_PROCS];
1220        let mut pb_end_address: [usize; MAX_PROCS] = [0; MAX_PROCS];
1221        match self.check_flash_for_valid_address(
1222            new_app_size,
1223            &mut pb_start_address,
1224            &mut pb_end_address,
1225        ) {
1226            Ok(app_address) => {
1227                let (pr, prev_app_addr, next_app_addr) = self
1228                    .compute_padding_requirement_and_neighbors(
1229                        app_address,
1230                        new_app_size,
1231                        &pb_start_address,
1232                        &pb_end_address,
1233                    );
1234                let (padding_requirement, previous_app_end_addr, next_app_start_addr) =
1235                    (pr, prev_app_addr, next_app_addr);
1236                Ok((
1237                    app_address,
1238                    padding_requirement,
1239                    previous_app_end_addr,
1240                    next_app_start_addr,
1241                ))
1242            }
1243            Err(e) => Err(e),
1244        }
1245    }
1246
1247    /// Function to check if the app binary at address `app_address` is valid.
1248    fn check_new_binary_validity(&self, app_address: usize) -> bool {
1249        let flash = self.flash_bank.get();
1250        // Pass the first eight bytes of the tbfheader to parse out the
1251        // length of the tbf header and app. We then use those values to see
1252        // if we have enough flash remaining to parse the remainder of the
1253        // header.
1254        let binary_header = match flash.get(app_address..app_address + 8) {
1255            Some(slice) if slice.len() == 8 => slice,
1256            _ => return false, // Ensure exactly 8 bytes are available
1257        };
1258
1259        let binary_header_array: &[u8; 8] = match binary_header.try_into() {
1260            Ok(arr) => arr,
1261            Err(_) => return false,
1262        };
1263
1264        match tock_tbf::parse::parse_tbf_header_lengths(binary_header_array) {
1265            Ok((_version, _header_length, _entry_length)) => true,
1266            Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(_entry_length)) => false,
1267            Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => false,
1268        }
1269    }
1270
1271    /// Function to start loading the new application at address `app_address` with size
1272    /// `app_size`.
1273    pub fn load_new_process_binary(
1274        &self,
1275        app_address: usize,
1276        app_size: usize,
1277    ) -> Result<(), ProcessLoadError> {
1278        let flash = self.flash_bank.get();
1279        let process_address = app_address - flash.as_ptr() as usize;
1280        let process_flash = flash.get(process_address..process_address + app_size);
1281        let result = self.check_new_binary_validity(process_address);
1282        match result {
1283            true => {
1284                if let Some(flash) = process_flash {
1285                    self.flash.set(flash);
1286                } else {
1287                    return Err(ProcessLoadError::BinaryError(
1288                        ProcessBinaryError::TbfHeaderNotFound,
1289                    ));
1290                }
1291
1292                self.state
1293                    .set(SequentialProcessLoaderMachineState::DiscoverProcessBinaries);
1294
1295                self.run_mode
1296                    .set(SequentialProcessLoaderMachineRunMode::RuntimeMode);
1297                // Start an asynchronous flow so we can issue a callback on error.
1298                self.deferred_call.set();
1299
1300                Ok(())
1301            }
1302            false => Err(ProcessLoadError::BinaryError(
1303                ProcessBinaryError::TbfHeaderNotFound,
1304            )),
1305        }
1306    }
1307}
1308
1309impl<'a, C: Chip, D: ProcessStandardDebug> ProcessLoadingAsync<'a>
1310    for SequentialProcessLoaderMachine<'a, C, D>
1311{
1312    fn set_client(&self, client: &'a dyn ProcessLoadingAsyncClient) {
1313        self.boot_client.set(client);
1314    }
1315
1316    fn set_policy(&self, policy: &'a dyn AppIdPolicy) {
1317        self.policy.replace(policy);
1318    }
1319
1320    fn start(&self) {
1321        self.state
1322            .set(SequentialProcessLoaderMachineState::DiscoverProcessBinaries);
1323        self.run_mode
1324            .set(SequentialProcessLoaderMachineRunMode::BootMode);
1325        // Start an asynchronous flow so we can issue a callback on error.
1326        self.deferred_call.set();
1327    }
1328}
1329
1330impl<C: Chip, D: ProcessStandardDebug> DeferredCallClient
1331    for SequentialProcessLoaderMachine<'_, C, D>
1332{
1333    fn handle_deferred_call(&self) {
1334        // We use deferred calls to start the operation in the async loop.
1335        match self.state.get() {
1336            Some(SequentialProcessLoaderMachineState::DiscoverProcessBinaries) => {
1337                self.load_and_check();
1338            }
1339            Some(SequentialProcessLoaderMachineState::LoadProcesses) => {
1340                let ret = self.load_process_objects();
1341                match ret {
1342                    Ok(()) => {}
1343                    Err(()) => {
1344                        // If this failed for some reason, we still need to
1345                        // signal that process loading has finished.
1346                        self.get_current_client().map(|client| {
1347                            client.process_loading_finished();
1348                        });
1349                    }
1350                }
1351            }
1352            None => {}
1353        }
1354    }
1355
1356    fn register(&'static self) {
1357        self.deferred_call.register(self);
1358    }
1359}
1360
1361impl<C: Chip, D: ProcessStandardDebug> crate::process_checker::ProcessCheckerMachineClient
1362    for SequentialProcessLoaderMachine<'_, C, D>
1363{
1364    fn done(
1365        &self,
1366        process_binary: ProcessBinary,
1367        result: Result<Option<AcceptedCredential>, crate::process_checker::ProcessCheckError>,
1368    ) {
1369        // Check if this process was approved by the checker.
1370        match result {
1371            Ok(optional_credential) => {
1372                if config::CONFIG.debug_load_processes {
1373                    debug!(
1374                        "Loading: Check succeeded for process {}",
1375                        process_binary.header.get_package_name().unwrap_or("")
1376                    );
1377                }
1378                // Save the checked process binary now that we know it is valid.
1379                match self.find_open_process_binary_slot() {
1380                    Some(index) => {
1381                        self.proc_binaries.map(|proc_binaries| {
1382                            process_binary.credential.insert(optional_credential);
1383                            proc_binaries[index] = Some(process_binary);
1384                        });
1385                    }
1386                    None => {
1387                        self.get_current_client().map(|client| {
1388                            client.process_loaded(Err(ProcessLoadError::NoProcessSlot));
1389                        });
1390                    }
1391                }
1392            }
1393            Err(e) => {
1394                if config::CONFIG.debug_load_processes {
1395                    debug!(
1396                        "Loading: Process {} check failed {:?}",
1397                        process_binary.header.get_package_name().unwrap_or(""),
1398                        e
1399                    );
1400                }
1401                // Signal error and call try next
1402                self.get_current_client().map(|client| {
1403                    client.process_loaded(Err(ProcessLoadError::CheckError(e)));
1404                });
1405            }
1406        }
1407
1408        // Try to load the next process in flash.
1409        self.deferred_call.set();
1410    }
1411}