/* * regnual.c -- Firmware installation for STM32F103 Flash ROM * * Copyright (C) 2012, 2013, 2015, 2016, 2017 * Free Software Initiative of Japan * Author: NIIBE Yutaka * * 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 . * */ /* * ReGNUal */ #include "types.h" #include "usb_lld.h" #include "sys.h" extern void *memset (void *s, int c, size_t n); extern void set_led (int); extern int flash_write (uint32_t dst_addr, const uint8_t *src, size_t len); extern int flash_protect (void); extern void nvic_system_reset (void); #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; #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x80) /* USB Standard Device Descriptor */ static const uint8_t regnual_device_desc[] = { 18, /* bLength */ DEVICE_DESCRIPTOR, /* bDescriptorType */ 0x10, 0x01, /* bcdUSB = 1.1 */ 0xFF, /* bDeviceClass: VENDOR */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ 0x40, /* bMaxPacketSize0 */ #include "../src/usb-vid-pid-ver.c.inc" 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 */ }; #if defined(USB_SELF_POWERED) #define REGNUAL_FEATURE_INIT 0xC0 /* self powered */ #else #define REGNUAL_FEATURE_INIT 0x80 /* bus powered */ #endif static const uint8_t regnual_config_desc[] = { 9, CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */ 18, 0, /* wTotalLength: no of returned bytes */ 1, /* bNumInterfaces: single vendor interface */ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: None */ REGNUAL_FEATURE_INIT, /* bmAttributes: bus powered */ 50, /* MaxPower 100 mA */ /* Interface Descriptor */ 9, INTERFACE_DESCRIPTOR, /* bDescriptorType: Interface */ 0, /* bInterfaceNumber: Index of this interface */ 0, /* Alternate setting for this interface */ 0, /* bNumEndpoints: None */ 0xFF, 0, 0, 0, /* string index for interface */ }; static const uint8_t regnual_string_lang_id[] = { 4, /* bLength */ STRING_DESCRIPTOR, 0x09, 0x04 /* LangID = 0x0409: US-English */ }; #include "../src/usb-strings.c.inc" static const uint8_t regnual_string_serial[] = { 8*2+2, STRING_DESCRIPTOR, /* FSIJ-0.0 */ 'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0, '0', 0, '.', 0, '0', 0, }; static void usb_device_reset (struct usb_dev *dev) { usb_lld_reset (dev, REGNUAL_FEATURE_INIT); /* Initialize Endpoint 0 */ usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64); } #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 static uint32_t mem[256/4]; static uint32_t result; static uint32_t rbit (uint32_t v) { uint32_t r; asm ("rbit %0, %1" : "=r" (r) : "r" (v)); return r; } static uint32_t fetch (int i) { uint32_t v; v = mem[i]; return rbit (v); } 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); return rbit (CRC->DR); } static void usb_ctrl_write_finish (struct usb_dev *dev) { struct device_req *arg = &dev->dev_req; uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT); if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (arg->type)) { if (arg->request == USB_REGNUAL_SEND && arg->value == 0) result = calc_crc32 (); else if (arg->request == USB_REGNUAL_FLASH) { uint32_t dst_addr = (0x08000000 + arg->value * 0x100); result = flash_write (dst_addr, (const uint8_t *)mem, 256); } else if (arg->request == USB_REGNUAL_PROTECT && arg->value == 0) result = flash_protect (); else if (arg->request == USB_REGNUAL_FINISH && arg->value == 0) nvic_system_reset (); } } static int usb_setup (struct usb_dev *dev) { struct device_req *arg = &dev->dev_req; uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT); if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)) { if (USB_SETUP_GET (arg->type)) { if (arg->request == USB_REGNUAL_MEMINFO) { const uint8_t *mem_info[2]; mem_info[0] = (const uint8_t *)FLASH_START; mem_info[1] = (const uint8_t *)flash_end; return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info)); } else if (arg->request == USB_REGNUAL_RESULT) return usb_lld_ctrl_send (dev, &result, sizeof (uint32_t)); } else /* SETUP_SET */ { if (arg->request == USB_REGNUAL_SEND) { if (arg->value != 0 || arg->index + arg->len > 256) return -1; if (arg->index + arg->len < 256) memset ((uint8_t *)mem + arg->index + arg->len, 0xff, 256 - (arg->index + arg->len)); return usb_lld_ctrl_recv (dev, mem + arg->index, arg->len); } else if (arg->request == USB_REGNUAL_FLASH && arg->len == 0 && arg->index == 0) { uint32_t dst_addr = (0x08000000 + arg->value * 0x100); if (dst_addr + 256 <= flash_end) return usb_lld_ctrl_ack (dev); } else if (arg->request == USB_REGNUAL_PROTECT && arg->len == 0 && arg->value == 0 && arg->index == 0) return usb_lld_ctrl_ack (dev); else if (arg->request == USB_REGNUAL_FINISH && arg->len == 0 && arg->value == 0 && arg->index == 0) return usb_lld_ctrl_ack (dev); } } return -1; } static int usb_get_descriptor (struct usb_dev *dev) { struct device_req *arg = &dev->dev_req; uint8_t rcp = arg->type & RECIPIENT; uint8_t desc_type = (arg->value >> 8); uint8_t desc_index = (arg->value & 0xff); if (rcp != DEVICE_RECIPIENT) return -1; if (desc_type == DEVICE_DESCRIPTOR) return usb_lld_ctrl_send (dev, regnual_device_desc, sizeof (regnual_device_desc)); else if (desc_type == CONFIG_DESCRIPTOR) return usb_lld_ctrl_send (dev, regnual_config_desc, sizeof (regnual_config_desc)); else if (desc_type == STRING_DESCRIPTOR) { const uint8_t *str; int size; switch (desc_index) { case 0: str = regnual_string_lang_id; size = sizeof (regnual_string_lang_id); break; case 1: str = gnuk_string_vendor; size = sizeof (gnuk_string_vendor); break; case 2: str = gnuk_string_product; size = sizeof (gnuk_string_product); break; case 3: str = regnual_string_serial; size = sizeof (regnual_string_serial); break; default: return -1; } return usb_lld_ctrl_send (dev, str, size); } return -1; } static int usb_set_configuration (struct usb_dev *dev) { uint8_t current_conf; current_conf = usb_lld_current_configuration (dev); if (current_conf == 0) { if (dev->dev_req.value != 1) return -1; usb_lld_set_configuration (dev, 1); } else if (current_conf != dev->dev_req.value) { if (dev->dev_req.value != 0) return -1; usb_lld_set_configuration (dev, 0); } /* Do nothing when current_conf == value */ return usb_lld_ctrl_ack (dev); } static void wait (int count) { int i; for (i = 0; i < count; i++) asm volatile ("" : : "r" (i) : "memory"); } #define WAIT 2400000 /* 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 static struct usb_dev dev; int main (int argc, char *argv[]) { (void)argc; (void)argv; set_led (0); #if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB) flash_end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024; #else flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024; #endif /* * 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 (&dev, REGNUAL_FEATURE_INIT); nvic_enable_intr (USB_LP_CAN1_RX0_IRQn); while (1) { set_led (1); wait (WAIT); set_led (0); wait (WAIT); } } void usb_interrupt_handler (void) { uint8_t ep_num; int e; e = usb_lld_event_handler (&dev); ep_num = USB_EVENT_ENDP (e); if (ep_num == 0) switch (USB_EVENT_ID (e)) { case USB_EVENT_DEVICE_RESET: usb_device_reset (&dev); break; case USB_EVENT_DEVICE_ADDRESSED: break; case USB_EVENT_GET_DESCRIPTOR: if (usb_get_descriptor (&dev) < 0) usb_lld_ctrl_error (&dev); break; case USB_EVENT_SET_CONFIGURATION: if (usb_set_configuration (&dev) < 0) usb_lld_ctrl_error (&dev); break; case USB_EVENT_SET_INTERFACE: usb_lld_ctrl_error (&dev); break; case USB_EVENT_CTRL_REQUEST: /* Device specific device request. */ if (usb_setup (&dev) < 0) usb_lld_ctrl_error (&dev); break; case USB_EVENT_GET_STATUS_INTERFACE: usb_lld_ctrl_error (&dev); break; case USB_EVENT_GET_INTERFACE: usb_lld_ctrl_error (&dev); break; case USB_EVENT_SET_FEATURE_DEVICE: case USB_EVENT_SET_FEATURE_ENDPOINT: case USB_EVENT_CLEAR_FEATURE_DEVICE: case USB_EVENT_CLEAR_FEATURE_ENDPOINT: usb_lld_ctrl_ack (&dev); break; case USB_EVENT_CTRL_WRITE_FINISH: /* Control WRITE transfer finished. */ usb_ctrl_write_finish (&dev); break; case USB_EVENT_OK: case USB_EVENT_DEVICE_SUSPEND: default: break; } }