Software APIs
pmp.h
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_
6 #define OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 
12 
13 /**
14  * RISC-V PMP address matching modes.
15  *
16  * PMP address matching modes, how protected regions are formed and
17  * implementation defined granularity information is described in:
18  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
19  * "3.6.1 Physical Memory Protection CSRs", "Address Matching".
20  *
21  * PMP regions matching logic and prioritisation is described in the
22  * "Priority and Matching Logic" paragraph of the section "3.6.1".
23  *
24  * Note that granularity is implementation defined (default G=0, making the
25  * minimal PMP region size as 2^(G+2) = 4 bytes), and with G >= 1, the
26  * NA4 is not available. Granularity also determines the minimal region size in
27  * TOR and NAPOT modes.
28  */
29 
30 /**
31  * RV32 PMP CSR definitions.
32  *
33  * The values for these defines have been taken from the:
34  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
35  * "3.6.1 Physical Memory Protection CSRs".
36  */
37 #define PMP_REGIONS_NUM 16
38 
39 /**
40  * Ibex PMP address granularity.
41  *
42  * Please see:
43  * https://ibex-core.readthedocs.io/en/latest/03_reference/pmp.html#pmp-granularity
44  */
45 #define PMP_GRANULARITY_IBEX 0
46 
47 /**
48  * RISC-V PMP address alignment and granularity.
49  *
50  * The values have been taken from the:
51  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
52  * "3.6.1 Physical Memory Protection CSRs", section "Address Matching".
53  *
54  * "PMP mechanism supports regions as small as four bytes, platforms may
55  * specify coarser PMP regions."
56  */
57 #define PMP_ADDRESS_MIN_ALIGNMENT 4
58 #define PMP_ADDRESS_MIN_ALIGNMENT_NAPOT 8
59 #define PMP_ADDRESS_ALIGNMENT (4u << PMP_GRANULARITY_IBEX)
60 #define PMP_ADDRESS_ALIGNMENT_MASK (PMP_ADDRESS_ALIGNMENT - 1)
61 #define PMP_ADDRESS_ALIGNMENT_INVERTED_MASK (~PMP_ADDRESS_ALIGNMENT_MASK)
62 #define PMP_ADDRESS_SHIFT 2
63 #define PMP_ADDRESS_SHIFT_NAPOT 3
64 
65 /**
66  * PMP region access permissions.
67  *
68  * PMP permissions are described in:
69  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
70  * "3.6.1 Physical Memory Protection CSRs", "Locking and Privilege Mode".
71  *
72  * Note that "The combination R=0 and W=1 is reserved for future use".
73  *
74  * When a region is configured with `kPmpRegionLockUnlocked` then these
75  * permissions only apply to RISC-V "U" and "S" privilege modes, and have no
76  * effect in the "M" mode.
77  */
78 typedef enum pmp_region_permissions {
79  kPmpRegionPermissionsNone = 0, /**< No access permitted .*/
80  kPmpRegionPermissionsReadOnly, /**< Only read access. */
81  kPmpRegionPermissionsExecuteOnly, /**< Only execute access. */
82  kPmpRegionPermissionsReadExecute, /**< Read and execute access. */
83  kPmpRegionPermissionsReadWrite, /**< Read and write access. */
84  kPmpRegionPermissionsReadWriteExecute, /**< Read, write and execute access. */
85 } pmp_region_permissions_t;
86 
87 /**
88  * PMP region locking.
89  *
90  * PMP locking is described in:
91  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
92  * "3.6.1 Physical Memory Protection CSRs", "Locking and Privilege Mode".
93  *
94  * When a region is configured with `kPmpRegionLockLocked`, this region cannot
95  * be accessed even by the machine "M" privilege code, and can be only unlocked
96  * by the system reset. Additionally it also forces the
97  * `pmp_region_permissions_t` access restrictions for the corresponding region
98  * in machine "M" mode, which otherwise are ignored.
99  */
100 typedef enum pmp_region_lock {
101  kPmpRegionLockUnlocked = 0, /**< The region is unlocked. */
102  kPmpRegionLockLocked, /**< The region is locked. */
103 } pmp_region_lock_t;
104 
105 /**
106  * PMP region index is used to identify one of `PMP_REGIONS_NUM` PMP regions.
107  */
108 typedef uint32_t pmp_region_index_t;
109 
110 /**
111  * PMP region configuration information.
112  */
113 typedef struct pmp_region_config {
114  pmp_region_lock_t lock; /**< Region lock for "M" privilege mode.*/
115  pmp_region_permissions_t permissions; /**< Region access permissions. */
117 
118 /**
119  * PMP generic status codes.
120  *
121  * These error codes can be used by any function. However if a function
122  * requires additional status codes, it must define a set of status codes to
123  * be used exclusively by such function.
124  */
125 typedef enum pmp_result {
126  kPmpOk = 0, /**< Success. */
127  kPmpError, /**< General error. */
128  kPmpBadArg, /**< Input parameter is not valid. */
129 } pmp_result_t;
130 
131 /**
132  * PMP region access and address configuration result.
133  */
134 typedef enum pmp_region_configure_result {
135  kPmpRegionConfigureOk = kPmpOk,
136  kPmpRegionConfigureError = kPmpError,
137  kPmpRegionConfigureBadArg = kPmpBadArg,
138  /**
139  * The requested region is invalid.
140  */
141  kPmpRegionConfigureBadRegion,
142  /**
143  * The requested address is invalid.
144  */
145  kPmpRegionConfigureBadAddress,
146  /**
147  * The requested region was not configured correctly. From the "Volume II:
148  * RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified":
149  * "Implementations will not raise an exception on writes of unsupported
150  * values to a WARL field. Implementations can return any legal value on the
151  * read of a WARL field when the last write was of an illegal value, but the
152  * legal value returned should deterministically depend on the illegal
153  * written value and the value of the field prior to the write"
154  */
155  kPmpRegionConfigureWarlError,
156 } pmp_region_configure_result_t;
157 
158 /**
159  * Disables PMP address matching.
160  *
161  * Address matching is disabled for `region`, however the corresponding
162  * pmpaddr can still be used as a TOR range start address. For example, when
163  * pmpcfgN is set to TOR, but pmpcfgN-1 is set to OFF, then pmpaddrN-1 can
164  * be used as TOR range start address.
165  *
166  * Please see the PMP specification reference and general information at the
167  * top of this header file.
168  *
169  * Note: this function will clear PMP `region` configuration.
170  *
171  * @param region PMP region to configure and set address for.
172  * @param address System address.
173  * @return `pmp_region_configure_result_t`.
174  */
176 pmp_region_configure_result_t pmp_region_configure_off(
177  pmp_region_index_t region, uintptr_t address);
178 
179 /**
180  * PMP region access and address NA4 configuration result.
181  */
182 typedef enum pmp_region_configure_na4_result {
183  kPmpRegionConfigureNa4Ok = kPmpRegionConfigureOk,
184  kPmpRegionConfigureNa4Error = kPmpRegionConfigureError,
185  kPmpRegionConfigureNa4BadArg = kPmpRegionConfigureBadArg,
186  kPmpRegionConfigureNa4BadRegion = kPmpRegionConfigureBadRegion,
187  kPmpRegionConfigureNa4BadAddress = kPmpRegionConfigureBadAddress,
188  kPmpRegionConfigureNa4WarlError = kPmpRegionConfigureWarlError,
189  /**
190  * NA4 is not available with granularity "G" > 0. Please see:
191  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
192  * "3.6.1 Physical Memory Protection CSRs", "Table 3.10" and section
193  * "Address Matching".
194  */
195  kPmpRegionConfigureNa4Unavailable,
196 } pmp_region_configure_na4_result_t;
197 
198 /**
199  * Configures PMP address matching to Naturally aligned four-byte (NA4).
200  *
201  * When pmpcfgN is set to NA4 then the protected region range is formed from
202  * pmpaddrN and extends to the next 4 bytes.
203  *
204  * Please see the PMP specification reference and general information at the
205  * top of this header file.
206  *
207  * @param region PMP region to configure and set the address for.
208  * @param config PMP region configuration information.
209  * @param address Range start system address.
210  * @return `pmp_region_configure_na4_result_t`.
211  */
213 pmp_region_configure_na4_result_t pmp_region_configure_na4(
214  pmp_region_index_t region, const pmp_region_config_t config,
215  uintptr_t address);
216 
217 /**
218  * PMP region access and address NAPOT configuration result.
219  */
220 typedef enum pmp_region_configure_napot_result {
221  kPmpRegionConfigureNapotOk = kPmpRegionConfigureOk,
222  kPmpRegionConfigureNapotError = kPmpRegionConfigureError,
223  kPmpRegionConfigureNapotBadArg = kPmpRegionConfigureBadArg,
224  kPmpRegionConfigureNapotBadRegion = kPmpRegionConfigureBadRegion,
225  kPmpRegionConfigureNapotBadAddress = kPmpRegionConfigureBadAddress,
226  kPmpRegionConfigureNapotWarlError = kPmpRegionConfigureWarlError,
227  /**
228  * NAPOT size must be at least 8bytes and Power Of Two. NAPOT address
229  * must be aligned to the size. Please see:
230  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
231  * "3.6.1 Physical Memory Protection CSRs", "Table 3.10" and section
232  * "Address Matching".
233  */
234  kPmpRegionConfigureNapotBadSize,
235 } pmp_region_configure_napot_result_t;
236 
237 /**
238  * Configures PMP address matching to Naturally aligned power-of-two (NAPOT).
239  *
240  * Size ≥ 8 bytes. When pmpcfgN is set to NAPOT then the protected region range
241  * is formed from a single encoded pmpaddrN address. NAPOT ranges make use of
242  * the low-order bits of the associated address register to encode the size of
243  * the range, please see the table "3.10" of the "Address Matching" section of
244  * the specification mentioned above.
245  *
246  * Example: NAPOT encoded address of yyyy011 describes the
247  * yyyy00000 .. yyyy11111 range. The index of the first "0", determines the
248  * range size ( 2^(3 + index) ).
249  *
250  * Please see the PMP specification reference and general information at the
251  * top of this header file.
252  *
253  * @param region PMP region to configure and set the address for.
254  * @param config PMP region configuration information.
255  * @param address Range start system address (must be aligned to `size`).
256  * @param size Address range size (must be power-of-two).
257  * @return `pmp_region_configure_napot_result_t`.
258  */
260 pmp_region_configure_napot_result_t pmp_region_configure_napot(
261  pmp_region_index_t region, const pmp_region_config_t config,
262  uintptr_t address, uint32_t size);
263 
264 /**
265  * Configures PMP address matching to Top Of the Range (TOR).
266  *
267  * When pmpcfgN is set to TOR, the protected address range is formed from the
268  * pmpaddrN-1 and pmpaddrN registers. Note that the combination of pmpcfgN set
269  * to TOR and pmpcfgN-1 set to NAPOT does not form any meaningful range for TOR
270  * addressing mode. pmpcfgN TOR mode will take the bottom of the range
271  * pmpaddrN-1 address as is, without decoding the NAPOT address.
272  *
273  * Please see the PMP specification reference and general information at the
274  * top of this header file.
275  *
276  * @param region_end PMP region to configure and set the address for.
277  * @param config PMP region configuration information.
278  * @param address_start Bottom of the range system address. Must be
279  * 0 for the "0" region.
280  * @param address_end Top of the range system address.
281  * @return `pmp_region_configure_result_t`.
282  */
284 pmp_region_configure_result_t pmp_region_configure_tor(
285  pmp_region_index_t region_end, const pmp_region_config_t config,
286  uintptr_t address_start, uintptr_t address_end);
287 
288 /**
289  * Check if the requested region is configured.
290  *
291  * @param region PMP region to query the information for.
292  * @param[out] configured Whether the PMP region is configured.
293  * @return `pmp_region_configure_result_t`.
294  */
296 pmp_region_configure_result_t pmp_region_is_configured(
297  pmp_region_index_t region, bool *configured);
298 
299 /**
300  * Queries the lock status for the requested region.
301  *
302  * @param region PMP region to query the lock information for.
303  * @param lock State of the PMP region (locked/unlocked).
304  * @return `pmp_region_configure_result_t`.
305  */
307 pmp_region_configure_result_t pmp_region_lock_status_get(
308  pmp_region_index_t region, pmp_region_lock_t *lock);
309 
310 #endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_PMP_H_