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