Physical Memory Protection

Physical Memory Protection (PMP) is a part of the RISC-V Privileged Architecture Specification which discribes the interface for a standard RISC-V memory protection unit.

The PMP defines a finite number of PMP regions which can be individually configured to enforce access permissions to a range of addresses in memory. Each PMP region is configurable with the following options:

struct metal_pmp_config

Configuration for a PMP region.

Public Types

enum metal_pmp_locked

Sets whether the PMP region is locked.

Values:

enumerator METAL_PMP_UNLOCKED
enumerator METAL_PMP_LOCKED

Public Members

unsigned int R

Sets whether reads to the PMP region succeed.

unsigned int W

Sets whether writes to the PMP region succeed.

unsigned int X

Sets whether the PMP region is executable.

enum metal_pmp_address_mode A

Sets the addressing mode of the PMP region.

Initializing the PMP

All PMP-related functions first depend on having a handle to the PMP device:

struct metal_pmp *pmp = metal_pmp_get_device();
if(!pmp) {
   /* Failed to get PMP device handle */
}

PMP initialization is optional and has the effect of disabling all PMP regions, if possible:

metal_pmp_init(pmp);

The number of PMP regions available can be retrieved from the PMP device handle:

struct metal_pmp

A handle for the PMP device.

Configuring a PMP Region

Freedom Metal has a set of APIs for configuring a PMP region. The most generic of these is

int metal_pmp_set_region(struct metal_pmp *pmp, unsigned int region, struct metal_pmp_config config, size_t address)

Configure a PMP region.

Return

0 upon success

Parameters
  • pmp: The PMP device handle

  • region: The PMP region to configure

  • config: The desired configuration of the PMP region

  • address: The desired address of the PMP region

This function allows for the configuration of all PMP region settings.

Additional APIs are provided for granularly changing individual PMP region settings. For example:

int metal_pmp_set_address(struct metal_pmp *pmp, unsigned int region, size_t address)

Set the address for a PMP region.

Return

0 if the address is successfully set

Parameters
  • pmp: The PMP device handle

  • region: The PMP region to set

  • address: The desired address of the PMP region

int metal_pmp_lock(struct metal_pmp *pmp, unsigned int region)

Lock a PMP region.

Return

0 if the region is successfully locked

Parameters
  • pmp: The PMP device handle

  • region: The PMP region to lock

int metal_pmp_set_writeable(struct metal_pmp *pmp, unsigned int region, int W)

Set the writable bit for a PMP region.

Return

0 if the writable bit is successfully set

Parameters
  • pmp: The PMP device handle

  • region: The PMP region to set

  • W: The desired value of the writable bit

Additional documentation for this API is provided in the PMP API reference.

The RISC-V specification allows implementation of PMP to hard-wire the configuration values of PMP regions. In these cases, attempts to configure these PMP regions will fail.

Handling PMP Access Faults

Attempted memory accesses which the PMP is configured to prevent trigger a CPU exception. These exceptions can be handled by installing a CPU exception handler for exception codes related to memory access faults.

Additional documentation about creating and registering exception handlers can be found in the Exception Handlers Developer Guide.

Additional Documentation

Additional documentation about the Physical Memory Protection system and fault handling on RISC-V systems can be found in The RISC-V Privileged ISA Specification v1.10.