1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * AAR - Accelerated address resolver
9  * ECB - AES electronic codebook mode encryption
10  * CCM - AES CCM mode encryption
11  *
12  * Notes:
13  *  * [AAR1][CCM1] The AAR and CCM peripherals share register addressing, but the layout is not
14  *    coherent between both.
15  *    For the spec, it is quite unclear how the event and interrupt logic is glued/shared.
16  *    (Note that, for ex., END and ERROR do not match in the INTEN bit, and have different, overlapping,
17  *     PUBLISH registers in AAR and CCM mode. Therefore, for ex., there can't be just a single
18  *     signal for both END events from the RTL logic towards the event/interrupt generation)
19  *    In real HW, it is understood that if INTEN or PUBLISH_* is left with a configuration and the other
20  *    mode is enabled spurious interrupts/events can be generated.
21  *
22  *    The model keeps a common register set, but separate interrupt and event logic.
23  *    The spec tells that SW should ensure the configuration is cleared in one side before using
24  *    the other. So SW which does this should not see a difference.
25  *
26  *  * [AAR2]: In real HW a TASK_START being triggered while the AAR is already running does nothing.
27  *    The model will also do nothing but warn.
28  *
29  *  * [AAR3][CCM3]: For the AAR & CCM peripherals, if ENABLE is changed while either is operating things
30  *    will fail badly in real HW. The model will warn about this.
31  *
32  *  * [AAR4]: For EVENTS_ERROR, the spec says "Operation aborted because of a STOP task or due to an error"
33  *    Although it may appear that a STOP will always cause the EVENT, even if the block was not running,
34  *    the HW only generates it if it was running.
35  *    The model does also only generate an EVENTS_ERROR if the block was indeed running and stopped with a STOP task.
36  *
37  *  * [ECB1]: How long t_ECB is, is just a guess at this point (1 micros)
38  *
39  *  * [ECB2]: About TASK_START the spec states that
40  *    "If a crypto operation is already running in the AES core, the START task will
41  *    not start a new encryption and an ERROR event will be triggered"
42  *    Although from that it is unclear if ERRORSTATUS is changed though, it seems the HW
43  *    will set ERRORSTATUS to aborted in any case.
44  *    The model sets ERRORSTATUS to 3(Aborted) as the HW does.
45  *
46  *  * [ECB3]: About TASK_STOP: The spec states:
47  *    "If a running ECB operation is aborted by STOP, the ERROR event is triggered."
48  *    Although from that it is unclear if ERRORSTATUS is changed, the HW does set it to Aborted.
49  *    The model does this also.
50  *    And similarly to [AAR4], the event ERROR EVENT is generated only if the block was indeed running and stopped with a STOP task.
51  *
52  *  * [ECB4]: Even that the spec says "A premature end of the input job list is padded to 16 bytes with zeros."
53  *    It is actually not ok to do that an an error event is generated in real HW and the model.
54  *
55  *  * [CCM1]: The CCM model (unlike the real HW) is instantaneous.
56  *    During encryption the RADIO model needs the whole packet at the preamble start,
57  *    so we cannot have the model be "as slow" as the real HW.
58  *    During decryption the HW is always running in Fast mode, so being a bit faster
59  *    in the model should ideally not matter
60  *
61  *  * [CCM3]: TASK_RATEOVERRIDE & RATEOVERRIDE & DATARATE do not have any real function (see CCM1)
62  *  * [CCM3b]: ERRORSTATUS EncryptionTooSlow cannot happen
63  *
64  *  * [CCM4]: Unlike the 52/53 models, the decryption is triggered by the START task, and not
65  *    by the radio models (The decryption is meant to be started by the radio PAYLOAD EVENT,
66  *    and run fast, unlike in the 52/3 where it was meant to run slowly as the bytes were
67  *    received)
68  *
69  *  * [CCM5]: At this point only BLE protocol is supported
70  *    (and therefore an AAD length/l_a of 1 byte, and MIC length of 4 bytes)
71  *
72  *  * [CCM6]: It is unclear if for the real HW, during decryption, when l_c < MACLEN (or < 5 for BLE)
73  *    if apart from an ERROR event being generated something else happens (for ex. if ERRORSTATUS
74  *    is changed)
75  *
76  */
77 
78 #include <string.h>
79 #include <stdbool.h>
80 #include <stdint.h>
81 #include "bs_types.h"
82 #include "NHW_config.h"
83 #include "NHW_templates.h"
84 #include "NHW_peri_types.h"
85 #include "NHW_54_AAR_CCM_ECB.h"
86 #include "NHW_DPPI.h"
87 #include "NHW_EVDMA.h"
88 #include "HW_utils.h"
89 #include "nsi_hw_scheduler.h"
90 #include "irq_ctrl.h"
91 #include "bs_tracing.h"
92 #include "BLECrypt_if.h"
93 #include "nsi_tasks.h"
94 #include "nsi_hws_models_if.h"
95 
96 static bs_time_t Timer_AAR_CCM_ECB = TIME_NEVER;
97 
98 union NRF_AARCCM_Type NRF_AARCCM_regs[NHW_AARCCMECB_TOTAL_INST];
99 
100 NRF_AAR_Type *NRF_AAR_regs[NHW_AARCCMECB_TOTAL_INST];
101 NRF_CCM_Type *NRF_CCM_regs[NHW_AARCCMECB_TOTAL_INST];
102 NRF_ECB_Type NRF_ECB_regs[NHW_AARCCMECB_TOTAL_INST];
103 
104 struct aar_status {
105   NRF_AAR_Type *NRF_AAR_regs;
106   uint32_t INTEN;
107 
108   bool Running;
109   bs_time_t Timer;
110   uint clockMHz;
111 };
112 struct ccm_status {
113   NRF_CCM_Type *NRF_CCM_regs;
114   uint32_t INTEN;
115   bool Running;
116 };
117 struct ecb_status {
118   NRF_ECB_Type *NRF_ECB_regs;
119   uint32_t INTEN;
120   bool Running;
121   bs_time_t Timer;
122   uint t_ECB;
123 };
124 
125 static struct aar_status nhw_aar_st[NHW_AARCCMECB_TOTAL_INST];
126 static struct ccm_status nhw_ccm_st[NHW_AARCCMECB_TOTAL_INST];
127 static struct ecb_status nhw_ecb_st[NHW_AARCCMECB_TOTAL_INST];
128 /* Mapping of peripheral instance to DPPI instance */
129 #define nhw_AAR_dppi_map nhw_AARCCMECB_dppi_map
130 #define nhw_CCM_dppi_map nhw_AARCCMECB_dppi_map
131 #define nhw_ECB_dppi_map nhw_AARCCMECB_dppi_map
132 static uint nhw_AARCCMECB_dppi_map[NHW_AARCCMECB_TOTAL_INST] = NHW_AARCCMECB_DPPI_MAP;
133 
134 void nhw_aes_ecb_cheat_reset_t_ecb(void);
135 static bool nhw_ECB_possible_abort(uint inst);
136 static void nhw_AAR_TASK_START(uint inst);
137 static void nhw_AAR_TASK_STOP(uint inst);
138 static void nhw_CCM_TASK_START(uint inst);
139 static void nhw_CCM_TASK_STOP(uint inst);
140 
nhw_AARCCMECB_init(void)141 static void nhw_AARCCMECB_init(void) {
142   memset(&NRF_AARCCM_regs, 0, sizeof(NRF_AARCCM_regs));
143   memset(&NRF_ECB_regs, 0, sizeof(NRF_ECB_regs));
144   uint clockMHz[NHW_AARCCMECB_TOTAL_INST] = NHW_AARCCMECB_CLOCK;
145 
146   for (int i = 0; i < NHW_AARCCMECB_TOTAL_INST; i++) {
147     NRF_AAR_regs[i] = (NRF_AAR_Type *)&NRF_AARCCM_regs[i];
148     NRF_CCM_regs[i] = (NRF_CCM_Type *)&NRF_AARCCM_regs[i];
149 
150     NRF_AAR_regs[i]->MAXRESOLVED = AAR_MAXRESOLVED_ResetValue;
151 
152     NRF_CCM_regs[i]->MODE = CCM_MODE_ResetValue;
153     NRF_CCM_regs[i]->RATEOVERRIDE = CCM_RATEOVERRIDE_ResetValue;
154     NRF_CCM_regs[i]->ADATAMASK = CCM_ADATAMASK_ResetValue;
155 
156     nhw_aar_st[i].NRF_AAR_regs = NRF_AAR_regs[i];
157     nhw_aar_st[i].INTEN = 0;
158     nhw_aar_st[i].Timer = TIME_NEVER;
159     nhw_aar_st[i].Running = false;
160     nhw_aar_st[i].clockMHz = clockMHz[i];
161 
162     nhw_ccm_st[i].NRF_CCM_regs = NRF_CCM_regs[i];
163     nhw_ccm_st[i].INTEN = 0;
164     nhw_ccm_st[i].Running = false;
165 
166     nhw_ecb_st[i].NRF_ECB_regs = &NRF_ECB_regs[i];
167     nhw_ecb_st[i].INTEN = 0;
168     nhw_ecb_st[i].Running = false;
169   }
170   nhw_aes_ecb_cheat_reset_t_ecb();
171   Timer_AAR_CCM_ECB = TIME_NEVER;
172 }
173 
174 NSI_TASK(nhw_AARCCMECB_init, HW_INIT, 100);
175 
update_master_timer(void)176 static void update_master_timer(void) {
177   Timer_AAR_CCM_ECB = TIME_NEVER;
178   for (int i = 0; i < NHW_AARCCMECB_TOTAL_INST; i++) {
179     if (nhw_aar_st[i].Running) {
180       if (nhw_aar_st[i].Timer < Timer_AAR_CCM_ECB) {
181         Timer_AAR_CCM_ECB = nhw_aar_st[i].Timer;
182       }
183     }
184     if (nhw_ecb_st[i].Running) {
185       if (nhw_ecb_st[i].Timer < Timer_AAR_CCM_ECB) {
186         Timer_AAR_CCM_ECB = nhw_ecb_st[i].Timer;
187       }
188     }
189   }
190   nsi_hws_find_next_event();
191 }
192 
193 static bool aarccm_int_line[NHW_AARCCMECB_TOTAL_INST]; /* Is the AAR/CCM currently driving its interrupt line high */
194 static struct nhw_irq_mapping nhw_aarccm_irq_map[NHW_AARCCMECB_TOTAL_INST] = NHW_AARCCM_INTMAP;
195 
nhw_AAR_eval_interrupt(uint inst)196 static void nhw_AAR_eval_interrupt(uint inst) {
197   bool new_int_line = false;
198 
199   uint32_t INTEN = nhw_aar_st[inst].INTEN;
200 
201   //Side note: Bit mapping in the INTEN register differs depending on mode
202   if (NRF_AAR_regs[inst]->ENABLE == AAR_ENABLE_ENABLE_Enabled) {
203     NHW_CHECK_INTERRUPT(AAR, NRF_AAR_regs[inst]->, END,         INTEN)
204     NHW_CHECK_INTERRUPT(AAR, NRF_AAR_regs[inst]->, RESOLVED,    INTEN)
205     NHW_CHECK_INTERRUPT(AAR, NRF_AAR_regs[inst]->, NOTRESOLVED, INTEN)
206     NHW_CHECK_INTERRUPT(AAR, NRF_AAR_regs[inst]->, ERROR,       INTEN)
207   } else {
208     bs_trace_info_time_line(3,"%s called with AAR not enabled (%i)\n", __func__, NRF_AAR_regs[inst]->ENABLE);
209   }
210 
211   hw_irq_ctrl_toggle_level_irq_line_if(&aarccm_int_line[inst],
212                                        new_int_line,
213                                        &nhw_aarccm_irq_map[inst]);
214 }
215 
nhw_CCM_eval_interrupt(uint inst)216 static void nhw_CCM_eval_interrupt(uint inst) {
217   bool new_int_line = false;
218 
219   uint32_t INTEN = nhw_ccm_st[inst].INTEN;
220 
221   if (NRF_CCM_regs[inst]->ENABLE == CCM_ENABLE_ENABLE_Enabled) {
222     NHW_CHECK_INTERRUPT(CCM, NRF_CCM_regs[inst]->, END,   INTEN)
223     NHW_CHECK_INTERRUPT(CCM, NRF_CCM_regs[inst]->, ERROR, INTEN)
224   } else {
225     bs_trace_info_time_line(3,"%s called with CCM not enabled (%i)\n", __func__, NRF_CCM_regs[inst]->ENABLE);
226   }
227 
228   hw_irq_ctrl_toggle_level_irq_line_if(&aarccm_int_line[inst],
229                                        new_int_line,
230                                        &nhw_aarccm_irq_map[inst]);
231 }
232 
nhw_ECB_eval_interrupt(uint inst)233 static void nhw_ECB_eval_interrupt(uint inst) {
234   static struct nhw_irq_mapping nhw_ecb_irq_map[NHW_AARCCMECB_TOTAL_INST] = NHW_ECB_INTMAP;
235   static bool ecb_int_line[NHW_AARCCMECB_TOTAL_INST]; /* Is the ECB currently driving its interrupt line high */
236   bool new_int_line = false;
237 
238   uint32_t INTEN = nhw_ecb_st[inst].INTEN;
239 
240   NHW_CHECK_INTERRUPT(ECB, NRF_ECB_regs[inst]., END,   INTEN)
241   NHW_CHECK_INTERRUPT(ECB, NRF_ECB_regs[inst]., ERROR, INTEN)
242 
243   hw_irq_ctrl_toggle_level_irq_line_if(&ecb_int_line[inst],
244                                        new_int_line,
245                                        &nhw_ecb_irq_map[inst]);
246 }
247 
248 
249 #define NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE_WRAP(TASK_N, PERI)                  \
250   static void nhw_##PERI##_task##TASK_N##_wrap(void* param)                         \
251   {                                                                                 \
252     nhw_##PERI##_TASK_##TASK_N((int) param);                                        \
253   }
254 
255 #define NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N, PERI, peri)                 \
256   void nhw_##PERI##_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst)                  \
257   {                                                                                 \
258      struct peri##_status *st = &nhw_##peri##_st[inst];                             \
259      static struct nhw_subsc_mem task##_subscribed[NHW_AARCCMECB_TOTAL_INST];       \
260                                                                                     \
261      nhw_dppi_common_subscribe_sideeffect(nhw_AARCCMECB_dppi_map[inst],             \
262                                           st->NRF_##PERI##_regs->SUBSCRIBE_##TASK_N,\
263                                           &task##_subscribed[inst],                 \
264                                           nhw_##PERI##_task##TASK_N##_wrap,         \
265                                           (void*) inst);                            \
266   }
267 
268 
269 static NHW_SIGNAL_EVENT(AAR, NRF_AAR_regs[inst]->, END)
270 static NHW_SIGNAL_EVENT(AAR, NRF_AAR_regs[inst]->, RESOLVED)
271 static NHW_SIGNAL_EVENT(AAR, NRF_AAR_regs[inst]->, NOTRESOLVED)
272 static NHW_SIGNAL_EVENT(AAR, NRF_AAR_regs[inst]->, ERROR)
273 
nhw_AAR_stop(uint inst)274 static void nhw_AAR_stop(uint inst) {
275   struct aar_status *st = &nhw_aar_st[inst];
276   st->Running = false;
277   st->Timer = TIME_NEVER;
278   update_master_timer();
279 }
280 
nhw_AAR_resolve_logic(uint inst)281 static void nhw_AAR_resolve_logic(uint inst) {
282   NRF_AAR_regs[inst]->ERRORSTATUS = 0;
283   NRF_AAR_regs[inst]->OUT.AMOUNT = 0;
284 
285   EVDMA_status_t in_evdma, out_evdma;
286   int ret;
287   size_t n_access;
288   uint32_t hash = 0, prand = 0, hash_check;
289   uint8_t irk[16];
290   uint n_resolved = 0;
291   uint n_iter = 0;
292   uint8_t prand_buf[16], hash_check_buf[16];
293 
294 #define MAX_IRKS 4095
295 
296 #define IF_NOT_READ_ERROR(ret) \
297   if (ret < 0) { \
298     NRF_AAR_regs[inst]->ERRORSTATUS = AAR_ERRORSTATUS_ERRORSTATUS_PrematureInptrEnd; \
299     nhw_AAR_stop(inst); \
300     nhw_AAR_signal_EVENTS_ERROR(inst); \
301     return; \
302   }
303 
304   ret = nhw_EVDMA_start(&in_evdma, (void *)NRF_AAR_regs[inst]->IN.PTR);
305   if (ret) {
306     bs_trace_error_time_line("AAR IN.PTR is NULL during start, that would have hard faulted\n");
307   }
308   ret = nhw_EVDMA_start(&out_evdma, (void *)NRF_AAR_regs[inst]->OUT.PTR);
309   if (ret) {
310     bs_trace_error_time_line("AAR OUT.PTR is NULL, that would have hard faulted\n");
311   }
312 
313   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
314                          (uint8_t *)&hash, 3,
315                          &n_access, NHW_EVDMA_NEWJOB);
316   IF_NOT_READ_ERROR(ret);
317 
318   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
319                          (uint8_t *)&prand, 3,
320                          &n_access, NHW_EVDMA_NEWJOB);
321   IF_NOT_READ_ERROR(ret);
322 
323   bs_trace_raw_time(9,"HW AAR address from packet to match %02x:%02x:%02x:%02x:%02x:%02x\n",
324       (prand >> 16), (prand >> 8) & 0xFF, prand & 0xFF,
325       (hash >> 16), (hash >> 8) & 0xFF, hash & 0xFF);
326 
327   if (prand >> 22 != 0x01) {
328     /* Not a resolvable private address */
329     bs_trace_raw_time(7,"HW AAR the address is not resolvable we proceed anyhow (0x%06X , %x)\n", prand, prand >> 22);
330   }
331 
332   memset(prand_buf,0,16);
333   /* Endiannes reversal to bigendian */
334   prand_buf[15] = prand & 0xFF;
335   prand_buf[14] = (prand >> 8) & 0xFF;
336   prand_buf[13] = (prand >> 16) & 0xFF;
337 
338   while ((n_resolved < NRF_AAR_regs[inst]->MAXRESOLVED) && (n_iter <= MAX_IRKS)) {
339     ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
340                            irk, 16,
341                            &n_access, (n_iter == 0)?NHW_EVDMA_NEWJOB:NHW_EVDMA_CONTINUEJOB);
342     if (ret == -2) { //End of job list => End of IRK list
343       break;
344     }
345     else IF_NOT_READ_ERROR(ret);
346 
347     /* this aes_128 function takes and produces big endian results */
348     BLECrypt_if_aes_128((const uint8_t *)&irk, prand_buf, hash_check_buf);
349 
350     /* Endianess reversal to little endian */
351     hash_check = hash_check_buf[15] | (uint32_t)hash_check_buf[14] << 8 | (uint32_t)hash_check_buf[13] << 16;
352 
353     bs_trace_raw_time(9, "HW AAR (%i): checking prand = 0x%06X, hash = 0x%06X, hashcheck = 0x%06X\n",
354                       n_iter, prand, hash, hash_check);
355 
356     if (hash == hash_check) {
357       bs_trace_raw_time(7, "HW AAR matched irk %i\n", n_iter);
358       n_resolved++;
359       NRF_AAR_regs[inst]->OUT.AMOUNT = 2*n_resolved;
360       ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
361                              (uint8_t *)&n_iter, 2,
362                              &n_access, NHW_EVDMA_CONTINUEJOB);
363       if (ret < 0) {
364         NRF_AAR_regs[inst]->ERRORSTATUS = 0x2; //AAR_ERRORSTATUS_ERRORSTATUS_PrematureOutptrEnd;
365         nhw_AAR_stop(inst);
366         nhw_AAR_signal_EVENTS_ERROR(inst);
367         return;
368       }
369     }
370     n_iter++;
371   }
372 #undef IF_NOT_READ_ERROR
373 
374   //Very rough approximation of duration ceil( (20 + (8 + 20)*n_iter + 11*N_matches cc)/Clock_in_MHz ) micros
375   uint clockMHz = nhw_aar_st[inst].clockMHz;
376   bs_time_t t_duration = (20 + (8 + 20)*n_iter + 11*n_resolved + clockMHz - 1)/clockMHz;
377 
378   nhw_aar_st[inst].Timer = nsi_hws_get_time() + t_duration;
379   update_master_timer();
380 }
381 
nhw_AAR_TASK_START_inner(uint inst)382 static void nhw_AAR_TASK_START_inner(uint inst) {
383   if (nhw_aar_st[inst].Running) {
384     bs_trace_warning_time_line("%s called while AAR was already Running enabled => ignored\n", __func__);
385     //Note [AAR2]
386     return;
387   }
388   nhw_ECB_possible_abort(inst);
389 
390   nhw_aar_st[inst].Running = true;
391   nhw_AAR_resolve_logic(inst);
392 }
393 
nhw_AAR_TASK_STOP_inner(uint inst)394 static void nhw_AAR_TASK_STOP_inner(uint inst) {
395   int was_running = nhw_aar_st[inst].Running;
396   nhw_AAR_stop(inst);
397   //Note [AAR4]
398   if (was_running) {
399     nhw_AAR_signal_EVENTS_ERROR(inst);
400   } else {
401     bs_trace_info_time_line(3, "%s called while AAR was not running\n", __func__);
402   }
403 }
404 
nhw_AARCCM_regw_sideeffects_ENABLE(unsigned int inst)405 void nhw_AARCCM_regw_sideeffects_ENABLE(unsigned int inst) {
406   //Note [AAR3][CCM3]
407   if ((nhw_aar_st[inst].Running) && (NRF_AAR_regs[inst]->ENABLE != AAR_ENABLE_ENABLE_Enabled)) {
408     bs_trace_warning_time_line("AAR/CCM%i ENABLE register modified while AAR was running\n", inst);
409   }
410   if ((nhw_ccm_st[inst].Running) && (NRF_AAR_regs[inst]->ENABLE != CCM_ENABLE_ENABLE_Enabled)) {
411     bs_trace_warning_time_line("AAR/CCM%i ENABLE register modified while CCM was running\n", inst);
412   }
413 }
414 
415 NHW_SIDEEFFECTS_INTSET(AAR, NRF_AAR_regs[inst]->, nhw_aar_st[inst].INTEN)
416 NHW_SIDEEFFECTS_INTCLR(AAR, NRF_AAR_regs[inst]->, nhw_aar_st[inst].INTEN)
417 
418 NHW_SIDEEFFECTS_TASKS(AAR, NRF_AAR_regs[inst]->, START)
419 NHW_SIDEEFFECTS_TASKS(AAR, NRF_AAR_regs[inst]->, STOP)
420 
421 #define NHW_AAR_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                   \
422   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE_WRAP(TASK_N, AAR)                         \
423   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N, AAR, aar)
424 
NHW_AAR_REGW_SIDEFFECTS_SUBSCRIBE(START)425 NHW_AAR_REGW_SIDEFFECTS_SUBSCRIBE(START)
426 NHW_AAR_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
427 
428 NHW_SIDEEFFECTS_EVENTS(AAR)
429 
430 static void nhw_AAR_timer_triggered(uint inst) {
431   nhw_AAR_stop(inst);
432 
433   if (NRF_AAR_regs[inst]->ENABLE != AAR_ENABLE_ENABLE_Enabled) {
434     bs_trace_warning_time_line("Programming error\n");
435   }
436 
437   if (NRF_AAR_regs[inst]->OUT.AMOUNT > 0) {
438     nhw_AAR_signal_EVENTS_RESOLVED(inst);
439   } else {
440     nhw_AAR_signal_EVENTS_NOTRESOLVED(inst);
441   }
442   nhw_AAR_signal_EVENTS_END(inst);
443 }
444 
445 /* CCM */
446 
447 NHW_SIDEEFFECTS_INTSET(CCM, NRF_CCM_regs[inst]->, nhw_ccm_st[inst].INTEN)
448 NHW_SIDEEFFECTS_INTCLR(CCM, NRF_CCM_regs[inst]->, nhw_ccm_st[inst].INTEN)
449 
450 static NHW_SIGNAL_EVENT(CCM, NRF_CCM_regs[inst]-> , END)
451 static NHW_SIGNAL_EVENT(CCM, NRF_CCM_regs[inst]-> , ERROR)
452 
nhw_CCM_MAC_size(uint inst)453 static int nhw_CCM_MAC_size(uint inst) {
454   switch ((NRF_CCM_regs[inst]->MODE & CCM_MODE_MACLEN_Msk) >> CCM_MODE_MACLEN_Pos) {
455   case CCM_MODE_MACLEN_M0: return 0;
456   case CCM_MODE_MACLEN_M4: return 4;
457   case CCM_MODE_MACLEN_M6: return 6;
458   case CCM_MODE_MACLEN_M8: return 8;
459   case CCM_MODE_MACLEN_M10: return 10;
460   case CCM_MODE_MACLEN_M12: return 12;
461   case CCM_MODE_MACLEN_M14: return 14;
462   case CCM_MODE_MACLEN_M16: return 16;
463   default:
464     bs_trace_error_time_line("Unsupported MAC size\n");
465     return 0;
466   }
467 }
468 
nhw_CCM_logic(uint inst)469 static void nhw_CCM_logic(uint inst) {
470   NRF_CCM_regs[inst]->ERRORSTATUS = 0;
471   NRF_CCM_regs[inst]->MACSTATUS = CCM_MACSTATUS_MACSTATUS_CheckFailed;
472 
473   uint8_t *ccm_nonce = (uint8_t*)NRF_CCM_regs[inst]->NONCE.VALUE;
474   uint8_t *key = (uint8_t*)NRF_CCM_regs[inst]->KEY.VALUE;
475   uint8_t ccm_nonce_swapped[13];
476   uint8_t key_be[16];
477   uint8_t ADATAMASK = NRF_CCM_regs[inst]->ADATAMASK;
478   uint mac_size = nhw_CCM_MAC_size(inst);
479   uint encrypt_not_decrypt = (NRF_CCM_regs[inst]->MODE & CCM_MODE_MODE_Msk) == CCM_MODE_MODE_Encryption;
480   uint protocol = (NRF_CCM_regs[inst]->MODE & CCM_MODE_PROTOCOL_Msk) >> CCM_MODE_PROTOCOL_Pos;
481                   //CCM_MODE_PROTOCOL_Ble or CCM_MODE_PROTOCOL_Ieee802154
482 
483   hwu_reverse_byte_order(key, key_be, sizeof(key_be));
484   hwu_reverse_byte_order(ccm_nonce, ccm_nonce_swapped, sizeof(ccm_nonce_swapped));
485 
486   EVDMA_status_t in_evdma, out_evdma;
487   int ret;
488   size_t n_access;
489   uint16_t l_a = 0;
490   uint16_t l_mc = 0;
491 
492 #define IF_NOT_READ_ERROR(ret) \
493   if (ret < 0) { \
494     NRF_CCM_regs[inst]->ERRORSTATUS = CCM_ERRORSTATUS_ERRORSTATUS_PrematureInptrEnd; \
495     nhw_CCM_signal_EVENTS_ERROR(inst); \
496     return; \
497   }
498 #define IF_NOT_WRITE_ERROR(ret) \
499   if (ret < 0) { \
500     NRF_CCM_regs[inst]->ERRORSTATUS = CCM_ERRORSTATUS_ERRORSTATUS_PrematureOutptrEnd; \
501     nhw_CCM_signal_EVENTS_ERROR(inst); \
502     return; \
503   }
504 
505   ret = nhw_EVDMA_start(&in_evdma, (void *)NRF_CCM_regs[inst]->IN.PTR);
506   if (ret) {
507     bs_trace_error_time_line("CCM IN.PTR is NULL during start, that would have hard faulted\n");
508   }
509   ret = nhw_EVDMA_start(&out_evdma, (void *)NRF_CCM_regs[inst]->OUT.PTR);
510   if (ret) {
511     bs_trace_error_time_line("CCM OUT.PTR is NULL during start, that would have hard faulted\n");
512   }
513 
514   //Read l_a, which must be 2 bytes always
515   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
516                          (uint8_t *)&l_a, 2,
517                          &n_access, NHW_EVDMA_NEWJOB);
518   IF_NOT_READ_ERROR(ret);
519   //Write l_a, which must be 2 bytes always
520   ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
521                          (uint8_t *)&l_a, 2,
522                          &n_access, NHW_EVDMA_NEWJOB);
523   IF_NOT_WRITE_ERROR(ret);
524 
525   //Read l_m/c, which must be 2 bytes always
526   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
527                          (uint8_t *)&l_mc, 2,
528                          &n_access, NHW_EVDMA_NEWJOB);
529   IF_NOT_READ_ERROR(ret);
530 
531   uint8_t a_in[l_a + 1];   /* We allocate these VLAs 1 byte larger than used to avoid them having size 0 in case the joblist configures a l_a or l_m as 0
532                             * A VLA with size 0 is in principle not C99 valid code and UBSAN complains about it
533                             * And for a_copy we unconditionally access byte 0, pressuming the joblist is not missconfigured */
534   uint8_t a_copy[l_a + 1];
535   uint8_t mc_in[l_mc + 1];
536   uint8_t mc_out[l_mc + BS_MAX(mac_size,4)]; //We just make place for the MAC/MIC even if this is decrypting.
537 
538   //Read "a" (AAD)
539   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
540                          a_in, l_a,
541                          &n_access, NHW_EVDMA_NEWJOB);
542   IF_NOT_READ_ERROR(ret);
543 
544   memcpy(a_copy, a_in, l_a);
545   a_copy[0] &= ADATAMASK;
546 
547   //Read "m" or "c" (the plaintext or encrypted PDU)
548   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
549                          mc_in, l_mc,
550                          &n_access, NHW_EVDMA_NEWJOB);
551   IF_NOT_READ_ERROR(ret);
552 
553   if (!( (l_a == 0 && l_mc == 0) ||
554           ((protocol == CCM_MODE_PROTOCOL_Ble) && (l_mc == 0))
555        ) ) //With no AAD and payload; or for BLE, with no payload there is nothing to do
556    {
557     if (encrypt_not_decrypt) {
558       BLECrypt_if_encrypt_packet_v3(a_copy,
559           l_a,
560           l_mc,
561           mac_size,
562           13,
563           mc_in,
564           key_be,
565           ccm_nonce_swapped,
566           mc_out);
567       l_mc += mac_size;
568 
569     } else { // Decrypt
570       if ((protocol == CCM_MODE_PROTOCOL_Ble) && (l_mc < mac_size + 1)) {
571         NRF_CCM_regs[inst]->MACSTATUS = CCM_MACSTATUS_MACSTATUS_CheckFailed;
572       } else if ((protocol == CCM_MODE_PROTOCOL_Ieee802154) && (l_mc < mac_size)) {
573         NRF_CCM_regs[inst]->MACSTATUS = CCM_MACSTATUS_MACSTATUS_CheckFailed;
574         nhw_CCM_signal_EVENTS_ERROR(inst);
575       } else {
576         int mic_error;
577         l_mc = BS_MAX((int)l_mc - mac_size, 0);
578 
579         mic_error = !BLECrypt_if_decrypt_packet_v3(a_copy,
580             l_a,
581             l_mc,
582             mac_size,
583             13,
584             mc_in,
585             key_be,
586             ccm_nonce_swapped,
587             mac_size == 0,
588             mc_out);
589 
590         if (!mic_error) {
591           NRF_CCM_regs[inst]->MACSTATUS = CCM_MACSTATUS_MACSTATUS_CheckPassed;
592         }
593       }
594     }
595   } else{ //l_mc == 0 or..
596     if (!encrypt_not_decrypt) {
597       nhw_CCM_signal_EVENTS_ERROR(inst);
598     }
599   }
600 
601   //Write l_m, which must be 2 bytes always
602   ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
603                          (uint8_t *)&l_mc, 2,
604                          &n_access, NHW_EVDMA_NEWJOB);
605   IF_NOT_WRITE_ERROR(ret);
606 
607   //Write a
608   ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
609                          a_in, l_a,
610                          &n_access, NHW_EVDMA_NEWJOB);
611   IF_NOT_WRITE_ERROR(ret);
612 
613   //Write c/m (encrypted/decrypted|plaintext message)
614   ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
615                          mc_out, l_mc,
616                          &n_access, NHW_EVDMA_NEWJOB);
617   if (ret == -3) { //It seems even not writing any output is fine
618     NRF_CCM_regs[inst]->ERRORSTATUS = (0x2UL);
619     nhw_CCM_signal_EVENTS_ERROR(inst);
620     return;
621   }
622 #undef IF_NOT_READ_ERROR
623 #undef IF_NOT_WRITE_ERROR
624 
625   nhw_CCM_signal_EVENTS_END(inst);
626 }
627 
nhw_CCM_TASK_START_inner(uint inst)628 static void nhw_CCM_TASK_START_inner(uint inst) {
629   nhw_ECB_possible_abort(inst);
630   nhw_CCM_logic(inst);
631 }
632 
nhw_CCM_TASK_STOP_inner(uint inst)633 static void nhw_CCM_TASK_STOP_inner(uint inst) {
634   (void) inst;
635   /* Note [CCM1]. The encryption is always instantaneous in the model,
636    * so FW should not catch it running */
637 }
638 
nhw_CCM_TASK_RATEOVERRIDE(uint inst)639 static void nhw_CCM_TASK_RATEOVERRIDE(uint inst) {
640   (void) inst;
641   /* Note [CCM3]. The encryption is always instantaneous in the model,
642    * so we do not need to do anything here */
643 }
644 
nhw_AARCCM_TASK_START(uint inst)645 static void nhw_AARCCM_TASK_START(uint inst) {
646   if (NRF_CCM_regs[inst]->ENABLE == AAR_ENABLE_ENABLE_Enabled) {
647     nhw_AAR_TASK_START_inner(inst);
648     return;
649   } else if (NRF_CCM_regs[inst]->ENABLE == CCM_ENABLE_ENABLE_Enabled) {
650     nhw_CCM_TASK_START_inner(inst);
651   } else {
652     bs_trace_warning_time_line("%s called with neither AAR or CCM enabled (%i) => ignored\n", __func__, NRF_CCM_regs[inst]->ENABLE);
653         return;
654   }
655 }
656 
nhw_AARCCM_TASK_STOP(uint inst)657 static void nhw_AARCCM_TASK_STOP(uint inst) {
658   if (NRF_CCM_regs[inst]->ENABLE == AAR_ENABLE_ENABLE_Enabled) {
659     nhw_AAR_TASK_STOP_inner(inst);
660     return;
661   } else if (NRF_CCM_regs[inst]->ENABLE == CCM_ENABLE_ENABLE_Enabled) {
662     nhw_CCM_TASK_STOP_inner(inst);
663   } else {
664     bs_trace_warning_time_line("%s called with neither AAR or CCM enabled (%i) => ignored\n", __func__, NRF_CCM_regs[inst]->ENABLE);
665         return;
666   }
667 }
668 
nhw_AAR_TASK_START(uint inst)669 static void nhw_AAR_TASK_START(uint inst) {
670   nhw_AARCCM_TASK_START(inst);
671 }
672 
nhw_CCM_TASK_START(uint inst)673 static void nhw_CCM_TASK_START(uint inst) {
674   nhw_AARCCM_TASK_START(inst);
675 }
676 
nhw_AAR_TASK_STOP(uint inst)677 static void nhw_AAR_TASK_STOP(uint inst) {
678   nhw_AARCCM_TASK_STOP(inst);
679 }
680 
nhw_CCM_TASK_STOP(uint inst)681 static void nhw_CCM_TASK_STOP(uint inst) {
682   nhw_AARCCM_TASK_STOP(inst);
683 }
684 
685 NHW_SIDEEFFECTS_TASKS(CCM, NRF_CCM_regs[inst]->, START)
686 NHW_SIDEEFFECTS_TASKS(CCM, NRF_CCM_regs[inst]->, STOP)
687 NHW_SIDEEFFECTS_TASKS(CCM, NRF_CCM_regs[inst]->, RATEOVERRIDE)
688 
689 #define NHW_CCM_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                   \
690   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE_WRAP(TASK_N, CCM)                         \
691   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N, CCM, ccm)
692 
NHW_CCM_REGW_SIDEFFECTS_SUBSCRIBE(START)693 NHW_CCM_REGW_SIDEFFECTS_SUBSCRIBE(START)
694 NHW_CCM_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
695 NHW_CCM_REGW_SIDEFFECTS_SUBSCRIBE(RATEOVERRIDE)
696 
697 NHW_SIDEEFFECTS_EVENTS(CCM)
698 
699 /* ECB */
700 
701 /*
702  * Cheat interface to adjust the time in microseconds it takes
703  * for a 16byte AES ECB block to be computed.
704  * (For all ECB peripheral instances)
705  */
706 void nhw_aes_ecb_cheat_set_t_ecb(unsigned int new_t){
707   for (int i = 0; i < NHW_AARCCMECB_TOTAL_INST; i++) {
708     nhw_ecb_st[i].t_ECB = new_t;
709   }
710 }
711 
712 /*
713  * Cheat interface to reset the time it takes
714  * for a 16byte AES ECB block to be computed
715  * to the value specified in the infocenter spec.
716  * (For all ECB peripheral instances)
717  */
nhw_aes_ecb_cheat_reset_t_ecb(void)718 void nhw_aes_ecb_cheat_reset_t_ecb(void){
719   uint t_ECB[NHW_AARCCMECB_TOTAL_INST] = NHW_ECB_t_ECB;
720   for (int i = 0; i < NHW_AARCCMECB_TOTAL_INST; i++) {
721     nhw_ecb_st[i].t_ECB = t_ECB[i];
722   }
723 }
724 
725 NHW_SIDEEFFECTS_INTSET(ECB, NRF_ECB_regs[inst]., nhw_ecb_st[inst].INTEN)
726 NHW_SIDEEFFECTS_INTCLR(ECB, NRF_ECB_regs[inst]., nhw_ecb_st[inst].INTEN)
727 
728 static NHW_SIGNAL_EVENT(ECB, NRF_ECB_regs[inst]. , END)
729 static NHW_SIGNAL_EVENT(ECB, NRF_ECB_regs[inst]. , ERROR)
730 
nhw_ECB_stop(uint inst)731 static void nhw_ECB_stop(uint inst) {
732   struct ecb_status *st = &nhw_ecb_st[inst];
733   st->Running = false;
734   st->Timer = TIME_NEVER;
735   update_master_timer();
736 }
737 
nhw_ECB_possible_abort(uint inst)738 static bool nhw_ECB_possible_abort(uint inst) {
739   if ((nhw_aar_st[inst].Running) || (nhw_ccm_st[inst].Running)) {
740     nhw_ECB_stop(inst);
741     NRF_ECB_regs[inst].ERRORSTATUS = ECB_ERRORSTATUS_ERRORSTATUS_Aborted;
742     nhw_ECB_signal_EVENTS_ERROR(inst);
743     return true;
744   }
745   return false;
746 }
747 
nhw_ECB_logic(uint inst)748 static void nhw_ECB_logic(uint inst) {
749   uint8_t input[16];
750   uint8_t output[16];
751   uint8_t key_be[16];
752   EVDMA_status_t in_evdma, out_evdma;
753   size_t n_access;
754   int ret;
755 
756   NRF_ECB_regs[inst].ERRORSTATUS = 0;
757 
758   memset(input, 0, sizeof(input));
759 
760   ret = nhw_EVDMA_start(&in_evdma, (void *)NRF_ECB_regs[inst].IN.PTR);
761   if (ret) {
762     bs_trace_error_time_line("ECB IN.PTR is NULL during start, that would have hard faulted\n");
763   }
764   ret = nhw_EVDMA_access(&in_evdma, NHW_EVDMA_READ,
765                          input, 16,
766                          &n_access, NHW_EVDMA_NEWJOB);
767   if (ret < 0) { //Note [ECB4]
768     NRF_ECB_regs[inst].ERRORSTATUS = ECB_ERRORSTATUS_ERRORSTATUS_PrematureInptrEnd;
769     nhw_ECB_stop(inst);
770     nhw_ECB_signal_EVENTS_ERROR(inst);
771     return;
772   }
773 
774   hwu_reverse_byte_order((const uint8_t*)&NRF_ECB_regs[inst].KEY, key_be, 16);
775 
776   BLECrypt_if_aes_128(key_be, input, output);
777 
778   ret = nhw_EVDMA_start(&out_evdma, (void *)NRF_ECB_regs[inst].OUT.PTR);
779   if (ret) {
780     bs_trace_error_time_line("ECB OUT.PTR is NULL during start, that would have hard faulted\n");
781   }
782   ret = nhw_EVDMA_access(&out_evdma, NHW_EVDMA_WRITE,
783                          output, 16,
784                          &n_access, NHW_EVDMA_NEWJOB);
785   if (n_access ==  0) { //It is ok to have a job for less than 16 bytes, just not to have none.
786     NRF_ECB_regs[inst].ERRORSTATUS = ECB_ERRORSTATUS_ERRORSTATUS_PrematureOutptrEnd;
787     nhw_ECB_stop(inst);
788     nhw_ECB_signal_EVENTS_ERROR(inst);
789     return;
790   }
791 
792   //Note [ECB1]
793   nhw_ecb_st[inst].Timer = nsi_hws_get_time() + nhw_ecb_st[inst].t_ECB;
794   update_master_timer();
795 }
796 
nhw_ECB_TASK_START(uint inst)797 static void nhw_ECB_TASK_START(uint inst) {
798   //Note [ECB2]
799   if (nhw_ecb_st[inst].Running) {
800     bs_trace_warning_time_line("%s called while ECB was already running => error event\n", __func__);
801     NRF_ECB_regs[inst].ERRORSTATUS = ECB_ERRORSTATUS_ERRORSTATUS_Aborted;
802     nhw_ECB_signal_EVENTS_ERROR(inst);
803     return;
804   }
805   if (nhw_ECB_possible_abort(inst)) {
806     bs_trace_warning_time_line("%s called while AAR or CCM was running => error event\n", __func__);
807     return;
808   }
809   nhw_ecb_st[inst].Running = true;
810   nhw_ECB_logic(inst);
811 }
812 
nhw_ECB_TASK_STOP(uint inst)813 static void nhw_ECB_TASK_STOP(uint inst) {
814   int was_running = nhw_ecb_st[inst].Running;
815   nhw_ECB_stop(inst);
816   if (was_running) {
817     NRF_ECB_regs[inst].ERRORSTATUS = ECB_ERRORSTATUS_ERRORSTATUS_Aborted;
818     nhw_ECB_signal_EVENTS_ERROR(inst);
819     //Note [ECB3]
820   } else {
821     bs_trace_info_time_line(3, "%s called while ECB was not running\n", __func__);
822   }
823 }
824 
825 NHW_SIDEEFFECTS_TASKS(ECB, NRF_ECB_regs[inst]., START)
826 NHW_SIDEEFFECTS_TASKS(ECB, NRF_ECB_regs[inst]., STOP)
827 
nhw_ECB_timer_triggered(uint inst)828 static void nhw_ECB_timer_triggered(uint inst) {
829   nhw_ECB_stop(inst);
830   nhw_ECB_signal_EVENTS_END(inst);
831 }
832 
833 #define NHW_ECB_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N)                                   \
834   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE_WRAP(TASK_N, ECB)                         \
835   NHW_AARECBCCM_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N, ECB, ecb)
836 
837 NHW_ECB_REGW_SIDEFFECTS_SUBSCRIBE(START)
NHW_ECB_REGW_SIDEFFECTS_SUBSCRIBE(STOP)838 NHW_ECB_REGW_SIDEFFECTS_SUBSCRIBE(STOP)
839 
840 NHW_SIDEEFFECTS_EVENTS(ECB)
841 
842 /***/
843 
844 static void nhw_AARCCMECB_timer_triggered(void) {
845   for (int i = 0; i < NHW_AARCCMECB_TOTAL_INST; i++) {
846     if (Timer_AAR_CCM_ECB == nhw_aar_st[i].Timer) {
847       nhw_AAR_timer_triggered(i);
848     } else if (Timer_AAR_CCM_ECB == nhw_ecb_st[i].Timer) {
849       nhw_ECB_timer_triggered(i);
850     } else {
851       bs_trace_error_time_line("Programming error\n");
852     }
853   }
854   nsi_hws_find_next_event();
855 }
856 
857 NSI_HW_EVENT(Timer_AAR_CCM_ECB, nhw_AARCCMECB_timer_triggered, 50);
858