Software APIs
pmp.c
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 #include "sw/device/lib/runtime/pmp.h"
6 
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
12 #include "sw/device/lib/base/csr.h"
14 
15 // "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
16 // "3.6.1 Physical Memory Protection CSRs",
17 // "Figure 3.28: PMP configuration register format".
18 #define PMP_CFG_CSR_R 0
19 #define PMP_CFG_CSR_W 1
20 #define PMP_CFG_CSR_X 2
21 #define PMP_CFG_CSR_A 3
22 #define PMP_CFG_CSR_L 7
23 
24 #define PMP_CFG_FIELDS_PER_REG 4
25 #define PMP_CFG_FIELD_WIDTH 8
26 #define PMP_CFG_FIELD_MASK 0xff
27 
28 // "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
29 // "3.6.1 Physical Memory Protection CSRs", "Address Matching".
30 #define PMP_CFG_CSR_MODE_OFF 0
31 #define PMP_CFG_CSR_MODE_TOR 1
32 #define PMP_CFG_CSR_MODE_NA4 2
33 #define PMP_CFG_CSR_MODE_NAPOT 3
34 #define PMP_CFG_CSR_MODE_MASK 0x3
35 
36 typedef enum pmp_csr_access_type {
37  kPmpCsrAccessTypeRead = 0,
38  kPmpCsrAccessTypeWrite,
39 } pmp_csr_access_type_t;
40 
41 static const bitfield_field32_t kPmpCfgModeField = {
42  .mask = PMP_CFG_CSR_MODE_MASK,
43  .index = PMP_CFG_CSR_A,
44 };
45 
46 /**
47  * This is an X-Macro used for automatically deriving switch statements which
48  * link PMP region identifiers to associated information including their
49  * configuration register identifier.
50  *
51  * This macro should be invoked with a macro argument with the following
52  * signature:
53  *
54  * @param region_id PMP Region Identifier.
55  * @param config_reg_id Configuration Register ID for a given PMP Region (for
56  * Ibex).
57  */
58 #define PMP_REGIONS(X) \
59  X(0, 0) \
60  X(1, 0) \
61  X(2, 0) \
62  X(3, 0) \
63  \
64  X(4, 1) \
65  X(5, 1) \
66  X(6, 1) \
67  X(7, 1) \
68  \
69  X(8, 2) \
70  X(9, 2) \
71  X(10, 2) \
72  X(11, 2) \
73  \
74  X(12, 3) \
75  X(13, 3) \
76  X(14, 3) \
77  X(15, 3)
78 
79 /**
80  * Reads the pmpcfg for a given region.
81  *
82  * This reads the entire `pmpcfgN` value, not just the word associated with the
83  * current region.
84  *
85  * @param region PMP Region ID to read.
86  * @param[out] value Where to put the result of the read.
87  * @return `true` if `pmp_region_index_t` is valid and value was read, `false`
88  * otherwise.
89  */
91 static bool pmp_cfg_csr_read(pmp_region_index_t region, uint32_t *value) {
92 #define PMP_READ_CONFIG_(region_id, config_reg_id) \
93  case region_id: { \
94  CSR_READ(CSR_REG_PMPCFG##config_reg_id, value); \
95  return true; \
96  }
97 
98  switch (region) {
99  PMP_REGIONS(PMP_READ_CONFIG_)
100  default:
101  return false;
102  }
103 }
104 
105 /**
106  * Writes the pmpcfg for a given region.
107  *
108  * This writes the entire `pmpcfgN` value, not just the word associated with the
109  * current region.
110  *
111  * @param region PMP Region ID to write.
112  * @param value the value to write.
113  * @return `true` if `pmp_region_index_t` is valid and value was written,
114  * `false` otherwise.
115  */
117 static bool pmp_cfg_csr_write(pmp_region_index_t region, uint32_t value) {
118 #define PMP_WRITE_CONFIG_(region_id, config_reg_id) \
119  case region_id: { \
120  CSR_WRITE(CSR_REG_PMPCFG##config_reg_id, value); \
121  return true; \
122  }
123 
124  switch (region) {
125  PMP_REGIONS(PMP_WRITE_CONFIG_)
126  default:
127  return false;
128  }
129 }
130 
131 /**
132  * Reads the pmpaddr for a given region.
133  *
134  * @param region PMP Region ID to read.
135  * @param[out] value Where to put the result of the read.
136  * @return `true` if `pmp_region_index_t` is valid and value was read, `false`
137  * otherwise.
138  */
140 static bool pmp_addr_csr_read(pmp_region_index_t region, uint32_t *value) {
141 #define PMP_READ_ADDR_(region_id, _) \
142  case region_id: { \
143  CSR_READ(CSR_REG_PMPADDR##region_id, value); \
144  return true; \
145  }
146 
147  switch (region) {
148  PMP_REGIONS(PMP_READ_ADDR_)
149  default:
150  return false;
151  }
152 }
153 
154 /**
155  * Writes the pmpcfg for a given region.
156  *
157  * @param region PMP region ID to get/set.
158  * @param value Value to write into a CSR.
159  * @return `pmp_region_configure_result_t`.
160  */
162 static bool pmp_addr_csr_write(pmp_region_index_t region, uint32_t value) {
163 #define PMP_WRITE_ADDR_(region_id, _) \
164  case region_id: { \
165  CSR_WRITE(CSR_REG_PMPADDR##region_id, value); \
166  return true; \
167  }
168 
169  switch (region) {
170  PMP_REGIONS(PMP_WRITE_ADDR_)
171  default:
172  return false;
173  }
174 }
175 
176 /**
177  * Retrievs configuration information for the requested `region`.
178  *
179  * A single `pmpcfg` CSR packs configuration information for `N` regions.
180  *
181  * @param region PMP region ID.
182  * @param field_value Configuration information for the `region`.
183  * @return `pmp_region_configure_result_t`.
184  */
186 static pmp_region_configure_result_t pmp_csr_cfg_field_read(
187  pmp_region_index_t region, uint32_t *field_value) {
188  uint32_t cfg_csr_original;
189  if (!pmp_cfg_csr_read(region, &cfg_csr_original)) {
190  return kPmpRegionConfigureError;
191  }
192 
193  size_t field_index = (region % PMP_CFG_FIELDS_PER_REG) * PMP_CFG_FIELD_WIDTH;
194  bitfield_field32_t pmp_csr_cfg_field = {
195  .mask = PMP_CFG_FIELD_MASK,
196  .index = field_index,
197  };
198 
199  *field_value = bitfield_field32_read(cfg_csr_original, pmp_csr_cfg_field);
200 
201  return kPmpRegionConfigureOk;
202 }
203 
204 /**
205  * Writes configuration information for the requested `region`.
206  *
207  * A single `pmpcfg` CSR packs configuration information for `N` regions.
208  *
209  * @param region PMP region ID.
210  * @param field_value Configuration information for the `region`.
211  * @return `pmp_region_configure_result_t`.
212  */
214 static pmp_region_configure_result_t pmp_csr_cfg_field_write(
215  pmp_region_index_t region, uint32_t field_value) {
216  uint32_t cfg_csr_current;
217  if (!pmp_cfg_csr_read(region, &cfg_csr_current)) {
218  return kPmpRegionConfigureError;
219  }
220 
221  // Determine the pmpcfg field index based on the `region`.
222  size_t field_index = (region % PMP_CFG_FIELDS_PER_REG) * PMP_CFG_FIELD_WIDTH;
223  bitfield_field32_t pmp_csr_cfg_field = {
224  .mask = PMP_CFG_FIELD_MASK,
225  .index = field_index,
226  };
227 
228  uint32_t cfg_csr_new =
229  bitfield_field32_write(cfg_csr_current, pmp_csr_cfg_field, field_value);
230 
231  if (!pmp_cfg_csr_write(region, cfg_csr_new)) {
232  return kPmpRegionConfigureError;
233  }
234 
235  if (!pmp_cfg_csr_read(region, &cfg_csr_current)) {
236  return kPmpRegionConfigureError;
237  }
238 
239  if (cfg_csr_current != cfg_csr_new) {
240  return kPmpRegionConfigureWarlError;
241  }
242 
243  return kPmpRegionConfigureOk;
244 }
245 
246 /**
247  * Writes `address` to a pmpaddr CSRs.
248  *
249  * The corresponding pmpaddrN index N is determined by `region`.
250  *
251  * PMP address must be at least 4bytes aligned, and pmpaddr holds only bits
252  * 33:2. This means that before writing an address to a pmpaddr CSR, it must be
253  * shifted 2 bits to the right.
254  *
255  * Please see:
256  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
257  * "3.6.1 Physical Memory Protection CSRs",
258  * "Figure 3.26: PMP address register format, RV32".
259  *
260  * @param region PMP region to configure and set address for.
261  * @param address Address to be set.
262  * @return `pmp_region_configure_result_t`.
263  */
264 pmp_region_configure_result_t pmp_csr_address_write(pmp_region_index_t region,
265  uintptr_t address) {
266  uint32_t address_shifted = address >> PMP_ADDRESS_SHIFT;
267  if (!pmp_addr_csr_write(region, address_shifted)) {
268  return kPmpRegionConfigureError;
269  }
270 
271  uint32_t addr_csr_after_write;
272  if (!pmp_addr_csr_read(region, &addr_csr_after_write)) {
273  return kPmpRegionConfigureError;
274  }
275 
276  if (address_shifted != addr_csr_after_write) {
277  return kPmpRegionConfigureWarlError;
278  }
279 
280  return kPmpRegionConfigureOk;
281 }
282 
283 /**
284  * Set PMP region permissions.
285  *
286  * @param perm Memory access permissions.
287  * @param bitfield Bitfield to set.
288  * @return `true` on success, `false` on failure.
289  */
291 static bool pmp_cfg_permissions_set(pmp_region_permissions_t perm,
292  uint32_t *bitfield) {
293  switch (perm) {
294  case kPmpRegionPermissionsNone:
295  // No access is allowed.
296  break;
297  case kPmpRegionPermissionsReadOnly:
298  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_R, true);
299  break;
300  case kPmpRegionPermissionsExecuteOnly:
301  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_X, true);
302  break;
303  case kPmpRegionPermissionsReadExecute:
304  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_R, true);
305  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_X, true);
306  break;
307  case kPmpRegionPermissionsReadWrite:
308  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_R, true);
309  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_W, true);
310  break;
311  case kPmpRegionPermissionsReadWriteExecute:
312  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_R, true);
313  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_W, true);
314  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_X, true);
315  break;
316  default:
317  return false;
318  }
319 
320  return true;
321 }
322 
323 /**
324  * Set PMP region lock.
325  *
326  * @param lock Lock to indicate whether the region must be locked.
327  * @param bitfield Bitfield to set.
328  */
329 static void pmp_cfg_mode_lock_set(pmp_region_lock_t lock, uint32_t *bitfield) {
330  bool flag = (lock == kPmpRegionLockLocked) ? true : false;
331  *bitfield = bitfield_bit32_write(*bitfield, PMP_CFG_CSR_L, flag);
332 }
333 
334 /**
335  * Check whether `address` is correctly aligned.
336  *
337  * The alignment depend on the granularity, which is implementation specific,
338  * and for Ibex is `PMP_GRANULARITY_IBEX`. Default granularity "G" is 0, which
339  * means a minimal alignment of 4bytes. Please see:
340  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
341  * "3.6 Physical Memory Protection", "Figure 3.26" and section
342  * "Address Matching".
343  *
344  * @param address System address.
345  * @return `true` on success, `false` on failure.
346  */
347 static bool pmp_address_aligned(uintptr_t address) {
348  return address == (address & PMP_ADDRESS_ALIGNMENT_INVERTED_MASK);
349 }
350 
351 /**
352  * Constructs a NAPOT address from the requested system address and size.
353  *
354  * This function makes sure that the `address` and `size` are valid, and then
355  * constructs a corresponding NAPOT address. Please see:
356  * "Volume II: RISC-V Privileged Architectures V20190608-Priv-MSU-Ratified",
357  * "3.6 Physical Memory Protection", "Figure 3.26" and "Table 3.10".
358  *
359  * @param address Conventional system address.
360  * @param size The size of a range to protect.
361  * @param pmp_address_napot Constructed NAPOT address.
362  * @return `pmp_region_configure_napot_result_t`.
363  */
365 static pmp_region_configure_napot_result_t pmp_napot_address_construct(
366  uintptr_t address, uint32_t size, uintptr_t *pmp_address_napot) {
367  // Must be at least the size of the minimal alignment adjusted for
368  // granularity, and the minimal allowed size for the NAPOT mode.
369  if (size < PMP_ADDRESS_ALIGNMENT || size < PMP_ADDRESS_MIN_ALIGNMENT_NAPOT) {
370  return kPmpRegionConfigureNapotBadAddress;
371  }
372 
373  // Check if the `size` is a Power Of Two.
374  uint32_t size_mask = size - 1;
375  if ((size & size_mask) != 0) {
376  return kPmpRegionConfigureNapotBadSize;
377  }
378 
379  // Check if the address is aligned to the `size`.
380  if (address != (address & (~size_mask))) {
381  return kPmpRegionConfigureNapotBadAddress;
382  }
383 
384  // `size_mask` must be right shifted, as the minimal legal size in NAPOT
385  // mode is 8 bytes.
386  *pmp_address_napot = address | (size_mask >> 1);
387 
388  return kPmpRegionConfigureNapotOk;
389 }
390 
391 pmp_region_configure_result_t pmp_region_configure_off(
392  pmp_region_index_t region, uintptr_t address) {
393  if (region >= PMP_REGIONS_NUM) {
394  return kPmpRegionConfigureBadRegion;
395  }
396 
397  if (!pmp_address_aligned(address)) {
398  return kPmpRegionConfigureBadAddress;
399  }
400 
401  // Address registers must be written prior to the configuration registers to
402  // ensure that they are not locked.
403  pmp_region_configure_result_t result = pmp_csr_address_write(region, address);
404  if (result != kPmpRegionConfigureOk) {
405  return result;
406  }
407 
408  // Clear the appropriate region field of the pmpcfg CSR.
409  result = pmp_csr_cfg_field_write(region, 0);
410  if (result != kPmpRegionConfigureOk) {
411  return result;
412  }
413 
414  return kPmpRegionConfigureOk;
415 }
416 
417 pmp_region_configure_na4_result_t pmp_region_configure_na4(
418  pmp_region_index_t region, pmp_region_config_t config, uintptr_t address) {
419  if (PMP_GRANULARITY_IBEX > 0) {
420  return kPmpRegionConfigureNa4Unavailable;
421  }
422 
423  if (region >= PMP_REGIONS_NUM) {
424  return kPmpRegionConfigureNa4BadRegion;
425  }
426 
427  if (!pmp_address_aligned(address)) {
428  return kPmpRegionConfigureNa4BadAddress;
429  }
430 
431  uint32_t field_value = 0;
432  if (!pmp_cfg_permissions_set(config.permissions, &field_value)) {
433  return kPmpRegionConfigureNa4Error;
434  }
435 
436  pmp_cfg_mode_lock_set(config.lock, &field_value);
437 
438  field_value = bitfield_field32_write(field_value, kPmpCfgModeField,
439  PMP_CFG_CSR_MODE_NA4);
440 
441  // Address registers must be written prior to the configuration registers to
442  // ensure that they are not locked.
443  pmp_region_configure_result_t result = pmp_csr_address_write(region, address);
444  if (result != kPmpRegionConfigureOk) {
445  return (pmp_region_configure_na4_result_t)result;
446  }
447 
448  result = pmp_csr_cfg_field_write(region, field_value);
449  if (result != kPmpRegionConfigureOk) {
450  return (pmp_region_configure_na4_result_t)result;
451  }
452 
453  return kPmpRegionConfigureNa4Ok;
454 }
455 
456 pmp_region_configure_napot_result_t pmp_region_configure_napot(
457  pmp_region_index_t region, pmp_region_config_t config, uintptr_t address,
458  uint32_t size) {
459  if (region >= PMP_REGIONS_NUM) {
460  return kPmpRegionConfigureNapotBadRegion;
461  }
462 
463  uintptr_t napot_address;
464  pmp_region_configure_napot_result_t napot_result =
465  pmp_napot_address_construct(address, size, &napot_address);
466  if (napot_result != kPmpRegionConfigureNapotOk) {
467  return napot_result;
468  }
469 
470  uint32_t field_value = 0;
471  if (!pmp_cfg_permissions_set(config.permissions, &field_value)) {
472  return kPmpRegionConfigureNapotError;
473  }
474 
475  pmp_cfg_mode_lock_set(config.lock, &field_value);
476 
477  field_value = bitfield_field32_write(field_value, kPmpCfgModeField,
478  PMP_CFG_CSR_MODE_NAPOT);
479 
480  // Address registers must be written prior to the configuration registers to
481  // ensure that they are not locked.
482  pmp_region_configure_result_t result =
483  pmp_csr_address_write(region, napot_address);
484  if (result != kPmpRegionConfigureOk) {
485  return (pmp_region_configure_napot_result_t)result;
486  }
487 
488  result = pmp_csr_cfg_field_write(region, field_value);
489  if (result != kPmpRegionConfigureOk) {
490  return (pmp_region_configure_napot_result_t)result;
491  }
492 
493  return kPmpRegionConfigureNapotOk;
494 }
495 
496 pmp_region_configure_result_t pmp_region_configure_tor(
497  pmp_region_index_t region_end, pmp_region_config_t config,
498  uintptr_t address_start, uintptr_t address_end) {
499  if (region_end >= PMP_REGIONS_NUM) {
500  return kPmpRegionConfigureBadRegion;
501  }
502 
503  if (region_end == 0 && address_start > 0) {
504  return kPmpRegionConfigureBadAddress;
505  }
506 
507  if (region_end > 0 && !pmp_address_aligned(address_start)) {
508  return kPmpRegionConfigureBadAddress;
509  }
510 
511  if (!pmp_address_aligned(address_end)) {
512  return kPmpRegionConfigureBadAddress;
513  }
514 
515  uint32_t field_value = 0;
516  if (!pmp_cfg_permissions_set(config.permissions, &field_value)) {
517  return kPmpRegionConfigureError;
518  }
519 
520  pmp_cfg_mode_lock_set(config.lock, &field_value);
521 
522  field_value = bitfield_field32_write(field_value, kPmpCfgModeField,
523  PMP_CFG_CSR_MODE_TOR);
524 
525  // Address registers must be written prior to the configuration registers to
526  // ensure that they are not locked.
527  if (region_end != 0) {
528  pmp_region_configure_result_t result =
529  pmp_csr_address_write(region_end - 1, address_start);
530  if (result != kPmpRegionConfigureOk) {
531  return result;
532  }
533  }
534 
535  pmp_region_configure_result_t result =
536  pmp_csr_address_write(region_end, address_end);
537  if (result != kPmpRegionConfigureOk) {
538  return result;
539  }
540 
541  result = pmp_csr_cfg_field_write(region_end, field_value);
542  if (result != kPmpRegionConfigureOk) {
543  return result;
544  }
545 
546  return kPmpRegionConfigureOk;
547 }
548 
549 pmp_region_configure_result_t pmp_region_is_configured(
550  pmp_region_index_t region, bool *configured) {
551  if (region >= PMP_REGIONS_NUM) {
552  return kPmpRegionConfigureBadRegion;
553  }
554 
555  if (configured == NULL) {
556  return kPmpRegionConfigureBadArg;
557  }
558 
559  uint32_t field_value;
560  pmp_region_configure_result_t result =
561  pmp_csr_cfg_field_read(region, &field_value);
562  if (result != kPmpRegionConfigureOk) {
563  return result;
564  }
565 
566  *configured = field_value != 0;
567 
568  return kPmpRegionConfigureOk;
569 }
570 
571 pmp_region_configure_result_t pmp_region_lock_status_get(
572  pmp_region_index_t region, pmp_region_lock_t *lock) {
573  if (region >= PMP_REGIONS_NUM) {
574  return kPmpRegionConfigureBadRegion;
575  }
576 
577  if (lock == NULL) {
578  return kPmpRegionConfigureBadArg;
579  }
580 
581  uint32_t field_value;
582  pmp_region_configure_result_t result =
583  pmp_csr_cfg_field_read(region, &field_value);
584  if (result != kPmpRegionConfigureOk) {
585  return result;
586  }
587 
588  bool flag = bitfield_bit32_read(field_value, PMP_CFG_CSR_L);
589  *lock = flag ? kPmpRegionLockLocked : kPmpRegionLockUnlocked;
590 
591  return kPmpRegionConfigureOk;
592 }