Software APIs
epmp.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/silicon_creator/lib/drivers/epmp.h"
6 
10 #include "sw/device/silicon_creator/lib/epmp_state.h"
11 
13 
14 #define EPMP_SET(cfg_reg, addr_reg, mask, cfg, addr) \
15  CSR_CLEAR_BITS(CSR_REG_PMPCFG##cfg_reg, mask); \
16  CSR_WRITE(CSR_REG_PMPADDR##addr_reg, pmpaddr); \
17  CSR_SET_BITS(CSR_REG_PMPCFG##cfg_reg, cfg);
18 
19 void epmp_set(uint8_t entry, uint32_t pmpcfg, uint32_t pmpaddr) {
20  uint32_t shift = 8 * (entry % 4);
21  uint32_t mask = 0xFFu << shift;
22  uint32_t cfg = (pmpcfg & 0xFFu) << shift;
23  HARDENED_CHECK_LT(entry, 16);
24  switch (entry) {
25  // clang-format off
26  case 0: EPMP_SET(0, 0, mask, cfg, pmpaddr); break;
27  case 1: EPMP_SET(0, 1, mask, cfg, pmpaddr); break;
28  case 2: EPMP_SET(0, 2, mask, cfg, pmpaddr); break;
29  case 3: EPMP_SET(0, 3, mask, cfg, pmpaddr); break;
30  case 4: EPMP_SET(1, 4, mask, cfg, pmpaddr); break;
31  case 5: EPMP_SET(1, 5, mask, cfg, pmpaddr); break;
32  case 6: EPMP_SET(1, 6, mask, cfg, pmpaddr); break;
33  case 7: EPMP_SET(1, 7, mask, cfg, pmpaddr); break;
34  case 8: EPMP_SET(2, 8, mask, cfg, pmpaddr); break;
35  case 9: EPMP_SET(2, 9, mask, cfg, pmpaddr); break;
36  case 10: EPMP_SET(2, 10, mask, cfg, pmpaddr); break;
37  case 11: EPMP_SET(2, 11, mask, cfg, pmpaddr); break;
38  case 12: EPMP_SET(3, 12, mask, cfg, pmpaddr); break;
39  case 13: EPMP_SET(3, 13, mask, cfg, pmpaddr); break;
40  case 14: EPMP_SET(3, 14, mask, cfg, pmpaddr); break;
41  case 15: EPMP_SET(3, 15, mask, cfg, pmpaddr); break;
42  // clang-format on
43  default:
44  // should be impossible to get here because of HARDENED_CHECK_LT above.
45  HARDENED_TRAP();
46  }
47  uint32_t cfgent = entry / 4;
48  epmp_state.pmpcfg[cfgent] = (epmp_state.pmpcfg[cfgent] & ~mask) | cfg;
49  epmp_state.pmpaddr[entry] = pmpaddr;
50 }
51 
52 void epmp_clear(uint8_t entry) { epmp_set(entry, kEpmpModeOff, 0); }
53 
54 void epmp_clear_lock_bits(void) {
55  const uint32_t mask =
56  ((uint32_t)EPMP_CFG_L << 0 * 8) | ((uint32_t)EPMP_CFG_L << 1 * 8) |
57  ((uint32_t)EPMP_CFG_L << 2 * 8) | ((uint32_t)EPMP_CFG_L << 3 * 8);
58  CSR_CLEAR_BITS(CSR_REG_PMPCFG0, mask);
59  CSR_CLEAR_BITS(CSR_REG_PMPCFG1, mask);
60  CSR_CLEAR_BITS(CSR_REG_PMPCFG2, mask);
61  CSR_CLEAR_BITS(CSR_REG_PMPCFG3, mask);
62  for (int cfgent = 0; cfgent < 4; ++cfgent) {
63  epmp_state.pmpcfg[cfgent] &= ~mask;
64  }
65 }
66 
67 uint32_t epmp_encode_napot(epmp_region_t region) {
68  const uint32_t length = region.end - region.start;
69  // The length must be 4 or more.
70  HARDENED_CHECK_GE(length, 4);
71  // The length must be a power of 2.
73  // The start address must be naturally aligned with length.
74  HARDENED_CHECK_EQ(region.start & (length - 1), 0);
75  return (region.start >> 2) | ((length - 1) >> 3);
76 }
77 
78 epmp_region_t epmp_decode_napot(uint32_t pmpaddr) {
79  HARDENED_CHECK_NE(pmpaddr, UINT32_MAX);
80  uint32_t size = 1u << bitfield_count_trailing_zeroes32(~pmpaddr);
81  pmpaddr = (pmpaddr & ~(size - 1)) << 2;
82  size <<= 3;
83  return (epmp_region_t){.start = pmpaddr, .end = pmpaddr + size};
84 }
85 
86 void epmp_set_napot(uint8_t entry, epmp_region_t region, epmp_perm_t perm) {
87  uint32_t addr = epmp_encode_napot(region);
88  epmp_mode_t mode =
89  region.end - region.start == 4 ? kEpmpModeNa4 : kEpmpModeNapot;
90  epmp_set(entry, (uint32_t)mode | (uint32_t)perm, addr);
91 }
92 
93 void epmp_set_tor(uint8_t entry, epmp_region_t region, epmp_perm_t perm) {
94  uint32_t start = region.start >> 2;
95  uint32_t end = ((region.end + 3u) & ~3u) >> 2;
96  epmp_set(entry, kEpmpModeOff, start);
97  epmp_set(entry + 1, (uint32_t)kEpmpModeTor | (uint32_t)perm, end);
98 }
99 
100 void epmp_clear_rlb(void) {
101  const uint32_t kMask = EPMP_MSECCFG_RLB;
102  epmp_state.mseccfg &= ~kMask;
103  CSR_CLEAR_BITS(CSR_REG_MSECCFG, kMask);
104 }