Build usbtrng-v2.0 with DEBUG_FIPS
[fw/altos] / src / drivers / ao_trng.c
1 /*
2  * Copyright © 2015 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_adc_fast.h>
20 #include <ao_crc.h>
21 #include <ao_boot.h>
22 #include <ao_trng.h>
23
24 static struct ao_task ao_blink_green_task;
25 static uint8_t ao_blinking_green = 0;
26
27 static void
28 ao_blink_green(void)
29 {
30         for (;;) {
31                 while (!ao_blinking_green)
32                         ao_sleep(&ao_blinking_green);
33                 while (ao_blinking_green) {
34                         ao_led_toggle(AO_LED_GREEN);
35                         ao_delay(AO_MS_TO_TICKS(1000));
36                 }
37         }
38 }
39
40 static struct ao_task ao_blink_red_task;
41 static uint8_t ao_failed = 0; /* 0 NOMINAL, 1 FAILED */
42 static uint8_t ao_post = 0; /* 0 POST needed, 1 powered up */
43
44 /* On handling failure, keithp said:
45  We could disconnect from USB easily enough, or disconnect and come back
46  with a different setup that the kernel driver could report as an
47  error. Lots of options.
48 */
49
50 void
51 ao_trng_failure()
52 {
53         ao_failed = 1;
54         ao_wakeup(&ao_failed);
55 }
56
57 #ifdef DEBUG_FIPS
58
59 static uint16_t ao_fail_ring_tail;
60 static uint32_t ao_fail_adc;
61 static uint32_t fail_ring[AO_ADC_RING_SIZE >> 1];
62
63 static void
64 ao_trng_fetch(void)
65 {
66         static uint16_t *buffer[2];
67         uint32_t        kbytes = 1;
68         uint32_t        count;
69         int             usb_buf_id;
70         uint16_t        i;
71         uint16_t        *buf;
72         uint16_t        t;
73         uint32_t        *rnd = (uint32_t *) ao_adc_ring;
74         uint32_t        cur;
75         uint32_t        prev = 0;
76         uint8_t         prev_set = 0; /* prev has been set */
77
78         if (!buffer[0]) {
79                 buffer[0] = ao_usb_alloc();
80                 buffer[1] = ao_usb_alloc();
81                 if (!buffer[0])
82                         return;
83         }
84
85         ao_cmd_decimal();
86         if (ao_cmd_status == ao_cmd_success)
87                 kbytes = ao_cmd_lex_u32;
88         else
89                 ao_cmd_status = ao_cmd_success;
90         usb_buf_id = 0;
91         count = kbytes * (1024/AO_USB_IN_SIZE);
92
93         ao_crc_reset();
94
95         ao_led_on(AO_LED_TRNG_ACTIVE);
96         while (!ao_failed && count--) {
97                 t = ao_adc_get(AO_USB_IN_SIZE) >> 1;    /* one 16-bit value per output byte */
98                 buf = buffer[usb_buf_id];
99                 for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
100                         cur = rnd[t];
101                         fail_ring[t] = cur;
102                         if (prev_set && (cur == prev)) {
103                                 ao_trng_failure();
104                                 ao_fail_ring_tail = t;
105                                 ao_fail_adc = cur;
106                                 break;
107                         }
108                         *buf++ = ao_crc_in_32_out_16(cur);
109                         t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1);
110                         prev = cur;
111                         prev_set = 1;
112                 }
113                 ao_adc_ack(AO_USB_IN_SIZE);
114                 ao_led_toggle(AO_LED_TRNG_ACTIVE);
115                 ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
116                 ao_led_toggle(AO_LED_TRNG_ACTIVE);
117                 usb_buf_id = 1-usb_buf_id;
118         }
119         ao_led_off(AO_LED_TRNG_ACTIVE);
120         flush();
121 }
122
123 static void
124 ao_trng_fetch_cmd(void)
125 {
126         if (!ao_failed)
127                 ao_trng_fetch();
128 }
129
130 static void
131 ao_trng_status(void)
132 {
133         if (ao_failed) {
134                 uint16_t i;
135                 uint32_t *rnd = (uint32_t *) ao_adc_ring;
136
137                 printf("FAILED at ring_tail: %3d,    adc = %08x\n", ao_fail_ring_tail, ao_fail_adc);
138                 for (i = 0; i < (AO_ADC_RING_SIZE >> 1); i += 4) {
139                         printf("%3d: %08x  ", i, rnd[i]);
140                         printf("%3d: %08x  ", i+1, rnd[i+1]);
141                         printf("%3d: %08x  ", i+2, rnd[i+2]);
142                         printf("%3d: %08x\n", i+3, rnd[i+3]);
143                 }
144                 printf("COPY fail_ring: %3d,    adc = %08x\n", ao_fail_ring_tail, ao_fail_adc);
145                 for (i = 0; i < (AO_ADC_RING_SIZE >> 1); i += 4) {
146                         printf("%3d: %08x  ", i, fail_ring[i]);
147                         printf("%3d: %08x  ", i+1, fail_ring[i+1]);
148                         printf("%3d: %08x  ", i+2, fail_ring[i+2]);
149                         printf("%3d: %08x\n", i+3, fail_ring[i+3]);
150                 }
151         } else
152                 printf("NOMINAL\n");
153 }
154
155 void ao_trng_reset(void); /* forward declaration */
156
157 static void
158 ao_blink_green_toggle(void)
159 {
160         ao_blinking_green = !ao_blinking_green;
161         if (!ao_blinking_green)
162                 ao_led_off(AO_LED_GREEN);
163         ao_wakeup(&ao_blinking_green);
164 }
165
166 static const struct ao_cmds ao_trng_cmds[] = {
167         { ao_trng_fetch_cmd, "f <kbytes>\0Fetch a block of numbers" },
168         { ao_trng_reset, "R\0Reset" },
169         { ao_blink_green_toggle, "G\0Toggle green LED blinking" },
170         { ao_trng_status, "s\0Show status" },
171         { ao_trng_failure, "z\0Simulate failure" },
172         { 0, NULL },
173 };
174
175 #else
176
177 static void
178 ao_trng_send(void)
179 {
180         static uint16_t *buffer[2];
181         int             usb_buf_id;
182         uint16_t        i;
183         uint16_t        *buf;
184         uint16_t        t;
185         uint32_t        *rnd = (uint32_t *) ao_adc_ring;
186
187         if (!buffer[0]) {
188                 buffer[0] = ao_usb_alloc();
189                 buffer[1] = ao_usb_alloc();
190                 if (!buffer[0])
191                         return;
192         }
193
194         usb_buf_id = 0;
195
196         ao_crc_reset();
197
198         for (;;) {
199                 ao_led_on(AO_LED_TRNG_ACTIVE);
200                 t = ao_adc_get(AO_USB_IN_SIZE) >> 1;    /* one 16-bit value per output byte */
201                 buf = buffer[usb_buf_id];
202                 for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) {
203                         *buf++ = ao_crc_in_32_out_16(rnd[t]);
204                         t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1);
205                 }
206                 ao_adc_ack(AO_USB_IN_SIZE);
207                 ao_led_off(AO_LED_TRNG_ACTIVE);
208                 ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE);
209                 usb_buf_id = 1-usb_buf_id;
210         }
211 }
212
213 static struct ao_task ao_trng_send_task;
214
215 static void
216 ao_bootloader_cmd(void)
217 {
218         for (;;) {
219                 getchar(); /* any char will do */
220                 /* give feedback we are going into bootloader mode */
221                 ao_led_on(AO_LED_GREEN);
222                 ao_delay(AO_MS_TO_TICKS(500));
223                 ao_led_off(AO_LED_GREEN);
224                 ao_delay(AO_MS_TO_TICKS(500));
225                 ao_led_on(AO_LED_GREEN);
226                 ao_delay(AO_MS_TO_TICKS(500));
227                 ao_led_off(AO_LED_GREEN);
228                 ao_delay(AO_MS_TO_TICKS(500));
229                 ao_led_on(AO_LED_GREEN);
230                 ao_delay(AO_MS_TO_TICKS(500));
231                 ao_led_off(AO_LED_GREEN);
232                 ao_boot_loader();
233         }
234 }
235
236 static struct ao_task ao_bootloader_cmd_task;
237
238 #endif
239
240
241 /* NOTE: the reset function also functions as the Power On Self Test */
242 void
243 ao_trng_reset(void)
244 {
245         /* printf("Resetting...\n"); */
246         ao_failed = 0;
247         ao_led_off(AO_LED_RED);
248         ao_wakeup(&ao_failed);
249         /* get the first 1k bits and ensure there are no duplicates */
250         /* FIXME ao_trng_fetch(); */
251         if (!ao_failed) {
252                 ao_led_on(AO_LED_GREEN);
253                 ao_delay(AO_MS_TO_TICKS(1000));
254                 ao_led_off(AO_LED_GREEN);
255         }
256 }
257
258 static void
259 ao_blink_red(void)
260 {
261         if (!ao_post) {
262                 ao_trng_reset(); /* POST */
263                 ao_post = 1;
264         }
265         for (;;) {
266                 while (!ao_failed)
267                         ao_sleep(&ao_failed);
268                 while (ao_failed) {
269                         ao_led_toggle(AO_LED_RED);
270                         ao_delay(AO_MS_TO_TICKS(500));
271                 }
272         }
273 }
274
275 void
276 ao_trng_init(void)
277 {
278         ao_add_task(&ao_blink_red_task, ao_blink_red, "blink_red");
279         ao_add_task(&ao_blink_green_task, ao_blink_green, "blink_green");
280 #ifdef DEBUG_FIPS
281         ao_cmd_register(ao_trng_cmds);
282 #else
283         ao_add_task(&ao_bootloader_cmd_task, ao_bootloader_cmd, "bootloader_cmd");
284         ao_add_task(&ao_trng_send_task, ao_trng_send, "trng_send");
285 #endif
286 }