From f93536af111063a40b15dc5dca38d0b93f9d6763 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 19 Sep 2012 12:29:28 +0900 Subject: [PATCH] support reGNUal --- ChangeLog | 10 ++ src/main.c | 190 ++++++++++++++++-------- src/neug.h | 1 + src/neug.ld.in | 9 +- src/random.c | 14 +- tool/neug_upgrade.py | 339 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 497 insertions(+), 66 deletions(-) create mode 100755 tool/neug_upgrade.py diff --git a/ChangeLog b/ChangeLog index b61762c..2ccd06c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-09-19 Niibe Yutaka + + * tool/neug_upgrade.py: New. + + * src/main.c (main): Support reGNUal. + * src/neug.ld.in (__ram_end__): Define. + * src/random.c (rng): Finish upon request of termination. + (neug_fini): New. + * src/neug.h (neug_fini): New. + 2012-09-18 Niibe Yutaka * src/random.c (NUM_NOISE_INPUTS, REPITITION_COUNT_TEST_CUTOFF) diff --git a/src/main.c b/src/main.c index c02a678..197b177 100644 --- a/src/main.c +++ b/src/main.c @@ -38,6 +38,8 @@ extern void *memcpy(void *dest, const void *src, size_t n); extern void *memset (void *s, int c, size_t n); +static Thread *main_thread = NULL; + #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x80) @@ -218,19 +220,24 @@ neug_device_reset (void) 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 +extern uint8_t _regnual_start, __heap_end__; + +static const uint8_t *const mem_info[] = { &_regnual_start, &__heap_end__, }; -static uint8_t mem[256]; -static uint32_t result; +#define USB_FSIJ_MEMINFO 0 +#define USB_FSIJ_DOWNLOAD 1 +#define USB_FSIJ_EXEC 2 +#define USB_NEUG_EXIT 255 /* exit and receive reGNUal */ -extern uint8_t __flash_start__, __flash_end__; -static const uint8_t *const mem_info[] = { &__flash_start__, &__flash_end__ }; +enum { + FSIJ_DEVICE_RUNNING = 0, + FSIJ_DEVICE_EXITED, + FSIJ_DEVICE_EXEC_REQUESTED, + /**/ + FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255 +}; +static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING; static uint32_t rbit (uint32_t v) { @@ -240,26 +247,23 @@ static uint32_t rbit (uint32_t v) return r; } -static uint32_t fetch (int i) -{ - uint32_t v; - - v = *(uint32_t *)(&mem[i*4]); - return rbit (v); -} - -static uint32_t calc_crc32 (void) +/* After calling this function, CRC module remain enabled. */ +static int download_check_crc32 (const uint32_t *end_p) { - int i; + uint32_t crc32 = *end_p; + const uint32_t *p; + RCC->AHBENR |= RCC_AHBENR_CRCEN; CRC->CR = CRC_CR_RESET; - for (i = 0; i < 256/4; i++) - CRC->DR = fetch (i); + for (p = (const uint32_t *)&_regnual_start; p < end_p; p++) + CRC->DR = rbit (*p); - return rbit (CRC->DR); -} + if ((rbit (CRC->DR) ^ crc32) == 0xffffffff) + return USB_SUCCESS; + return USB_UNSUPPORT; +} static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value, uint16_t index, @@ -267,22 +271,15 @@ static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no, { uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT); - if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req)) + if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) + && USB_SETUP_SET (req) && req_no == USB_FSIJ_EXEC && len == 0) { - if (req_no == USB_REGNUAL_SEND && value == 0) - result = calc_crc32 (); - else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0) - { - uint32_t dst_addr = (0x08000000 + value * 0x100); + if (fsij_device_state != FSIJ_DEVICE_EXITED) + return; - result = flash_write (dst_addr, mem, 256); - } - else if (req_no == USB_REGNUAL_PROTECT && len == 0 - && value == 0 && index == 0) - result = flash_protect (); - else if (req_no == USB_REGNUAL_FINISH && len == 0 - && value == 0 && index == 0) - nvic_system_reset (); + (void)value; (void)index; + usb_lld_prepare_shutdown (); /* No further USB communication */ + fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED; } } @@ -350,43 +347,50 @@ neug_setup (uint8_t req, uint8_t req_no, { if (USB_SETUP_GET (req)) { - if (req_no == USB_REGNUAL_MEMINFO) + if (req_no == USB_FSIJ_MEMINFO) { usb_lld_set_data_to_send (mem_info, sizeof (mem_info)); return USB_SUCCESS; } - else if (req_no == USB_REGNUAL_RESULT) - { - usb_lld_set_data_to_send (&result, sizeof (uint32_t)); - return USB_SUCCESS; - } } else /* SETUP_SET */ { - if (req_no == USB_REGNUAL_SEND) + uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index); + + if (req_no == USB_FSIJ_DOWNLOAD) { - if (value != 0 || index + len > 256) + if (fsij_device_state != FSIJ_DEVICE_EXITED) + return USB_UNSUPPORT; + + if (addr < &_regnual_start || addr + len > &__heap_end__) return USB_UNSUPPORT; if (index + len < 256) - memset (mem + index + len, 0xff, 256 - (index + len)); + memset (addr + index + len, 0, 256 - (index + len)); - usb_lld_set_data_to_recv (mem + index, len); + usb_lld_set_data_to_recv (addr, len); return USB_SUCCESS; } - else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0) + else if (req_no == USB_FSIJ_EXEC && len == 0) { - uint32_t dst_addr = (0x08000000 + value * 0x100); + if (fsij_device_state != FSIJ_DEVICE_EXITED) + return USB_UNSUPPORT; + + if (((uint32_t)addr & 0x03)) + return USB_UNSUPPORT; - if (dst_addr + 256 <= (uint32_t)&__flash_end__) - return USB_SUCCESS; + return download_check_crc32 ((uint32_t *)addr); + } + else if (req_no == USB_NEUG_EXIT && len == 0) + { + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + return USB_UNSUPPORT; + + fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED; + chEvtSignalFlagsI (main_thread, 1); + chSchReadyI (main_thread); + return USB_SUCCESS; } - else if (req_no == USB_REGNUAL_PROTECT && len == 0 - && value == 0 && index == 0) - return USB_SUCCESS; - else if (req_no == USB_REGNUAL_FINISH && len == 0 - && value == 0 && index == 0) - return USB_SUCCESS; } } else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)) @@ -556,8 +560,6 @@ static void fill_serial_no_by_unique_id (void) } } -static Thread *main_thread = NULL; - CH_IRQ_HANDLER (Vector90) { CH_IRQ_PROLOGUE(); @@ -613,6 +615,9 @@ static msg_t led_blinker (void *arg) eventmask_t m; m = chEvtWaitOne (ALL_EVENTS); + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + break; + set_led (1); if (m == LED_ONESHOT_SHORT) chThdSleep (MS2ST (100)); @@ -655,22 +660,31 @@ main (int argc, char **argv) { unsigned int count = 0; + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + break; + connected = 0; while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED) { + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + break; + (void)neug_get (NEUG_KICK_FILLING); if ((count & 0x000f) == 0) chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT); - chThdSleep (MS2ST (25)); + chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (25)); count++; } waiting_connection: while ((connected & 1) == 0) { + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + break; + neug_flush (); chEvtSignalFlags (led_thread, LED_ONESHOT_LONG); - chThdSleep (MS2ST (2500)); + chEvtWaitOneTimeout (ALL_EVENTS, MS2ST (2500)); } /* The connection opened. */ @@ -678,6 +692,9 @@ main (int argc, char **argv) while (1) { + if (fsij_device_state != FSIJ_DEVICE_RUNNING) + break; + if ((connected & 1) == 0) goto waiting_connection; @@ -701,5 +718,54 @@ main (int argc, char **argv) } } + /* + * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED. + */ + neug_fini (); + + chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT); + chThdWait (led_thread); + + fsij_device_state = FSIJ_DEVICE_EXITED; + + while (fsij_device_state == FSIJ_DEVICE_EXITED) + chThdSleep (MS2ST (500)); + + flash_unlock (); /* Flash unlock should be done here */ + set_led (1); + usb_lld_shutdown (); + /* Disable SysTick */ + SysTick->CTRL = 0; + /* Disable all interrupts */ + port_disable (); + /* Set vector */ + SCB->VTOR = (uint32_t)&_regnual_start; +#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; + void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10]; + + /* 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); + + /* Leave NeuG to exec reGNUal */ + (*func) (*((void (**)(void))(&_regnual_start+4))); + for (;;); + } +#else + /* Leave NeuG to exec reGNUal */ + flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4))); +#endif + + /* Never reached */ return 0; } diff --git a/src/neug.h b/src/neug.h index f83d8a5..898c865 100644 --- a/src/neug.h +++ b/src/neug.h @@ -9,3 +9,4 @@ uint32_t neug_get (int kick); void neug_kick_filling (void); void neug_flush (void); void neug_wait_full (void); +void neug_fini (void); diff --git a/src/neug.ld.in b/src/neug.ld.in index e34464d..a576cc9 100644 --- a/src/neug.ld.in +++ b/src/neug.ld.in @@ -157,14 +157,17 @@ SECTIONS PROVIDE(_bss_end = .); } > ram + PROVIDE(end = .); + _end = .; + . = ALIGN(512); + /* it is at offset 0x1400 from ram start */ + _regnual_start = __ram_start__ + 0x1400; + .fill_ffff : { . = ALIGN (@FLASH_PAGE_SIZE@); } > flash =0xffffffff } -PROVIDE(end = .); -_end = .; - __heap_base__ = _end; __heap_end__ = __ram_end__; diff --git a/src/random.c b/src/random.c index 10e5d49..a373a0f 100644 --- a/src/random.c +++ b/src/random.c @@ -370,7 +370,7 @@ static msg_t rng (void *arg) adcStart (&ADCD1, NULL); adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH); - while (1) + while (!chThdShouldTerminate ()) { chMtxLock (&rb->m); while (rb->full) @@ -462,3 +462,15 @@ neug_wait_full (void) chCondWait (&rb->data_available); chMtxUnlock (); } + +void +neug_fini (void) +{ + if (rng_thread) + { + chThdTerminate (rng_thread); + neug_get (1); + chThdWait (rng_thread); + rng_thread = NULL; + } +} diff --git a/tool/neug_upgrade.py b/tool/neug_upgrade.py new file mode 100755 index 0000000..c953c92 --- /dev/null +++ b/tool/neug_upgrade.py @@ -0,0 +1,339 @@ +#! /usr/bin/python + +""" +neug_upgrade.py - a tool to upgrade firmware of Gnuk Token + +Copyright (C) 2012 Free Software Initiative of Japan +Author: NIIBE Yutaka + +This file is a part of NeuG, a TRNG 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 . +""" + +from struct import * +import sys, time, os, binascii, string + +# INPUT: binary file + +# Assume only single NeuG device is attached to computer + +import usb + +# USB class, subclass, protocol +COM_CLASS = 0x0a +COM_SUBCLASS = 0x00 +COM_PROTOCOL_0 = 0x00 + +class regnual(object): + def __init__(self, dev): + conf = dev.configurations[0] + intf_alt = conf.interfaces[0] + intf = intf_alt[0] + if intf.interfaceClass != 0xff: + raise ValueError, "Wrong interface class" + self.__devhandle = dev.open() + try: + self.__devhandle.setConfiguration(conf) + except: + pass + self.__devhandle.claimInterface(intf) + self.__devhandle.setAltInterface(intf) + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10000) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x08000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d: %d : %d" % (addr, i, j, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10000) + crc32code = crc32(data[j*256:j*256+256]) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = 0, index = 0, + buffer = data[j*256:], + timeout = 10000) + crc32code = crc32(data[j*256:].ljust(256,chr(255))) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if (crc32code ^ r_value) != 0xffffffff: + print "failure" + self.__devhandle.controlMsg(requestType = 0x40, request = 3, + value = i, index = 0, + buffer = None, + timeout = 10000) + time.sleep(0.010) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "failure" + + def protect(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 4, + value = 0, index = 0, buffer = None, + timeout = 10000) + time.sleep(0.100) + res = self.__devhandle.controlMsg(requestType = 0xc0, request = 2, + value = 0, index = 0, buffer = 4, + timeout = 10000) + r_value = ((res[3]*256 + res[2])*256 + res[1])*256 + res[0] + if r_value == 0: + print "protection failure" + + def finish(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 5, + value = 0, index = 0, buffer = None, + timeout = 10000) + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + +class neug(object): + def __init__(self, device, configuration, interface): + """ + __init__(device, configuration, interface) -> None + Initialize the device. + device: usb.Device object. + configuration: configuration number. + interface: usb.Interface object representing the interface and altenate setting. + """ + if interface.interfaceClass !=COM_CLASS: + raise ValueError, "Wrong interface class" + if interface.interfaceSubClass != COM_SUBCLASS: + raise ValueError, "Wrong interface sub class" + self.__devhandle = device.open() + try: + self.__devhandle.setConfiguration(configuration) + except: + pass + + self.__devhandle.detachKernelDriver(interface) + self.__devhandle.claimInterface(interface) + self.__devhandle.setAltInterface(interface) + + self.__intf = interface.interfaceNumber + self.__alt = interface.alternateSetting + self.__conf = configuration + + self.__timeout = 10000 + + def reset_device(self): + try: + self.__devhandle.reset() + except: + pass + + def stop_neug(self): + self.__devhandle.controlMsg(requestType = 0x40, request = 255, + value = 0, index = 0, buffer = None, + timeout = 10) + self.__devhandle.releaseInterface() + self.__devhandle.setConfiguration(0) + return + + def mem_info(self): + mem = self.__devhandle.controlMsg(requestType = 0xc0, request = 0, + value = 0, index = 0, buffer = 8, + timeout = 10) + start = ((mem[3]*256 + mem[2])*256 + mem[1])*256 + mem[0] + end = ((mem[7]*256 + mem[6])*256 + mem[5])*256 + mem[4] + return (start, end) + + def download(self, start, data): + addr = start + addr_end = (start + len(data)) & 0xffffff00 + i = (addr - 0x20000000) / 0x100 + j = 0 + print "start %08x" % addr + print "end %08x" % addr_end + while addr < addr_end: + print "# %08x: %d : %d" % (addr, i, 256) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:j*256+256], + timeout = 10) + i = i+1 + j = j+1 + addr = addr + 256 + residue = len(data) % 256 + if residue != 0: + print "# %08x: %d : %d" % (addr, i, residue) + self.__devhandle.controlMsg(requestType = 0x40, request = 1, + value = i, index = 0, + buffer = data[j*256:], + timeout = 10) + + def execute(self, last_addr): + i = (last_addr - 0x20000000) / 0x100 + o = (last_addr - 0x20000000) % 0x100 + self.__devhandle.controlMsg(requestType = 0x40, request = 2, + value = i, index = o, buffer = None, + timeout = 10) + +def compare(data_original, data_in_device): + i = 0 + for d in data_original: + if ord(d) != data_in_device[i]: + raise ValueError, "verify failed at %08x" % i + i += 1 + +def com_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + for config in dev.configurations: + for intf in config.interfaces: + for alt in intf: + if alt.interfaceClass == COM_CLASS and \ + alt.interfaceSubClass == COM_SUBCLASS and \ + alt.interfaceProtocol == COM_PROTOCOL_0: + yield dev, config, alt + +USB_VENDOR_FSIJ=0x234b +USB_PRODUCT_GNUK=0x0000 + +def gnuk_devices(): + busses = usb.busses() + for bus in busses: + devices = bus.devices + for dev in devices: + if dev.idVendor != USB_VENDOR_FSIJ: + continue + if dev.idProduct != USB_PRODUCT_GNUK: + continue + yield dev + +def to_string(t): + result = "" + for c in t: + result += chr(c) + return result + +def UNSIGNED(n): + return n & 0xffffffff + +def crc32(bytestr): + crc = binascii.crc32(bytestr) + return UNSIGNED(crc) + +def main(data_regnual, data_upgrade): + l = len(data_regnual) + if (l & 0x03) != 0: + data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0)) + crc32code = crc32(data_regnual) + print "CRC32: %04x\n" % crc32code + data_regnual += pack('