1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * AES electronic codebook mode encryption
10 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/ecb.html?cp=5_1_0_5_5
11 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/ecb.html?cp=4_0_0_6_9
12 */
13
14 #include <string.h>
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include "NHW_common_types.h"
18 #include "NHW_templates.h"
19 #include "NHW_config.h"
20 #include "NHW_peri_types.h"
21 #include "NHW_AES_ECB.h"
22 #include "NHW_xPPI.h"
23 #include "nsi_hw_scheduler.h"
24 #include "irq_ctrl.h"
25 #include "bs_tracing.h"
26 #include "BLECrypt_if.h"
27 #include "nsi_tasks.h"
28 #include "nsi_hws_models_if.h"
29
30 #if NHW_ECB_TOTAL_INST > 1
31 #error "This model only supports 1 instance so far"
32 #endif
33
34 static bs_time_t Timer_ECB = TIME_NEVER; /* Time when the ECB will finish */
35
36 NRF_ECB_Type NRF_ECB_regs;
37
38 #if (NHW_HAS_DPPI)
39 /* Mapping of peripheral instance to DPPI instance */
40 static uint nhw_ECB_dppi_map[NHW_ECB_TOTAL_INST] = NHW_ECB_DPPI_MAP;
41 #endif
42
43 static uint32_t ECB_INTEN; /* interrupt enable */
44 static bool ECB_Running;
45
46 static uint ECB_t_ECB = NHW_ECB_t_ECB;
47
48 typedef struct {
49 uint8_t KEY[16]; /* 16 byte AES key */
50 uint8_t CLEARTEXT[16]; /* 16 byte AES cleartext input block */
51 uint8_t CIPHERTEXT[16]; /* 16 byte AES ciphertext output block */
52 } ecbdata_t;
53
nhw_aes_ecb_init(void)54 static void nhw_aes_ecb_init(void) {
55 memset(&NRF_ECB_regs, 0, sizeof(NRF_ECB_regs));
56 Timer_ECB = TIME_NEVER;
57 ECB_INTEN = 0;
58 ECB_Running = false;
59 }
60
61 NSI_TASK(nhw_aes_ecb_init, HW_INIT, 100);
62
63 /*
64 * Cheat interface to adjust the time in microseconds it takes
65 * for a 16byte AES ECB block to be computed
66 */
nhw_aes_ecb_cheat_set_t_ecb(unsigned int new_t)67 void nhw_aes_ecb_cheat_set_t_ecb(unsigned int new_t){
68 ECB_t_ECB = new_t;
69 }
nrf_aes_ecb_cheat_set_t_ecb(unsigned int new_t)70 void nrf_aes_ecb_cheat_set_t_ecb(unsigned int new_t) {
71 nhw_aes_ecb_cheat_set_t_ecb(new_t);
72 }
73
74 /*
75 * Cheat interface to reset the time it takes
76 * for a 16byte AES ECB block to be computed
77 * to the value specified in the infocenter spec.
78 */
nhw_aes_ecb_cheat_reset_t_ecb(void)79 void nhw_aes_ecb_cheat_reset_t_ecb(void){
80 ECB_t_ECB = NHW_ECB_t_ECB;
81 }
nrf_aes_ecb_cheat_reset_t_ecb(void)82 void nrf_aes_ecb_cheat_reset_t_ecb(void){
83 nhw_aes_ecb_cheat_reset_t_ecb();
84 }
85
nhw_ECB_eval_interrupt(uint inst)86 static void nhw_ECB_eval_interrupt(uint inst) {
87 static bool ecb_int_line[NHW_ECB_TOTAL_INST]; /* Is the ECB currently driving its interrupt line high */
88 /* Mapping of peripheral instance to {int controller instance, int number} */
89 static struct nhw_irq_mapping nhw_ecb_irq_map[NHW_ECB_TOTAL_INST] = NHW_ECB_INT_MAP;
90 bool new_int_line = false;
91
92 NHW_CHECK_INTERRUPT_si(ECB, ENDECB, ECB_INTEN)
93 NHW_CHECK_INTERRUPT_si(ECB, ERRORECB, ECB_INTEN)
94
95 hw_irq_ctrl_toggle_level_irq_line_if(&ecb_int_line[inst],
96 new_int_line,
97 &nhw_ecb_irq_map[inst]);
98 }
99
NHW_SIGNAL_EVENT_si(ECB,ENDECB)100 static NHW_SIGNAL_EVENT_si(ECB, ENDECB)
101 static NHW_SIGNAL_EVENT_si(ECB, ERRORECB)
102
103 void nhw_ECB_TASK_STOPECB(void) {
104 if (!ECB_Running) {
105 return;
106 }
107
108 ECB_Running = false;
109 Timer_ECB = TIME_NEVER;
110 nsi_hws_find_next_event();
111 nhw_ECB_signal_EVENTS_ERRORECB(0);
112 }
113
nhw_ECB_TASK_STARTECB(void)114 void nhw_ECB_TASK_STARTECB(void) {
115 ECB_Running = true;
116 Timer_ECB = nsi_hws_get_time() + ECB_t_ECB;
117 nsi_hws_find_next_event();
118 }
119
120 NHW_SIDEEFFECTS_INTSET_si(ECB, NRF_ECB_regs., ECB_INTEN)
121 NHW_SIDEEFFECTS_INTCLR_si(ECB, NRF_ECB_regs., ECB_INTEN)
122
NHW_SIDEEFFECTS_EVENTS(ECB)123 NHW_SIDEEFFECTS_EVENTS(ECB)
124
125 NHW_SIDEEFFECTS_TASKS_si(ECB, STARTECB)
126 NHW_SIDEEFFECTS_TASKS_si(ECB, STOPECB)
127
128 #if (NHW_HAS_DPPI)
129 NHW_SIDEEFFECTS_SUBSCRIBE_si(ECB, STARTECB)
130 NHW_SIDEEFFECTS_SUBSCRIBE_si(ECB, STOPECB)
131 #endif /* NHW_HAS_DPPI */
132
133 static void nhw_ecb_timer_triggered(void) {
134
135 ECB_Running = false;
136 Timer_ECB = TIME_NEVER;
137 nsi_hws_find_next_event();
138
139 ecbdata_t *ecbptr = (ecbdata_t *)NRF_ECB_regs.ECBDATAPTR;
140
141 if (!ecbptr) {
142 bs_trace_error_time_line("NRF_ECB_regs.ECBDATAPT is NULL\n");
143 } else {
144 /* Note all KEY, and data are assumed to be big endian ordered */
145 BLECrypt_if_aes_128(
146 ecbptr->KEY,
147 ecbptr->CLEARTEXT,
148 ecbptr->CIPHERTEXT);
149 nhw_ECB_signal_EVENTS_ENDECB(0);
150 }
151 }
152
153 NSI_HW_EVENT(Timer_ECB, nhw_ecb_timer_triggered, 50);
154