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 * AAR - Accelerated address resolver
10 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/aar.html?cp=4_1_0_5_1
11 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/aar.html?cp=4_0_0_6_3
12 *
13 * Notes:
14 * * Unlike in the real HW the AAR peripheral does not share resources with the CCM or ECB peripherals.
15 * They are actually 2 separate peripherals, so if they are used simultaneously nothing will fail.
16 * Therefore
17 * * Starting the AAR block while the ECB block is running will not abort the ECB and
18 * cause a ERRORECB
19 * * The AAR register map (including interrupt mask, enable, & task start) does not
20 * overlap the CCM one.
21 * * The AAR block could even be used in parallel to the CCM block without conflicts.
22 * * IMPORTANT: This may change in the future. No embedded SW or tests may rely on this,
23 * but instead they should behave like they would with real HW.
24 */
25
26 #include <string.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include "NHW_config.h"
30 #include "NHW_common_types.h"
31 #include "NHW_templates.h"
32 #include "NHW_AAR.h"
33 #include "nsi_hw_scheduler.h"
34 #include "NHW_peri_types.h"
35 #include "NHW_xPPI.h"
36 #include "irq_ctrl.h"
37 #include "bs_tracing.h"
38 #include "BLECrypt_if.h"
39 #include "nsi_tasks.h"
40 #include "nsi_hws_models_if.h"
41
42 #if NHW_AAR_TOTAL_INST > 1
43 #error "This model only supports 1 instance so far"
44 #endif
45
46 static bs_time_t Timer_AAR = TIME_NEVER; /* Time when the AAR will finish */
47
48 NRF_AAR_Type NRF_AAR_regs;
49 #if (NHW_HAS_DPPI)
50 /* Mapping of peripheral instance to DPPI instance */
51 static uint nhw_AAR_dppi_map[NHW_AAR_TOTAL_INST] = NHW_AAR_DPPI_MAP;
52 #endif
53
54 static uint32_t AAR_INTEN = 0; //interrupt enable
55 static bool AAR_Running;
56 static int matching_irk;
57
nhw_aar_init(void)58 static void nhw_aar_init(void) {
59 memset(&NRF_AAR_regs, 0, sizeof(NRF_AAR_regs));
60 AAR_INTEN = 0;
61 Timer_AAR = TIME_NEVER;
62 AAR_Running = false;
63 }
64
65 NSI_TASK(nhw_aar_init, HW_INIT, 100);
66
67 static int nhw_aar_resolve(int *good_irk);
68
nhw_AAR_eval_interrupt(uint inst)69 static void nhw_AAR_eval_interrupt(uint inst) {
70 static bool aar_int_line[NHW_AAR_TOTAL_INST]; /* Is the AAR currently driving its interrupt line high */
71 /* Mapping of peripheral instance to {int controller instance, int number} */
72 static struct nhw_irq_mapping nhw_aar_irq_map[NHW_AAR_TOTAL_INST] = NHW_AAR_INT_MAP;
73 bool new_int_line = false;
74
75 NHW_CHECK_INTERRUPT_si(AAR, END, AAR_INTEN)
76 NHW_CHECK_INTERRUPT_si(AAR, RESOLVED, AAR_INTEN)
77 NHW_CHECK_INTERRUPT_si(AAR, NOTRESOLVED, AAR_INTEN)
78
79 hw_irq_ctrl_toggle_level_irq_line_if(&aar_int_line[inst],
80 new_int_line,
81 &nhw_aar_irq_map[inst]);
82 }
83
NHW_SIGNAL_EVENT_si(AAR,END)84 static NHW_SIGNAL_EVENT_si(AAR, END)
85 static NHW_SIGNAL_EVENT_si(AAR, RESOLVED)
86 static NHW_SIGNAL_EVENT_si(AAR, NOTRESOLVED)
87
88 void nhw_AAR_TASK_START(void) {
89 int n_irks;
90
91 if (NRF_AAR_regs.ENABLE != 0x3) {
92 return;
93 }
94
95 AAR_Running = true;
96 n_irks = nhw_aar_resolve(&matching_irk);
97
98 Timer_AAR = nsi_hws_get_time() + 1 + NHW_AAR_t_AAR * n_irks; /*AAR delay*/
99 nsi_hws_find_next_event();
100 }
101
nhw_AAR_TASK_STOP(void)102 void nhw_AAR_TASK_STOP(void) {
103 if (!AAR_Running) {
104 return;
105 }
106
107 AAR_Running = false;
108 Timer_AAR = TIME_NEVER;
109 nsi_hws_find_next_event();
110 nhw_AAR_signal_EVENTS_END(0);
111 //Does this actually signal an END?
112 //and only an END?
113 }
114
115 NHW_SIDEEFFECTS_INTSET_si(AAR, NRF_AAR_regs., AAR_INTEN)
116 NHW_SIDEEFFECTS_INTCLR_si(AAR, NRF_AAR_regs., AAR_INTEN)
117
NHW_SIDEEFFECTS_EVENTS(AAR)118 NHW_SIDEEFFECTS_EVENTS(AAR)
119
120 NHW_SIDEEFFECTS_TASKS_si(AAR, START)
121 NHW_SIDEEFFECTS_TASKS_si(AAR, STOP)
122
123 #if (NHW_HAS_DPPI)
124 NHW_SIDEEFFECTS_SUBSCRIBE_si(AAR, START)
125 NHW_SIDEEFFECTS_SUBSCRIBE_si(AAR, STOP)
126 #endif /* NHW_HAS_DPPI */
127
128 static void nhw_aar_timer_triggered(void) {
129 AAR_Running = false;
130 Timer_AAR = TIME_NEVER;
131 nsi_hws_find_next_event();
132
133 if (matching_irk != -1) {
134 NRF_AAR_regs.STATUS = matching_irk;
135 nhw_AAR_signal_EVENTS_RESOLVED(0);
136 } else {
137 nhw_AAR_signal_EVENTS_NOTRESOLVED(0);
138 }
139 nhw_AAR_signal_EVENTS_END(0);
140 }
141
142 NSI_HW_EVENT(Timer_AAR, nhw_aar_timer_triggered, 50);
143
read_3_bytes_value(const uint8_t * ptr)144 static inline uint32_t read_3_bytes_value(const uint8_t *ptr) {
145 uint32_t value = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
146 return value;
147 }
148
149 /**
150 * Try to resolve the address
151 * Returns the number of IRKs it went thru before matching
152 * (or if it did not, it returns NRF_AAR_regs.NIRK)
153 *
154 * It sets *good_irk to the index of the IRK that matched
155 * or to -1 if none did.
156 */
nhw_aar_resolve(int * good_irk)157 static int nhw_aar_resolve(int *good_irk) {
158 int i;
159 uint8_t prand_buf[16];
160 uint8_t hash_check_buf[16];
161 uint32_t hash, hash_check;
162 uint32_t prand;
163 const uint8_t *irkptr;
164 /*
165 * The AAR module always assumes the S0+Length+S1 occupy 3 bytes
166 * independently of the RADIO config
167 */
168 uint8_t *address_ptr = (uint8_t*)NRF_AAR_regs.ADDRPTR + 3;
169
170 *good_irk = -1;
171
172 bs_trace_raw_time(9,"HW AAR address to match %02x:%02x:%02x:%02x:%02x:%02x\n",
173 address_ptr[5], address_ptr[4], address_ptr[3],
174 address_ptr[2], address_ptr[1], address_ptr[0]);
175
176 prand = read_3_bytes_value(address_ptr+3);
177 if (prand >> 22 != 0x01){
178 /* Not a resolvable private address */
179 bs_trace_raw_time(7,"HW AAR the address is not resolvable (0x%06X , %x)\n", prand, prand >> 22);
180 return NRF_AAR_regs.NIRK;
181 }
182
183 memset(prand_buf,0,16);
184
185 /* Endiannes reversal to bigendian */
186 prand_buf[15] = prand & 0xFF;
187 prand_buf[14] = (prand >> 8) & 0xFF;
188 prand_buf[13] = (prand >> 16) & 0xFF;
189
190 hash = read_3_bytes_value(address_ptr);
191
192 for (i = 0 ; i < NRF_AAR_regs.NIRK; i++){
193 /* The provided IRKs are assumed to be already big endian */
194 irkptr = ((const uint8_t*)NRF_AAR_regs.IRKPTR) + 16*i;
195
196 /* this aes_128 function takes and produces big endian results */
197 BLECrypt_if_aes_128(
198 irkptr,
199 prand_buf,
200 hash_check_buf);
201
202 /* Endianess reversal to little endian */
203 hash_check = hash_check_buf[15] | (uint32_t)hash_check_buf[14] << 8 | (uint32_t)hash_check_buf[13] << 16;
204
205 bs_trace_raw_time(9,"HW AAR (%i): checking prand = 0x%06X, hash = 0x%06X, hashcheck = 0x%06X\n",i, prand, hash, hash_check);
206
207 if (hash == hash_check) {
208 bs_trace_raw_time(7,"HW AAR matched irk %i (of %i)\n",i, NRF_AAR_regs.NIRK);
209 *good_irk = i;
210 return i+1;
211 }
212 }
213
214 bs_trace_raw_time(7,"HW AAR did not match any IRK of %i\n", NRF_AAR_regs.NIRK);
215 return i;
216 }
217