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