1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * CRACEN CryptoMaster
9 *
10 * This file implements the DMA and wrap logic of the cryptomaster
11 * Each cryptomaster engine is implemented in its own file
12 *
13 * Notes:
14 * * [Note1] Writing to PUSH_ADDR_MSB or FETCH_ADDR_MSB has no effect
15 *
16 * * [Note2] The DMA does not model the interrupt back-preasure mechanism described in the spec.
17 * Meaning, it will not hold fetching the next descriptor and updating the addr registers if
18 * the corresponding end of block interrupt status bit is high.
19 *
20 * * [Note3] This model assumes the CONFIG.software reset bit is not self clearing though this is not clear from the spec.
21 * STATUS.SoftRst_busy is never set.
22 *
23 * * [Note4] The fetcher and pusher DMAs are instantaneous and transfer instantaneously to/from the crypto engines
24 * as soon as the data can be feed to/is provided by the crypto engine.
25 * * [Note4b] For the fetcher
26 * This model fetcher always feeds the crypto engines in full fetcher blocks/one descriptor at a time,
27 * so, for data, they better match the cryptoengines processing size
28 * Data is read and fed in one go, so:
29 * STATUS.{Not empty flag from input FIFO (fetcher)} is never set
30 * STATUS.{Number of data in output FIFO} is also not changed (just 0).
31 *
32 * STATUS.{Fetch busy} is set if the cryptoengine applies back pressure while processing data.
33 * * [Note4c] For the pusher:
34 * STATUS.{Pusher busy} and {Pusher Waiting FIFO} are set until the engine has provided enough data.
35 *
36 * * [Note7] The descriptors {Constant address}, and Realign, bits are ignored/not supported.
37 * (Realign is not needed as effectively all accesses in the model are properly "aligned"
38 * independently of the size of the previous access)
39 *
40 * * [Note8]: Only the AES crypto engine, and bypass, are implemented at this point
41 *
42 * * [Note9]: Error interrupts (in both fetcher and pusher) are not generated
43 *
44 * * [Note10]: From the spec there is many opens about how the pusher would handle descriptors which are
45 * shorter or longer than the data produced by the engines, or several blocks. The model just copies data
46 * until there is no more left configured in the pusher at which points it raises the Stopped interrupt.
47 * So the amount of produced data better match the pusher configuration.
48 *
49 * * [Note11]: During pushes, the model just ignores the tag.
50 *
51 */
52
53 #include <stdint.h>
54 #include <stdbool.h>
55 #include <string.h>
56 #include "NHW_common_types.h"
57 #include "NHW_config.h"
58 #include "NHW_peri_types.h"
59 #include "NHW_templates.h"
60 #include "NHW_CRACEN_CM.h"
61 #include "NHW_CRACEN_CM.AES.h"
62 #include "NHW_CRACEN_wrap.h"
63 #include "bs_tracing.h"
64
65 extern NRF_CRACEN_Type NRF_CRACEN_regs;
66 extern NRF_CRACENCORE_Type NRF_CRACENCORE_regs;
67
68 bs_time_t Timer_CRACEN_CM;
69 extern bs_time_t Timer_CRACEN_CM_AES;
70
71 static NRF_CRACENCORE_CRYPTMSTRDMA_Type volatile *CMDMA_regs;
72
73 struct CM_descr {
74 char *Address;
75 union {
76 uint32_t Stop:1;
77 void *Next;
78 };
79 struct {
80 uint32_t Length:28;
81 uint32_t CstAddr:1;
82 uint32_t Realign:1;
83 uint32_t Discard :1;
84 uint32_t IntEn :1;
85 };
86 struct CM_tag tag;
87 } __attribute__ ((packed));
88
89 struct fetcher_pusher_st {
90 bool processing;
91 struct CM_tag tag;
92 bool Discard;
93 bool Stop;
94 bool IntEn;
95 char *current_address;
96 size_t current_len;
97 struct CM_descr *next;
98 };
99
100 static struct fetcher_pusher_st CM_pusher_st;
101 static struct fetcher_pusher_st CM_fetcher_st;
102
103 enum NRF_CRACENCORE_CMDMA_Int_t {
104 Fetch_EndBlock_int = 1,
105 Fetch_Stopped_int = 2,
106 Fetch_Error_int = 4,
107 Push_EndBlock_int = 8,
108 Push_Stopped_int = 0x10,
109 Push_Error_int = 0x20,
110 };
111
112 static void nhw_CRACEN_CM_set_int(enum NRF_CRACENCORE_CMDMA_Int_t interrupt);
113 static void nhw_CRACEN_CM_load_pusher_descr(struct CM_descr *descr);
114 static void nhw_CRACEN_CM_load_fetcher_descr(struct CM_descr *descr);
115
nhw_CRACEN_CM_soft_reset(void)116 static void nhw_CRACEN_CM_soft_reset(void) {
117 memset(&CM_pusher_st, 0, sizeof(CM_pusher_st));
118 memset(&CM_fetcher_st, 0, sizeof(CM_fetcher_st));
119 CMDMA_regs->STATUS = 0;
120 }
121
nhw_CRACEN_CM_init(void)122 void nhw_CRACEN_CM_init(void) {
123
124 CMDMA_regs = &NRF_CRACENCORE_regs.CRYPTMSTRDMA;
125
126 NRF_CRACENCORE_CRYPTMSTRHW_Type volatile *HWconf_regs;
127
128 HWconf_regs = &NRF_CRACENCORE_regs.CRYPTMSTRHW;
129 HWconf_regs->INCLIPSHWCFG = CRACENCORE_CRYPTMSTRHW_INCLIPSHWCFG_ResetValue;
130 HWconf_regs->BA411EAESHWCFG1 = CRACENCORE_CRYPTMSTRHW_BA411EAESHWCFG1_ResetValue;
131 HWconf_regs->BA411EAESHWCFG2 = CRACENCORE_CRYPTMSTRHW_BA411EAESHWCFG2_ResetValue;
132 HWconf_regs->BA413HASHHWCFG = CRACENCORE_CRYPTMSTRHW_BA413HASHHWCFG_ResetValue;
133 HWconf_regs->BA418SHA3HWCFG = CRACENCORE_CRYPTMSTRHW_BA418SHA3HWCFG_ResetValue;
134 HWconf_regs->BA419SM4HWCFG = CRACENCORE_CRYPTMSTRHW_BA419SM4HWCFG_ResetValue;
135 HWconf_regs->BA424ARIAHWCFG = CRACENCORE_CRYPTMSTRHW_BA424ARIAHWCFG_ResetValue;
136
137 Timer_CRACEN_CM = TIME_NEVER;
138
139 nhw_CRACEN_CM_soft_reset();
140 nhw_CRACEN_CM_AES_init();
141 }
142
nhw_CRACEN_CM_eval_interrupt(uint inst)143 static void nhw_CRACEN_CM_eval_interrupt(uint inst) {
144 (void) inst;
145
146 static bool int_level = false;
147
148 CMDMA_regs->INTSTAT = CMDMA_regs->INTSTATRAW & CMDMA_regs->INTEN;
149
150 bool new_int_level = (CMDMA_regs->INTSTAT != 0);
151
152 if (new_int_level != int_level) {
153 int_level = new_int_level;
154 nhw_CRACEN_toggle_CRYPTOMASTER_intline(int_level);
155 }
156 }
157
158 /*
159 * Interface for the cryptoengine to provide output data to the Cryptomaster pusher
160 */
nhw_CRACEN_CM_give_pusher_data(char * data,size_t len)161 void nhw_CRACEN_CM_give_pusher_data(char *data, size_t len) {
162 if (CM_pusher_st.processing == 0) {
163 bs_trace_warning_time_line("A CM engine provided data but the pusher was not expecting it => discarded\n");
164 return;
165 }
166
167 while (len > 0) {
168 unsigned int to_copy = BS_MIN(len, CM_pusher_st.current_len);
169
170 if (!CM_pusher_st.Discard) {
171 memcpy(CM_pusher_st.current_address, data, to_copy);
172 }
173 len -= to_copy;
174 data += to_copy;
175 CM_pusher_st.current_len -= to_copy;
176 CM_pusher_st.current_address += to_copy;
177
178 if (CM_pusher_st.current_len == 0) { //End of pusher block
179 if (CM_pusher_st.IntEn) {
180 nhw_CRACEN_CM_set_int(Push_EndBlock_int);
181 }
182 if (CM_pusher_st.Stop) { //No more blocks
183 nhw_CRACEN_CM_set_int(Push_Stopped_int);
184 CM_pusher_st.processing = false;
185 CMDMA_regs->STATUS &= ~(CRACENCORE_CRYPTMSTRDMA_STATUS_PUSHBUSY_Msk
186 | CRACENCORE_CRYPTMSTRDMA_STATUS_PUSHWAITINGFIFO_Msk);
187 break;
188 } else {
189 nhw_CRACEN_CM_load_pusher_descr(CM_pusher_st.next);
190 }
191 }
192 }
193 if (len > 0) {
194 bs_trace_warning_time_line("Crypto engine provided more data than pusher configuration had space for\n");
195 }
196 }
197
nhw_CRACEN_CM_fetcher_demux(struct CM_tag * tag,char * buf,size_t len)198 static bool nhw_CRACEN_CM_fetcher_demux(struct CM_tag *tag, char* buf, size_t len) {
199
200 if ((len != 0) && (buf == NULL)) {
201 bs_trace_error_time_line("Attempting to access NULL buffer\n");
202 }
203 switch (tag->EngineSelect) {
204 case 0x0: //Bypass
205 nhw_CRACEN_CM_give_pusher_data(buf, len);
206 return false;
207 break;
208 case 0x1:
209 return nhw_CRACEN_CM_AES_feed_data(tag, buf, len);
210 break;
211 default:
212 bs_trace_error_time_line("Engine %i not yet supported\n", tag->EngineSelect);
213 break;
214 }
215 return true;
216 }
217
218 /*
219 * Interface for the cryptoengines to request new data/indicate that is ready for more data
220 * from the cryptomaster fetcher
221 */
nhw_CRACEN_CM_fetcher_feed(void)222 void nhw_CRACEN_CM_fetcher_feed(void) {
223 bool hold = false;
224
225 while ((CM_fetcher_st.processing == true) && (hold == false)) {
226
227 hold = nhw_CRACEN_CM_fetcher_demux(&CM_fetcher_st.tag, CM_fetcher_st.current_address, CM_fetcher_st.current_len);
228
229 if (CM_fetcher_st.IntEn) {
230 nhw_CRACEN_CM_set_int(Fetch_EndBlock_int);
231 }
232 if (CM_fetcher_st.Stop) {
233 nhw_CRACEN_CM_set_int(Fetch_Stopped_int);
234 CM_fetcher_st.processing = false;
235 CMDMA_regs->STATUS &= ~CRACENCORE_CRYPTMSTRDMA_STATUS_FETCHBUSY_Msk;
236 break;
237 } else {
238 nhw_CRACEN_CM_load_fetcher_descr(CM_fetcher_st.next);
239 }
240 }
241 }
242
nhw_CRACEN_CM_load_descr(struct fetcher_pusher_st * st,struct CM_descr * descr)243 static void nhw_CRACEN_CM_load_descr(struct fetcher_pusher_st *st, struct CM_descr *descr) {
244 if (descr == NULL) {
245 bs_trace_error_time_line("Descriptor in address 0\n");
246 }
247 st->tag = descr->tag;
248 st->Discard = descr->Discard;
249 st->current_len = descr->Length;
250 st->current_address = descr->Address;
251 st->Stop = descr->Stop;
252 st->IntEn = descr->IntEn;
253 st->next = (struct CM_descr *)((uintptr_t)descr->Next & ~0x3);
254 }
255
nhw_CRACEN_CM_load_pusher_descr(struct CM_descr * descr)256 static void nhw_CRACEN_CM_load_pusher_descr(struct CM_descr *descr) {
257 nhw_CRACEN_CM_load_descr(&CM_pusher_st, descr);
258
259 CMDMA_regs->PUSHADDRLSB = (uintptr_t)descr;
260 CMDMA_regs->PUSHADDRMSB = (uintptr_t)descr;
261 }
262
nhw_CRACEN_CM_load_fetcher_descr(struct CM_descr * descr)263 static void nhw_CRACEN_CM_load_fetcher_descr(struct CM_descr *descr) {
264 nhw_CRACEN_CM_load_descr(&CM_fetcher_st, descr);
265
266 CMDMA_regs->FETCHADDRLSB = (uintptr_t)descr;
267 CMDMA_regs->FETCHADDRMSB = (uintptr_t)descr;
268 }
269
nhw_CRACEN_CM_start(int start)270 static void nhw_CRACEN_CM_start(int start) {
271 if (start & 0x2) { //Pusher start
272 CM_pusher_st.processing = true;
273 if ((CMDMA_regs->CONFIG & CRACENCORE_CRYPTMSTRDMA_CONFIG_PUSHCTRLINDIRECT_Msk) == 0) { //Direct mode
274 CM_pusher_st.Discard = (CMDMA_regs->PUSHLEN >> CRACENCORE_CRYPTMSTRDMA_PUSHLEN_PUSHDISCARD_Pos) & 0x1;
275 CM_pusher_st.current_len = CMDMA_regs->PUSHLEN & CRACENCORE_CRYPTMSTRDMA_PUSHLEN_PUSHLEN_Msk;
276 CM_pusher_st.current_address = (char *)CMDMA_regs->PUSHADDRLSB;
277 CM_pusher_st.Stop = true;
278 CM_pusher_st.IntEn = false;
279 CM_pusher_st.next = NULL;
280 memset(&CM_pusher_st.tag, 0 , sizeof(CM_pusher_st.tag));
281 } else { //Scatter mode
282 nhw_CRACEN_CM_load_pusher_descr((struct CM_descr *)CMDMA_regs->PUSHADDRLSB);
283 }
284 CMDMA_regs->STATUS |= CRACENCORE_CRYPTMSTRDMA_STATUS_PUSHBUSY_Msk
285 | CRACENCORE_CRYPTMSTRDMA_STATUS_PUSHWAITINGFIFO_Msk;
286
287 }
288 if (start & 0x1) { //Fetcher start
289 CM_fetcher_st.processing = true;
290 if ((CMDMA_regs->CONFIG & CRACENCORE_CRYPTMSTRDMA_CONFIG_FETCHCTRLINDIRECT_Msk) == 0) { //Direct mode
291 CM_fetcher_st.Discard = (CMDMA_regs->FETCHLEN >> CRACENCORE_CRYPTMSTRDMA_PUSHLEN_PUSHDISCARD_Pos) & 0x1;
292 CM_fetcher_st.current_len = CMDMA_regs->FETCHLEN & CRACENCORE_CRYPTMSTRDMA_FETCHLEN_FETCHLEN_Msk;
293 CM_fetcher_st.current_address = (char *)CMDMA_regs->FETCHADDRLSB;
294 CM_fetcher_st.Stop = true;
295 CM_fetcher_st.IntEn = false;
296 CM_fetcher_st.next = NULL;
297 memcpy(&CM_fetcher_st.tag, (char *)&CMDMA_regs->FETCHTAG , sizeof(uint32_t));
298 } else {
299 nhw_CRACEN_CM_load_fetcher_descr((struct CM_descr *)CMDMA_regs->FETCHADDRLSB);
300 }
301 CMDMA_regs->STATUS |= CRACENCORE_CRYPTMSTRDMA_STATUS_FETCHBUSY_Msk;
302 nhw_CRACEN_CM_fetcher_feed();
303 }
304 }
305
nhw_CRACEN_CM_regw_sideeffects_CONFIG(void)306 void nhw_CRACEN_CM_regw_sideeffects_CONFIG(void) {
307 if (CMDMA_regs->CONFIG & CRACENCORE_CRYPTMSTRDMA_CONFIG_SOFTRST_Msk) {
308 nhw_CRACEN_CM_soft_reset();
309 nhw_CRACEN_CM_AES_hard_stop();
310 }
311 if (CMDMA_regs->CONFIG & CRACENCORE_CRYPTMSTRDMA_CONFIG_PUSHSTOP_Msk) {
312 CM_pusher_st.Stop = 1;
313 }
314 if (CMDMA_regs->CONFIG & CRACENCORE_CRYPTMSTRDMA_CONFIG_FETCHSTOP_Msk) {
315 CM_fetcher_st.Stop = 1;
316 }
317 }
318
nhw_CRACEN_CM_regw_sideeffects_START(void)319 void nhw_CRACEN_CM_regw_sideeffects_START(void) {
320 if (CMDMA_regs->START) {
321 if ((NRF_CRACEN_regs.ENABLE & CRACEN_ENABLE_CRYPTOMASTER_Msk) == 0) {
322 bs_trace_warning_time_line("Attempting to enable CRACEN Cryptomaster while the CRACEN wrap logic is off\n");
323 }
324
325 nhw_CRACEN_CM_start(CMDMA_regs->START);
326 CMDMA_regs->START = 0;
327 }
328 }
329
nhw_CRACEN_CM_regw_sideeffects_INTSTARTCLR(uint inst)330 void nhw_CRACEN_CM_regw_sideeffects_INTSTARTCLR(uint inst) {
331 if (CMDMA_regs->INTSTATCLR) {
332 CMDMA_regs->INTSTATRAW &= ~CMDMA_regs->INTSTATCLR;
333 CMDMA_regs->INTSTATCLR = 0;
334 nhw_CRACEN_CM_eval_interrupt(inst);
335 }
336 }
337
338 NHW_SIDEEFFECTS_INTEN(CRACEN_CM, CMDMA_regs->, CMDMA_regs->INTEN)
339 NHW_SIDEEFFECTS_INTSET(CRACEN_CM, CMDMA_regs->, CMDMA_regs->INTEN)
340 NHW_SIDEEFFECTS_INTCLR(CRACEN_CM, CMDMA_regs->, CMDMA_regs->INTEN)
341
nhw_CRACEN_CM_set_int(enum NRF_CRACENCORE_CMDMA_Int_t interrupt)342 static void nhw_CRACEN_CM_set_int(enum NRF_CRACENCORE_CMDMA_Int_t interrupt) {
343 CMDMA_regs->INTSTATRAW |= interrupt;
344 nhw_CRACEN_CM_eval_interrupt(0);
345 }
346
nhw_CRACEN_CM_update_timer(void)347 void nhw_CRACEN_CM_update_timer(void) {
348 if (Timer_CRACEN_CM_AES != Timer_CRACEN_CM) {
349 Timer_CRACEN_CM = Timer_CRACEN_CM_AES;
350 nhw_CRACEN_update_timer();
351 }
352 }
353
nhw_CRACEN_CM_timer_triggered(void)354 void nhw_CRACEN_CM_timer_triggered(void) {
355 if (Timer_CRACEN_CM == Timer_CRACEN_CM_AES) {
356 nhw_CRACEN_CM_AES_timer_triggered();
357 }
358 }
359