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 let opt_this_upcall_id = match task {
609 Task::FunctionCall(FunctionCall {
610 source: FunctionCallSource::Driver(upcall_id),
611 ..
612 }) => Some(upcall_id),
613 Task::ReturnValue(ReturnArguments { upcall_id, .. }) => Some(upcall_id),
614 _ => None,
615 };
616
617 // If the process is yielded-for this task, set the ready flag.
618 //
619 // In case the process is yielding for another upcall, don't
620 // clear the flag; this would re-introduce the race
621 // condition of #5195.
622 if let State::YieldedFor(yielded_upcall_id) = self.state.get()
623 && let Some(this_upcall_id) = opt_this_upcall_id
624 && yielded_upcall_id == this_upcall_id
625 {
626 self.is_yield_wait_for_ready.set(true);
627 }
628
629 // The task has been successfully enqueued.
630 Ok(())
631 }
632 false => {
633 // The task could not be enqueued as there is
634 // insufficient space in the ring buffer.
635 Err(ErrorCode::NOMEM)
636 }
637 }
638 });
639
640 if ret.is_err() {
641 // On any error we were unable to enqueue the task. Record the
642 // error, but importantly do _not_ increment kernel work.
643 self.debug.increment_dropped_upcall_count();
644 }
645
646 ret
647 }
648
649 fn ready(&self) -> bool {
650 match self.state.get() {
651 State::Running => true,
652 State::YieldedFor(_) => self.is_yield_wait_for_ready.get(),
653 State::Yielded => self.tasks.map_or(false, |ring_buf| ring_buf.has_elements()),
654 _ => false,
655 }
656 }
657
658 fn remove_pending_upcalls(&self, upcall_id: UpcallId) -> usize {
659 self.tasks.map_or(0, |tasks| {
660 let count_before = tasks.len();
661 tasks.retain(|task| match task {
662 // Remove only tasks that are function calls with an id equal
663 // to `upcall_id`.
664 Task::FunctionCall(function_call) => match function_call.source {
665 FunctionCallSource::Kernel => true,
666 FunctionCallSource::Driver(id) => id != upcall_id,
667 },
668 _ => true,
669 });
670 let count_after = tasks.len();
671 if config::CONFIG.trace_syscalls {
672 debug!(
673 "[{:?}] remove_pending_upcalls[{:#x}:{}] = {} upcall(s) removed",
674 self.processid(),
675 upcall_id.driver_num,
676 upcall_id.subscribe_num,
677 count_before - count_after,
678 );
679 }
680 count_before - count_after
681 })
682 }
683
684 fn is_running(&self) -> bool {
685 match self.state.get() {
686 State::Running | State::Yielded | State::YieldedFor(_) | State::Stopped(_) => true,
687 _ => false,
688 }
689 }
690
691 fn get_state(&self) -> State {
692 self.state.get()
693 }
694
695 fn set_yielded_state(&self) {
696 if self.state.get() == State::Running {
697 self.state.set(State::Yielded);
698 }
699 }
700
701 fn set_yielded_for_state(&self, upcall_id: UpcallId) {
702 if self.state.get() == State::Running
703 || self.state.get() == State::Stopped(StoppedState::YieldedFor(upcall_id))
704 {
705 self.state.set(State::YieldedFor(upcall_id));
706
707 // Verify if the process has a task that this yield waits for
708 self.is_yield_wait_for_ready
709 .set(self.tasks.map_or(false, |tasks| {
710 tasks
711 .find_first_matching(|task| match task {
712 Task::ReturnValue(ReturnArguments { upcall_id: id, .. }) => {
713 upcall_id == *id
714 }
715 Task::FunctionCall(FunctionCall {
716 source: FunctionCallSource::Driver(id),
717 ..
718 }) => upcall_id == *id,
719 _ => false,
720 })
721 .is_some()
722 }));
723 }
724 }
725
726 fn stop(&self) {
727 match self.state.get() {
728 State::Running => self.state.set(State::Stopped(StoppedState::Running)),
729 State::Yielded => self.state.set(State::Stopped(StoppedState::Yielded)),
730 State::YieldedFor(upcall_id) => self
731 .state
732 .set(State::Stopped(StoppedState::YieldedFor(upcall_id))),
733 State::Stopped(_stopped_state) => {
734 // Already stopped, nothing to do.
735 }
736 State::Faulted | State::Terminated => {
737 // Stop has no meaning on a inactive process.
738 }
739 }
740 }
741
742 fn resume(&self) {
743 if let State::Stopped(stopped_state) = self.state.get() {
744 match stopped_state {
745 StoppedState::Running => self.state.set(State::Running),
746 StoppedState::Yielded => self.state.set(State::Yielded),
747 StoppedState::YieldedFor(upcall_id) => self.set_yielded_for_state(upcall_id),
748 }
749 }
750 }
751
752 fn set_fault_state(&self) {
753 // Use the per-process fault policy to determine what action the kernel
754 // should take since the process faulted.
755 let action = self.fault_policy.action(self);
756 match action {
757 FaultAction::Panic => {
758 // process faulted. Panic and print status
759 self.state.set(State::Faulted);
760 panic!("Process {} had a fault", self.get_process_name());
761 }
762 FaultAction::Restart => {
763 self.try_restart(None);
764 }
765 FaultAction::Stop => {
766 // This looks a lot like restart, except we just leave the app
767 // how it faulted and mark it as `Faulted`. By clearing
768 // all of the app's todo work it will not be scheduled, and
769 // clearing all of the grant regions will cause capsules to drop
770 // this app as well.
771 self.terminate(None);
772 self.state.set(State::Faulted);
773 }
774 }
775 }
776
777 fn start(&self, _cap: &dyn crate::capabilities::ProcessStartCapability) {
778 // `start()` can only be called on a terminated process.
779 if self.get_state() != State::Terminated {
780 return;
781 }
782
783 // Reset to start the process.
784 if let Ok(()) = self.reset() {
785 self.state.set(State::Yielded);
786 }
787 }
788
789 fn try_restart(&self, completion_code: Option<u32>) {
790 // `try_restart()` cannot be called if the process is terminated. Only
791 // `start()` can start a terminated process.
792 if self.get_state() == State::Terminated {
793 return;
794 }
795
796 // Terminate the process, freeing its state and removing any
797 // pending tasks from the scheduler's queue.
798 self.terminate(completion_code);
799
800 // If there is a kernel policy that controls restarts, it should be
801 // implemented here. For now, always restart.
802 if let Ok(()) = self.reset() {
803 self.state.set(State::Yielded);
804 }
805
806 // Decide what to do with res later. E.g., if we can't restart
807 // want to reclaim the process resources.
808 }
809
810 fn terminate(&self, completion_code: Option<u32>) {
811 // A process can be terminated if it is running or in the `Faulted`
812 // state. Otherwise, you cannot terminate it and this method return
813 // early.
814 //
815 // The kernel can terminate in the `Faulted` state to return the process
816 // to a state in which it can run again (e.g., reset it).
817 if !self.is_running() && self.get_state() != State::Faulted {
818 return;
819 }
820
821 // And remove those tasks
822 self.tasks.map(|tasks| {
823 tasks.empty();
824 });
825
826 // Clear any grant regions this app has setup with any capsules by
827 // setting all `grant_ptr`s to NULL.
828 self.grant_pointers.map(|grant_pointers| {
829 for grant_entry in grant_pointers.iter_mut() {
830 grant_entry.driver_num = 0;
831 grant_entry.grant_ptr = ptr::null_mut();
832 }
833 });
834
835 // Save the completion code.
836 self.completion_code.set(completion_code);
837
838 // Mark the app as stopped so the scheduler won't try to run it.
839 self.state.set(State::Terminated);
840 }
841
842 fn get_restart_count(&self) -> usize {
843 self.restart_count.get()
844 }
845
846 fn has_tasks(&self) -> bool {
847 self.tasks.map_or(false, |tasks| tasks.has_elements())
848 }
849
850 fn dequeue_task(&self) -> Option<Task> {
851 self.tasks.map_or(None, |tasks| tasks.dequeue())
852 }
853
854 fn remove_upcall(&self, upcall_id: UpcallId) -> Option<Task> {
855 self.tasks.map_or(None, |tasks| {
856 tasks.remove_first_matching(|task| match task {
857 Task::FunctionCall(fc) => match fc.source {
858 FunctionCallSource::Driver(upid) => upid == upcall_id,
859 _ => false,
860 },
861 Task::ReturnValue(rv) => rv.upcall_id == upcall_id,
862 Task::IPC(_) => false,
863 })
864 })
865 }
866
867 fn pending_tasks(&self) -> usize {
868 self.tasks.map_or(0, |tasks| tasks.len())
869 }
870
871 fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions {
872 self.header.get_command_permissions(driver_num, offset)
873 }
874
875 fn get_storage_permissions(&self) -> StoragePermissions {
876 self.storage_permissions.get()
877 }
878
879 fn number_writeable_flash_regions(&self) -> usize {
880 self.header.number_writeable_flash_regions()
881 }
882
883 fn get_writeable_flash_region(&self, region_index: usize) -> (usize, usize) {
884 self.header.get_writeable_flash_region(region_index)
885 }
886
887 fn update_stack_start_pointer(&self, stack_pointer: *const u8) {
888 if stack_pointer >= self.mem_start() && stack_pointer < self.mem_end() {
889 self.debug.set_app_stack_start_pointer(stack_pointer);
890 // We also reset the minimum stack pointer because whatever
891 // value we had could be entirely wrong by now.
892 self.debug.set_app_stack_min_pointer(stack_pointer);
893 }
894 }
895
896 fn update_heap_start_pointer(&self, heap_pointer: *const u8) {
897 if heap_pointer >= self.mem_start() && heap_pointer < self.mem_end() {
898 self.debug.set_app_heap_start_pointer(heap_pointer);
899 }
900 }
901
902 fn setup_mpu(&self) {
903 self.mpu_config.map(|config| {
904 // SAFETY: `configure_mpu` is unsafe, as invoking it with an incorrect
905 // configuration can allow an untrusted application to access
906 // kernel-private memory.
907 //
908 // This call is safe given we trust that the implementation of
909 // `ProcessStandard` correctly provisions a set of MPU regions that
910 // does not grant access to any kernel-private memory, and
911 // `ProcessStandard` does not provide safe, publicly accessible
912 // APIs to add other arbitrary MPU regions to this configuration.
913 unsafe {
914 self.chip.mpu().configure_mpu(config);
915 }
916 });
917 }
918
919 fn add_mpu_region(
920 &self,
921 unallocated_memory_start: *const u8,
922 unallocated_memory_size: usize,
923 min_region_size: usize,
924 ) -> Option<mpu::Region> {
925 self.mpu_config.and_then(|config| {
926 let new_region = self.chip.mpu().allocate_region(
927 unallocated_memory_start,
928 unallocated_memory_size,
929 min_region_size,
930 mpu::Permissions::ReadWriteOnly,
931 config,
932 )?;
933
934 for region in self.mpu_regions.iter() {
935 if region.get().is_none() {
936 region.set(Some(new_region));
937 return Some(new_region);
938 }
939 }
940
941 // Not enough room in Process struct to store the MPU region.
942 None
943 })
944 }
945
946 fn remove_mpu_region(&self, region: mpu::Region) -> Result<(), ErrorCode> {
947 self.mpu_config.map_or(Err(ErrorCode::INVAL), |config| {
948 // Find the existing mpu region that we are removing; it needs to match exactly.
949 if let Some(internal_region) = self.mpu_regions.iter().find(|r| r.get() == Some(region))
950 {
951 self.chip
952 .mpu()
953 .remove_memory_region(region, config)
954 .or(Err(ErrorCode::FAIL))?;
955
956 // Remove this region from the tracking cache of mpu_regions
957 internal_region.set(None);
958 Ok(())
959 } else {
960 Err(ErrorCode::INVAL)
961 }
962 })
963 }
964
965 fn sbrk(&self, increment: isize) -> Result<CapabilityPtr, Error> {
966 // Do not modify an inactive process.
967 if !self.is_running() {
968 return Err(Error::InactiveApp);
969 }
970
971 let new_break = self.app_break.get().wrapping_offset(increment);
972 self.brk(new_break)
973 }
974
975 fn brk(&self, new_break: *const u8) -> Result<CapabilityPtr, Error> {
976 // Do not modify an inactive process.
977 if !self.is_running() {
978 return Err(Error::InactiveApp);
979 }
980
981 self.mpu_config.map_or(Err(Error::KernelError), |config| {
982 if new_break < self.allow_high_water_mark.get() || new_break >= self.mem_end() {
983 Err(Error::AddressOutOfBounds)
984 } else if new_break > self.kernel_memory_break.get() {
985 Err(Error::OutOfMemory)
986 } else if let Err(()) = self.chip.mpu().update_app_memory_region(
987 new_break,
988 self.kernel_memory_break.get(),
989 mpu::Permissions::ReadWriteOnly,
990 config,
991 ) {
992 Err(Error::OutOfMemory)
993 } else {
994 let old_break: *const u8 = self.app_break.get();
995 self.app_break.set(new_break);
996
997 // SAFETY: `configure_mpu` is unsafe, as invoking it with an incorrect
998 // configuration can allow an untrusted application to access
999 // kernel-private memory.
1000 //
1001 // This call is safe given we trust that the implementation of
1002 // `ProcessStandard` correctly provisions a set of MPU regions
1003 // that does not grant access to any kernel-private memory, and
1004 // `ProcessStandard` does not provide safe, publicly
1005 // accessible APIs to add other arbitrary MPU regions to this
1006 // configuration.
1007 unsafe {
1008 self.chip.mpu().configure_mpu(config);
1009 }
1010
1011 if new_break > old_break {
1012 // We need to initialize (zero) the newly accessible memory
1013 // region at `[old_break; new_break)`. This serves two
1014 // purposes:
1015 //
1016 // 1. It prevents a process from accessing any information
1017 // still contained in this memory from prior kernel
1018 // instances or processes.
1019 //
1020 // 2. It satisfies Rust's requirements that all
1021 // dereferencable memory be properly initialized. This is
1022 // important, as we'll be creating references into this
1023 // process-accessible memory region through the process
1024 // buffer infrastructure.
1025 let old_break_mut_ptr: *mut u8 = old_break.cast_mut();
1026 // SAFETY: We know this will write to only process-accessible memory
1027 // that has never been used to create any kernel data structures
1028 // because of the checks at the beginning of this function. We also
1029 // know this is valid memory to write to because we checked the
1030 // new_break is within process memory. Because we are using `u8`, we
1031 // know `old_break_mut_ptr` is aligned. Since the process will have
1032 // access to this memory we know the kernel will not try to use it
1033 // for any data structures, avoiding any potential future memory
1034 // initialization error.
1035 unsafe {
1036 core::ptr::write_bytes(
1037 old_break_mut_ptr,
1038 // Set the newly app-accessible memory to `0`:
1039 0_u8,
1040 new_break.addr() - old_break.addr(),
1041 );
1042 }
1043 }
1044
1045 let base = self.mem_start() as usize;
1046 let old_break_unit_ptr: *const () = old_break.cast();
1047 // SAFETY: It must be safe for this process to access the
1048 // bounds+permission expressed here while assuming no other
1049 // protection mechanism is active.
1050 // - A process should have Read+Write access to its memory.
1051 // - The function has established [base, new_break) as the
1052 // (new) valid bounds for process memory.
1053 // - We grant only Read+Write permissions.
1054 // - We only pass this pointer to this process.
1055 let break_result = unsafe {
1056 CapabilityPtr::new_with_authority(
1057 old_break_unit_ptr,
1058 base,
1059 (new_break as usize) - base,
1060 CapabilityPtrPermissions::ReadWrite,
1061 )
1062 };
1063
1064 Ok(break_result)
1065 }
1066 })
1067 }
1068
1069 #[allow(clippy::not_unsafe_ptr_arg_deref)]
1070 fn build_readwrite_process_buffer(
1071 &self,
1072 buf_start_addr: *mut u8,
1073 size: usize,
1074 ) -> Result<ReadWriteProcessBuffer, ErrorCode> {
1075 if !self.is_running() {
1076 // Do not operate on an inactive process
1077 return Err(ErrorCode::FAIL);
1078 }
1079
1080 // A process is allowed to pass any pointer if the buffer length is 0,
1081 // as to revoke kernel access to a memory region without granting access
1082 // to another one
1083 if size == 0 {
1084 // Clippy complains that we're dereferencing a pointer in a public
1085 // and safe function here. While we are not dereferencing the
1086 // pointer here, we pass it along to an unsafe function, which is as
1087 // dangerous (as it is likely to be dereferenced down the line).
1088 //
1089 // Relevant discussion:
1090 // https://github.com/rust-lang/rust-clippy/issues/3045
1091 //
1092 // It should be fine to ignore the lint here, as a buffer of length
1093 // 0 will never allow dereferencing any memory in a safe manner.
1094 //
1095 // SAFETY: We specify a zero-length buffer, so the implementation of
1096 // `ReadWriteProcessBuffer` will handle any safety issues.
1097 // Therefore, we can encapsulate the unsafe.
1098 Ok(unsafe { ReadWriteProcessBuffer::new(buf_start_addr, 0, self.processid()) })
1099 } else if self.in_app_owned_memory(buf_start_addr, size) {
1100 // TODO: Check for buffer aliasing here
1101
1102 // Valid buffer, we need to adjust the app's watermark
1103 // note: `in_app_owned_memory` ensures this offset does not wrap
1104 let buf_end_addr = buf_start_addr.wrapping_add(size);
1105 let new_water_mark = cmp::max(self.allow_high_water_mark.get(), buf_end_addr);
1106 self.allow_high_water_mark.set(new_water_mark);
1107
1108 // Clippy complains that we're dereferencing a pointer in a public
1109 // and safe function here. While we are not dereferencing the
1110 // pointer here, we pass it along to an unsafe function, which is as
1111 // dangerous (as it is likely to be dereferenced down the line).
1112 //
1113 // Relevant discussion:
1114 // https://github.com/rust-lang/rust-clippy/issues/3045
1115 //
1116 // It should be fine to ignore the lint here, as long as we make
1117 // sure that we're pointing towards userspace memory (verified using
1118 // `in_app_owned_memory`) and respect alignment and other
1119 // constraints of the Rust references created by
1120 // `ReadWriteProcessBuffer`.
1121 //
1122 // SAFETY: We encapsulate the unsafe here on the condition in the TODO
1123 // above, as we must ensure that this `ReadWriteProcessBuffer` will
1124 // be the only reference to this memory.
1125 Ok(unsafe { ReadWriteProcessBuffer::new(buf_start_addr, size, self.processid()) })
1126 } else {
1127 Err(ErrorCode::INVAL)
1128 }
1129 }
1130
1131 #[allow(clippy::not_unsafe_ptr_arg_deref)]
1132 fn build_readonly_process_buffer(
1133 &self,
1134 buf_start_addr: *const u8,
1135 size: usize,
1136 ) -> Result<ReadOnlyProcessBuffer, ErrorCode> {
1137 if !self.is_running() {
1138 // Do not operate on an inactive process
1139 return Err(ErrorCode::FAIL);
1140 }
1141
1142 // A process is allowed to pass any pointer if the buffer length is 0,
1143 // as to revoke kernel access to a memory region without granting access
1144 // to another one
1145 if size == 0 {
1146 // Clippy complains that we're dereferencing a pointer in a public
1147 // and safe function here. While we are not dereferencing the
1148 // pointer here, we pass it along to an unsafe function, which is as
1149 // dangerous (as it is likely to be dereferenced down the line).
1150 //
1151 // Relevant discussion:
1152 // https://github.com/rust-lang/rust-clippy/issues/3045
1153 //
1154 // It should be fine to ignore the lint here, as a buffer of length
1155 // 0 will never allow dereferencing any memory in a safe manner.
1156 //
1157 // SAFETY: We specify a zero-length buffer, so the implementation of
1158 // `ReadOnlyProcessBuffer` will handle any safety issues. Therefore,
1159 // we can encapsulate the unsafe.
1160 Ok(unsafe { ReadOnlyProcessBuffer::new(buf_start_addr, 0, self.processid()) })
1161 } else if self.in_app_owned_memory(buf_start_addr, size)
1162 || self.in_app_flash_memory(buf_start_addr, size)
1163 {
1164 // TODO: Check for buffer aliasing here
1165
1166 if self.in_app_owned_memory(buf_start_addr, size) {
1167 // Valid buffer, and since this is in read-write memory (i.e.
1168 // not flash), we need to adjust the process's watermark. Note:
1169 // `in_app_owned_memory()` ensures this offset does not wrap.
1170 let buf_end_addr = buf_start_addr.wrapping_add(size);
1171 let new_water_mark = cmp::max(self.allow_high_water_mark.get(), buf_end_addr);
1172 self.allow_high_water_mark.set(new_water_mark);
1173 }
1174
1175 // Clippy complains that we're dereferencing a pointer in a public
1176 // and safe function here. While we are not dereferencing the
1177 // pointer here, we pass it along to an unsafe function, which is as
1178 // dangerous (as it is likely to be dereferenced down the line).
1179 //
1180 // Relevant discussion:
1181 // https://github.com/rust-lang/rust-clippy/issues/3045
1182 //
1183 // It should be fine to ignore the lint here, as long as we make
1184 // sure that we're pointing towards userspace memory (verified using
1185 // `in_app_owned_memory` or `in_app_flash_memory`) and respect
1186 // alignment and other constraints of the Rust references created by
1187 // `ReadWriteProcessBuffer`.
1188 //
1189 // SAFETY: We encapsulate the unsafe here on the condition in the TODO
1190 // above, as we must ensure that this `ReadOnlyProcessBuffer` will
1191 // be the only reference to this memory.
1192 Ok(unsafe { ReadOnlyProcessBuffer::new(buf_start_addr, size, self.processid()) })
1193 } else {
1194 Err(ErrorCode::INVAL)
1195 }
1196 }
1197
1198 unsafe fn set_byte(&self, addr: *mut u8, value: u8) -> bool {
1199 if self.in_app_owned_memory(addr, 1) {
1200 // SAFETY: We verify that this will only write process-accessible memory,
1201 // but this can still be undefined behavior if something else holds
1202 // a reference to this memory. The caller must ensure nothing else
1203 // holds a reference to this memory.
1204 unsafe {
1205 *addr = value;
1206 }
1207 true
1208 } else {
1209 false
1210 }
1211 }
1212
1213 fn grant_is_allocated(&self, grant_num: usize) -> Option<bool> {
1214 // Do not modify an inactive process.
1215 if !self.is_running() {
1216 return None;
1217 }
1218
1219 // Update the grant pointer to the address of the new allocation.
1220 self.grant_pointers.map_or(None, |grant_pointers| {
1221 // Implement `grant_pointers[grant_num]` without a chance of a
1222 // panic.
1223 grant_pointers
1224 .get(grant_num)
1225 .map(|grant_entry| !grant_entry.grant_ptr.is_null())
1226 })
1227 }
1228
1229 fn allocate_grant(
1230 &self,
1231 grant_num: usize,
1232 driver_num: usize,
1233 size: usize,
1234 align: usize,
1235 ) -> Result<(), ()> {
1236 // Do not modify an inactive process.
1237 if !self.is_running() {
1238 return Err(());
1239 }
1240
1241 // Verify the grant_num is valid.
1242 if grant_num >= self.kernel.get_grant_count_and_finalize() {
1243 return Err(());
1244 }
1245
1246 // Verify that the grant is not already allocated. If the pointer is not
1247 // null then the grant is already allocated.
1248 if let Some(is_allocated) = self.grant_is_allocated(grant_num) {
1249 if is_allocated {
1250 return Err(());
1251 }
1252 }
1253
1254 // Verify that there is not already a grant allocated with the same
1255 // `driver_num`.
1256 let exists = self.grant_pointers.map_or(false, |grant_pointers| {
1257 // Check our list of grant pointers if the driver number is used.
1258 grant_pointers.iter().any(|grant_entry| {
1259 // Check if the grant is both allocated (its grant pointer is
1260 // non null) and the driver number matches.
1261 (!grant_entry.grant_ptr.is_null()) && grant_entry.driver_num == driver_num
1262 })
1263 });
1264 // If we find a match, then the `driver_num` must already be used and
1265 // the grant allocation fails.
1266 if exists {
1267 return Err(());
1268 }
1269
1270 // Use the shared grant allocator function to actually allocate memory.
1271 // Returns `None` if the allocation cannot be created.
1272 if let Some(grant_ptr) = self.allocate_in_grant_region_internal(size, align) {
1273 // Update the grant pointer to the address of the new allocation.
1274 self.grant_pointers.map_or(Err(()), |grant_pointers| {
1275 // Implement `grant_pointers[grant_num] = grant_ptr` without a
1276 // chance of a panic.
1277 grant_pointers
1278 .get_mut(grant_num)
1279 .map_or(Err(()), |grant_entry| {
1280 // Actually set the driver num and grant pointer.
1281 grant_entry.driver_num = driver_num;
1282 grant_entry.grant_ptr = grant_ptr.as_ptr();
1283
1284 // If all of this worked, return true.
1285 Ok(())
1286 })
1287 })
1288 } else {
1289 // Could not allocate the memory for the grant region.
1290 Err(())
1291 }
1292 }
1293
1294 fn allocate_custom_grant(
1295 &self,
1296 size: usize,
1297 align: usize,
1298 ) -> Result<(ProcessCustomGrantIdentifier, NonNull<u8>), ()> {
1299 // Do not modify an inactive process.
1300 if !self.is_running() {
1301 return Err(());
1302 }
1303
1304 // Use the shared grant allocator function to actually allocate memory.
1305 // Returns `None` if the allocation cannot be created.
1306 if let Some(ptr) = self.allocate_in_grant_region_internal(size, align) {
1307 // Create the identifier that the caller will use to get access to
1308 // this custom grant in the future.
1309 let identifier = self.create_custom_grant_identifier(ptr);
1310
1311 Ok((identifier, ptr))
1312 } else {
1313 // Could not allocate memory for the custom grant.
1314 Err(())
1315 }
1316 }
1317
1318 fn enter_grant(&self, grant_num: usize) -> Result<NonNull<u8>, Error> {
1319 // Do not try to access the grant region of an inactive process.
1320 if !self.is_running() {
1321 return Err(Error::InactiveApp);
1322 }
1323
1324 // Retrieve the grant pointer from the `grant_pointers` slice. We use
1325 // `[slice].get()` so that if the grant number is invalid this will
1326 // return `Err` and not panic.
1327 self.grant_pointers
1328 .map_or(Err(Error::KernelError), |grant_pointers| {
1329 // Implement `grant_pointers[grant_num]` without a chance of a
1330 // panic.
1331 match grant_pointers.get_mut(grant_num) {
1332 Some(grant_entry) => {
1333 // Check if this is entering a valid grant that has been created and
1334 // initialized. If the grant is not valid then the `grant_ptr` will
1335 // be null.
1336 if let Some(grant_ptr_nonnull) = NonNull::new(grant_entry.grant_ptr) {
1337 // Check if the grant pointer is marked that the grant has already
1338 // been entered. If so, return an error.
1339 if (usize::from(grant_ptr_nonnull.addr())) & 0x1 == 0x1 {
1340 // Lowest bit is one, meaning this grant has been entered.
1341 Err(Error::AlreadyInUse)
1342 } else {
1343 // Now, to mark that the grant has been entered, we set the lowest
1344 // bit to one and save this as the grant pointer.
1345 grant_entry.grant_ptr =
1346 grant_ptr_nonnull.map_addr(|a| a | 0x1).as_ptr();
1347
1348 // And we return the grant pointer to the entered grant.
1349 Ok(grant_ptr_nonnull)
1350 }
1351 } else {
1352 // The grant has not been created and is not valid to enter.
1353 Err(Error::OutOfMemory)
1354 }
1355 }
1356 None => Err(Error::AddressOutOfBounds),
1357 }
1358 })
1359 }
1360
1361 fn enter_custom_grant(
1362 &self,
1363 identifier: ProcessCustomGrantIdentifier,
1364 ) -> Result<*mut u8, Error> {
1365 // Do not try to access the grant region of an inactive process.
1366 if !self.is_running() {
1367 return Err(Error::InactiveApp);
1368 }
1369
1370 // Get the address of the custom grant based on the identifier.
1371 let address = self.get_custom_grant_address(identifier);
1372
1373 // We never deallocate custom grants and only we can change the
1374 // `identifier` so we know this is a valid address for the custom grant.
1375 // kernel_memory_break seems like the most reasonable pointer to get the
1376 // provenance from.
1377 Ok(self.kernel_memory_break().with_addr(address).cast_mut())
1378 }
1379
1380 unsafe fn leave_grant(&self, grant_num: usize) {
1381 // Do not modify an inactive process.
1382 if !self.is_running() {
1383 return;
1384 }
1385
1386 self.grant_pointers.map(|grant_pointers| {
1387 // Implement `grant_pointers[grant_num]` without a chance of a
1388 // panic.
1389 if let Some(grant_entry) = grant_pointers.get_mut(grant_num) {
1390 // Get a copy of the actual grant pointer.
1391 let grant_ptr = grant_entry.grant_ptr;
1392
1393 // Now, to mark that the grant has been released, we set the
1394 // lowest bit back to zero and save this as the grant
1395 // pointer.
1396 grant_entry.grant_ptr = grant_ptr.map_addr(|a| a & !0x1);
1397 }
1398 });
1399 }
1400
1401 fn grant_allocated_count(&self) -> Option<usize> {
1402 // Do not modify an inactive process.
1403 if !self.is_running() {
1404 return None;
1405 }
1406
1407 self.grant_pointers.map(|grant_pointers| {
1408 // Filter our list of grant pointers into just the non-null ones,
1409 // and count those. A grant is allocated if its grant pointer is
1410 // non-null.
1411 grant_pointers
1412 .iter()
1413 .filter(|grant_entry| !grant_entry.grant_ptr.is_null())
1414 .count()
1415 })
1416 }
1417
1418 fn lookup_grant_from_driver_num(&self, driver_num: usize) -> Result<usize, Error> {
1419 self.grant_pointers
1420 .map_or(Err(Error::KernelError), |grant_pointers| {
1421 // Filter our list of grant pointers into just the non null
1422 // ones, and count those. A grant is allocated if its grant
1423 // pointer is non-null.
1424 match grant_pointers.iter().position(|grant_entry| {
1425 // Only consider allocated grants.
1426 (!grant_entry.grant_ptr.is_null()) && grant_entry.driver_num == driver_num
1427 }) {
1428 Some(idx) => Ok(idx),
1429 None => Err(Error::OutOfMemory),
1430 }
1431 })
1432 }
1433
1434 fn is_valid_upcall_function_pointer(&self, upcall_fn: *const ()) -> bool {
1435 let ptr: *const u8 = upcall_fn.cast();
1436 let size = mem::size_of::<*const u8>();
1437
1438 // It is okay if this function is in memory or flash.
1439 self.in_app_flash_memory(ptr, size) || self.in_app_owned_memory(ptr, size)
1440 }
1441
1442 fn get_process_name(&self) -> &'static str {
1443 self.header.get_package_name().unwrap_or("")
1444 }
1445
1446 fn get_completion_code(&self) -> Option<Option<u32>> {
1447 self.completion_code.get()
1448 }
1449
1450 fn set_syscall_return_value(&self, return_value: SyscallReturn) {
1451 match self.stored_state.map(|stored_state| {
1452 // Actually set the return value for a particular process.
1453 //
1454 // SAFETY: The UKB implementation uses the bounds of
1455 // process-accessible memory to verify that any memory changes are
1456 // valid. Here, the unsafe promise we are making is that the bounds
1457 // passed to the UKB are correct. Because we use the start of the
1458 // process's memory, and the current `app_break`, we know that the
1459 // memory in that range is accessible to the process.
1460 unsafe {
1461 self.chip
1462 .userspace_kernel_boundary()
1463 .set_syscall_return_value(
1464 self.mem_start(),
1465 self.app_break.get(),
1466 stored_state,
1467 return_value,
1468 )
1469 }
1470 }) {
1471 Some(Ok(())) => {
1472 // If we get an `Ok` we are all set.
1473
1474 // The process is either already in the running state (having
1475 // just called a nonblocking syscall like command) or needs to
1476 // be moved to the running state having called Yield-WaitFor and
1477 // now needing to be resumed. Either way we can set the state to
1478 // running.
1479 self.state.set(State::Running);
1480 // The task is running, if it was yielded-for an upcall,
1481 // the upcall must have been scheduled, unset
1482 // the ready flag.
1483 self.is_yield_wait_for_ready.set(false);
1484 }
1485
1486 Some(Err(())) => {
1487 // If we get an `Err`, then the UKB implementation could not set
1488 // the return value, likely because the process's stack is no
1489 // longer accessible to it. All we can do is fault.
1490 self.set_fault_state();
1491 }
1492
1493 None => {
1494 // We should never be here since `stored_state` should always be
1495 // occupied.
1496 self.set_fault_state();
1497 }
1498 }
1499 }
1500
1501 fn set_process_function(&self, callback: FunctionCall) {
1502 // See if we can actually enqueue this function for this process.
1503 // Architecture-specific code handles actually doing this since the
1504 // exact method is both architecture- and implementation-specific.
1505 //
1506 // This can fail, for example if the process does not have enough memory
1507 // remaining.
1508 match self.stored_state.map(|stored_state| {
1509 // Let the UKB implementation handle setting the process's PC so
1510 // that the process executes the upcall function.
1511 //
1512 // SAFETY: We encapsulate unsafe here because we are guaranteeing
1513 // that the memory bounds passed to `set_process_function` are
1514 // correct. We know this because we use the start of process memory
1515 // and the current `app_break`, and that range is accessible to the
1516 // process.
1517 unsafe {
1518 self.chip.userspace_kernel_boundary().set_process_function(
1519 self.mem_start(),
1520 self.app_break.get(),
1521 stored_state,
1522 callback,
1523 )
1524 }
1525 }) {
1526 Some(Ok(())) => {
1527 // If we got an `Ok` we are all set and should mark that this
1528 // process is ready to be scheduled.
1529
1530 // Move this process to the "running" state so the scheduler
1531 // will schedule it.
1532 self.state.set(State::Running);
1533 }
1534
1535 Some(Err(())) => {
1536 // If we got an Error, then there was likely not enough room on
1537 // the stack to allow the process to execute this function given
1538 // the details of the particular architecture this is running
1539 // on. This process has essentially faulted, so we mark it as
1540 // such.
1541 self.set_fault_state();
1542 }
1543
1544 None => {
1545 // We should never be here since `stored_state` should always be
1546 // occupied.
1547 self.set_fault_state();
1548 }
1549 }
1550 }
1551
1552 unsafe fn switch_to(&self) -> Option<syscall::ContextSwitchReason> {
1553 // Cannot switch to an invalid process
1554 if !self.is_running() {
1555 return None;
1556 }
1557
1558 let (switch_reason, stack_pointer) =
1559 self.stored_state.map_or((None, None), |stored_state| {
1560 // Switch to the process.
1561 //
1562 // SAFETY: We guarantee that the memory pointers we pass are valid,
1563 // ensuring this context switch is safe. We know this because we use
1564 // the start of process memory and the current `app_break`, and that
1565 // range is accessible to the process. Therefore we encapsulate the
1566 // `unsafe`. Also, the safety requirements for `switch_to` ensure
1567 // the MPU is correctly configured.
1568 unsafe {
1569 let (switch_reason, optional_stack_pointer) = self
1570 .chip
1571 .userspace_kernel_boundary()
1572 .switch_to_process(self.mem_start(), self.app_break.get(), stored_state);
1573 (Some(switch_reason), optional_stack_pointer)
1574 }
1575 });
1576
1577 // If the UKB implementation passed us a stack pointer, update our
1578 // debugging state. This is completely optional.
1579 if let Some(sp) = stack_pointer {
1580 self.debug.set_new_app_stack_min_pointer(sp);
1581 }
1582
1583 switch_reason
1584 }
1585
1586 fn debug_syscall_count(&self) -> usize {
1587 self.debug.get_syscall_count()
1588 }
1589
1590 fn debug_dropped_upcall_count(&self) -> usize {
1591 self.debug.get_dropped_upcall_count()
1592 }
1593
1594 fn debug_timeslice_expiration_count(&self) -> usize {
1595 self.debug.get_timeslice_expiration_count()
1596 }
1597
1598 fn debug_timeslice_expired(&self) {
1599 self.debug.increment_timeslice_expiration_count();
1600 }
1601
1602 fn debug_syscall_called(&self, last_syscall: Syscall) {
1603 self.debug.increment_syscall_count();
1604 self.debug.set_last_syscall(last_syscall);
1605 }
1606
1607 fn debug_syscall_last(&self) -> Option<Syscall> {
1608 self.debug.get_last_syscall()
1609 }
1610
1611 fn get_addresses(&self) -> ProcessAddresses {
1612 ProcessAddresses {
1613 flash_start: self.flash_start() as usize,
1614 flash_non_protected_start: self.flash_non_protected_start(),
1615 flash_integrity_end: self
1616 .flash
1617 .as_ptr()
1618 .wrapping_add(self.header.get_binary_end() as usize),
1619 flash_end: self.flash_end(),
1620 sram_start: self.mem_start() as usize,
1621 sram_app_brk: self.app_memory_break() as usize,
1622 sram_grant_start: self.kernel_memory_break() as usize,
1623 sram_end: self.mem_end() as usize,
1624 sram_heap_start: self.debug.get_app_heap_start_pointer().map(|p| p as usize),
1625 sram_stack_top: self.debug.get_app_stack_start_pointer().map(|p| p as usize),
1626 sram_stack_bottom: self.debug.get_app_stack_min_pointer().map(|p| p as usize),
1627 }
1628 }
1629
1630 fn get_sizes(&self) -> ProcessSizes {
1631 ProcessSizes {
1632 grant_pointers: mem::size_of::<GrantPointerEntry>()
1633 * self.kernel.get_grant_count_and_finalize(),
1634 upcall_list: Self::CALLBACKS_SIZE,
1635 process_control_block: Self::PROCESS_STRUCT_SIZE,
1636 }
1637 }
1638
1639 fn print_full_process(&self, writer: &mut dyn Write) {
1640 if !config::CONFIG.debug_panics {
1641 return;
1642 }
1643
1644 self.stored_state.map(|stored_state| {
1645 // SAFETY: We guarantee the memory bounds pointers provided to the
1646 // UKB are correct. We know this because we use the start of process
1647 // memory and the current `app_break`, and that range is accessible
1648 // to the process.
1649 unsafe {
1650 self.chip.userspace_kernel_boundary().print_context(
1651 self.mem_start(),
1652 self.app_break.get(),
1653 stored_state,
1654 writer,
1655 );
1656 }
1657 });
1658
1659 // Display grant information.
1660 let number_grants = self.kernel.get_grant_count_and_finalize();
1661 let _ = writer.write_fmt(format_args!(
1662 "\
1663 \r\n Total number of grant regions defined: {}\r\n",
1664 self.kernel.get_grant_count_and_finalize()
1665 ));
1666 let rows = number_grants.div_ceil(3);
1667
1668 // Access our array of grant pointers.
1669 self.grant_pointers.map(|grant_pointers| {
1670 // Iterate each grant and show its address.
1671 for i in 0..rows {
1672 for j in 0..3 {
1673 let index = i + (rows * j);
1674 if index >= number_grants {
1675 break;
1676 }
1677
1678 // Implement `grant_pointers[grant_num]` without a chance of
1679 // a panic.
1680 grant_pointers.get(index).map(|grant_entry| {
1681 if grant_entry.grant_ptr.is_null() {
1682 let _ =
1683 writer.write_fmt(format_args!(" Grant {:>2} : -- ", index));
1684 } else {
1685 let _ = writer.write_fmt(format_args!(
1686 " Grant {:>2} {:#x}: {:p}",
1687 index, grant_entry.driver_num, grant_entry.grant_ptr
1688 ));
1689 }
1690 });
1691 }
1692 let _ = writer.write_fmt(format_args!("\r\n"));
1693 }
1694 });
1695
1696 // Display the current state of the MPU for this process.
1697 self.mpu_config.map(|config| {
1698 let _ = writer.write_fmt(format_args!("{}", config));
1699 });
1700
1701 // Print a helpful message on how to re-compile a process to view the
1702 // listing file. If a process is PIC, then we also need to print the
1703 // actual addresses the process executed at so that the .lst file can be
1704 // generated for those addresses. If the process was already compiled
1705 // for a fixed address, then just generating a .lst file is fine.
1706
1707 if self.debug.get_fixed_address_flash().is_some() {
1708 // Fixed addresses, can just run `make lst`.
1709 let _ = writer.write_fmt(format_args!(
1710 "\
1711 \r\nTo debug libtock-c apps, run `make lst` in the app's\
1712 \r\nfolder and open the arch.{:#x}.{:#x}.lst file.\r\n\r\n",
1713 self.debug.get_fixed_address_flash().unwrap_or(0),
1714 self.debug.get_fixed_address_ram().unwrap_or(0)
1715 ));
1716 } else {
1717 // PIC, need to specify the addresses.
1718 let sram_start = self.mem_start() as usize;
1719 let flash_start = self.flash.as_ptr() as usize;
1720 let flash_init_fn = flash_start + self.header.get_init_function_offset() as usize;
1721
1722 let _ = writer.write_fmt(format_args!(
1723 "\
1724 \r\nTo debug libtock-c apps, run\
1725 \r\n`make debug RAM_START={:#x} FLASH_INIT={:#x}`\
1726 \r\nin the app's folder and open the .lst file.\r\n\r\n",
1727 sram_start, flash_init_fn
1728 ));
1729 }
1730 }
1731
1732 fn get_stored_state(&self, out: &mut [u8]) -> Result<usize, ErrorCode> {
1733 self.stored_state
1734 .map(|stored_state| {
1735 self.chip
1736 .userspace_kernel_boundary()
1737 .store_context(stored_state, out)
1738 })
1739 .unwrap_or(Err(ErrorCode::FAIL))
1740 }
1741}
1742
1743impl<C: 'static + Chip, D: 'static + ProcessStandardDebug> ProcessStandard<'_, C, D> {
1744 /// Alignment requirement for each `GrantPointerEntry` in the grant pointers
1745 /// slice.
1746 const GRANT_POINTERS_ALIGNMENT: usize = mem::align_of::<GrantPointerEntry>();
1747
1748 /// Number of upcalls stored in the upcall ring buffer (10 element length).
1749 const CALLBACK_LEN: usize = 10;
1750 /// Size of the upcall storage buffer.
1751 ///
1752 /// As of June 2026, we cannot do
1753 ///
1754 /// ```ignore
1755 /// const CALLBACKS_SIZE usize = mem::size_of::<MaybeUninit<[Task; Self::CALLBACK_LEN]>>();
1756 /// ```
1757 ///
1758 /// because of the error:
1759 ///
1760 /// ```text
1761 /// error: generic `Self` types are currently not permitted in anonymous constants
1762 /// --> kernel/src/process_standard.rs:1712:70
1763 /// |
1764 /// 1712 | const CALLBACKS_SIZE: usize = mem::size_of::<MaybeUninit<[Task; Self::CALLBACK_LEN]>>();
1765 /// | ^^^^
1766 /// |
1767 /// ```
1768 const CALLBACKS_SIZE: usize = mem::size_of::<Task>() * Self::CALLBACK_LEN;
1769 /// Alignment requirement of the upcall storage buffer.
1770 const CALLBACKS_ALIGNMENT: usize = mem::align_of::<Task>();
1771
1772 // Memory offset to make room for this process's control block.
1773 const PROCESS_STRUCT_SIZE: usize = mem::size_of::<ProcessStandard<C, D>>();
1774 /// Alignment requirement for `ProcessStandard`.
1775 const PROCESS_STRUCT_ALIGNMENT: usize = mem::align_of::<ProcessStandard<C, D>>();
1776
1777 /// Create a `ProcessStandard` object based on the found `ProcessBinary`.
1778 ///
1779 /// # Safety
1780 ///
1781 /// This function allocates memory from `remaining_memory` for use by the
1782 /// process. There must not be any references to or other uses of
1783 /// `remaining_memory` when calling this function.
1784 pub(crate) unsafe fn create(
1785 kernel: &'static Kernel,
1786 chip: &'static C,
1787 pb: ProcessBinary,
1788 remaining_memory: *mut [u8],
1789 fault_policy: &'static dyn ProcessFaultPolicy,
1790 storage_permissions_policy: &'static dyn ProcessStandardStoragePermissionsPolicy<C, D>,
1791 app_id: ShortId,
1792 index: usize,
1793 ) -> Result<(Option<&'static dyn Process>, *mut [u8]), (ProcessLoadError, *mut [u8])> {
1794 let process_name = pb.header.get_package_name();
1795 let process_ram_requested_size = pb.header.get_minimum_app_ram_size() as usize;
1796
1797 // Initialize MPU region configuration.
1798 let mut mpu_config = match chip.mpu().new_config() {
1799 Some(mpu_config) => mpu_config,
1800 None => return Err((ProcessLoadError::MpuConfigurationError, remaining_memory)),
1801 };
1802
1803 // Allocate MPU region for flash.
1804 if chip
1805 .mpu()
1806 .allocate_region(
1807 pb.flash.as_ptr(),
1808 pb.flash.len(),
1809 pb.flash.len(),
1810 mpu::Permissions::ReadExecuteOnly,
1811 &mut mpu_config,
1812 )
1813 .is_none()
1814 {
1815 if config::CONFIG.debug_load_processes {
1816 debug!(
1817 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't allocate MPU region for flash",
1818 pb.flash.as_ptr() as usize,
1819 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
1820 process_name
1821 );
1822 }
1823 return Err((ProcessLoadError::MpuInvalidFlashLength, remaining_memory));
1824 }
1825
1826 // Determine how much space we need in the application's memory space
1827 // just for kernel and grant state. We need to make sure we allocate
1828 // enough memory just for that.
1829
1830 // Calculate how many bytes we need for grant pointers.
1831 let grant_ptr_size = mem::size_of::<GrantPointerEntry>();
1832 let grant_ptrs_num = kernel.get_grant_count_and_finalize();
1833 let grant_ptrs_size = grant_ptrs_num * grant_ptr_size;
1834
1835 // Initial size of the kernel-owned part of process memory can be
1836 // calculated directly based on the initial size of all kernel-owned
1837 // data structures.
1838 //
1839 // Add the alignment size of each data structure to handle the case
1840 // where the memory region starts at the worst possible address and we
1841 // need to add padding. Note: the maximum shift will only ever be one
1842 // less than the alignment size, but to avoid unusual addresses we just
1843 // use the full alignment.
1844 let initial_kernel_memory_size = grant_ptrs_size
1845 + Self::GRANT_POINTERS_ALIGNMENT
1846 + Self::CALLBACKS_SIZE
1847 + Self::CALLBACKS_ALIGNMENT
1848 + Self::PROCESS_STRUCT_SIZE
1849 + Self::PROCESS_STRUCT_ALIGNMENT;
1850
1851 // By default we start with the initial size of process-accessible
1852 // memory set to 0. This maximizes the flexibility that processes have
1853 // to allocate their memory as they see fit. If a process needs more
1854 // accessible memory it must use the `brk` memop syscalls to request
1855 // more memory.
1856 //
1857 // We must take into account any process-accessible memory required by
1858 // the context switching implementation and allocate at least that much
1859 // memory so that we can successfully switch to the process. This is
1860 // architecture and implementation specific, so we query that now.
1861 let min_process_memory_size = chip
1862 .userspace_kernel_boundary()
1863 .initial_process_app_brk_size();
1864
1865 // We have to ensure that we at least ask the MPU for
1866 // `min_process_memory_size` so that we can be sure that `app_brk` is
1867 // not set inside the kernel-owned memory region. Now, in practice,
1868 // processes should not request 0 (or very few) bytes of memory in their
1869 // TBF header (i.e. `process_ram_requested_size` will almost always be
1870 // much larger than `min_process_memory_size`), as they are unlikely to
1871 // work with essentially no available memory. But, we still must protect
1872 // for that case.
1873 let min_process_ram_size = cmp::max(process_ram_requested_size, min_process_memory_size);
1874
1875 // Minimum memory size for the process.
1876 let min_total_memory_size = min_process_ram_size + initial_kernel_memory_size;
1877
1878 // Check if this process requires a fixed memory start address. If so,
1879 // try to adjust the memory region to work for this process.
1880 //
1881 // Right now, we only support skipping some RAM and leaving a chunk
1882 // unused so that the memory region starts where the process needs it
1883 // to.
1884 let remaining_memory = if let Some(fixed_memory_start) = pb
1885 .header
1886 .get_fixed_address_ram()
1887 .map(|addr: u32| remaining_memory.cast::<u8>().with_addr(addr as usize))
1888 {
1889 // The process does have a fixed address.
1890 if fixed_memory_start == remaining_memory.cast() {
1891 // Address already matches.
1892 remaining_memory
1893 } else if fixed_memory_start > remaining_memory.cast() {
1894 // Process wants a memory address farther in memory. Try to
1895 // advance the memory region to make the address match.
1896 let diff = fixed_memory_start.addr() - remaining_memory.addr();
1897 if diff > remaining_memory.len() {
1898 // We ran out of memory.
1899 let actual_address = (remaining_memory.cast::<u8>())
1900 .wrapping_byte_add(remaining_memory.len())
1901 .wrapping_byte_sub(1);
1902 let expected_address = fixed_memory_start;
1903 return Err((
1904 ProcessLoadError::MemoryAddressMismatch {
1905 actual_address,
1906 expected_address,
1907 },
1908 remaining_memory,
1909 ));
1910 } else {
1911 // Change the memory range to start where the process requested it.
1912 // Because of the if statement above we know this should work. Doing
1913 // it more cleanly would be good but was a bit beyond my borrow ken;
1914 // calling get_mut has a mutable borrow.-pal
1915 //
1916 // SAFETY: `diff` must be within the `remaining_memory` slice. Because we
1917 // check that `diff` is less than the length of `remaining_memory`
1918 // we know diff will be within `remaining_memory`.
1919 let (_, sliced) = unsafe { raw_slice_split_at_mut(remaining_memory, diff) };
1920 sliced
1921 }
1922 } else {
1923 // Address is earlier in memory, nothing we can do.
1924 let actual_address = remaining_memory.cast();
1925 let expected_address = fixed_memory_start;
1926 return Err((
1927 ProcessLoadError::MemoryAddressMismatch {
1928 actual_address,
1929 expected_address,
1930 },
1931 remaining_memory,
1932 ));
1933 }
1934 } else {
1935 remaining_memory
1936 };
1937
1938 // Determine where process memory will go and allocate an MPU region.
1939 //
1940 // `[allocation_start, allocation_size)` will cover both
1941 //
1942 // - the app-owned `min_process_memory_size`-long part of memory (at
1943 // some offset within `remaining_memory`), as well as
1944 //
1945 // - the kernel-owned allocation growing downward starting at the end
1946 // of this allocation, `initial_kernel_memory_size` bytes long.
1947 //
1948 let (allocation_start, allocation_size) = match chip.mpu().allocate_app_memory_region(
1949 remaining_memory.cast(),
1950 remaining_memory.len(),
1951 min_total_memory_size,
1952 min_process_memory_size,
1953 initial_kernel_memory_size,
1954 mpu::Permissions::ReadWriteOnly,
1955 &mut mpu_config,
1956 ) {
1957 Some((memory_start, memory_size)) => (memory_start, memory_size),
1958 None => {
1959 // Failed to load process. Insufficient memory.
1960 if config::CONFIG.debug_load_processes {
1961 debug!(
1962 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't allocate memory region of size >= {:#X}",
1963 pb.flash.as_ptr() as usize,
1964 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
1965 process_name,
1966 min_total_memory_size
1967 );
1968 }
1969 return Err((ProcessLoadError::NotEnoughMemory, remaining_memory));
1970 }
1971 };
1972
1973 // Determine the offset of the app-owned part of the above memory
1974 // allocation. An MPU may not place it at the very start of
1975 // `remaining_memory` for internal alignment constraints. This can only
1976 // overflow if the MPU implementation is incorrect; a compliant
1977 // implementation must return a memory allocation within the
1978 // `remaining_memory` slice.
1979 let app_memory_start_offset = allocation_start.addr() - remaining_memory.addr();
1980
1981 // Check if the memory region is valid for the process. If a process
1982 // included a fixed address for the start of RAM in its TBF header (this
1983 // field is optional, processes that are position independent do not
1984 // need a fixed address) then we check that we used the same address
1985 // when we allocated it in RAM.
1986 if let Some(fixed_memory_start) = pb
1987 .header
1988 .get_fixed_address_ram()
1989 .map(|addr: u32| remaining_memory.cast::<u8>().with_addr(addr as usize))
1990 {
1991 let actual_address = remaining_memory
1992 .cast::<u8>()
1993 .wrapping_byte_add(app_memory_start_offset);
1994 let expected_address = fixed_memory_start;
1995 if actual_address != expected_address {
1996 return Err((
1997 ProcessLoadError::MemoryAddressMismatch {
1998 actual_address,
1999 expected_address,
2000 },
2001 remaining_memory,
2002 ));
2003 }
2004 }
2005
2006 // With our MPU allocation, we can begin to divide up the
2007 // `remaining_memory` slice into individual regions for the process and
2008 // kernel, as follows:
2009 //
2010 //
2011 // ┌───────────────────────────────────────────────────────────────────────────────────────
2012 // │ remaining_memory
2013 // └───────────────────────────────────────────────────────────────────────────────────────
2014 // ┆ ┆
2015 // ┌────────────────────────────────────────────────────────────────────────┬──────────────
2016 // │ allocated_padded_memory │ unused_memory
2017 // └────────────────────────────────────────────────────────────────────────┴──────────────
2018 // ┆ ┆
2019 // ┌────────────────────────────────────────────────────────────────────┐
2020 // ┆←─→│ allocated_memory │
2021 // ↑ └────────────────────────────────────────────────────────────────────┘
2022 // └┄┄┄app_memory_start_offset ┆
2023 // ┌─────────────────────────┬──────────────────────────────────────────┐
2024 // │ app_accessible_memory │ allocated_kernel_memory │
2025 // └─────────────────────────┴──────────────────────────────────────────┘
2026 // ┆←min_process_memory_size→┆←────→┆←────initial_kernel_memory_size───→┆
2027 // ↑ ↑ ┆ ┆
2028 // initial_app_brk┄┄┄┘ ┆ ┆ ┌┄┄┄kernel_memory_break ┆
2029 // initially unallocated┄┄┄┘ ┆ ↓ ┆
2030 // ┆ ┌───────┬──────────┬──────────────┐
2031 // ┆↔│process│upcall_buf│grant_pointers│
2032 // ┆ └───────┴──────────┴──────────────┘
2033 // ↑ ↑ ↑ ↑
2034 // possible alignment padding┄┴┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
2035 //
2036 //
2037 // First split the `remaining_memory` into two slices:
2038 //
2039 // 1. `allocated_padded_memory`: the allocated memory region, containing:
2040 //
2041 // 1. optional padding at the start of the memory region of
2042 // `app_memory_start_offset` bytes,
2043 // 2. the app accessible memory region of `min_process_memory_size`,
2044 // 3. optional unallocated memory, and
2045 // 4. kernel-reserved memory, growing downward starting at the end of
2046 // `allocated_memory`.
2047 //
2048 // 2. `unused_memory`: the rest of the `remaining_memory`, not assigned
2049 // to this app.
2050 //
2051 // SAFETY: `app_memory_start_offset + allocation_size` must be within `remaining_memory`.
2052 let (allocated_padded_memory, unused_memory) = unsafe {
2053 raw_slice_split_at_mut(remaining_memory, app_memory_start_offset + allocation_size)
2054 };
2055
2056 // Now, slice off the (optional) padding at the start:
2057 //
2058 // SAFETY: `app_memory_start_offset` must be within `allocated_padded_memory`.
2059 let (_padding, allocated_memory) =
2060 unsafe { raw_slice_split_at_mut(allocated_padded_memory, app_memory_start_offset) };
2061
2062 // We continue to sub-slice the `allocated_memory` into
2063 // process-accessible and kernel-owned memory. Prior to that, store the
2064 // start and length ofthe overall allocation:
2065 let allocated_memory_start = allocated_memory.cast();
2066 let allocated_memory_len = allocated_memory.len();
2067
2068 // Slice off the process-accessible memory:
2069 //
2070 // SAFETY: `min_process_memory_size` must be within `allocated_memory`.
2071 let (app_accessible_memory, allocated_kernel_memory) =
2072 unsafe { raw_slice_split_at_mut(allocated_memory, min_process_memory_size) };
2073
2074 // Initialize (zero) the initial process-accessible memory region. This
2075 // serves two purposes:
2076 //
2077 // 1. It prevents a process from accessing any information still
2078 // contained in this memory from prior kernel instances or processes.
2079 //
2080 // 2. It satisfies Rust's requirements that all dereferencable memory be
2081 // properly initialized. This is important, as we'll be creating
2082 // references into this process-accessible memory region through the
2083 // process buffer infrastructure.
2084 let app_accessible_memory_bytes: *mut u8 = app_accessible_memory.cast();
2085 // SAFETY: `app_accessible_memory_bytes` is from a slice, and we use that
2086 // slice's length, so we know that there is enough memory and that the
2087 // pointer is aligned.
2088 unsafe {
2089 core::ptr::write_bytes(
2090 app_accessible_memory_bytes,
2091 // Set the entire app-accessible memory region to `0`:
2092 0_u8,
2093 app_accessible_memory.len(),
2094 );
2095 }
2096
2097 // Set the initial process-accessible memory.
2098 //
2099 // SAFETY: By using the slice `app_accessible_memory` and getting a pointer to
2100 // the byte after the slice, we are ensured that the memory between the
2101 // start of the allocation and the new pointer (at the end of the slice)
2102 // is valid because of the existing slice.
2103 let initial_app_brk = unsafe {
2104 app_accessible_memory
2105 .cast::<u8>()
2106 .add(app_accessible_memory.len())
2107 };
2108
2109 // Set the initial allow high water mark to the start of process memory
2110 // since no `allow` calls have been made yet.
2111 let initial_allow_high_water_mark = app_accessible_memory.cast();
2112
2113 // Set up initial grant region.
2114 //
2115 // `kernel_memory_break` is set to the end of kernel-accessible memory
2116 // and grows downward.
2117 let mut kernel_memory_break: *mut u8 = allocated_kernel_memory
2118 .cast::<u8>()
2119 .wrapping_add(allocated_kernel_memory.len());
2120
2121 ////////////////////////
2122 // Grant Region Pointers
2123 ////////////////////////
2124
2125 // Now that we know we have the space we can setup the grant pointers.
2126 //
2127 // First, move `kernel_memory_break` up to make room for the grant pointers.
2128 kernel_memory_break = kernel_memory_break.wrapping_sub(grant_ptrs_size);
2129 // Next, use the extra alignment padding we factored in to the total
2130 // calculation of `initial_kernel_memory_size` to ensure that
2131 // `kernel_memory_break` is aligned to a `GrantPointerEntry`.
2132 kernel_memory_break = kernel_memory_break
2133 .wrapping_sub(kernel_memory_break as usize % Self::GRANT_POINTERS_ALIGNMENT);
2134
2135 // Create the `GrantPointerEntry`s in the kernel region, then initialize
2136 // them.
2137 //
2138 // Where we calculated the updated kernel_memory_break is where the
2139 // `GrantPointerEntry`s start.
2140 let grant_pointers_memory_location: *mut MaybeUninit<GrantPointerEntry> =
2141 kernel_memory_break.cast();
2142 // Get a reference to the slice of `GrantPointerEntry`s.
2143 //
2144 // SAFETY: This is safe, as `grant_pointers_memory_location` is aligned to a
2145 // `GrantPointerEntry`, and we ensured there is space for
2146 // `grant_ptrs_num` of `GrantPointerEntry`s allocated.
2147 let grant_pointers_uninit: &mut [MaybeUninit<GrantPointerEntry>] =
2148 unsafe { slice::from_raw_parts_mut(grant_pointers_memory_location, grant_ptrs_num) };
2149 // Set all grant pointers to null.
2150 for grant_entry in grant_pointers_uninit.iter_mut() {
2151 grant_entry.write(GrantPointerEntry {
2152 driver_num: 0,
2153 grant_ptr: core::ptr::null_mut(),
2154 });
2155 }
2156 // SAFETY: All values in this slice have been properly initialized.
2157 let grant_pointers = unsafe { maybe_uninit_slice_assume_init_mut(grant_pointers_uninit) };
2158
2159 ////////////////////////
2160 // Upcall Queue
2161 ////////////////////////
2162
2163 // Now that we know we have the space we can setup the memory for the
2164 // upcalls.
2165 //
2166 // Move our `kernel_memory_break` up the size of the callback slice.
2167 kernel_memory_break = kernel_memory_break.wrapping_sub(Self::CALLBACKS_SIZE);
2168 // Use the space we allocated for alignment in case the pointer is not aligned.
2169 kernel_memory_break = kernel_memory_break
2170 .wrapping_sub(kernel_memory_break as usize % Self::CALLBACKS_ALIGNMENT);
2171
2172 // Set up ring buffer for upcalls to the process. The memory is uninitialized here,
2173 // so we cast to MaybeUninit<Task> which accurately represents that state.
2174 let upcall_buf: *mut core::mem::MaybeUninit<Task> = kernel_memory_break.cast();
2175
2176 // Get a reference `&mut [Task; Self:CALLBACK_LEN]`
2177 //
2178 // SAFETY: This needs to be aligned and have allocated space for
2179 // `Self::CALLBACK_LEN` instances of `Task`. We ensured there is enough
2180 // space when we allocated `allocated_kernel_memory` and we moved
2181 // kernel_memory_break up to fit the callbacks. We ensured this is
2182 // aligned by moving `kernel_memory_break` up if needed, and we
2183 // accounted for that potential increase in size when we allocated
2184 // `allocated_kernel_memory`.
2185 let upcall_buf = unsafe { slice::from_raw_parts_mut(upcall_buf, Self::CALLBACK_LEN) };
2186 // Actually setup the ring buffer.
2187 let tasks = RingBuffer::new(upcall_buf);
2188
2189 ////////////////////////
2190 // ProcessStandard
2191 ////////////////////////
2192
2193 // Last thing in the kernel region of process RAM is the process struct.
2194 //
2195 // Move `kernel_memory_break` to make room for the `ProcessStandard` struct.
2196 kernel_memory_break = kernel_memory_break.wrapping_sub(Self::PROCESS_STRUCT_SIZE);
2197 // Use the space we allocated for alignment in case the pointer is not aligned.
2198 kernel_memory_break = kernel_memory_break
2199 .wrapping_sub(kernel_memory_break as usize % Self::PROCESS_STRUCT_ALIGNMENT);
2200
2201 // Create a pointer to where the `ProcessStandard` struct will go in the
2202 // app grant region.
2203 let process_struct_memory_location: *mut MaybeUninit<ProcessStandard<'static, C, D>> =
2204 kernel_memory_break.cast();
2205 // Get a reference to the uninitialized `ProcessStandard` object.
2206 //
2207 // Note, this requires every field be explicitly initialized, as we are
2208 // just transforming a pointer into a structure. Because the
2209 // `ProcessStandard` is not initialized we mark it with `MaybeUninit`.
2210 //
2211 // SAFETY: This must have sufficient allocated space and proper alignment. When
2212 // we sized `allocated_kernel_memory` we ensured there was room for the
2213 // entire `ProcessStandard` struct. We also allocated space for
2214 // potential alignment issues, and ensured `kernel_memory_break` was
2215 // properly aligned for `ProcessStandard`.
2216 let process_uninit: &mut MaybeUninit<ProcessStandard<C, D>> =
2217 unsafe { &mut *process_struct_memory_location };
2218
2219 // Initialize ALL fields of `ProcessStandard`.
2220 //
2221 // SAFETY: These need to be valid and aligned writes. When we create the `MaybeUnint`
2222 // ProcessStandard struct we ensure there is valid memory for the object and
2223 // that it is aligned.
2224 unsafe {
2225 init_uninit_struct!(process_uninit => ProcessStandard<C, D> {
2226 process_id: Cell::new(ProcessId::new(
2227 kernel,
2228 kernel.create_process_identifier(),
2229 index,
2230 )),
2231 app_id: app_id,
2232 kernel: kernel,
2233 chip: chip,
2234 allow_high_water_mark: Cell::new(initial_allow_high_water_mark),
2235 memory_start: allocated_memory_start,
2236 memory_len: allocated_memory_len,
2237 header: pb.header,
2238 kernel_memory_break: Cell::new(kernel_memory_break),
2239 app_break: Cell::new(initial_app_brk),
2240 grant_pointers: MapCell::new(grant_pointers),
2241
2242 credential: pb.credential.get(),
2243 footers: pb.footers,
2244 flash: pb.flash,
2245
2246 stored_state: MapCell::new(Default::default()),
2247 state: Cell::new(State::Yielded),
2248 fault_policy: fault_policy,
2249 restart_count: Cell::new(0),
2250 completion_code: OptionalCell::empty(),
2251
2252 storage_permissions: Cell::new(StoragePermissions::new_null()),
2253
2254 mpu_config: MapCell::new(mpu_config),
2255 mpu_regions: [
2256 Cell::new(None),
2257 Cell::new(None),
2258 Cell::new(None),
2259 Cell::new(None),
2260 Cell::new(None),
2261 Cell::new(None),
2262 ],
2263 tasks: MapCell::new(tasks),
2264 is_yield_wait_for_ready: Cell::new(false),
2265
2266 debug: D::default(),
2267 });
2268 }
2269
2270 // Convert the originally uninitialized `ProcessStandard` to a proper
2271 // `ProcessStandard` struct reference.
2272 //
2273 // SAFETY: All fields in `ProcessStandard` must be initialized. We guaranteed
2274 // this by using the `init_uninit_struct!()` macro, which causes a
2275 // compiler error if there is a missing field.
2276 let process = unsafe { process_uninit.assume_init_mut() };
2277
2278 // Save copies of these in case the app was compiled for fixed addresses
2279 // for later debugging.
2280 let fixed_address_flash = process.header.get_fixed_address_flash();
2281 let fixed_address_ram = process.header.get_fixed_address_ram();
2282 if let Some(fix_addr_flash) = fixed_address_flash {
2283 process.debug.set_fixed_address_flash(fix_addr_flash);
2284 }
2285 if let Some(fix_addr_ram) = fixed_address_ram {
2286 process.debug.set_fixed_address_ram(fix_addr_ram);
2287 }
2288
2289 // Handle any architecture-specific requirements for a new process.
2290 match process.stored_state.map(|stored_state| {
2291 // SAFETY: NOTE! We have to ensure that the start of process-accessible memory
2292 // (`app_memory_start`) is word-aligned. Since we currently start
2293 // process-accessible memory at the beginning of the allocated memory
2294 // region, we trust the MPU to give us a word-aligned starting address.
2295 //
2296 // TODO: https://github.com/tock/tock/issues/1739
2297 unsafe {
2298 chip.userspace_kernel_boundary().initialize_process(
2299 app_accessible_memory.cast(),
2300 initial_app_brk,
2301 stored_state,
2302 )
2303 }
2304 }) {
2305 Some(Ok(())) => {}
2306 _ => {
2307 if config::CONFIG.debug_load_processes {
2308 debug!(
2309 "[!] flash={:#010X}-{:#010X} process={:?} - couldn't initialize process",
2310 pb.flash.as_ptr() as usize,
2311 pb.flash.as_ptr() as usize + pb.flash.len() - 1,
2312 process_name
2313 );
2314 }
2315 // Note that since remaining_memory was split by split_at_mut into
2316 // application memory and unused_memory, a failure here will leak
2317 // the application memory. Not leaking it requires being able to
2318 // reconstitute the original memory slice.
2319 return Err((ProcessLoadError::InternalError, unused_memory));
2320 }
2321 }
2322
2323 let flash_start: *const u8 = process.flash.as_ptr();
2324 let app_start =
2325 flash_start.wrapping_add(process.header.get_app_start_offset() as usize) as usize;
2326 let init_addr: *const () = flash_start
2327 .wrapping_add(process.header.get_init_function_offset() as usize)
2328 .cast();
2329 let fn_base = flash_start as usize;
2330 let fn_len = process.flash.len();
2331
2332 // We need to construct a capability with sufficient authority to cover
2333 // all of a user's code, with permissions to execute it. The entirety
2334 // of this process's flash is sufficient.
2335 //
2336 // SAFETY: It must be safe for this process to access the
2337 // bounds+permission expressed here while assuming no other protection
2338 // mechanism is active.
2339 // - It is valid under Tock's threat model for a process to try to
2340 // execute anything within process-owned flash.
2341 // - `process.flash` which we use to derive the bounds is defined as
2342 // process-owned flash for a well-formed process, which we trust is
2343 // the case here.
2344 // - We grant only execute permission.
2345 // - We only pass this pointer to this process.
2346 let init_fn = unsafe {
2347 CapabilityPtr::new_with_authority(
2348 init_addr,
2349 fn_base,
2350 fn_len,
2351 CapabilityPtrPermissions::Execute,
2352 )
2353 };
2354
2355 process.tasks.map(|tasks| {
2356 tasks.enqueue(Task::FunctionCall(FunctionCall {
2357 source: FunctionCallSource::Kernel,
2358 pc: init_fn,
2359 argument0: app_start,
2360 argument1: process.memory_start as usize,
2361 argument2: process.memory_len,
2362 argument3: (process.app_break.get() as usize).into(),
2363 }));
2364 });
2365
2366 // Set storage permissions. Put this at the end so that `process` is
2367 // completely formed before using it to determine the storage
2368 // permissions.
2369 process
2370 .storage_permissions
2371 .set(storage_permissions_policy.get_permissions(process));
2372
2373 // Return the process object and a remaining memory for processes slice.
2374 Ok((Some(process), unused_memory))
2375 }
2376
2377 /// Reset the process, resetting all of its state and re-initializing it so
2378 /// it can start running. Assumes the process is not running but is still in
2379 /// flash and still has its memory region allocated to it.
2380 fn reset(&self) -> Result<(), ErrorCode> {
2381 // We need a new process identifier for this process since the restarted
2382 // version is in effect a new process. This is also necessary to
2383 // invalidate any stored `ProcessId`s that point to the old version of
2384 // the process. However, the process has not moved locations in the
2385 // processes array, so we copy the existing index.
2386 let old_index = self.process_id.get().index;
2387 let new_identifier = self.kernel.create_process_identifier();
2388 self.process_id
2389 .set(ProcessId::new(self.kernel, new_identifier, old_index));
2390
2391 // Reset debug information that is per-execution and not per-process.
2392 self.debug.reset_last_syscall();
2393 self.debug.reset_syscall_count();
2394 self.debug.reset_dropped_upcall_count();
2395 self.debug.reset_timeslice_expiration_count();
2396
2397 // Reset MPU region configuration.
2398 //
2399 // TODO: ideally, this would be moved into a helper function used by
2400 // both create() and reset(), but process load debugging complicates
2401 // this. We just want to create new config with only flash and memory
2402 // regions.
2403 //
2404 // We must have a previous MPU configuration stored, fault the
2405 // process if this invariant is violated. We avoid allocating
2406 // a new MPU configuration, as this may eventually exhaust the
2407 // number of available MPU configurations.
2408 let mut mpu_config = self.mpu_config.take().ok_or(ErrorCode::FAIL)?;
2409 self.chip.mpu().reset_config(&mut mpu_config);
2410
2411 // Allocate MPU region for flash.
2412 let app_mpu_flash = self.chip.mpu().allocate_region(
2413 self.flash.as_ptr(),
2414 self.flash.len(),
2415 self.flash.len(),
2416 mpu::Permissions::ReadExecuteOnly,
2417 &mut mpu_config,
2418 );
2419 if app_mpu_flash.is_none() {
2420 // We were unable to allocate an MPU region for flash. This is very
2421 // unexpected since we previously ran this process. However, we
2422 // return now and leave the process faulted and it will not be
2423 // scheduled.
2424 return Err(ErrorCode::FAIL);
2425 }
2426
2427 // RAM
2428
2429 // Re-determine the minimum amount of RAM the kernel must allocate to
2430 // the process based on the specific requirements of the syscall
2431 // implementation.
2432 let min_process_memory_size = self
2433 .chip
2434 .userspace_kernel_boundary()
2435 .initial_process_app_brk_size();
2436
2437 // Recalculate initial_kernel_memory_size as was done in create()
2438 let grant_ptr_size = mem::size_of::<GrantPointerEntry>();
2439 let grant_ptrs_num = self.kernel.get_grant_count_and_finalize();
2440 let grant_ptrs_size = grant_ptrs_num * grant_ptr_size;
2441
2442 let initial_kernel_memory_size = grant_ptrs_size
2443 + Self::GRANT_POINTERS_ALIGNMENT
2444 + Self::CALLBACKS_SIZE
2445 + Self::CALLBACKS_ALIGNMENT
2446 + Self::PROCESS_STRUCT_SIZE
2447 + Self::PROCESS_STRUCT_ALIGNMENT;
2448
2449 let app_mpu_mem = self.chip.mpu().allocate_app_memory_region(
2450 self.mem_start(),
2451 self.memory_len,
2452 self.memory_len, //we want exactly as much as we had before restart
2453 min_process_memory_size,
2454 initial_kernel_memory_size,
2455 mpu::Permissions::ReadWriteOnly,
2456 &mut mpu_config,
2457 );
2458 let (app_mpu_mem_start, app_mpu_mem_len) = match app_mpu_mem {
2459 Some((start, len)) => (start, len),
2460 None => {
2461 // We couldn't configure the MPU for the process. This shouldn't
2462 // happen since we were able to start the process before, but at
2463 // this point it is better to leave the app faulted and not
2464 // schedule it.
2465 return Err(ErrorCode::NOMEM);
2466 }
2467 };
2468
2469 // Reset memory pointers now that we know the layout of the process
2470 // memory and know that we can configure the MPU.
2471
2472 // app_brk is set based on minimum syscall size above the start of
2473 // memory.
2474 let app_brk = app_mpu_mem_start.wrapping_add(min_process_memory_size);
2475 self.app_break.set(app_brk);
2476 // kernel_brk is calculated backwards from the end of memory the size of
2477 // the initial kernel data structures.
2478 let kernel_brk = app_mpu_mem_start
2479 .wrapping_add(app_mpu_mem_len)
2480 .wrapping_sub(initial_kernel_memory_size);
2481 self.kernel_memory_break.set(kernel_brk);
2482 // High water mark for `allow`ed memory is reset to the start of the
2483 // process's memory region.
2484 self.allow_high_water_mark.set(app_mpu_mem_start);
2485
2486 // Store the adjusted MPU configuration:
2487 self.mpu_config.replace(mpu_config);
2488
2489 // Handle any architecture-specific requirements for a process when it
2490 // first starts (as it would when it is new).
2491 let ukb_init_process = self.stored_state.map_or(Err(()), |stored_state| {
2492 // SAFETY: The memory bounds must be valid for this process. We know
2493 // this is true here because we use the start of process memory and
2494 // the current `app_brk`, and that range is accessible to the
2495 // process.
2496 unsafe {
2497 self.chip.userspace_kernel_boundary().initialize_process(
2498 app_mpu_mem_start,
2499 app_brk,
2500 stored_state,
2501 )
2502 }
2503 });
2504 match ukb_init_process {
2505 Ok(()) => {}
2506 Err(()) => {
2507 // We couldn't initialize the architecture-specific state for
2508 // this process. This shouldn't happen since the app was able to
2509 // be started before, but at this point the app is no longer
2510 // valid. The best thing we can do now is leave the app as still
2511 // faulted and not schedule it.
2512 return Err(ErrorCode::RESERVE);
2513 }
2514 }
2515
2516 self.restart_count.increment();
2517
2518 // Mark the state as `Yielded` for the scheduler.
2519 self.state.set(State::Yielded);
2520
2521 // And queue up this app to be restarted.
2522 let flash_start: *const u8 = self.flash_start();
2523 let app_start =
2524 flash_start.wrapping_add(self.header.get_app_start_offset() as usize) as usize;
2525 let init_addr: *const () = flash_start
2526 .wrapping_add(self.header.get_init_function_offset() as usize)
2527 .cast();
2528
2529 // We need to construct a capability with sufficient authority to cover
2530 // all of a user's code, with permissions to execute it. The entirety
2531 // of this process's flash is sufficient.
2532 //
2533 // SAFETY: It must be safe for this process to access the
2534 // bounds+permission expressed here while assuming no other protection
2535 // mechanism is active.
2536 // - It is valid under Tock's threat model for a process to try to
2537 // execute anything within process-owned flash.
2538 // - `self.flash` which we use to derive the bounds is defined as
2539 // process-owned flash for a well-formed process, which we trust is
2540 // the case here.
2541 // - We grant only execute permission.
2542 // - We only pass this pointer to this process.
2543 let init_fn = unsafe {
2544 CapabilityPtr::new_with_authority(
2545 init_addr,
2546 flash_start as usize,
2547 self.flash_end() - (flash_start as usize),
2548 CapabilityPtrPermissions::Execute,
2549 )
2550 };
2551
2552 self.enqueue_task(Task::FunctionCall(FunctionCall {
2553 source: FunctionCallSource::Kernel,
2554 pc: init_fn,
2555 argument0: app_start,
2556 argument1: self.memory_start as usize,
2557 argument2: self.memory_len,
2558 argument3: (self.app_break.get() as usize).into(),
2559 }))
2560 }
2561
2562 /// Checks if the buffer represented by the passed in base pointer and size
2563 /// is within the RAM bounds currently exposed to the processes (i.e. ending
2564 /// at `app_break`). If this method returns `true`, the buffer is guaranteed
2565 /// to be accessible to the process and to not overlap with the grant
2566 /// region.
2567 fn in_app_owned_memory(&self, buf_start_addr: *const u8, size: usize) -> bool {
2568 // TODO: On some platforms, CapabilityPtr has sufficient authority that we
2569 // could skip this check.
2570 // CapabilityPtr needs to make it slightly further, and we need to add
2571 // interfaces that tell us how much assurance it gives on the current
2572 // platform.
2573 let buf_end_addr = buf_start_addr.wrapping_add(size);
2574
2575 buf_end_addr >= buf_start_addr
2576 && buf_start_addr >= self.mem_start()
2577 && buf_end_addr <= self.app_break.get()
2578 }
2579
2580 /// Checks if the buffer represented by the passed in base pointer and size
2581 /// are within the readable region of an application's flash memory. If
2582 /// this method returns true, the buffer is guaranteed to be readable to the
2583 /// process.
2584 fn in_app_flash_memory(&self, buf_start_addr: *const u8, size: usize) -> bool {
2585 #![allow(
2586 clippy::suspicious_operation_groupings,
2587 reason = "false positive on flash_non_protected_start"
2588 )]
2589
2590 // TODO: On some platforms, CapabilityPtr has sufficient authority that we
2591 // could skip this check.
2592 // CapabilityPtr needs to make it slightly further, and we need to add
2593 // interfaces that tell us how much assurance it gives on the current
2594 // platform.
2595 let buf_end_addr = buf_start_addr.wrapping_add(size);
2596
2597 buf_end_addr >= buf_start_addr
2598 && buf_start_addr.addr() >= self.flash_non_protected_start()
2599 && buf_end_addr.addr() <= self.flash_end()
2600 }
2601
2602 /// Allocate memory in a process's grant region.
2603 ///
2604 /// Ensures that the allocation is of `size` bytes and aligned to `align`
2605 /// bytes.
2606 ///
2607 /// If there is not enough memory, or the MPU cannot isolate the process
2608 /// accessible region from the new kernel memory break after doing the
2609 /// allocation, then this will return `None`.
2610 fn allocate_in_grant_region_internal(&self, size: usize, align: usize) -> Option<NonNull<u8>> {
2611 self.mpu_config.and_then(|config| {
2612 // First, compute the candidate new pointer. Note that at this point
2613 // we have not yet checked whether there is space for this
2614 // allocation or that it meets alignment requirements.
2615 let new_break_unaligned = self.kernel_memory_break.get().wrapping_sub(size);
2616
2617 // Our minimum alignment requirement is two bytes, so that the
2618 // lowest bit of the address will always be zero and we can use it
2619 // as a flag. It doesn't hurt to increase the alignment (except for
2620 // potentially a wasted byte) so we make sure `align` is at least
2621 // two.
2622 let align = cmp::max(align, 2);
2623
2624 // The alignment must be a power of two, 2^a. The expression
2625 // `!(align - 1)` then returns a mask with leading ones, followed by
2626 // `a` trailing zeros.
2627 let alignment_mask = !(align - 1);
2628 let new_break = new_break_unaligned.map_addr(|a| a & alignment_mask);
2629
2630 // Verify there is space for this allocation
2631 if new_break < self.app_break.get() {
2632 None
2633 // Verify it didn't wrap around
2634 } else if new_break > self.kernel_memory_break.get() {
2635 None
2636 // Verify this is compatible with the MPU.
2637 } else if let Err(()) = self.chip.mpu().update_app_memory_region(
2638 self.app_break.get(),
2639 new_break,
2640 mpu::Permissions::ReadWriteOnly,
2641 config,
2642 ) {
2643 None
2644 } else {
2645 // Allocation is valid.
2646
2647 // We always allocate down, so we must lower the
2648 // kernel_memory_break.
2649 self.kernel_memory_break.set(new_break);
2650
2651 // We need `grant_ptr` as a mutable pointer.
2652 let grant_ptr: *mut u8 = new_break.cast_mut();
2653
2654 // SAFETY: Here we are guaranteeing that `grant_ptr` is not null. We can
2655 // ensure this because we just created `grant_ptr` based on the
2656 // process's allocated memory, and we know it cannot be null.
2657 unsafe { Some(NonNull::new_unchecked(grant_ptr)) }
2658 }
2659 })
2660 }
2661
2662 /// Create the identifier for a custom grant that grant.rs uses to access
2663 /// the custom grant.
2664 ///
2665 /// We create this identifier by calculating the number of bytes between
2666 /// where the custom grant starts and the end of the process memory.
2667 fn create_custom_grant_identifier(&self, ptr: NonNull<u8>) -> ProcessCustomGrantIdentifier {
2668 let custom_grant_address = ptr.as_ptr() as usize;
2669 let process_memory_end = self.mem_end() as usize;
2670
2671 ProcessCustomGrantIdentifier {
2672 offset: process_memory_end - custom_grant_address,
2673 }
2674 }
2675
2676 /// Use a `ProcessCustomGrantIdentifier` to find the address of the
2677 /// custom grant.
2678 ///
2679 /// This reverses `create_custom_grant_identifier()`.
2680 fn get_custom_grant_address(&self, identifier: ProcessCustomGrantIdentifier) -> usize {
2681 let process_memory_end = self.mem_end() as usize;
2682
2683 // Subtract the offset in the identifier from the end of the process
2684 // memory to get the address of the custom grant.
2685 process_memory_end - identifier.offset
2686 }
2687
2688 /// Return the app's read and modify storage permissions from the TBF header
2689 /// if it exists.
2690 ///
2691 /// If the header does not exist then return `None`. If the header does
2692 /// exist, this returns a 5-tuple with:
2693 ///
2694 /// - `write_allowed`: bool. If this process should have write permissions.
2695 /// - `read_count`: usize. How many read IDs are valid.
2696 /// - `read_ids`: [u32]. The read IDs.
2697 /// - `modify_count`: usze. How many modify IDs are valid.
2698 /// - `modify_ids`: [u32]. The modify IDs.
2699 pub fn get_tbf_storage_permissions(&self) -> Option<(bool, usize, [u32; 8], usize, [u32; 8])> {
2700 let read_perms = self.header.get_storage_read_ids();
2701 let modify_perms = self.header.get_storage_modify_ids();
2702
2703 match (read_perms, modify_perms) {
2704 (Some((read_count, read_ids)), Some((modify_count, modify_ids))) => Some((
2705 self.header.get_storage_write_id().is_some(),
2706 read_count,
2707 read_ids,
2708 modify_count,
2709 modify_ids,
2710 )),
2711 _ => None,
2712 }
2713 }
2714
2715 /// The start address of allocated RAM for this process.
2716 fn mem_start(&self) -> *const u8 {
2717 self.memory_start
2718 }
2719
2720 /// The first address after the end of the allocated RAM for this process.
2721 fn mem_end(&self) -> *const u8 {
2722 self.memory_start.wrapping_add(self.memory_len)
2723 }
2724
2725 /// The start address of the flash region allocated for this process.
2726 fn flash_start(&self) -> *const u8 {
2727 self.flash.as_ptr()
2728 }
2729
2730 /// Get the first address of process's flash that isn't protected by the
2731 /// kernel. The protected range of flash contains the TBF header and
2732 /// potentially other state the kernel is storing on behalf of the process,
2733 /// and cannot be edited by the process.
2734 fn flash_non_protected_start(&self) -> usize {
2735 (self.flash.as_ptr() as usize) + self.header.get_protected_size() as usize
2736 }
2737
2738 /// The first address after the end of the flash region allocated for this
2739 /// process.
2740 fn flash_end(&self) -> usize {
2741 self.flash.as_ptr().addr().wrapping_add(self.flash.len())
2742 }
2743
2744 /// The lowest address of the grant region for the process.
2745 fn kernel_memory_break(&self) -> *const u8 {
2746 self.kernel_memory_break.get()
2747 }
2748
2749 /// Return the highest address the process has access to, or the current
2750 /// process memory brk.
2751 fn app_memory_break(&self) -> *const u8 {
2752 self.app_break.get()
2753 }
2754}