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