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