kernel/
process.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//! Types for Tock-compatible processes.
6
7use core::fmt;
8use core::fmt::Write;
9use core::num::NonZeroU32;
10use core::ptr::NonNull;
11use core::str;
12
13use crate::capabilities;
14use crate::errorcode::ErrorCode;
15use crate::ipc;
16use crate::kernel::Kernel;
17use crate::platform::mpu::{self};
18use crate::processbuffer::{ReadOnlyProcessBuffer, ReadWriteProcessBuffer};
19use crate::storage_permissions;
20use crate::syscall::{self, Syscall, SyscallReturn};
21use crate::upcall::UpcallId;
22use crate::utilities::capability_ptr::CapabilityPtr;
23use crate::utilities::machine_register::MachineRegister;
24use tock_tbf::types::CommandPermissions;
25
26// Export all process related types via `kernel::process::`.
27pub use crate::process_binary::ProcessBinary;
28pub use crate::process_checker::AcceptedCredential;
29pub use crate::process_checker::{ProcessCheckerMachine, ProcessCheckerMachineClient};
30pub use crate::process_loading::load_processes;
31pub use crate::process_loading::ProcessLoadError;
32pub use crate::process_loading::SequentialProcessLoaderMachine;
33pub use crate::process_loading::{ProcessLoadingAsync, ProcessLoadingAsyncClient};
34pub use crate::process_policies::{ProcessFaultPolicy, ProcessStandardStoragePermissionsPolicy};
35pub use crate::process_printer::{ProcessPrinter, ProcessPrinterContext};
36pub use crate::process_standard::ProcessStandard;
37pub use crate::process_standard::{ProcessStandardDebug, ProcessStandardDebugFull};
38
39/// Userspace process identifier.
40///
41/// This is an opaque type that can be used to represent a running process on
42/// the board without requiring an actual reference to a `Process` object.
43/// Having this `ProcessId` reference type is useful for managing ownership and
44/// type issues in Rust, but more importantly `ProcessId` serves as a tool for
45/// capsules to hold pointers to applications.
46///
47/// Since `ProcessId` implements `Copy`, having an `ProcessId` does _not_ ensure
48/// that the process the `ProcessId` refers to is still valid. The process may
49/// have been removed, terminated, or restarted as a new process. Therefore, all
50/// uses of `ProcessId` in the kernel must check that the `ProcessId` is still
51/// valid. This check happens automatically when `.index()` is called, as noted
52/// by the return type: `Option<usize>`. `.index()` will return the index of the
53/// process in the processes array, but if the process no longer exists then
54/// `None` is returned.
55///
56/// Outside of the kernel crate, holders of an `ProcessId` may want to use
57/// `.id()` to retrieve a simple identifier for the process that can be
58/// communicated over a UART bus or syscall interface. This call is guaranteed
59/// to return a suitable identifier for the `ProcessId`, but does not check that
60/// the corresponding application still exists.
61///
62/// This type also provides capsules an interface for interacting with processes
63/// since they otherwise would have no reference to a `Process`. Very limited
64/// operations are available through this interface since capsules should not
65/// need to know the details of any given process. However, certain information
66/// makes certain capsules possible to implement. For example, capsules can use
67/// the `get_editable_flash_range()` function so they can safely allow an app to
68/// modify its own flash.
69#[derive(Clone, Copy)]
70pub struct ProcessId {
71    /// Reference to the main kernel struct. This is needed for checking on
72    /// certain properties of the referred app (like its editable bounds), but
73    /// also for checking that the index is valid.
74    pub(crate) kernel: &'static Kernel,
75
76    /// The index in the kernel.PROCESSES[] array where this app's state is
77    /// stored. This makes for fast lookup of the process and helps with
78    /// implementing IPC.
79    ///
80    /// This value is crate visible to enable optimizations in sched.rs. Other
81    /// users should call `.index()` instead.
82    pub(crate) index: usize,
83
84    /// The unique identifier for this process. This can be used to refer to the
85    /// process in situations where a single number is required, for instance
86    /// when referring to specific applications across the syscall interface.
87    ///
88    /// The combination of (index, identifier) is used to check if the app this
89    /// `ProcessId` refers to is still valid. If the stored identifier in the
90    /// process at the given index does not match the value saved here, then the
91    /// process moved or otherwise ended, and this `ProcessId` is no longer
92    /// valid.
93    identifier: usize,
94}
95
96impl PartialEq for ProcessId {
97    fn eq(&self, other: &ProcessId) -> bool {
98        self.identifier == other.identifier
99    }
100}
101
102impl Eq for ProcessId {}
103
104impl fmt::Debug for ProcessId {
105    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
106        // We handle alignment and width.
107        if let Some(width) = formatter.width() {
108            match formatter.align() {
109                Some(fmt::Alignment::Left) => {
110                    write!(formatter, "{:<width$}", self.identifier, width = width)
111                }
112                Some(fmt::Alignment::Right) => {
113                    write!(formatter, "{:width$}", self.identifier, width = width)
114                }
115                Some(fmt::Alignment::Center) => {
116                    write!(formatter, "{:^width$}", self.identifier, width = width)
117                }
118                None => write!(formatter, "{:width$}", self.identifier, width = width),
119            }
120        } else {
121            // Otherwise just do default.
122            write!(formatter, "{}", self.identifier)
123        }
124    }
125}
126
127impl ProcessId {
128    /// Create a new `ProcessId` object based on the app identifier and its
129    /// index in the processes array.
130    pub(crate) fn new(kernel: &'static Kernel, identifier: usize, index: usize) -> ProcessId {
131        ProcessId {
132            kernel,
133            index,
134            identifier,
135        }
136    }
137
138    /// Create a new `ProcessId` object based on the app identifier and its
139    /// index in the processes array.
140    ///
141    /// This constructor is public but protected with a capability so that
142    /// external implementations of `Process` can use it.
143    pub fn new_external(
144        kernel: &'static Kernel,
145        identifier: usize,
146        index: usize,
147        _capability: &dyn capabilities::ExternalProcessCapability,
148    ) -> ProcessId {
149        ProcessId {
150            kernel,
151            index,
152            identifier,
153        }
154    }
155
156    /// Get the location of this app in the processes array.
157    ///
158    /// This will return `Some(index)` if the identifier stored in this
159    /// `ProcessId` matches the app saved at the known index. If the identifier
160    /// does not match then `None` will be returned.
161    pub(crate) fn index(&self) -> Option<usize> {
162        // Do a lookup to make sure that the index we have is correct.
163        if self.kernel.processid_is_valid(self) {
164            Some(self.index)
165        } else {
166            None
167        }
168    }
169
170    /// Get a `usize` unique identifier for the app this `ProcessId` refers to.
171    ///
172    /// This function should not generally be used, instead code should just use
173    /// the `ProcessId` object itself to refer to various apps on the system.
174    /// However, getting just a `usize` identifier is particularly useful when
175    /// referring to a specific app with things outside of the kernel, say for
176    /// userspace (e.g. IPC) or tockloader (e.g. for debugging) where a concrete
177    /// number is required.
178    ///
179    /// Note, this will always return the saved unique identifier for the app
180    /// originally referred to, even if that app no longer exists. For example,
181    /// the app may have restarted, or may have been ended or removed by the
182    /// kernel. Therefore, calling `id()` is _not_ a valid way to check that an
183    /// application still exists.
184    pub fn id(&self) -> usize {
185        self.identifier
186    }
187
188    /// Get the `ShortId` for this application this process is an execution of.
189    ///
190    /// The `ShortId` is an identifier for the _application_, not the particular
191    /// execution (i.e. the currently running process). This makes `ShortId`
192    /// distinct from `ProcessId`.
193    ///
194    /// This function is a helper function as capsules typically use `ProcessId`
195    /// as a handle to the running process and corresponding app.
196    pub fn short_app_id(&self) -> ShortId {
197        self.kernel
198            .process_map_or(ShortId::LocallyUnique, *self, |process| {
199                process.short_app_id()
200            })
201    }
202
203    /// Returns the full address of the start and end of the flash region that
204    /// the app owns and can write to. This includes the app's code and data and
205    /// any padding at the end of the app. It does not include the TBF header,
206    /// or any space that the kernel is using for any potential bookkeeping.
207    pub fn get_editable_flash_range(&self) -> (usize, usize) {
208        self.kernel.process_map_or((0, 0), *self, |process| {
209            let addresses = process.get_addresses();
210            (addresses.flash_non_protected_start, addresses.flash_end)
211        })
212    }
213
214    /// Get the storage permissions for the process. These permissions indicate
215    /// what the process is allowed to read and write. Returns `None` if the
216    /// process has no storage permissions.
217    pub fn get_storage_permissions(&self) -> Option<storage_permissions::StoragePermissions> {
218        self.kernel.process_map_or(None, *self, |process| {
219            Some(process.get_storage_permissions())
220        })
221    }
222}
223
224/// A compressed form of an Application Identifier.
225///
226/// ShortIds are useful for more efficient operations with app identifiers
227/// within the kernel. They are guaranteed to be unique among all running
228/// processes on the same board. However, as they are only 32 bits they are not
229/// globally unique.
230///
231/// ShortIds are persistent across restarts of the same app (whereas ProcessIDs
232/// are not).
233///
234/// As ShortIds must be unique for each app on a board, and since not every
235/// platform may have a use for ShortIds, the definition of a ShortId provides a
236/// convenient mechanism for meeting the uniqueness requirement without actually
237/// requiring assigning unique discrete values to each app. This is done with
238/// the `LocallyUnique` variant which is an abstract ID that is guaranteed to be
239/// unique (i.e. an equality comparison with any other ShortId will always
240/// return `false`). Platforms which have a use for an actual number for a
241/// `ShortId` should use the `Fixed(NonZeroU32)` variant. Note, for type space
242/// efficiency, we disallow using the number 0 as a fixed ShortId.
243///
244/// ShortIds are assigned to the app as part of the credential checking process.
245/// Specifically, an implementation of the `process_checker::Compress` trait
246/// assigns ShortIds.
247#[derive(Clone, Copy)]
248pub enum ShortId {
249    /// An abstract `ShortId` that is always guaranteed to be unique. As this is
250    /// not an actual discrete value, it cannot be used for anything other than
251    /// meeting the uniqueness requirement.
252    LocallyUnique,
253    /// A 32 bit number `ShortId`. This fixed value is guaranteed to be unique
254    /// among all running processes as the kernel will not start two processes
255    /// with the same ShortId.
256    Fixed(core::num::NonZeroU32),
257}
258
259impl PartialEq for ShortId {
260    fn eq(&self, other: &Self) -> bool {
261        match (self, other) {
262            (ShortId::Fixed(a), ShortId::Fixed(b)) => a == b,
263            _ => false,
264        }
265    }
266}
267impl Eq for ShortId {}
268
269impl core::convert::From<Option<core::num::NonZeroU32>> for ShortId {
270    fn from(id: Option<core::num::NonZeroU32>) -> ShortId {
271        match id {
272            Some(fixed) => ShortId::Fixed(fixed),
273            None => ShortId::LocallyUnique,
274        }
275    }
276}
277
278impl core::fmt::Display for ShortId {
279    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> fmt::Result {
280        match *self {
281            ShortId::LocallyUnique => {
282                write!(fmt, "Unique")
283            }
284            ShortId::Fixed(id) => {
285                write!(fmt, "0x{:<8x} ", id)
286            }
287        }
288    }
289}
290
291/// Enum used to inform scheduler why a process stopped executing (aka why
292/// `do_process()` returned).
293///
294/// This is publicly exported to allow for schedulers implemented outside of the
295/// kernel crate.
296#[derive(PartialEq, Eq)]
297pub enum StoppedExecutingReason {
298    /// The process returned because it is no longer ready to run.
299    NoWorkLeft,
300
301    /// The process faulted, and the board restart policy was configured such
302    /// that it was not restarted and there was not a kernel panic.
303    StoppedFaulted,
304
305    /// The kernel stopped the process.
306    Stopped,
307
308    /// The process was preempted because its timeslice expired.
309    TimesliceExpired,
310
311    /// The process returned because it was preempted by the kernel. This can
312    /// mean that kernel work became ready (most likely because an interrupt
313    /// fired and the kernel thread needs to execute the bottom half of the
314    /// interrupt), or because the scheduler no longer wants to execute that
315    /// process.
316    KernelPreemption,
317}
318
319/// The version of a binary.
320#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
321pub struct BinaryVersion(NonZeroU32);
322
323impl BinaryVersion {
324    /// Creates a new binary version.
325    pub fn new(value: NonZeroU32) -> Self {
326        Self(value)
327    }
328}
329
330/// This trait represents a generic process that the Tock scheduler can
331/// schedule.
332pub trait Process {
333    /// Returns the process's identifier.
334    fn processid(&self) -> ProcessId;
335
336    /// Returns the [`ShortId`] generated by the application binary checker at
337    /// loading.
338    fn short_app_id(&self) -> ShortId;
339
340    /// Returns the version number of the binary in this process, as specified
341    /// in a TBF Program Header. If the binary has no version assigned this
342    /// returns [`None`].
343    fn binary_version(&self) -> Option<BinaryVersion>;
344
345    /// Return the credential which the credential checker approved if the
346    /// credential checker approved a credential. If the process was allowed to
347    /// run without credentials, return `None`.
348    fn get_credential(&self) -> Option<AcceptedCredential>;
349
350    /// Returns how many times this process has been restarted.
351    fn get_restart_count(&self) -> usize;
352
353    /// Get the name of the process. Used for IPC.
354    fn get_process_name(&self) -> &'static str;
355
356    /// Return if there are any Tasks (upcalls/IPC requests) enqueued for the
357    /// process.
358    fn has_tasks(&self) -> bool;
359
360    /// Returns the number of pending tasks. If 0 then `dequeue_task()` will
361    /// return `None` when called.
362    fn pending_tasks(&self) -> usize;
363
364    /// Queue a [`Task`] for the process. This will be added to a per-process
365    /// buffer and executed by the scheduler. [`Task`]s are some function the
366    /// process should run, for example a upcall or an IPC call.
367    ///
368    /// This function returns:
369    /// - `Ok(())` if the [`Task`] was successfully enqueued.
370    /// - [`Err(ErrorCode::NODEVICE)`] if the process is no longer alive.
371    /// - [`Err(ErrorCode::NOMEM)`] if the task could not be enqueued because
372    ///   there is insufficient space in the internal task queue.
373    ///
374    /// Other return values must be treated as kernel-internal errors.
375    fn enqueue_task(&self, task: Task) -> Result<(), ErrorCode>;
376
377    /// Remove the scheduled operation from the front of the queue and return it
378    /// to be handled by the scheduler.
379    ///
380    /// If there are no [`Task`]s in the queue for this process this will return
381    /// [`None`].
382    fn dequeue_task(&self) -> Option<Task>;
383
384    /// Search the work queue for the first pending operation with the given
385    /// `upcall_id` and if one exists remove it from the queue.process
386    ///
387    /// ## Returns
388    ///
389    /// Returns the associated [`Task`] if one was found, otherwise returns
390    /// [`None`].
391    fn remove_upcall(&self, upcall_id: UpcallId) -> Option<Task>;
392
393    /// Remove all scheduled upcalls with the given `upcall_id` from the task
394    /// queue.
395    ///
396    /// Returns the number of removed upcalls.
397    fn remove_pending_upcalls(&self, upcall_id: UpcallId) -> usize;
398
399    /// Returns the current state the process is in.
400    fn get_state(&self) -> State;
401
402    /// Returns whether this process is ready to execute.
403    ///
404    /// A process is ready if it has work to do or if it was interrupted while
405    /// executing and can continue to execute.
406    ///
407    /// ## Returns
408    ///
409    /// `true` if the process is ready and `false` otherwise.
410    fn ready(&self) -> bool;
411
412    /// Returns whether the process is running or not.
413    ///
414    /// A process is considered running if it is active and has active stack
415    /// frames. A running process can be executed.
416    ///
417    /// A process that is not running cannot be executed. The process may have
418    /// faulted or it may have completed.
419    ///
420    /// ## Returns
421    ///
422    /// `true` if the process is running and `false` otherwise.
423    fn is_running(&self) -> bool;
424
425    /// Move this process from the running state to the yielded state.
426    ///
427    /// This will fail (i.e. not do anything) if the process was not previously
428    /// running.
429    fn set_yielded_state(&self);
430
431    /// Move this process from the running state to the yielded-for state.
432    ///
433    /// This will fail (i.e. not do anything) if the process was not previously
434    /// running.
435    fn set_yielded_for_state(&self, upcall_id: UpcallId);
436
437    /// Move this process from running or yielded state into the stopped state.
438    ///
439    /// This will fail (i.e. not do anything) if the process was not either
440    /// running or yielded.
441    fn stop(&self);
442
443    /// Move this stopped process back into its original state.
444    ///
445    /// This transitions a process from
446    /// [`Stopped`](State::Stopped) to [`Running`](State::Running), [`Yielded`](State::Running) or
447    /// [`YieldedFor`](State::YieldedFor).
448    ///
449    /// This will fail (i.e. not do anything) if the process was not stopped.
450    fn resume(&self);
451
452    /// Put this process in the fault state.
453    ///
454    /// The kernel will use the process's fault policy to decide what action to
455    /// take in regards to the faulted process.
456    fn set_fault_state(&self);
457
458    /// Start a terminated process. This function can only be called on a
459    /// terminated process.
460    ///
461    /// The caller MUST verify this process is unique before calling this
462    /// function. This requires a capability to call to ensure that the caller
463    /// have verified that this process is unique before trying to start it.
464    fn start(&self, cap: &dyn crate::capabilities::ProcessStartCapability);
465
466    /// Terminates and attempts to restart the process. The process and current
467    /// application always terminate. The kernel may, based on its own policy,
468    /// restart the application using the same process, reuse the process for
469    /// another application, or simply terminate the process and application.
470    ///
471    /// This function can be called when the process is in any state except for
472    /// [`Terminated`](State::Terminated). It attempts to reset all process
473    /// state and re-initialize it so that it can be reused.
474    ///
475    /// Restarting an application can fail for three general reasons:
476    ///
477    /// 1. The process is already terminated. Use [`Process::start()`] instead.
478    ///
479    /// 2. The kernel chooses not to restart the application, based on its
480    ///    policy.
481    ///
482    /// 3. The kernel decides to restart the application but fails to do so
483    ///    because some state can no long be configured for the process. For
484    ///    example, the syscall state for the process fails to initialize.
485    ///
486    /// After `try_restart()` runs, the process will either be queued to run the
487    /// same application's `_start` function, terminated, or queued to run a
488    /// different application's `_start` function.
489    ///
490    /// As the process will be terminated before being restarted, this function
491    /// accepts an optional `completion_code`. If the process provided a
492    /// completion code (e.g. via the exit syscall), then this should be called
493    /// with `Some(u32)`. If the kernel is trying to restart the process and the
494    /// process did not provide a completion code, then this should be called
495    /// with `None`.
496    fn try_restart(&self, completion_code: Option<u32>);
497
498    /// Stop and clear a process's state and put it into the
499    /// [`Terminated`](State::Terminated) state.
500    ///
501    /// This will end the process, but does not reset it such that it could be
502    /// restarted and run again. This function instead frees grants and any
503    /// queued tasks for this process, but leaves the debug information about
504    /// the process and other state intact.
505    ///
506    /// When a process is terminated, an optional `completion_code` should be
507    /// stored for the process. If the process provided the completion code
508    /// (e.g. via the exit syscall), then this function should be called with a
509    /// completion code of `Some(u32)`. If the kernel is terminating the process
510    /// and therefore has no completion code from the process, it should provide
511    /// `None`.
512    fn terminate(&self, completion_code: Option<u32>);
513
514    /// Get the completion code if the process has previously terminated.
515    ///
516    /// ## Returns
517    ///
518    /// If the process has never terminated then there has been no opportunity
519    /// for a completion code to be set, and this will return `None`.
520    ///
521    /// If the process has previously terminated this will return `Some()`. If
522    /// the last time the process terminated it did not provide a completion
523    /// code (e.g. the process faulted), then this will return `Some(None)`. If
524    /// the last time the process terminated it did provide a completion code,
525    /// this will return `Some(Some(completion_code))`.
526    fn get_completion_code(&self) -> Option<Option<u32>>;
527
528    // memop operations
529
530    /// Change the location of the program break to `new_break` and reallocate
531    /// the MPU region covering program memory.
532    ///
533    /// ## Returns
534    ///
535    /// On success, return the previous break address with authority that
536    /// has RW permissions from the start of process RAM to the new break.
537    ///
538    /// On error, return:
539    /// - [`Error::InactiveApp`] if the process is not running and adjusting the
540    ///   memory pointers is not valid.
541    /// - [`Error::OutOfMemory`] if the requested break would overlap with the
542    ///   grant region or if the newly requested memory cannot be protected with
543    ///   the MPU.
544    /// - [`Error::AddressOutOfBounds`] if the requested break is beyond the
545    ///   process's memory region.
546    /// - [`Error::KernelError`] if there was an internal kernel error. This is
547    ///   a bug.
548    fn brk(&self, new_break: *const u8) -> Result<CapabilityPtr, Error>;
549
550    /// Change the location of the program break by `increment` bytes,
551    /// reallocate the MPU region covering program memory, and return the
552    /// previous break address.
553    ///
554    /// ## Returns
555    ///
556    /// On success, return the previous break address with authority that
557    /// has RW permissions from the start of process RAM to the new break.
558    ///
559    /// On error, return:
560    /// - [`Error::InactiveApp`] if the process is not running and adjusting the
561    ///   sbrk is not valid.
562    /// - [`Error::OutOfMemory`] if the requested break would overlap with the
563    ///   grant region or if the newly requested memory cannot be protected with
564    ///   the MPU.
565    /// - [`Error::AddressOutOfBounds`] if the requested break is beyond the
566    ///   process's memory region.
567    /// - [`Error::KernelError`] if there was an internal kernel error. This is
568    ///   a bug.
569    fn sbrk(&self, increment: isize) -> Result<CapabilityPtr, Error>;
570
571    /// How many writeable flash regions defined in the TBF header for this
572    /// process.
573    ///
574    /// ## Returns
575    ///
576    /// The number of writeable flash regions defined for this process.
577    fn number_writeable_flash_regions(&self) -> usize;
578
579    /// Get the offset from the beginning of flash and the size of the defined
580    /// writeable flash region.
581    ///
582    /// ## Returns
583    ///
584    /// A tuple containing the a `usize` of the offset from the beginning of the
585    /// process's flash region where the writeable region starts and a `usize` of
586    /// the size of the region in bytes.
587    fn get_writeable_flash_region(&self, region_index: usize) -> (usize, usize);
588
589    /// Debug function to update the kernel on where the stack starts for this
590    /// process. Processes are not required to call this through the memop
591    /// system call, but it aids in debugging the process.
592    fn update_stack_start_pointer(&self, stack_pointer: *const u8);
593
594    /// Debug function to update the kernel on where the process heap starts.
595    /// Also optional.
596    fn update_heap_start_pointer(&self, heap_pointer: *const u8);
597
598    /// Creates a [`ReadWriteProcessBuffer`] from the given offset and size in
599    /// process memory.
600    ///
601    /// ## Returns
602    ///
603    /// In case of success, this method returns the created
604    /// [`ReadWriteProcessBuffer`].
605    ///
606    /// In case of an error, an appropriate `ErrorCode` is returned:
607    ///
608    /// - If the memory is not contained in the process-accessible memory space
609    ///   / `buf_start_addr` and `size` are not a valid read-write buffer (any
610    ///   byte in the range is not read/write accessible to the process):
611    ///   [`ErrorCode::INVAL`].
612    /// - If the process is not active: [`ErrorCode::FAIL`].
613    /// - For all other errors: [`ErrorCode::FAIL`].
614    fn build_readwrite_process_buffer(
615        &self,
616        buf_start_addr: *mut u8,
617        size: usize,
618    ) -> Result<ReadWriteProcessBuffer, ErrorCode>;
619
620    /// Creates a [`ReadOnlyProcessBuffer`] from the given offset and size in
621    /// process memory.
622    ///
623    /// ## Returns
624    ///
625    /// In case of success, this method returns the created
626    /// [`ReadOnlyProcessBuffer`].
627    ///
628    /// In case of an error, an appropriate ErrorCode is returned:
629    ///
630    /// - If the memory is not contained in the process-accessible memory space
631    ///   / `buf_start_addr` and `size` are not a valid read-only buffer (any
632    ///   byte in the range is not read-accessible to the process):
633    ///   [`ErrorCode::INVAL`].
634    /// - If the process is not active: [`ErrorCode::FAIL`].
635    /// - For all other errors: [`ErrorCode::FAIL`].
636    fn build_readonly_process_buffer(
637        &self,
638        buf_start_addr: *const u8,
639        size: usize,
640    ) -> Result<ReadOnlyProcessBuffer, ErrorCode>;
641
642    /// Set a single byte within the process address space at `addr` to `value`.
643    /// Return true if `addr` is within the RAM bounds currently exposed to the
644    /// process (thereby writable by the process itself) and the value was set,
645    /// false otherwise.
646    ///
647    /// ### Safety
648    ///
649    /// This function verifies that the byte to be written is in the process's
650    /// accessible memory. However, to avoid undefined behavior the caller needs
651    /// to ensure that no other references exist to the process's memory before
652    /// calling this function.
653    unsafe fn set_byte(&self, addr: *mut u8, value: u8) -> bool;
654
655    /// Return the permissions for this process for a given `driver_num`.
656    ///
657    /// The returned `CommandPermissions` will indicate if any permissions for
658    /// individual command numbers are specified. If there are permissions set
659    /// they are returned as a 64 bit bitmask for sequential command numbers.
660    /// The offset indicates the multiple of 64 command numbers to get
661    /// permissions for.
662    fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions;
663
664    /// Get the storage permissions for the process.
665    ///
666    /// Returns `None` if the process has no storage permissions.
667    fn get_storage_permissions(&self) -> storage_permissions::StoragePermissions;
668
669    // mpu
670
671    /// Configure the MPU to use the process's allocated regions.
672    ///
673    /// It is not valid to call this function when the process is inactive (i.e.
674    /// the process will not run again).
675    fn setup_mpu(&self);
676
677    /// Allocate a new MPU region for the process that is at least
678    /// `min_region_size` bytes and lies within the specified stretch of
679    /// unallocated memory.
680    ///
681    /// It is not valid to call this function when the process is inactive (i.e.
682    /// the process will not run again).
683    fn add_mpu_region(
684        &self,
685        unallocated_memory_start: *const u8,
686        unallocated_memory_size: usize,
687        min_region_size: usize,
688    ) -> Option<mpu::Region>;
689
690    /// Removes an MPU region from the process that has been previously added
691    /// with `add_mpu_region`.
692    ///
693    /// It is not valid to call this function when the process is inactive (i.e.
694    /// the process will not run again).
695    fn remove_mpu_region(&self, region: mpu::Region) -> Result<(), ErrorCode>;
696
697    // grants
698
699    /// Allocate memory from the grant region and store the reference in the
700    /// proper grant pointer index.
701    ///
702    /// This function must check that doing the allocation does not cause the
703    /// kernel memory break to go below the top of the process accessible memory
704    /// region allowed by the MPU. Note, this can be different from the actual
705    /// app_brk, as MPU alignment and size constraints may result in the MPU
706    /// enforced region differing from the app_brk.
707    ///
708    /// This will return `Err(())` and fail if:
709    /// - The process is inactive, or
710    /// - There is not enough available memory to do the allocation, or
711    /// - The grant_num is invalid, or
712    /// - The grant_num already has an allocated grant.
713    fn allocate_grant(
714        &self,
715        grant_num: usize,
716        driver_num: usize,
717        size: usize,
718        align: usize,
719    ) -> Result<(), ()>;
720
721    /// Check if a given grant for this process has been allocated.
722    ///
723    /// Returns `None` if the process is not active. Otherwise, returns `true`
724    /// if the grant has been allocated, `false` otherwise.
725    fn grant_is_allocated(&self, grant_num: usize) -> Option<bool>;
726
727    /// Allocate memory from the grant region that is `size` bytes long and
728    /// aligned to `align` bytes. This is used for creating custom grants which
729    /// are not recorded in the grant pointer array, but are useful for capsules
730    /// which need additional process-specific dynamically allocated memory.
731    ///
732    /// If successful, return a Ok() with an identifier that can be used with
733    /// `enter_custom_grant()` to get access to the memory and the pointer to
734    /// the memory which must be used to initialize the memory.
735    fn allocate_custom_grant(
736        &self,
737        size: usize,
738        align: usize,
739    ) -> Result<(ProcessCustomGrantIdentifier, NonNull<u8>), ()>;
740
741    /// Enter the grant based on `grant_num` for this process.
742    ///
743    /// Entering a grant means getting access to the actual memory for the
744    /// object stored as the grant.
745    ///
746    /// This will return an `Err` if the process is inactive of the `grant_num`
747    /// is invalid, if the grant has not been allocated, or if the grant is
748    /// already entered. If this returns `Ok()` then the pointer points to the
749    /// previously allocated memory for this grant.
750    fn enter_grant(&self, grant_num: usize) -> Result<NonNull<u8>, Error>;
751
752    /// Enter a custom grant based on the `identifier`.
753    ///
754    /// This retrieves a pointer to the previously allocated custom grant based
755    /// on the identifier returned when the custom grant was allocated.
756    ///
757    /// This returns an error if the custom grant is no longer accessible, or if
758    /// the process is inactive.
759    fn enter_custom_grant(
760        &self,
761        identifier: ProcessCustomGrantIdentifier,
762    ) -> Result<*mut u8, Error>;
763
764    /// Opposite of `enter_grant()`. Used to signal that the grant is no longer
765    /// entered.
766    ///
767    /// If `grant_num` is valid, this function cannot fail. If `grant_num` is
768    /// invalid, this function will do nothing. If the process is inactive then
769    /// grants are invalid and are not entered or not entered, and this function
770    /// will do nothing.
771    ///
772    /// ### Safety
773    ///
774    /// The caller must ensure that no references to the memory inside the grant
775    /// exist after calling `leave_grant()`. Otherwise, it would be possible to
776    /// effectively enter the grant twice (once using the existing reference,
777    /// once with a new call to `enter_grant()`) which breaks the memory safety
778    /// requirements of grants.
779    unsafe fn leave_grant(&self, grant_num: usize);
780
781    /// Return the count of the number of allocated grant pointers if the
782    /// process is active. This does not count custom grants. This is used to
783    /// determine if a new grant has been allocated after a call to
784    /// `SyscallDriver::allocate_grant()`.
785    ///
786    /// Useful for debugging/inspecting the system.
787    fn grant_allocated_count(&self) -> Option<usize>;
788
789    /// Get the grant number (grant_num) associated with a given driver number
790    /// if there is a grant associated with that driver_num.
791    fn lookup_grant_from_driver_num(&self, driver_num: usize) -> Result<usize, Error>;
792
793    // subscribe
794
795    /// Verify that an upcall function pointer is within process-accessible
796    /// memory.
797    ///
798    /// Returns `true` if the upcall function pointer is valid for this process,
799    /// and `false` otherwise.
800    // `upcall_fn` can eventually be a better type:
801    // <https://github.com/tock/tock/issues/4134>
802    fn is_valid_upcall_function_pointer(&self, upcall_fn: *const ()) -> bool;
803
804    // functions for processes that are architecture specific
805
806    /// Set the return value the process should see when it begins executing
807    /// again after the syscall.
808    ///
809    /// It is not valid to call this function when the process is inactive (i.e.
810    /// the process will not run again).
811    ///
812    /// This can fail, if the UKB implementation cannot correctly set the return
813    /// value. An example of how this might occur:
814    ///
815    /// 1. The UKB implementation uses the process's stack to transfer values
816    ///    between kernelspace and userspace.
817    /// 2. The process calls memop.brk and reduces its accessible memory region
818    ///    below its current stack.
819    /// 3. The UKB implementation can no longer set the return value on the
820    ///    stack since the process no longer has access to its stack.
821    ///
822    /// If it fails, the process will be put into the faulted state.
823    fn set_syscall_return_value(&self, return_value: SyscallReturn);
824
825    /// Set the function that is to be executed when the process is resumed.
826    ///
827    /// It is not valid to call this function when the process is inactive (i.e.
828    /// the process will not run again).
829    fn set_process_function(&self, callback: FunctionCall);
830
831    /// Context switch to a specific process.
832    ///
833    /// This will return `None` if the process is inactive and cannot be
834    /// switched to.
835    fn switch_to(&self) -> Option<syscall::ContextSwitchReason>;
836
837    /// Return process state information related to the location in memory of
838    /// various process data structures.
839    fn get_addresses(&self) -> ProcessAddresses;
840
841    /// Return process state information related to the size in memory of
842    /// various process data structures.
843    fn get_sizes(&self) -> ProcessSizes;
844
845    /// Write stored state as a binary blob into the `out` slice. Returns the
846    /// number of bytes written to `out` on success.
847    ///
848    /// Returns `ErrorCode::SIZE` if `out` is too short to hold the stored state
849    /// binary representation. Returns `ErrorCode::FAIL` on an internal error.
850    fn get_stored_state(&self, out: &mut [u8]) -> Result<usize, ErrorCode>;
851
852    /// Print out the full state of the process: its memory map, its context,
853    /// and the state of the memory protection unit (MPU).
854    fn print_full_process(&self, writer: &mut dyn Write);
855
856    // debug
857
858    /// Returns how many syscalls this app has called.
859    fn debug_syscall_count(&self) -> usize;
860
861    /// Returns how many upcalls for this process have been dropped.
862    fn debug_dropped_upcall_count(&self) -> usize;
863
864    /// Returns how many times this process has exceeded its timeslice.
865    fn debug_timeslice_expiration_count(&self) -> usize;
866
867    /// Increment the number of times the process has exceeded its timeslice.
868    fn debug_timeslice_expired(&self);
869
870    /// Increment the number of times the process called a syscall and record
871    /// the last syscall that was called.
872    fn debug_syscall_called(&self, last_syscall: Syscall);
873
874    /// Return the last syscall the process called. Returns `None` if the
875    /// process has not called any syscalls or the information is unknown.
876    fn debug_syscall_last(&self) -> Option<Syscall>;
877}
878
879/// Opaque identifier for custom grants allocated dynamically from a process's
880/// grant region.
881///
882/// This type allows Process to provide a handle to a custom grant within a
883/// process's memory that `ProcessGrant` can use to access the custom grant
884/// memory later.
885///
886/// We use this type rather than a direct pointer so that any attempt to access
887/// can ensure the process still exists and is valid, and that the custom grant
888/// has not been freed.
889///
890/// The fields of this struct are private so only Process can create this
891/// identifier.
892#[derive(Copy, Clone)]
893pub struct ProcessCustomGrantIdentifier {
894    pub(crate) offset: usize,
895}
896
897/// Error types related to processes.
898#[derive(Copy, Clone, Debug, Eq, PartialEq)]
899pub enum Error {
900    /// The process has been removed and no longer exists. For example, the
901    /// kernel could stop a process and re-claim its resources.
902    NoSuchApp,
903    /// The process does not have enough memory to complete the requested
904    /// operation.
905    OutOfMemory,
906    /// The provided memory address is not accessible or not valid for the
907    /// process.
908    AddressOutOfBounds,
909    /// The process is inactive (likely in a fault or exit state) and the
910    /// attempted operation is therefore invalid.
911    InactiveApp,
912    /// This likely indicates a bug in the kernel and that some state is
913    /// inconsistent in the kernel.
914    KernelError,
915    /// Indicates some process data, such as a Grant, is already borrowed.
916    AlreadyInUse,
917}
918
919impl From<Error> for Result<(), ErrorCode> {
920    fn from(err: Error) -> Result<(), ErrorCode> {
921        match err {
922            Error::OutOfMemory => Err(ErrorCode::NOMEM),
923            Error::AddressOutOfBounds => Err(ErrorCode::INVAL),
924            Error::NoSuchApp => Err(ErrorCode::INVAL),
925            Error::InactiveApp => Err(ErrorCode::FAIL),
926            Error::KernelError => Err(ErrorCode::FAIL),
927            Error::AlreadyInUse => Err(ErrorCode::FAIL),
928        }
929    }
930}
931
932impl From<Error> for ErrorCode {
933    fn from(err: Error) -> ErrorCode {
934        match err {
935            Error::OutOfMemory => ErrorCode::NOMEM,
936            Error::AddressOutOfBounds => ErrorCode::INVAL,
937            Error::NoSuchApp => ErrorCode::INVAL,
938            Error::InactiveApp => ErrorCode::FAIL,
939            Error::KernelError => ErrorCode::FAIL,
940            Error::AlreadyInUse => ErrorCode::FAIL,
941        }
942    }
943}
944
945/// States a process can be in.
946///
947/// This is public so external implementations of `Process` can re-use these
948/// process states.
949///
950/// While a process is running, it transitions between the `Running`, `Yielded`,
951/// `YieldedFor`, and `Stopped` states. If an error occurs (e.g., a memory
952/// access error), the kernel faults it and either leaves it in the `Faulted`
953/// state, restarts it, or takes some other action defined by the kernel fault
954/// policy. If the process issues an `exit-terminate` system call, it enters the
955/// `Terminated` state. If it issues an `exit-restart` system call, it
956/// terminates then tries to back to a runnable state.
957///
958/// When a process faults, it enters the `Faulted` state. To be restarted, it
959/// must first transition to the `Terminated` state, which means that all of its
960/// state has been cleaned up.
961#[derive(Copy, Clone, Debug, Eq, PartialEq)]
962pub enum State {
963    /// Process expects to be running code. The process may not be currently
964    /// scheduled by the scheduler, but the process has work to do if it is
965    /// scheduled.
966    Running,
967
968    /// Process stopped executing and returned to the kernel because it called
969    /// the `yield` syscall. This likely means it is waiting for some event to
970    /// occur, but it could also mean it has finished and doesn't need to be
971    /// scheduled again.
972    Yielded,
973
974    /// Process stopped executing and returned to the kernel because it called
975    /// the `WaitFor` variant of the `yield` syscall. The process should not be
976    /// scheduled until the specified driver attempts to execute the specified
977    /// upcall.
978    YieldedFor(UpcallId),
979
980    /// The process is stopped and the previous state the process was in when it
981    /// was stopped. This is used if the kernel forcibly stops a process. This
982    /// state indicates to the kernel not to schedule the process, but if the
983    /// process is to be resumed later it should be put back in its previous
984    /// state so it will execute correctly.
985    Stopped(StoppedState),
986
987    /// The process ran, faulted while running, and is no longer runnable. For a
988    /// faulted process to be made runnable, it must first be terminated (to
989    /// clean up its state).
990    Faulted,
991
992    /// The process is not running: it exited with the `exit-terminate` system
993    /// call or was terminated for some other reason (e.g., by the process
994    /// console). Processes in the `Terminated` state can be run again.
995    Terminated,
996}
997
998/// States a process could previously have been in when stopped.
999///
1000/// This is public so external implementations of `Process` can re-use these
1001/// process stopped states.
1002///
1003/// These are recorded so the process can be returned to its previous state when
1004/// it is resumed.
1005#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1006pub enum StoppedState {
1007    /// The process was in the running state when it was stopped.
1008    Running,
1009    /// The process was in the yielded state when it was stopped.
1010    Yielded,
1011    /// The process was in the yielded for state when it was stopped with a
1012    /// particular upcall it was waiting for.
1013    YieldedFor(UpcallId),
1014}
1015
1016/// The action the kernel should take when a process encounters a fault.
1017///
1018/// When an exception occurs during a process's execution (a common example is a
1019/// process trying to access memory outside of its allowed regions) the system
1020/// will trap back to the kernel, and the kernel has to decide what to do with
1021/// the process at that point.
1022///
1023/// The actions are separate from the policy on deciding which action to take. A
1024/// separate process-specific policy should determine which action to take.
1025#[derive(Copy, Clone)]
1026pub enum FaultAction {
1027    /// Generate a `panic!()` call and crash the entire system. This is useful
1028    /// for debugging applications as the error is displayed immediately after
1029    /// it occurs.
1030    Panic,
1031
1032    /// Attempt to cleanup and restart the process which caused the fault. This
1033    /// resets the process's memory to how it was when the process was started
1034    /// and schedules the process to run again from its init function.
1035    Restart,
1036
1037    /// Stop the process by no longer scheduling it to run.
1038    Stop,
1039}
1040
1041/// Tasks that can be enqueued for a process.
1042///
1043/// This is public for external implementations of `Process`.
1044#[derive(Copy, Clone)]
1045pub enum Task {
1046    /// Function pointer in the process to execute. Generally this is a upcall
1047    /// from a capsule.
1048    FunctionCall(FunctionCall),
1049    /// Data to return to the process. This is used to resume a suspended
1050    /// process without invoking any callbacks in userspace (e.g., in response
1051    /// to a YieldFor).
1052    ReturnValue(ReturnArguments),
1053    /// An IPC operation that needs additional setup to configure memory access.
1054    IPC((ProcessId, ipc::IPCUpcallType)),
1055}
1056
1057/// Enumeration to identify whether a function call for a process comes directly
1058/// from the kernel or from a upcall subscribed through a `Driver`
1059/// implementation.
1060///
1061/// An example of a kernel function is the application entry point.
1062#[derive(Copy, Clone, Debug)]
1063pub enum FunctionCallSource {
1064    /// For functions coming directly from the kernel, such as `init_fn`.
1065    Kernel,
1066    /// For functions coming from capsules or any implementation of `Driver`.
1067    Driver(UpcallId),
1068}
1069
1070/// Struct that defines a upcall that can be passed to a process. The upcall
1071/// takes four arguments that are `Driver` and upcall specific, so they are
1072/// represented generically here.
1073///
1074/// Likely these four arguments will get passed as the first four register
1075/// values, but this is architecture-dependent.
1076///
1077/// A `FunctionCall` also identifies the upcall that scheduled it, if any, so
1078/// that it can be unscheduled when the process unsubscribes from this upcall.
1079#[derive(Copy, Clone, Debug)]
1080pub struct FunctionCall {
1081    /// Whether the kernel called this directly or this is an upcall.
1082    pub source: FunctionCallSource,
1083    /// The first argument to the function.
1084    pub argument0: usize,
1085    /// The second argument to the function.
1086    pub argument1: usize,
1087    /// The third argument to the function.
1088    pub argument2: usize,
1089    /// The userdata provided by the process via `subscribe`
1090    pub argument3: MachineRegister,
1091    /// The PC of the function to execute.
1092    pub pc: CapabilityPtr,
1093}
1094
1095/// This is similar to `FunctionCall` but for the special case of the Null
1096/// Upcall for a subscribe.
1097///
1098/// Because there is no function pointer in a Null Upcall we can only
1099/// return these values to userspace. This is used to pass around
1100/// upcall parameters when there is no associated upcall to actually
1101/// call or userdata.
1102#[derive(Copy, Clone, Debug)]
1103pub struct ReturnArguments {
1104    /// Which upcall generates this event.
1105    pub upcall_id: UpcallId,
1106    /// The first argument to return.
1107    pub argument0: usize,
1108    /// The second argument to return.
1109    pub argument1: usize,
1110    /// The third argument to return.
1111    pub argument2: usize,
1112}
1113
1114/// Collection of process state information related to the memory addresses of
1115/// different elements of the process.
1116pub struct ProcessAddresses {
1117    /// The address of the beginning of the process's region in nonvolatile
1118    /// memory.
1119    pub flash_start: usize,
1120    /// The address of the beginning of the region the process has access to in
1121    /// nonvolatile memory. This is after the TBF header and any other memory
1122    /// the kernel has reserved for its own use.
1123    pub flash_non_protected_start: usize,
1124    /// The address immediately after the end of part of the process binary that
1125    /// is covered by integrity; the integrity region is [flash_start -
1126    /// flash_integrity_end). Footers are stored in the flash after
1127    /// flash_integrity_end.
1128    pub flash_integrity_end: *const u8,
1129    /// The address immediately after the end of the region allocated for this
1130    /// process in nonvolatile memory.
1131    pub flash_end: usize,
1132    /// The address of the beginning of the process's allocated region in
1133    /// memory.
1134    pub sram_start: usize,
1135    /// The address of the application break. This is the address immediately
1136    /// after the end of the memory the process has access to.
1137    pub sram_app_brk: usize,
1138    /// The lowest address of any allocated grant. This is the start of the
1139    /// region the kernel is using for its own internal state on behalf of this
1140    /// process.
1141    pub sram_grant_start: usize,
1142    /// The address immediately after the end of the region allocated for this
1143    /// process in memory.
1144    pub sram_end: usize,
1145
1146    /// The address of the start of the process's heap, if known. Note, managing
1147    /// this is completely up to the process, and the kernel relies on the
1148    /// process explicitly notifying it of this address. Therefore, its possible
1149    /// the kernel does not know the start address, or its start address could
1150    /// be incorrect.
1151    pub sram_heap_start: Option<usize>,
1152    /// The address of the top (or start) of the process's stack, if known.
1153    /// Note, managing the stack is completely up to the process, and the kernel
1154    /// relies on the process explicitly notifying it of where it started its
1155    /// stack. Therefore, its possible the kernel does not know the start
1156    /// address, or its start address could be incorrect.
1157    pub sram_stack_top: Option<usize>,
1158    /// The lowest address the kernel has seen the stack pointer. Note, the
1159    /// stack is entirely managed by the process, and the process could
1160    /// intentionally obscure this address from the kernel. Also, the stack may
1161    /// have reached a lower address, this is only the lowest address seen when
1162    /// the process calls a syscall.
1163    pub sram_stack_bottom: Option<usize>,
1164}
1165
1166/// Collection of process state related to the size in memory of various process
1167/// structures.
1168pub struct ProcessSizes {
1169    /// The number of bytes used for the grant pointer table.
1170    pub grant_pointers: usize,
1171    /// The number of bytes used for the pending upcall queue.
1172    pub upcall_list: usize,
1173    /// The number of bytes used for the process control block (i.e. the
1174    /// `ProcessX` struct).
1175    pub process_control_block: usize,
1176}