Software APIs
dif_keymgr_dpe.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 <assert.h>
8
10
11#include "keymgr_dpe_regs.h" // Generated.
13
14/**
15 * Address spaces of SW_BINDING_N, SALT_N, SW_SHARE0_OUTPUT_N, and
16 * SW_SHARE1_OUTPUT_N registers must be contiguous to be able to use
17 * `mmio_region_memcpy_to/from_mmio32()`.
18 */
19static_assert(KEYMGR_DPE_SW_BINDING_1_REG_OFFSET ==
20 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 4,
21 "SW_BINDING_N registers must be contiguous.");
22static_assert(KEYMGR_DPE_SW_BINDING_2_REG_OFFSET ==
23 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 8,
24 "SW_BINDING_N registers must be contiguous.");
25static_assert(KEYMGR_DPE_SW_BINDING_3_REG_OFFSET ==
26 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 12,
27 "SW_BINDING_N registers must be contiguous.");
28static_assert(KEYMGR_DPE_SW_BINDING_4_REG_OFFSET ==
29 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 16,
30 "SW_BINDING_N registers must be contiguous.");
31static_assert(KEYMGR_DPE_SW_BINDING_5_REG_OFFSET ==
32 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 20,
33 "SW_BINDING_N registers must be contiguous.");
34static_assert(KEYMGR_DPE_SW_BINDING_6_REG_OFFSET ==
35 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 24,
36 "SW_BINDING_N registers must be contiguous.");
37static_assert(KEYMGR_DPE_SW_BINDING_7_REG_OFFSET ==
38 KEYMGR_DPE_SW_BINDING_0_REG_OFFSET + 28,
39 "SW_BINDING_N registers must be contiguous.");
40
41static_assert(KEYMGR_DPE_SALT_1_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 4,
42 "SALT_N registers must be contiguous.");
43static_assert(KEYMGR_DPE_SALT_2_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 8,
44 "SALT_N registers must be contiguous.");
45static_assert(KEYMGR_DPE_SALT_3_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 12,
46 "SALT_N registers must be contiguous.");
47static_assert(KEYMGR_DPE_SALT_4_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 16,
48 "SALT_N registers must be contiguous.");
49static_assert(KEYMGR_DPE_SALT_5_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 20,
50 "SALT_N registers must be contiguous.");
51static_assert(KEYMGR_DPE_SALT_6_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 24,
52 "SALT_N registers must be contiguous.");
53static_assert(KEYMGR_DPE_SALT_7_REG_OFFSET == KEYMGR_DPE_SALT_0_REG_OFFSET + 28,
54 "SALT_N registers must be contiguous.");
55
56static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_1_REG_OFFSET ==
57 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 4,
58 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
59static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_2_REG_OFFSET ==
60 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 8,
61 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
62static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_3_REG_OFFSET ==
63 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 12,
64 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
65static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_4_REG_OFFSET ==
66 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 16,
67 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
68static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_5_REG_OFFSET ==
69 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 20,
70 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
71static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_6_REG_OFFSET ==
72 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 24,
73 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
74static_assert(KEYMGR_DPE_SW_SHARE0_OUTPUT_7_REG_OFFSET ==
75 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET + 28,
76 "SW_SHARE0_OUTPUT_N registers must be contiguous.");
77
78static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_1_REG_OFFSET ==
79 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 4,
80 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
81static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_2_REG_OFFSET ==
82 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 8,
83 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
84static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_3_REG_OFFSET ==
85 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 12,
86 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
87static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_4_REG_OFFSET ==
88 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 16,
89 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
90static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_5_REG_OFFSET ==
91 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 20,
92 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
93static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_6_REG_OFFSET ==
94 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 24,
95 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
96static_assert(KEYMGR_DPE_SW_SHARE1_OUTPUT_7_REG_OFFSET ==
97 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET + 28,
98 "SW_SHARE1_OUTPUT_N registers must be contiguous.");
99
100/**
101 * Error code constants of `dif_keymgr_dpe_status_code_t` are masks for the bits
102 * of ERR_CODE register shifted left by 1.
103 */
104static_assert(kDifKeymgrDpeStatusCodeInvalidOperation >> 1 ==
105 1 << KEYMGR_DPE_ERR_CODE_INVALID_OP_BIT,
106 "Layout of ERR_CODE register changed.");
107static_assert(kDifKeymgrDpeStatusCodeInvalidKmacInput >> 1 ==
108 1 << KEYMGR_DPE_ERR_CODE_INVALID_KMAC_INPUT_BIT,
109 "Layout of ERR_CODE register changed.");
110
111/**
112 * Ensure that enum values for versioned key generation match the parameters
113 * generated by HW.
114 */
115static_assert(kDifKeymgrDpeKeyDestAes ==
116 KEYMGR_DPE_CONTROL_SHADOWED_DEST_SEL_VALUE_AES,
117 "Key destination macros must match the values from its enum.");
118static_assert(kDifKeymgrDpeKeyDestKmac ==
119 KEYMGR_DPE_CONTROL_SHADOWED_DEST_SEL_VALUE_KMAC,
120 "Key destination macros must match the values from its enum.");
121static_assert(kDifKeymgrDpeKeyDestOtbn ==
122 KEYMGR_DPE_CONTROL_SHADOWED_DEST_SEL_VALUE_OTBN,
123 "Key destination macros must match the values from its enum.");
124
125/**
126 * Ensure that SW-visible FSM values match the one defined as SW enum.
127 */
128static_assert(kDifKeymgrDpeStateReset ==
129 KEYMGR_DPE_WORKING_STATE_STATE_VALUE_RESET,
130 "Keymgr_DPE reported FSM state and SW enums must match.");
131static_assert(kDifKeymgrDpeStateAvailable ==
132 KEYMGR_DPE_WORKING_STATE_STATE_VALUE_AVAILABLE,
133 "Keymgr_DPE reported FSM state and SW enums must match.");
134static_assert(kDifKeymgrDpeStateDisabled ==
135 KEYMGR_DPE_WORKING_STATE_STATE_VALUE_DISABLED,
136 "Keymgr_DPE reported FSM state and SW enums must match.");
137static_assert(kDifKeymgrDpeStateInvalid ==
138 KEYMGR_DPE_WORKING_STATE_STATE_VALUE_INVALID,
139 "Keymgr_DPE reported FSM state and SW enums must match.");
140
141/**
142 * Checks if the key manager is ready for a new operation, i.e. it is idle and
143 * the CONFIG register is unlocked.
144 */
146static bool is_ready(const dif_keymgr_dpe_t *keymgr_dpe) {
147 // KeymgrDPE must be idle and the CONTROL register must be writable.
148 uint32_t reg_op_status = mmio_region_read32(keymgr_dpe->base_addr,
149 KEYMGR_DPE_OP_STATUS_REG_OFFSET);
150 if (bitfield_field32_read(reg_op_status, KEYMGR_DPE_OP_STATUS_STATUS_FIELD) !=
151 KEYMGR_DPE_OP_STATUS_STATUS_VALUE_IDLE) {
152 return false;
153 }
154 uint32_t reg_cfg_regwen = mmio_region_read32(
155 keymgr_dpe->base_addr, KEYMGR_DPE_CFG_REGWEN_REG_OFFSET);
156 return bitfield_bit32_read(reg_cfg_regwen, KEYMGR_DPE_CFG_REGWEN_EN_BIT);
157}
158
159dif_result_t dif_keymgr_dpe_initialize(const dif_keymgr_dpe_t *keymgr_dpe,
160 uint32_t slot_dst_sel) {
161 if (keymgr_dpe == NULL) {
162 return kDifBadArg;
163 }
164
165 if (!is_ready(keymgr_dpe)) {
166 return kDifLocked;
167 }
168
169 uint32_t reg_control = bitfield_field32_write(
170 KEYMGR_DPE_CONTROL_SHADOWED_REG_RESVAL,
171 KEYMGR_DPE_CONTROL_SHADOWED_SLOT_DST_SEL_FIELD, slot_dst_sel);
172 reg_control = bitfield_field32_write(
173 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_FIELD,
174 KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_VALUE_ADVANCE);
175 mmio_region_write32_shadowed(keymgr_dpe->base_addr,
176 KEYMGR_DPE_CONTROL_SHADOWED_REG_OFFSET,
177 reg_control);
178
179 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_START_REG_OFFSET,
180 1 << KEYMGR_DPE_START_EN_BIT);
181
182 return kDifOk;
183}
184
185dif_result_t dif_keymgr_dpe_advance_state(
186 const dif_keymgr_dpe_t *keymgr_dpe,
187 const dif_keymgr_dpe_advance_params_t *params) {
188 if (keymgr_dpe == NULL || params == NULL) {
189 return kDifBadArg;
190 }
191
192 if (!is_ready(keymgr_dpe)) {
193 return kDifLocked;
194 }
195
196 // If either of SLOT_POLICY_REGWEN, MAX_KEY_VER_REGWEN or SW_BINDING_REGWEN is
197 // locked, return error.
198 uint32_t slot_policy_regwen = mmio_region_read32(
199 keymgr_dpe->base_addr, KEYMGR_DPE_SLOT_POLICY_REGWEN_REG_OFFSET);
200 if (!bitfield_bit32_read(slot_policy_regwen,
201 KEYMGR_DPE_SLOT_POLICY_REGWEN_EN_BIT)) {
202 return kDifLocked;
203 }
204
205 uint32_t reg_max_key_ver_wen = mmio_region_read32(
206 keymgr_dpe->base_addr, KEYMGR_DPE_MAX_KEY_VER_REGWEN_REG_OFFSET);
207 if (!bitfield_bit32_read(reg_max_key_ver_wen,
208 KEYMGR_DPE_MAX_KEY_VER_REGWEN_EN_BIT)) {
209 return kDifLocked;
210 }
211
212 uint32_t sw_binding_regwen = mmio_region_read32(
213 keymgr_dpe->base_addr, KEYMGR_DPE_SW_BINDING_REGWEN_REG_OFFSET);
214 if (!bitfield_bit32_read(sw_binding_regwen,
215 KEYMGR_DPE_SW_BINDING_REGWEN_EN_BIT)) {
216 return kDifLocked;
217 }
218
219 // Now that we know REGWEN registers are enabled, we can write each value and
220 // then lock REGWEN registers (rw0c).
221 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_SLOT_POLICY_REG_OFFSET,
222 params->slot_policy);
223 mmio_region_write32(keymgr_dpe->base_addr,
224 KEYMGR_DPE_SLOT_POLICY_REGWEN_REG_OFFSET, 0);
225
226 mmio_region_write32_shadowed(keymgr_dpe->base_addr,
227 KEYMGR_DPE_MAX_KEY_VER_SHADOWED_REG_OFFSET,
228 params->max_key_version);
229 mmio_region_write32(keymgr_dpe->base_addr,
230 KEYMGR_DPE_MAX_KEY_VER_REGWEN_REG_OFFSET, 0);
231
232 mmio_region_memcpy_to_mmio32(
233 keymgr_dpe->base_addr, KEYMGR_DPE_SW_BINDING_0_REG_OFFSET,
234 params->binding_value, sizeof(params->binding_value));
235 mmio_region_write32(keymgr_dpe->base_addr,
236 KEYMGR_DPE_SW_BINDING_REGWEN_REG_OFFSET, 0);
237
238 uint32_t reg_control = bitfield_field32_write(
239 KEYMGR_DPE_CONTROL_SHADOWED_REG_RESVAL,
240 KEYMGR_DPE_CONTROL_SHADOWED_SLOT_SRC_SEL_FIELD, params->slot_src_sel);
241 reg_control = bitfield_field32_write(
242 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_SLOT_DST_SEL_FIELD,
243 params->slot_dst_sel);
244 reg_control = bitfield_field32_write(
245 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_FIELD,
246 KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_VALUE_ADVANCE);
247 mmio_region_write32_shadowed(keymgr_dpe->base_addr,
248 KEYMGR_DPE_CONTROL_SHADOWED_REG_OFFSET,
249 reg_control);
250 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_START_REG_OFFSET,
251 1 << KEYMGR_DPE_START_EN_BIT);
252
253 return kDifOk;
254}
255
256dif_result_t dif_keymgr_dpe_erase_slot(
257 const dif_keymgr_dpe_t *keymgr_dpe,
258 const dif_keymgr_dpe_erase_params_t *params) {
259 if (keymgr_dpe == NULL) {
260 return kDifBadArg;
261 }
262
263 if (!is_ready(keymgr_dpe)) {
264 return kDifLocked;
265 }
266
267 uint32_t reg_control = bitfield_field32_write(
268 KEYMGR_DPE_CONTROL_SHADOWED_REG_RESVAL,
269 KEYMGR_DPE_CONTROL_SHADOWED_SLOT_DST_SEL_FIELD, params->slot_dst_sel);
270 reg_control = bitfield_field32_write(
271 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_FIELD,
272 KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_VALUE_ERASE_SLOT);
273 mmio_region_write32_shadowed(keymgr_dpe->base_addr,
274 KEYMGR_DPE_CONTROL_SHADOWED_REG_OFFSET,
275 reg_control);
276 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_START_REG_OFFSET,
277 1 << KEYMGR_DPE_START_EN_BIT);
278
279 return kDifOk;
280}
281
282dif_result_t dif_keymgr_dpe_generate(
283 const dif_keymgr_dpe_t *keymgr_dpe,
284 const dif_keymgr_dpe_generate_params_t *params) {
285 if (keymgr_dpe == NULL || params == NULL) {
286 return kDifBadArg;
287 }
288
289 if (!is_ready(keymgr_dpe)) {
290 return kDifLocked;
291 }
292
293 uint32_t reg_control = bitfield_field32_write(
294 KEYMGR_DPE_CONTROL_SHADOWED_REG_RESVAL,
295 KEYMGR_DPE_CONTROL_SHADOWED_DEST_SEL_FIELD, params->key_dest);
296 reg_control = bitfield_field32_write(
297 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_SLOT_SRC_SEL_FIELD,
298 params->slot_src_sel);
299
300 if (params->sideload_key) {
301 reg_control = bitfield_field32_write(
302 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_FIELD,
303 KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_HW_OUTPUT);
304 } else {
305 reg_control = bitfield_field32_write(
306 reg_control, KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_FIELD,
307 KEYMGR_DPE_CONTROL_SHADOWED_OPERATION_VALUE_GENERATE_SW_OUTPUT);
308 }
309 mmio_region_write32_shadowed(keymgr_dpe->base_addr,
310 KEYMGR_DPE_CONTROL_SHADOWED_REG_OFFSET,
311 reg_control);
312
313 // Write SALT and VERSION.
314 mmio_region_memcpy_to_mmio32(keymgr_dpe->base_addr,
315 KEYMGR_DPE_SALT_0_REG_OFFSET, params->salt,
316 sizeof(params->salt));
317 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_KEY_VERSION_REG_OFFSET,
318 params->version);
319
320 // Start the operation
321 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_START_REG_OFFSET,
322 1 << KEYMGR_DPE_START_EN_BIT);
323
324 return kDifOk;
325}
326
327dif_result_t dif_keymgr_dpe_read_output(const dif_keymgr_dpe_t *keymgr_dpe,
328 dif_keymgr_dpe_output_t *output) {
329 if (keymgr_dpe == NULL || output == NULL) {
330 return kDifBadArg;
331 }
332
333 mmio_region_memcpy_from_mmio32(keymgr_dpe->base_addr,
334 KEYMGR_DPE_SW_SHARE0_OUTPUT_0_REG_OFFSET,
335 output->value[0], sizeof(output->value[0]));
336 mmio_region_memcpy_from_mmio32(keymgr_dpe->base_addr,
337 KEYMGR_DPE_SW_SHARE1_OUTPUT_0_REG_OFFSET,
338 output->value[1], sizeof(output->value[1]));
339
340 return kDifOk;
341}
342
343dif_result_t dif_keymgr_dpe_get_status_codes(
344 const dif_keymgr_dpe_t *keymgr_dpe,
345 dif_keymgr_dpe_status_codes_t *status_codes) {
346 if (keymgr_dpe == NULL || status_codes == NULL) {
347 return kDifBadArg;
348 }
349
350 // Read and clear OP_STATUS register (rw1c).
351 uint32_t reg_op_status = mmio_region_read32(keymgr_dpe->base_addr,
352 KEYMGR_DPE_OP_STATUS_REG_OFFSET);
353
354 bool is_idle = false;
355 bool has_error = false;
356 switch (reg_op_status) {
357 case KEYMGR_DPE_OP_STATUS_STATUS_VALUE_IDLE:
358 is_idle = true;
359 break;
360 case KEYMGR_DPE_OP_STATUS_STATUS_VALUE_DONE_SUCCESS:
361 is_idle = true;
362 mmio_region_write32(keymgr_dpe->base_addr,
363 KEYMGR_DPE_OP_STATUS_REG_OFFSET, reg_op_status);
364 break;
365 case KEYMGR_DPE_OP_STATUS_STATUS_VALUE_DONE_ERROR:
366 is_idle = true;
367 has_error = true;
368 mmio_region_write32(keymgr_dpe->base_addr,
369 KEYMGR_DPE_OP_STATUS_REG_OFFSET, reg_op_status);
370 break;
371 case KEYMGR_DPE_OP_STATUS_STATUS_VALUE_WIP:
372 break;
373 default:
374 return kDifError;
375 }
376
377 // `kIdleBitfield` defines the idle field within
378 // `dif_keymgr_dpe_status_codes_t`.
379 *status_codes = (dif_keymgr_dpe_status_codes_t)bitfield_field32_write(
380 0, kIdleBitfield, is_idle);
381
382 if (has_error) {
383 // Read and clear ERR_CODE register (rw1c).
384 uint32_t reg_err_code = mmio_region_read32(keymgr_dpe->base_addr,
385 KEYMGR_DPE_ERR_CODE_REG_OFFSET);
386 mmio_region_write32(keymgr_dpe->base_addr, KEYMGR_DPE_ERR_CODE_REG_OFFSET,
387 reg_err_code);
388 *status_codes = (dif_keymgr_dpe_status_codes_t)bitfield_field32_write(
389 *status_codes, kErrorBitfield, reg_err_code);
390 }
391
392 return kDifOk;
393}
394
395dif_result_t dif_keymgr_dpe_get_state(const dif_keymgr_dpe_t *keymgr_dpe,
396 dif_keymgr_dpe_state_t *state) {
397 if (keymgr_dpe == NULL || state == NULL) {
398 return kDifBadArg;
399 }
400
401 uint32_t reg_state = mmio_region_read32(keymgr_dpe->base_addr,
402 KEYMGR_DPE_WORKING_STATE_REG_OFFSET);
403
404 *state =
405 bitfield_field32_read(reg_state, KEYMGR_DPE_WORKING_STATE_STATE_FIELD);
406 return kDifOk;
407}