1use 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
34pub enum ProcessLoadError {
36 NotEnoughMemory,
40
41 MpuInvalidFlashLength,
45
46 MpuConfigurationError,
50
51 MemoryAddressMismatch {
55 actual_address: u32,
56 expected_address: u32,
57 },
58
59 NoProcessSlot,
61
62 BinaryError(ProcessBinaryError),
64
65 CheckError(ProcessCheckError),
67
68 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#[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#[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 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 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 continue;
277 }
278 }
279 }
280 }
281 }
282 Ok(())
283}
284
285fn 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 let test_header_slice = flash
304 .get(0..8)
305 .ok_or((flash, ProcessBinaryError::NotEnoughFlash))?;
306
307 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 (0, 0, app_length)
323 }
324 Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
325 return Err((flash, ProcessBinaryError::TbfHeaderNotFound));
330 }
331 };
332
333 let app_flash = flash
337 .get(0..app_length as usize)
338 .ok_or((flash, ProcessBinaryError::NotEnoughFlash))?;
339
340 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
353fn 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 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
419pub trait ProcessLoadingAsyncClient {
429 fn process_loaded(&self, result: Result<(), ProcessLoadError>);
432
433 fn process_loading_finished(&self);
435}
436
437pub trait ProcessLoadingAsync<'a> {
445 fn set_client(&self, client: &'a dyn ProcessLoadingAsyncClient);
448
449 fn set_policy(&self, policy: &'a dyn AppIdPolicy);
451
452 fn start(&self);
454}
455
456#[derive(Clone, Copy)]
458enum SequentialProcessLoaderMachineState {
459 DiscoverProcessBinaries,
461 LoadProcesses,
463}
464
465#[derive(Clone, Copy)]
472enum SequentialProcessLoaderMachineRunMode {
473 BootMode,
475 RuntimeMode,
477}
478
479#[derive(Clone, Copy, PartialEq, Default)]
481pub enum PaddingRequirement {
482 #[default]
483 None,
484 PrePad,
485 PostPad,
486 PreAndPostPad,
487}
488
489pub struct SequentialProcessLoaderMachine<'a, C: Chip + 'static, D: ProcessStandardDebug + 'static>
496{
497 boot_client: OptionalCell<&'a dyn ProcessLoadingAsyncClient>,
499 runtime_client: OptionalCell<&'a dyn ProcessLoadingAsyncClient>,
501 checker: &'static ProcessCheckerMachine,
503 procs: MapCell<&'static mut [Option<&'static dyn Process>]>,
505 proc_binaries: MapCell<&'static mut [Option<ProcessBinary>]>,
507 flash_bank: Cell<&'static [u8]>,
509 flash: Cell<&'static [u8]>,
511 app_memory: Cell<&'static mut [u8]>,
513 deferred_call: DeferredCall,
515 kernel: &'static Kernel,
517 chip: &'static C,
519 policy: OptionalCell<&'a dyn AppIdPolicy>,
521 fault_policy: &'static dyn ProcessFaultPolicy,
523 storage_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
525 state: OptionalCell<SequentialProcessLoaderMachineState>,
527 run_mode: OptionalCell<SequentialProcessLoaderMachineRunMode>,
529}
530
531impl<'a, C: Chip, D: ProcessStandardDebug> SequentialProcessLoaderMachine<'a, C, D> {
532 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 pub fn set_runtime_client(&self, client: &'a dyn ProcessLoadingAsyncClient) {
572 self.runtime_client.set(client);
573 }
574
575 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 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 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 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 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 fn discover_process_binary(&self) -> Result<ProcessBinary, ProcessBinaryError> {
649 let flash = self.flash.get();
650
651 match discover_process_binary(flash) {
652 Ok((remaining_flash, pb)) => {
653 self.flash.set(remaining_flash);
654 Ok(pb)
655 }
656
657 Err((remaining_flash, err)) => {
658 self.flash.set(remaining_flash);
659 Err(err)
660 }
661 }
662 }
663
664 fn load_process_objects(&self) -> Result<(), ()> {
668 let proc_binaries = self.proc_binaries.take().ok_or(())?;
669 let proc_binaries_len = proc_binaries.len();
670
671 for i in 0..proc_binaries_len {
673 if let Some(process_binary) = proc_binaries[i].take() {
676 let mut ok_to_load = true;
679
680 for proc_bin in proc_binaries.iter() {
683 match proc_bin {
684 Some(other_process_binary) => {
685 let blocked = self
686 .is_blocked_from_loading_by(&process_binary, other_process_binary);
687
688 if blocked {
689 ok_to_load = false;
690 break;
691 }
692 }
693 None => {}
694 }
695 }
696
697 if !ok_to_load {
699 continue;
700 }
701
702 self.procs.map(|procs| {
707 for proc in procs.iter() {
708 match proc {
709 Some(p) => {
710 let blocked =
711 self.is_blocked_from_loading_by_process(&process_binary, *p);
712
713 if blocked {
714 ok_to_load = false;
715 break;
716 }
717 }
718 None => {}
719 }
720 }
721 });
722
723 if !ok_to_load {
724 continue;
725 }
726
727 match self.find_open_process_slot() {
729 Some(index) => {
730 let short_app_id = self.policy.map_or(ShortId::LocallyUnique, |policy| {
732 policy.to_short_id(&process_binary)
733 });
734
735 let load_result = load_process(
737 self.kernel,
738 self.chip,
739 process_binary,
740 self.app_memory.take(),
741 short_app_id,
742 index,
743 self.fault_policy,
744 self.storage_policy,
745 );
746 match load_result {
747 Ok((new_mem, proc)) => {
748 self.app_memory.set(new_mem);
749 match proc {
750 Some(p) => {
751 if config::CONFIG.debug_load_processes {
752 debug!(
753 "Loading: Loaded process {}",
754 p.get_process_name()
755 )
756 }
757
758 self.procs.map(|procs| {
761 procs[index] = proc;
762 });
763 self.get_current_client().map(|client| {
766 client.process_loaded(Ok(()));
767 });
768 }
769 None => {
770 if config::CONFIG.debug_load_processes {
771 debug!("No process loaded.");
772 }
773 }
774 }
775 }
776 Err((new_mem, err)) => {
777 self.app_memory.set(new_mem);
778 if config::CONFIG.debug_load_processes {
779 debug!("Could not load process: {:?}.", err);
780 }
781 self.get_current_client().map(|client| {
782 client.process_loaded(Err(err));
783 });
784 }
785 }
786 }
787 None => {
788 self.get_current_client().map(|client| {
790 client.process_loaded(Err(ProcessLoadError::NoProcessSlot));
791 });
792 }
793 }
794 }
795 }
796 self.proc_binaries.put(proc_binaries);
797
798 self.get_current_client().map(|client| {
801 client.process_loading_finished();
802 });
803
804 self.state.clear();
805 Ok(())
806 }
807
808 fn is_blocked_from_loading_by(&self, pb1: &ProcessBinary, pb2: &ProcessBinary) -> bool {
815 let same_app_id = self
816 .policy
817 .map_or(false, |policy| !policy.different_identifier(pb1, pb2));
818 let same_short_app_id = self.policy.map_or(false, |policy| {
819 policy.to_short_id(pb1) == policy.to_short_id(pb2)
820 });
821 let other_newer = pb2.header.get_binary_version() > pb1.header.get_binary_version();
822
823 let blocks = (same_app_id || same_short_app_id) && other_newer;
824
825 if config::CONFIG.debug_process_credentials {
826 debug!(
827 "Loading: ProcessBinary {}({:#02x}) does{} block {}({:#02x})",
828 pb2.header.get_package_name().unwrap_or(""),
829 pb2.flash.as_ptr() as usize,
830 if blocks { " not" } else { "" },
831 pb1.header.get_package_name().unwrap_or(""),
832 pb1.flash.as_ptr() as usize,
833 );
834 }
835
836 blocks
837 }
838
839 fn is_blocked_from_loading_by_process(
849 &self,
850 pb: &ProcessBinary,
851 process: &dyn Process,
852 ) -> bool {
853 let same_app_id = self.policy.map_or(false, |policy| {
854 !policy.different_identifier_process(pb, process)
855 });
856 let same_short_app_id = self.policy.map_or(false, |policy| {
857 policy.to_short_id(pb) == process.short_app_id()
858 });
859
860 let blocks = same_app_id || same_short_app_id;
861
862 if config::CONFIG.debug_process_credentials {
863 debug!(
864 "Loading: Process {}({:#02x}) does{} block {}({:#02x})",
865 process.get_process_name(),
866 process.get_addresses().flash_start,
867 if blocks { " not" } else { "" },
868 pb.header.get_package_name().unwrap_or(""),
869 pb.flash.as_ptr() as usize,
870 );
871 }
872
873 blocks
874 }
875
876 fn scan_flash_for_process_binaries(
882 &self,
883 flash: &'static [u8],
884 process_binaries_start_addresses: &mut [usize],
885 process_binaries_end_addresses: &mut [usize],
886 ) -> Result<(), ()> {
887 fn inner_function(
888 flash: &'static [u8],
889 process_binaries_start_addresses: &mut [usize],
890 process_binaries_end_addresses: &mut [usize],
891 ) -> Result<(), ProcessBinaryError> {
892 let flash_end = flash.as_ptr() as usize + flash.len() - 1;
893 let mut addresses = flash.as_ptr() as usize;
894 let mut index: usize = 0;
895
896 while addresses < flash_end {
897 let flash_offset = addresses - flash.as_ptr() as usize;
898
899 let test_header_slice = flash
900 .get(flash_offset..flash_offset + 8)
901 .ok_or(ProcessBinaryError::NotEnoughFlash)?;
902
903 let header = test_header_slice
904 .try_into()
905 .or(Err(ProcessBinaryError::NotEnoughFlash))?;
906
907 let (_version, header_length, app_length) =
908 match tock_tbf::parse::parse_tbf_header_lengths(header) {
909 Ok((v, hl, el)) => (v, hl, el),
910 Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(app_length)) => {
911 (0, 0, app_length)
912 }
913 Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => {
914 return Ok(());
915 }
916 };
917
918 let app_flash = flash
919 .get(flash_offset..flash_offset + app_length as usize)
920 .ok_or(ProcessBinaryError::NotEnoughFlash)?;
921
922 let app_header = flash
923 .get(flash_offset..flash_offset + header_length as usize)
924 .ok_or(ProcessBinaryError::NotEnoughFlash)?;
925
926 let remaining_flash = flash
927 .get(flash_offset + app_flash.len()..)
928 .ok_or(ProcessBinaryError::NotEnoughFlash)?;
929
930 let remaining_header = app_header
934 .get(16..)
935 .ok_or(ProcessBinaryError::NotEnoughFlash)?;
936
937 if remaining_header.len() == 0 {
938 if config::CONFIG.debug_load_processes {
940 debug!("Is padding!");
941 }
942 } else {
943 process_binaries_start_addresses[index] = app_flash.as_ptr() as usize;
945 process_binaries_end_addresses[index] =
946 app_flash.as_ptr() as usize + app_length as usize;
947
948 if config::CONFIG.debug_load_processes {
949 debug!(
950 "[Metadata] Process binary start address at index {}: {:#010x}, with end_address {:#010x}",
951 index,
952 process_binaries_start_addresses[index],
953 process_binaries_end_addresses[index]
954 );
955 }
956 index += 1;
957 if index > process_binaries_start_addresses.len() - 1 {
958 return Err(ProcessBinaryError::NotEnoughFlash);
959 }
960 }
961 addresses = remaining_flash.as_ptr() as usize;
962 }
963
964 Ok(())
965 }
966
967 inner_function(
968 flash,
969 process_binaries_start_addresses,
970 process_binaries_end_addresses,
971 )
972 .or(Err(()))
973 }
974
975 fn find_next_cortex_m_aligned_address(&self, address: usize, app_length: usize) -> usize {
978 let remaining = address % app_length;
979 if remaining == 0 {
980 address
981 } else {
982 address + (app_length - remaining)
983 }
984 }
985
986 fn compute_new_process_binary_address(
988 &self,
989 app_size: usize,
990 process_binaries_start_addresses: &mut [usize],
991 process_binaries_end_addresses: &mut [usize],
992 ) -> usize {
993 let mut start_count = 0;
994 let mut end_count = 0;
995
996 for i in 0..process_binaries_start_addresses.len() {
998 if process_binaries_start_addresses[i] != 0 {
999 process_binaries_start_addresses[start_count] = process_binaries_start_addresses[i];
1000 start_count += 1;
1001 }
1002 }
1003
1004 for i in 0..process_binaries_end_addresses.len() {
1005 if process_binaries_end_addresses[i] != 0 {
1006 process_binaries_end_addresses[end_count] = process_binaries_end_addresses[i];
1007 end_count += 1;
1008 }
1009 }
1010
1011 if start_count == 1 {
1013 let potential_address = self
1014 .find_next_cortex_m_aligned_address(process_binaries_end_addresses[0], app_size);
1015 return potential_address;
1016 }
1017
1018 for i in 0..start_count - 1 {
1020 let gap_start = process_binaries_end_addresses[i];
1021 let gap_end = process_binaries_start_addresses[i + 1];
1022
1023 if gap_end == 0 {
1025 continue;
1026 }
1027
1028 if gap_end > gap_start {
1030 let potential_address =
1031 self.find_next_cortex_m_aligned_address(gap_start, app_size);
1032 if potential_address + app_size < gap_end {
1033 return potential_address;
1034 }
1035 }
1036 }
1037 let last_app_end_address = process_binaries_end_addresses[end_count - 1];
1039 let potential_address =
1040 self.find_next_cortex_m_aligned_address(last_app_end_address, app_size);
1041 potential_address
1042 }
1043
1044 fn compute_padding_requirement_and_neighbors(
1061 &self,
1062 new_app_start_address: usize,
1063 app_length: usize,
1064 process_binaries_start_addresses: &[usize],
1065 process_binaries_end_addresses: &[usize],
1066 ) -> (PaddingRequirement, usize, usize) {
1067 let new_app_end_address = new_app_start_address + app_length;
1069 let mut next_app_start_addr = 0;
1071 let mut previous_app_end_addr = 0;
1073 let mut padding_requirement: PaddingRequirement = PaddingRequirement::None;
1074
1075 if let Some(next_closest_neighbor) = process_binaries_start_addresses
1086 .iter()
1087 .filter(|&&x| x > new_app_end_address - 1)
1088 .min()
1089 {
1090 next_app_start_addr = *next_closest_neighbor;
1092 if next_app_start_addr != 0 {
1093 padding_requirement = PaddingRequirement::PostPad;
1094 }
1095 } else {
1096 if config::CONFIG.debug_load_processes {
1097 debug!("No App Found after the new app so not adding post padding.");
1098 }
1099 }
1100
1101 if let Some(previous_closest_neighbor) = process_binaries_end_addresses
1103 .iter()
1104 .filter(|&&x| x < new_app_start_address + 1)
1105 .max()
1106 {
1107 previous_app_end_addr = *previous_closest_neighbor;
1109 if new_app_start_address - previous_app_end_addr != 0 {
1110 if padding_requirement == PaddingRequirement::PostPad {
1111 padding_requirement = PaddingRequirement::PreAndPostPad;
1112 } else {
1113 padding_requirement = PaddingRequirement::PrePad;
1114 }
1115 }
1116 } else {
1117 if config::CONFIG.debug_load_processes {
1118 debug!("No Previous App Found, so not padding before the new app.");
1119 }
1120 }
1121 (
1122 padding_requirement,
1123 previous_app_end_addr,
1124 next_app_start_addr,
1125 )
1126 }
1127
1128 fn check_flash_for_valid_address(
1131 &self,
1132 new_app_size: usize,
1133 pb_start_address: &mut [usize],
1134 pb_end_address: &mut [usize],
1135 ) -> Result<usize, ProcessBinaryError> {
1136 let total_flash = self.flash_bank.get();
1137 let total_flash_start = total_flash.as_ptr() as usize;
1138 let total_flash_end = total_flash_start + total_flash.len() - 1;
1139
1140 match self.scan_flash_for_process_binaries(total_flash, pb_start_address, pb_end_address) {
1141 Ok(()) => {
1142 if config::CONFIG.debug_load_processes {
1143 debug!("Successfully scanned flash");
1144 }
1145 let new_app_address = self.compute_new_process_binary_address(
1146 new_app_size,
1147 pb_start_address,
1148 pb_end_address,
1149 );
1150 if new_app_address + new_app_size - 1 > total_flash_end {
1151 Err(ProcessBinaryError::NotEnoughFlash)
1152 } else {
1153 Ok(new_app_address)
1154 }
1155 }
1156 Err(()) => Err(ProcessBinaryError::NotEnoughFlash),
1157 }
1158 }
1159
1160 pub fn check_if_within_flash_bounds(&self, offset: usize, length: usize) -> bool {
1163 let flash = self.flash_bank.get();
1164 let flash_end = flash.as_ptr() as usize + flash.len() - 1;
1165
1166 (flash_end - offset) >= length
1167 }
1168
1169 pub fn check_flash_for_new_address(
1171 &self,
1172 new_app_size: usize,
1173 ) -> Result<(usize, PaddingRequirement, usize, usize), ProcessBinaryError> {
1174 const MAX_PROCS: usize = 10;
1175 let mut pb_start_address: [usize; MAX_PROCS] = [0; MAX_PROCS];
1176 let mut pb_end_address: [usize; MAX_PROCS] = [0; MAX_PROCS];
1177 match self.check_flash_for_valid_address(
1178 new_app_size,
1179 &mut pb_start_address,
1180 &mut pb_end_address,
1181 ) {
1182 Ok(app_address) => {
1183 let (pr, prev_app_addr, next_app_addr) = self
1184 .compute_padding_requirement_and_neighbors(
1185 app_address,
1186 new_app_size,
1187 &pb_start_address,
1188 &pb_end_address,
1189 );
1190 let (padding_requirement, previous_app_end_addr, next_app_start_addr) =
1191 (pr, prev_app_addr, next_app_addr);
1192 Ok((
1193 app_address,
1194 padding_requirement,
1195 previous_app_end_addr,
1196 next_app_start_addr,
1197 ))
1198 }
1199 Err(e) => Err(e),
1200 }
1201 }
1202
1203 fn check_new_binary_validity(&self, app_address: usize) -> bool {
1205 let flash = self.flash_bank.get();
1206 let binary_header = match flash.get(app_address..app_address + 8) {
1211 Some(slice) if slice.len() == 8 => slice,
1212 _ => return false, };
1214
1215 let binary_header_array: &[u8; 8] = match binary_header.try_into() {
1216 Ok(arr) => arr,
1217 Err(_) => return false,
1218 };
1219
1220 match tock_tbf::parse::parse_tbf_header_lengths(binary_header_array) {
1221 Ok((_version, _header_length, _entry_length)) => true,
1222 Err(tock_tbf::types::InitialTbfParseError::InvalidHeader(_entry_length)) => false,
1223 Err(tock_tbf::types::InitialTbfParseError::UnableToParse) => false,
1224 }
1225 }
1226
1227 pub fn load_new_process_binary(
1230 &self,
1231 app_address: usize,
1232 app_size: usize,
1233 ) -> Result<(), ProcessLoadError> {
1234 let flash = self.flash_bank.get();
1235 let process_address = app_address - flash.as_ptr() as usize;
1236 let process_flash = flash.get(process_address..process_address + app_size);
1237 let result = self.check_new_binary_validity(process_address);
1238 match result {
1239 true => {
1240 if let Some(flash) = process_flash {
1241 self.flash.set(flash);
1242 } else {
1243 return Err(ProcessLoadError::BinaryError(
1244 ProcessBinaryError::TbfHeaderNotFound,
1245 ));
1246 }
1247
1248 self.state
1249 .set(SequentialProcessLoaderMachineState::DiscoverProcessBinaries);
1250
1251 self.run_mode
1252 .set(SequentialProcessLoaderMachineRunMode::RuntimeMode);
1253 self.deferred_call.set();
1255
1256 Ok(())
1257 }
1258 false => Err(ProcessLoadError::BinaryError(
1259 ProcessBinaryError::TbfHeaderNotFound,
1260 )),
1261 }
1262 }
1263}
1264
1265impl<'a, C: Chip, D: ProcessStandardDebug> ProcessLoadingAsync<'a>
1266 for SequentialProcessLoaderMachine<'a, C, D>
1267{
1268 fn set_client(&self, client: &'a dyn ProcessLoadingAsyncClient) {
1269 self.boot_client.set(client);
1270 }
1271
1272 fn set_policy(&self, policy: &'a dyn AppIdPolicy) {
1273 self.policy.replace(policy);
1274 }
1275
1276 fn start(&self) {
1277 self.state
1278 .set(SequentialProcessLoaderMachineState::DiscoverProcessBinaries);
1279 self.run_mode
1280 .set(SequentialProcessLoaderMachineRunMode::BootMode);
1281 self.deferred_call.set();
1283 }
1284}
1285
1286impl<C: Chip, D: ProcessStandardDebug> DeferredCallClient
1287 for SequentialProcessLoaderMachine<'_, C, D>
1288{
1289 fn handle_deferred_call(&self) {
1290 match self.state.get() {
1292 Some(SequentialProcessLoaderMachineState::DiscoverProcessBinaries) => {
1293 self.load_and_check();
1294 }
1295 Some(SequentialProcessLoaderMachineState::LoadProcesses) => {
1296 let ret = self.load_process_objects();
1297 match ret {
1298 Ok(()) => {}
1299 Err(()) => {
1300 self.get_current_client().map(|client| {
1303 client.process_loading_finished();
1304 });
1305 }
1306 }
1307 }
1308 None => {}
1309 }
1310 }
1311
1312 fn register(&'static self) {
1313 self.deferred_call.register(self);
1314 }
1315}
1316
1317impl<C: Chip, D: ProcessStandardDebug> crate::process_checker::ProcessCheckerMachineClient
1318 for SequentialProcessLoaderMachine<'_, C, D>
1319{
1320 fn done(
1321 &self,
1322 process_binary: ProcessBinary,
1323 result: Result<Option<AcceptedCredential>, crate::process_checker::ProcessCheckError>,
1324 ) {
1325 match result {
1327 Ok(optional_credential) => {
1328 if config::CONFIG.debug_load_processes {
1329 debug!(
1330 "Loading: Check succeeded for process {}",
1331 process_binary.header.get_package_name().unwrap_or("")
1332 );
1333 }
1334 match self.find_open_process_binary_slot() {
1336 Some(index) => {
1337 self.proc_binaries.map(|proc_binaries| {
1338 process_binary.credential.insert(optional_credential);
1339 proc_binaries[index] = Some(process_binary);
1340 });
1341 }
1342 None => {
1343 self.get_current_client().map(|client| {
1344 client.process_loaded(Err(ProcessLoadError::NoProcessSlot));
1345 });
1346 }
1347 }
1348 }
1349 Err(e) => {
1350 if config::CONFIG.debug_load_processes {
1351 debug!(
1352 "Loading: Process {} check failed {:?}",
1353 process_binary.header.get_package_name().unwrap_or(""),
1354 e
1355 );
1356 }
1357 self.get_current_client().map(|client| {
1359 client.process_loaded(Err(ProcessLoadError::CheckError(e)));
1360 });
1361 }
1362 }
1363
1364 self.deferred_call.set();
1366 }
1367}