int main(void) { void (*applptr)( void ) = 0x0000; MCUCR = _BV(IVCE); // enable wechsel der Interrupt Vectoren MCUCR = _BV(IVSEL); // Interrupts auf Boot Section umschalten #if MITLED LEDDDR |= _BV(LEDPIN); //LED pin auf ausgang blink(2, 20, 20); #endif init_twi(); while (1) { /* Endlosschleife weil 1 immer WAHR*/ /* Bootloader Quit und sprung zur App */ if(kommando == 0xFE || timeout == 0xFFFE){ // Turn off the I2C interrupts TWCR = 0; #if MITLED blink(5, 5, 10); #endif cli(); MCUCR = _BV(IVCE); // enable wechsel der Interrupt Vectoren MCUCR = 0x00; // Interrupts auf Application Section umschalten applptr(); // Rücksprung zur Application } /* Datenblock (64byte) in Flash schreiben */ if(kommando == 0x04){ #if MITLED STATUSLED(1);//PORTB |= _BV(PB0); #endif boot_program_page (pageaddr); #if MITLED STATUSLED(0);//PORTB &= ~_BV(PB0); #endif kommando = 0x00; /* TWI wieder aktivieren */ TWCR |= (1<<TWINT); } if(TWSR == 0x00){ init_twi(); } if(timeout != 0xFFFF){ timeout++; _delay_us(50); } } return 0; }
int main(void) { int i; uint16_t page; uint8_t data[SPM_PAGESIZE]; init(); page = 0; for( i = 0 ; i < SPM_PAGESIZE ; i++ ) data[i] = 0x00; //prog code boot_program_page( page, data); PORTD = 0xA5; while(1); return 0; }
uint8_t wibo_run(void) { uint8_t isLeave=0; uint8_t isStay=0; unsigned long timeout = WIBO_TIMEOUT; while(!isLeave) { #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif if (!(isStay)) { while(!(wibo_available()) && (timeout--)) _delay_ms(1); // minimum frame time @ 250kbps ~ 2ms. if (!(wibo_available())) // no packets received, bye bye! { isLeave=1; return isLeave; } } else { while(!(wibo_available())); // wait for next packet } trx_reg_write(RG_IRQ_STATUS, TRX_IRQ_RX_END); /* clear the flag */ trx_frame_read(rxbuf.data, sizeof(rxbuf.data) / sizeof(rxbuf.data[0]), &tmp); /* dont use LQI, write into tmp variable */ #if !defined(NO_LEDS) LED_SET(PROGLED); /* light as long as actions are running */ #endif switch (rxbuf.hdr.cmd) { case P2P_PING_REQ: isStay=1; if (0 == deaf) { pingrep.hdr.dst = rxbuf.hdr.src; pingrep.hdr.seq++; pingrep.crc = datacrc; trx_reg_write(RG_TRX_STATE, CMD_TX_ARET_ON); /* no need to make block atomic since no IRQs are used */ TRX_SLPTR_HIGH() ; TRX_SLPTR_LOW() ; trx_frame_write(sizeof(p2p_ping_cnf_t) + sizeof(BOARD_NAME) + 2, (uint8_t*) &pingrep); /*******************************************************/ #if defined(_DEBUG_SERIAL_) printf("Pinged by 0x%04X"EOL, rxbuf.hdr.src); #endif #if defined(TRX_IF_RFA1) while (!(trx_reg_read(RG_IRQ_STATUS) & TRX_IRQ_TX_END)) ; trx_reg_write(RG_IRQ_STATUS, TRX_IRQ_TX_END); /* clear the flag */ #else while (!(trx_reg_read(RG_IRQ_STATUS) & TRX_IRQ_TRX_END)) ; #endif /* defined(TRX_IF_RFA1) */ trx_reg_write(RG_TRX_STATE, CMD_RX_AACK_ON); } /* (0 == deaf) */ break; case P2P_WIBO_TARGET: isStay=1; target = rxbuf.wibo_target.targmem; #if defined(_DEBUG_SERIAL_) printf("Set Target to %c"EOL, target); #endif break; case P2P_WIBO_RESET: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Reset"EOL); #endif addr = SPM_PAGESIZE; /* misuse as counter */ ptr = pagebuf; do { *ptr++ = 0xFF; } while (--addr); addr = 0; datacrc = 0; pagebufidx = 0; deaf = 0; break; case P2P_WIBO_ADDR: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Set address: 0x%08lX"EOL, rxbuf.wibo_addr.address); #endif addr = rxbuf.wibo_addr.address; pagebufidx = 0; break; case P2P_WIBO_DATA: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Data[%d]", rxbuf.wibo_data.dsize); uint8_t len = rxbuf.wibo_data.dsize; if (len > 10) len = 10; for(uint8_t j=0;j<len;j++) { printf(" %02X", rxbuf.wibo_data.data[j]); } if (len != rxbuf.wibo_data.dsize) printf("..."); printf(EOL); #endif tmp = rxbuf.wibo_data.dsize; ptr = rxbuf.wibo_data.data; do { datacrc = _crc_ccitt_update(datacrc, *ptr); pagebuf[pagebufidx++] = *ptr; if (pagebufidx >= PAGEBUFSIZE) { /* LED off to save current and avoid flash corruption * because of possible voltage drops */ #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif if (target == 'F') /* Flash memory */ { boot_program_page(addr, pagebuf); } else if (target == 'E') { /* not implemented */ } else { /* unknown target, dry run */ } /* also for dry run! */ addr += SPM_PAGESIZE; pagebufidx = 0; } ptr++; } while (--tmp); break; #if defined(WIBO_FLAVOUR_BOOTLUP) case P2P_WIBO_BOOTLUP: isStay=1; bootlup(); break; #endif case P2P_WIBO_FINISH: isStay=1; #if defined(_DEBUG_SERIAL_) printf("Finish"EOL); #endif if (target == 'F') /* Flash memory */ { boot_program_page(addr, pagebuf); } else if (target == 'E') { /* not implemented */ } else { /* unknown target, dry run */ } /* also for dry run! */ addr += SPM_PAGESIZE; pagebufidx = 0; break; case P2P_WIBO_EXIT: #if defined(_DEBUG_SERIAL_) printf("Exit"EOL); #endif #if !defined(NO_LEDS) LED_CLR(PROGLED); #endif isLeave=1; break; case P2P_WIBO_DEAF: isStay=1; deaf = 1; break; default: /* unknown or unhandled command */ if (!(isStay)) { if (!(timeout--)) { isLeave = 1; } } break; }; /* switch (rxbuf.hdr.cmd) */ } return isLeave; }
/*! \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); } } } }
uint8_t fileParser_parseNextBlock(unsigned long filesize) { switch(fileParser_parseState) { case INFO_HEADER: { //--- read info header --- struct InfoHeader *tmpHeader; tmpHeader = (struct InfoHeader *) &sd_buffer[0]; infoHeader = *tmpHeader; if( (infoHeader.headerId[0] != 'S') || (infoHeader.headerId[1] != 'P') || (infoHeader.headerId[2] != 'F') || (infoHeader.headerId[3] != 'I') ) { //header not right -> abort lcd_clear(); lcd_home(); lcd_string("header error"); while(1); return 0; } fileParser_bytesRead += 512; if ((fileParser_bytesRead) >= filesize ) { lcd_setcursor(0,2); lcd_string("EOF error"); while(1); } fileParser_parseState = AVR_DATA; } break; case AVR_DATA: { //--- read avr code --- //program data into flash (512 bytes data to 4 pages a 128 bytes -> mega32 SPM_PAGESIZE = 128 //program data into flash (512 bytes data to 2 pages a 256 bytes -> mega644 SPM_PAGESIZE = 256 for(int i=0; (i<(512/SPM_PAGESIZE)) && (fileParser_bytesRead < (infoHeader.avrCodeSize + 512)); i++ ) { boot_program_page(fileParser_pagesWritten,(uint8_t *)&sd_buffer[0+i*SPM_PAGESIZE]); fileParser_bytesRead += SPM_PAGESIZE; fileParser_pagesWritten+=SPM_PAGESIZE; } //increment the byte counter //fileParser_bytesRead += 512 if ((fileParser_bytesRead) >= filesize ) { return 0; } //check if AVR code end is reached if(fileParser_bytesRead >= (infoHeader.avrCodeSize + 512) ) { //reset cortex chip lcd_home(); lcd_string("updating...(1/2)"); lcd_setcursor(0,2); lcd_command(LCD_CURSOR_ON); fileParser_resetCortex(); //initialize the cortex bootloader //try 10 times to give the cortex some time to boot and answer int i=0; for(;;) { uart_tx(INIT_BOOTLOADER); _delay_ms(1000); //if received data is available #ifdef MEGA32 if( (UCSRA & (1<<RXC)) ) #else if( (UCSR0A & (1<<RXC0)) ) #endif { uint8_t data = uart_rxWait(); if(data == ACK) { //bootloader successfully initialized //it is now waiting for commands break; } } dout_updateOutputs(); } //check if init is ok (ACK received) if(i>=10) { //an error occured //could not initialize bootloader lcd_home(); lcd_string("mainboard error"); while(1); return 0; } //now we can send the cortex bootloader commands and data fileParser_parseState = CORTEX_DATA; //give the cortex time to erase the flash lcd_home(); lcd_string("updating...(2/2)"); return 1; } } break; case CORTEX_DATA: //--- read cortex code --- //we have 512 bytes of data //data is 32 bit unsigned int //we increment with 4 because in each run we send out 4 bytes => 1 32 bit int message for(int i=0;i<512;i+=4) { uint16_t crc; // send the address crc = calcCrc(WRITE_ADDRESS,(uint8_t*)&addressCounter); //send next address packet until ACK received do { uart_tx(WRITE_ADDRESS); //lcd_home(); //lcd_string("cmd"); uart_tx(addressCounter>>24); uart_tx(addressCounter>>16); uart_tx(addressCounter>>8); uart_tx(addressCounter); //send calculated CRC uart_tx(crc>>8); uart_tx(crc&0xff); } while (uart_checkAck()!=ACK); //calc crc for data block crc = calcCrc(WRITE_DATA,&sd_buffer[i]); //send next data packet until ACK received do { //send command uart_tx(WRITE_DATA); //after the command, send the 4 data bytes uart_tx(sd_buffer[i+3]); uart_tx(sd_buffer[i+2]); uart_tx(sd_buffer[i+1]); uart_tx(sd_buffer[i]); //send calculated CRC uart_tx(crc>>8); uart_tx(crc&0xff); } while (uart_checkAck()!=ACK); //transfer succeeded addressCounter++; } dout_updateOutputs(); fileParser_bytesRead+=512; //send cortex bootloader data if ((fileParser_bytesRead) >= filesize ) { lcd_clear(); lcd_home(); lcd_string("success!"); lcd_setcursor(0,2); lcd_string("please reboot..."); lcd_command(LCD_CURSOR_OFF); uart_tx(END_BOOTLOADER); while(1); return 0; } break; } return 1; }