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