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