/** @brief Dump fuse values * * Reply fields: low, high, extended fuse bytes (u8s) */ static void cmd_fuse_read(void) { reply_success(3); send_u8(boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)); send_u8(boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)); send_u8(boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)); }
void fuse_info(void) { uint8_t lowfuse, hifuse, extfuse, lockfuse; cli(); lowfuse = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS); hifuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); extfuse = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS); lockfuse = boot_lock_fuse_bits_get(GET_LOCK_BITS); sei(); term_printf("\r\nFuses: l=%02X h=%02X e=%02X l=%02X\r\n", lowfuse, hifuse, extfuse, lockfuse); }
CDWORD BootloaderAllocatedSize() { #ifndef SPM_PAGESIZE return 0; #else STATIC DWORD BOOTLOADER_SIZE = 0; #if defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) #define BOOTSIZE_FACTOR_FUSE_BYTE GET_EXTENDED_FUSE_BITS #define BOOTSIZE_FACTOR_FACTOR 5 #else #define BOOTSIZE_FACTOR_FUSE_BYTE GET_HIGH_FUSE_BITS #define BOOTSIZE_FACTOR_FACTOR 4 #endif __fuse_byte_high_or_extended = boot_lock_fuse_bits_get(BOOTSIZE_FACTOR_FUSE_BYTE); STATIC BYTE bootSizeFactor = CHECK_BITS(__fuse_byte_high_or_extended, BOOTSZ1 OR BOOTSZ0) SHR 0b1; BOOTLOADER_SIZE = 2 ^ (BOOTSIZE_FACTOR_FACTOR - bootSizeFactor) * SPM_PAGESIZE; return static_cast<CDWORD>(BOOTLOADER_SIZE); #endif }
/** \brief initialize MCU status by watchdog reset * * FIXME: needs doc */ void bootloader_jump(void) { #if !defined(BOOTLOADER_SIZE) uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); if (high_fuse & BOOT_SIZE_256) { bootloader_start = (FLASH_SIZE - 512) >> 1; } else if (high_fuse & BOOT_SIZE_512) {
uint8_t BootloaderAPI_ReadLock(void) { return boot_lock_fuse_bits_get(GET_LOCK_BITS); }
uint8_t BootloaderAPI_ReadFuse(const uint16_t Address) { return boot_lock_fuse_bits_get(Address); }
/** Special startup routine to check if the bootloader was started via a watchdog reset, and if the magic application * start key has been loaded into \ref MagicBootKey. If the bootloader started via the watchdog and the key is valid, * this will force the user application to start via a software jump. */ void Application_Jump_Check(void) { bool JumpToApplication = false; #if (BOARD == BOARD_LEONARDO) /* Enable pull-up on the IO13 pin so we can use it to select the mode */ PORTC |= (1 << 7); Delay_MS(10); /* If IO13 is not jumpered to ground, start the user application instead */ JumpToApplication = ((PINC & (1 << 7)) != 0); /* Disable pull-up after the check has completed */ PORTC &= ~(1 << 7); #elif ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)) /* Disable JTAG debugging */ JTAG_DISABLE(); /* Enable pull-up on the JTAG TCK pin so we can use it to select the mode */ PORTF |= (1 << 4); Delay_MS(10); /* If the TCK pin is not jumpered to ground, start the user application instead */ JumpToApplication = ((PINF & (1 << 4)) != 0); /* Re-enable JTAG debugging */ JTAG_ENABLE(); #else /* Check if the device's BOOTRST fuse is set */ if (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) & FUSE_BOOTRST) { /* If the reset source was not an external reset or the key is correct, clear it and jump to the application */ if (!(MCUSR & (1 << EXTRF)) || (MagicBootKey == MAGIC_BOOT_KEY)) JumpToApplication = true; /* Clear reset source */ MCUSR &= ~(1 << EXTRF); } else { /* If the reset source was the bootloader and the key is correct, clear it and jump to the application; * this can happen in the HWBE fuse is set, and the HBE pin is low during the watchdog reset */ if ((MCUSR & (1 << WDRF)) && (MagicBootKey == MAGIC_BOOT_KEY)) JumpToApplication = true; /* Clear reset source */ MCUSR &= ~(1 << WDRF); } #endif /* Don't run the user application if the reset vector is blank (no app loaded) */ bool ApplicationValid = (pgm_read_word_near(0) != 0xFFFF); /* If a request has been made to jump to the user application, honor it */ if (JumpToApplication && ApplicationValid) { /* Turn off the watchdog */ MCUSR &= ~(1 << WDRF); wdt_disable(); /* Clear the boot key and jump to the user application */ MagicBootKey = 0; // cppcheck-suppress constStatement ((void (*)(void))0x0000)(); } }
/*! \fn main(void) * \brief Main function */ int main(void) { uint16_t current_bootkey_val = eeprom_read_word((uint16_t*)EEP_BOOTKEY_ADDR); RET_TYPE flash_init_result; RET_TYPE touch_init_result; RET_TYPE card_detect_ret; uint8_t fuse_ok = TRUE; // Disable JTAG to gain access to pins, set prescaler to 1 (fuses not set) #ifndef PRODUCTION_KICKSTARTER_SETUP disableJTAG(); CPU_PRESCALE(0); #endif // Check fuse settings: boot reset vector, 2k words, SPIEN, BOD 2.6V, programming & ver disabled if ((boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS) != 0xFF) || (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) != 0xD8) || (boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS) != 0xFB) || (boot_lock_fuse_bits_get(GET_LOCK_BITS) != 0xFC)) { fuse_ok = FALSE; } // Check if PB5 is low to start electrical test DDRB &= ~(1 << 5); PORTB |= (1 << 5); smallForLoopBasedDelay(); if (!(PINB & (1 << 5))) { // Test result, true by default uint8_t test_result = TRUE; // Leave flash nS off DDR_FLASH_nS |= (1 << PORTID_FLASH_nS); PORT_FLASH_nS |= (1 << PORTID_FLASH_nS); // Set PORTD as output, leave PORTID_OLED_SS high DDRD |= 0xFF; PORTD |= 0xFF; // All other pins are input by default, run our test for (uint8_t i = 0; i < 4; i++) { PORTD |= 0xFF; smallForLoopBasedDelay(); if (!(PINF & (0xC3)) || !(PINC & (1 << 6)) || !(PINE & (1 << 6)) || !(PINB & (1 << 4))) { test_result = FALSE; } PORTD &= (1 << PORTID_OLED_SS); smallForLoopBasedDelay(); if ((PINF & (0xC3)) || (PINC & (1 << 6)) || (PINE & (1 << 6)) || (PINB & (1 << 4))) { test_result = FALSE; } } // PB6 as test result output DDRB |= (1 << 6); // If test successful, light green LED if ((test_result == TRUE) && (fuse_ok == TRUE)) { PORTB |= (1 << 6); } else { PORTB &= ~(1 << 6); } while(1); } // This code will only be used for developers and beta testers #if !defined(PRODUCTION_SETUP) && !defined(PRODUCTION_KICKSTARTER_SETUP) // Check if we were reset and want to go to the bootloader if (current_bootkey_val == BOOTLOADER_BOOTKEY) { // Disable WDT wdt_reset(); wdt_clear_flag(); wdt_change_enable(); wdt_stop(); // Store correct bootkey eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); // Jump to bootloader start_bootloader(); } // Check if there was a change in the mooltipass setting storage to reset the parameters to their correct values if (getMooltipassParameterInEeprom(USER_PARAM_INIT_KEY_PARAM) != USER_PARAM_CORRECT_INIT_KEY) { mooltipassParametersInit(); setMooltipassParameterInEeprom(USER_PARAM_INIT_KEY_PARAM, USER_PARAM_CORRECT_INIT_KEY); } #endif // First time initializations for Eeprom (first boot at production or flash layout changes for beta testers) if (current_bootkey_val != CORRECT_BOOTKEY) { // Erase Mooltipass parameters mooltipassParametersInit(); // Set bootloader password bool to FALSE eeprom_write_byte((uint8_t*)EEP_BOOT_PWD_SET, FALSE); } /* Check if a card is inserted in the Mooltipass to go to the bootloader */ #ifdef AVR_BOOTLOADER_PROGRAMMING /* Disable JTAG to get access to the pins */ disableJTAG(); /* Init SMC port */ initPortSMC(); /* Delay for detection */ smallForLoopBasedDelay(); #if defined(HARDWARE_V1) if (PIN_SC_DET & (1 << PORTID_SC_DET)) #elif defined(HARDWARE_OLIVIER_V1) if (!(PIN_SC_DET & (1 << PORTID_SC_DET))) #endif { uint16_t tempuint16; /* What follows is a copy from firstDetectFunctionSMC() */ /* Enable power to the card */ PORT_SC_POW &= ~(1 << PORTID_SC_POW); /* Default state: PGM to 0 and RST to 1 */ PORT_SC_PGM &= ~(1 << PORTID_SC_PGM); DDR_SC_PGM |= (1 << PORTID_SC_PGM); PORT_SC_RST |= (1 << PORTID_SC_RST); DDR_SC_RST |= (1 << PORTID_SC_RST); /* Activate SPI port */ PORT_SPI_NATIVE &= ~((1 << SCK_SPI_NATIVE) | (1 << MOSI_SPI_NATIVE)); DDRB |= (1 << SCK_SPI_NATIVE) | (1 << MOSI_SPI_NATIVE); setSPIModeSMC(); /* Let the card come online */ smallForLoopBasedDelay(); /* Check smart card FZ */ readFabricationZone((uint8_t*)&tempuint16); if ((swap16(tempuint16)) != SMARTCARD_FABRICATION_ZONE) { removeFunctionSMC(); start_bootloader(); } else { removeFunctionSMC(); } } #endif initPortSMC(); // Initialize smart card port initPwm(); // Initialize PWM controller initIRQ(); // Initialize interrupts powerSettlingDelay(); // Let the power settle initUsb(); // Initialize USB controller powerSettlingDelay(); // Let the USB 3.3V LDO rise initI2cPort(); // Initialize I2C interface rngInit(); // Initialize avrentropy library oledInitIOs(); // Initialize OLED input/outputs spiUsartBegin(SPI_RATE_8_MHZ); // Start USART SPI at 8MHz // If offline mode isn't enabled, wait for device to be enumerated if (getMooltipassParameterInEeprom(OFFLINE_MODE_PARAM) == FALSE) { while(!isUsbConfigured()); // Wait for host to set configuration } // Set correct timeout_enabled val mp_timeout_enabled = getMooltipassParameterInEeprom(LOCK_TIMEOUT_ENABLE_PARAM); // Launch the before flash initialization tests #ifdef TESTS_ENABLED beforeFlashInitTests(); #endif // Check if we can initialize the Flash memory flash_init_result = initFlash(); // Launch the after flash initialization tests #ifdef TESTS_ENABLED afterFlashInitTests(); #endif // Set up OLED now that USB is receiving full 500mA. oledBegin(FONT_DEFAULT); // First time initializations for Flash (first time power up at production) if (current_bootkey_val != CORRECT_BOOTKEY) { // Erase everything non graphic in flash eraseFlashUsersContents(); // Erase # of cards and # of users firstTimeUserHandlingInit(); } // Check if we can initialize the touch sensing element touch_init_result = initTouchSensing(); // Enable proximity detection #ifndef HARDWARE_V1 activateProxDetection(); #endif // Launch the after touch initialization tests #ifdef TESTS_ENABLED afterTouchInitTests(); #endif // Test procedure to check that all HW is working #if defined(PRODUCTION_SETUP) || defined(PRODUCTION_KICKSTARTER_SETUP) if (current_bootkey_val != CORRECT_BOOTKEY) { RET_TYPE temp_rettype; // Wait for USB host to upload bundle, which then sets USER_PARAM_INIT_KEY_PARAM //#ifdef PRODUCTION_KICKSTARTER_SETUP while(getMooltipassParameterInEeprom(USER_PARAM_INIT_KEY_PARAM) != 0xF1) { usbProcessIncoming(USB_CALLER_MAIN); } //#endif // Bundle uploaded, start the screen oledBegin(FONT_DEFAULT); oledWriteActiveBuffer(); oledSetXY(0,0); // LEDs ON, to check setPwmDc(MAX_PWM_VAL); switchOnButtonWheelLeds(); guiDisplayRawString(ID_STRING_TEST_LEDS_CH); // Check flash init if (flash_init_result != RETURN_OK) { guiDisplayRawString(ID_STRING_TEST_FLASH_PB); } // Check touch init if (touch_init_result != RETURN_OK) { guiDisplayRawString(ID_STRING_TEST_TOUCH_PB); } // Touch instructions guiDisplayRawString(ID_STRING_TEST_INST_TCH); // Check prox while(!(touchDetectionRoutine(0) & RETURN_PROX_DETECTION)); guiDisplayRawString(ID_STRING_TEST_DET); activateGuardKey(); // Check left while(!(touchDetectionRoutine(0) & RETURN_LEFT_PRESSED)); guiDisplayRawString(ID_STRING_TEST_LEFT); // Check wheel while(!(touchDetectionRoutine(0) & RETURN_WHEEL_PRESSED)); guiDisplayRawString(ID_STRING_TEST_WHEEL); // Check right while(!(touchDetectionRoutine(0) & RETURN_RIGHT_PRESSED)); guiDisplayRawString(ID_STRING_TEST_RIGHT); // Insert card guiDisplayRawString(ID_STRING_TEST_CARD_INS); while(isCardPlugged() != RETURN_JDETECT); temp_rettype = cardDetectedRoutine(); // Check card if (!((temp_rettype == RETURN_MOOLTIPASS_BLANK) || (temp_rettype == RETURN_MOOLTIPASS_USER))) { guiDisplayRawString(ID_STRING_TEST_CARD_PB); } // Display result uint8_t script_return = RETURN_OK; if ((flash_init_result == RETURN_OK) && (touch_init_result == RETURN_OK) && ((temp_rettype == RETURN_MOOLTIPASS_BLANK) || (temp_rettype == RETURN_MOOLTIPASS_USER))) { // Inform script of success usbSendMessage(CMD_FUNCTIONAL_TEST_RES, 1, &script_return); // Wait for password to be set while(eeprom_read_byte((uint8_t*)EEP_BOOT_PWD_SET) != BOOTLOADER_PWDOK_KEY) { usbProcessIncoming(USB_CALLER_MAIN); } // Display test result guiDisplayRawString(ID_STRING_TEST_OK); timerBasedDelayMs(3000); } else { // Set correct bool script_return = RETURN_NOK; // Display test result guiDisplayRawString(ID_STRING_TEST_NOK); // Inform script of failure usbSendMessage(CMD_FUNCTIONAL_TEST_RES, 1, &script_return); while(1) { usbProcessIncoming(USB_CALLER_MAIN); } } } #endif // Stop the Mooltipass if we can't communicate with the flash or the touch interface #if defined(HARDWARE_OLIVIER_V1) #ifdef PRODUCTION_KICKSTARTER_SETUP while ((flash_init_result != RETURN_OK) || (touch_init_result != RETURN_OK) || (fuse_ok != TRUE)); #else while ((flash_init_result != RETURN_OK) || (touch_init_result != RETURN_OK)); #endif #endif // First time initializations done.... write correct value in eeprom if (current_bootkey_val != CORRECT_BOOTKEY) { // Store correct bootkey eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); } // Write inactive buffer & go to startup screen oledWriteInactiveBuffer(); guiSetCurrentScreen(SCREEN_DEFAULT_NINSERTED); guiGetBackToCurrentScreen(); // Launch the after HaD logo display tests #ifdef TESTS_ENABLED afterHadLogoDisplayTests(); #endif // Let's fade in the LEDs for (uint16_t i = 0; i < MAX_PWM_VAL; i++) { setPwmDc(i); timerBasedDelayMs(0); } activityDetectedRoutine(); launchCalibrationCycle(); touchClearCurrentDetections(); // Inhibit touch inputs for the first 3 seconds activateTimer(TIMER_TOUCH_INHIBIT, 3000); while (1) { // Process possible incoming USB packets usbProcessIncoming(USB_CALLER_MAIN); // Call GUI routine once the touch input inhibit timer is finished if (hasTimerExpired(TIMER_TOUCH_INHIBIT, FALSE) == TIMER_EXPIRED) { guiMainLoop(); } // Check if a card just got inserted / removed card_detect_ret = isCardPlugged(); // Do appropriate actions on smartcard insertion / removal if (card_detect_ret == RETURN_JDETECT) { // Light up the Mooltipass and call the dedicated function activityDetectedRoutine(); handleSmartcardInserted(); } else if (card_detect_ret == RETURN_JRELEASED) { // Light up the Mooltipass and call the dedicated function activityDetectedRoutine(); handleSmartcardRemoved(); // Set correct screen guiDisplayInformationOnScreen(ID_STRING_CARD_REMOVED); guiSetCurrentScreen(SCREEN_DEFAULT_NINSERTED); userViewDelay(); guiGetBackToCurrentScreen(); } // Two quick caps lock presses wakes up the device if ((hasTimerExpired(TIMER_CAPS, FALSE) == TIMER_EXPIRED) && (getKeyboardLeds() & HID_CAPS_MASK) && (wasCapsLockTimerArmed == FALSE)) { wasCapsLockTimerArmed = TRUE; activateTimer(TIMER_CAPS, CAPS_LOCK_DEL); } else if ((hasTimerExpired(TIMER_CAPS, FALSE) == TIMER_RUNNING) && !(getKeyboardLeds() & HID_CAPS_MASK)) { activityDetectedRoutine(); } else if ((hasTimerExpired(TIMER_CAPS, FALSE) == TIMER_EXPIRED) && !(getKeyboardLeds() & HID_CAPS_MASK)) { wasCapsLockTimerArmed = FALSE; } // If we have a timeout lock if ((mp_timeout_enabled == TRUE) && (hasTimerExpired(SLOW_TIMER_LOCKOUT, TRUE) == TIMER_EXPIRED)) { guiSetCurrentScreen(SCREEN_DEFAULT_INSERTED_LCK); guiGetBackToCurrentScreen(); handleSmartcardRemoved(); } } }
/*! \fn main(void) * \brief Main function * \note For our security chain to be valid, EEP_BOOT_PWD_SET in eeprom needs to be set to BOOTLOADER_PWDOK_KEY */ int main(void) { /* Fetch bootkey in eeprom */ uint16_t current_bootkey_val = eeprom_read_word((uint16_t*)EEP_BOOTKEY_ADDR); // Bootkey in EEPROM uint8_t new_aes_key[AES_KEY_LENGTH/8]; // New AES encryption key uint8_t cur_aes_key[AES_KEY_LENGTH/8]; // AES encryption key uint8_t firmware_data[SPM_PAGESIZE]; // One page of firmware data aes256_context temp_aes_context; // AES context uint8_t cur_cbc_mac[16]; // Current CBCMAC val uint8_t temp_data[16]; // Temporary 16 bytes array RET_TYPE flash_init_result; // Flash initialization result uint16_t firmware_start_address = UINT16_MAX - MAX_FIRMWARE_SIZE - sizeof(cur_cbc_mac) - sizeof(cur_aes_key) + 1; // Start address of firmware in external memory uint16_t firmware_end_address = UINT16_MAX - sizeof(cur_cbc_mac) - sizeof(cur_aes_key) + 1; // End address of firmware in external memory /* Just in case we are going to disable the watch dog timer and disable interrupts */ cli(); wdt_reset(); wdt_clear_flag(); wdt_change_enable(); wdt_stop(); /* Check fuses: 2k words, SPIEN, BOD 4.3V, BOOTRST programming & ver disabled >> http://www.engbedded.com/fusecalc/ */ if ((boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS) != 0xFF) || (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) != 0xD8) || (boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS) != 0xF8) || (boot_lock_fuse_bits_get(GET_LOCK_BITS) != 0xFC)) { while(1); } /* If security isn't set in place yet, no point in launching the bootloader */ if (eeprom_read_byte((uint8_t*)EEP_BOOT_PWD_SET) != BOOTLOADER_PWDOK_KEY) { start_firmware(); } /* Check if the device is booting normally, if the bootloader was called, or unknown state */ if (current_bootkey_val == CORRECT_BOOTKEY) { /* Security system set, correct bootkey for firmware */ start_firmware(); } else if (current_bootkey_val != BOOTLOADER_BOOTKEY) { /* Security system set, bootkey isn't the bootloader one nor the main fw one... */ while(1); } /* By default, brick the device so it's an all or nothing update procedure */ eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, BRICKED_BOOTKEY); /* Init IOs */ UHWCON = 0x01; // Enable USB 3.3V LDO initFlashIOs(); // Init EXT Flash IOs spiUsartBegin(); // Init SPI Controller DDR_ACC_SS |= (1 << PORTID_ACC_SS); // Setup PORT for the Accelerometer SS PORT_ACC_SS |= (1 << PORTID_ACC_SS); // Setup PORT for the Accelerometer SS DDR_OLED_SS |= (1 << PORTID_OLED_SS); // Setup PORT for the OLED SS PORT_OLED_SS |= (1 << PORTID_OLED_SS); // Setup PORT for the OLED SS for (uint16_t i = 0; i < 20000; i++) asm volatile ("NOP"); /* Disable I2C block of the Accelerometer */ PORT_ACC_SS &= ~(1 << PORTID_ACC_SS); spiUsartTransfer(0x23); spiUsartTransfer(0x02); PORT_ACC_SS |= (1 << PORTID_ACC_SS); /* Check Flash */ flash_init_result = checkFlashID(); if (flash_init_result != RETURN_OK) { while(1); } for (uint8_t pass_number = 0; pass_number < 2; pass_number++) { /* Init CBCMAC encryption context*/ eeprom_read_block((void*)cur_aes_key, (void*)EEP_BOOT_PWD, sizeof(cur_aes_key)); memset((void*)cur_cbc_mac, 0x00, sizeof(cur_cbc_mac)); memset((void*)temp_data, 0x00, sizeof(temp_data)); aes256_init_ecb(&temp_aes_context, cur_aes_key); // Compute CBCMAC for between the start of the graphics zone until the max addressing space (65536) - the size of the CBCMAC for (uint16_t i = GRAPHIC_ZONE_START; i < (UINT16_MAX - sizeof(cur_cbc_mac) + 1); i += sizeof(cur_cbc_mac)) { // Read data from external flash flashRawRead(temp_data, i, sizeof(temp_data)); // If we got to the part containing to firmware if ((i >= firmware_start_address) && (i < firmware_end_address)) { // Append firmware data to current buffer uint16_t firmware_data_address = i - firmware_start_address; memcpy(firmware_data + (firmware_data_address & SPM_PAGE_SIZE_BYTES_BM), temp_data, sizeof(temp_data)); // If we have a full page in buffer, flash it firmware_data_address += sizeof(cur_cbc_mac); if (((firmware_data_address & SPM_PAGE_SIZE_BYTES_BM) == 0x0000) && (pass_number == 1)) { boot_program_page(firmware_data_address - SPM_PAGESIZE, firmware_data); } } // If we got to the part containing the encrypted new aes key (end of the for()) if (i >= firmware_end_address) { memcpy(new_aes_key + i - firmware_end_address, temp_data, sizeof(temp_data)); } // Continue computation of CBCMAC aesXorVectors(cur_cbc_mac, temp_data, sizeof(temp_data)); aes256_encrypt_ecb(&temp_aes_context, cur_cbc_mac); } // Read CBCMAC in memory and compare it with the computed value flashRawRead(temp_data, (UINT16_MAX - sizeof(cur_cbc_mac) + 1), sizeof(cur_cbc_mac)); if (pass_number == 0) { // First pass, compare CBCMAC and see if we do the next pass or start the firmware if (sideChannelSafeMemCmp(temp_data, cur_cbc_mac, sizeof(cur_cbc_mac)) != 0) { // No match, start the main firmware eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); start_firmware(); } else { // Otherwise, next pass! } } else { // Second pass, compare CBCMAC and then update AES keys if (sideChannelSafeMemCmp(temp_data, cur_cbc_mac, sizeof(cur_cbc_mac)) == 0) { // Fetch the encrypted new aes key from flash, decrypt it, store it aes256_decrypt_ecb(&temp_aes_context, new_aes_key); aes256_decrypt_ecb(&temp_aes_context, new_aes_key+16); eeprom_write_block((void*)new_aes_key, (void*)EEP_BOOT_PWD, sizeof(new_aes_key)); eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); start_firmware(); } else { // Fail, erase everything! >> maybe just write a while(1) in the future? for (uint16_t i = 0; i < MAX_FIRMWARE_SIZE; i += SPM_PAGESIZE) { boot_page_erase(i); boot_spm_busy_wait(); } while(1); } } } }
void try_receive_data(void) { byte i; byte *ptr; if (uart0_flags.data_received) { ptr = uart0_get_data_begin(); for (i=0; i<9; i++) { TB_bufIn[i] = *ptr; ptr++; } uart0_get_data_end(); uart0_flags.data_received = FALSE; if (TB_Read() == 0) { switch (TB_Decode()) { case ENTER_BOOTLOADER: BootStatus = 1; TB_SendAck(TB_ERR_OK, ENTER_BOOTLOADER); break; case READ_LOCK_BITS: TB_SendAck(TB_ERR_OK, boot_lock_fuse_bits_get(GET_LOCK_BITS)); break; case CHIP_ERASE_FLASH: ChipErase(); TB_SendAck(TB_ERR_OK, CHIP_ERASE_FLASH); break; case CHIP_ERASE_EEPROM: EepromErase(); TB_SendAck(TB_ERR_OK, CHIP_ERASE_EEPROM); break; case CHIP_ERASE_ALL: ChipErase(); EepromErase(); TB_SendAck(TB_ERR_OK, CHIP_ERASE_ALL); break; case WRITE_LOCK_BITS: TB_SendAck(TB_ERR_NOTEVALUABLE, WRITE_LOCK_BITS); break; case READ_LOW_FUSE: TB_SendAck(TB_ERR_OK, boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)); break; case READ_HIGH_FUSE: TB_SendAck(TB_ERR_OK, boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)); break; case READ_EXTENDED_FUSE: TB_SendAck(TB_ERR_NOTEVALUABLE, boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)); break; case READ_SIGNATURE: Signature = 0x1E9502; TB_SendAck(TB_ERR_OK, Signature); break; case READ_SOFTWARE_VERSION: TB_SendAck(TB_ERR_OK, SOFTWARE_IDENTIFIER); break; case READ_BOOTLOADER_VERSION: TB_SendAck(TB_ERR_OK, BOOTLOADER_VERSION); break; case VERIFY_FLASH: Address = TB_bufIn[TB_BUF_TYPE] << 8; Address |= TB_bufIn[TB_BUF_MOTOR]; if (Address < (START_BOOT_ADDRESS_BYTES - 4)) { VerifyFlash(Address); } else { TB_SendAck(TB_ERR_VALUE, Address); } break; case WRITE_FLASH: Address = TB_bufIn[TB_BUF_TYPE] << 8; Address |= TB_bufIn[TB_BUF_MOTOR]; Aktualni = (Address & ADDRESS_MASK_MSB); if (Address < (START_BOOT_ADDRESS_BYTES - 4)) { if (Aktualni == Predchozi) { FillBufferData(Address); EndComFlash = 1; TB_SendAck(TB_ERR_OK, WRITE_FLASH); } else { if (EndComFlash) { WriteFlashPages(Predchozi, BufferFlash); memset(BufferFlash, 0xFF, SPM_PAGESIZE); FillBufferData(Address); TB_SendAck(TB_ERR_OK, Address); Predchozi = Address; } else { memset(BufferFlash, 0xFF, SPM_PAGESIZE); FillBufferData(Address); TB_SendAck(TB_ERR_OK, WRITE_FLASH); Predchozi = Address; } } NowFlash = 1; } else { TB_SendAck(TB_ERR_VALUE, Address); } break; case WRITE_EEPROM: Address = TB_bufIn[TB_BUF_TYPE] << 8; Address |= TB_bufIn[TB_BUF_MOTOR]; Aktualni = (Address & ADDRESS_MASK_MSB); if (Address < (START_EEPROM_ADDRESS - 4)) { if (Aktualni == Predchozi) { FillBufferData(Address); EndComEeprom = 1; TB_SendAck(TB_ERR_OK, WRITE_EEPROM); } else { if (EndComEeprom) { WriteEepromPages(Predchozi, BufferFlash); memset(BufferFlash, 0xFF, SPM_PAGESIZE); FillBufferData(Address); TB_SendAck(TB_ERR_OK, Address); Predchozi = Address; } else { memset(BufferFlash, 0xFF, SPM_PAGESIZE); FillBufferData(Address); TB_SendAck(TB_ERR_OK, WRITE_EEPROM); } } NowEeprom = 1; } else { TB_SendAck(TB_ERR_VALUE, Address); } break; case END_WRITE_ALL: if (NowFlash) { WriteFlashPages(Predchozi, BufferFlash); EndComFlash=0; TB_SendAck(TB_ERR_OK, END_WRITE_ALL); } else if(NowEeprom) { WriteEepromPages(Predchozi, BufferFlash); EndComEeprom = 0; TB_SendAck(TB_ERR_OK, END_WRITE_ALL); } else { TB_SendAck(TB_ERR_VALUE, 0); } memset(BufferFlash, 0xFF, SPM_PAGESIZE); Predchozi = 0; Aktualni = 0; break; case READ_FLASH: Address = TB_bufIn[TB_BUF_TYPE] << 8; Address |= TB_bufIn[TB_BUF_MOTOR]; if (Address < (START_BOOT_ADDRESS_BYTES - 4)) { ReadFlashPages(Address); } else { TB_SendAck(TB_ERR_VALUE, 0); } break; case READ_EEPROM: Address = TB_bufIn[TB_BUF_TYPE] << 8; Address |= TB_bufIn[TB_BUF_MOTOR]; if (Address < (START_EEPROM_ADDRESS - 4)) { ReadEepromPages(Address); } else { TB_SendAck(TB_ERR_VALUE, READ_EEPROM); } break; case CMD_SPM_PAGE_SIZE: TB_SendAck(TB_ERR_OK, SPM_PAGESIZE); break; case CMD_ALL_PAGE_SIZE: TB_SendAck(TB_ERR_OK, PAGE_SIZE); break; case EXIT_BOOTLOADER: TB_SendAck(TB_ERR_OK, EXIT_BOOTLOADER); jumpaddress(); break; } } } }
// ---------------------------------------------------------------------- // Handle a non-standard SETUP packet. // ---------------------------------------------------------------------- uchar usbFunctionSetup ( uchar data[8] ) { uchar req; usbRequest_t *rq = (void *)data; idle_cnt = idle_cnt2 = 0; // Generic requests req = data[1]; if ( req == USBTINY_READ) { // do nothing return 1; } else if ( req == USBTINY_POWERDOWN ) { usb_maybe_finalizing = 1; #ifndef ENABLE_WRITE_WHEN_TOLD finalize_flash_if_dirty(); #endif return 0; } else if ( req == USBTINY_SPI ) { usb_maybe_finalizing = 1; #ifndef ENABLE_WRITE_WHEN_TOLD finalize_flash_if_dirty(); // partial page writes are not fully written unless this is called here, it must be HERE #endif usbMsgPtr = (usbMsgPtr_t)buffer; buffer[2] = data[3]; // this tricks "usbtiny_cmd" into succeeding buffer[3] = 0; // fools safemode into succeeding // for the commands, refer to ATmega datasheet under "Serial Programming Instruction Set" // usage of avr/boot.h here is experimental if (0) { } // fools the C preprocessor #ifdef ENABLE_SIG_READING else if (data[2] == 0x30 && data[3] == 0x00) { // read signature byte #ifdef ENABLE_SIG_FAKING buffer[3] = 0x01; #else buffer[3] = boot_signature_byte_get(data[4] * 2); #endif } #endif #ifdef ENABLE_FUSE_READING else if (data[2] == 0x50 && data[3] == 0x00 && data[4] == 0x00) { // read LFUSE buffer[3] = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS); } else if (data[2] == 0x58 && data[3] == 0x08 && data[4] == 0x00) { // read HFUSE buffer[3] = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); } else if (data[2] == 0x50 && data[3] == 0x08 && data[4] == 0x00) { // read EFUSE buffer[3] = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS); } else if (data[2] == 0x58 && data[3] == 0x00 && data[4] == 0x00) { // read lock bits buffer[3] = boot_lock_fuse_bits_get(GET_LOCK_BITS); } else if (data[2] == 0x38 && data[3] == 0x00 && data[4] == 0x00) { // read calibration buffer[3] = boot_signature_byte_get(0); } #endif #ifdef ENABLE_CHIP_ERASE else if (data[2] == 0xAC && data[3] == 0x80 && data[4] == 0x00 && data[5] == 0x00) { // chip erase, will erase all pages except the first page and the bootloader region full_erase_requested = 1; } #endif #ifdef ENABLE_WRITE_WHEN_TOLD else if (data[2] == 0x4C && data[5] == 0x00) { // write memory page // page is data[3] as MSB and data[4] as LSB need_write_page = 1; } #endif // all other commands are unhandled return 4; } /* else if ( req == USBTINY_SPI1 ) { // I don't know what this is used for, there are no single SPI transactions in the ISP protocol usb_maybe_finalizing = 1; #ifndef ENABLE_WRITE_WHEN_TOLD finalize_flash_if_dirty(); #endif return 1; } */ else if ( req == USBTINY_POLL_BYTES ) { usb_maybe_finalizing = 1; #ifndef ENABLE_WRITE_WHEN_TOLD finalize_flash_if_dirty(); #endif return 0; } CUR_ADDR = *((uint16_t*)(&data[4])); remaining = rq->wLength.bytes[0]; if ( req >= USBTINY_FLASH_READ && req <= USBTINY_EEPROM_WRITE ) { #ifdef ENABLE_LED_BLINK OCR0B = 0x7F; #endif usb_has_activity = 1; cmd0 = req; if ( cmd0 != USBTINY_FLASH_WRITE ) { usb_maybe_finalizing = 1; #ifndef ENABLE_WRITE_WHEN_TOLD finalize_flash_if_dirty(); #endif } return USB_NO_MSG; // usbFunctionRead() or usbFunctionWrite() will be called to handle the data } // do nothing if nothing done return 0; }
void receive_at_command(void) { unsigned char received_bytes = 0; unsigned char rx_char_buffer = 0; unsigned char x = 0; #if defined BOOTLOCK_BIT_SET_SUPPORT && BOOTLOCK_BIT_SET_SUPPORT == 1 unsigned char blb = 0; unsigned char lock_bits = 0; #endif #if defined VERSION_INFO_NEEDED && VERSION_INFO_NEEDED == 1 unsigned int eep_address = 0; #endif while(memory_to_write == 0) { x=_UDR_; x=_UDR_; sput_str(prompt); do{ received_bytes = 0; //uart_rx_timeout = UART_TIMEOUT_ABS_MAX_VALUE; rx_char_buffer = sget_char(); if(rx_char_buffer){ sput_char(rx_char_buffer); } if( rx_char_buffer == 'A' || rx_char_buffer == 'a' ) { rx_char_buffer = sget_char(); if(rx_char_buffer){ sput_char(rx_char_buffer); } if( rx_char_buffer == 'T' || rx_char_buffer == 't' ) { while(1) { rx_char_buffer = sget_char(); sput_char(rx_char_buffer); if(received_bytes > 10 ) { received_bytes = 0xff; sput_str(error_message); break; } if(rx_char_buffer == '\r' || rx_char_buffer == '\n') { x_buffer[received_bytes] = '\0'; break; } x_buffer[received_bytes++] = rx_char_buffer; if(rx_char_buffer == 0) { received_bytes = 0; break; } } } }else if( rx_char_buffer == '\n' || rx_char_buffer == '\r' ) { sput_str(prompt); } }while(received_bytes == 0 ); // end of "while(1)" loop if(received_bytes == 0Xff){ continue; } strupr((char*)x_buffer); memory_to_write = 0; switch(x_buffer[0]) { case('W'): switch(x_buffer[1]) { case('F'): memory_to_write = 1; break; case('E'): memory_to_write = 2; break; #if defined BOOTLOCK_BIT_SET_SUPPORT && BOOTLOCK_BIT_SET_SUPPORT == 1 case('B'): blb = 7; lock_bits = 0xFF; for(x=2; x<=9; x++) { rx_char_buffer = x_buffer[x]; if(rx_char_buffer == '0'){ lock_bits &= (~(1<<blb)); } blb--; } x_buffer[10] = '\0'; utoa(lock_bits,(char*)x_buffer, 2); sput_str((char*)x_buffer); sput_str("Y/N"); rx_char_buffer = sget_char(); if(rx_char_buffer == 'Y' || rx_char_buffer == 'y') { boot_lock_bits_set(~lock_bits); sput_str(success_message); }else{ sput_str("Aborted"); } break; #endif default : sput_str(error_message); break; } break; #if defined BOOTLOCK_BIT_READ_SUPPORT && BOOTLOCK_BIT_READ_SUPPORT == 1 case('R'): switch(x_buffer[1]) { case('B'): utoa(boot_lock_fuse_bits_get(GET_LOCK_BITS), (char*)x_buffer, 2); sput_str((char*)x_buffer); break; case('L'): utoa(boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS), (char*)x_buffer, 2); sput_str((char*)x_buffer); break; case('H'): utoa(boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS), (char*)x_buffer, 2); sput_str((char*)x_buffer); break; case('E'): utoa(boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS), (char*)x_buffer, 2); sput_str((char*)x_buffer); break; default : sput_str(error_message); break; } break; #endif //END of #if defined BOOTLOCK_BIT_READ_SUPPORT && BOOTLOCK_BIT_READ_SUPPORT == 1 case('I'): #if defined VERSION_INFO_NEEDED && VERSION_INFO_NEEDED == 1 sput_char('\r'); sput_char('\n'); eep_address = (E2END - 31); while(eep_address <= E2END) { x = eeprom_read_byte((unsigned char*)eep_address++); if(x < 0xff && x > 0){ sput_char(x); } } #endif sput_str("BootLoader V3.2\r\nChris Efstathiou 2009"); break; default : sput_str(error_message); break; } }//end of "while(memory_to_write == 0)" loop. return; }