pub trait TORUserPMP<const MAX_REGIONS: usize> {
const CONST_ASSERT_CHECK: ();
// Required methods
fn available_regions(&self) -> usize;
fn configure_pmp(
&self,
regions: &[(TORUserPMPCFG, *const u8, *const u8); MAX_REGIONS],
) -> Result<(), ()>;
fn enable_user_pmp(&self) -> Result<(), ()>;
fn disable_user_pmp(&self);
}
Expand description
A RISC-V PMP implementation exposing a number of TOR memory protection
regions to the PMPUserMPU
.
The RISC-V PMP is complex and can be used to enforce memory protection in various modes (Machine, Supervisor and User mode). Depending on the exact extension set present (e.g., ePMP) and the machine’s security configuration bits, it may expose a vastly different set of constraints and application semantics.
Because we can’t possibly capture all of this in a single readable, maintainable and efficient implementation, we implement a two-layer system:
-
a
TORUserPMP
is a simple abstraction over some underlying PMP hardware implementation, which exposes an interface to configure regions that are active (enforced) in user-mode and can be configured for arbitrary addresses on a 4-byte granularity. -
the
PMPUserMPU
takes this abstraction and implements the Tock kernel’smpu::MPU
trait. It worries about re-configuring memory protection when switching processes, allocating memory regions of an appropriate size, etc.
Implementors of a chip are free to define their own TORUserPMP
implementations, adhering to their specific PMP layout & constraints,
provided they implement this trait.
The MAX_REGIONS
const generic is used to indicate the maximum number of
TOR PMP regions available to the PMPUserMPU
. The PMP implementation may
provide less regions than indicated through MAX_REGIONS
, for instance when
entries are enforced (locked) in machine mode. The number of available
regions may change at runtime. The current number of regions available to
the PMPUserMPU
is indicated by the TORUserPMP::available_regions
method. However, when it is known that a number of regions are not available
for userspace protection, MAX_REGIONS
can be used to reduce the memory
footprint allocated by stored PMP configurations, as well as the
re-configuration overhead.
Required Associated Constants§
Sourceconst CONST_ASSERT_CHECK: ()
const CONST_ASSERT_CHECK: ()
A placeholder to define const-assertions which are evaluated in
PMPUserMPU::new
. This can be used to, for instance, assert that the
number of userspace regions does not exceed the number of hardware
regions.
Required Methods§
Sourcefn available_regions(&self) -> usize
fn available_regions(&self) -> usize
The number of TOR regions currently available for userspace memory
protection. Within [0; MAX_REGIONS]
.
The PMP implementation may provide less regions than indicated through
MAX_REGIONS
, for instance when entries are enforced (locked) in
machine mode. The number of available regions may change at runtime. The
implementation is free to map these regions to arbitrary PMP entries
(and change this mapping at runtime), provided that they are enforced
when the hart is in user-mode, and other memory regions are generally
inaccessible when in user-mode.
When allocating regions for kernel-mode protection, and thus reducing
the number of regions available to userspace, re-configuring the PMP may
fail. This is allowed behavior. However, the PMP must not remove any
regions from the user-mode current configuration while it is active
(TORUserPMP::enable_user_pmp
has been called, and it has not been
disabled through TORUserPMP::disable_user_pmp
).
Sourcefn configure_pmp(
&self,
regions: &[(TORUserPMPCFG, *const u8, *const u8); MAX_REGIONS],
) -> Result<(), ()>
fn configure_pmp( &self, regions: &[(TORUserPMPCFG, *const u8, *const u8); MAX_REGIONS], ) -> Result<(), ()>
Configure the user-mode memory protection.
This method configures the user-mode memory protection, to be enforced
on a call to TORUserPMP::enable_user_pmp
.
PMP implementations where configured regions are only enforced in
user-mode may re-configure the PMP on this function invocation and
implement TORUserPMP::enable_user_pmp
as a no-op. If configured
regions are enforced in machine-mode (for instance when using an ePMP
with the machine-mode whitelist policy), the new configuration rules
must not apply until TORUserPMP::enable_user_pmp
.
The tuples as passed in the regions
parameter are defined as follows:
-
first value (
TORUserPMPCFG
): the memory protection mode as enforced on the region. ATORUserPMPCFG
can be created from thempu::Permissions
type. It is in a format compatible to the pmpcfgX register, guaranteed to not have the lock (L
) bit set, and configured either as a TOR region (A = 0b01
), or disabled (all bits set to0
). -
second value (
*const u8
): the region’s start addres. As a PMP TOR region has a 4-byte address granularity, this address is rounded down to the next 4-byte boundary. -
third value (
*const u8
): the region’s end addres. As a PMP TOR region has a 4-byte address granularity, this address is rounded down to the next 4-byte boundary.
To disable a region, set its configuration to TORUserPMPCFG::OFF
. In
this case, the start and end addresses are ignored and can be set to
arbitrary values.
Sourcefn enable_user_pmp(&self) -> Result<(), ()>
fn enable_user_pmp(&self) -> Result<(), ()>
Enable the user-mode memory protection.
Enables the memory protection for user-mode, as configured through
TORUserPMP::configure_pmp
. Enabling the PMP for user-mode may make
the user-mode accessible regions inaccessible to the kernel. For PMP
implementations where configured regions are only enforced in user-mode,
this method may be implemented as a no-op.
If enabling the current configuration is not possible (e.g., because
regions have been allocated to the kernel), this function must return
Err(())
. Otherwise, this function returns Ok(())
.
Sourcefn disable_user_pmp(&self)
fn disable_user_pmp(&self)
Disable the user-mode memory protection.
Disables the memory protection for user-mode. If enabling the user-mode memory protetion made user-mode accessible regions inaccessible to machine-mode, this method should make these regions accessible again.
For PMP implementations where configured regions are only enforced in
user-mode, this method may be implemented as a no-op. This method is not
responsible for making regions inaccessible to user-mode. If previously
configured regions must be made inaccessible,
TORUserPMP::configure_pmp
must be used to re-configure the PMP
accordingly.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.