blob: 2579d24b4fa12c2450916fb731c498a60beddad2 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_
#define OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_
#include <stdbool.h>
#include <stdint.h>
#include "sw/device/lib/base/macros.h"
/**
* RISC-V PMP address matching modes.
*
* PMP address matching modes, how protected regions are formed and
* implementation defined granularity information is described in:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", "Address Matching".
*
* PMP regions matching logic and prioritisation is described in the
* "Priority and Matching Logic" paragraph of the section "3.6.1".
*
* Note that granularity is implementation defined (default G=0, making the
* minimal PMP region size as 2^(G+2) = 4 bytes), and with G >= 1, the
* NA4 is not available. Granularity also determines the minimal region size in
* TOR and NAPOT modes.
*/
/**
* RV32 PMP CSR definitions.
*
* The values for these defines have been taken from the:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs".
*/
#define PMP_REGIONS_NUM 16
/**
* Ibex PMP address granularity.
*
* Please see:
* https://ibex-core.readthedocs.io/en/latest/03_reference/pmp.html#pmp-granularity
*/
#define PMP_GRANULARITY_IBEX 0
/**
* RISC-V PMP address alignment and granularity.
*
* The values have been taken from the:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", section "Address Matching".
*
* "PMP mechanism supports regions as small as four bytes, platforms may
* specify coarser PMP regions."
*/
#define PMP_ADDRESS_MIN_ALIGNMENT 4
#define PMP_ADDRESS_MIN_ALIGNMENT_NAPOT 8
#define PMP_ADDRESS_ALIGNMENT (4 << PMP_GRANULARITY_IBEX)
#define PMP_ADDRESS_ALIGNMENT_MASK (PMP_ADDRESS_ALIGNMENT - 1)
#define PMP_ADDRESS_ALIGNMENT_INVERTED_MASK (~PMP_ADDRESS_ALIGNMENT_MASK)
#define PMP_ADDRESS_SHIFT 2
#define PMP_ADDRESS_SHIFT_NAPOT 3
/**
* PMP region access permissions.
*
* PMP permissions are described in:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", "Locking and Privilege Mode".
*
* Note that "The combination R=0 and W=1 is reserved for future use".
*
* When a region is configured with `kPmpRegionLockUnlocked` then these
* permissions only apply to RISC-V "U" and "S" privilege modes, and have no
* effect in the "M" mode.
*/
typedef enum pmp_region_permissions {
kPmpRegionPermissionsNone = 0, /**< No access permitted .*/
kPmpRegionPermissionsReadOnly, /**< Only read access. */
kPmpRegionPermissionsExecuteOnly, /**< Only execute access. */
kPmpRegionPermissionsReadExecute, /**< Read and execute access. */
kPmpRegionPermissionsReadWrite, /**< Read and write access. */
kPmpRegionPermissionsReadWriteExecute, /**< Read, write and execute access. */
} pmp_region_permissions_t;
/**
* PMP region locking.
*
* PMP locking is described in:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", "Locking and Privilege Mode".
*
* When a region is configured with `kPmpRegionLockLocked`, this region cannot
* be accessed even by the machine "M" privilege code, and can be only unlocked
* by the system reset. Additionally it also forces the
* `pmp_region_permissions_t` access restrictions for the corresponding region
* in machine "M" mode, which otherwise are ignored.
*/
typedef enum pmp_region_lock {
kPmpRegionLockUnlocked = 0, /**< The region is unlocked. */
kPmpRegionLockLocked, /**< The region is locked. */
} pmp_region_lock_t;
/**
* PMP region index is used to identify one of `PMP_REGIONS_NUM` PMP regions.
*/
typedef uint32_t pmp_region_index_t;
/**
* PMP region configuration information.
*/
typedef struct pmp_region_config {
pmp_region_lock_t lock; /**< Region lock for "M" privilege mode.*/
pmp_region_permissions_t permissions; /**< Region access permissions. */
} pmp_region_config_t;
/**
* PMP generic status codes.
*
* These error codes can be used by any function. However if a function
* requires additional status codes, it must define a set of status codes to
* be used exclusively by such function.
*/
typedef enum pmp_result {
kPmpOk = 0, /**< Success. */
kPmpError, /**< General error. */
kPmpBadArg, /**< Input parameter is not valid. */
} pmp_result_t;
/**
* PMP region access and address configuration result.
*/
typedef enum pmp_region_configure_result {
kPmpRegionConfigureOk = kPmpOk,
kPmpRegionConfigureError = kPmpError,
kPmpRegionConfigureBadArg = kPmpBadArg,
/**
* The requested region is invalid.
*/
kPmpRegionConfigureBadRegion,
/**
* The requested address is invalid.
*/
kPmpRegionConfigureBadAddress,
/**
* The requested region was not configured correctly. From the "Volume II:
* RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified":
* "Implementations will not raise an exception on writes of unsupported
* values to a WARL field. Implementations can return any legal value on the
* read of a WARL field when the last write was of an illegal value, but the
* legal value returned should deterministically depend on the illegal
* written value and the value of the field prior to the write"
*/
kPmpRegionConfigureWarlError,
} pmp_region_configure_result_t;
/**
* Disables PMP address matching.
*
* Address matching is disabled for `region`, however the corresponding
* pmpaddr can still be used as a TOR range start address. For example, when
* pmpcfgN is set to TOR, but pmpcfgN-1 is set to OFF, then pmpaddrN-1 can
* be used as TOR range start address.
*
* Please see the PMP specification reference and general information at the
* top of this header file.
*
* Note: this function will clear PMP `region` configuration.
*
* @param region PMP region to configure and set address for.
* @param address System address.
* @return `pmp_region_configure_result_t`.
*/
OT_WARN_UNUSED_RESULT
pmp_region_configure_result_t pmp_region_configure_off(
pmp_region_index_t region, uintptr_t address);
/**
* PMP region access and address NA4 configuration result.
*/
typedef enum pmp_region_configure_na4_result {
kPmpRegionConfigureNa4Ok = kPmpRegionConfigureOk,
kPmpRegionConfigureNa4Error = kPmpRegionConfigureError,
kPmpRegionConfigureNa4BadArg = kPmpRegionConfigureBadArg,
kPmpRegionConfigureNa4BadRegion = kPmpRegionConfigureBadRegion,
kPmpRegionConfigureNa4BadAddress = kPmpRegionConfigureBadAddress,
kPmpRegionConfigureNa4WarlError = kPmpRegionConfigureWarlError,
/**
* NA4 is not available with granularity "G" > 0. Please see:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", "Table 3.10" and section
* "Address Matching".
*/
kPmpRegionConfigureNa4Unavailable,
} pmp_region_configure_na4_result_t;
/**
* Configures PMP address matching to Naturally aligned four-byte (NA4).
*
* When pmpcfgN is set to NA4 then the protected region range is formed from
* pmpaddrN and extends to the next 4 bytes.
*
* Please see the PMP specification reference and general information at the
* top of this header file.
*
* @param region PMP region to configure and set the address for.
* @param config PMP region configuration information.
* @param address Range start system address.
* @return `pmp_region_configure_na4_result_t`.
*/
OT_WARN_UNUSED_RESULT
pmp_region_configure_na4_result_t pmp_region_configure_na4(
pmp_region_index_t region, const pmp_region_config_t config,
uintptr_t address);
/**
* PMP region access and address NAPOT configuration result.
*/
typedef enum pmp_region_configure_napot_result {
kPmpRegionConfigureNapotOk = kPmpRegionConfigureOk,
kPmpRegionConfigureNapotError = kPmpRegionConfigureError,
kPmpRegionConfigureNapotBadArg = kPmpRegionConfigureBadArg,
kPmpRegionConfigureNapotBadRegion = kPmpRegionConfigureBadRegion,
kPmpRegionConfigureNapotBadAddress = kPmpRegionConfigureBadAddress,
kPmpRegionConfigureNapotWarlError = kPmpRegionConfigureWarlError,
/**
* NAPOT size must be at least 8bytes and Power Of Two. NAPOT address
* must be aligned to the size. Please see:
* "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
* "3.6.1 Physical Memory Protection CSRs", "Table 3.10" and section
* "Address Matching".
*/
kPmpRegionConfigureNapotBadSize,
} pmp_region_configure_napot_result_t;
/**
* Configures PMP address matching to Naturally aligned power-of-two (NAPOT).
*
* Size ≥ 8 bytes. When pmpcfgN is set to NAPOT then the protected region range
* is formed from a single encoded pmpaddrN address. NAPOT ranges make use of
* the low-order bits of the associated address register to encode the size of
* the range, please see the table "3.10" of the "Address Matching" section of
* the specification mentioned above.
*
* Example: NAPOT encoded address of yyyy011 describes the
* yyyy00000 .. yyyy11111 range. The index of the first "0", determines the
* range size ( 2^(3 + index) ).
*
* Please see the PMP specification reference and general information at the
* top of this header file.
*
* @param region PMP region to configure and set the address for.
* @param config PMP region configuration information.
* @param address Range start system address (must be aligned to `size`).
* @param size Address range size (must be power-of-two).
* @return `pmp_region_configure_napot_result_t`.
*/
OT_WARN_UNUSED_RESULT
pmp_region_configure_napot_result_t pmp_region_configure_napot(
pmp_region_index_t region, const pmp_region_config_t config,
uintptr_t address, uint32_t size);
/**
* Configures PMP address matching to Top Of the Range (TOR).
*
* When pmpcfgN is set to TOR, the protected address range is formed from the
* pmpaddrN-1 and pmpaddrN registers. Note that the combination of pmpcfgN set
* to TOR and pmpcfgN-1 set to NAPOT does not form any meaningful range for TOR
* addressing mode. pmpcfgN TOR mode will take the bottom of the range
* pmpaddrN-1 address as is, without decoding the NAPOT address.
*
* Please see the PMP specification reference and general information at the
* top of this header file.
*
* @param region_end PMP region to configure and set the address for.
* @param config PMP region configuration information.
* @param address_start Bottom of the range system address. Must be
* 0 for the "0" region.
* @param address_end Top of the range system address.
* @return `pmp_region_configure_result_t`.
*/
OT_WARN_UNUSED_RESULT
pmp_region_configure_result_t pmp_region_configure_tor(
pmp_region_index_t region_end, const pmp_region_config_t config,
uintptr_t address_start, uintptr_t address_end);
/**
* Queries the lock status for the requested region.
*
* @param region PMP region to query the lock information for.
* @param lock State of the PMP region (locked/unlocked).
* @return `pmp_region_configure_result_t`.
*/
OT_WARN_UNUSED_RESULT
pmp_region_configure_result_t pmp_region_lock_status_get(
pmp_region_index_t region, pmp_region_lock_t *lock);
#endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_