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