kernel/process_standard.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//! Tock default Process implementation.
6//!
7//! `ProcessStandard` is an implementation for a userspace process running on
8//! the Tock kernel.
9
10use core::cell::Cell;
11use core::cmp;
12use core::fmt::Write;
13use core::mem::MaybeUninit;
14use core::num::NonZeroU32;
15use core::ptr::NonNull;
16use core::{mem, ptr, slice, str};
17
18use crate::collections::queue::Queue;
19use crate::collections::ring_buffer::RingBuffer;
20use crate::config;
21use crate::debug;
22use crate::errorcode::ErrorCode;
23use crate::init_uninit_struct;
24use crate::kernel::Kernel;
25use crate::platform::chip::Chip;
26use crate::platform::mpu::{self, MPU};
27use crate::process::ProcessBinary;
28use crate::process::{BinaryVersion, ReturnArguments};
29use crate::process::{Error, FunctionCall, FunctionCallSource, Process, Task};
30use crate::process::{FaultAction, ProcessCustomGrantIdentifier, ProcessId};
31use crate::process::{ProcessAddresses, ProcessSizes, ShortId};
32use crate::process::{State, StoppedState};
33use crate::process_checker::AcceptedCredential;
34use crate::process_loading::ProcessLoadError;
35use crate::process_policies::ProcessFaultPolicy;
36use crate::process_policies::ProcessStandardStoragePermissionsPolicy;
37use crate::processbuffer::{ReadOnlyProcessBuffer, ReadWriteProcessBuffer};
38use crate::storage_permissions::StoragePermissions;
39use crate::syscall::{self, Syscall, SyscallReturn, UserspaceKernelBoundary};
40use crate::upcall::UpcallId;
41use crate::utilities::capability_ptr::{CapabilityPtr, CapabilityPtrPermissions};
42use crate::utilities::cells::{MapCell, NumericCellExt, OptionalCell};
43
44use tock_tbf::types::CommandPermissions;
45
46/// Gets a mutable (unique) reference to the contained value.
47///
48/// TODO: this is copied from the standard library, where it is available under
49/// the `maybe_uninit_slice` nightly feature. Remove and switch to the core
50/// library variant once that is stable.
51///
52/// # Safety
53///
54/// Calling this when the content is not yet fully initialized causes undefined
55/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in the
56/// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot
57/// be used to initialize a `MaybeUninit` slice.
58#[inline(always)]
59const unsafe fn maybe_uninit_slice_assume_init_mut<T>(src: &mut [MaybeUninit<T>]) -> &mut [T] {
60 // SAFETY: similar to safety notes for `slice_get_ref`, but we have a
61 // mutable reference which is also guaranteed to be valid for writes.
62 #[allow(clippy::ref_as_ptr)]
63 unsafe {
64 &mut *(src as *mut [MaybeUninit<T>] as *mut [T])
65 }
66}
67
68/// Divides one mutable raw slice into two at an index.
69///
70/// This method implementation is copied from the standard library, where it is
71/// available with `raw_slice_split` nightly feature. TODO: switch to the
72/// standard library function once that is stable.
73///
74/// The first will contain all indices from `[0, mid)` (excluding the index
75/// `mid` itself) and the second will contain all indices from `[mid, len)`
76/// (excluding the index `len` itself).
77///
78/// # Panics
79///
80/// Panics if `mid > len`.
81///
82/// # Safety
83///
84/// `mid` must be [in-bounds] of the underlying [allocation]. Which means
85/// `self` must be dereferenceable and span a single allocation that is at least
86/// `mid * size_of::<T>()` bytes long. Not upholding these requirements is
87/// *[undefined behavior]* even if the resulting pointers are not used.
88///
89/// Since `len` being in-bounds is not a safety invariant of `*mut [T]` the
90/// safety requirements of this method are the same as for
91/// [`split_at_mut_unchecked`]. The explicit bounds check is only as useful as
92/// `len` is correct.
93///
94/// [`split_at_mut_unchecked`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.split_at_mut_unchecked
95/// [in-bounds]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.add-1
96/// [allocation]: https://doc.rust-lang.org/stable/std/ptr/index.html#allocation
97/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
98unsafe fn raw_slice_split_at_mut<T>(slice: *mut [T], mid: usize) -> (*mut [T], *mut [T]) {
99 assert!(mid <= slice.len());
100
101 let len = slice.len();
102 let ptr = slice.cast::<T>();
103
104 // SAFETY: Caller must pass a valid pointer and an index that is in-bounds.
105 let tail = unsafe { ptr.add(mid) };
106 (
107 core::ptr::slice_from_raw_parts_mut(ptr, mid),
108 core::ptr::slice_from_raw_parts_mut(tail, len - mid),
109 )
110}
111
112/// Interface supported by [`ProcessStandard`] for recording debug information.
113///
114/// This trait provides flexibility to users of [`ProcessStandard`] to determine
115/// how debugging information should be recorded, or if debugging information
116/// should be recorded at all.
117///
118/// Platforms that want to only maintain certain debugging information can
119/// implement only part of this trait.
120///
121/// Tock provides a default implementation of this trait on the `()` type.
122/// Kernels that wish to use [`ProcessStandard`] but do not need process-level
123/// debugging information can use `()` as the `ProcessStandardDebug` type.
124pub trait ProcessStandardDebug: Default {
125 /// Record the address in flash the process expects to start at.
126 fn set_fixed_address_flash(&self, address: u32);
127 /// Get the address in flash the process expects to start at, if it was
128 /// recorded.
129 fn get_fixed_address_flash(&self) -> Option<u32>;
130 /// Record the address in RAM the process expects to start at.
131 fn set_fixed_address_ram(&self, address: u32);
132 /// Get the address in RAM the process expects to start at, if it was
133 /// recorded.
134 fn get_fixed_address_ram(&self) -> Option<u32>;
135 /// Record the address where the process placed its heap.
136 fn set_app_heap_start_pointer(&self, ptr: *const u8);
137 /// Get the address where the process placed its heap, if it was recorded.
138 fn get_app_heap_start_pointer(&self) -> Option<*const u8>;
139 /// Record the address where the process placed its stack.
140 fn set_app_stack_start_pointer(&self, ptr: *const u8);
141 /// Get the address where the process placed its stack, if it was recorded.
142 fn get_app_stack_start_pointer(&self) -> Option<*const u8>;
143 /// Update the lowest address that the process's stack has reached.
144 fn set_app_stack_min_pointer(&self, ptr: *const u8);
145 /// Get the lowest address of the process's stack , if it was recorded.
146 fn get_app_stack_min_pointer(&self) -> Option<*const u8>;
147 /// Provide the current address of the bottom of the stack and record the
148 /// address if it is the lowest address that the process's stack has
149 /// reached.
150 fn set_new_app_stack_min_pointer(&self, ptr: *const u8);
151
152 /// Record the most recent system call the process called.
153 fn set_last_syscall(&self, syscall: Syscall);
154 /// Get the most recent system call the process called, if it was recorded.
155 fn get_last_syscall(&self) -> Option<Syscall>;
156 /// Clear any record of the most recent system call the process called.
157 fn reset_last_syscall(&self);
158
159 /// Increase the recorded count of the number of system calls the process
160 /// has called.
161 fn increment_syscall_count(&self);
162 /// Get the recorded count of the number of system calls the process has
163 /// called.
164 ///
165 /// This should return 0 if
166 /// [`ProcessStandardDebug::increment_syscall_count()`] is never called.
167 fn get_syscall_count(&self) -> usize;
168 /// Reset the recorded count of the number of system calls called by the app
169 /// to 0.
170 fn reset_syscall_count(&self);
171
172 /// Increase the recorded count of the number of upcalls that have been
173 /// dropped for the process.
174 fn increment_dropped_upcall_count(&self);
175 /// Get the recorded count of the number of upcalls that have been dropped
176 /// for the process.
177 ///
178 /// This should return 0 if
179 /// [`ProcessStandardDebug::increment_dropped_upcall_count()`] is never
180 /// called.
181 fn get_dropped_upcall_count(&self) -> usize;
182 /// Reset the recorded count of the number of upcalls that have been dropped
183 /// for the process to 0.
184 fn reset_dropped_upcall_count(&self);
185
186 /// Increase the recorded count of the number of times the process has
187 /// exceeded its timeslice.
188 fn increment_timeslice_expiration_count(&self);
189 /// Get the recorded count of the number times the process has exceeded its
190 /// timeslice.
191 ///
192 /// This should return 0 if
193 /// [`ProcessStandardDebug::increment_timeslice_expiration_count()`] is
194 /// never called.
195 fn get_timeslice_expiration_count(&self) -> usize;
196 /// Reset the recorded count of the number of the process has exceeded its
197 /// timeslice to 0.
198 fn reset_timeslice_expiration_count(&self);
199}
200
201/// A debugging implementation for [`ProcessStandard`] that records the full
202/// debugging state.
203pub struct ProcessStandardDebugFull {
204 /// Inner field for the debug state that is in a [`MapCell`] to provide
205 /// mutable access.
206 debug: MapCell<ProcessStandardDebugFullInner>,
207}
208
209/// Struct for debugging [`ProcessStandard`] processes that records the full set
210/// of debugging information.
211///
212/// These pointers and counters are not strictly required for kernel operation,
213/// but provide helpful information when an app crashes.
214#[derive(Default)]
215struct ProcessStandardDebugFullInner {
216 /// If this process was compiled for fixed addresses, save the address
217 /// it must be at in flash. This is useful for debugging and saves having
218 /// to re-parse the entire TBF header.
219 fixed_address_flash: Option<u32>,
220
221 /// If this process was compiled for fixed addresses, save the address
222 /// it must be at in RAM. This is useful for debugging and saves having
223 /// to re-parse the entire TBF header.
224 fixed_address_ram: Option<u32>,
225
226 /// Where the process has started its heap in RAM.
227 app_heap_start_pointer: Option<*const u8>,
228
229 /// Where the start of the stack is for the process. If the kernel does the
230 /// PIC setup for this app then we know this, otherwise we need the app to
231 /// tell us where it put its stack.
232 app_stack_start_pointer: Option<*const u8>,
233
234 /// How low have we ever seen the stack pointer.
235 app_stack_min_pointer: Option<*const u8>,
236
237 /// How many syscalls have occurred since the process started.
238 syscall_count: usize,
239
240 /// What was the most recent syscall.
241 last_syscall: Option<Syscall>,
242
243 /// How many upcalls were dropped because the queue was insufficiently
244 /// long.
245 dropped_upcall_count: usize,
246
247 /// How many times this process has been paused because it exceeded its
248 /// timeslice.
249 timeslice_expiration_count: usize,
250}
251
252impl ProcessStandardDebug for ProcessStandardDebugFull {
253 fn set_fixed_address_flash(&self, address: u32) {
254 self.debug.map(|d| d.fixed_address_flash = Some(address));
255 }
256 fn get_fixed_address_flash(&self) -> Option<u32> {
257 self.debug.map_or(None, |d| d.fixed_address_flash)
258 }
259 fn set_fixed_address_ram(&self, address: u32) {
260 self.debug.map(|d| d.fixed_address_ram = Some(address));
261 }
262 fn get_fixed_address_ram(&self) -> Option<u32> {
263 self.debug.map_or(None, |d| d.fixed_address_ram)
264 }
265 fn set_app_heap_start_pointer(&self, ptr: *const u8) {
266 self.debug.map(|d| d.app_heap_start_pointer = Some(ptr));
267 }
268 fn get_app_heap_start_pointer(&self) -> Option<*const u8> {
269 self.debug.map_or(None, |d| d.app_heap_start_pointer)
270 }
271 fn set_app_stack_start_pointer(&self, ptr: *const u8) {
272 self.debug.map(|d| d.app_stack_start_pointer = Some(ptr));
273 }
274 fn get_app_stack_start_pointer(&self) -> Option<*const u8> {
275 self.debug.map_or(None, |d| d.app_stack_start_pointer)
276 }
277 fn set_app_stack_min_pointer(&self, ptr: *const u8) {
278 self.debug.map(|d| d.app_stack_min_pointer = Some(ptr));
279 }
280 fn get_app_stack_min_pointer(&self) -> Option<*const u8> {
281 self.debug.map_or(None, |d| d.app_stack_min_pointer)
282 }
283 fn set_new_app_stack_min_pointer(&self, ptr: *const u8) {
284 self.debug.map(|d| {
285 match d.app_stack_min_pointer {
286 None => d.app_stack_min_pointer = Some(ptr),
287 Some(asmp) => {
288 // Update max stack depth if needed.
289 if ptr < asmp {
290 d.app_stack_min_pointer = Some(ptr);
291 }
292 }
293 }
294 });
295 }
296
297 fn set_last_syscall(&self, syscall: Syscall) {
298 self.debug.map(|d| d.last_syscall = Some(syscall));
299 }
300 fn get_last_syscall(&self) -> Option<Syscall> {
301 self.debug.map_or(None, |d| d.last_syscall)
302 }
303 fn reset_last_syscall(&self) {
304 self.debug.map(|d| d.last_syscall = None);
305 }
306
307 fn increment_syscall_count(&self) {
308 self.debug.map(|d| d.syscall_count += 1);
309 }
310 fn get_syscall_count(&self) -> usize {
311 self.debug.map_or(0, |d| d.syscall_count)
312 }
313 fn reset_syscall_count(&self) {
314 self.debug.map(|d| d.syscall_count = 0);
315 }
316
317 fn increment_dropped_upcall_count(&self) {
318 self.debug.map(|d| d.dropped_upcall_count += 1);
319 }
320 fn get_dropped_upcall_count(&self) -> usize {
321 self.debug.map_or(0, |d| d.dropped_upcall_count)
322 }
323 fn reset_dropped_upcall_count(&self) {
324 self.debug.map(|d| d.dropped_upcall_count = 0);
325 }
326
327 fn increment_timeslice_expiration_count(&self) {
328 self.debug.map(|d| d.timeslice_expiration_count += 1);
329 }
330 fn get_timeslice_expiration_count(&self) -> usize {
331 self.debug.map_or(0, |d| d.timeslice_expiration_count)
332 }
333 fn reset_timeslice_expiration_count(&self) {
334 self.debug.map(|d| d.timeslice_expiration_count = 0);
335 }
336}
337
338impl Default for ProcessStandardDebugFull {
339 fn default() -> Self {
340 Self {
341 debug: MapCell::new(ProcessStandardDebugFullInner::default()),
342 }
343 }
344}
345
346impl ProcessStandardDebug for () {
347 fn set_fixed_address_flash(&self, _address: u32) {}
348 fn get_fixed_address_flash(&self) -> Option<u32> {
349 None
350 }
351 fn set_fixed_address_ram(&self, _address: u32) {}
352 fn get_fixed_address_ram(&self) -> Option<u32> {
353 None
354 }
355 fn set_app_heap_start_pointer(&self, _ptr: *const u8) {}
356 fn get_app_heap_start_pointer(&self) -> Option<*const u8> {
357 None
358 }
359 fn set_app_stack_start_pointer(&self, _ptr: *const u8) {}
360 fn get_app_stack_start_pointer(&self) -> Option<*const u8> {
361 None
362 }
363 fn set_app_stack_min_pointer(&self, _ptr: *const u8) {}
364 fn get_app_stack_min_pointer(&self) -> Option<*const u8> {
365 None
366 }
367 fn set_new_app_stack_min_pointer(&self, _ptr: *const u8) {}
368
369 fn set_last_syscall(&self, _syscall: Syscall) {}
370 fn get_last_syscall(&self) -> Option<Syscall> {
371 None
372 }
373 fn reset_last_syscall(&self) {}
374
375 fn increment_syscall_count(&self) {}
376 fn get_syscall_count(&self) -> usize {
377 0
378 }
379 fn reset_syscall_count(&self) {}
380 fn increment_dropped_upcall_count(&self) {}
381 fn get_dropped_upcall_count(&self) -> usize {
382 0
383 }
384 fn reset_dropped_upcall_count(&self) {}
385 fn increment_timeslice_expiration_count(&self) {}
386 fn get_timeslice_expiration_count(&self) -> usize {
387 0
388 }
389 fn reset_timeslice_expiration_count(&self) {}
390}
391
392/// Entry that is stored in the grant pointer table at the top of process
393/// memory.
394///
395/// One copy of this entry struct is stored per grant region defined in the
396/// kernel. This type allows the core kernel to lookup a grant based on the
397/// driver_num associated with the grant, and also holds the pointer to the
398/// memory allocated for the particular grant.
399#[repr(C)]
400struct GrantPointerEntry {
401 /// The syscall driver number associated with the allocated grant.
402 ///
403 /// This defaults to 0 if the grant has not been allocated. Note, however,
404 /// that 0 is a valid driver_num, and therefore cannot be used to check if a
405 /// grant is allocated or not.
406 driver_num: usize,
407
408 /// The start of the memory location where the grant has been allocated, or
409 /// null if the grant has not been allocated.
410 grant_ptr: *mut u8,
411}
412
413/// A type for userspace processes in Tock.
414///
415/// As its name implies, this is the standard implementation for Tock processes
416/// that exposes the full support for processes running on embedded hardware.
417///
418/// [`ProcessStandard`] is templated on two parameters:
419///
420/// - `C`: [`Chip`]: The implementation must know the [`Chip`] the kernel is
421/// running on to properly store architecture-specific and MPU state for the
422/// process.
423/// - `D`: [`ProcessStandardDebug`]: This configures the debugging mechanism the
424/// process uses for storing optional debugging data. Kernels that do not wish
425/// to store per-process debugging state can use the `()` type for this
426/// parameter.
427pub struct ProcessStandard<'a, C: 'static + Chip, D: 'static + ProcessStandardDebug + Default> {
428 /// Identifier of this process and the index of the process in the process
429 /// table.
430 process_id: Cell<ProcessId>,
431
432 /// An application ShortId, generated from process loading and
433 /// checking, which denotes the security identity of this process.
434 app_id: ShortId,
435
436 /// Pointer to the main Kernel struct.
437 kernel: &'static Kernel,
438
439 /// Pointer to the struct that defines the actual chip the kernel is running
440 /// on. This is used because processes have subtle hardware-based
441 /// differences. Specifically, the actual syscall interface and how
442 /// processes are switched to is architecture-specific, and how memory must
443 /// be allocated for memory protection units is also hardware-specific.
444 chip: &'static C,
445
446 /// Application memory layout:
447 ///
448 /// ```text
449 /// ╒════════ ← memory_start + memory_len
450 /// ╔═ │ Grant Pointers
451 /// ║ │ ──────
452 /// ║ │ Upcall Queue
453 /// ║ │ ──────
454 /// │ Process Control Block
455 /// D │ ──────
456 /// Y │ Grant Regions
457 /// N │
458 /// A │ ↓
459 /// M │ ────── ← kernel_memory_break
460 /// I │
461 /// C │ ────── ← app_break ═╗
462 /// │ ║
463 /// ║ │ ↑ A
464 /// ║ │ Heap P C
465 /// ╠═ │ ────── ← app_heap_start R C
466 /// │ Data O E
467 /// F │ ────── ← data_start_pointer C S
468 /// I │ Stack E S
469 /// X │ ↓ S I
470 /// E │ S B
471 /// D │ ────── ← current_stack_pointer L
472 /// │ ║ E
473 /// ╚═ ╘════════ ← memory_start ═╝
474 /// ```
475 ///
476 /// The start of process memory. We store this as a pointer and length and
477 /// not a slice due to Rust aliasing rules. If we were to store a slice,
478 /// then any time another slice to the same memory or an ProcessBuffer is
479 /// used in the kernel would be undefined behavior.
480 memory_start: *const u8,
481 /// Number of bytes of memory allocated to this process.
482 memory_len: usize,
483
484 /// Reference to the slice of `GrantPointerEntry`s stored in the process's
485 /// memory reserved for the kernel. These driver numbers are zero and
486 /// pointers are null if the grant region has not been allocated. When the
487 /// grant region is allocated these pointers are updated to point to the
488 /// allocated memory and the driver number is set to match the driver that
489 /// owns the grant. No other reference to these pointers exists in the Tock
490 /// kernel.
491 grant_pointers: MapCell<&'static mut [GrantPointerEntry]>,
492
493 /// Pointer to the end of the allocated (and MPU protected) grant region.
494 kernel_memory_break: Cell<*const u8>,
495
496 /// Pointer to the end of process RAM that has been sbrk'd to the process.
497 app_break: Cell<*const u8>,
498
499 /// Pointer to high water mark for process buffers shared through `allow`
500 allow_high_water_mark: Cell<*const u8>,
501
502 /// Process flash segment. This is the region of nonvolatile flash that
503 /// the process occupies.
504 flash: &'static [u8],
505
506 /// The footers of the process binary (may be zero-sized), which are metadata
507 /// about the process not covered by integrity. Used, among other things, to
508 /// store signatures.
509 footers: &'static [u8],
510
511 /// Collection of pointers to the TBF header in flash.
512 header: tock_tbf::types::TbfHeader<'static>,
513
514 /// Credential that was approved for this process, or `None` if the
515 /// credential was permitted to run without an accepted credential.
516 credential: Option<AcceptedCredential>,
517
518 /// State saved on behalf of the process each time the app switches to the
519 /// kernel.
520 stored_state:
521 MapCell<<<C as Chip>::UserspaceKernelBoundary as UserspaceKernelBoundary>::StoredState>,
522
523 /// The current state of the app. The scheduler uses this to determine
524 /// whether it can schedule this app to execute.
525 ///
526 /// The `state` is used both for bookkeeping for the scheduler as well as
527 /// for enabling control by other parts of the system. The scheduler keeps
528 /// track of if a process is ready to run or not by switching between the
529 /// `Running` and `Yielded` states. The system can control the process by
530 /// switching it to a "stopped" state to prevent the scheduler from
531 /// scheduling it.
532 state: Cell<State>,
533
534 /// How to respond if this process faults.
535 fault_policy: &'a dyn ProcessFaultPolicy,
536
537 /// Storage permissions for this process.
538 ///
539 /// This is stored in a `Cell` because we need to create the
540 /// [`ProcessStandard`] first to then later determine the storage
541 /// permissions.
542 storage_permissions: Cell<StoragePermissions>,
543
544 /// Configuration data for the MPU
545 mpu_config: MapCell<<<C as Chip>::MPU as MPU>::MpuConfig>,
546
547 /// MPU regions are saved as a pointer-size pair.
548 mpu_regions: [Cell<Option<mpu::Region>>; 6],
549
550 /// Essentially a list of upcalls that want to call functions in the
551 /// process.
552 tasks: MapCell<RingBuffer<'a, Task>>,
553
554 /// Count of how many times this process has entered the fault condition and
555 /// been restarted. This is used by some `ProcessRestartPolicy`s to
556 /// determine if the process should be restarted or not.
557 restart_count: Cell<usize>,
558
559 /// The completion code set by the process when it last exited, restarted,
560 /// or was terminated. If the process is has never terminated, then the
561 /// `OptionalCell` will be empty (i.e. `None`). If the process has exited,
562 /// restarted, or terminated, the `OptionalCell` will contain an optional 32
563 /// bit value. The option will be `None` if the process crashed or was
564 /// stopped by the kernel and there is no provided completion code. If the
565 /// process called the exit syscall then the provided completion code will
566 /// be stored as `Some(completion code)`.
567 completion_code: OptionalCell<Option<u32>>,
568
569 /// Flag that stores whether this process has a task that is ready when
570 /// the process is in the [`State::YieldedFor`] state.
571 is_yield_wait_for_ready: Cell<bool>,
572
573 /// Values kept so that we can print useful debug messages when apps fault.
574 debug: D,
575}
576
577impl<C: Chip, D: 'static + ProcessStandardDebug> Process for ProcessStandard<'_, C, D> {
578 fn processid(&self) -> ProcessId {
579 self.process_id.get()
580 }
581
582 fn short_app_id(&self) -> ShortId {
583 self.app_id
584 }
585
586 fn binary_version(&self) -> Option<BinaryVersion> {
587 let version = self.header.get_binary_version();
588 match NonZeroU32::new(version) {
589 Some(version_nonzero) => Some(BinaryVersion::new(version_nonzero)),
590 None => None,
591 }
592 }
593
594 fn get_credential(&self) -> Option<AcceptedCredential> {
595 self.credential
596 }
597
598 fn enqueue_task(&self, task: Task) -> Result<(), ErrorCode> {
599 // If this app is in a `Fault` state then we shouldn't schedule
600 // any work for it.
601 if !self.is_running() {
602 return Err(ErrorCode::NODEVICE);
603 }
604
605 let ret = self.tasks.map_or(Err(ErrorCode::FAIL), |tasks| {
606 match tasks.enqueue(task) {
607 true => {
608 // If the process is yielded-for this task, set the ready flag.
609 if let State::YieldedFor(yielded_upcall_id) = self.state.get() {
610 if let Some(upcall_id) = match task {
611 Task::FunctionCall(FunctionCall {
612 source: FunctionCallSource::Driver(upcall_id),
613 ..
614 }) => Some(upcall_id),
615 Task::ReturnValue(ReturnArguments { upcall_id, .. }) => Some(upcall_id),
616 _ => None,
617 } {
618 self.is_yield_wait_for_ready
619 .set(upcall_id == yielded_upcall_id);
620 }
621 }
622 // The task has been successfully enqueued.
623 Ok(())
624 }
625 false => {
626 // The task could not be enqueued as there is
627 // insufficient space in the ring buffer.
628 Err(ErrorCode::NOMEM)
629 }
630 }
631 });
632
633 if ret.is_err() {
634 // On any error we were unable to enqueue the task. Record the
635 // error, but importantly do _not_ increment kernel work.
636 self.debug.increment_dropped_upcall_count();
637 }
638
639 ret
640 }
641
642 fn ready(&self) -> bool {
643 match self.state.get() {
644 State::Running => true,
645 State::YieldedFor(_) => self.is_yield_wait_for_ready.get(),
646 State::Yielded => self.tasks.map_or(false, |ring_buf| ring_buf.has_elements()),
647 _ => false,
648 }
649 }
650
651 fn remove_pending_upcalls(&self, upcall_id: UpcallId) -> usize {
652 self.tasks.map_or(0, |tasks| {
653 let count_before = tasks.len();
654 tasks.retain(|task| match task {
655 // Remove only tasks that are function calls with an id equal
656 // to `upcall_id`.
657 Task::FunctionCall(function_call) => match function_call.source {
658 FunctionCallSource::Kernel => true,
659 FunctionCallSource::Driver(id) => id != upcall_id,
660 },
661 _ => true,
662 });
663 let count_after = tasks.len();
664 if config::CONFIG.trace_syscalls {
665 debug!(
666 "[{:?}] remove_pending_upcalls[{:#x}:{}] = {} upcall(s) removed",
667 self.processid(),
668 upcall_id.driver_num,
669 upcall_id.subscribe_num,
670 count_before - count_after,
671 );
672 }
673 count_before - count_after
674 })
675 }
676
677 fn is_running(&self) -> bool {
678 match self.state.get() {
679 State::Running | State::Yielded | State::YieldedFor(_) | State::Stopped(_) => true,
680 _ => false,
681 }
682 }
683
684 fn get_state(&self) -> State {
685 self.state.get()
686 }
687
688 fn set_yielded_state(&self) {
689 if self.state.get() == State::Running {
690 self.state.set(State::Yielded);
691 }
692 }
693
694 fn set_yielded_for_state(&self, upcall_id: UpcallId) {
695 if self.state.get() == State::Running {
696 self.state.set(State::YieldedFor(upcall_id));
697
698 // Verify if the process has a task that this yield waits for
699 self.is_yield_wait_for_ready
700 .set(self.tasks.map_or(false, |tasks| {
701 tasks
702 .find_first_matching(|task| match task {
703 Task::ReturnValue(ReturnArguments { upcall_id: id, .. }) => {
704 upcall_id == *id
705 }
706 Task::FunctionCall(FunctionCall {
707 source: FunctionCallSource::Driver(id),
708 ..
709 }) => upcall_id == *id,
710 _ => false,
711 })
712 .is_some()
713 }));
714 }
715 }
716
717 fn stop(&self) {
718 match self.state.get() {
719 State::Running => self.state.set(State::Stopped(StoppedState::Running)),
720 State::Yielded => self.state.set(State::Stopped(StoppedState::Yielded)),
721 State::YieldedFor(upcall_id) => self
722 .state
723 .set(State::Stopped(StoppedState::YieldedFor(upcall_id))),
724 State::Stopped(_stopped_state) => {
725 // Already stopped, nothing to do.
726 }
727 State::Faulted | State::Terminated => {
728 // Stop has no meaning on a inactive process.
729 }
730 }
731 }
732
733 fn resume(&self) {
734 if let State::Stopped(stopped_state) = self.state.get() {
735 match stopped_state {
736 StoppedState::Running => self.state.set(State::Running),
737 StoppedState::Yielded => self.state.set(State::Yielded),
738 StoppedState::YieldedFor(upcall_id) => self.set_yielded_for_state(upcall_id),
739 }
740 }
741 }
742
743 fn set_fault_state(&self) {
744 // Use the per-process fault policy to determine what action the kernel
745 // should take since the process faulted.
746 let action = self.fault_policy.action(self);
747 match action {
748 FaultAction::Panic => {
749 // process faulted. Panic and print status
750 self.state.set(State::Faulted);
751 panic!("Process {} had a fault", self.get_process_name());
752 }
753 FaultAction::Restart => {
754 self.try_restart(None);
755 }
756 FaultAction::Stop => {
757 // This looks a lot like restart, except we just leave the app
758 // how it faulted and mark it as `Faulted`. By clearing
759 // all of the app's todo work it will not be scheduled, and
760 // clearing all of the grant regions will cause capsules to drop
761 // this app as well.
762 self.terminate(None);
763 self.state.set(State::Faulted);
764 }
765 }
766 }
767
768 fn start(&self, _cap: &dyn crate::capabilities::ProcessStartCapability) {
769 // `start()` can only be called on a terminated process.
770 if self.get_state() != State::Terminated {
771 return;
772 }
773
774 // Reset to start the process.
775 if let Ok(()) = self.reset() {
776 self.state.set(State::Yielded);
777 }
778 }
779
780 fn try_restart(&self, completion_code: Option<u32>) {
781 // `try_restart()` cannot be called if the process is terminated. Only
782 // `start()` can start a terminated process.
783 if self.get_state() == State::Terminated {
784 return;
785 }
786
787 // Terminate the process, freeing its state and removing any
788 // pending tasks from the scheduler's queue.
789 self.terminate(completion_code);
790
791 // If there is a kernel policy that controls restarts, it should be
792 // implemented here. For now, always restart.
793 if let Ok(()) = self.reset() {
794 self.state.set(State::Yielded);
795 }
796
797 // Decide what to do with res later. E.g., if we can't restart
798 // want to reclaim the process resources.
799 }
800
801 fn terminate(&self, completion_code: Option<u32>) {
802 // A process can be terminated if it is running or in the `Faulted`
803 // state. Otherwise, you cannot terminate it and this method return
804 // early.
805 //
806 // The kernel can terminate in the `Faulted` state to return the process
807 // to a state in which it can run again (e.g., reset it).
808 if !self.is_running() && self.get_state() != State::Faulted {
809 return;
810 }
811
812 // And remove those tasks
813 self.tasks.map(|tasks| {
814 tasks.empty();
815 });
816
817 // Clear any grant regions this app has setup with any capsules.
818 unsafe {
819 self.grant_ptrs_reset();
820 }
821
822 // Save the completion code.
823 self.completion_code.set(completion_code);
824
825 // Mark the app as stopped so the scheduler won't try to run it.
826 self.state.set(State::Terminated);
827 }
828
829 fn get_restart_count(&self) -> usize {
830 self.restart_count.get()
831 }
832
833 fn has_tasks(&self) -> bool {
834 self.tasks.map_or(false, |tasks| tasks.has_elements())
835 }
836
837 fn dequeue_task(&self) -> Option<Task> {
838 self.tasks.map_or(None, |tasks| tasks.dequeue())
839 }
840
841 fn remove_upcall(&self, upcall_id: UpcallId) -> Option<Task> {
842 self.tasks.map_or(None, |tasks| {
843 tasks.remove_first_matching(|task| match task {
844 Task::FunctionCall(fc) => match fc.source {
845 FunctionCallSource::Driver(upid) => upid == upcall_id,
846 _ => false,
847 },
848 Task::ReturnValue(rv) => rv.upcall_id == upcall_id,
849 Task::IPC(_) => false,
850 })
851 })
852 }
853
854 fn pending_tasks(&self) -> usize {
855 self.tasks.map_or(0, |tasks| tasks.len())
856 }
857
858 fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions {
859 self.header.get_command_permissions(driver_num, offset)
860 }
861
862 fn get_storage_permissions(&self) -> StoragePermissions {
863 self.storage_permissions.get()
864 }
865
866 fn number_writeable_flash_regions(&self) -> usize {
867 self.header.number_writeable_flash_regions()
868 }
869
870 fn get_writeable_flash_region(&self, region_index: usize) -> (usize, usize) {
871 self.header.get_writeable_flash_region(region_index)
872 }
873
874 fn update_stack_start_pointer(&self, stack_pointer: *const u8) {
875 if stack_pointer >= self.mem_start() && stack_pointer < self.mem_end() {
876 self.debug.set_app_stack_start_pointer(stack_pointer);
877 // We also reset the minimum stack pointer because whatever
878 // value we had could be entirely wrong by now.
879 self.debug.set_app_stack_min_pointer(stack_pointer);
880 }
881 }
882
883 fn update_heap_start_pointer(&self, heap_pointer: *const u8) {
884 if heap_pointer >= self.mem_start() && heap_pointer < self.mem_end() {
885 self.debug.set_app_heap_start_pointer(heap_pointer);
886 }
887 }
888
889 fn setup_mpu(&self) {
890 self.mpu_config.map(|config| {
891 // # Safety
892 //
893 // `configure_mpu` is unsafe, as invoking it with an incorrect
894 // configuration can allow an untrusted application to access
895 // kernel-private memory.
896 //
897 // This call is safe given we trust that the implementation of
898 // `ProcessStandard` correctly provisions a set of MPU regions that
899 // does not grant access to any kernel-private memory, and
900 // `ProcessStandard` does not provide safe, publically accessible
901 // APIs to add other arbitrary MPU regions to this configuration.
902 unsafe {
903 self.chip.mpu().configure_mpu(config);
904 }
905 });
906 }
907
908 fn add_mpu_region(
909 &self,
910 unallocated_memory_start: *const u8,
911 unallocated_memory_size: usize,
912 min_region_size: usize,
913 ) -> Option<mpu::Region> {
914 self.mpu_config.and_then(|config| {
915 let new_region = self.chip.mpu().allocate_region(
916 unallocated_memory_start,
917 unallocated_memory_size,
918 min_region_size,
919 mpu::Permissions::ReadWriteOnly,
920 config,
921 )?;
922
923 for region in self.mpu_regions.iter() {
924 if region.get().is_none() {
925 region.set(Some(new_region));
926 return Some(new_region);
927 }
928 }
929
930 // Not enough room in Process struct to store the MPU region.
931 None
932 })
933 }
934
935 fn remove_mpu_region(&self, region: mpu::Region) -> Result<(), ErrorCode> {
936 self.mpu_config.map_or(Err(ErrorCode::INVAL), |config| {
937 // Find the existing mpu region that we are removing; it needs to match exactly.
938 if let Some(internal_region) = self.mpu_regions.iter().find(|r| r.get() == Some(region))
939 {
940 self.chip
941 .mpu()
942 .remove_memory_region(region, config)
943 .or(Err(ErrorCode::FAIL))?;
944
945 // Remove this region from the tracking cache of mpu_regions
946 internal_region.set(None);
947 Ok(())
948 } else {
949 Err(ErrorCode::INVAL)
950 }
951 })
952 }
953
954 fn sbrk(&self, increment: isize) -> Result<CapabilityPtr, Error> {
955 // Do not modify an inactive process.
956 if !self.is_running() {
957 return Err(Error::InactiveApp);
958 }
959
960 let new_break = self.app_break.get().wrapping_offset(increment);
961 self.brk(new_break)
962 }
963
964 fn brk(&self, new_break: *const u8) -> Result<CapabilityPtr, Error> {
965 // Do not modify an inactive process.
966 if !self.is_running() {
967 return Err(Error::InactiveApp);
968 }
969
970 self.mpu_config.map_or(Err(Error::KernelError), |config| {
971 if new_break < self.allow_high_water_mark.get() || new_break >= self.mem_end() {
972 Err(Error::AddressOutOfBounds)
973 } else if new_break > self.kernel_memory_break.get() {
974 Err(Error::OutOfMemory)
975 } else if let Err(()) = self.chip.mpu().update_app_memory_region(
976 new_break,
977 self.kernel_memory_break.get(),
978 mpu::Permissions::ReadWriteOnly,
979 config,
980 ) {
981 Err(Error::OutOfMemory)
982 } else {
983 let old_break: *const u8 = self.app_break.get();
984 self.app_break.set(new_break);
985
986 // # Safety
987 //
988 // `configure_mpu` is unsafe, as invoking it with an incorrect
989 // configuration can allow an untrusted application to access
990 // kernel-private memory.
991 //
992 // This call is safe given we trust that the implementation of
993 // `ProcessStandard` correctly provisions a set of MPU regions
994 // that does not grant access to any kernel-private memory, and
995 // `ProcessStandard` does not provide safe, publically
996 // accessible APIs to add other arbitrary MPU regions to this
997 // configuration.
998 unsafe {
999 self.chip.mpu().configure_mpu(config);
1000 }
1001
1002 if new_break > old_break {
1003 // We need to initialize (zero) the newly accessible memory
1004 // region at `[old_break; new_break)`. This serves two
1005 // purposes:
1006 //
1007 // 1. It prevents a process from accessing any information
1008 // still contained in this memory from prior kernel
1009 // instances or processes.
1010 //
1011 // 2. It satisfies Rust's requirements that all
1012 // dereferencable memory be properly initialized. This is
1013 // important, as we'll be creating references into this
1014 // process-accessible memory region through the process
1015 // buffer infrastructure.
1016 let old_break_mut_ptr: *mut u8 = old_break.cast_mut();
1017 unsafe {
1018 core::ptr::write_bytes(
1019 old_break_mut_ptr,
1020 // Set the newly app-accessible memory to `0`:
1021 0_u8,
1022 new_break.addr() - old_break.addr(),
1023 );
1024 }
1025 }
1026
1027 let base = self.mem_start() as usize;
1028 let old_break_unit_ptr: *const () = old_break.cast();
1029 // # Safety
1030 // The passed range [base, new_break) exactly matches the process' memory range,
1031 // and a process should have RW access to its own memory.
1032 let break_result = unsafe {
1033 CapabilityPtr::new_with_authority(
1034 old_break_unit_ptr,
1035 base,
1036 (new_break as usize) - base,
1037 CapabilityPtrPermissions::ReadWrite,
1038 )
1039 };
1040
1041 Ok(break_result)
1042 }
1043 })
1044 }
1045
1046 #[allow(clippy::not_unsafe_ptr_arg_deref)]
1047 fn build_readwrite_process_buffer(
1048 &self,
1049 buf_start_addr: *mut u8,
1050 size: usize,
1051 ) -> Result<ReadWriteProcessBuffer, ErrorCode> {
1052 if !self.is_running() {
1053 // Do not operate on an inactive process
1054 return Err(ErrorCode::FAIL);
1055 }
1056
1057 // A process is allowed to pass any pointer if the buffer length is 0,
1058 // as to revoke kernel access to a memory region without granting access
1059 // to another one
1060 if size == 0 {
1061 // Clippy complains that we're dereferencing a pointer in a public
1062 // and safe function here. While we are not dereferencing the
1063 // pointer here, we pass it along to an unsafe function, which is as
1064 // dangerous (as it is likely to be dereferenced down the line).
1065 //
1066 // Relevant discussion:
1067 // https://github.com/rust-lang/rust-clippy/issues/3045
1068 //
1069 // It should be fine to ignore the lint here, as a buffer of length
1070 // 0 will never allow dereferencing any memory in a safe manner.
1071 //
1072 // ### Safety
1073 //
1074 // We specify a zero-length buffer, so the implementation of
1075 // `ReadWriteProcessBuffer` will handle any safety issues.
1076 // Therefore, we can encapsulate the unsafe.
1077 Ok(unsafe { ReadWriteProcessBuffer::new(buf_start_addr, 0, self.processid()) })
1078 } else if self.in_app_owned_memory(buf_start_addr, size) {
1079 // TODO: Check for buffer aliasing here
1080
1081 // Valid buffer, we need to adjust the app's watermark
1082 // note: `in_app_owned_memory` ensures this offset does not wrap
1083 let buf_end_addr = buf_start_addr.wrapping_add(size);
1084 let new_water_mark = cmp::max(self.allow_high_water_mark.get(), buf_end_addr);
1085 self.allow_high_water_mark.set(new_water_mark);
1086
1087 // Clippy complains that we're dereferencing a pointer in a public
1088 // and safe function here. While we are not dereferencing the
1089 // pointer here, we pass it along to an unsafe function, which is as
1090 // dangerous (as it is likely to be dereferenced down the line).
1091 //
1092 // Relevant discussion:
1093 // https://github.com/rust-lang/rust-clippy/issues/3045
1094 //
1095 // It should be fine to ignore the lint here, as long as we make
1096 // sure that we're pointing towards userspace memory (verified using
1097 // `in_app_owned_memory`) and respect alignment and other
1098 // constraints of the Rust references created by
1099 // `ReadWriteProcessBuffer`.
1100 //
1101 // ### Safety
1102 //
1103 // We encapsulate the unsafe here on the condition in the TODO
1104 // above, as we must ensure that this `ReadWriteProcessBuffer` will
1105 // be the only reference to this memory.
1106 Ok(unsafe { ReadWriteProcessBuffer::new(buf_start_addr, size, self.processid()) })
1107 } else {
1108 Err(ErrorCode::INVAL)
1109 }
1110 }
1111
1112 #[allow(clippy::not_unsafe_ptr_arg_deref)]
1113 fn build_readonly_process_buffer(
1114 &self,
1115 buf_start_addr: *const u8,
1116 size: usize,
1117 ) -> Result<ReadOnlyProcessBuffer, ErrorCode> {
1118 if !self.is_running() {
1119 // Do not operate on an inactive process
1120 return Err(ErrorCode::FAIL);
1121 }
1122
1123 // A process is allowed to pass any pointer if the buffer length is 0,
1124 // as to revoke kernel access to a memory region without granting access
1125 // to another one
1126 if size == 0 {
1127 // Clippy complains that we're dereferencing a pointer in a public
1128 // and safe function here. While we are not dereferencing the
1129 // pointer here, we pass it along to an unsafe function, which is as
1130 // dangerous (as it is likely to be dereferenced down the line).
1131 //
1132 // Relevant discussion:
1133 // https://github.com/rust-lang/rust-clippy/issues/3045
1134 //
1135 // It should be fine to ignore the lint here, as a buffer of length
1136 // 0 will never allow dereferencing any memory in a safe manner.
1137 //
1138 // ### Safety
1139 //
1140 // We specify a zero-length buffer, so the implementation of
1141 // `ReadOnlyProcessBuffer` will handle any safety issues. Therefore,
1142 // we can encapsulate the unsafe.
1143 Ok(unsafe { ReadOnlyProcessBuffer::new(buf_start_addr, 0, self.processid()) })
1144 } else if self.in_app_owned_memory(buf_start_addr, size)
1145 || self.in_app_flash_memory(buf_start_addr, size)
1146 {
1147 // TODO: Check for buffer aliasing here
1148
1149 if self.in_app_owned_memory(buf_start_addr, size) {
1150 // Valid buffer, and since this is in read-write memory (i.e.
1151 // not flash), we need to adjust the process's watermark. Note:
1152 // `in_app_owned_memory()` ensures this offset does not wrap.
1153 let buf_end_addr = buf_start_addr.wrapping_add(size);
1154 let new_water_mark = cmp::max(self.allow_high_water_mark.get(), buf_end_addr);
1155 self.allow_high_water_mark.set(new_water_mark);
1156 }
1157
1158 // Clippy complains that we're dereferencing a pointer in a public
1159 // and safe function here. While we are not dereferencing the
1160 // pointer here, we pass it along to an unsafe function, which is as
1161 // dangerous (as it is likely to be dereferenced down the line).
1162 //
1163 // Relevant discussion:
1164 // https://github.com/rust-lang/rust-clippy/issues/3045
1165 //
1166 // It should be fine to ignore the lint here, as long as we make
1167 // sure that we're pointing towards userspace memory (verified using
1168 // `in_app_owned_memory` or `in_app_flash_memory`) and respect
1169 // alignment and other constraints of the Rust references created by
1170 // `ReadWriteProcessBuffer`.
1171 //
1172 // ### Safety
1173 //
1174 // We encapsulate the unsafe here on the condition in the TODO
1175 // above, as we must ensure that this `ReadOnlyProcessBuffer` will
1176 // be the only reference to this memory.
1177 Ok(unsafe { ReadOnlyProcessBuffer::new(buf_start_addr, size, self.processid()) })
1178 } else {
1179 Err(ErrorCode::INVAL)
1180 }
1181 }
1182
1183 unsafe fn set_byte(&self, addr: *mut u8, value: u8) -> bool {
1184 if self.in_app_owned_memory(addr, 1) {
1185 // # Safety
1186 //
1187 // We verify that this will only write process-accessible memory,
1188 // but this can still be undefined behavior if something else holds
1189 // a reference to this memory. The caller must ensure nothing else
1190 // holds a reference to this memory.
1191 unsafe {
1192 *addr = value;
1193 }
1194 true
1195 } else {
1196 false
1197 }
1198 }
1199
1200 fn grant_is_allocated(&self, grant_num: usize) -> Option<bool> {
1201 // Do not modify an inactive process.
1202 if !self.is_running() {
1203 return None;
1204 }
1205
1206 // Update the grant pointer to the address of the new allocation.
1207 self.grant_pointers.map_or(None, |grant_pointers| {
1208 // Implement `grant_pointers[grant_num]` without a chance of a
1209 // panic.
1210 grant_pointers
1211 .get(grant_num)
1212 .map(|grant_entry| !grant_entry.grant_ptr.is_null())
1213 })
1214 }
1215
1216 fn allocate_grant(
1217 &self,
1218 grant_num: usize,
1219 driver_num: usize,
1220 size: usize,
1221 align: usize,
1222 ) -> Result<(), ()> {
1223 // Do not modify an inactive process.
1224 if !self.is_running() {
1225 return Err(());
1226 }
1227
1228 // Verify the grant_num is valid.
1229 if grant_num >= self.kernel.get_grant_count_and_finalize() {
1230 return Err(());
1231 }
1232
1233 // Verify that the grant is not already allocated. If the pointer is not
1234 // null then the grant is already allocated.
1235 if let Some(is_allocated) = self.grant_is_allocated(grant_num) {
1236 if is_allocated {
1237 return Err(());
1238 }
1239 }
1240
1241 // Verify that there is not already a grant allocated with the same
1242 // `driver_num`.
1243 let exists = self.grant_pointers.map_or(false, |grant_pointers| {
1244 // Check our list of grant pointers if the driver number is used.
1245 grant_pointers.iter().any(|grant_entry| {
1246 // Check if the grant is both allocated (its grant pointer is
1247 // non null) and the driver number matches.
1248 (!grant_entry.grant_ptr.is_null()) && grant_entry.driver_num == driver_num
1249 })
1250 });
1251 // If we find a match, then the `driver_num` must already be used and
1252 // the grant allocation fails.
1253 if exists {
1254 return Err(());
1255 }
1256
1257 // Use the shared grant allocator function to actually allocate memory.
1258 // Returns `None` if the allocation cannot be created.
1259 if let Some(grant_ptr) = self.allocate_in_grant_region_internal(size, align) {
1260 // Update the grant pointer to the address of the new allocation.
1261 self.grant_pointers.map_or(Err(()), |grant_pointers| {
1262 // Implement `grant_pointers[grant_num] = grant_ptr` without a
1263 // chance of a panic.
1264 grant_pointers
1265 .get_mut(grant_num)
1266 .map_or(Err(()), |grant_entry| {
1267 // Actually set the driver num and grant pointer.
1268 grant_entry.driver_num = driver_num;
1269 grant_entry.grant_ptr = grant_ptr.as_ptr();
1270
1271 // If all of this worked, return true.
1272 Ok(())
1273 })
1274 })
1275 } else {
1276 // Could not allocate the memory for the grant region.
1277 Err(())
1278 }
1279 }
1280
1281 fn allocate_custom_grant(
1282 &self,
1283 size: usize,
1284 align: usize,
1285 ) -> Result<(ProcessCustomGrantIdentifier, NonNull<u8>), ()> {
1286 // Do not modify an inactive process.
1287 if !self.is_running() {
1288 return Err(());
1289 }
1290
1291 // Use the shared grant allocator function to actually allocate memory.
1292 // Returns `None` if the allocation cannot be created.
1293 if let Some(ptr) = self.allocate_in_grant_region_internal(size, align) {
1294 // Create the identifier that the caller will use to get access to
1295 // this custom grant in the future.
1296 let identifier = self.create_custom_grant_identifier(ptr);
1297
1298 Ok((identifier, ptr))
1299 } else {
1300 // Could not allocate memory for the custom grant.
1301 Err(())
1302 }
1303 }
1304
1305 fn enter_grant(&self, grant_num: usize) -> Result<NonNull<u8>, Error> {
1306 // Do not try to access the grant region of an inactive process.
1307 if !self.is_running() {
1308 return Err(Error::InactiveApp);
1309 }
1310
1311 // Retrieve the grant pointer from the `grant_pointers` slice. We use
1312 // `[slice].get()` so that if the grant number is invalid this will
1313 // return `Err` and not panic.
1314 self.grant_pointers
1315 .map_or(Err(Error::KernelError), |grant_pointers| {
1316 // Implement `grant_pointers[grant_num]` without a chance of a
1317 // panic.
1318 match grant_pointers.get_mut(grant_num) {
1319 Some(grant_entry) => {
1320 // Get a copy of the actual grant pointer.
1321 let grant_ptr = grant_entry.grant_ptr;
1322
1323 // Check if the grant pointer is marked that the grant
1324 // has already been entered. If so, return an error.
1325 if (grant_ptr as usize) & 0x1 == 0x1 {
1326 // Lowest bit is one, meaning this grant has been
1327 // entered.
1328 Err(Error::AlreadyInUse)
1329 } else {
1330 // Now, to mark that the grant has been entered, we
1331 // set the lowest bit to one and save this as the
1332 // grant pointer.
1333 grant_entry.grant_ptr = (grant_ptr as usize | 0x1) as *mut u8;
1334
1335 // And we return the grant pointer to the entered
1336 // grant.
1337 Ok(unsafe { NonNull::new_unchecked(grant_ptr) })
1338 }
1339 }
1340 None => Err(Error::AddressOutOfBounds),
1341 }
1342 })
1343 }
1344
1345 fn enter_custom_grant(
1346 &self,
1347 identifier: ProcessCustomGrantIdentifier,
1348 ) -> Result<*mut u8, Error> {
1349 // Do not try to access the grant region of an inactive process.
1350 if !self.is_running() {
1351 return Err(Error::InactiveApp);
1352 }
1353
1354 // Get the address of the custom grant based on the identifier.
1355 let custom_grant_address = self.get_custom_grant_address(identifier);
1356
1357 // We never deallocate custom grants and only we can change the
1358 // `identifier` so we know this is a valid address for the custom grant.
1359 Ok(custom_grant_address as *mut u8)
1360 }
1361
1362 unsafe fn leave_grant(&self, grant_num: usize) {
1363 // Do not modify an inactive process.
1364 if !self.is_running() {
1365 return;
1366 }
1367
1368 self.grant_pointers.map(|grant_pointers| {
1369 // Implement `grant_pointers[grant_num]` without a chance of a
1370 // panic.
1371 if let Some(grant_entry) = grant_pointers.get_mut(grant_num) {
1372 // Get a copy of the actual grant pointer.
1373 let grant_ptr = grant_entry.grant_ptr;
1374
1375 // Now, to mark that the grant has been released, we set the
1376 // lowest bit back to zero and save this as the grant
1377 // pointer.
1378 grant_entry.grant_ptr = (grant_ptr as usize & !0x1) as *mut u8;
1379 }
1380 });
1381 }
1382
1383 fn grant_allocated_count(&self) -> Option<usize> {
1384 // Do not modify an inactive process.
1385 if !self.is_running() {
1386 return None;
1387 }
1388
1389 self.grant_pointers.map(|grant_pointers| {
1390 // Filter our list of grant pointers into just the non-null ones,
1391 // and count those. A grant is allocated if its grant pointer is
1392 // non-null.
1393 grant_pointers
1394 .iter()
1395 .filter(|grant_entry| !grant_entry.grant_ptr.is_null())
1396 .count()
1397 })
1398 }
1399
1400 fn lookup_grant_from_driver_num(&self, driver_num: usize) -> Result<usize, Error> {
1401 self.grant_pointers
1402 .map_or(Err(Error::KernelError), |grant_pointers| {
1403 // Filter our list of grant pointers into just the non null
1404 // ones, and count those. A grant is allocated if its grant
1405 // pointer is non-null.
1406 match grant_pointers.iter().position(|grant_entry| {
1407 // Only consider allocated grants.
1408 (!grant_entry.grant_ptr.is_null()) && grant_entry.driver_num == driver_num
1409 }) {
1410 Some(idx) => Ok(idx),
1411 None => Err(Error::OutOfMemory),
1412 }
1413 })
1414 }
1415
1416 fn is_valid_upcall_function_pointer(&self, upcall_fn: *const ()) -> bool {
1417 let ptr: *const u8 = upcall_fn.cast();
1418 let size = mem::size_of::<*const u8>();
1419
1420 // It is okay if this function is in memory or flash.
1421 self.in_app_flash_memory(ptr, size) || self.in_app_owned_memory(ptr, size)
1422 }
1423
1424 fn get_process_name(&self) -> &'static str {
1425 self.header.get_package_name().unwrap_or("")
1426 }
1427
1428 fn get_completion_code(&self) -> Option<Option<u32>> {
1429 self.completion_code.get()
1430 }
1431
1432 fn set_syscall_return_value(&self, return_value: SyscallReturn) {
1433 match self.stored_state.map(|stored_state| unsafe {
1434 // Actually set the return value for a particular process.
1435 //
1436 // The UKB implementation uses the bounds of process-accessible
1437 // memory to verify that any memory changes are valid. Here, the
1438 // unsafe promise we are making is that the bounds passed to the UKB
1439 // are correct.
1440 self.chip
1441 .userspace_kernel_boundary()
1442 .set_syscall_return_value(
1443 self.mem_start(),
1444 self.app_break.get(),
1445 stored_state,
1446 return_value,
1447 )
1448 }) {
1449 Some(Ok(())) => {
1450 // If we get an `Ok` we are all set.
1451
1452 // The process is either already in the running state (having
1453 // just called a nonblocking syscall like command) or needs to
1454 // be moved to the running state having called Yield-WaitFor and
1455 // now needing to be resumed. Either way we can set the state to
1456 // running.
1457 self.state.set(State::Running);
1458 // The task is running, if it was yielded-for an upcall,
1459 // the upcall must have been scheduled, unset
1460 // the ready flag.
1461 self.is_yield_wait_for_ready.set(false);
1462 }
1463
1464 Some(Err(())) => {
1465 // If we get an `Err`, then the UKB implementation could not set
1466 // the return value, likely because the process's stack is no
1467 // longer accessible to it. All we can do is fault.
1468 self.set_fault_state();
1469 }
1470
1471 None => {
1472 // We should never be here since `stored_state` should always be
1473 // occupied.
1474 self.set_fault_state();
1475 }
1476 }
1477 }
1478
1479 fn set_process_function(&self, callback: FunctionCall) {
1480 // See if we can actually enqueue this function for this process.
1481 // Architecture-specific code handles actually doing this since the
1482 // exact method is both architecture- and implementation-specific.
1483 //
1484 // This can fail, for example if the process does not have enough memory
1485 // remaining.
1486 match self.stored_state.map(|stored_state| {
1487 // Let the UKB implementation handle setting the process's PC so
1488 // that the process executes the upcall function. We encapsulate
1489 // unsafe here because we are guaranteeing that the memory bounds
1490 // passed to `set_process_function` are correct.
1491 unsafe {
1492 self.chip.userspace_kernel_boundary().set_process_function(
1493 self.mem_start(),
1494 self.app_break.get(),
1495 stored_state,
1496 callback,
1497 )
1498 }
1499 }) {
1500 Some(Ok(())) => {
1501 // If we got an `Ok` we are all set and should mark that this
1502 // process is ready to be scheduled.
1503
1504 // Move this process to the "running" state so the scheduler
1505 // will schedule it.
1506 self.state.set(State::Running);
1507 }
1508
1509 Some(Err(())) => {
1510 // If we got an Error, then there was likely not enough room on
1511 // the stack to allow the process to execute this function given
1512 // the details of the particular architecture this is running
1513 // on. This process has essentially faulted, so we mark it as
1514 // such.
1515 self.set_fault_state();
1516 }
1517
1518 None => {
1519 // We should never be here since `stored_state` should always be
1520 // occupied.
1521 self.set_fault_state();
1522 }
1523 }
1524 }
1525
1526 fn switch_to(&self) -> Option<syscall::ContextSwitchReason> {
1527 // Cannot switch to an invalid process
1528 if !self.is_running() {
1529 return None;
1530 }
1531
1532 let (switch_reason, stack_pointer) =
1533 self.stored_state.map_or((None, None), |stored_state| {
1534 // Switch to the process. We guarantee that the memory pointers
1535 // we pass are valid, ensuring this context switch is safe.
1536 // Therefore we encapsulate the `unsafe`.
1537 unsafe {
1538 let (switch_reason, optional_stack_pointer) = self
1539 .chip
1540 .userspace_kernel_boundary()
1541 .switch_to_process(self.mem_start(), self.app_break.get(), stored_state);
1542 (Some(switch_reason), optional_stack_pointer)
1543 }
1544 });
1545
1546 // If the UKB implementation passed us a stack pointer, update our
1547 // debugging state. This is completely optional.
1548 if let Some(sp) = stack_pointer {
1549 self.debug.set_new_app_stack_min_pointer(sp);
1550 }
1551
1552 switch_reason
1553 }
1554
1555 fn debug_syscall_count(&self) -> usize {
1556 self.debug.get_syscall_count()
1557 }
1558
1559 fn debug_dropped_upcall_count(&self) -> usize {
1560 self.debug.get_dropped_upcall_count()
1561 }
1562
1563 fn debug_timeslice_expiration_count(&self) -> usize {
1564 self.debug.get_timeslice_expiration_count()
1565 }
1566
1567 fn debug_timeslice_expired(&self) {
1568 self.debug.increment_timeslice_expiration_count();
1569 }
1570
1571 fn debug_syscall_called(&self, last_syscall: Syscall) {
1572 self.debug.increment_syscall_count();
1573 self.debug.set_last_syscall(last_syscall);
1574 }
1575
1576 fn debug_syscall_last(&self) -> Option<Syscall> {
1577 self.debug.get_last_syscall()
1578 }
1579
1580 fn get_addresses(&self) -> ProcessAddresses {
1581 ProcessAddresses {
1582 flash_start: self.flash_start() as usize,
1583 flash_non_protected_start: self.flash_non_protected_start() as usize,
1584 flash_integrity_end: ((self.flash.as_ptr() as usize)
1585 + (self.header.get_binary_end() as usize))
1586 as *const u8,
1587 flash_end: self.flash_end() as usize,
1588 sram_start: self.mem_start() as usize,
1589 sram_app_brk: self.app_memory_break() as usize,
1590 sram_grant_start: self.kernel_memory_break() as usize,
1591 sram_end: self.mem_end() as usize,
1592 sram_heap_start: self.debug.get_app_heap_start_pointer().map(|p| p as usize),
1593 sram_stack_top: self.debug.get_app_stack_start_pointer().map(|p| p as usize),
1594 sram_stack_bottom: self.debug.get_app_stack_min_pointer().map(|p| p as usize),
1595 }
1596 }
1597
1598 fn get_sizes(&self) -> ProcessSizes {
1599 ProcessSizes {
1600 grant_pointers: mem::size_of::<GrantPointerEntry>()
1601 * self.kernel.get_grant_count_and_finalize(),
1602 upcall_list: Self::CALLBACKS_SIZE,
1603 process_control_block: Self::PROCESS_STRUCT_SIZE,
1604 }
1605 }
1606
1607 fn print_full_process(&self, writer: &mut dyn Write) {
1608 if !config::CONFIG.debug_panics {
1609 return;
1610 }
1611
1612 self.stored_state.map(|stored_state| {
1613 // We guarantee the memory bounds pointers provided to the UKB are
1614 // correct.
1615 unsafe {
1616 self.chip.userspace_kernel_boundary().print_context(
1617 self.mem_start(),
1618 self.app_break.get(),
1619 stored_state,
1620 writer,
1621 );
1622 }
1623 });
1624
1625 // Display grant information.
1626 let number_grants = self.kernel.get_grant_count_and_finalize();
1627 let _ = writer.write_fmt(format_args!(
1628 "\
1629 \r\n Total number of grant regions defined: {}\r\n",
1630 self.kernel.get_grant_count_and_finalize()
1631 ));
1632 let rows = number_grants.div_ceil(3);
1633
1634 // Access our array of grant pointers.
1635 self.grant_pointers.map(|grant_pointers| {
1636 // Iterate each grant and show its address.
1637 for i in 0..rows {
1638 for j in 0..3 {
1639 let index = i + (rows * j);
1640 if index >= number_grants {
1641 break;
1642 }
1643
1644 // Implement `grant_pointers[grant_num]` without a chance of
1645 // a panic.
1646 grant_pointers.get(index).map(|grant_entry| {
1647 if grant_entry.grant_ptr.is_null() {
1648 let _ =
1649 writer.write_fmt(format_args!(" Grant {:>2} : -- ", index));
1650 } else {
1651 let _ = writer.write_fmt(format_args!(
1652 " Grant {:>2} {:#x}: {:p}",
1653 index, grant_entry.driver_num, grant_entry.grant_ptr
1654 ));
1655 }
1656 });
1657 }
1658 let _ = writer.write_fmt(format_args!("\r\n"));
1659 }
1660 });
1661
1662 // Display the current state of the MPU for this process.
1663 self.mpu_config.map(|config| {
1664 let _ = writer.write_fmt(format_args!("{}", config));
1665 });
1666
1667 // Print a helpful message on how to re-compile a process to view the
1668 // listing file. If a process is PIC, then we also need to print the
1669 // actual addresses the process executed at so that the .lst file can be
1670 // generated for those addresses. If the process was already compiled
1671 // for a fixed address, then just generating a .lst file is fine.
1672
1673 if self.debug.get_fixed_address_flash().is_some() {
1674 // Fixed addresses, can just run `make lst`.
1675 let _ = writer.write_fmt(format_args!(
1676 "\
1677 \r\nTo debug libtock-c apps, run `make lst` in the app's\
1678 \r\nfolder and open the arch.{:#x}.{:#x}.lst file.\r\n\r\n",
1679 self.debug.get_fixed_address_flash().unwrap_or(0),
1680 self.debug.get_fixed_address_ram().unwrap_or(0)
1681 ));
1682 } else {
1683 // PIC, need to specify the addresses.
1684 let sram_start = self.mem_start() as usize;
1685 let flash_start = self.flash.as_ptr() as usize;
1686 let flash_init_fn = flash_start + self.header.get_init_function_offset() as usize;
1687
1688 let _ = writer.write_fmt(format_args!(
1689 "\
1690 \r\nTo debug libtock-c apps, run\
1691 \r\n`make debug RAM_START={:#x} FLASH_INIT={:#x}`\
1692 \r\nin the app's folder and open the .lst file.\r\n\r\n",
1693 sram_start, flash_init_fn
1694 ));
1695 }
1696 }
1697
1698 fn get_stored_state(&self, out: &mut [u8]) -> Result<usize, ErrorCode> {
1699 self.stored_state
1700 .map(|stored_state| {
1701 self.chip
1702 .userspace_kernel_boundary()
1703 .store_context(stored_state, out)
1704 })
1705 .unwrap_or(Err(ErrorCode::FAIL))
1706 }
1707}
1708
1709impl<C: 'static + Chip, D: 'static + ProcessStandardDebug> ProcessStandard<'_, C, D> {
1710 /// Alignment requirement for each `GrantPointerEntry` in the grant pointers
1711 /// slice.
1712 const GRANT_POINTERS_ALIGNMENT: usize = mem::align_of::<GrantPointerEntry>();
1713
1714 /// Number of upcalls stored in the upcall ring buffer (10 element length).
1715 const CALLBACK_LEN: usize = 10;
1716 /// Size of the upcall storage buffer.
1717 ///
1718 /// As of June 2026, we cannot do
1719 ///
1720 /// ```ignore
1721 /// const CALLBACKS_SIZE usize = mem::size_of::<MaybeUninit<[Task; Self::CALLBACK_LEN]>>();
1722 /// ```
1723 ///
1724 /// because of the error:
1725 ///
1726 /// ```ignore
1727 /// error: generic `Self` types are currently not permitted in anonymous constants
1728 /// --> kernel/src/process_standard.rs:1712:70
1729 /// |
1730 /// 1712 | const CALLBACKS_SIZE: usize = mem::size_of::<MaybeUninit<[Task; Self::CALLBACK_LEN]>>();
1731 /// | ^^^^
1732 /// |
1733 /// ```
1734 const CALLBACKS_SIZE: usize = mem::size_of::<Task>() * Self::CALLBACK_LEN;
1735 /// Alignment requirement of the upcall storage buffer.
1736 const CALLBACKS_ALIGNMENT: usize = mem::align_of::<Task>();
1737
1738 // Memory offset to make room for this process's control block.
1739 const PROCESS_STRUCT_SIZE: usize = mem::size_of::<ProcessStandard<C, D>>();
1740 /// Alignment requirement for `ProcessStandard`.
1741 const PROCESS_STRUCT_ALIGNMENT: usize = mem::align_of::<ProcessStandard<C, D>>();
1742
1743 /// Create a `ProcessStandard` object based on the found `ProcessBinary`.
1744 pub(crate) unsafe fn create(
1745 kernel: &'static Kernel,
1746 chip: &'static C,
1747 pb: ProcessBinary,
1748 remaining_memory: *mut [u8],
1749 fault_policy: &'static dyn ProcessFaultPolicy,
1750 storage_permissions_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
1751 app_id: ShortId,
1752 index: usize,
1753 ) -> Result<(Option<&'static dyn Process>, *mut [u8]), (ProcessLoadError, *mut [u8])> {
1754 let process_name = pb.header.get_package_name();
1755 let process_ram_requested_size = pb.header.get_minimum_app_ram_size() as usize;
1756
1757 // Initialize MPU region configuration.
1758 let mut mpu_config = match chip.mpu().new_config() {
1759 Some(mpu_config) => mpu_config,
1760 None => return Err((ProcessLoadError::MpuConfigurationError, remaining_memory)),
1761 };
1762
1763 // Allocate MPU region for flash.
1764 if chip
1765 .mpu()
1766 .allocate_region(
1767 pb.flash.as_ptr(),
1768 pb.flash.len(),
1769 pb.flash.len(),
1770 mpu::Permissions::ReadExecuteOnly,
1771 &mut mpu_config,
1772 )
1773 .is_none()
1774 {
1775 if config::CONFIG.debug_load_processes {
1776 debug!(
1777 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't allocate MPU region for flash",
1778 pb.flash.as_ptr() as usize,
1779 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
1780 process_name
1781 );
1782 }
1783 return Err((ProcessLoadError::MpuInvalidFlashLength, remaining_memory));
1784 }
1785
1786 // Determine how much space we need in the application's memory space
1787 // just for kernel and grant state. We need to make sure we allocate
1788 // enough memory just for that.
1789
1790 // Calculate how many bytes we need for grant pointers.
1791 let grant_ptr_size = mem::size_of::<GrantPointerEntry>();
1792 let grant_ptrs_num = kernel.get_grant_count_and_finalize();
1793 let grant_ptrs_size = grant_ptrs_num * grant_ptr_size;
1794
1795 // Initial size of the kernel-owned part of process memory can be
1796 // calculated directly based on the initial size of all kernel-owned
1797 // data structures.
1798 //
1799 // Add the alignment size of each data structure to handle the case
1800 // where the memory region starts at the worst possible address and we
1801 // need to add padding. Note: the maximum shift will only ever be one
1802 // less than the alignment size, but to avoid unusual addresses we just
1803 // use the full alignment.
1804 let initial_kernel_memory_size = grant_ptrs_size
1805 + Self::GRANT_POINTERS_ALIGNMENT
1806 + Self::CALLBACKS_SIZE
1807 + Self::CALLBACKS_ALIGNMENT
1808 + Self::PROCESS_STRUCT_SIZE
1809 + Self::PROCESS_STRUCT_ALIGNMENT;
1810
1811 // By default we start with the initial size of process-accessible
1812 // memory set to 0. This maximizes the flexibility that processes have
1813 // to allocate their memory as they see fit. If a process needs more
1814 // accessible memory it must use the `brk` memop syscalls to request
1815 // more memory.
1816 //
1817 // We must take into account any process-accessible memory required by
1818 // the context switching implementation and allocate at least that much
1819 // memory so that we can successfully switch to the process. This is
1820 // architecture and implementation specific, so we query that now.
1821 let min_process_memory_size = chip
1822 .userspace_kernel_boundary()
1823 .initial_process_app_brk_size();
1824
1825 // We have to ensure that we at least ask the MPU for
1826 // `min_process_memory_size` so that we can be sure that `app_brk` is
1827 // not set inside the kernel-owned memory region. Now, in practice,
1828 // processes should not request 0 (or very few) bytes of memory in their
1829 // TBF header (i.e. `process_ram_requested_size` will almost always be
1830 // much larger than `min_process_memory_size`), as they are unlikely to
1831 // work with essentially no available memory. But, we still must protect
1832 // for that case.
1833 let min_process_ram_size = cmp::max(process_ram_requested_size, min_process_memory_size);
1834
1835 // Minimum memory size for the process.
1836 let min_total_memory_size = min_process_ram_size + initial_kernel_memory_size;
1837
1838 // Check if this process requires a fixed memory start address. If so,
1839 // try to adjust the memory region to work for this process.
1840 //
1841 // Right now, we only support skipping some RAM and leaving a chunk
1842 // unused so that the memory region starts where the process needs it
1843 // to.
1844 let remaining_memory = if let Some(fixed_memory_start) = pb
1845 .header
1846 .get_fixed_address_ram()
1847 .map(|addr: u32| remaining_memory.cast::<u8>().with_addr(addr as usize))
1848 {
1849 // The process does have a fixed address.
1850 if fixed_memory_start == remaining_memory.cast() {
1851 // Address already matches.
1852 remaining_memory
1853 } else if fixed_memory_start > remaining_memory.cast() {
1854 // Process wants a memory address farther in memory. Try to
1855 // advance the memory region to make the address match.
1856 let diff = fixed_memory_start.addr() - remaining_memory.addr();
1857 if diff > remaining_memory.len() {
1858 // We ran out of memory.
1859 let actual_address = (remaining_memory.cast::<u8>())
1860 .wrapping_byte_add(remaining_memory.len())
1861 .wrapping_byte_sub(1);
1862 let expected_address = fixed_memory_start;
1863 return Err((
1864 ProcessLoadError::MemoryAddressMismatch {
1865 actual_address,
1866 expected_address,
1867 },
1868 remaining_memory,
1869 ));
1870 } else {
1871 // Change the memory range to start where the process requested it.
1872 // Because of the if statement above we know this should work. Doing
1873 // it more cleanly would be good but was a bit beyond my borrow ken;
1874 // calling get_mut has a mutable borrow.-pal
1875 //
1876 // # Safety
1877 //
1878 // `diff` must be within the `remaining_memory` slice. Because we
1879 // check that `diff` is less than the length of `remaining_memory`
1880 // we know diff will be within `remaining_memory`.
1881 let (_, sliced) = unsafe { raw_slice_split_at_mut(remaining_memory, diff) };
1882 sliced
1883 }
1884 } else {
1885 // Address is earlier in memory, nothing we can do.
1886 let actual_address = remaining_memory.cast();
1887 let expected_address = fixed_memory_start;
1888 return Err((
1889 ProcessLoadError::MemoryAddressMismatch {
1890 actual_address,
1891 expected_address,
1892 },
1893 remaining_memory,
1894 ));
1895 }
1896 } else {
1897 remaining_memory
1898 };
1899
1900 // Determine where process memory will go and allocate an MPU region.
1901 //
1902 // `[allocation_start, allocation_size)` will cover both
1903 //
1904 // - the app-owned `min_process_memory_size`-long part of memory (at
1905 // some offset within `remaining_memory`), as well as
1906 //
1907 // - the kernel-owned allocation growing downward starting at the end
1908 // of this allocation, `initial_kernel_memory_size` bytes long.
1909 //
1910 let (allocation_start, allocation_size) = match chip.mpu().allocate_app_memory_region(
1911 remaining_memory.cast(),
1912 remaining_memory.len(),
1913 min_total_memory_size,
1914 min_process_memory_size,
1915 initial_kernel_memory_size,
1916 mpu::Permissions::ReadWriteOnly,
1917 &mut mpu_config,
1918 ) {
1919 Some((memory_start, memory_size)) => (memory_start, memory_size),
1920 None => {
1921 // Failed to load process. Insufficient memory.
1922 if config::CONFIG.debug_load_processes {
1923 debug!(
1924 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't allocate memory region of size >= {:#X}",
1925 pb.flash.as_ptr() as usize,
1926 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
1927 process_name,
1928 min_total_memory_size
1929 );
1930 }
1931 return Err((ProcessLoadError::NotEnoughMemory, remaining_memory));
1932 }
1933 };
1934
1935 // Determine the offset of the app-owned part of the above memory
1936 // allocation. An MPU may not place it at the very start of
1937 // `remaining_memory` for internal alignment constraints. This can only
1938 // overflow if the MPU implementation is incorrect; a compliant
1939 // implementation must return a memory allocation within the
1940 // `remaining_memory` slice.
1941 let app_memory_start_offset = allocation_start.addr() - remaining_memory.addr();
1942
1943 // Check if the memory region is valid for the process. If a process
1944 // included a fixed address for the start of RAM in its TBF header (this
1945 // field is optional, processes that are position independent do not
1946 // need a fixed address) then we check that we used the same address
1947 // when we allocated it in RAM.
1948 if let Some(fixed_memory_start) = pb
1949 .header
1950 .get_fixed_address_ram()
1951 .map(|addr: u32| remaining_memory.cast::<u8>().with_addr(addr as usize))
1952 {
1953 let actual_address = remaining_memory
1954 .cast::<u8>()
1955 .wrapping_byte_add(app_memory_start_offset);
1956 let expected_address = fixed_memory_start;
1957 if actual_address != expected_address {
1958 return Err((
1959 ProcessLoadError::MemoryAddressMismatch {
1960 actual_address,
1961 expected_address,
1962 },
1963 remaining_memory,
1964 ));
1965 }
1966 }
1967
1968 // With our MPU allocation, we can begin to divide up the
1969 // `remaining_memory` slice into individual regions for the process and
1970 // kernel, as follows:
1971 //
1972 //
1973 // ┌───────────────────────────────────────────────────────────────────────────────────────
1974 // │ remaining_memory
1975 // └───────────────────────────────────────────────────────────────────────────────────────
1976 // ┆ ┆
1977 // ┌────────────────────────────────────────────────────────────────────────┬──────────────
1978 // │ allocated_padded_memory │ unused_memory
1979 // └────────────────────────────────────────────────────────────────────────┴──────────────
1980 // ┆ ┆
1981 // ┌────────────────────────────────────────────────────────────────────┐
1982 // ┆←─→│ allocated_memory │
1983 // ↑ └────────────────────────────────────────────────────────────────────┘
1984 // └┄┄┄app_memory_start_offset ┆
1985 // ┌─────────────────────────┬──────────────────────────────────────────┐
1986 // │ app_accessible_memory │ allocated_kernel_memory │
1987 // └─────────────────────────┴──────────────────────────────────────────┘
1988 // ┆←min_process_memory_size→┆←────→┆←────initial_kernel_memory_size───→┆
1989 // ↑ ↑ ┆ ┆
1990 // initial_app_brk┄┄┄┘ ┆ ┆ ┌┄┄┄kernel_memory_break ┆
1991 // initially unallocated┄┄┄┘ ┆ ↓ ┆
1992 // ┆ ┌───────┬──────────┬──────────────┐
1993 // ┆↔│process│upcall_buf│grant_pointers│
1994 // ┆ └───────┴──────────┴──────────────┘
1995 // ↑ ↑ ↑ ↑
1996 // possible alignment padding┄┴┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
1997 //
1998 //
1999 // First split the `remaining_memory` into two slices:
2000 //
2001 // 1. `allocated_padded_memory`: the allocated memory region, containing:
2002 //
2003 // 1. optional padding at the start of the memory region of
2004 // `app_memory_start_offset` bytes,
2005 // 2. the app accessible memory region of `min_process_memory_size`,
2006 // 3. optional unallocated memory, and
2007 // 4. kernel-reserved memory, growing downward starting at the end of
2008 // `allocated_memory`.
2009 //
2010 // 2. `unused_memory`: the rest of the `remaining_memory`, not assigned
2011 // to this app.
2012 //
2013 // # Safety
2014 //
2015 // `app_memory_start_offset + allocation_size` must be within `remaining_memory`.
2016 let (allocated_padded_memory, unused_memory) = unsafe {
2017 raw_slice_split_at_mut(remaining_memory, app_memory_start_offset + allocation_size)
2018 };
2019
2020 // Now, slice off the (optional) padding at the start:
2021 //
2022 // # Safety
2023 //
2024 // `app_memory_start_offset` must be within `allocated_padded_memory`.
2025 let (_padding, allocated_memory) =
2026 unsafe { raw_slice_split_at_mut(allocated_padded_memory, app_memory_start_offset) };
2027
2028 // We continue to sub-slice the `allocated_memory` into
2029 // process-accessible and kernel-owned memory. Prior to that, store the
2030 // start and length ofthe overall allocation:
2031 let allocated_memory_start = allocated_memory.cast();
2032 let allocated_memory_len = allocated_memory.len();
2033
2034 // Slice off the process-accessible memory:
2035 //
2036 // # Safety
2037 //
2038 // `min_process_memory_size` must be within `allocated_memory`.
2039 let (app_accessible_memory, allocated_kernel_memory) =
2040 unsafe { raw_slice_split_at_mut(allocated_memory, min_process_memory_size) };
2041
2042 // Initialize (zero) the initial process-accessible memory region. This
2043 // serves two purposes:
2044 //
2045 // 1. It prevents a process from accessing any information still
2046 // contained in this memory from prior kernel instances or processes.
2047 //
2048 // 2. It satisfies Rust's requirements that all dereferencable memory be
2049 // properly initialized. This is important, as we'll be creating
2050 // references into this process-accessible memory region through the
2051 // process buffer infrastructure.
2052 let app_accessible_memory_bytes: *mut u8 = app_accessible_memory.cast();
2053 // # Safety
2054 //
2055 // `app_accessible_memory_bytes` is from a slice, and we use that
2056 // slice's length, so we know that there is enough memory and that the
2057 // pointer is aligned.
2058 unsafe {
2059 core::ptr::write_bytes(
2060 app_accessible_memory_bytes,
2061 // Set the entire app-accessible memory region to `0`:
2062 0_u8,
2063 app_accessible_memory.len(),
2064 );
2065 }
2066
2067 // Set the initial process-accessible memory.
2068 //
2069 // # Safety
2070 //
2071 // By using the slice `app_accessible_memory` and getting a pointer to
2072 // the byte after the slice, we are ensured that the memory between the
2073 // start of the allocation and the new pointer (at the end of the slice)
2074 // is valid because of the existing slice.
2075 let initial_app_brk = unsafe {
2076 app_accessible_memory
2077 .cast::<u8>()
2078 .add(app_accessible_memory.len())
2079 };
2080
2081 // Set the initial allow high water mark to the start of process memory
2082 // since no `allow` calls have been made yet.
2083 let initial_allow_high_water_mark = app_accessible_memory.cast();
2084
2085 // Set up initial grant region.
2086 //
2087 // `kernel_memory_break` is set to the end of kernel-accessible memory
2088 // and grows downward.
2089 let mut kernel_memory_break: *mut u8 = allocated_kernel_memory
2090 .cast::<u8>()
2091 .wrapping_add(allocated_kernel_memory.len());
2092
2093 ////////////////////////
2094 // Grant Region Pointers
2095 ////////////////////////
2096
2097 // Now that we know we have the space we can setup the grant pointers.
2098 //
2099 // First, move `kernel_memory_break` up to make room for the grant pointers.
2100 kernel_memory_break = kernel_memory_break.wrapping_sub(grant_ptrs_size);
2101 // Next, use the extra alignment padding we factored in to the total
2102 // calculation of `initial_kernel_memory_size` to ensure that
2103 // `kernel_memory_break` is aligned to a `GrantPointerEntry`.
2104 kernel_memory_break = kernel_memory_break
2105 .wrapping_sub(kernel_memory_break as usize % Self::GRANT_POINTERS_ALIGNMENT);
2106
2107 // Create the `GrantPointerEntry`s in the kernel region, then initialize
2108 // them.
2109 //
2110 // Where we calculated the updated kernel_memory_break is where the
2111 // `GrantPointerEntry`s start.
2112 let grant_pointers_memory_location: *mut MaybeUninit<GrantPointerEntry> =
2113 kernel_memory_break.cast();
2114 // Get a reference to the slice of `GrantPointerEntry`s.
2115 //
2116 // # Safety
2117 //
2118 // This is safe, as `grant_pointers_memory_location` is aligned to a
2119 // `GrantPointerEntry`, and we ensured there is space for
2120 // `grant_ptrs_num` of `GrantPointerEntry`s allocated.
2121 let grant_pointers_uninit: &mut [MaybeUninit<GrantPointerEntry>] =
2122 unsafe { slice::from_raw_parts_mut(grant_pointers_memory_location, grant_ptrs_num) };
2123 // Set all grant pointers to null.
2124 for grant_entry in grant_pointers_uninit.iter_mut() {
2125 grant_entry.write(GrantPointerEntry {
2126 driver_num: 0,
2127 grant_ptr: core::ptr::null_mut(),
2128 });
2129 }
2130 // # Safety
2131 //
2132 // All values in this slice have been properly initialized.
2133 let grant_pointers = unsafe { maybe_uninit_slice_assume_init_mut(grant_pointers_uninit) };
2134
2135 ////////////////////////
2136 // Upcall Queue
2137 ////////////////////////
2138
2139 // Now that we know we have the space we can setup the memory for the
2140 // upcalls.
2141 //
2142 // Move our `kernel_memory_break` up the size of the callback slice.
2143 kernel_memory_break = kernel_memory_break.wrapping_sub(Self::CALLBACKS_SIZE);
2144 // Use the space we allocated for alignment in case the pointer is not aligned.
2145 kernel_memory_break = kernel_memory_break
2146 .wrapping_sub(kernel_memory_break as usize % Self::CALLBACKS_ALIGNMENT);
2147
2148 // Set up ring buffer for upcalls to the process. The memory is uninitialized here,
2149 // so we cast to MaybeUninit<Task> which accurately represents that state.
2150 let upcall_buf: *mut core::mem::MaybeUninit<Task> = kernel_memory_break.cast();
2151
2152 // Get a reference `&mut [Task; Self:CALLBACK_LEN]`
2153 //
2154 // # Safety
2155 //
2156 // This needs to be aligned and have allocated space for
2157 // `Self::CALLBACK_LEN` instances of `Task`. We ensured there is enough
2158 // space when we allocated `allocated_kernel_memory` and we moved
2159 // kernel_memory_break up to fit the callbacks. We ensured this is
2160 // aligned by moving `kernel_memory_break` up if needed, and we
2161 // accounted for that potential increase in size when we allocated
2162 // `allocated_kernel_memory`.
2163 let upcall_buf = unsafe { slice::from_raw_parts_mut(upcall_buf, Self::CALLBACK_LEN) };
2164 // Actually setup the ring buffer.
2165 let tasks = RingBuffer::new(upcall_buf);
2166
2167 ////////////////////////
2168 // ProcessStandard
2169 ////////////////////////
2170
2171 // Last thing in the kernel region of process RAM is the process struct.
2172 //
2173 // Move `kernel_memory_break` to make room for the `ProcessStandard` struct.
2174 kernel_memory_break = kernel_memory_break.wrapping_sub(Self::PROCESS_STRUCT_SIZE);
2175 // Use the space we allocated for alignment in case the pointer is not aligned.
2176 kernel_memory_break = kernel_memory_break
2177 .wrapping_sub(kernel_memory_break as usize % Self::PROCESS_STRUCT_ALIGNMENT);
2178
2179 // Create a pointer to where the `ProcessStandard` struct will go in the
2180 // app grant region.
2181 let process_struct_memory_location: *mut MaybeUninit<ProcessStandard<'static, C, D>> =
2182 kernel_memory_break.cast();
2183 // Get a reference to the uninitialized `ProcessStandard` object.
2184 //
2185 // Note, this requires every field be explicitly initialized, as we are
2186 // just transforming a pointer into a structure. Because the
2187 // `ProcessStandard` is not initialized we mark it with `MaybeUninit`.
2188 //
2189 // # Safety
2190 //
2191 // This must have sufficient allocated space and proper alignment. When
2192 // we sized `allocated_kernel_memory` we ensured there was room for the
2193 // entire `ProcessStandard` struct. We also allocated space for
2194 // potential alignment issues, and ensured `kernel_memory_break` was
2195 // properly aligned for `ProcessStandard`.
2196 let process_uninit: &mut MaybeUninit<ProcessStandard<C, D>> =
2197 unsafe { &mut *process_struct_memory_location };
2198
2199 // Initialize ALL fields of `ProcessStandard`.
2200 //
2201 // # Safety
2202 //
2203 // These need to be valid and aligned writes. When we create the `MaybeUnint`
2204 // ProcessStandard struct we ensure there is valid memory for the object and
2205 // that it is aligned.
2206 unsafe {
2207 init_uninit_struct!(process_uninit => ProcessStandard<C, D> {
2208 process_id: Cell::new(ProcessId::new(
2209 kernel,
2210 kernel.create_process_identifier(),
2211 index,
2212 )),
2213 app_id: app_id,
2214 kernel: kernel,
2215 chip: chip,
2216 allow_high_water_mark: Cell::new(initial_allow_high_water_mark),
2217 memory_start: allocated_memory_start,
2218 memory_len: allocated_memory_len,
2219 header: pb.header,
2220 kernel_memory_break: Cell::new(kernel_memory_break),
2221 app_break: Cell::new(initial_app_brk),
2222 grant_pointers: MapCell::new(grant_pointers),
2223
2224 credential: pb.credential.get(),
2225 footers: pb.footers,
2226 flash: pb.flash,
2227
2228 stored_state: MapCell::new(Default::default()),
2229 state: Cell::new(State::Yielded),
2230 fault_policy: fault_policy,
2231 restart_count: Cell::new(0),
2232 completion_code: OptionalCell::empty(),
2233
2234 storage_permissions: Cell::new(StoragePermissions::new_null()),
2235
2236 mpu_config: MapCell::new(mpu_config),
2237 mpu_regions: [
2238 Cell::new(None),
2239 Cell::new(None),
2240 Cell::new(None),
2241 Cell::new(None),
2242 Cell::new(None),
2243 Cell::new(None),
2244 ],
2245 tasks: MapCell::new(tasks),
2246 is_yield_wait_for_ready: Cell::new(false),
2247
2248 debug: D::default(),
2249 });
2250 }
2251
2252 // Convert the originally uninitialized `ProcessStandard` to a proper
2253 // `ProcessStandard` struct reference.
2254 //
2255 // # Safety
2256 //
2257 // All fields in `ProcessStandard` must be initialized. We guaranteed
2258 // this by using the `init_uninit_struct!()` macro, which causes a
2259 // compiler error if there is a missing field.
2260 let process = unsafe { process_uninit.assume_init_mut() };
2261
2262 // Save copies of these in case the app was compiled for fixed addresses
2263 // for later debugging.
2264 let fixed_address_flash = process.header.get_fixed_address_flash();
2265 let fixed_address_ram = process.header.get_fixed_address_ram();
2266 if let Some(fix_addr_flash) = fixed_address_flash {
2267 process.debug.set_fixed_address_flash(fix_addr_flash);
2268 }
2269 if let Some(fix_addr_ram) = fixed_address_ram {
2270 process.debug.set_fixed_address_ram(fix_addr_ram);
2271 }
2272
2273 // Handle any architecture-specific requirements for a new process.
2274 match process.stored_state.map(|stored_state| {
2275 // # Safety
2276 //
2277 // NOTE! We have to ensure that the start of process-accessible memory
2278 // (`app_memory_start`) is word-aligned. Since we currently start
2279 // process-accessible memory at the beginning of the allocated memory
2280 // region, we trust the MPU to give us a word-aligned starting address.
2281 //
2282 // TODO: https://github.com/tock/tock/issues/1739
2283 unsafe {
2284 chip.userspace_kernel_boundary().initialize_process(
2285 app_accessible_memory.cast(),
2286 initial_app_brk,
2287 stored_state,
2288 )
2289 }
2290 }) {
2291 Some(Ok(())) => {}
2292 _ => {
2293 if config::CONFIG.debug_load_processes {
2294 debug!(
2295 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't initialize process",
2296 pb.flash.as_ptr() as usize,
2297 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
2298 process_name
2299 );
2300 }
2301 // Note that since remaining_memory was split by split_at_mut into
2302 // application memory and unused_memory, a failure here will leak
2303 // the application memory. Not leaking it requires being able to
2304 // reconstitute the original memory slice.
2305 return Err((ProcessLoadError::InternalError, unused_memory));
2306 }
2307 }
2308
2309 let flash_start = process.flash.as_ptr();
2310 let app_start =
2311 flash_start.wrapping_add(process.header.get_app_start_offset() as usize) as usize;
2312 let init_addr =
2313 flash_start.wrapping_add(process.header.get_init_function_offset() as usize) as usize;
2314 let fn_base = flash_start as usize;
2315 let fn_len = process.flash.len();
2316
2317 // We need to construct a capability with sufficient authority to cover
2318 // all of a user's code, with permissions to execute it. The entirety of
2319 // flash is sufficient.
2320 //
2321 // # Safety
2322 //
2323 // TODO? I don't understand the `new_with_authority()` safety block as
2324 // it doesn't define what the caller must do.
2325 let init_fn = unsafe {
2326 CapabilityPtr::new_with_authority(
2327 init_addr as *const (),
2328 fn_base,
2329 fn_len,
2330 CapabilityPtrPermissions::Execute,
2331 )
2332 };
2333
2334 process.tasks.map(|tasks| {
2335 tasks.enqueue(Task::FunctionCall(FunctionCall {
2336 source: FunctionCallSource::Kernel,
2337 pc: init_fn,
2338 argument0: app_start,
2339 argument1: process.memory_start as usize,
2340 argument2: process.memory_len,
2341 argument3: (process.app_break.get() as usize).into(),
2342 }));
2343 });
2344
2345 // Set storage permissions. Put this at the end so that `process` is
2346 // completely formed before using it to determine the storage
2347 // permissions.
2348 process
2349 .storage_permissions
2350 .set(storage_permissions_policy.get_permissions(process));
2351
2352 // Return the process object and a remaining memory for processes slice.
2353 Ok((Some(process), unused_memory))
2354 }
2355
2356 /// Reset the process, resetting all of its state and re-initializing it so
2357 /// it can start running. Assumes the process is not running but is still in
2358 /// flash and still has its memory region allocated to it.
2359 fn reset(&self) -> Result<(), ErrorCode> {
2360 // We need a new process identifier for this process since the restarted
2361 // version is in effect a new process. This is also necessary to
2362 // invalidate any stored `ProcessId`s that point to the old version of
2363 // the process. However, the process has not moved locations in the
2364 // processes array, so we copy the existing index.
2365 let old_index = self.process_id.get().index;
2366 let new_identifier = self.kernel.create_process_identifier();
2367 self.process_id
2368 .set(ProcessId::new(self.kernel, new_identifier, old_index));
2369
2370 // Reset debug information that is per-execution and not per-process.
2371 self.debug.reset_last_syscall();
2372 self.debug.reset_syscall_count();
2373 self.debug.reset_dropped_upcall_count();
2374 self.debug.reset_timeslice_expiration_count();
2375
2376 // Reset MPU region configuration.
2377 //
2378 // TODO: ideally, this would be moved into a helper function used by
2379 // both create() and reset(), but process load debugging complicates
2380 // this. We just want to create new config with only flash and memory
2381 // regions.
2382 //
2383 // We must have a previous MPU configuration stored, fault the
2384 // process if this invariant is violated. We avoid allocating
2385 // a new MPU configuration, as this may eventually exhaust the
2386 // number of available MPU configurations.
2387 let mut mpu_config = self.mpu_config.take().ok_or(ErrorCode::FAIL)?;
2388 self.chip.mpu().reset_config(&mut mpu_config);
2389
2390 // Allocate MPU region for flash.
2391 let app_mpu_flash = self.chip.mpu().allocate_region(
2392 self.flash.as_ptr(),
2393 self.flash.len(),
2394 self.flash.len(),
2395 mpu::Permissions::ReadExecuteOnly,
2396 &mut mpu_config,
2397 );
2398 if app_mpu_flash.is_none() {
2399 // We were unable to allocate an MPU region for flash. This is very
2400 // unexpected since we previously ran this process. However, we
2401 // return now and leave the process faulted and it will not be
2402 // scheduled.
2403 return Err(ErrorCode::FAIL);
2404 }
2405
2406 // RAM
2407
2408 // Re-determine the minimum amount of RAM the kernel must allocate to
2409 // the process based on the specific requirements of the syscall
2410 // implementation.
2411 let min_process_memory_size = self
2412 .chip
2413 .userspace_kernel_boundary()
2414 .initial_process_app_brk_size();
2415
2416 // Recalculate initial_kernel_memory_size as was done in create()
2417 let grant_ptr_size = mem::size_of::<GrantPointerEntry>();
2418 let grant_ptrs_num = self.kernel.get_grant_count_and_finalize();
2419 let grant_ptrs_size = grant_ptrs_num * grant_ptr_size;
2420
2421 let initial_kernel_memory_size = grant_ptrs_size
2422 + Self::GRANT_POINTERS_ALIGNMENT
2423 + Self::CALLBACKS_SIZE
2424 + Self::CALLBACKS_ALIGNMENT
2425 + Self::PROCESS_STRUCT_SIZE
2426 + Self::PROCESS_STRUCT_ALIGNMENT;
2427
2428 let app_mpu_mem = self.chip.mpu().allocate_app_memory_region(
2429 self.mem_start(),
2430 self.memory_len,
2431 self.memory_len, //we want exactly as much as we had before restart
2432 min_process_memory_size,
2433 initial_kernel_memory_size,
2434 mpu::Permissions::ReadWriteOnly,
2435 &mut mpu_config,
2436 );
2437 let (app_mpu_mem_start, app_mpu_mem_len) = match app_mpu_mem {
2438 Some((start, len)) => (start, len),
2439 None => {
2440 // We couldn't configure the MPU for the process. This shouldn't
2441 // happen since we were able to start the process before, but at
2442 // this point it is better to leave the app faulted and not
2443 // schedule it.
2444 return Err(ErrorCode::NOMEM);
2445 }
2446 };
2447
2448 // Reset memory pointers now that we know the layout of the process
2449 // memory and know that we can configure the MPU.
2450
2451 // app_brk is set based on minimum syscall size above the start of
2452 // memory.
2453 let app_brk = app_mpu_mem_start.wrapping_add(min_process_memory_size);
2454 self.app_break.set(app_brk);
2455 // kernel_brk is calculated backwards from the end of memory the size of
2456 // the initial kernel data structures.
2457 let kernel_brk = app_mpu_mem_start
2458 .wrapping_add(app_mpu_mem_len)
2459 .wrapping_sub(initial_kernel_memory_size);
2460 self.kernel_memory_break.set(kernel_brk);
2461 // High water mark for `allow`ed memory is reset to the start of the
2462 // process's memory region.
2463 self.allow_high_water_mark.set(app_mpu_mem_start);
2464
2465 // Store the adjusted MPU configuration:
2466 self.mpu_config.replace(mpu_config);
2467
2468 // Handle any architecture-specific requirements for a process when it
2469 // first starts (as it would when it is new).
2470 let ukb_init_process = self.stored_state.map_or(Err(()), |stored_state| unsafe {
2471 self.chip.userspace_kernel_boundary().initialize_process(
2472 app_mpu_mem_start,
2473 app_brk,
2474 stored_state,
2475 )
2476 });
2477 match ukb_init_process {
2478 Ok(()) => {}
2479 Err(()) => {
2480 // We couldn't initialize the architecture-specific state for
2481 // this process. This shouldn't happen since the app was able to
2482 // be started before, but at this point the app is no longer
2483 // valid. The best thing we can do now is leave the app as still
2484 // faulted and not schedule it.
2485 return Err(ErrorCode::RESERVE);
2486 }
2487 }
2488
2489 self.restart_count.increment();
2490
2491 // Mark the state as `Yielded` for the scheduler.
2492 self.state.set(State::Yielded);
2493
2494 // And queue up this app to be restarted.
2495 let flash_start = self.flash_start();
2496 let app_start =
2497 flash_start.wrapping_add(self.header.get_app_start_offset() as usize) as usize;
2498 let init_addr =
2499 flash_start.wrapping_add(self.header.get_init_function_offset() as usize) as usize;
2500
2501 // We need to construct a capability with sufficient authority to cover all of a user's
2502 // code, with permissions to execute it. The entirety of flash is sufficient.
2503
2504 let init_fn = unsafe {
2505 CapabilityPtr::new_with_authority(
2506 init_addr as *const (),
2507 flash_start as usize,
2508 (self.flash_end() as usize) - (flash_start as usize),
2509 CapabilityPtrPermissions::Execute,
2510 )
2511 };
2512
2513 self.enqueue_task(Task::FunctionCall(FunctionCall {
2514 source: FunctionCallSource::Kernel,
2515 pc: init_fn,
2516 argument0: app_start,
2517 argument1: self.memory_start as usize,
2518 argument2: self.memory_len,
2519 argument3: (self.app_break.get() as usize).into(),
2520 }))
2521 }
2522
2523 /// Checks if the buffer represented by the passed in base pointer and size
2524 /// is within the RAM bounds currently exposed to the processes (i.e. ending
2525 /// at `app_break`). If this method returns `true`, the buffer is guaranteed
2526 /// to be accessible to the process and to not overlap with the grant
2527 /// region.
2528 fn in_app_owned_memory(&self, buf_start_addr: *const u8, size: usize) -> bool {
2529 // TODO: On some platforms, CapabilityPtr has sufficient authority that we
2530 // could skip this check.
2531 // CapabilityPtr needs to make it slightly further, and we need to add
2532 // interfaces that tell us how much assurance it gives on the current
2533 // platform.
2534 let buf_end_addr = buf_start_addr.wrapping_add(size);
2535
2536 buf_end_addr >= buf_start_addr
2537 && buf_start_addr >= self.mem_start()
2538 && buf_end_addr <= self.app_break.get()
2539 }
2540
2541 /// Checks if the buffer represented by the passed in base pointer and size
2542 /// are within the readable region of an application's flash memory. If
2543 /// this method returns true, the buffer is guaranteed to be readable to the
2544 /// process.
2545 fn in_app_flash_memory(&self, buf_start_addr: *const u8, size: usize) -> bool {
2546 // TODO: On some platforms, CapabilityPtr has sufficient authority that we
2547 // could skip this check.
2548 // CapabilityPtr needs to make it slightly further, and we need to add
2549 // interfaces that tell us how much assurance it gives on the current
2550 // platform.
2551 let buf_end_addr = buf_start_addr.wrapping_add(size);
2552
2553 buf_end_addr >= buf_start_addr
2554 && buf_start_addr >= self.flash_non_protected_start()
2555 && buf_end_addr <= self.flash_end()
2556 }
2557
2558 /// Reset all `grant_ptr`s to NULL.
2559 unsafe fn grant_ptrs_reset(&self) {
2560 self.grant_pointers.map(|grant_pointers| {
2561 for grant_entry in grant_pointers.iter_mut() {
2562 grant_entry.driver_num = 0;
2563 grant_entry.grant_ptr = ptr::null_mut();
2564 }
2565 });
2566 }
2567
2568 /// Allocate memory in a process's grant region.
2569 ///
2570 /// Ensures that the allocation is of `size` bytes and aligned to `align`
2571 /// bytes.
2572 ///
2573 /// If there is not enough memory, or the MPU cannot isolate the process
2574 /// accessible region from the new kernel memory break after doing the
2575 /// allocation, then this will return `None`.
2576 fn allocate_in_grant_region_internal(&self, size: usize, align: usize) -> Option<NonNull<u8>> {
2577 self.mpu_config.and_then(|config| {
2578 // First, compute the candidate new pointer. Note that at this point
2579 // we have not yet checked whether there is space for this
2580 // allocation or that it meets alignment requirements.
2581 let new_break_unaligned = self.kernel_memory_break.get().wrapping_sub(size);
2582
2583 // Our minimum alignment requirement is two bytes, so that the
2584 // lowest bit of the address will always be zero and we can use it
2585 // as a flag. It doesn't hurt to increase the alignment (except for
2586 // potentially a wasted byte) so we make sure `align` is at least
2587 // two.
2588 let align = cmp::max(align, 2);
2589
2590 // The alignment must be a power of two, 2^a. The expression
2591 // `!(align - 1)` then returns a mask with leading ones, followed by
2592 // `a` trailing zeros.
2593 let alignment_mask = !(align - 1);
2594 let new_break = (new_break_unaligned as usize & alignment_mask) as *const u8;
2595
2596 // Verify there is space for this allocation
2597 if new_break < self.app_break.get() {
2598 None
2599 // Verify it didn't wrap around
2600 } else if new_break > self.kernel_memory_break.get() {
2601 None
2602 // Verify this is compatible with the MPU.
2603 } else if let Err(()) = self.chip.mpu().update_app_memory_region(
2604 self.app_break.get(),
2605 new_break,
2606 mpu::Permissions::ReadWriteOnly,
2607 config,
2608 ) {
2609 None
2610 } else {
2611 // Allocation is valid.
2612
2613 // We always allocate down, so we must lower the
2614 // kernel_memory_break.
2615 self.kernel_memory_break.set(new_break);
2616
2617 // We need `grant_ptr` as a mutable pointer.
2618 let grant_ptr: *mut u8 = new_break.cast_mut();
2619
2620 // ### Safety
2621 //
2622 // Here we are guaranteeing that `grant_ptr` is not null. We can
2623 // ensure this because we just created `grant_ptr` based on the
2624 // process's allocated memory, and we know it cannot be null.
2625 unsafe { Some(NonNull::new_unchecked(grant_ptr)) }
2626 }
2627 })
2628 }
2629
2630 /// Create the identifier for a custom grant that grant.rs uses to access
2631 /// the custom grant.
2632 ///
2633 /// We create this identifier by calculating the number of bytes between
2634 /// where the custom grant starts and the end of the process memory.
2635 fn create_custom_grant_identifier(&self, ptr: NonNull<u8>) -> ProcessCustomGrantIdentifier {
2636 let custom_grant_address = ptr.as_ptr() as usize;
2637 let process_memory_end = self.mem_end() as usize;
2638
2639 ProcessCustomGrantIdentifier {
2640 offset: process_memory_end - custom_grant_address,
2641 }
2642 }
2643
2644 /// Use a `ProcessCustomGrantIdentifier` to find the address of the
2645 /// custom grant.
2646 ///
2647 /// This reverses `create_custom_grant_identifier()`.
2648 fn get_custom_grant_address(&self, identifier: ProcessCustomGrantIdentifier) -> usize {
2649 let process_memory_end = self.mem_end() as usize;
2650
2651 // Subtract the offset in the identifier from the end of the process
2652 // memory to get the address of the custom grant.
2653 process_memory_end - identifier.offset
2654 }
2655
2656 /// Return the app's read and modify storage permissions from the TBF header
2657 /// if it exists.
2658 ///
2659 /// If the header does not exist then return `None`. If the header does
2660 /// exist, this returns a 5-tuple with:
2661 ///
2662 /// - `write_allowed`: bool. If this process should have write permissions.
2663 /// - `read_count`: usize. How many read IDs are valid.
2664 /// - `read_ids`: [u32]. The read IDs.
2665 /// - `modify_count`: usze. How many modify IDs are valid.
2666 /// - `modify_ids`: [u32]. The modify IDs.
2667 pub fn get_tbf_storage_permissions(&self) -> Option<(bool, usize, [u32; 8], usize, [u32; 8])> {
2668 let read_perms = self.header.get_storage_read_ids();
2669 let modify_perms = self.header.get_storage_modify_ids();
2670
2671 match (read_perms, modify_perms) {
2672 (Some((read_count, read_ids)), Some((modify_count, modify_ids))) => Some((
2673 self.header.get_storage_write_id().is_some(),
2674 read_count,
2675 read_ids,
2676 modify_count,
2677 modify_ids,
2678 )),
2679 _ => None,
2680 }
2681 }
2682
2683 /// The start address of allocated RAM for this process.
2684 fn mem_start(&self) -> *const u8 {
2685 self.memory_start
2686 }
2687
2688 /// The first address after the end of the allocated RAM for this process.
2689 fn mem_end(&self) -> *const u8 {
2690 self.memory_start.wrapping_add(self.memory_len)
2691 }
2692
2693 /// The start address of the flash region allocated for this process.
2694 fn flash_start(&self) -> *const u8 {
2695 self.flash.as_ptr()
2696 }
2697
2698 /// Get the first address of process's flash that isn't protected by the
2699 /// kernel. The protected range of flash contains the TBF header and
2700 /// potentially other state the kernel is storing on behalf of the process,
2701 /// and cannot be edited by the process.
2702 fn flash_non_protected_start(&self) -> *const u8 {
2703 ((self.flash.as_ptr() as usize) + self.header.get_protected_size() as usize) as *const u8
2704 }
2705
2706 /// The first address after the end of the flash region allocated for this
2707 /// process.
2708 fn flash_end(&self) -> *const u8 {
2709 self.flash.as_ptr().wrapping_add(self.flash.len())
2710 }
2711
2712 /// The lowest address of the grant region for the process.
2713 fn kernel_memory_break(&self) -> *const u8 {
2714 self.kernel_memory_break.get()
2715 }
2716
2717 /// Return the highest address the process has access to, or the current
2718 /// process memory brk.
2719 fn app_memory_break(&self) -> *const u8 {
2720 self.app_break.get()
2721 }
2722}