2010-08-10 03:11:02 +00:00
|
|
|
|
/*
|
2010-08-30 02:39:10 +00:00
|
|
|
|
* main.c - main routine of Gnuk
|
|
|
|
|
*
|
2013-03-09 01:04:36 +00:00
|
|
|
|
* Copyright (C) 2010, 2011, 2012, 2013 Free Software Initiative of Japan
|
2010-08-30 02:39:10 +00:00
|
|
|
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
|
|
|
*
|
|
|
|
|
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
|
|
|
*
|
|
|
|
|
* Gnuk is free software: you can redistribute it and/or modify it
|
|
|
|
|
* under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
|
|
|
* License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2010-08-10 03:11:02 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <chopstx.h>
|
|
|
|
|
#include <eventflag.h>
|
|
|
|
|
|
2010-09-04 04:48:26 +00:00
|
|
|
|
#include "config.h"
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
2012-05-25 06:20:08 +00:00
|
|
|
|
#include "sys.h"
|
2013-02-18 06:07:13 +00:00
|
|
|
|
#include "adc.h"
|
2010-08-26 10:50:06 +00:00
|
|
|
|
#include "gnuk.h"
|
2010-09-09 00:51:09 +00:00
|
|
|
|
#include "usb_lld.h"
|
2012-05-11 00:28:04 +00:00
|
|
|
|
#include "usb-cdc.h"
|
2013-02-18 06:07:13 +00:00
|
|
|
|
#include "random.h"
|
2013-06-20 07:19:49 +00:00
|
|
|
|
#include "stm32f103.h"
|
2010-08-10 03:11:02 +00:00
|
|
|
|
|
2010-09-03 15:42:36 +00:00
|
|
|
|
#ifdef DEBUG
|
2013-06-20 07:19:49 +00:00
|
|
|
|
#include "debug.h"
|
2010-09-04 04:48:26 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
struct stdout stdout;
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
stdout_init (void)
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_init (&stdout.m);
|
|
|
|
|
chopstx_mutex_init (&stdout.m_dev);
|
|
|
|
|
chopstx_cond_init (&stdout.cond_dev);
|
|
|
|
|
stdout.connected = 0;
|
2010-08-10 07:30:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-08-26 10:50:06 +00:00
|
|
|
|
void
|
2013-06-20 07:19:49 +00:00
|
|
|
|
_write (const char *s, int len)
|
2010-08-10 07:30:05 +00:00
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
int packet_len;
|
2010-08-10 06:35:34 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if (len == 0)
|
|
|
|
|
return;
|
2010-09-08 05:24:12 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_lock (&stdout.m);
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_lock (&stdout.m_dev);
|
|
|
|
|
if (!stdout.connected)
|
|
|
|
|
chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
|
|
|
|
|
chopstx_mutex_unlock (&stdout.m_dev);
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
do
|
2010-08-10 07:30:05 +00:00
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
packet_len =
|
|
|
|
|
(len < VIRTUAL_COM_PORT_DATA_SIZE) ? len : VIRTUAL_COM_PORT_DATA_SIZE;
|
2010-08-10 08:47:55 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_lock (&stdout.m_dev);
|
|
|
|
|
usb_lld_write (ENDP3, s, packet_len);
|
|
|
|
|
chopstx_cond_wait (&stdout.cond_dev, &stdout.m_dev);
|
|
|
|
|
chopstx_mutex_unlock (&stdout.m_dev);
|
2010-09-08 05:24:12 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
s += packet_len;
|
|
|
|
|
len -= packet_len;
|
2010-08-10 07:30:05 +00:00
|
|
|
|
}
|
2013-06-20 07:19:49 +00:00
|
|
|
|
/* Send a Zero-Length-Packet if the last packet is full size. */
|
|
|
|
|
while (len != 0 || packet_len == VIRTUAL_COM_PORT_DATA_SIZE);
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_unlock (&stdout.m);
|
2010-08-10 07:30:05 +00:00
|
|
|
|
}
|
2012-05-15 01:16:25 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
EP3_IN_Callback (void)
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_lock (&stdout.m_dev);
|
|
|
|
|
chopstx_cond_signal (&stdout.cond_dev);
|
|
|
|
|
chopstx_mutex_unlock (&stdout.m_dev);
|
2012-05-15 01:16:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
EP5_OUT_Callback (void)
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_lock (&stdout.m_dev);
|
2012-05-15 01:16:25 +00:00
|
|
|
|
usb_lld_rx_enable (ENDP5);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_unlock (&stdout.m_dev);
|
2012-05-15 01:16:25 +00:00
|
|
|
|
}
|
2010-09-03 15:42:36 +00:00
|
|
|
|
#else
|
|
|
|
|
void
|
|
|
|
|
_write (const char *s, int size)
|
|
|
|
|
{
|
|
|
|
|
(void)s;
|
|
|
|
|
(void)size;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
extern void *USBthread (void *arg);
|
2010-08-19 08:09:59 +00:00
|
|
|
|
|
2010-09-03 15:42:36 +00:00
|
|
|
|
/*
|
2010-12-09 01:12:54 +00:00
|
|
|
|
* main thread does 1-bit LED display output
|
2010-09-03 15:42:36 +00:00
|
|
|
|
*/
|
2013-06-20 07:19:49 +00:00
|
|
|
|
#define MAIN_TIMEOUT_INTERVAL (5000*1000)
|
2012-06-18 03:24:54 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
#define LED_TIMEOUT_INTERVAL (75*1000)
|
|
|
|
|
#define LED_TIMEOUT_ZERO (25*1000)
|
|
|
|
|
#define LED_TIMEOUT_ONE (100*1000)
|
|
|
|
|
#define LED_TIMEOUT_STOP (200*1000)
|
2010-09-08 05:24:12 +00:00
|
|
|
|
|
2010-09-03 15:42:36 +00:00
|
|
|
|
|
2013-02-15 02:45:52 +00:00
|
|
|
|
/* It has two-byte prefix and content is "FSIJ-1.0.1-" (2 + 11*2). */
|
2012-08-03 02:20:13 +00:00
|
|
|
|
#define ID_OFFSET 24
|
2011-05-11 01:56:36 +00:00
|
|
|
|
static void
|
|
|
|
|
device_initialize_once (void)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *p = &gnukStringSerial[ID_OFFSET];
|
|
|
|
|
|
|
|
|
|
if (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff && p[3] == 0xff)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This is the first time invocation.
|
|
|
|
|
* Setup serial number by unique device ID.
|
|
|
|
|
*/
|
|
|
|
|
const uint8_t *u = unique_device_id ();
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
|
{
|
|
|
|
|
uint8_t b = u[i];
|
2012-06-18 03:24:54 +00:00
|
|
|
|
uint8_t nibble;
|
2011-05-11 01:56:36 +00:00
|
|
|
|
|
|
|
|
|
nibble = (b >> 4);
|
|
|
|
|
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
2011-05-11 07:47:26 +00:00
|
|
|
|
flash_put_data_internal (&p[i*4], nibble);
|
2011-05-11 01:56:36 +00:00
|
|
|
|
nibble = (b & 0x0f);
|
|
|
|
|
nibble += (nibble >= 10 ? ('A' - 10) : '0');
|
2011-05-11 07:47:26 +00:00
|
|
|
|
flash_put_data_internal (&p[i*4+2], nibble);
|
2011-05-11 01:56:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-09 01:12:54 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
static volatile uint8_t fatal_code;
|
|
|
|
|
static struct eventflag led_event;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
|
2012-06-18 03:24:54 +00:00
|
|
|
|
static void display_fatal_code (void)
|
2011-11-01 05:57:11 +00:00
|
|
|
|
{
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (1);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ZERO);
|
2012-06-08 00:48:40 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (1);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ZERO);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (1);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ZERO);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_STOP);
|
2012-06-08 00:48:40 +00:00
|
|
|
|
set_led (1);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
if (fatal_code & 1)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ONE);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
else
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ZERO);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (1);
|
|
|
|
|
if (fatal_code & 2)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ONE);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
else
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_ZERO);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_INTERVAL);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (1);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_STOP);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (0);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_usec_wait (LED_TIMEOUT_INTERVAL*10);
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-18 03:24:54 +00:00
|
|
|
|
static uint8_t led_inverted;
|
|
|
|
|
|
|
|
|
|
static eventmask_t emit_led (int on_time, int off_time)
|
2011-11-01 05:57:11 +00:00
|
|
|
|
{
|
2012-06-18 03:24:54 +00:00
|
|
|
|
eventmask_t m;
|
|
|
|
|
|
|
|
|
|
set_led (!led_inverted);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
m = eventflag_wait_timeout (&led_event, on_time);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
set_led (led_inverted);
|
|
|
|
|
if (m) return m;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if ((m = eventflag_wait_timeout (&led_event, off_time)))
|
2012-06-18 03:24:54 +00:00
|
|
|
|
return m;
|
|
|
|
|
return 0;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-06-18 03:24:54 +00:00
|
|
|
|
static eventmask_t display_status_code (void)
|
2011-11-01 05:57:11 +00:00
|
|
|
|
{
|
2012-01-20 09:18:23 +00:00
|
|
|
|
enum icc_state icc_state;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
eventmask_t m;
|
2012-01-20 09:18:23 +00:00
|
|
|
|
|
|
|
|
|
if (icc_state_p == NULL)
|
|
|
|
|
icc_state = ICC_STATE_START;
|
|
|
|
|
else
|
|
|
|
|
icc_state = *icc_state_p;
|
|
|
|
|
|
2011-11-01 05:57:11 +00:00
|
|
|
|
if (icc_state == ICC_STATE_START)
|
2012-06-18 03:24:54 +00:00
|
|
|
|
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
|
2011-11-01 05:57:11 +00:00
|
|
|
|
else
|
|
|
|
|
/* GPGthread running */
|
|
|
|
|
{
|
2012-06-18 03:24:54 +00:00
|
|
|
|
if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
|
|
|
|
|
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
|
|
|
|
LED_TIMEOUT_INTERVAL)))
|
|
|
|
|
return m;
|
|
|
|
|
if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
|
|
|
|
|
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
|
|
|
|
LED_TIMEOUT_INTERVAL)))
|
|
|
|
|
return m;
|
|
|
|
|
if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
|
|
|
|
|
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
|
|
|
|
LED_TIMEOUT_INTERVAL)))
|
|
|
|
|
return m;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
|
|
|
|
|
if (icc_state == ICC_STATE_WAIT)
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP * 2)))
|
2012-06-18 03:24:54 +00:00
|
|
|
|
return m;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if ((m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_INTERVAL)))
|
2012-06-18 03:24:54 +00:00
|
|
|
|
return m;
|
|
|
|
|
|
|
|
|
|
if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
|
|
|
|
|
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
|
|
|
|
|
LED_TIMEOUT_STOP)))
|
|
|
|
|
return m;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
2012-06-18 03:24:54 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
led_blink (int spec)
|
|
|
|
|
{
|
2013-06-20 07:19:49 +00:00
|
|
|
|
eventflag_signal (&led_event, spec);
|
2011-11-01 05:57:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-09 01:04:36 +00:00
|
|
|
|
/*
|
|
|
|
|
* In Gnuk 1.0.[12], reGNUal was not relocatable.
|
|
|
|
|
* Now, it's relocatable, but we need to calculate its entry address
|
|
|
|
|
* based on it's pre-defined address.
|
|
|
|
|
*/
|
|
|
|
|
#define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
|
|
|
|
|
static uint32_t
|
|
|
|
|
calculate_regnual_entry_address (const uint8_t *addr)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *p = addr + 4;
|
|
|
|
|
uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
|
|
|
|
|
|
|
|
|
|
v -= REGNUAL_START_ADDRESS_COMPATIBLE;
|
|
|
|
|
v += (uint32_t)addr;
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
2013-07-19 04:40:49 +00:00
|
|
|
|
extern uint8_t __process4_stack_base__, __process4_stack_size__;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
const uint32_t __stackaddr_ccid = (uint32_t)&__process1_stack_base__;
|
|
|
|
|
const size_t __stacksize_ccid = (size_t)&__process1_stack_size__;
|
|
|
|
|
|
2013-07-19 04:40:49 +00:00
|
|
|
|
const uint32_t __stackaddr_usb = (uint32_t)&__process4_stack_base__;
|
|
|
|
|
const size_t __stacksize_usb = (size_t)&__process4_stack_size__;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
#define PRIO_CCID 2
|
|
|
|
|
#define PRIO_USB 4
|
|
|
|
|
|
|
|
|
|
extern void *usb_intr (void *arg);
|
|
|
|
|
|
|
|
|
|
static void gnuk_malloc_init (void);
|
|
|
|
|
|
2012-05-23 05:55:04 +00:00
|
|
|
|
|
2010-08-10 03:11:02 +00:00
|
|
|
|
/*
|
2010-12-09 01:12:54 +00:00
|
|
|
|
* Entry point.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: the main function is already a thread in the system on entry.
|
|
|
|
|
* See the hwinit1_common function.
|
2010-08-10 03:11:02 +00:00
|
|
|
|
*/
|
2010-08-30 02:39:10 +00:00
|
|
|
|
int
|
2012-05-18 07:54:17 +00:00
|
|
|
|
main (int argc, char *argv[])
|
2010-08-10 07:30:05 +00:00
|
|
|
|
{
|
2012-06-18 05:04:34 +00:00
|
|
|
|
unsigned int count = 0;
|
2013-03-09 01:04:36 +00:00
|
|
|
|
uint32_t entry;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_t usb_thd;
|
|
|
|
|
chopstx_t ccid_thd;
|
2010-08-10 03:11:02 +00:00
|
|
|
|
|
|
|
|
|
(void)argc;
|
|
|
|
|
(void)argv;
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
gnuk_malloc_init ();
|
|
|
|
|
|
2011-05-16 01:14:09 +00:00
|
|
|
|
flash_unlock ();
|
2011-05-11 01:56:36 +00:00
|
|
|
|
device_initialize_once ();
|
2013-02-18 06:07:13 +00:00
|
|
|
|
|
|
|
|
|
adc_init ();
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
eventflag_init (&led_event, chopstx_main);
|
2013-02-18 06:07:13 +00:00
|
|
|
|
|
2011-10-06 07:56:08 +00:00
|
|
|
|
random_init ();
|
2010-08-10 03:11:02 +00:00
|
|
|
|
|
2010-09-04 09:44:01 +00:00
|
|
|
|
#ifdef DEBUG
|
2010-08-10 07:30:05 +00:00
|
|
|
|
stdout_init ();
|
2010-09-03 15:42:36 +00:00
|
|
|
|
#endif
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
ccid_thd = chopstx_create (PRIO_CCID, __stackaddr_ccid,
|
|
|
|
|
__stacksize_ccid, USBthread, NULL);
|
|
|
|
|
|
|
|
|
|
usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
|
|
|
|
|
usb_intr, NULL);
|
2010-08-18 05:21:58 +00:00
|
|
|
|
|
2011-12-12 09:12:43 +00:00
|
|
|
|
#ifdef PINPAD_DND_SUPPORT
|
|
|
|
|
msc_init ();
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
if (bDeviceState != UNCONNECTED)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
chopstx_usec_wait (250*1000);
|
|
|
|
|
}
|
2012-06-18 03:24:54 +00:00
|
|
|
|
|
2010-08-10 07:30:05 +00:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
2011-11-01 05:57:11 +00:00
|
|
|
|
eventmask_t m;
|
2010-09-08 05:24:12 +00:00
|
|
|
|
|
2012-05-18 07:54:17 +00:00
|
|
|
|
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
|
|
|
|
|
break;
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
m = eventflag_wait_timeout (&led_event, MAIN_TIMEOUT_INTERVAL);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
got_it:
|
2012-06-18 05:04:34 +00:00
|
|
|
|
count++;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
switch (m)
|
2010-12-09 01:12:54 +00:00
|
|
|
|
{
|
2012-06-18 03:24:54 +00:00
|
|
|
|
case LED_ONESHOT:
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if ((m = emit_led (100*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
case LED_TWOSHOTS:
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if ((m = emit_led (50*1000, 50*1000))) goto got_it;
|
|
|
|
|
if ((m = emit_led (50*1000, MAIN_TIMEOUT_INTERVAL))) goto got_it;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
case LED_SHOW_STATUS:
|
2012-06-18 05:12:00 +00:00
|
|
|
|
if ((count & 0x07) != 0) continue; /* Display once for eight times */
|
2012-06-18 03:24:54 +00:00
|
|
|
|
if ((m = display_status_code ())) goto got_it;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
case LED_START_COMMAND:
|
2010-12-09 01:12:54 +00:00
|
|
|
|
set_led (1);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
led_inverted = 1;
|
|
|
|
|
break;
|
|
|
|
|
case LED_FINISH_COMMAND:
|
2013-06-20 07:19:49 +00:00
|
|
|
|
m = eventflag_wait_timeout (&led_event, LED_TIMEOUT_STOP);
|
2012-06-18 03:24:54 +00:00
|
|
|
|
led_inverted = 0;
|
2010-12-09 01:12:54 +00:00
|
|
|
|
set_led (0);
|
2012-06-18 03:44:37 +00:00
|
|
|
|
if (m)
|
2012-06-18 03:24:54 +00:00
|
|
|
|
goto got_it;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
case LED_FATAL:
|
|
|
|
|
display_fatal_code ();
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2012-06-18 03:24:54 +00:00
|
|
|
|
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
|
|
|
|
|
goto got_it;
|
2011-11-01 05:57:11 +00:00
|
|
|
|
break;
|
2012-06-18 03:24:54 +00:00
|
|
|
|
}
|
2010-08-10 07:30:05 +00:00
|
|
|
|
|
2010-09-05 16:55:29 +00:00
|
|
|
|
#ifdef DEBUG_MORE
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if (stdout.connected && (count % 10) == 0)
|
2010-08-10 08:47:55 +00:00
|
|
|
|
{
|
2010-12-09 01:12:54 +00:00
|
|
|
|
DEBUG_SHORT (count / 10);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
_write ("\r\nThis is Gnuk on STM32F103.\r\n"
|
2010-08-10 08:47:55 +00:00
|
|
|
|
"Testing USB driver.\n\n"
|
2013-06-20 07:19:49 +00:00
|
|
|
|
"Hello world\r\n\r\n", 30+21+15);
|
2010-08-10 08:47:55 +00:00
|
|
|
|
}
|
2010-09-05 16:55:29 +00:00
|
|
|
|
#endif
|
2010-08-10 06:35:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-26 01:25:32 +00:00
|
|
|
|
random_fini ();
|
|
|
|
|
|
2012-05-23 03:17:11 +00:00
|
|
|
|
set_led (1);
|
2012-05-18 07:54:17 +00:00
|
|
|
|
usb_lld_shutdown ();
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
/* Finish application. */
|
|
|
|
|
chopstx_join (ccid_thd, NULL);
|
|
|
|
|
|
|
|
|
|
chopstx_cancel (usb_thd);
|
|
|
|
|
chopstx_join (usb_thd, NULL);
|
|
|
|
|
|
2012-05-26 11:15:07 +00:00
|
|
|
|
/* Set vector */
|
2012-05-18 17:05:31 +00:00
|
|
|
|
SCB->VTOR = (uint32_t)&_regnual_start;
|
2013-03-09 01:04:36 +00:00
|
|
|
|
entry = calculate_regnual_entry_address (&_regnual_start);
|
2012-05-29 01:07:23 +00:00
|
|
|
|
#ifdef DFU_SUPPORT
|
|
|
|
|
#define FLASH_SYS_START_ADDR 0x08000000
|
|
|
|
|
#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
|
|
|
|
|
{
|
|
|
|
|
extern uint8_t _sys;
|
|
|
|
|
uint32_t addr;
|
|
|
|
|
handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
|
2013-07-19 03:18:46 +00:00
|
|
|
|
void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
|
2012-05-29 01:07:23 +00:00
|
|
|
|
|
|
|
|
|
/* Kill DFU */
|
|
|
|
|
for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
|
|
|
|
|
addr += FLASH_PAGE_SIZE)
|
|
|
|
|
flash_erase_page (addr);
|
|
|
|
|
|
|
|
|
|
/* copy system service routines */
|
|
|
|
|
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
|
|
|
|
|
|
2012-06-18 03:24:54 +00:00
|
|
|
|
/* Leave Gnuk to exec reGNUal */
|
2013-03-09 01:04:36 +00:00
|
|
|
|
(*func) ((void (*)(void))entry);
|
2012-05-29 01:07:23 +00:00
|
|
|
|
for (;;);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2012-06-18 03:24:54 +00:00
|
|
|
|
/* Leave Gnuk to exec reGNUal */
|
2013-03-09 01:04:36 +00:00
|
|
|
|
flash_erase_all_and_exec ((void (*)(void))entry);
|
2012-05-29 01:07:23 +00:00
|
|
|
|
#endif
|
2012-05-18 17:05:31 +00:00
|
|
|
|
|
2012-05-23 05:55:04 +00:00
|
|
|
|
/* Never reached */
|
2010-08-10 03:11:02 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-09-03 15:42:36 +00:00
|
|
|
|
|
|
|
|
|
void
|
2010-12-09 01:12:54 +00:00
|
|
|
|
fatal (uint8_t code)
|
2010-09-03 15:42:36 +00:00
|
|
|
|
{
|
2010-12-09 01:12:54 +00:00
|
|
|
|
fatal_code = code;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
eventflag_signal (&led_event, LED_FATAL);
|
2010-09-03 15:42:36 +00:00
|
|
|
|
_write ("fatal\r\n", 7);
|
|
|
|
|
for (;;);
|
|
|
|
|
}
|
2013-07-19 02:45:18 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Malloc for Gnuk.
|
|
|
|
|
*
|
|
|
|
|
* Each memory chunk has header with size information.
|
|
|
|
|
* The size of chunk is at least 16.
|
|
|
|
|
*
|
|
|
|
|
* Free memory is managed by FREE_LIST.
|
|
|
|
|
*
|
|
|
|
|
* When it is managed in FREE_LIST, three pointers, ->NEXT, ->PREV,
|
|
|
|
|
* and ->NEIGHBOR is used. NEXT and PREV is to implement doubly
|
|
|
|
|
* linked list. NEIGHBOR is to link adjacent memory chunk to be
|
|
|
|
|
* reclaimed to system.
|
|
|
|
|
*/
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
extern uint8_t __heap_base__[];
|
|
|
|
|
extern uint8_t __heap_end__[];
|
|
|
|
|
|
|
|
|
|
#define MEMORY_END (__heap_end__)
|
2013-07-18 06:21:36 +00:00
|
|
|
|
#define MEMORY_ALIGNMENT 16
|
|
|
|
|
#define MEMORY_ALIGN(n) (((n) + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1))
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
static uint8_t *heap_p;
|
|
|
|
|
static chopstx_mutex_t malloc_mtx;
|
|
|
|
|
|
|
|
|
|
struct mem_head {
|
2013-07-19 02:45:18 +00:00
|
|
|
|
uint32_t size;
|
|
|
|
|
/**/
|
|
|
|
|
struct mem_head *next, *prev; /* free list chain */
|
|
|
|
|
struct mem_head *neighbor; /* backlink to neighbor */
|
|
|
|
|
};
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
static struct mem_head *free_list;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gnuk_malloc_init (void)
|
|
|
|
|
{
|
|
|
|
|
chopstx_mutex_init (&malloc_mtx);
|
|
|
|
|
heap_p = __heap_base__;
|
2013-07-19 02:45:18 +00:00
|
|
|
|
free_list = NULL;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
static void *
|
|
|
|
|
sbrk (size_t size)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
{
|
|
|
|
|
void *p = (void *)heap_p;
|
|
|
|
|
|
2013-07-18 06:21:36 +00:00
|
|
|
|
if ((size_t)(MEMORY_END - heap_p) < size)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
heap_p += size;
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
static void
|
|
|
|
|
remove_from_free_list (struct mem_head *m)
|
|
|
|
|
{
|
|
|
|
|
if (m->prev)
|
|
|
|
|
m->prev->next = m->next;
|
|
|
|
|
else
|
|
|
|
|
free_list = m->next;
|
|
|
|
|
if (m->next)
|
|
|
|
|
m->next->prev = m->prev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
void *
|
|
|
|
|
gnuk_malloc (size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct mem_head *m;
|
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
size = MEMORY_ALIGN (size + sizeof (uint32_t));
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
chopstx_mutex_lock (&malloc_mtx);
|
|
|
|
|
DEBUG_INFO ("malloc: ");
|
|
|
|
|
DEBUG_SHORT (size);
|
2013-07-19 02:45:18 +00:00
|
|
|
|
m = free_list;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2013-07-19 02:45:18 +00:00
|
|
|
|
if (m == NULL)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
{
|
2013-07-19 02:45:18 +00:00
|
|
|
|
m = (struct mem_head *)sbrk (size);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
if (m)
|
2013-07-19 02:45:18 +00:00
|
|
|
|
m->size = size;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-18 06:21:36 +00:00
|
|
|
|
if (m->size == size)
|
2013-06-20 07:19:49 +00:00
|
|
|
|
{
|
2013-07-19 02:45:18 +00:00
|
|
|
|
remove_from_free_list (m);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
m = m->next;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chopstx_mutex_unlock (&malloc_mtx);
|
|
|
|
|
if (m == NULL)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_WORD (0);
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-07-19 02:45:18 +00:00
|
|
|
|
DEBUG_WORD ((uint32_t)m + sizeof (uint32_t));
|
|
|
|
|
return (void *)m + sizeof (uint32_t);
|
2013-06-20 07:19:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-19 02:45:18 +00:00
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
void
|
|
|
|
|
gnuk_free (void *p)
|
|
|
|
|
{
|
2013-07-19 02:45:18 +00:00
|
|
|
|
struct mem_head *m = (struct mem_head *)((void *)p - sizeof (uint32_t));
|
|
|
|
|
struct mem_head *m0 = free_list;
|
2013-06-20 07:19:49 +00:00
|
|
|
|
|
|
|
|
|
chopstx_mutex_lock (&malloc_mtx);
|
|
|
|
|
DEBUG_INFO ("free: ");
|
|
|
|
|
DEBUG_SHORT (m->size);
|
|
|
|
|
DEBUG_WORD ((uint32_t)p);
|
2013-07-19 02:45:18 +00:00
|
|
|
|
|
|
|
|
|
m->neighbor = NULL;
|
|
|
|
|
while (m0)
|
|
|
|
|
{
|
|
|
|
|
if ((void *)m + m->size == (void *)m0)
|
|
|
|
|
m0->neighbor = m;
|
|
|
|
|
else if ((void *)m0 + m0->size == (void *)m)
|
|
|
|
|
m->neighbor = m0;
|
|
|
|
|
|
|
|
|
|
m0 = m0->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((void *)m + m->size == heap_p)
|
|
|
|
|
{
|
|
|
|
|
struct mem_head *mn = m->neighbor;
|
|
|
|
|
|
|
|
|
|
heap_p -= m->size;
|
|
|
|
|
while (mn)
|
|
|
|
|
{
|
|
|
|
|
heap_p -= mn->size;
|
|
|
|
|
remove_from_free_list (mn);
|
|
|
|
|
mn = mn->neighbor;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m->next = free_list;
|
|
|
|
|
m->prev = NULL;
|
|
|
|
|
if (free_list)
|
|
|
|
|
free_list->prev = m;
|
|
|
|
|
free_list = m;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-20 07:19:49 +00:00
|
|
|
|
chopstx_mutex_unlock (&malloc_mtx);
|
|
|
|
|
}
|