integrate ccid and usb threads
[gnuk/gnuk.git] / src / main.c
1 /*
2  * main.c - main routine of Gnuk
3  *
4  * Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016
5  *               Free Software Initiative of Japan
6  * Author: NIIBE Yutaka <gniibe@fsij.org>
7  *
8  * This file is a part of Gnuk, a GnuPG USB Token implementation.
9  *
10  * Gnuk is free software: you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <chopstx.h>
28 #include <eventflag.h>
29
30 #include "config.h"
31
32 #include "sys.h"
33 #include "adc.h"
34 #include "gnuk.h"
35 #include "usb_lld.h"
36 #include "usb-cdc.h"
37 #include "random.h"
38 #include "stm32f103.h"
39
40
41 /*
42  * main thread does 1-bit LED display output
43  */
44 #define MAIN_TIMEOUT_INTERVAL   (5000*1000)
45
46 #define LED_TIMEOUT_INTERVAL    (75*1000)
47 #define LED_TIMEOUT_ZERO        (25*1000)
48 #define LED_TIMEOUT_ONE         (100*1000)
49 #define LED_TIMEOUT_STOP        (200*1000)
50
51
52 #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
53 static void
54 device_initialize_once (void)
55 {
56   const uint8_t *p = &gnuk_string_serial[ID_OFFSET];
57
58   if (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff)
59     {
60       /*
61        * This is the first time invocation.
62        * Setup serial number by unique device ID.
63        */
64       const uint8_t *u = unique_device_id () + 8;
65       int i;
66
67       for (i = 0; i < 4; i++)
68         {
69           uint8_t b = u[3-i];
70           uint8_t nibble;
71
72           nibble = (b >> 4);
73           nibble += (nibble >= 10 ? ('A' - 10) : '0');
74           flash_put_data_internal (&p[i*4], nibble);
75           nibble = (b & 0x0f);
76           nibble += (nibble >= 10 ? ('A' - 10) : '0');
77           flash_put_data_internal (&p[i*4+2], nibble);
78         }
79     }
80 }
81
82
83 static volatile uint8_t fatal_code;
84 static struct eventflag led_event;
85
86 static void display_fatal_code (void)
87 {
88   while (1)
89     {
90       set_led (1);
91       chopstx_usec_wait (LED_TIMEOUT_ZERO);
92       set_led (0);
93       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
94       set_led (1);
95       chopstx_usec_wait (LED_TIMEOUT_ZERO);
96       set_led (0);
97       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
98       set_led (1);
99       chopstx_usec_wait (LED_TIMEOUT_ZERO);
100       set_led (0);
101       chopstx_usec_wait (LED_TIMEOUT_STOP);
102       set_led (1);
103       if (fatal_code & 1)
104         chopstx_usec_wait (LED_TIMEOUT_ONE);
105       else
106         chopstx_usec_wait (LED_TIMEOUT_ZERO);
107       set_led (0);
108       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
109       set_led (1);
110       if (fatal_code & 2)
111         chopstx_usec_wait (LED_TIMEOUT_ONE);
112       else
113         chopstx_usec_wait (LED_TIMEOUT_ZERO);
114       set_led (0);
115       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
116       set_led (1);
117       chopstx_usec_wait (LED_TIMEOUT_STOP);
118       set_led (0);
119       chopstx_usec_wait (LED_TIMEOUT_INTERVAL*10);
120     }
121 }
122
123 static uint8_t led_inverted;
124
125 static eventmask_t emit_led (int on_time, int off_time)
126 {
127   eventmask_t m;
128
129   set_led (!led_inverted);
130   m = eventflag_wait_timeout (&led_event, on_time);
131   set_led (led_inverted);
132   if (m) return m;
133   if ((m = eventflag_wait_timeout (&led_event, off_time)))
134     return m;
135   return 0;
136 }
137
138 static eventmask_t display_status_code (void)
139 {
140   eventmask_t m;
141   enum icc_state icc_state = *icc_state_p;
142
143   if (icc_state == ICC_STATE_START)
144     return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
145   else
146     /* OpenPGP card thread  running */
147     {
148       if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
149                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
150                           LED_TIMEOUT_INTERVAL)))
151         return m;
152       if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
153                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
154                           LED_TIMEOUT_INTERVAL)))
155         return m;
156       if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
157                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
158                           LED_TIMEOUT_INTERVAL)))
159         return m;
160
161       if (icc_state == ICC_STATE_WAIT)
162         {
163           if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP * 2)))
164             return m;
165         }
166       else
167         {
168           if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL)))
169             return m;
170
171           if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
172                               LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
173                               LED_TIMEOUT_STOP)))
174             return m;
175         }
176
177       return 0;
178     }
179 }
180
181 void
182 led_blink (int spec)
183 {
184   eventflag_signal (&led_event, spec);
185 }
186
187 /*
188  * In Gnuk 1.0.[12], reGNUal was not relocatable.
189  * Now, it's relocatable, but we need to calculate its entry address
190  * based on it's pre-defined address.
191  */
192 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
193 static uint32_t
194 calculate_regnual_entry_address (const uint8_t *addr)
195 {
196   const uint8_t *p = addr + 4;
197   uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
198
199   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
200   v += (uint32_t)addr;
201   return v;
202 }
203
204 extern uint8_t __process1_stack_base__, __process1_stack_size__;
205 const uint32_t __stackaddr_ccid = (uint32_t)&__process1_stack_base__;
206 const size_t __stacksize_ccid = (size_t)&__process1_stack_size__;
207
208 #define PRIO_CCID 3
209 #define PRIO_MAIN 5
210
211 extern void *ccid_thread (void *arg);
212
213 static void gnuk_malloc_init (void);
214
215
216 extern uint32_t bDeviceState;
217
218 /*
219  * Entry point.
220  */
221 int
222 main (int argc, char *argv[])
223 {
224   unsigned int count = 0;
225   uint32_t entry;
226   chopstx_t ccid_thd;
227
228   (void)argc;
229   (void)argv;
230
231   gnuk_malloc_init ();
232
233   flash_unlock ();
234   device_initialize_once ();
235
236   adc_init ();
237
238   eventflag_init (&led_event);
239
240   random_init ();
241
242 #ifdef DEBUG
243   stdout_init ();
244 #endif
245
246   ccid_thd = chopstx_create (PRIO_CCID, __stackaddr_ccid, __stacksize_ccid,
247                              ccid_thread, NULL);
248
249 #ifdef PINPAD_CIR_SUPPORT
250   cir_init ();
251 #endif
252 #ifdef PINPAD_DND_SUPPORT
253   msc_init ();
254 #endif
255
256   chopstx_setpriority (PRIO_MAIN);
257
258   while (1)
259     {
260       if (bDeviceState != UNCONNECTED)
261         break;
262
263       chopstx_usec_wait (250*1000);
264     }
265
266   while (1)
267     {
268       eventmask_t m;
269
270       m = eventflag_wait_timeout (&led_event, MAIN_TIMEOUT_INTERVAL);
271     got_it:
272       count++;
273       switch (m)
274         {
275         case LED_ONESHOT:
276           if ((m = emit_led (100*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
277           break;
278         case LED_TWOSHOTS:
279           if ((m = emit_led (50*1000, 50*1000))) goto got_it;
280           if ((m = emit_led (50*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
281           break;
282         case LED_SHOW_STATUS:
283           if ((count & 0x07) != 0) continue; /* Display once for eight times */
284           if ((m = display_status_code ())) goto got_it;
285           break;
286         case LED_START_COMMAND:
287           set_led (1);
288           led_inverted = 1;
289           break;
290         case LED_FINISH_COMMAND:
291           m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP);
292           led_inverted = 0;
293           set_led (0);
294           if (m)
295             goto got_it;
296           break;
297         case LED_FATAL:
298           display_fatal_code ();
299           break;
300         case LED_USB_RESET:
301           ccid_usb_reset ();
302           break;
303         case LED_GNUK_EXEC:
304           goto exec;
305         default:
306           if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
307             goto got_it;
308           break;
309         }
310
311 #ifdef DEBUG_MORE
312       if (stdout.connected && (count % 10) == 0)
313         {
314           DEBUG_SHORT (count / 10);
315           _write ("\r\nThis is Gnuk on STM32F103.\r\n"
316                   "Testing USB driver.\n\n"
317                   "Hello world\r\n\r\n", 30+21+15);
318         }
319 #endif
320     }
321
322  exec:
323   random_fini ();
324
325   set_led (1);
326   usb_lld_shutdown ();
327
328   /* Finish application.  */
329   chopstx_join (ccid_thd, NULL);
330
331   /* Set vector */
332   SCB->VTOR = (uint32_t)&_regnual_start;
333   entry = calculate_regnual_entry_address (&_regnual_start);
334 #ifdef DFU_SUPPORT
335 #define FLASH_SYS_START_ADDR 0x08000000
336 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
337 #define CHIP_ID_REG ((uint32_t *)0xE0042000)
338   {
339     extern uint8_t _sys;
340     uint32_t addr;
341     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
342     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
343     uint32_t flash_page_size = 1024; /* 1KiB default */
344
345    if ((*CHIP_ID_ADDR)&0x07 == 0x04) /* High dencity device.  */
346      flash_page_size = 2048; /* It's 2KiB. */
347
348     /* Kill DFU */
349     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
350          addr += flash_page_size)
351       flash_erase_page (addr);
352
353     /* copy system service routines */
354     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
355
356     /* Leave Gnuk to exec reGNUal */
357     (*func) ((void (*)(void))entry);
358     for (;;);
359   }
360 #else
361   /* Leave Gnuk to exec reGNUal */
362   flash_erase_all_and_exec ((void (*)(void))entry);
363 #endif
364
365   /* Never reached */
366   return 0;
367 }
368
369 void
370 fatal (uint8_t code)
371 {
372   extern void _write (const char *s, int len);
373
374   fatal_code = code;
375   eventflag_signal (&led_event, LED_FATAL);
376   _write ("fatal\r\n", 7);
377   for (;;);
378 }
379 \f
380 /*
381  * Malloc for Gnuk.
382  *
383  * Each memory chunk has header with size information.
384  * The size of chunk is at least 16.
385  *
386  * Free memory is managed by FREE_LIST.
387  *
388  * When it is managed in FREE_LIST, three pointers, ->NEXT, ->PREV,
389  * and ->NEIGHBOR is used.  NEXT and PREV is to implement doubly
390  * linked list.  NEIGHBOR is to link adjacent memory chunk to be
391  * reclaimed to system.
392  */
393
394 extern uint8_t __heap_base__[];
395 extern uint8_t __heap_end__[];
396
397 #define MEMORY_END (__heap_end__)
398 #define MEMORY_ALIGNMENT 16
399 #define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1))
400
401 static uint8_t *heap_p;
402 static chopstx_mutex_t malloc_mtx;
403
404 struct mem_head {
405   uint32_t size;
406   /**/
407   struct mem_head *next, *prev; /* free list chain */
408   struct mem_head *neighbor;    /* backlink to neighbor */
409 };
410
411 static struct mem_head *free_list;
412
413 static void
414 gnuk_malloc_init (void)
415 {
416   chopstx_mutex_init (&malloc_mtx);
417   heap_p = __heap_base__;
418   free_list = NULL;
419 }
420
421 static void *
422 sbrk (size_t size)
423 {
424   void *p = (void *)heap_p;
425
426   if ((size_t)(MEMORY_END - heap_p) < size)
427     return NULL;
428
429   heap_p += size;
430   return p;
431 }
432
433 static void
434 remove_from_free_list (struct mem_head *m)
435 {
436   if (m->prev)
437     m->prev->next = m->next;
438   else
439     free_list = m->next;
440   if (m->next)
441     m->next->prev = m->prev;
442 }
443
444
445 void *
446 gnuk_malloc (size_t size)
447 {
448   struct mem_head *m;
449   struct mem_head *m0;
450
451   size = MEMORY_ALIGN (size + sizeof (uint32_t));
452
453   chopstx_mutex_lock (&malloc_mtx);
454   DEBUG_INFO ("malloc: ");
455   DEBUG_SHORT (size);
456   m = free_list;
457
458   while (1)
459     {
460       if (m == NULL)
461         {
462           m = (struct mem_head *)sbrk (size);
463           if (m)
464             m->size = size;
465           break;
466         }
467
468       if (m->size == size)
469         {
470           remove_from_free_list (m);
471           m0 = free_list;
472           while (m0)
473             if (m0->neighbor == m)
474               m0->neighbor = NULL;
475             else
476               m0 = m0->next;
477           break;
478         }
479
480       m = m->next;
481     }
482
483   chopstx_mutex_unlock (&malloc_mtx);
484   if (m == NULL)
485     {
486       DEBUG_WORD (0);
487       return m;
488     }
489   else
490     {
491       DEBUG_WORD ((uint32_t)m + sizeof (uint32_t));
492       return (void *)m + sizeof (uint32_t);
493     }
494 }
495
496
497 void
498 gnuk_free (void *p)
499 {
500   struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uint32_t));
501   struct mem_head *m0;
502
503   chopstx_mutex_lock (&malloc_mtx);
504   m0 = free_list;
505   DEBUG_INFO ("free: ");
506   DEBUG_SHORT (m->size);
507   DEBUG_WORD ((uint32_t)p);
508
509   m->neighbor = NULL;
510   while (m0)
511     {
512       if ((void *)m + m->size == (void *)m0)
513         m0->neighbor = m;
514       else if ((void *)m0 + m0->size == (void *)m)
515         m->neighbor = m0;
516
517       m0 = m0->next;
518     }
519
520   if ((void *)m + m->size == heap_p)
521     {
522       struct mem_head *mn = m->neighbor;
523
524       heap_p -= m->size;
525       while (mn)
526         {
527           heap_p -= mn->size;
528           remove_from_free_list (mn);
529           mn = mn->neighbor;
530         }
531     }
532   else
533     {
534       m->next = free_list;
535       m->prev = NULL;
536       if (free_list)
537         free_list->prev = m;
538       free_list = m;
539     }
540
541   chopstx_mutex_unlock (&malloc_mtx);
542 }