Struct kernel::process_standard::ProcessStandard

source ·
pub struct ProcessStandard<'a, C: 'static + Chip> {
Show 22 fields process_id: Cell<ProcessId>, app_id: ShortId, kernel: &'static Kernel, chip: &'static C, memory_start: *const u8, memory_len: usize, grant_pointers: MapCell<&'static mut [GrantPointerEntry]>, kernel_memory_break: Cell<*const u8>, app_break: Cell<*const u8>, allow_high_water_mark: Cell<*const u8>, flash: &'static [u8], footers: &'static [u8], header: TbfHeader, stored_state: MapCell<<<C as Chip>::UserspaceKernelBoundary as UserspaceKernelBoundary>::StoredState>, state: Cell<State>, fault_policy: &'a dyn ProcessFaultPolicy, mpu_config: MapCell<<<C as Chip>::MPU as MPU>::MpuConfig>, mpu_regions: [Cell<Option<Region>>; 6], tasks: MapCell<RingBuffer<'a, Task>>, restart_count: Cell<usize>, completion_code: OptionalCell<Option<u32>>, debug: MapCell<ProcessStandardDebug>,
}
Expand description

A type for userspace processes in Tock.

Fields§

§process_id: Cell<ProcessId>

Identifier of this process and the index of the process in the process table.

§app_id: ShortId

An application ShortId, generated from process loading and checking, which denotes the security identity of this process.

§kernel: &'static Kernel

Pointer to the main Kernel struct.

§chip: &'static C

Pointer to the struct that defines the actual chip the kernel is running on. This is used because processes have subtle hardware-based differences. Specifically, the actual syscall interface and how processes are switched to is architecture-specific, and how memory must be allocated for memory protection units is also hardware-specific.

§memory_start: *const u8

Application memory layout:

    ╒════════ ← memory_start + memory_len
 ╔═ │ Grant Pointers
 ║  │ ──────
    │ Process Control Block
 D  │ ──────
 Y  │ Grant Regions
 N  │
 A  │   ↓
 M  │ ──────  ← kernel_memory_break
 I  │
 C  │ ──────  ← app_break               ═╗
    │                                    ║
 ║  │   ↑                                  A
 ║  │  Heap                              P C
 ╠═ │ ──────  ← app_heap_start           R C
    │  Data                              O E
 F  │ ──────  ← data_start_pointer       C S
 I  │ Stack                              E S
 X  │   ↓                                S I
 E  │                                    S B
 D  │ ──────  ← current_stack_pointer      L
    │                                    ║ E
 ╚═ ╘════════ ← memory_start            ═╝

The start of process memory. We store this as a pointer and length and not a slice due to Rust aliasing rules. If we were to store a slice, then any time another slice to the same memory or an ProcessBuffer is used in the kernel would be undefined behavior.

§memory_len: usize

Number of bytes of memory allocated to this process.

§grant_pointers: MapCell<&'static mut [GrantPointerEntry]>

Reference to the slice of GrantPointerEntrys stored in the process’s memory reserved for the kernel. These driver numbers are zero and pointers are null if the grant region has not been allocated. When the grant region is allocated these pointers are updated to point to the allocated memory and the driver number is set to match the driver that owns the grant. No other reference to these pointers exists in the Tock kernel.

§kernel_memory_break: Cell<*const u8>

Pointer to the end of the allocated (and MPU protected) grant region.

§app_break: Cell<*const u8>

Pointer to the end of process RAM that has been sbrk’d to the process.

§allow_high_water_mark: Cell<*const u8>

Pointer to high water mark for process buffers shared through allow

§flash: &'static [u8]

Process flash segment. This is the region of nonvolatile flash that the process occupies.

§footers: &'static [u8]

The footers of the process binary (may be zero-sized), which are metadata about the process not covered by integrity. Used, among other things, to store signatures.

§header: TbfHeader

Collection of pointers to the TBF header in flash.

§stored_state: MapCell<<<C as Chip>::UserspaceKernelBoundary as UserspaceKernelBoundary>::StoredState>

State saved on behalf of the process each time the app switches to the kernel.

§state: Cell<State>

The current state of the app. The scheduler uses this to determine whether it can schedule this app to execute.

The state is used both for bookkeeping for the scheduler as well as for enabling control by other parts of the system. The scheduler keeps track of if a process is ready to run or not by switching between the Running and Yielded states. The system can control the process by switching it to a “stopped” state to prevent the scheduler from scheduling it.

§fault_policy: &'a dyn ProcessFaultPolicy

How to respond if this process faults.

§mpu_config: MapCell<<<C as Chip>::MPU as MPU>::MpuConfig>

Configuration data for the MPU

§mpu_regions: [Cell<Option<Region>>; 6]

MPU regions are saved as a pointer-size pair.

§tasks: MapCell<RingBuffer<'a, Task>>

Essentially a list of upcalls that want to call functions in the process.

§restart_count: Cell<usize>

Count of how many times this process has entered the fault condition and been restarted. This is used by some ProcessRestartPolicys to determine if the process should be restarted or not.

§completion_code: OptionalCell<Option<u32>>

The completion code set by the process when it last exited, restarted, or was terminated. If the process is has never terminated, then the OptionalCell will be empty (i.e. None). If the process has exited, restarted, or terminated, the OptionalCell will contain an optional 32 bit value. The option will be None if the process crashed or was stopped by the kernel and there is no provided completion code. If the process called the exit syscall then the provided completion code will be stored as Some(completion code).

§debug: MapCell<ProcessStandardDebug>

Values kept so that we can print useful debug messages when apps fault.

Implementations§

source§

impl<C: 'static + Chip> ProcessStandard<'_, C>

source

const CALLBACK_LEN: usize = 10usize

source

const CALLBACKS_OFFSET: usize = 640usize

source

const PROCESS_STRUCT_OFFSET: usize = _

source

pub(crate) unsafe fn create<'a>( kernel: &'static Kernel, chip: &'static C, pb: ProcessBinary, remaining_memory: &'a mut [u8], fault_policy: &'static dyn ProcessFaultPolicy, app_id: ShortId, index: usize, ) -> Result<(Option<&'static dyn Process>, &'a mut [u8]), (ProcessLoadError, &'a mut [u8])>

Create a ProcessStandard object based on the found ProcessBinary.

source

fn reset(&self) -> Result<(), ErrorCode>

Reset the process, resetting all of its state and re-initializing it so it can start running. Assumes the process is not running but is still in flash and still has its memory region allocated to it.

source

fn in_app_owned_memory(&self, buf_start_addr: *const u8, size: usize) -> bool

Checks if the buffer represented by the passed in base pointer and size is within the RAM bounds currently exposed to the processes (i.e. ending at app_break). If this method returns true, the buffer is guaranteed to be accessible to the process and to not overlap with the grant region.

source

fn in_app_flash_memory(&self, buf_start_addr: *const u8, size: usize) -> bool

Checks if the buffer represented by the passed in base pointer and size are within the readable region of an application’s flash memory. If this method returns true, the buffer is guaranteed to be readable to the process.

source

unsafe fn grant_ptrs_reset(&self)

Reset all grant_ptrs to NULL.

source

fn allocate_in_grant_region_internal( &self, size: usize, align: usize, ) -> Option<NonNull<u8>>

Allocate memory in a process’s grant region.

Ensures that the allocation is of size bytes and aligned to align bytes.

If there is not enough memory, or the MPU cannot isolate the process accessible region from the new kernel memory break after doing the allocation, then this will return None.

source

fn create_custom_grant_identifier( &self, ptr: NonNull<u8>, ) -> ProcessCustomGrantIdentifier

Create the identifier for a custom grant that grant.rs uses to access the custom grant.

We create this identifier by calculating the number of bytes between where the custom grant starts and the end of the process memory.

source

fn get_custom_grant_address( &self, identifier: ProcessCustomGrantIdentifier, ) -> usize

Use a ProcessCustomGrantIdentifier to find the address of the custom grant.

This reverses create_custom_grant_identifier().

source

fn mem_start(&self) -> *const u8

The start address of allocated RAM for this process.

source

fn mem_end(&self) -> *const u8

The first address after the end of the allocated RAM for this process.

source

fn flash_start(&self) -> *const u8

The start address of the flash region allocated for this process.

source

fn flash_non_protected_start(&self) -> *const u8

Get the first address of process’s flash that isn’t protected by the kernel. The protected range of flash contains the TBF header and potentially other state the kernel is storing on behalf of the process, and cannot be edited by the process.

source

fn flash_end(&self) -> *const u8

The first address after the end of the flash region allocated for this process.

source

fn kernel_memory_break(&self) -> *const u8

The lowest address of the grant region for the process.

source

fn app_memory_break(&self) -> *const u8

Return the highest address the process has access to, or the current process memory brk.

Trait Implementations§

source§

impl<C: Chip> Process for ProcessStandard<'_, C>

source§

fn processid(&self) -> ProcessId

Returns the process’s identifier.
source§

fn short_app_id(&self) -> ShortId

Returns the ShortId generated by the application binary checker at loading.
source§

fn binary_version(&self) -> Option<BinaryVersion>

Returns the version number of the binary in this process, as specified in a TBF Program Header; if the binary has no version assigned, return None
source§

fn enqueue_task(&self, task: Task) -> Result<(), ErrorCode>

Queue a Task for the process. This will be added to a per-process buffer and executed by the scheduler. Tasks are some function the app should run, for example a upcall or an IPC call. Read more
source§

fn ready(&self) -> bool

Returns whether this process is ready to execute.
source§

fn remove_pending_upcalls(&self, upcall_id: UpcallId)

Remove all scheduled upcalls for a given upcall id from the task queue.
source§

fn is_running(&self) -> bool

Returns whether the process is running (has active stack frames) or not (has never run, has faulted, or has completed).
source§

fn get_state(&self) -> State

Returns the current state the process is in. Common states are “running” or “yielded”.
source§

fn set_yielded_state(&self)

Move this process from the running state to the yielded state. Read more
source§

fn set_yielded_for_state(&self, upcall_id: UpcallId)

Move this process from the running state to the yielded-for state. Read more
source§

fn stop(&self)

Move this process from running or yielded state into the stopped state. Read more
source§

fn resume(&self)

Move this stopped process back into its original state. Read more
source§

fn set_fault_state(&self)

Put this process in the fault state. The kernel will use its process fault policy to decide what action to take in regards to the faulted process.
source§

fn start(&self, _cap: &dyn ProcessStartCapability)

Start a terminated process. This function can only be called on a terminated process. Read more
source§

fn try_restart(&self, completion_code: Option<u32>)

Terminates and attempts to restart the process. The process and current application always terminate. The kernel may, based on its own policy, restart the application using the same process, reuse the process for another application, or simply terminate the process and application. Read more
source§

fn terminate(&self, completion_code: Option<u32>)

Stop and clear a process’s state and put it into the Terminated state. Read more
source§

fn get_restart_count(&self) -> usize

Returns how many times this process has been restarted.
source§

fn has_tasks(&self) -> bool

Return if there are any Tasks (upcalls/IPC requests) enqueued for the process.
source§

fn dequeue_task(&self) -> Option<Task>

Remove the scheduled operation from the front of the queue and return it to be handled by the scheduler. Read more
source§

fn remove_upcall(&self, upcall_id: UpcallId) -> Option<Task>

Search the work queue for a specific upcall_id. If it is present, return the associated Task, otherwise return None.
source§

fn pending_tasks(&self) -> usize

Returns the number of pending tasks. If 0 then dequeue_task() will return None when called.
source§

fn get_command_permissions( &self, driver_num: usize, offset: usize, ) -> CommandPermissions

Return the permissions for this process for a given driver_num. Read more
source§

fn get_storage_permissions(&self) -> Option<StoragePermissions>

Get the storage permissions for the process. Read more
source§

fn number_writeable_flash_regions(&self) -> usize

How many writeable flash regions defined in the TBF header for this process.
source§

fn get_writeable_flash_region(&self, region_index: usize) -> (u32, u32)

Get the offset from the beginning of flash and the size of the defined writeable flash region.
source§

fn update_stack_start_pointer(&self, stack_pointer: *const u8)

Debug function to update the kernel on where the stack starts for this process. Processes are not required to call this through the memop system call, but it aids in debugging the process.
source§

fn update_heap_start_pointer(&self, heap_pointer: *const u8)

Debug function to update the kernel on where the process heap starts. Also optional.
source§

fn setup_mpu(&self)

Configure the MPU to use the process’s allocated regions. Read more
source§

fn add_mpu_region( &self, unallocated_memory_start: *const u8, unallocated_memory_size: usize, min_region_size: usize, ) -> Option<Region>

Allocate a new MPU region for the process that is at least min_region_size bytes and lies within the specified stretch of unallocated memory. Read more
source§

fn remove_mpu_region(&self, region: Region) -> Result<(), ErrorCode>

Removes an MPU region from the process that has been previously added with add_mpu_region. Read more
source§

fn sbrk(&self, increment: isize) -> Result<*const u8, Error>

Change the location of the program break, reallocate the MPU region covering program memory, and return the previous break address. Read more
source§

fn brk(&self, new_break: *const u8) -> Result<*const u8, Error>

Change the location of the program break and reallocate the MPU region covering program memory. Read more
source§

fn build_readwrite_process_buffer( &self, buf_start_addr: *mut u8, size: usize, ) -> Result<ReadWriteProcessBuffer, ErrorCode>

Creates a ReadWriteProcessBuffer from the given offset and size in process memory. Read more
source§

fn build_readonly_process_buffer( &self, buf_start_addr: *const u8, size: usize, ) -> Result<ReadOnlyProcessBuffer, ErrorCode>

Creates a ReadOnlyProcessBuffer from the given offset and size in process memory. Read more
source§

unsafe fn set_byte(&self, addr: *mut u8, value: u8) -> bool

Set a single byte within the process address space at addr to value. Return true if addr is within the RAM bounds currently exposed to the process (thereby writable by the process itself) and the value was set, false otherwise. Read more
source§

fn grant_is_allocated(&self, grant_num: usize) -> Option<bool>

Check if a given grant for this process has been allocated. Read more
source§

fn allocate_grant( &self, grant_num: usize, driver_num: usize, size: usize, align: usize, ) -> Result<(), ()>

Allocate memory from the grant region and store the reference in the proper grant pointer index. Read more
source§

fn allocate_custom_grant( &self, size: usize, align: usize, ) -> Result<(ProcessCustomGrantIdentifier, NonNull<u8>), ()>

Allocate memory from the grant region that is size bytes long and aligned to align bytes. This is used for creating custom grants which are not recorded in the grant pointer array, but are useful for capsules which need additional process-specific dynamically allocated memory. Read more
source§

fn enter_grant(&self, grant_num: usize) -> Result<NonNull<u8>, Error>

Enter the grant based on grant_num for this process. Read more
source§

fn enter_custom_grant( &self, identifier: ProcessCustomGrantIdentifier, ) -> Result<*mut u8, Error>

Enter a custom grant based on the identifier. Read more
source§

unsafe fn leave_grant(&self, grant_num: usize)

Opposite of enter_grant(). Used to signal that the grant is no longer entered. Read more
source§

fn grant_allocated_count(&self) -> Option<usize>

Return the count of the number of allocated grant pointers if the process is active. This does not count custom grants. This is used to determine if a new grant has been allocated after a call to SyscallDriver::allocate_grant(). Read more
source§

fn lookup_grant_from_driver_num( &self, driver_num: usize, ) -> Result<usize, Error>

Get the grant number (grant_num) associated with a given driver number if there is a grant associated with that driver_num.
source§

fn is_valid_upcall_function_pointer(&self, upcall_fn: NonNull<()>) -> bool

Verify that an upcall function pointer is within process-accessible memory. Read more
source§

fn get_process_name(&self) -> &'static str

Get the name of the process. Used for IPC.
source§

fn get_completion_code(&self) -> Option<Option<u32>>

Get the completion code if the process has previously terminated. Read more
source§

fn set_syscall_return_value(&self, return_value: SyscallReturn)

Set the return value the process should see when it begins executing again after the syscall. Read more
source§

fn set_process_function(&self, callback: FunctionCall)

Set the function that is to be executed when the process is resumed. Read more
source§

fn switch_to(&self) -> Option<ContextSwitchReason>

Context switch to a specific process. Read more
source§

fn debug_syscall_count(&self) -> usize

Returns how many syscalls this app has called.
source§

fn debug_dropped_upcall_count(&self) -> usize

Returns how many upcalls for this process have been dropped.
source§

fn debug_timeslice_expiration_count(&self) -> usize

Returns how many times this process has exceeded its timeslice.
source§

fn debug_timeslice_expired(&self)

Increment the number of times the process has exceeded its timeslice.
source§

fn debug_syscall_called(&self, last_syscall: Syscall)

Increment the number of times the process called a syscall and record the last syscall that was called.
source§

fn debug_syscall_last(&self) -> Option<Syscall>

Return the last syscall the process called. Returns None if the process has not called any syscalls or the information is unknown.
source§

fn get_addresses(&self) -> ProcessAddresses

Return process state information related to the location in memory of various process data structures.
source§

fn get_sizes(&self) -> ProcessSizes

Return process state information related to the size in memory of various process data structures.
source§

fn print_full_process(&self, writer: &mut dyn Write)

Print out the full state of the process: its memory map, its context, and the state of the memory protection unit (MPU).
source§

fn get_stored_state(&self, out: &mut [u8]) -> Result<usize, ErrorCode>

Write stored state as a binary blob into the out slice. Returns the number of bytes written to out on success. Read more

Auto Trait Implementations§

§

impl<'a, C> !Freeze for ProcessStandard<'a, C>

§

impl<'a, C> !RefUnwindSafe for ProcessStandard<'a, C>

§

impl<'a, C> !Send for ProcessStandard<'a, C>

§

impl<'a, C> !Sync for ProcessStandard<'a, C>

§

impl<'a, C> Unpin for ProcessStandard<'a, C>

§

impl<'a, C> !UnwindSafe for ProcessStandard<'a, C>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.