Software APIs
dif_sram_ctrl.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
6
7#include "sw/device/lib/base/multibits.h"
8
9#include "sram_ctrl_regs.h" // Generated.
10
11/**
12 * Obtains the lock state of the "Control" register.
13 *
14 * When locked, new scrambling key and SRAM pseudo-random data overwriting
15 * requests are not available.
16 */
17static bool sram_ctrl_locked_ctrl(const dif_sram_ctrl_t *sram_ctrl) {
18 return mmio_region_read32(sram_ctrl->base_addr,
19 SRAM_CTRL_CTRL_REGWEN_REG_OFFSET)
20 ? false
21 : true;
22}
23
24/**
25 * Obtains the lock state of the "Exec enable" register.
26 *
27 * When locked, execution from SRAM is disabled, and an attempt to do so
28 * will result in an access violation.
29 */
30static bool sram_ctrl_exec_locked(const dif_sram_ctrl_t *sram_ctrl) {
31 return mmio_region_read32(sram_ctrl->base_addr,
32 SRAM_CTRL_EXEC_REGWEN_REG_OFFSET)
33 ? false
34 : true;
35}
36
37/**
38 * Obtains the lock state of the "Readback enable" register.
39 *
40 * When locked, enabling or disabling the readback feature is not possible.
41 */
42static bool sram_ctrl_readback_locked(const dif_sram_ctrl_t *sram_ctrl) {
43 return mmio_region_read32(sram_ctrl->base_addr,
44 SRAM_CTRL_READBACK_REGWEN_REG_OFFSET)
45 ? false
46 : true;
47}
48
49/**
50 * Locks SRAM Controller "Control" functionality.
51 *
52 * SRAM Scrambling and RAM wiping is no longer available.
53 */
54static void sram_ctrl_lock_ctrl(const dif_sram_ctrl_t *sram_ctrl) {
55 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REGWEN_REG_OFFSET,
56 0);
57}
58
59/**
60 * Locks SRAM Controller "Execute" functionality.
61 *
62 * Execution from SRAM cannot be changed (when enabled - it stays enabled, and
63 * vice versa).
64 */
65static void sram_ctrl_lock_exec(const dif_sram_ctrl_t *sram_ctrl) {
66 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REGWEN_REG_OFFSET,
67 0);
68}
69
70/**
71 * Locks SRAM Controller "Readback" functionality.
72 *
73 * Enabling / disabling the readback functionality is no longer available.
74 */
75static void sram_ctrl_lock_readback(const dif_sram_ctrl_t *sram_ctrl) {
76 mmio_region_write32(sram_ctrl->base_addr,
77 SRAM_CTRL_READBACK_REGWEN_REG_OFFSET, 0);
78}
79
80/**
81 * Obtains the SRAM Controller statues.
82 *
83 * `dif_sram_ctrl_status_t` can be used to query individual flags.
84 */
85static uint32_t sram_ctrl_get_status(const dif_sram_ctrl_t *sram_ctrl) {
86 return mmio_region_read32(sram_ctrl->base_addr, SRAM_CTRL_STATUS_REG_OFFSET);
87}
88
89dif_result_t dif_sram_ctrl_scramble(const dif_sram_ctrl_t *sram_ctrl) {
90 if (sram_ctrl == NULL) {
91 return kDifBadArg;
92 }
93
94 if (sram_ctrl_locked_ctrl(sram_ctrl)) {
95 return kDifLocked;
96 }
97
98 // Issue request for new scrambling key.
99 uint32_t reg =
100 bitfield_bit32_write(0, SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true);
101 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
102
103 // Wait until the scrambling key has been updated.
105 do {
106 status = sram_ctrl_get_status(sram_ctrl);
107 } while ((status & kDifSramCtrlStatusScrKeyValid) == 0);
108
109 // Overwrite memory with pseudo random data.
110 reg = bitfield_bit32_write(0, SRAM_CTRL_CTRL_INIT_BIT, true);
111 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
112
113 // Wait for memory to be overwritten with pseudo random data.
114 do {
115 status = sram_ctrl_get_status(sram_ctrl);
116 } while ((status & kDifSramCtrlStatusInitDone) == 0);
117
118 // Check for the errors during memory overwriting.
120}
121
122dif_result_t dif_sram_ctrl_request_new_key(const dif_sram_ctrl_t *sram_ctrl) {
123 if (sram_ctrl == NULL) {
124 return kDifBadArg;
125 }
126
127 if (sram_ctrl_locked_ctrl(sram_ctrl)) {
128 return kDifLocked;
129 }
130
131 uint32_t reg =
132 bitfield_bit32_write(0, SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT, true);
133 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
134
135 return kDifOk;
136}
137
138dif_result_t dif_sram_ctrl_wipe(const dif_sram_ctrl_t *sram_ctrl) {
139 if (sram_ctrl == NULL) {
140 return kDifBadArg;
141 }
142
143 if (sram_ctrl_locked_ctrl(sram_ctrl)) {
144 return kDifLocked;
145 }
146
147 uint32_t reg = bitfield_bit32_write(0, SRAM_CTRL_CTRL_INIT_BIT, true);
148 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_CTRL_REG_OFFSET, reg);
149
150 return kDifOk;
151}
152
153dif_result_t dif_sram_ctrl_get_status(const dif_sram_ctrl_t *sram_ctrl,
155 if (sram_ctrl == NULL) {
156 return kDifBadArg;
157 }
158
159 if (status == NULL) {
160 return kDifBadArg;
161 }
162
163 *status = sram_ctrl_get_status(sram_ctrl);
164
165 return kDifOk;
166}
167
168dif_result_t dif_sram_ctrl_exec_get_enabled(const dif_sram_ctrl_t *sram_ctrl,
169 dif_toggle_t *state) {
170 if (sram_ctrl == NULL || state == NULL) {
171 return kDifBadArg;
172 }
173
174 uint32_t reg =
175 mmio_region_read32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REG_OFFSET);
176
177 *state = (reg == kMultiBitBool4True) ? kDifToggleEnabled : kDifToggleDisabled;
178
179 return kDifOk;
180}
181
182dif_result_t dif_sram_ctrl_exec_set_enabled(const dif_sram_ctrl_t *sram_ctrl,
183 dif_toggle_t state) {
184 if (sram_ctrl == NULL) {
185 return kDifBadArg;
186 }
187
188 if (sram_ctrl_exec_locked(sram_ctrl)) {
189 return kDifLocked;
190 }
191
192 uint32_t value =
193 (state == kDifToggleEnabled) ? kMultiBitBool4True : kMultiBitBool4False;
194 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_EXEC_REG_OFFSET, value);
195
196 return kDifOk;
197}
198
199dif_result_t dif_sram_ctrl_readback_set(const dif_sram_ctrl_t *sram_ctrl,
200 dif_toggle_t state) {
201 if (sram_ctrl == NULL) {
202 return kDifBadArg;
203 }
204
205 if (sram_ctrl_readback_locked(sram_ctrl)) {
206 return kDifLocked;
207 }
208
209 uint32_t value =
210 (state == kDifToggleEnabled) ? kMultiBitBool4True : kMultiBitBool4False;
211 mmio_region_write32(sram_ctrl->base_addr, SRAM_CTRL_READBACK_REG_OFFSET,
212 value);
213
214 return kDifOk;
215}
216
219 if (sram_ctrl == NULL) {
220 return kDifBadArg;
221 }
222
223 switch (lock) {
225 sram_ctrl_lock_ctrl(sram_ctrl);
226 break;
228 sram_ctrl_lock_exec(sram_ctrl);
229 break;
231 sram_ctrl_lock_readback(sram_ctrl);
232 break;
233 default:
234 return kDifError;
235 }
236
237 return kDifOk;
238}
239
240dif_result_t dif_sram_ctrl_is_locked(const dif_sram_ctrl_t *sram_ctrl,
242 bool *is_locked) {
243 if (sram_ctrl == NULL || is_locked == NULL) {
244 return kDifBadArg;
245 }
246
247 switch (lock) {
249 *is_locked = sram_ctrl_locked_ctrl(sram_ctrl);
250 break;
252 *is_locked = sram_ctrl_exec_locked(sram_ctrl);
253 break;
255 *is_locked = sram_ctrl_readback_locked(sram_ctrl);
256 break;
257 default:
258 return kDifError;
259 }
260
261 return kDifOk;
262}
263
264dif_result_t dif_sram_ctrl_scr_key_rotated(const dif_sram_ctrl_t *sram_ctrl,
265 multi_bit_bool_t *success,
266 multi_bit_bool_t clear) {
267 if (sram_ctrl == NULL || success == NULL) {
268 return kDifBadArg;
269 }
270
271 // We do not use any control flow statements to determine whether to clear
272 // the CSR or not. Rather, the register is always written and we let the
273 // MuBi logic determine what needs to be done. I.e., the register is
274 // specified as W1C in which case a clear operation only takes place if
275 // clear is set to kMultiBitBool4True. If it is set to kMultiBitBool4False,
276 // the current state will persist.
277 *success = mmio_region_read32(sram_ctrl->base_addr,
278 SRAM_CTRL_SCR_KEY_ROTATED_REG_OFFSET);
279 mmio_region_write32(sram_ctrl->base_addr,
280 SRAM_CTRL_SCR_KEY_ROTATED_REG_OFFSET, clear);
281
282 return kDifOk;
283}