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