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}