gnuk/regnual/regnual.c

385 lines
9.0 KiB
C
Raw Normal View History

2012-05-18 17:07:31 +00:00
/*
* regnual.c -- Firmware installation for STM32F103 Flash ROM
*
2016-03-08 02:58:43 +00:00
* Copyright (C) 2012, 2013, 2015, 2016
2015-07-31 07:13:06 +00:00
* Free Software Initiative of Japan
2012-05-18 17:07:31 +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/>.
*
*/
/*
* ReGNUal
*/
2012-05-22 01:44:37 +00:00
#include "types.h"
2012-05-18 17:07:31 +00:00
#include "usb_lld.h"
2012-05-25 06:20:08 +00:00
#include "sys.h"
2012-05-18 17:07:31 +00:00
extern void *memset (void *s, int c, size_t n);
2012-05-22 08:02:54 +00:00
extern void set_led (int);
extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len);
2012-05-23 06:25:20 +00:00
extern int flash_protect (void);
2012-05-22 08:02:54 +00:00
extern void nvic_system_reset (void);
2015-07-31 07:13:06 +00:00
#define FLASH_START_ADDR 0x08000000 /* Fixed for all STM32F1. */
#define FLASH_OFFSET 0x1000 /* First pages are not-writable. */
#define FLASH_START (FLASH_START_ADDR+FLASH_OFFSET)
#define FLASH_SIZE_REG ((uint16_t *)0x1ffff7e0)
static uint32_t flash_end;
2012-05-18 17:07:31 +00:00
#define ENDP0_RXADDR (0x40)
#define ENDP0_TXADDR (0x80)
/* USB Standard Device Descriptor */
static const uint8_t regnual_device_desc[] = {
18, /* bLength */
2016-03-08 02:58:43 +00:00
DEVICE_DESCRIPTOR, /* bDescriptorType */
2012-05-18 17:07:31 +00:00
0x10, 0x01, /* bcdUSB = 1.1 */
0xFF, /* bDeviceClass: VENDOR */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
2012-05-22 02:20:16 +00:00
#include "../src/usb-vid-pid-ver.c.inc"
2012-05-18 17:07:31 +00:00
1, /* Index of string descriptor describing manufacturer */
2, /* Index of string descriptor describing product */
3, /* Index of string descriptor describing the device's serial number */
0x01 /* bNumConfigurations */
};
2016-05-18 04:32:00 +00:00
#if defined(USB_SELF_POWERED)
#define REGNUAL_FEATURE_INIT 0xC0 /* self powered */
#else
#define REGNUAL_FEATURE_INIT 0x80 /* bus powered */
#endif
2012-05-18 17:07:31 +00:00
static const uint8_t regnual_config_desc[] = {
9,
2016-03-08 02:58:43 +00:00
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
18, 0, /* wTotalLength: no of returned bytes */
2015-08-11 03:35:35 +00:00
1, /* bNumInterfaces: single vendor interface */
2012-05-18 17:07:31 +00:00
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: None */
2016-05-18 04:32:00 +00:00
REGNUAL_FEATURE_INIT, /* bmAttributes: bus powered */
50, /* MaxPower 100 mA */
2012-06-01 04:18:34 +00:00
/* Interface Descriptor */
9,
2016-03-08 02:58:43 +00:00
INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */
0, /* bInterfaceNumber: Index of this interface */
2012-06-01 04:18:34 +00:00
0, /* Alternate setting for this interface */
0, /* bNumEndpoints: None */
0xFF,
0,
0,
0, /* string index for interface */
2012-05-18 17:07:31 +00:00
};
static const uint8_t regnual_string_lang_id[] = {
4, /* bLength */
2016-03-08 02:58:43 +00:00
STRING_DESCRIPTOR,
2012-05-18 17:07:31 +00:00
0x09, 0x04 /* LangID = 0x0409: US-English */
};
2012-06-01 04:18:34 +00:00
#include "../src/usb-strings.c.inc"
2012-05-18 17:07:31 +00:00
static const uint8_t regnual_string_serial[] = {
8*2+2,
2016-03-08 02:58:43 +00:00
STRING_DESCRIPTOR,
2012-05-18 17:07:31 +00:00
/* FSIJ-0.0 */
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
'0', 0, '.', 0, '0', 0,
};
2013-03-06 08:27:42 +00:00
void
usb_cb_device_reset (void)
2012-05-18 17:07:31 +00:00
{
2016-05-18 04:32:00 +00:00
usb_lld_reset (REGNUAL_FEATURE_INIT);
2012-05-18 17:07:31 +00:00
/* Initialize Endpoint 0 */
usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR,
64);
}
2012-05-23 03:16:31 +00:00
#define USB_REGNUAL_MEMINFO 0
#define USB_REGNUAL_SEND 1
#define USB_REGNUAL_RESULT 2
#define USB_REGNUAL_FLASH 3
#define USB_REGNUAL_PROTECT 4
#define USB_REGNUAL_FINISH 5
2012-05-18 17:07:31 +00:00
2013-03-06 08:27:42 +00:00
static uint32_t mem[256/4];
2012-05-23 03:16:31 +00:00
static uint32_t result;
2012-05-22 08:02:54 +00:00
2012-05-18 17:07:31 +00:00
2012-06-05 01:33:50 +00:00
static uint32_t rbit (uint32_t v)
2012-06-04 07:31:40 +00:00
{
uint32_t r;
2012-06-05 01:33:50 +00:00
asm ("rbit %0, %1" : "=r" (r) : "r" (v));
2012-06-04 07:31:40 +00:00
return r;
}
2012-06-05 01:33:50 +00:00
static uint32_t fetch (int i)
{
uint32_t v;
2013-03-06 08:27:42 +00:00
v = mem[i];
2012-06-05 01:33:50 +00:00
return rbit (v);
}
2012-06-04 07:31:40 +00:00
struct CRC {
__IO uint32_t DR;
__IO uint8_t IDR;
uint8_t RESERVED0;
uint16_t RESERVED1;
__IO uint32_t CR;
};
#define CRC_CR_RESET 0x01
static uint32_t calc_crc32 (void)
{
struct CRC *CRC = (struct CRC *)0x40023000;
int i;
CRC->CR = CRC_CR_RESET;
for (i = 0; i < 256/4; i++)
CRC->DR = fetch (i);
2012-06-05 01:33:50 +00:00
return rbit (CRC->DR);
2012-06-04 07:31:40 +00:00
}
2016-03-08 02:58:43 +00:00
void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no,
2016-05-18 04:32:00 +00:00
struct req_args *arg)
2012-05-18 17:07:31 +00:00
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
2012-06-04 07:31:40 +00:00
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
2012-05-18 17:07:31 +00:00
{
2016-05-18 04:32:00 +00:00
if (req_no == USB_REGNUAL_SEND && arg->value == 0)
2012-06-04 07:31:40 +00:00
result = calc_crc32 ();
2015-07-31 07:13:06 +00:00
else if (req_no == USB_REGNUAL_FLASH)
2012-05-23 03:16:31 +00:00
{
2016-05-18 04:32:00 +00:00
uint32_t dst_addr = (0x08000000 + arg->value * 0x100);
2012-05-23 03:16:31 +00:00
2013-03-06 08:27:42 +00:00
result = flash_write (dst_addr, (const uint8_t *)mem, 256);
2012-05-23 03:16:31 +00:00
}
2016-05-18 04:32:00 +00:00
else if (req_no == USB_REGNUAL_PROTECT && arg->value == 0)
2012-05-23 06:25:20 +00:00
result = flash_protect ();
2016-05-18 04:32:00 +00:00
else if (req_no == USB_REGNUAL_FINISH && arg->value == 0)
2012-05-22 08:02:54 +00:00
nvic_system_reset ();
2012-05-23 03:16:31 +00:00
}
2012-05-18 17:07:31 +00:00
}
2013-03-06 08:27:42 +00:00
int
2016-05-18 04:32:00 +00:00
usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
2012-05-18 17:07:31 +00:00
{
uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
{
if (USB_SETUP_GET (req))
{
if (req_no == USB_REGNUAL_MEMINFO)
{
2015-07-31 07:13:06 +00:00
const uint8_t *mem_info[2];
2013-03-06 08:27:42 +00:00
2015-07-31 07:13:06 +00:00
mem_info[0] = (const uint8_t *)FLASH_START;
mem_info[1] = (const uint8_t *)flash_end;
2016-05-18 04:32:00 +00:00
return usb_lld_reply_request (mem_info, sizeof (mem_info), arg);
2012-05-18 17:07:31 +00:00
}
2012-05-23 03:16:31 +00:00
else if (req_no == USB_REGNUAL_RESULT)
2016-05-18 04:32:00 +00:00
return usb_lld_reply_request (&result, sizeof (uint32_t), arg);
2012-05-18 17:07:31 +00:00
}
else /* SETUP_SET */
{
if (req_no == USB_REGNUAL_SEND)
{
2016-05-18 04:32:00 +00:00
if (arg->value != 0 || arg->index + arg->len > 256)
2012-05-18 17:07:31 +00:00
return USB_UNSUPPORT;
2016-05-18 04:32:00 +00:00
if (arg->index + arg->len < 256)
memset ((uint8_t *)mem + arg->index + arg->len, 0xff,
256 - (arg->index + arg->len));
2012-05-22 08:02:54 +00:00
2016-05-18 04:32:00 +00:00
usb_lld_set_data_to_recv (mem + arg->index, arg->len);
2012-05-18 17:07:31 +00:00
return USB_SUCCESS;
}
2016-05-18 04:32:00 +00:00
else if (req_no == USB_REGNUAL_FLASH && arg->len == 0
&& arg->index == 0)
2012-05-18 17:07:31 +00:00
{
2016-05-18 04:32:00 +00:00
uint32_t dst_addr = (0x08000000 + arg->value * 0x100);
2012-05-18 17:07:31 +00:00
2015-07-31 07:13:06 +00:00
if (dst_addr + 256 <= flash_end)
2012-05-22 08:02:54 +00:00
return USB_SUCCESS;
}
2016-05-18 04:32:00 +00:00
else if (req_no == USB_REGNUAL_PROTECT && arg->len == 0
&& arg->value == 0 && arg->index == 0)
2012-05-23 06:25:20 +00:00
return USB_SUCCESS;
2016-05-18 04:32:00 +00:00
else if (req_no == USB_REGNUAL_FINISH && arg->len == 0
&& arg->value == 0 && arg->index == 0)
2012-05-22 08:02:54 +00:00
return USB_SUCCESS;
2012-05-18 17:07:31 +00:00
}
}
return USB_UNSUPPORT;
}
2013-03-06 08:27:42 +00:00
int
2013-11-12 04:02:02 +00:00
usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
2016-05-18 04:32:00 +00:00
struct req_args *arg)
2012-05-18 17:07:31 +00:00
{
2013-11-12 04:02:02 +00:00
if (rcp != DEVICE_RECIPIENT)
return USB_UNSUPPORT;
2012-05-18 17:07:31 +00:00
if (desc_type == DEVICE_DESCRIPTOR)
2015-07-31 07:13:06 +00:00
return usb_lld_reply_request (regnual_device_desc,
2016-05-18 04:32:00 +00:00
sizeof (regnual_device_desc), arg);
2012-05-18 17:07:31 +00:00
else if (desc_type == CONFIG_DESCRIPTOR)
2015-07-31 07:13:06 +00:00
return usb_lld_reply_request (regnual_config_desc,
2016-05-18 04:32:00 +00:00
sizeof (regnual_config_desc), arg);
2012-05-18 17:07:31 +00:00
else if (desc_type == STRING_DESCRIPTOR)
{
2013-03-06 08:27:42 +00:00
const uint8_t *str;
int size;
2012-05-18 17:07:31 +00:00
2013-03-06 08:27:42 +00:00
switch (desc_index)
2012-05-18 17:07:31 +00:00
{
2013-03-06 08:27:42 +00:00
case 0:
str = regnual_string_lang_id;
size = sizeof (regnual_string_lang_id);
2013-03-15 01:39:47 +00:00
break;
2013-03-06 08:27:42 +00:00
case 1:
2015-07-31 07:13:06 +00:00
str = gnuk_string_vendor;
size = sizeof (gnuk_string_vendor);
2013-03-15 01:39:47 +00:00
break;
2013-03-06 08:27:42 +00:00
case 2:
2015-07-31 07:13:06 +00:00
str = gnuk_string_product;
size = sizeof (gnuk_string_product);
2013-03-15 01:39:47 +00:00
break;
2013-03-06 08:27:42 +00:00
case 3:
str = regnual_string_serial;
size = sizeof (regnual_string_serial);
break;
default:
return USB_UNSUPPORT;
2012-05-18 17:07:31 +00:00
}
2013-03-06 08:27:42 +00:00
2016-05-18 04:32:00 +00:00
return usb_lld_reply_request (str, size, arg);
2012-05-18 17:07:31 +00:00
}
return USB_UNSUPPORT;
}
2013-03-06 08:27:42 +00:00
int usb_cb_handle_event (uint8_t event_type, uint16_t value)
2012-05-18 17:07:31 +00:00
{
(void)value;
switch (event_type)
{
case USB_EVENT_ADDRESS:
case USB_EVENT_CONFIG:
return USB_SUCCESS;
default:
break;
}
return USB_UNSUPPORT;
}
2016-05-18 04:32:00 +00:00
int usb_cb_interface (uint8_t cmd, struct req_args *arg)
2012-05-18 17:07:31 +00:00
{
2016-05-18 04:32:00 +00:00
(void)cmd; (void)arg;
2012-05-18 17:07:31 +00:00
return USB_UNSUPPORT;
}
2016-05-16 13:43:51 +00:00
void usb_cb_rx_ready (uint8_t ep_num)
{
(void)ep_num;
}
void usb_cb_tx_done (uint8_t ep_num)
{
(void)ep_num;
}
2012-05-18 17:07:31 +00:00
2012-05-22 01:44:37 +00:00
static void wait (int count)
{
int i;
for (i = 0; i < count; i++)
asm volatile ("" : : "r" (i) : "memory");
}
#define WAIT 2400000
2016-05-18 04:32:00 +00:00
/* NVIC: Nested Vectored Interrupt Controller. */
struct NVIC {
volatile uint32_t ISER[8];
uint32_t unused1[24];
volatile uint32_t ICER[8];
uint32_t unused2[24];
volatile uint32_t ISPR[8];
uint32_t unused3[24];
volatile uint32_t ICPR[8];
uint32_t unused4[24];
volatile uint32_t IABR[8];
uint32_t unused5[56];
volatile uint32_t IPR[60];
};
static struct NVIC *const NVIC = (struct NVIC *const)0xE000E100;
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
static void nvic_enable_intr (uint8_t irq_num)
{
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
}
#define USB_LP_CAN1_RX0_IRQn 20
2012-05-18 17:07:31 +00:00
int
main (int argc, char *argv[])
{
(void)argc; (void)argv;
set_led (0);
2015-07-31 07:13:06 +00:00
flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
2016-05-18 04:32:00 +00:00
/*
* NVIC interrupt priority was set by Gnuk.
* USB interrupt is disabled by NVIC setting.
* We enable the interrupt again by nvic_enable_intr.
*/
usb_lld_init (REGNUAL_FEATURE_INIT);
nvic_enable_intr (USB_LP_CAN1_RX0_IRQn);
2012-05-18 17:07:31 +00:00
while (1)
{
set_led (1);
2012-05-22 01:44:37 +00:00
wait (WAIT);
2012-05-18 17:07:31 +00:00
set_led (0);
2012-05-22 01:44:37 +00:00
wait (WAIT);
2012-05-18 17:07:31 +00:00
}
}