Add ST_DONGLE and ST_NUCLEO_F103
[gnuk/gnuk.git] / src / main.c
1 /*
2  * main.c - main routine of Gnuk
3  *
4  * Copyright (C) 2010, 2011, 2012, 2013, 2015
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 #ifdef DEBUG
41 #include "debug.h"
42
43 struct stdout stdout;
44
45 static void
46 stdout_init (void)
47 {
48   chopstx_mutex_init (&stdout.m);
49   chopstx_mutex_init (&stdout.m_dev);
50   chopstx_cond_init (&stdout.cond_dev);
51   stdout.connected = 0;
52 }
53
54 void
55 _write (const char *s, int len)
56 {
57   int packet_len;
58
59   if (len == 0)
60     return;
61
62   chopstx_mutex_lock (&stdout.m);
63
64   chopstx_mutex_lock (&stdout.m_dev);
65   if (!stdout.connected)
66     chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
67   chopstx_mutex_unlock (&stdout.m_dev);
68
69   do
70     {
71       packet_len =
72         (len < VIRTUAL_COM_PORT_DATA_SIZE) ? len : VIRTUAL_COM_PORT_DATA_SIZE;
73
74       chopstx_mutex_lock (&stdout.m_dev);     
75       usb_lld_write (ENDP3, s, packet_len);
76       chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
77       chopstx_mutex_unlock (&stdout.m_dev);
78
79       s += packet_len;
80       len -= packet_len;
81     }
82   /* Send a Zero-Length-Packet if the last packet is full size.  */
83   while (len != 0 || packet_len == VIRTUAL_COM_PORT_DATA_SIZE);
84
85   chopstx_mutex_unlock (&stdout.m);
86 }
87
88 void
89 EP3_IN_Callback (void)
90 {
91   chopstx_mutex_lock (&stdout.m_dev);
92   chopstx_cond_signal (&stdout.cond_dev);
93   chopstx_mutex_unlock (&stdout.m_dev);
94 }
95
96 void
97 EP5_OUT_Callback (void)
98 {
99   chopstx_mutex_lock (&stdout.m_dev);
100   usb_lld_rx_enable (ENDP5);
101   chopstx_mutex_unlock (&stdout.m_dev);
102 }
103 #else
104 void
105 _write (const char *s, int size)
106 {
107   (void)s;
108   (void)size;
109 }
110 #endif
111
112 extern void *USBthread (void *arg);
113
114 /*
115  * main thread does 1-bit LED display output
116  */
117 #define MAIN_TIMEOUT_INTERVAL   (5000*1000)
118
119 #define LED_TIMEOUT_INTERVAL    (75*1000)
120 #define LED_TIMEOUT_ZERO        (25*1000)
121 #define LED_TIMEOUT_ONE         (100*1000)
122 #define LED_TIMEOUT_STOP        (200*1000)
123
124
125 #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
126 static void
127 device_initialize_once (void)
128 {
129   const uint8_t *p = &gnuk_string_serial[ID_OFFSET];
130
131   if (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff)
132     {
133       /*
134        * This is the first time invocation.
135        * Setup serial number by unique device ID.
136        */
137       const uint8_t *u = unique_device_id () + 8;
138       int i;
139
140       for (i = 0; i < 4; i++)
141         {
142           uint8_t b = u[3-i];
143           uint8_t nibble;
144
145           nibble = (b >> 4);
146           nibble += (nibble >= 10 ? ('A' - 10) : '0');
147           flash_put_data_internal (&p[i*4], nibble);
148           nibble = (b & 0x0f);
149           nibble += (nibble >= 10 ? ('A' - 10) : '0');
150           flash_put_data_internal (&p[i*4+2], nibble);
151         }
152     }
153 }
154
155
156 static volatile uint8_t fatal_code;
157 static struct eventflag led_event;
158
159 static void display_fatal_code (void)
160 {
161   while (1)
162     {
163       set_led (1);
164       chopstx_usec_wait (LED_TIMEOUT_ZERO);
165       set_led (0);
166       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
167       set_led (1);
168       chopstx_usec_wait (LED_TIMEOUT_ZERO);
169       set_led (0);
170       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
171       set_led (1);
172       chopstx_usec_wait (LED_TIMEOUT_ZERO);
173       set_led (0);
174       chopstx_usec_wait (LED_TIMEOUT_STOP);
175       set_led (1);
176       if (fatal_code & 1)
177         chopstx_usec_wait (LED_TIMEOUT_ONE);
178       else
179         chopstx_usec_wait (LED_TIMEOUT_ZERO);
180       set_led (0);
181       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
182       set_led (1);
183       if (fatal_code & 2)
184         chopstx_usec_wait (LED_TIMEOUT_ONE);
185       else
186         chopstx_usec_wait (LED_TIMEOUT_ZERO);
187       set_led (0);
188       chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
189       set_led (1);
190       chopstx_usec_wait (LED_TIMEOUT_STOP);
191       set_led (0);
192       chopstx_usec_wait (LED_TIMEOUT_INTERVAL*10);
193     }
194 }
195
196 static uint8_t led_inverted;
197
198 static eventmask_t emit_led (int on_time, int off_time)
199 {
200   eventmask_t m;
201
202   set_led (!led_inverted);
203   m = eventflag_wait_timeout (&led_event, on_time);
204   set_led (led_inverted);
205   if (m) return m;
206   if ((m = eventflag_wait_timeout (&led_event, off_time)))
207     return m;
208   return 0;
209 }
210
211 static eventmask_t display_status_code (void)
212 {
213   enum icc_state icc_state;
214   eventmask_t m;
215
216   if (icc_state_p == NULL)
217     icc_state = ICC_STATE_START;
218   else
219     icc_state = *icc_state_p;
220
221   if (icc_state == ICC_STATE_START)
222     return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
223   else
224     /* OpenPGP card thread  running */
225     {
226       if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
227                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
228                           LED_TIMEOUT_INTERVAL)))
229         return m;
230       if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
231                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
232                           LED_TIMEOUT_INTERVAL)))
233         return m;
234       if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
235                           LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
236                           LED_TIMEOUT_INTERVAL)))
237         return m;
238
239       if (icc_state == ICC_STATE_WAIT)
240         {
241           if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP * 2)))
242             return m;
243         }
244       else
245         {
246           if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL)))
247             return m;
248
249           if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
250                               LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
251                               LED_TIMEOUT_STOP)))
252             return m;
253         }
254
255       return 0;
256     }
257 }
258
259 void
260 led_blink (int spec)
261 {
262   eventflag_signal (&led_event, spec);
263 }
264
265 /*
266  * In Gnuk 1.0.[12], reGNUal was not relocatable.
267  * Now, it's relocatable, but we need to calculate its entry address
268  * based on it's pre-defined address.
269  */
270 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
271 static uint32_t
272 calculate_regnual_entry_address (const uint8_t *addr)
273 {
274   const uint8_t *p = addr + 4;
275   uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
276
277   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
278   v += (uint32_t)addr;
279   return v;
280 }
281
282 extern uint8_t __process1_stack_base__, __process1_stack_size__;
283 extern uint8_t __process4_stack_base__, __process4_stack_size__;
284
285 const uint32_t __stackaddr_ccid = (uint32_t)&__process1_stack_base__;
286 const size_t __stacksize_ccid = (size_t)&__process1_stack_size__;
287
288 const uint32_t __stackaddr_usb = (uint32_t)&__process4_stack_base__;
289 const size_t __stacksize_usb = (size_t)&__process4_stack_size__;
290
291 #define PRIO_CCID 3
292 #define PRIO_USB  4
293 #define PRIO_MAIN 5 
294
295 extern void *usb_intr (void *arg);
296
297 static void gnuk_malloc_init (void);
298
299
300 extern uint32_t bDeviceState;
301
302 /*
303  * Entry point.
304  *
305  * NOTE: the main function is already a thread in the system on entry.
306  *       See the hwinit1_common function.
307  */
308 int
309 main (int argc, char *argv[])
310 {
311   unsigned int count = 0;
312   uint32_t entry;
313   chopstx_t usb_thd;
314   chopstx_t ccid_thd;
315
316   (void)argc;
317   (void)argv;
318
319   gnuk_malloc_init ();
320
321   flash_unlock ();
322   device_initialize_once ();
323
324   adc_init ();
325
326   eventflag_init (&led_event, chopstx_main);
327
328   random_init ();
329
330 #ifdef DEBUG
331   stdout_init ();
332 #endif
333
334   ccid_thd = chopstx_create (PRIO_CCID, __stackaddr_ccid,
335                              __stacksize_ccid, USBthread, NULL);
336
337 #ifdef PINPAD_CIR_SUPPORT
338   cir_init ();
339 #endif
340 #ifdef PINPAD_DND_SUPPORT
341   msc_init ();
342 #endif
343
344   usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
345                             usb_intr, NULL);
346
347   chopstx_main_init (PRIO_MAIN);
348
349   while (1)
350     {
351       if (bDeviceState != UNCONNECTED)
352         break;
353
354       chopstx_usec_wait (250*1000);
355     }
356
357   while (1)
358     {
359       eventmask_t m;
360
361       if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
362         break;
363
364       m = eventflag_wait_timeout (&led_event, MAIN_TIMEOUT_INTERVAL);
365     got_it:
366       count++;
367       switch (m)
368         {
369         case LED_ONESHOT:
370           if ((m = emit_led (100*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
371           break;
372         case LED_TWOSHOTS:
373           if ((m = emit_led (50*1000, 50*1000))) goto got_it;
374           if ((m = emit_led (50*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
375           break;
376         case LED_SHOW_STATUS:
377           if ((count & 0x07) != 0) continue; /* Display once for eight times */
378           if ((m = display_status_code ())) goto got_it;
379           break;
380         case LED_START_COMMAND:
381           set_led (1);
382           led_inverted = 1;
383           break;
384         case LED_FINISH_COMMAND:
385           m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP);
386           led_inverted = 0;
387           set_led (0);
388           if (m)
389             goto got_it;
390           break;
391         case LED_FATAL:
392           display_fatal_code ();
393           break;
394         default:
395           if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
396             goto got_it;
397           break;
398         }
399
400 #ifdef DEBUG_MORE
401       if (stdout.connected && (count % 10) == 0)
402         {
403           DEBUG_SHORT (count / 10);
404           _write ("\r\nThis is Gnuk on STM32F103.\r\n"
405                   "Testing USB driver.\n\n"
406                   "Hello world\r\n\r\n", 30+21+15);
407         }
408 #endif
409     }
410
411   random_fini ();
412
413   set_led (1);
414   usb_lld_shutdown ();
415
416   /* Finish application.  */
417   chopstx_join (ccid_thd, NULL);
418
419   chopstx_cancel (usb_thd);
420   chopstx_join (usb_thd, NULL);
421
422   /* Set vector */
423   SCB->VTOR = (uint32_t)&_regnual_start;
424   entry = calculate_regnual_entry_address (&_regnual_start);
425 #ifdef DFU_SUPPORT
426 #define FLASH_SYS_START_ADDR 0x08000000
427 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
428 #define CHIP_ID_REG ((uint32_t *)0xE0042000)
429   {
430     extern uint8_t _sys;
431     uint32_t addr;
432     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
433     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
434     uint32_t flash_page_size = 1024; /* 1KiB default */
435
436    if ((*CHIP_ID_ADDR)&0x07 == 0x04) /* High dencity device.  */
437      flash_page_size = 2048; /* It's 2KiB. */
438
439     /* Kill DFU */
440     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
441          addr += flash_page_size)
442       flash_erase_page (addr);
443
444     /* copy system service routines */
445     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
446
447     /* Leave Gnuk to exec reGNUal */
448     (*func) ((void (*)(void))entry);
449     for (;;);
450   }
451 #else
452   /* Leave Gnuk to exec reGNUal */
453   flash_erase_all_and_exec ((void (*)(void))entry);
454 #endif
455
456   /* Never reached */
457   return 0;
458 }
459
460 void
461 fatal (uint8_t code)
462 {
463   fatal_code = code;
464   eventflag_signal (&led_event, LED_FATAL);
465   _write ("fatal\r\n", 7);
466   for (;;);
467 }
468 \f
469 /*
470  * Malloc for Gnuk.
471  *
472  * Each memory chunk has header with size information.
473  * The size of chunk is at least 16.
474  *
475  * Free memory is managed by FREE_LIST.
476  *
477  * When it is managed in FREE_LIST, three pointers, ->NEXT, ->PREV,
478  * and ->NEIGHBOR is used.  NEXT and PREV is to implement doubly
479  * linked list.  NEIGHBOR is to link adjacent memory chunk to be
480  * reclaimed to system.
481  */
482
483 extern uint8_t __heap_base__[];
484 extern uint8_t __heap_end__[];
485
486 #define MEMORY_END (__heap_end__)
487 #define MEMORY_ALIGNMENT 16
488 #define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1))
489
490 static uint8_t *heap_p;
491 static chopstx_mutex_t malloc_mtx;
492
493 struct mem_head {
494   uint32_t size;
495   /**/
496   struct mem_head *next, *prev; /* free list chain */
497   struct mem_head *neighbor;    /* backlink to neighbor */
498 };
499
500 static struct mem_head *free_list;
501
502 static void
503 gnuk_malloc_init (void)
504 {
505   chopstx_mutex_init (&malloc_mtx);
506   heap_p = __heap_base__;
507   free_list = NULL;
508 }
509
510 static void *
511 sbrk (size_t size)
512 {
513   void *p = (void *)heap_p;
514
515   if ((size_t)(MEMORY_END - heap_p) < size)
516     return NULL;
517
518   heap_p += size;
519   return p;
520 }
521
522 static void
523 remove_from_free_list (struct mem_head *m)
524 {
525   if (m->prev)
526     m->prev->next = m->next;
527   else
528     free_list = m->next;
529   if (m->next)
530     m->next->prev = m->prev;
531 }
532
533
534 void *
535 gnuk_malloc (size_t size)
536 {
537   struct mem_head *m;
538   struct mem_head *m0;
539
540   size = MEMORY_ALIGN (size + sizeof (uint32_t));
541
542   chopstx_mutex_lock (&malloc_mtx);
543   DEBUG_INFO ("malloc: ");
544   DEBUG_SHORT (size);
545   m = free_list;
546
547   while (1)
548     {
549       if (m == NULL)
550         {
551           m = (struct mem_head *)sbrk (size);
552           if (m)
553             m->size = size;
554           break;
555         }
556
557       if (m->size == size)
558         {
559           remove_from_free_list (m);
560           m0 = free_list;
561           while (m0)
562             if (m0->neighbor == m)
563               m0->neighbor = NULL;
564             else
565               m0 = m0->next;
566           break;
567         }
568
569       m = m->next;
570     }
571
572   chopstx_mutex_unlock (&malloc_mtx);
573   if (m == NULL)
574     {
575       DEBUG_WORD (0);
576       return m;
577     }
578   else
579     {
580       DEBUG_WORD ((uint32_t)m + sizeof (uint32_t));
581       return (void *)m + sizeof (uint32_t);
582     }
583 }
584
585
586 void
587 gnuk_free (void *p)
588 {
589   struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uint32_t));
590   struct mem_head *m0;
591
592   chopstx_mutex_lock (&malloc_mtx);
593   m0 = free_list;
594   DEBUG_INFO ("free: ");
595   DEBUG_SHORT (m->size);
596   DEBUG_WORD ((uint32_t)p);
597
598   m->neighbor = NULL;
599   while (m0)
600     {
601       if ((void *)m + m->size == (void *)m0)
602         m0->neighbor = m;
603       else if ((void *)m0 + m0->size == (void *)m)
604         m->neighbor = m0;
605
606       m0 = m0->next;
607     }
608
609   if ((void *)m + m->size == heap_p)
610     {
611       struct mem_head *mn = m->neighbor;
612
613       heap_p -= m->size;
614       while (mn)
615         {
616           heap_p -= mn->size;
617           remove_from_free_list (mn);
618           mn = mn->neighbor;
619         }
620     }
621   else
622     {
623       m->next = free_list;
624       m->prev = NULL;
625       if (free_list)
626         free_list->prev = m;
627       free_list = m;
628     }
629
630   chopstx_mutex_unlock (&malloc_mtx);
631 }