Software APIs
epmp_state.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_SILICON_CREATOR_LIB_EPMP_STATE_H_
6 #define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_EPMP_STATE_H_
7 
8 #include <stdint.h>
9 
11 #include "sw/device/silicon_creator/lib/epmp_defs.h"
12 #include "sw/device/silicon_creator/lib/error.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif // __cplusplus
17 
18 /**
19  * Silicon creator ePMP library.
20  *
21  * This library provides functions to create and manage an in-memory copy of the
22  * ePMP configuration. To update the hardware configuration please use either
23  * assembly or the CSR library directly as needed.
24  */
25 
26 enum {
27  /**
28  * The number of PMP entries supported by the hardware.
29  */
30  kEpmpNumRegions = 16,
31 };
32 
33 /**
34  * PMP configuration permission settings.
35  *
36  * May be combined with `epmp_mode_t` values to form complete configurations.
37  *
38  * Bit | Index
39  * ----+------
40  * L | 7
41  * R | 0
42  * W | 1
43  * X | 2
44  *
45  * NOTE: Because the chip is configured with MMWP=1 and MML=0, the ePMP bit
46  * patterns can sometimes have counterintuitive meanings.
47  *
48  * NOTE: After setting MML=1, the meanings of some of the bit patterns will
49  * change. See section 2.2 of the "PMP Enhancements for memory access and
50  * execution prevention on Machine mode (Smepmp)" document
51  * (https://github.com/riscv/riscv-tee/blob/main/Smepmp/Smepmp.pdf).
52  */
53 typedef enum epmp_perm {
54  kEpmpPermUnlocked = 0,
55  /** M mode: no access. U mode: no access. */
56  kEpmpPermLockedNoAccess = EPMP_CFG_L,
57 
58  /** M mode: read only. U mode: no access. */
59  kEpmpPermLockedReadOnly = EPMP_CFG_LR,
60 
61  /** M mode: read/write. U mode: no access. */
62  kEpmpPermLockedReadWrite = EPMP_CFG_LRW,
63 
64  /** M mode: read/execute. U mode: no access. */
65  kEpmpPermLockedReadExecute = EPMP_CFG_LRX,
66 
67  /** M mode: read/execute. U mode: read/execute. */
68  kEpmpPermLockedReadWriteExecute = EPMP_CFG_LRWX,
69 
70  /** M mode: read/write/execute. U mode: read only. */
71  kEpmpPermReadOnly = EPMP_CFG_R,
72 
73  /** M mode: read/write/execute. U mode: read/write. */
74  kEpmpPermReadWrite = EPMP_CFG_R | EPMP_CFG_W,
75 
76  /** M mode: read/write/execute. U mode: read/execute. */
77  kEpmpPermReadExecute = EPMP_CFG_R | EPMP_CFG_X,
78 
79  /** M mode: read/write/execute. U mode: read/write/execute. */
80  kEpmpPermReadWriteExecute = EPMP_CFG_R | EPMP_CFG_W | EPMP_CFG_X,
81 } epmp_perm_t;
82 
83 /**
84  * PMP configuration addressing mode fields.
85  *
86  * May be combined with `epmp_perm_t` values to form complete configurations.
87  */
88 typedef enum epmp_mode {
89  kEpmpModeOff = EPMP_CFG_A_OFF,
90  kEpmpModeTor = EPMP_CFG_A_TOR,
91  kEpmpModeNa4 = EPMP_CFG_A_NA4,
92  kEpmpModeNapot = EPMP_CFG_A_NAPOT,
93 } epmp_mode_t;
94 
95 /**
96  * ePMP region specification.
97  *
98  * Provides the unencoded start and end addresses of a particular region.
99  *
100  * The `start` address is inclusive and the `end` address is exclusive.
101  */
102 typedef struct epmp_region {
103  uintptr_t start;
104  uintptr_t end;
105 } epmp_region_t;
106 
107 /**
108  * In-memory copy of the ePMP register state.
109  */
110 typedef struct epmp_state {
111  /**
112  * PMP configuration values (pmpcfg0 - pmpcfg3).
113  *
114  * The 8-bit configuration values (pmp0cfg - pmp15cfg) are packed into these
115  * registers in little-endian byte order.
116  *
117  * Each 8-bit configuration value is encoded as follows:
118  *
119  * Layout:
120  *
121  * +---+-------+-------+---+---+---+
122  * | L | 0 | A | X | W | R |
123  * +---+-------+-------+---+---+---+
124  * 8 7 6 5 4 3 2 1 0
125  *
126  * Key:
127  *
128  * L = Locked
129  * A = Address-matching Mode (OFF=0, TOR=1, NA4=2, NAPOT=3)
130  * X = Executable
131  * W = Writeable
132  * R = Readable
133  *
134  * Note: the interpretation of these configuration bits depends on
135  * whether Machine Mode Lockdown (mseccfg.MML) is enabled or not.
136  * See the PMP Enhancements specification for more details.
137  */
138  uint32_t pmpcfg[kEpmpNumRegions / 4];
139 
140  /**
141  * PMP address registers (pmpaddr0 - pmpaddr15).
142  *
143  * The way that address register values are interpreted differs
144  * depending on the address-matching mode (A) in the relevant pmpcfg
145  * register(s).
146  */
147  uint32_t pmpaddr[kEpmpNumRegions];
148 
149  /**
150  * Machine Security Configuration register (mseccfg).
151  *
152  * +---...---+------+------+------+
153  * | 0 | RLB | MMWP | MML |
154  * +---...---+------+------+------+
155  * 63 3 2 1 0
156  *
157  * Key:
158  *
159  * RLB = Rule Locking Bypass
160  * MMWP = Machine Mode Whitelist Policy
161  * MML = Machine Mode Lockdown
162  *
163  * See the PMP Enhancements specification for more details.
164  *
165  * Note: these are the low 32 bits of mseccfg only. The high 32 bits
166  * are set to 0.
167  */
168  uint32_t mseccfg;
169 } epmp_state_t;
170 
171 extern epmp_state_t epmp_state;
172 
173 /**
174  * Configure the given PMP entry in state using the Top-Of-Range addressing
175  * mode.
176  *
177  * @param state The ePMP state to update.
178  * @param entry The index of the entry to update.
179  * @param region The memory region to encode in the address registers.
180  * @param perm The permissions to set for the entry.
181  */
182 inline void epmp_state_configure_tor(uint32_t entry, epmp_region_t region,
183  epmp_perm_t perm) {
184  // Set address registers.
185  if (entry > 0) {
186  epmp_state.pmpaddr[entry - 1] = region.start >> 2;
187  }
188  epmp_state.pmpaddr[entry] = region.end >> 2;
189 
190  // Set configuration register.
191  bitfield_field32_t field = {.mask = 0xff, .index = (entry % 4) * 8};
193  epmp_state.pmpcfg[entry / 4], field, kEpmpModeTor | perm);
194 }
195 
196 /**
197  * Configure the given PMP entry in state using the Naturally-Aligned-4-byte
198  * addressing mode.
199  *
200  * @param state The ePMP state to update.
201  * @param entry The index of the entry to update.
202  * @param region The memory region to encode in the address registers.
203  * @param perm The permissions to set for the entry.
204  */
205 inline void epmp_state_configure_na4(uint32_t entry, epmp_region_t region,
206  epmp_perm_t perm) {
207  // Set address register.
208  epmp_state.pmpaddr[entry] = region.start >> 2;
209 
210  // Set configuration register.
211  bitfield_field32_t field = {.mask = 0xff, .index = (entry % 4) * 8};
213  epmp_state.pmpcfg[entry / 4], field, kEpmpModeNa4 | perm);
214 }
215 
216 /**
217  * Configure the given PMP entry in state using the
218  * Naturally-Aligned-Power-Of-Two addressing mode.
219  *
220  * @param state The ePMP state to update.
221  * @param entry The index of the entry to update.
222  * @param region The memory region to encode in the address registers.
223  * @param perm The permissions to set for the entry.
224  */
225 inline void epmp_state_configure_napot(uint32_t entry, epmp_region_t region,
226  epmp_perm_t perm) {
227  // Set address register.
228  uint32_t len = (region.end - region.start - 1) >> 3;
229  epmp_state.pmpaddr[entry] = (region.start >> 2) | len;
230 
231  // Set configuration register.
232  bitfield_field32_t field = {.mask = 0xff, .index = (entry % 4) * 8};
234  epmp_state.pmpcfg[entry / 4], field, kEpmpModeNapot | perm);
235 }
236 
237 /**
238  * Report whether the given state matches the current hardware ePMP
239  * configuration.
240  *
241  * @param state Expected values of the ePMP CSRs.
242  * @return Whether the check succeeded.
243  */
245 rom_error_t epmp_state_check(void);
246 
247 #ifdef __cplusplus
248 } // extern "C"
249 #endif // __cplusplus
250 
251 #endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_EPMP_STATE_H_