pub unsafe trait MPU {
type MpuConfig: Display;
// Required methods
fn enable_app_mpu(&self);
unsafe fn disable_app_mpu(&self);
fn number_total_regions(&self) -> usize;
fn new_config(&self) -> Option<Self::MpuConfig>;
fn reset_config(&self, config: &mut Self::MpuConfig);
fn allocate_region(
&self,
unallocated_memory_start: *const u8,
unallocated_memory_size: usize,
min_region_size: usize,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Option<Region>;
fn remove_memory_region(
&self,
region: Region,
config: &mut Self::MpuConfig,
) -> Result<(), ()>;
fn allocate_app_memory_region(
&self,
unallocated_memory_start: *const u8,
unallocated_memory_size: usize,
min_memory_size: usize,
initial_app_memory_size: usize,
initial_kernel_memory_size: usize,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Option<(*const u8, usize)>;
fn update_app_memory_region(
&self,
app_memory_break: *const u8,
kernel_memory_break: *const u8,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Result<(), ()>;
unsafe fn configure_mpu(&self, config: &Self::MpuConfig);
}Expand description
The generic trait that particular memory protection unit implementations need to implement.
This trait is a blend of relatively generic MPU functionality that should be common across different MPU implementations, and more specific requirements that Tock needs to support protecting applications. While a less Tock-specific interface may be desirable, due to the sometimes complex alignment rules and other restrictions imposed by MPU hardware, some of the Tock details have to be passed into this interface. That allows the MPU implementation to have more flexibility when satisfying the protection requirements, and also allows the MPU to specify some addresses used by the kernel when deciding where to place certain application memory regions so that the MPU can appropriately provide protection for those memory regions.
§Safety
This is an unsafe trait, as it is crucial to uphold Tock’s isolation
properties, and thus safety of the Tock kernel. Users of this trait must be
able to rely on its implementations being correct. Specifically, they must
ensure that applications only have access to the configured MPU regions and
no kernel memory.
Required Associated Types§
Sourcetype MpuConfig: Display
type MpuConfig: Display
MPU-specific state that defines a particular configuration for the MPU. That is, this should contain all of the required state such that the implementation can be passed an object of this type and it should be able to correctly and entirely configure the MPU.
This state will be held on a per-process basis as a way to cache all of
the process settings. When the kernel switches to a new process it will
use the MpuConfig for that process to quickly configure the MPU.
It is Default so we can create empty state when the process is
created, and Display so that the panic!() output can display the
current state to help with debugging.
Required Methods§
Sourcefn enable_app_mpu(&self)
fn enable_app_mpu(&self)
Enables the MPU for userspace apps.
This function must enable the permission restrictions on the various regions protected by the MPU.
Sourceunsafe fn disable_app_mpu(&self)
unsafe fn disable_app_mpu(&self)
Disables the MPU for userspace apps.
This function must disable any memory protection rules that were previously setup for an app, if those rules can prevent the kernel from accessing this application’s memory.
This function is intended to be called when switching back from an application to the kernel, as some platforms prevent kernel-mode from accessing memory made accessible to less-privileged applications. This restriction is intended to increase security by making it harder to inject application-controlled data into a buggy kernel (e.g., through an incorrect context switch application that provides kernel-mode privileges to applications). However, it also prevents the kernel from managing application state or accessing application-provided data.
§Safety
This function is marked unsafe, as invoking it and subsequently
switching back to an application could, depending on the underlying MPU
implementation, provide that application access to kernel memory. Before
switching back to an application, and after calling this function, the
kernel must first re-enable memory protection through a call to
MPU::enable_app_mpu.
Sourcefn number_total_regions(&self) -> usize
fn number_total_regions(&self) -> usize
Returns the maximum number of regions supported by the MPU.
Sourcefn new_config(&self) -> Option<Self::MpuConfig>
fn new_config(&self) -> Option<Self::MpuConfig>
Creates a new empty MPU configuration.
The returned configuration must not have any userspace-accessible regions pre-allocated.
The underlying implementation may only be able to allocate a finite
number of MPU configurations. It may return None if this resource is
exhausted.
Sourcefn reset_config(&self, config: &mut Self::MpuConfig)
fn reset_config(&self, config: &mut Self::MpuConfig)
Resets an MPU configuration.
This method resets an MPU configuration to its initial state, as
returned by MPU::new_config. After invoking this operation, it must
not have any userspace-acessible regions pre-allocated.
Sourcefn allocate_region(
&self,
unallocated_memory_start: *const u8,
unallocated_memory_size: usize,
min_region_size: usize,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Option<Region>
fn allocate_region( &self, unallocated_memory_start: *const u8, unallocated_memory_size: usize, min_region_size: usize, permissions: Permissions, config: &mut Self::MpuConfig, ) -> Option<Region>
Allocates a new MPU region.
An implementation must allocate an MPU region at least min_region_size
bytes in size within the specified stretch of unallocated memory, and
with the specified user mode permissions, and store it in config. The
allocated region may not overlap any of the regions already stored in
config.
§Arguments
unallocated_memory_start: start of unallocated memoryunallocated_memory_size: size of unallocated memorymin_region_size: minimum size of the regionpermissions: permissions for the regionconfig: MPU region configuration
§Return Value
Returns the start and size of the allocated MPU region. If it is infeasible to allocate the MPU region, returns None.
Sourcefn remove_memory_region(
&self,
region: Region,
config: &mut Self::MpuConfig,
) -> Result<(), ()>
fn remove_memory_region( &self, region: Region, config: &mut Self::MpuConfig, ) -> Result<(), ()>
Removes an MPU region within app-owned memory.
An implementation must remove the MPU region that matches the region parameter if it exists. If there is not a region that matches exactly, then the implementation may return an Error. Implementors should not remove the app_memory_region and should return an Error if that region is supplied.
§Arguments
region: a region previously allocated withallocate_regionconfig: MPU region configuration
§Return Value
Returns an error if the specified region is not exactly mapped to the process as specified
Sourcefn allocate_app_memory_region(
&self,
unallocated_memory_start: *const u8,
unallocated_memory_size: usize,
min_memory_size: usize,
initial_app_memory_size: usize,
initial_kernel_memory_size: usize,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Option<(*const u8, usize)>
fn allocate_app_memory_region( &self, unallocated_memory_start: *const u8, unallocated_memory_size: usize, min_memory_size: usize, initial_app_memory_size: usize, initial_kernel_memory_size: usize, permissions: Permissions, config: &mut Self::MpuConfig, ) -> Option<(*const u8, usize)>
Chooses the location for a process’s memory, and allocates an MPU region covering the app-owned part.
An implementation must choose a contiguous block of memory that is at
least min_memory_size bytes in size and lies completely within the
specified stretch of unallocated memory.
It must also allocate an MPU region with the following properties:
- The region covers at least the first
initial_app_memory_sizebytes at the beginning of the memory block. - The region does not overlap the last
initial_kernel_memory_sizebytes. - The region has the user mode permissions specified by
permissions.
The end address of app-owned memory will increase in the future, so the
implementation should choose the location of the process memory block
such that it is possible for the MPU region to grow along with it. The
implementation must store the allocated region in config. The
allocated region may not overlap any of the regions already stored in
config.
§Arguments
unallocated_memory_start: start of unallocated memoryunallocated_memory_size: size of unallocated memorymin_memory_size: minimum total memory to allocate for processinitial_app_memory_size: initial size of app-owned memoryinitial_kernel_memory_size: initial size of kernel-owned memorypermissions: permissions for the MPU regionconfig: MPU region configuration
§Return Value
This function returns the start address and the size of the memory block chosen for the process. If it is infeasible to find a memory block or allocate the MPU region, or if the function has already been called, returns None. If None is returned no changes are made.
Sourcefn update_app_memory_region(
&self,
app_memory_break: *const u8,
kernel_memory_break: *const u8,
permissions: Permissions,
config: &mut Self::MpuConfig,
) -> Result<(), ()>
fn update_app_memory_region( &self, app_memory_break: *const u8, kernel_memory_break: *const u8, permissions: Permissions, config: &mut Self::MpuConfig, ) -> Result<(), ()>
Updates the MPU region for app-owned memory.
An implementation must reallocate the MPU region for app-owned memory
stored in config to maintain the 3 conditions described in
allocate_app_memory_region.
§Arguments
app_memory_break: new address for the end of app-owned memorykernel_memory_break: new address for the start of kernel-owned memorypermissions: permissions for the MPU regionconfig: MPU region configuration
§Return Value
Returns an error if it is infeasible to update the MPU region, or if it was never created. If an error is returned no changes are made to the configuration.
Sourceunsafe fn configure_mpu(&self, config: &Self::MpuConfig)
unsafe fn configure_mpu(&self, config: &Self::MpuConfig)
Configures the MPU with the provided region configuration.
An implementation must ensure that, after the MPU configuration has been
activated through MPU::enable_app_mpu and until it has been disabled
through MPU::disable_app_mpu, all memory locations not covered by an
allocated region are inaccessible in user mode, and all memory locations
covered by an allocated region are accessible in user mode.
While the MPU configuration is active, memory locations covered by an allocated region may or may not be accessible in kernel mode. When the MPU configuration is not active, allocated regions must be accessible in kernel mode.
§Arguments
config: MPU region configuration
§Safety
This function is unsafe as incorrect use of it can endagner Tock’s
isolation properties, and thus safety of the Tock kernel. Specifically,
callers of this function must ensure that they are applying an MPU
configuration that does not permit an application to access any
kernel-private memory (such as the grant region) or peripherals that can
transitively write to kernel-private memory (such as MMIO registers of
DMA-capable peripherals).