From 5eff2a104db3b055d7ddde2e9ff54e3cf5a98293 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Fri, 13 Jul 2018 21:34:15 -0400 Subject: [PATCH] add flash support to efm32 port --- efm32/emlib/em_msc.c | 1163 ++++++++++++++++++++++++++++++++++++++++++ efm32/src/device.c | 101 +++- fido2/storage.h | 2 +- fido2/wallet.c | 2 +- pc/device.c | 3 +- web/js/wallet.js | 20 +- 6 files changed, 1268 insertions(+), 23 deletions(-) create mode 100644 efm32/emlib/em_msc.c diff --git a/efm32/emlib/em_msc.c b/efm32/emlib/em_msc.c new file mode 100644 index 0000000..2391d2a --- /dev/null +++ b/efm32/emlib/em_msc.c @@ -0,0 +1,1163 @@ +/***************************************************************************//** + * @file em_msc.c + * @brief Flash controller (MSC) Peripheral API + * @version 5.5.0 + ******************************************************************************* + * # License + * Copyright 2016 Silicon Laboratories, Inc. www.silabs.com + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ + +#include "em_msc.h" +#if defined(MSC_COUNT) && (MSC_COUNT > 0) + +#include "em_system.h" +#if defined(_MSC_TIMEBASE_MASK) +#include "em_cmu.h" +#endif +#include "em_assert.h" +#if defined(_MSC_ECCCTRL_MASK) +#include "em_cmu.h" +#include "em_core.h" +#endif + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#if defined(__ICCARM__) +/* Suppress warnings originating from use of EFM_ASSERT() with IAR: + EFM_ASSERT() is implemented as a local ramfunc */ +#pragma diag_suppress=Ta022 +#endif + +#if defined(EM_MSC_RUN_FROM_FLASH) && defined(_EFM32_GECKO_FAMILY) +#error "Running Flash write/erase operations from Flash is not supported on EFM32G." +#endif + +/******************************************************************************* + ****************************** DEFINES ****************************** + ******************************************************************************/ +#if defined(MSC_WRITECTRL_WDOUBLE) +#define WORDS_PER_DATA_PHASE (FLASH_SIZE < (512 * 1024) ? 1 : 2) +#else +#define WORDS_PER_DATA_PHASE (1) +#endif + +#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) +/* Fix for errata FLASH_E201 - Potential program failure after Power On */ +#define ERRATA_FIX_FLASH_E201_EN +#endif + +#if defined(_MSC_ECCCTRL_MASK) +#if defined(_SILICON_LABS_32B_SERIES_1_CONFIG_1) +/* On Series 1 Config 1, EFM32GG11, ECC is supported for RAM0 and RAM1 + banks (not RAM2). It is necessary to figure out which is biggest to + calculate the number of DMA descriptors needed. */ +#define ECC_RAM_SIZE_MAX (SL_MAX(RAM0_MEM_SIZE, RAM1_MEM_SIZE)) + +#define ECC_RAM0_MEM_BASE (RAM0_MEM_BASE) +#define ECC_RAM0_MEM_SIZE (RAM0_MEM_SIZE) + +#define ECC_RAM1_MEM_BASE (RAM1_MEM_BASE) +#define ECC_RAM1_MEM_SIZE (RAM1_MEM_SIZE) + +#define ECC_CTRL_REG_ADDR (&MSC->ECCCTRL) +#define ECC_RAM0_WRITE_EN (_MSC_ECCCTRL_RAMECCEWEN_SHIFT) +#define ECC_RAM0_CHECK_EN (_MSC_ECCCTRL_RAMECCCHKEN_SHIFT) +#define ECC_RAM1_WRITE_EN (_MSC_ECCCTRL_RAM1ECCEWEN_SHIFT) +#define ECC_RAM1_CHECK_EN (_MSC_ECCCTRL_RAM1ECCCHKEN_SHIFT) + +#define ECC_IFC_REG_ADDR (&MSC->IFC) +#define ECC_IFC_MASK (MSC_IFC_RAMERR1B | MSC_IFC_RAMERR2B \ + | MSC_IFC_RAM1ERR1B | MSC_IFC_RAM1ERR2B) +#else +#error Unknown device. +#endif + +#define ECC_DMA_MAX_XFERCNT (_LDMA_CH_CTRL_XFERCNT_MASK \ + >> _LDMA_CH_CTRL_XFERCNT_SHIFT) +#define ECC_DMA_DESC_SIZE ((ECC_DMA_MAX_XFERCNT + 1) * 4) /* 4 bytes units */ + +#define ECC_DMA_DESCS (ECC_RAM_SIZE_MAX / ECC_DMA_DESC_SIZE) + +#endif + +/******************************************************************************* + ****************************** TYPEDEFS ****************************** + ******************************************************************************/ +typedef enum { + mscWriteIntSafe, + mscWriteFast, +} MSC_WriteStrategy_Typedef; + +#if defined(_MSC_ECCCTRL_MASK) +typedef struct { + volatile uint32_t *ctrlReg; + uint32_t writeEnBit; + uint32_t checkEnBit; + volatile uint32_t *ifClearReg; + uint32_t ifClearMask; + uint32_t base; + uint32_t size; +} MSC_EccBank_Typedef; +#endif + +/******************************************************************************* + ****************************** LOCALS ******************************* + ******************************************************************************/ +#if defined(_MSC_ECCCTRL_MASK) +static const MSC_EccBank_Typedef eccBank[MSC_ECC_BANKS] = +{ + { ECC_CTRL_REG_ADDR, ECC_RAM0_WRITE_EN, ECC_RAM0_CHECK_EN, + ECC_IFC_REG_ADDR, ECC_IFC_MASK, + ECC_RAM0_MEM_BASE, ECC_RAM0_MEM_SIZE }, +#if MSC_ECC_BANKS > 1 + { ECC_CTRL_REG_ADDR, ECC_RAM1_WRITE_EN, ECC_RAM1_CHECK_EN, + ECC_IFC_REG_ADDR, ECC_IFC_MASK, + ECC_RAM1_MEM_BASE, ECC_RAM1_MEM_SIZE }, +#endif +}; +#endif + +/******************************************************************************* + ****************************** FUNCTIONS ****************************** + ******************************************************************************/ +MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef +MSC_WriteWordI(uint32_t *address, + void const *data, + uint32_t numBytes, + MSC_WriteStrategy_Typedef writeStrategy); + +MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef +MSC_LoadWriteData(uint32_t* data, + uint32_t numWords, + MSC_WriteStrategy_Typedef writeStrategy); + +MSC_RAMFUNC_DECLARATOR MSC_Status_TypeDef +MSC_LoadVerifyAddress(uint32_t* address); + +#if !defined(EM_MSC_RUN_FROM_FLASH) + +MSC_RAMFUNC_DECLARATOR void mscRfAssertEFM(const char *file, int line); + +/***************************************************************************//** + * @brief + * Local ramfunc assertEFM. + * + * A local ramfunc version of assertEFM is needed because certain MSC functions + * are allocated to RAM. The Flash may get erased and code normally located in + * Flash must therefore have a RAM copy. + * + * This function is invoked through EFM_ASSERT() macro usage only and should + * not be used explicitly. + * + * @param[in] file + * The source file where assertion failed. + * + * @param[in] line + * A line number in the source file where assertion failed. + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +void mscRfAssertEFM(const char *file, int line) +{ + (void)file; /* Unused parameter */ + (void)line; /* Unused parameter */ + + while (true) { + } +} +MSC_RAMFUNC_DEFINITION_END + +/* Undef the define from em_assert.h and redirect to a local ramfunc version. */ +#undef EFM_ASSERT +#if defined(DEBUG_EFM) || defined(DEBUG_EFM_USER) +#define EFM_ASSERT(expr) ((expr) ? ((void)0) : mscRfAssertEFM(__FILE__, __LINE__)) +#else +#define EFM_ASSERT(expr) ((void)(expr)) +#endif /* defined(DEBUG_EFM) || defined(DEBUG_EFM_USER) */ + +#endif /* !EM_MSC_RUN_FROM_FLASH */ + +/** @endcond */ + +/***************************************************************************//** + * @addtogroup emlib + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup MSC + * @{ + ******************************************************************************/ + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Enables the flash controller for writing. + * @note + * This function must be called before flash operations when + * AUXHFRCO clock has been changed from a default band. + ******************************************************************************/ +void MSC_Init(void) +{ +#if defined(_MSC_TIMEBASE_MASK) + uint32_t freq, cycles; +#endif + +#if defined(_EMU_STATUS_VSCALE_MASK) + /* VSCALE must be done. Flash erase and write requires VSCALE2. */ + EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK)); + EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2); +#endif + + /* Unlock the MSC module. */ + MSC->LOCK = MSC_UNLOCK_CODE; + /* Disable writing to the Flash. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + +#if defined(_MSC_TIMEBASE_MASK) + /* Configure MSC->TIMEBASE according to a selected frequency. */ + freq = CMU_ClockFreqGet(cmuClock_AUX); + + /* Timebase 5us is used for the 1/1.2 MHz band only. Note that the 1 MHz band + is tuned to 1.2 MHz on newer revisions. */ + if (freq > 1200000) { + /* Calculate a number of clock cycles for 1 us as a base period. */ + freq = (freq * 11) / 10; + cycles = (freq / 1000000) + 1; + + /* Configure clock cycles for flash timing. */ + MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK + | _MSC_TIMEBASE_PERIOD_MASK)) + | MSC_TIMEBASE_PERIOD_1US + | (cycles << _MSC_TIMEBASE_BASE_SHIFT); + } else { + /* Calculate a number of clock cycles for 5 us as a base period. */ + freq = (freq * 5 * 11) / 10; + cycles = (freq / 1000000) + 1; + + /* Configure clock cycles for flash timing */ + MSC->TIMEBASE = (MSC->TIMEBASE & ~(_MSC_TIMEBASE_BASE_MASK + | _MSC_TIMEBASE_PERIOD_MASK)) + | MSC_TIMEBASE_PERIOD_5US + | (cycles << _MSC_TIMEBASE_BASE_SHIFT); + } +#endif +} + +/***************************************************************************//** + * @brief + * Disables the flash controller for writing. + ******************************************************************************/ +void MSC_Deinit(void) +{ + /* Disable writing to the Flash. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + /* Lock the MSC module.*/ + MSC->LOCK = 0; +} + +/***************************************************************************//** + * @brief + * Set the MSC code execution configuration. + * + * @param[in] execConfig + * The code execution configuration. + ******************************************************************************/ +void MSC_ExecConfigSet(MSC_ExecConfig_TypeDef *execConfig) +{ + uint32_t mscReadCtrl; + +#if defined(MSC_READCTRL_MODE_WS0SCBTP) + mscReadCtrl = MSC->READCTRL & _MSC_READCTRL_MODE_MASK; + if ((mscReadCtrl == MSC_READCTRL_MODE_WS0) && (execConfig->scbtEn)) { + mscReadCtrl |= MSC_READCTRL_MODE_WS0SCBTP; + } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS1) && (execConfig->scbtEn)) { + mscReadCtrl |= MSC_READCTRL_MODE_WS1SCBTP; + } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS0SCBTP) && (!execConfig->scbtEn)) { + mscReadCtrl |= MSC_READCTRL_MODE_WS0; + } else if ((mscReadCtrl == MSC_READCTRL_MODE_WS1SCBTP) && (!execConfig->scbtEn)) { + mscReadCtrl |= MSC_READCTRL_MODE_WS1; + } else { + /* No change needed. */ + } +#endif + + mscReadCtrl = MSC->READCTRL & ~(0 +#if defined(MSC_READCTRL_SCBTP) + | MSC_READCTRL_SCBTP +#endif +#if defined(MSC_READCTRL_USEHPROT) + | MSC_READCTRL_USEHPROT +#endif +#if defined(MSC_READCTRL_PREFETCH) + | MSC_READCTRL_PREFETCH +#endif +#if defined(MSC_READCTRL_ICCDIS) + | MSC_READCTRL_ICCDIS +#endif +#if defined(MSC_READCTRL_AIDIS) + | MSC_READCTRL_AIDIS +#endif +#if defined(MSC_READCTRL_IFCDIS) + | MSC_READCTRL_IFCDIS +#endif + ); + mscReadCtrl |= (0 +#if defined(MSC_READCTRL_SCBTP) + | (execConfig->scbtEn ? MSC_READCTRL_SCBTP : 0) +#endif +#if defined(MSC_READCTRL_USEHPROT) + | (execConfig->useHprot ? MSC_READCTRL_USEHPROT : 0) +#endif +#if defined(MSC_READCTRL_PREFETCH) + | (execConfig->prefetchEn ? MSC_READCTRL_PREFETCH : 0) +#endif +#if defined(MSC_READCTRL_ICCDIS) + | (execConfig->iccDis ? MSC_READCTRL_ICCDIS : 0) +#endif +#if defined(MSC_READCTRL_AIDIS) + | (execConfig->aiDis ? MSC_READCTRL_AIDIS : 0) +#endif +#if defined(MSC_READCTRL_IFCDIS) + | (execConfig->ifcDis ? MSC_READCTRL_IFCDIS : 0) +#endif + ); + + MSC->READCTRL = mscReadCtrl; +} + +#if defined(_MSC_ECCCTRL_MASK) + +/***************************************************************************//** + * @brief + * DMA read and write existing values (for ECC initialization). + * + * @details + * This function uses DMA to read and write the existing data values in + * the RAM region specified by start and size. The function will use the + * 2 DMA channels specified by the channels[2] array. + * + * @param[in] start + * A start address of the address range in RAM to read/write. + * + * @param[in] size + * A size of the address range in RAM to read/write. + * + * @param[in] channels[2] + * An array of 2 DMA channels to use. + ******************************************************************************/ +static void mscEccReadWriteExistingDma(uint32_t start, + uint32_t size, + uint32_t channels[2]) +{ + uint32_t descCnt = 0; + uint32_t dmaDesc[ECC_DMA_DESCS][4]; + uint32_t chMask = (1 << channels[0]) | (1 << channels[1]); + /* Assert that the 2 DMA channel numbers are different. */ + EFM_ASSERT(channels[0] != channels[1]); + + /* Make sure that the ECC_RAM_SIZE_MAX is a multiple of ECC_DMA_DESC_SIZE + to match the total xfer size of the descriptor chain with the largest + ECC RAM bank. */ + EFM_ASSERT((ECC_RAM_SIZE_MAX % ECC_DMA_DESC_SIZE) == 0); + + /* Initialize the LDMA descriptor chain. */ + do { + dmaDesc[descCnt][0] = /* DMA desc CTRL word */ + LDMA_CH_CTRL_STRUCTTYPE_TRANSFER + | LDMA_CH_CTRL_STRUCTREQ + | _LDMA_CH_CTRL_XFERCNT_MASK + | LDMA_CH_CTRL_BLOCKSIZE_ALL + | LDMA_CH_CTRL_REQMODE_ALL + | LDMA_CH_CTRL_SRCINC_ONE + | LDMA_CH_CTRL_SIZE_WORD + | LDMA_CH_CTRL_DSTINC_ONE; + + /* A source and destination address. */ + dmaDesc[descCnt][1] = start; + dmaDesc[descCnt][2] = start; + /* A link to the next descriptor. */ + dmaDesc[descCnt][3] = LDMA_CH_LINK_LINK + | (((uint32_t) &dmaDesc[descCnt + 1][0]) + & _LDMA_CH_LINK_LINKADDR_MASK); + + start += ECC_DMA_DESC_SIZE; + size -= ECC_DMA_DESC_SIZE; + descCnt++; + } while (size); + + /* Divide the descriptor list in two parts, one for each channel, + by setting the link bit and address 0 of the descriptor in the middle + to 0. */ + dmaDesc[(descCnt / 2) - 1][3] = 0; + + /* Set the last descriptor link bit and address to 0. */ + dmaDesc[descCnt - 1][3] = 0; + + /* Start the LDMA clock. */ + CMU_ClockEnable(cmuClock_LDMA, true); + + /* Round robin scheduling for all channels (0 = no fixed priority channels). + */ + LDMA->CTRL = 0 << _LDMA_CTRL_NUMFIXED_SHIFT; + LDMA->CHEN = 0; + LDMA->DBGHALT = 0; + LDMA->REQDIS = 0; + + /* Disable LDMA interrupts and clear interrupt status. */ + LDMA->IEN = 0; + LDMA->IFC = 0xFFFFFFFF; + + /* Disable looping. */ + LDMA->CH[channels[0]].LOOP = 0; + LDMA->CH[channels[1]].LOOP = 0; + + /* Set the descriptor address for the first channel. */ + LDMA->CH[channels[0]].LINK = ((uint32_t)&dmaDesc[0][0]) + & _LDMA_CH_LINK_LINKADDR_MASK; + /* Set the descriptor address for the second channel. */ + LDMA->CH[channels[1]].LINK = ((uint32_t)&dmaDesc[descCnt / 2][0]) + & _LDMA_CH_LINK_LINKADDR_MASK; + /* Clear the channel done flags. */ + BUS_RegMaskedClear(&LDMA->CHDONE, chMask); + + /* Start transfer by loading descriptors. */ + LDMA->LINKLOAD = chMask; + + /* Wait until finished. */ + while (!(((LDMA->CHEN & chMask) == 0) + && ((LDMA->CHDONE & chMask) == chMask))) { + } + + /* Stop the LDMA clock. */ + CMU_ClockEnable(cmuClock_LDMA, false); +} + +/***************************************************************************//** + * @brief + * Initialize ECC for a given memory bank. + * + * @brief + * This function initializes ECC for a given memory bank which is specified + * with the MSC_EccBank_Typedef structure input parameter. + * + * @param[in] eccBank + * The ECC memory bank device structure. + * + * @param[in] dmaChannels + * An array of 2 DMA channels that may be used during ECC initialization. + * + ******************************************************************************/ +static void mscEccBankInit(const MSC_EccBank_Typedef *eccBank, + uint32_t dmaChannels[2]) +{ + uint32_t ctrlReg; + + CORE_DECLARE_IRQ_STATE; + + CORE_ENTER_CRITICAL(); + + /* Enable the ECC write. Keep ECC checking disabled during initialization. */ + ctrlReg = *eccBank->ctrlReg; + ctrlReg |= 1 << eccBank->writeEnBit; + *eccBank->ctrlReg = ctrlReg; + + /* Initialize ECC syndromes by using DMA to read and write the existing + data values in RAM. */ + mscEccReadWriteExistingDma(eccBank->base, eccBank->size, dmaChannels); + + /* Clear any ECC errors that may have been reported before or during + initialization. */ + *eccBank->ifClearReg = eccBank->ifClearMask; + + /* Enable the ECC decoder to detect and report ECC errors. */ + ctrlReg |= 1 << eccBank->checkEnBit; + *eccBank->ctrlReg = ctrlReg; + + CORE_EXIT_CRITICAL(); +} + +/***************************************************************************//** + * @brief + * Disable ECC for a given memory bank. + * + * @brief + * This function disables ECC for a given memory bank which is specified + * with the MSC_EccBank_Typedef structure input parameter. + * + * @param[in] eccBank + * ECC memory bank device structure. + * + ******************************************************************************/ +static void mscEccBankDisable(const MSC_EccBank_Typedef *eccBank) +{ + /* Disable ECC write (encoder) and checking (decoder). */ + *eccBank->ctrlReg &= ~((1 << eccBank->writeEnBit) | (1 << eccBank->checkEnBit)); +} + +/***************************************************************************//** + * @brief + * Configure Error Correcting Code (ECC) + * + * @details + * This function configures ECC support according to the configuration + * input parameter. If the user requests enabling ECC for a given RAM bank, + * this function will initialize ECC memory (syndromes) for the bank by + * reading and writing the existing values in memory, i.e., all data is + * preserved. The initialization process runs in a critical section + * disallowing interrupts and thread scheduling and will consume a + * considerable amount of clock cycles. Therefore, carefully + * assess where to call this function. Consider increasing + * the clock frequency to reduce the execution time. + * This function makes use of 2 DMA channels to move data to/from RAM in an + * efficient way. The user can select which 2 DMA channels to use + * to avoid conflicts with the application. However, make sure + * that no other DMA operations take place while this function is executing. + * If the application is using the DMA controller prior to calling this + * function, the application will need to reinitialize DMA registers after + * this function has completed. + * + * @note + * This function protects the ECC initialization procedure from interrupts + * and other threads by using a critical section (defined by em_core.h) + * When running on an RTOS, the user may need to override CORE_EnterCritical + * CORE_ExitCritical which are declared as 'SL_WEAK' in em_core.c. + * + * @param[in] eccConfig + * ECC configuration + ******************************************************************************/ +void MSC_EccConfigSet(MSC_EccConfig_TypeDef *eccConfig) +{ + unsigned int cnt; + +#if defined(_SILICON_LABS_32B_SERIES_1_CONFIG_1) + /* On Series 1 Config 1, EFM32GG11, disable the ECC fault enable. */ + MSC->CTRL &= ~MSC_CTRL_RAMECCERRFAULTEN; +#endif + + /* Loop through the ECC banks array and enable or disable according to + the eccConfig->enableEccBank array. */ + for (cnt = 0; cnt < MSC_ECC_BANKS; cnt++) { + if (eccConfig->enableEccBank[cnt]) { + mscEccBankInit(&eccBank[cnt], eccConfig->dmaChannels); + } else { + mscEccBankDisable(&eccBank[cnt]); + } + } +} + +#endif /* #if defined(_MSC_ECCCTRL_MASK) */ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @brief + * Perform the address phase of the flash write cycle. + * @details + * This function performs the address phase of a flash write operation by + * writing the given flash address to the ADDRB register and issuing the + * LADDRIM command to load the address. + * @param[in] address + * An address in flash memory. Must be aligned at a 4 byte boundary. + * @return + * Returns the status of the address load operation, #MSC_Status_TypeDef + * @verbatim + * mscReturnOk - The operation completed successfully. + * mscReturnInvalidAddr - The operation tried to erase a non-flash area. + * mscReturnLocked - The operation tried to erase a locked area of the Flash. + * @endverbatim + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_LoadVerifyAddress(uint32_t* address) +{ + uint32_t status; + uint32_t timeOut; + + /* Wait for the MSC to become ready. */ + timeOut = MSC_PROGRAM_TIMEOUT; + while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { + timeOut--; + } + + /* Check for timeout. */ + if (timeOut == 0) { + return mscReturnTimeOut; + } + /* Load the address. */ + MSC->ADDRB = (uint32_t)address; + MSC->WRITECMD = MSC_WRITECMD_LADDRIM; + + status = MSC->STATUS; + if (status & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { + /* Check for an invalid address. */ + if (status & MSC_STATUS_INVADDR) { + return mscReturnInvalidAddr; + } + /* Check for the write protected page. */ + if (status & MSC_STATUS_LOCKED) { + return mscReturnLocked; + } + } + return mscReturnOk; +} +MSC_RAMFUNC_DEFINITION_END + +/***************************************************************************//** + * @brief + * Perform a flash data write phase. + * @details + * This function performs the data phase of a flash write operation by loading + * the given number of 32-bit words to the WDATA register. + * @param[in] data + * A pointer to the first data word to load. + * @param[in] numWords + * A number of data words (32-bit) to load. + * @param[in] writeStrategy + * A write strategy to apply. + * @return + * Returns the status of the data load operation. + * @verbatim + * mscReturnOk - An operation completed successfully. + * mscReturnTimeOut - An operation timed out waiting for the flash operation + * to complete. + * @endverbatim + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_LoadWriteData(uint32_t* data, + uint32_t numWords, + MSC_WriteStrategy_Typedef writeStrategy) +{ + uint32_t timeOut; + uint32_t wordIndex; + bool useWDouble = false; + MSC_Status_TypeDef retval = mscReturnOk; +#if !defined(_EFM32_GECKO_FAMILY) + uint32_t irqState; +#endif + +#if defined(_MSC_WRITECTRL_LPWRITE_MASK) && defined(_MSC_WRITECTRL_WDOUBLE_MASK) + /* If the LPWRITE (Low Power Write) is NOT enabled, set WDOUBLE (Write Double word). */ + if (!(MSC->WRITECTRL & MSC_WRITECTRL_LPWRITE)) { +#if defined(_SILICON_LABS_32B_SERIES_0) + /* If the number of words to be written is odd, align by writing + a single word first, before setting the WDOUBLE bit. */ + if (numWords & 0x1) { + /* Wait for the MSC to become ready for the next word. */ + timeOut = MSC_PROGRAM_TIMEOUT; + while ((!(MSC->STATUS & MSC_STATUS_WDATAREADY)) && (timeOut != 0)) { + timeOut--; + } + /* Check for timeout. */ + if (timeOut == 0) { + return mscReturnTimeOut; + } + /* Clear the double word option to write the initial single word. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; + /* Write first data word. */ + MSC->WDATA = *data++; + MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; + + /* Wait for the operation to finish. It may be required to change the WDOUBLE + configuration after the initial write. It should not be changed while BUSY. */ + timeOut = MSC_PROGRAM_TIMEOUT; + while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { + timeOut--; + } + /* Check for timeout. */ + if (timeOut == 0) { + return mscReturnTimeOut; + } + /* Subtract this initial odd word for the write loop below. */ + numWords -= 1; + retval = mscReturnOk; + } + /* Set the double word option to write two words per + data phase. */ +#endif + MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE; + useWDouble = true; + } +#endif /* defined( _MSC_WRITECTRL_LPWRITE_MASK ) && defined( _MSC_WRITECTRL_WDOUBLE_MASK ) */ + + /* Write the rest as a double word write if wordsPerDataPhase == 2 */ + if (numWords > 0) { + /**** Write strategy: mscWriteIntSafe ****/ + if (writeStrategy == mscWriteIntSafe) { + /* Requires a system core clock at 1MHz or higher */ + EFM_ASSERT(SystemCoreClock >= 1000000); + wordIndex = 0; + while (wordIndex < numWords) { + if (!useWDouble) { + MSC->WDATA = *data++; + wordIndex++; + MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; + } else { // useWDouble == true + /* Trigger a double write according to flash properties. */ +#if defined(_SILICON_LABS_32B_SERIES_0) && defined(_MSC_WRITECTRL_WDOUBLE_MASK) + MSC->WDATA = *data++; + while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)) ; + MSC->WDATA = *data++; + wordIndex += 2; + MSC->WRITECMD = MSC_WRITECMD_WRITEONCE; + +#elif defined(_SILICON_LABS_32B_SERIES_1) && defined(_MSC_WRITECTRL_WDOUBLE_MASK) + while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)) ; + do { + MSC->WDATA = *data++; + wordIndex++; + } while ((MSC->STATUS & MSC_STATUS_WDATAREADY) + && (wordIndex < numWords)); + MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; +#endif + } + + /* Wait for the transaction to finish. */ + timeOut = MSC_PROGRAM_TIMEOUT; + while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { + timeOut--; + } + /* Check for a timeout. */ + if (timeOut == 0) { + retval = mscReturnTimeOut; + break; + } +#if defined(_EFM32_GECKO_FAMILY) + MSC->ADDRB += 4; + MSC->WRITECMD = MSC_WRITECMD_LADDRIM; +#endif + } + } + /**** Write strategy: mscWriteFast ****/ + else { +#if defined(_EFM32_GECKO_FAMILY) + /* Gecko does not have auto-increment of ADDR. */ + EFM_ASSERT(false); +#else + /* Requires a system core clock at 14 MHz or higher. */ + EFM_ASSERT(SystemCoreClock >= 14000000); + + /* + * Protect from interrupts to be sure to satisfy the us timing + * needs of the MSC flash programming state machine. + */ + irqState = __get_PRIMASK(); + __disable_irq(); + + wordIndex = 0; + while (wordIndex < numWords) { + /* Wait for the MSC to be ready for the next word. */ + while (!(MSC->STATUS & MSC_STATUS_WDATAREADY)) { + /* If the write to MSC->WDATA below missed the 30 us timeout and the + following MSC_WRITECMD_WRITETRIG command arrived while + MSC_STATUS_BUSY is 1, the MSC_WRITECMD_WRITETRIG could be ignored by + the MSC. In this case, MSC_STATUS_WORDTIMEOUT is set to 1 + and MSC_STATUS_BUSY is 0. A new trigger is therefore needed to + complete write of data in MSC->WDATA. + If WDATAREADY became high since entering the loop, exit and continue + to the next WDATA write. + */ + if ((MSC->STATUS & (MSC_STATUS_WORDTIMEOUT + | MSC_STATUS_BUSY + | MSC_STATUS_WDATAREADY)) + == MSC_STATUS_WORDTIMEOUT) { + MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; + } + } + + if (!useWDouble) { + MSC->WDATA = *data; + MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; + data++; + wordIndex++; + } else { // useWDouble == true + /* Trigger double write according to flash properties. */ +#if defined(_SILICON_LABS_32B_SERIES_0) + MSC->WDATA = *data; + if (wordIndex & 0x1) { + MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; + } + data++; + wordIndex++; + +#elif (_SILICON_LABS_32B_SERIES_1_CONFIG >= 2) + do { + MSC->WDATA = *data++; + wordIndex++; + } while ((MSC->STATUS & MSC_STATUS_WDATAREADY) + && (wordIndex < numWords)); + MSC->WRITECMD = MSC_WRITECMD_WRITETRIG; +#endif + } + } + + if (irqState == 0) { + /* Restore the previous interrupt state. */ + __enable_irq(); + } + + /* Wait for the transaction to finish. */ + timeOut = MSC_PROGRAM_TIMEOUT; + while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { + timeOut--; + } + /* Check for a timeout. */ + if (timeOut == 0) { + retval = mscReturnTimeOut; + } +#endif + } /* writeStrategy */ + } + +#if defined(_MSC_WRITECTRL_WDOUBLE_MASK) + /* Clear a double word option, which should not be left on when returning. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; +#endif + + return retval; +} +MSC_RAMFUNC_DEFINITION_END + +/***************************************************************************//** + * @brief + * An internal flash write function with the select write strategy parameter. + * @param[in] address + * A write address. + * @param[in] data + * A pointer to the first data word to load. + * @param[in] numBytes + * A nsumber of data bytes to load, which must be a multiple of 4 bytes. + * @param[in] writeStrategy + * A wWrite strategy to apply. + * @return + * Returns the status of the data load operation. + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_WriteWordI(uint32_t *address, + void const *data, + uint32_t numBytes, + MSC_WriteStrategy_Typedef writeStrategy) +{ + uint32_t wordCount; + uint32_t numWords; + uint32_t pageWords; + uint32_t* pData; + MSC_Status_TypeDef retval = mscReturnOk; + + /* Check alignment (must be aligned to words). */ + EFM_ASSERT(((uint32_t) address & 0x3) == 0); + + /* Check a number of bytes. Must be divisible by four. */ + EFM_ASSERT((numBytes & 0x3) == 0); + +#if defined(_EMU_STATUS_VSCALE_MASK) + /* VSCALE must be done and flash write requires VSCALE2. */ + EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK)); + EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2); +#endif + + /* Enable writing to the MSC module. */ + MSC->WRITECTRL |= MSC_WRITECTRL_WREN; + + /* Convert bytes to words. */ + numWords = numBytes >> 2; + EFM_ASSERT(numWords > 0); + + /* The following loop splits the data into chunks corresponding to flash pages. + The address is loaded only once per page because the hardware automatically + increments the address internally for each data load inside a page. */ + for (wordCount = 0, pData = (uint32_t *)data; wordCount < numWords; ) { + /* First, the address is loaded. The address is auto-incremented within a page. + Therefore, the address phase is only needed once for each page. */ + retval = MSC_LoadVerifyAddress(address + wordCount); + if (mscReturnOk != retval) { + return retval; + } + /* Compute the number of words to write to the current page. */ + pageWords = + (FLASH_PAGE_SIZE + - (((uint32_t) (address + wordCount)) & (FLASH_PAGE_SIZE - 1))) + / sizeof(uint32_t); + if (pageWords > numWords - wordCount) { + pageWords = numWords - wordCount; + } + /* Write the data in the current page. */ + retval = MSC_LoadWriteData(pData, pageWords, writeStrategy); + if (mscReturnOk != retval) { + break; + } + wordCount += pageWords; + pData += pageWords; + } + +#if defined(ERRATA_FIX_FLASH_E201_EN) + /* Fix for errata FLASH_E201 - Potential program failure after Power On. + * + * Check if the first word was programmed correctly. If a failure is detected, + * retry programming of the first word. + * + * A full description of the errata is in the errata document. */ + pData = (uint32_t *) data; + if (*address != *pData) { + retval = MSC_LoadVerifyAddress(address); + if (mscReturnOk == retval) { + retval = MSC_LoadWriteData(pData, 1, writeStrategy); + } + } +#endif + + /* Disable writing to the MSC module. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + +#if defined(_MSC_WRITECTRL_WDOUBLE_MASK) +#if (WORDS_PER_DATA_PHASE == 2) + /* Turn off the double word write cycle support. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE; +#endif +#endif + + return retval; +} +MSC_RAMFUNC_DEFINITION_END + +/** @endcond */ + +/***************************************************************************//** + * @brief + * Erases a page in flash memory. + * @note + * It is recommended to run this code from RAM. On the Gecko family, it is required + * to run this function from RAM. + * + * For IAR IDE, Rowley IDE, SimplicityStudio IDE, Atollic IDE, and ARM GCC IDE, this is + * achieved automatically by using attributes in the function proctype. For Keil + * uVision IDE, define a section called "ram_code" and place this manually in + * the project's scatter file. + * + * @param[in] startAddress + * A pointer to the flash page to erase. Must be aligned to the beginning of the page + * boundary. + * @return + * Returns the status of erase operation, #MSC_Status_TypeDef + * @verbatim + * mscReturnOk - The operation completed successfully. + * mscReturnInvalidAddr - The operation tried to erase a non-flash area. + * mscReturnLocked - The operation tried to erase a locked area of the flash. + * mscReturnTimeOut - The operation timed out waiting for the flash operation + * to complete. + * @endverbatim + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_ErasePage(uint32_t *startAddress) +{ + uint32_t timeOut = MSC_PROGRAM_TIMEOUT; + + /* An address must be aligned to pages. */ + EFM_ASSERT((((uint32_t) startAddress) & (FLASH_PAGE_SIZE - 1)) == 0); +#if defined(_EMU_STATUS_VSCALE_MASK) + /* VSCALE must be done and flash erase requires VSCALE2. */ + EFM_ASSERT(!(EMU->STATUS & _EMU_STATUS_VSCALEBUSY_MASK)); + EFM_ASSERT((EMU->STATUS & _EMU_STATUS_VSCALE_MASK) == EMU_STATUS_VSCALE_VSCALE2); +#endif + + /* Enable writing to the MSC module. */ + MSC->WRITECTRL |= MSC_WRITECTRL_WREN; + + /* Load an address. */ + MSC->ADDRB = (uint32_t)startAddress; + MSC->WRITECMD = MSC_WRITECMD_LADDRIM; + + /* Check for an invalid address. */ + if (MSC->STATUS & MSC_STATUS_INVADDR) { + /* Disable writing to the MSC */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + return mscReturnInvalidAddr; + } + /* Check for write protected page. */ + if (MSC->STATUS & MSC_STATUS_LOCKED) { + /* Disable writing to the MSC module. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + return mscReturnLocked; + } + /* Send erase page command. */ + MSC->WRITECMD = MSC_WRITECMD_ERASEPAGE; + + /* Wait for the erase to complete. */ + while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0)) { + timeOut--; + } + if (timeOut == 0) { + /* Disable writing to the MSC module. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + return mscReturnTimeOut; + } + /* Disable writing to the MSC module. */ + MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN; + return mscReturnOk; +} +MSC_RAMFUNC_DEFINITION_END + +/***************************************************************************//** + * @brief + * Writes data to flash memory. This function is interrupt-safe, but slower than + * MSC_WriteWordFast(), which writes to flash with interrupts disabled. + * Write data must be aligned to words and contain a number of bytes that is + * divisible by four. + * @note + * It is recommended to erase the flash page before performing a write. + * + * It is recommended to run this code from RAM. On the Gecko family, it is required + * to run this function from RAM. + * + * For IAR IDE, Rowley IDE, SimplicityStudio IDE, Atollic IDE, and ARM GCC IDE, + * this is done automatically by using attributes in the function proctype. + * For Keil uVision IDE, define a section called "ram_code" and place it + * manually in the project's scatter file. + * + * This function requires a system core clock at 1 MHz or higher. + * + * @param[in] address + * A pointer to the flash word to write to. Must be aligned to words. + * @param[in] data + * Data to write to flash. + * @param[in] numBytes + * A number of bytes to write from flash. NB: Must be divisible by four. + * @return + * Returns the status of the write operation. + * @verbatim + * flashReturnOk - The operation completed successfully. + * flashReturnInvalidAddr - The operation tried to erase a non-flash area. + * flashReturnLocked - The operation tried to erase a locked area of the Flash. + * flashReturnTimeOut - The operation timed out waiting for the flash operation + * to complete, or the MSC module timed out waiting for the software to write + * the next word into the DWORD register. + * @endverbatim + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_WriteWord(uint32_t *address, + void const *data, + uint32_t numBytes) +{ + return MSC_WriteWordI(address, data, numBytes, mscWriteIntSafe); +} +MSC_RAMFUNC_DEFINITION_END + +#if !defined(_EFM32_GECKO_FAMILY) +/***************************************************************************//** + * @brief + * Writes data to flash memory. This function is faster than MSC_WriteWord(), + * but it disables interrupts. Write data must be aligned to words and contain + * a number of bytes that is divisible by four. + * @note + * It is recommended to erase the flash page before performing a write. + * It is required to run this function from RAM on parts that include a + * flash write buffer. + * + * For IAR IDE, Rowley IDE, SimplicityStudio IDE, Atollic IDE, and ARM GCC IDE, + * this is done automatically by using attributes in the function proctype. + * For Keil uVision IDE, define a section called "ram_code" and place this manually + * in the project's scatter file. + * + * @param[in] address + * A pointer to the flash word to write to. Must be aligned to words. + * @param[in] data + * Data to write to flash. + * @param[in] numBytes + * A number of bytes to write from the Flash. NB: Must be divisible by four. + * @return + * Returns the status of the write operation. + * @verbatim + * flashReturnOk - The operation completed successfully. + * flashReturnInvalidAddr - The operation tried to erase a non-flash area. + * flashReturnLocked - The operation tried to erase a locked area of the flash. + * flashReturnTimeOut - The operation timed out waiting for flash operation + * to complete. Or the MSC timed out waiting for the software to write + * the next word into the DWORD register. + * @endverbatim + ******************************************************************************/ +#if !defined (EM_MSC_RUN_FROM_FLASH) || (_SILICON_LABS_GECKO_INTERNAL_SDID < 84) +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_WriteWordFast(uint32_t *address, + void const *data, + uint32_t numBytes) +{ + return MSC_WriteWordI(address, data, numBytes, mscWriteFast); +} +MSC_RAMFUNC_DEFINITION_END + +#endif +#endif + +#if defined(_MSC_MASSLOCK_MASK) +/***************************************************************************//** + * @brief + * Erase the entire Flash in one operation. + * + * @note + * This command will erase the entire contents of the device. + * Use with care, both a debug session and all contents of the flash will be + * lost. The lock bit, MLW will prevent this operation from executing and + * might prevent a successful mass erase. + ******************************************************************************/ +MSC_RAMFUNC_DEFINITION_BEGIN +MSC_Status_TypeDef MSC_MassErase(void) +{ + /* Enable writing to the MSC module. */ + MSC->WRITECTRL |= MSC_WRITECTRL_WREN; + + /* Unlock the device mass erase. */ + MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_UNLOCK; + + /* Erase the first 512 K block. */ + MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN0; + + /* Waiting for erase to complete. */ + while ((MSC->STATUS & MSC_STATUS_BUSY) != 0U) { + } + +#if ((FLASH_SIZE >= (512 * 1024)) && defined(_MSC_WRITECMD_ERASEMAIN1_MASK)) + /* Erase the second 512 K block. */ + MSC->WRITECMD = MSC_WRITECMD_ERASEMAIN1; + + /* Waiting for erase to complete. */ + while ((MSC->STATUS & MSC_STATUS_BUSY) != 0U) { + } +#endif + + /* Restore the mass erase lock. */ + MSC->MASSLOCK = MSC_MASSLOCK_LOCKKEY_LOCK; + + /* This will only successfully return if calling function is also in SRAM. */ + return mscReturnOk; +} +MSC_RAMFUNC_DEFINITION_END + +#endif + +/** @} (end addtogroup MSC) */ +/** @} (end addtogroup emlib) */ +#endif /* defined(MSC_COUNT) && (MSC_COUNT > 0) */ diff --git a/efm32/src/device.c b/efm32/src/device.c index 03a0efd..d1c0268 100644 --- a/efm32/src/device.c +++ b/efm32/src/device.c @@ -13,6 +13,7 @@ #include "em_usart.h" #include "em_adc.h" #include "em_cmu.h" +#include "em_msc.h" #include "InitDevice.h" #include "cbor.h" @@ -25,20 +26,70 @@ #define RDY_PIN gpioPortC,10 #define RW_PIN gpioPortD,11 +#define PAGE_SIZE 2048 +#define PAGES 128 +#define COUNTER_PAGE 125 +#define STATE1_PAGE 126 +#define STATE2_PAGE 127 + + + +static void init_atomic_counter() +{ + int offset = 0; + uint32_t count; + uint32_t one = 1; + uint32_t * ptr = PAGE_SIZE * COUNTER_PAGE; + + for (offset = 0; offset < PAGE_SIZE/4; offset += 1) + { + count = *(ptr+offset); + if (count != 0xffffffff) + { + return; + } + } + MSC_WriteWordFast(ptr,&one,4); +} + -uint32_t _c1 = 0, _c2 = 0; uint32_t ctap_atomic_count(int sel) { - if (sel == 0) + int offset = 0; + uint32_t count; + uint32_t zero = 0; + uint32_t * ptr = PAGE_SIZE * COUNTER_PAGE; + + if (sel != 0) { - _c1++; - return _c1; + printf2(TAG_ERR,"counter2 not imple\n"); + exit(1); } - else + + for (offset = 0; offset < PAGE_SIZE/4; offset += 1) // wear-level the flash { - _c2++; - return _c2; + count = *(ptr+offset); + if (count != 0) + { + count++; + offset++; + if (offset == PAGE_SIZE/4) + { + offset = 0; + MSC_ErasePage(ptr); + /*printf("RESET page counter\n");*/ + } + else + { + MSC_WriteWordFast(ptr+offset-1,&zero,4); + } + MSC_WriteWordFast(ptr+offset,&count,4); + + break; + } } + + return count; } // Verify the user @@ -166,7 +217,7 @@ void GPIO_ODD_IRQHandler() GPIO->IFC = flag; if (flag & (1<<9)) { - // printf("pin 9 interrupt\r\n"); + // printf("pin 9 interrupt\r\n"); msgs_to_recv++; } else @@ -201,28 +252,40 @@ void init_adc() ADC0->SINGLEFIFOCLEAR = ADC_SINGLEFIFOCLEAR_SINGLEFIFOCLEAR; } + + static uint8_t _STATE1[sizeof(AuthenticatorState)]; static uint8_t _STATE2[sizeof(AuthenticatorState)]; void authenticator_read_state(AuthenticatorState * state) { - memmove(state,_STATE1,sizeof(AuthenticatorState)); + uint32_t * ptr = PAGE_SIZE*STATE1_PAGE; + memmove(state,ptr,sizeof(AuthenticatorState)); } void authenticator_read_backup_state(AuthenticatorState * state ) { - memmove(state,_STATE2,sizeof(AuthenticatorState)); + uint32_t * ptr = PAGE_SIZE*STATE2_PAGE; + memmove(state,ptr,sizeof(AuthenticatorState)); } void authenticator_write_state(AuthenticatorState * state, int backup) { + uint32_t * ptr; + int i; if (! backup) { - memmove(_STATE1,state,sizeof(AuthenticatorState)); + ptr = PAGE_SIZE*STATE1_PAGE; + MSC_ErasePage(ptr); + // for (i = 0; i < sizeof(AuthenticatorState)/4; i++ ) + MSC_WriteWordFast(ptr,state,sizeof(AuthenticatorState) + (sizeof(AuthenticatorState)%4)); } else { - memmove(_STATE2,state,sizeof(AuthenticatorState)); + ptr = PAGE_SIZE*STATE2_PAGE; + MSC_ErasePage(ptr); + // for (i = 0; i < sizeof(AuthenticatorState)/4; i++ ) + MSC_WriteWordFast(ptr,state,sizeof(AuthenticatorState) + (sizeof(AuthenticatorState)%4)); } } @@ -230,7 +293,9 @@ void authenticator_write_state(AuthenticatorState * state, int backup) int authenticator_is_backup_initialized() { uint8_t header[16]; - AuthenticatorState * state = (AuthenticatorState*) _STATE2; + uint32_t * ptr = PAGE_SIZE*STATE2_PAGE; + memmove(header,ptr,16); + AuthenticatorState * state = (AuthenticatorState*)header; return state->is_initialized == INITIALIZED_MARKER; } @@ -275,6 +340,14 @@ void device_init(void) init_adc(); + MSC_Init(); + init_atomic_counter(); + if (sizeof(AuthenticatorState) > PAGE_SIZE) + { + printf2(TAG_ERR, "not enough room in page\n"); + exit(1); + } + CborEncoder test; uint8_t buf[64]; cbor_encoder_init(&test, buf, 20, 0); @@ -284,7 +357,7 @@ void device_init(void) for (i = 0; i < sizeof(buf); i++) { - buf[i] = adc_rng(); + buf[i] = adc_rng(); } dump_hex(buf,sizeof(buf)); } diff --git a/fido2/storage.h b/fido2/storage.h index f3a386e..a0c60e2 100644 --- a/fido2/storage.h +++ b/fido2/storage.h @@ -4,7 +4,7 @@ #include "ctap.h" #define KEY_SPACE_BYTES 128 -#define MAX_KEYS (KEY_SPACE_BYTES/1) +#define MAX_KEYS (1) #define BACKUP_MARKER 0x5A #define INITIALIZED_MARKER 0xA5 diff --git a/fido2/wallet.c b/fido2/wallet.c index eb5effd..d3084bf 100644 --- a/fido2/wallet.c +++ b/fido2/wallet.c @@ -213,7 +213,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui printf1(TAG_WALLET, "u2f2wallet [%d]: ",reqlen); dump_hex1(TAG_WALLET, msg_buf,reqlen); - if (req->operation != WalletRng) + if (req->operation == WalletRegister || req->operation == WalletSign) { count = ctap_atomic_count(0); } diff --git a/pc/device.c b/pc/device.c index b96da85..b80e538 100644 --- a/pc/device.c +++ b/pc/device.c @@ -190,7 +190,8 @@ uint32_t ctap_atomic_count(int sel) } else { - return counter2++; + printf2(TAG_ERR,"counter2 not imple\n"); + exit(1); } } diff --git a/web/js/wallet.js b/web/js/wallet.js index 1fb559d..f2949a6 100644 --- a/web/js/wallet.js +++ b/web/js/wallet.js @@ -1157,22 +1157,30 @@ async function run_tests() { var p = await dev.register(wif); TEST(p.status == 'CTAP1_SUCCESS', 'Wallet accepts good WIF key'); - - for (i = 0; i < 10; i++) + var count,lcount; + lcount = -1; + for (i = 0; i < 2048; i++) { t1 = performance.now(); p = await dev.sign({challenge: chal}); t2 = performance.now(); var ver = key.verify(chal, p.sig); + count = p.count; TEST(ver && p.status == 'CTAP1_SUCCESS', 'Wallet returns signature ('+(t2-t1)+' ms)'); + if (i != 0) TEST(count == (lcount+1), 'Count increased by 1 ('+count+')'); + + lcount = count; } } - await device_start_over(); - //await test_pin(); - //await test_crypto(); - //await test_rng(); + while(1) + { + await device_start_over(); + await test_pin(); + await test_crypto(); + await test_rng(); + } await benchmark(); }