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