Software APIs
dif_otbn.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
12
13#include "otbn_regs.h" // Generated.
14
15static_assert(kDifOtbnErrBitsBadDataAddr ==
16 (1 << OTBN_ERR_BITS_BAD_DATA_ADDR_BIT),
17 "Layout of error bits changed.");
18static_assert(kDifOtbnErrBitsBadInsnAddr ==
19 (1 << OTBN_ERR_BITS_BAD_INSN_ADDR_BIT),
20 "Layout of error bits changed.");
21static_assert(kDifOtbnErrBitsCallStack == (1 << OTBN_ERR_BITS_CALL_STACK_BIT),
22 "Layout of error bits changed.");
23static_assert(kDifOtbnErrBitsIllegalInsn ==
24 (1 << OTBN_ERR_BITS_ILLEGAL_INSN_BIT),
25 "Layout of error bits changed.");
26static_assert(kDifOtbnErrBitsLoop == (1 << OTBN_ERR_BITS_LOOP_BIT),
27 "Layout of error bits changed.");
29 (1 << OTBN_ERR_BITS_IMEM_INTG_VIOLATION_BIT),
30 "Layout of error bits changed.");
32 (1 << OTBN_ERR_BITS_DMEM_INTG_VIOLATION_BIT),
33 "Layout of error bits changed.");
35 (1 << OTBN_ERR_BITS_REG_INTG_VIOLATION_BIT),
36 "Layout of error bits changed.");
38 (1 << OTBN_ERR_BITS_BUS_INTG_VIOLATION_BIT),
39 "Layout of error bits changed.");
41 (1 << OTBN_ERR_BITS_ILLEGAL_BUS_ACCESS_BIT),
42 "Layout of error bits changed.");
44 (1 << OTBN_ERR_BITS_LIFECYCLE_ESCALATION_BIT),
45 "Layout of error bits changed.");
46static_assert(kDifOtbnErrBitsFatalSoftware ==
47 (1 << OTBN_ERR_BITS_FATAL_SOFTWARE_BIT),
48 "Layout of error bits changed.");
49
50/**
51 * Data width of big number subset, in bytes.
52 */
53const int kDifOtbnWlenBytes = 256 / 8;
54
55/**
56 * Ensures that `offset` and `size` are valid for a given `mem_size`.
57 *
58 * Valid are 32b word accesses to 32b-aligned memory locations within
59 * `mem_size`.
60 */
61static bool check_offset_len(uint32_t offset_bytes, size_t len_bytes,
62 size_t mem_size) {
63 // The overflow check below assumes/requires two unsigned inputs.
64 return (len_bytes % sizeof(uint32_t) == 0 &&
65 offset_bytes % sizeof(uint32_t) == 0 &&
66 offset_bytes + len_bytes >= len_bytes &&
67 offset_bytes + len_bytes <= mem_size);
68}
69
70dif_result_t dif_otbn_reset(const dif_otbn_t *otbn) {
71 if (otbn == NULL) {
72 return kDifBadArg;
73 }
74
75 mmio_region_write32(otbn->base_addr, OTBN_INTR_ENABLE_REG_OFFSET, 0);
76
77 // Clear all pending interrupts.
78 mmio_region_write32(otbn->base_addr, OTBN_INTR_STATE_REG_OFFSET, 0xFFFFFFFF);
79
80 return kDifOk;
81}
82
83dif_result_t dif_otbn_write_cmd(const dif_otbn_t *otbn, dif_otbn_cmd_t cmd) {
84 if (otbn == NULL) {
85 return kDifBadArg;
86 }
87
88 mmio_region_write32(otbn->base_addr, OTBN_CMD_REG_OFFSET, cmd);
89
90 return kDifOk;
91}
92
93dif_result_t dif_otbn_get_status(const dif_otbn_t *otbn,
95 if (otbn == NULL || status == NULL) {
96 return kDifBadArg;
97 }
98
99 *status = mmio_region_read32(otbn->base_addr, OTBN_STATUS_REG_OFFSET);
100
101 return kDifOk;
102}
103
104dif_result_t dif_otbn_get_err_bits(const dif_otbn_t *otbn,
105 dif_otbn_err_bits_t *err_bits) {
106 if (otbn == NULL || err_bits == NULL) {
107 return kDifBadArg;
108 }
109
110 uint32_t err_bits_raw =
111 mmio_region_read32(otbn->base_addr, OTBN_ERR_BITS_REG_OFFSET);
112
113 *err_bits = err_bits_raw;
114 return kDifOk;
115}
116
117dif_result_t dif_otbn_get_insn_cnt(const dif_otbn_t *otbn, uint32_t *insn_cnt) {
118 if (otbn == NULL || insn_cnt == NULL) {
119 return kDifBadArg;
120 }
121
122 *insn_cnt = mmio_region_read32(otbn->base_addr, OTBN_INSN_CNT_REG_OFFSET);
123 return kDifOk;
124}
125
126dif_result_t dif_otbn_get_load_checksum(const dif_otbn_t *otbn,
127 uint32_t *checksum) {
128 if (otbn == NULL || checksum == NULL) {
129 return kDifBadArg;
130 }
131
132 *checksum =
133 mmio_region_read32(otbn->base_addr, OTBN_LOAD_CHECKSUM_REG_OFFSET);
134 return kDifOk;
135}
136
137dif_result_t dif_otbn_clear_load_checksum(const dif_otbn_t *otbn) {
138 if (otbn == NULL) {
139 return kDifBadArg;
140 }
141
142 mmio_region_write32(otbn->base_addr, OTBN_LOAD_CHECKSUM_REG_OFFSET, 0);
143
144 return kDifOk;
145}
146
147dif_result_t dif_otbn_imem_write(const dif_otbn_t *otbn, uint32_t offset_bytes,
148 const void *src, size_t len_bytes) {
149 if (otbn == NULL || src == NULL ||
150 !check_offset_len(offset_bytes, len_bytes, OTBN_IMEM_SIZE_BYTES)) {
151 return kDifBadArg;
152 }
153
154 mmio_region_memcpy_to_mmio32(
155 otbn->base_addr, OTBN_IMEM_REG_OFFSET + offset_bytes, src, len_bytes);
156
157 return kDifOk;
158}
159
160dif_result_t dif_otbn_imem_read(const dif_otbn_t *otbn, uint32_t offset_bytes,
161 void *dest, size_t len_bytes) {
162 if (otbn == NULL || dest == NULL ||
163 !check_offset_len(offset_bytes, len_bytes, OTBN_IMEM_SIZE_BYTES)) {
164 return kDifBadArg;
165 }
166
167 mmio_region_memcpy_from_mmio32(
168 otbn->base_addr, OTBN_IMEM_REG_OFFSET + offset_bytes, dest, len_bytes);
169
170 return kDifOk;
171}
172
173dif_result_t dif_otbn_dmem_write(const dif_otbn_t *otbn, uint32_t offset_bytes,
174 const void *src, size_t len_bytes) {
175 if (otbn == NULL || src == NULL ||
176 !check_offset_len(offset_bytes, len_bytes, OTBN_DMEM_SIZE_BYTES)) {
177 return kDifBadArg;
178 }
179
180 mmio_region_memcpy_to_mmio32(
181 otbn->base_addr, OTBN_DMEM_REG_OFFSET + offset_bytes, src, len_bytes);
182
183 return kDifOk;
184}
185
186dif_result_t dif_otbn_dmem_read(const dif_otbn_t *otbn, uint32_t offset_bytes,
187 void *dest, size_t len_bytes) {
188 if (otbn == NULL || dest == NULL ||
189 !check_offset_len(offset_bytes, len_bytes, OTBN_DMEM_SIZE_BYTES)) {
190 return kDifBadArg;
191 }
192
193 mmio_region_memcpy_from_mmio32(
194 otbn->base_addr, OTBN_DMEM_REG_OFFSET + offset_bytes, dest, len_bytes);
195
196 return kDifOk;
197}
198
199dif_result_t dif_otbn_set_ctrl_software_errs_fatal(const dif_otbn_t *otbn,
200 bool enable) {
201 if (otbn == NULL) {
202 return kDifBadArg;
203 }
204
205 // Only one bit in the CTRL register so no need to read current value.
206 uint32_t new_ctrl;
207
208 if (enable) {
209 new_ctrl = 1;
210 } else {
211 new_ctrl = 0;
212 }
213
214 mmio_region_write32(otbn->base_addr, OTBN_CTRL_REG_OFFSET, new_ctrl);
215 if (mmio_region_read32(otbn->base_addr, OTBN_CTRL_REG_OFFSET) != new_ctrl) {
216 return kDifUnavailable;
217 }
218
219 return kDifOk;
220}
221
222size_t dif_otbn_get_dmem_size_bytes(const dif_otbn_t *otbn) {
223 return OTBN_DMEM_SIZE_BYTES;
224}
225
226size_t dif_otbn_get_imem_size_bytes(const dif_otbn_t *otbn) {
227 return OTBN_IMEM_SIZE_BYTES;
228}