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