Files
TX/source/Loader/flashUpdate.c

344 lines
11 KiB
C
Raw Normal View History

/*
* flashUpdate.c
*
* Created on: Oct 23, 2023
* Author: Brian.Bailey
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "usbComms.h"
#include "sha256.h"
#include "flashUpdate.h"
#include "fsl_common.h"
#include "fsl_iap.h"
#include "bootloader.h"
#include "eeprom.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define null 0 //NULL is defined at (void *)0 so it causes errors
//sector0~2 for bootloader, sector3~7 for APP
#define IAP_FLASH_SECTOR_START (3)
#define IAP_FLASH_SECTOR_END (7)
// #define IAP_FLASH_SECTOR_END (3) //for test
/*******************************************************************************
* Variables
******************************************************************************/
FLASH_UPDATE_t fu;
extern USB_t usb;
extern BL_DATA_t blData;
/*******************************************************************************
* Static Function Declarations
******************************************************************************/
/*******************************************************************************
* Static Functions
******************************************************************************/
/*
* Convert the source string to bytes & store in *dst
* Converts 32 ASCII chars to 16 bytes
*/
static void ConvertStringToHalfHash(uint8_t *src, uint8_t *dst)
{
//32 ASCII chars to 16 bytes
for(uint32_t i = 0; i < SHA256_BLOCK_SIZE/2; i++)
{
//sscanf(&src[i*2], "%02hhX", &dst[i]); //This works in the RX but has problems when ASCII is > 127?
uint8_t temp[3];
temp[0] = src[i*2];
temp[1] = src[i*2+1];
temp[3] = 0;
dst[i] = strtol(temp, NULL, 16);
}
}
/*!
* @brief Convert uint8 to uint32.
*
* @param len length of arr8.
*/
static void ConvertUint8ToUint32(uint8_t *arr8, uint32_t *arr32, uint32_t len) {
uint32_t temp;
for (uint32_t i = 0; i < FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES; i++)
{
*(((uint8_t *)arr32) + i) = 0xFF;
}
//get the length of arr32
if(len % 4){
len /= 4;
len += 1;
}
else{
len /= 4;
}
for(uint32_t i = 0; i < len; i++) {
temp = (uint32_t)arr8[3] << 24;
temp |= (uint32_t)arr8[2] << 16;
temp |= (uint32_t)arr8[1] << 8;
temp |= (uint32_t)arr8[0];
arr8 += 4;
arr32[i] = temp;
}
}
/*******************************************************************************
* Public Functions
******************************************************************************/
/* Setup for FLASH programming
* /arg *data: csv string: pProgramSetup,<numBytes>,<hash>
* Use program length to calculate number of FLASH sectors to erase
* Save hash, program size, and calculated parameters
* Set usb.programMode
* Send ACK / NAK
*/
void FU_ProgramSetup(uint8_t *data)
{
//reset variables
fu.imageReceived = false;
fu.flashHashMatch = false;
fu.numBytesToProgram = 0;
fu.numBytesProgrammed = 0;
bool error = false;
//Parse Program message
static uint8_t *p; //pointer for strtok - static so it doesn't get optimized out.
p = strtok(data, ","); //points to "pProgramSetup"
p = strtok(null, ","); //number of bytes in the image
fu.numBytesToProgram = atoi(p);
p = strtok(null, ","); //hash - sent as string
ConvertStringToHalfHash(p, fu.hostHash);
//clear programmed flag in EEPROM
blData.transmitterProgrammed = 0;
EE_WriteMemoryUINT32(BL_PROGRAMMED_EEPROM_ADDR, &blData.transmitterProgrammed);
//Erase APP flash
//USB_SendString("Erasing flash..."); //or to LCD
IAP_PrepareSectorForWrite(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
IAP_EraseSector(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END, SystemCoreClock);
//USB_SendString("Erase flash completed"); //OR TO LCD
status_t status;
status = IAP_BlankCheckSector(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
if (status != kStatus_IAP_Success)
{
error = 1;
// PRINTF("\r\nSector erase failed\r\n"); //to LCD
}
//Initialize fu
memset(fu.rxPageData, 0xff, sizeof(fu.rxPageData));
fu.flashProgramTargetAddress = BL_APP_IMAGE_ADDR;
if(error)
{
USB_SendString(NAK);
}
else
{
usb.programMode = true;
USB_SendString(ACK);
}
}
/* Write received data to FLASH using fu struct information
* This function is called repeatedly to write program FLASH
* When all data received, function sends ACK or NACK via USB
*/
void FU_WriteProgramDataToFLASH(void)
{
bool error = false;
//Verify packet: check header and check that size matches
if (USB_PACKET_START_BYTE != usb.rxDataBuffer[USB_PACKET_HEADER_OFFSET])
{
error = true;
}
uint32_t packetSize = usb.rxDataBuffer[USB_PACKET_LENGTH_H_OFFSET] * 256; //high byte
packetSize += usb.rxDataBuffer[USB_PACKET_LENGTH_L_OFFSET]; //low byte
if(packetSize != usb.rxDataIndex) //check that computed packet size matches number of bytes received
{
error = true;
}
//Write data to FLASH
//you can use packetSize. It is the size of the data in bytes
//Best to wait for a whole page or sector of data before writing to FLASH.
//faster this way
uint32_t rxData[64];
if(!error){
//Judge whether it is the last packet
if((packetSize - USB_PACKET_HEADER_SIZE + fu.numBytesProgrammed) == fu.numBytesToProgram)
{
//Judge whether the page is going to be full
if((fu.numBytesInPageData + packetSize - USB_PACKET_HEADER_SIZE) >= FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES)
{
uint16_t numBytesCurrentPage;
numBytesCurrentPage = FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES - fu.numBytesInPageData;
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET], numBytesCurrentPage);
ConvertUint8ToUint32(fu.rxPageData, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES);
IAP_PrepareSectorForWrite(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
IAP_CopyRamToFlash(fu.flashProgramTargetAddress, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES, SystemCoreClock);
fu.flashProgramTargetAddress += FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES;
//start the next FLASH page
memset(fu.rxPageData, 0xff, sizeof(fu.rxPageData));
fu.numBytesInPageData = 0;
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET + numBytesCurrentPage], (packetSize - USB_PACKET_HEADER_SIZE - numBytesCurrentPage));
fu.numBytesInPageData += (packetSize - USB_PACKET_HEADER_SIZE - numBytesCurrentPage);
//write to FLASH
ConvertUint8ToUint32(fu.rxPageData, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES);
IAP_PrepareSectorForWrite(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
IAP_CopyRamToFlash(fu.flashProgramTargetAddress, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES, SystemCoreClock);
fu.flashProgramTargetAddress += FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES;
}
else
{
//write the final page to FLASH
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET], (packetSize - USB_PACKET_HEADER_SIZE)); //copy packet to fu.rxPageData
fu.numBytesInPageData += (packetSize - USB_PACKET_HEADER_SIZE);
ConvertUint8ToUint32(fu.rxPageData, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES);
IAP_PrepareSectorForWrite(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
IAP_CopyRamToFlash(fu.flashProgramTargetAddress, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES, SystemCoreClock);
fu.flashProgramTargetAddress += FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES;
}
}
else{
//Judge whether the page is going to be full
if((fu.numBytesInPageData + packetSize - USB_PACKET_HEADER_SIZE) >= FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES){
uint16_t numBytesCurrentPage;
numBytesCurrentPage = FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES - fu.numBytesInPageData;
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET], numBytesCurrentPage);
ConvertUint8ToUint32(fu.rxPageData, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES);
IAP_PrepareSectorForWrite(IAP_FLASH_SECTOR_START, IAP_FLASH_SECTOR_END);
IAP_CopyRamToFlash(fu.flashProgramTargetAddress, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES, SystemCoreClock);
fu.flashProgramTargetAddress += FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES;
//start the next FLASH page
memset(fu.rxPageData, 0xff, sizeof(fu.rxPageData));
fu.numBytesInPageData = 0;
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET + numBytesCurrentPage], (packetSize - USB_PACKET_HEADER_SIZE - numBytesCurrentPage));
fu.numBytesInPageData += (packetSize - USB_PACKET_HEADER_SIZE - numBytesCurrentPage);
}
else{
memcpy(&fu.rxPageData[fu.numBytesInPageData], &usb.rxDataBuffer[USB_PACKET_PAYLOAD_OFFSET], (packetSize - USB_PACKET_HEADER_SIZE));
fu.numBytesInPageData += (packetSize - USB_PACKET_HEADER_SIZE);
}
}
fu.numBytesProgrammed += packetSize - USB_PACKET_HEADER_SIZE;
}
//Test for all data transferred
if(fu.numBytesProgrammed >= fu.numBytesToProgram)
{
usb.programMode = false;
fu.imageReceived = true;
}
if(error)
{
USB_SendString(NAK);
}
else
{
USB_SendString(ACK);
}
}
/* Verify FLASH image using sha256 hash
* Compute sha256 hash of program image
* Compare to fu.hostHash
*/
void FU_VerifyImage()
{
//TODO: Compute sha256 hash of program image from FLASH
static uint32_t dstAddr = BL_APP_IMAGE_ADDR;
uint8_t rxData[FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES];
uint32_t i = 0;
SHA256_CTX ctx;
/* EMAMPLE: (Also see sha256_test())
* SHA256_CTX ctx;
* sha256_init(&ctx); //initialize
* sha256_update(&ctx, data, dataLength); //call this for each block of data
* sha256_final(&ctx, fu.flashHash); //finish
*/
sha256_init(&ctx);
for(i = 0; i < (fu.numBytesToProgram / FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES); i++){
//read flash
for(uint32_t j = 0; j < FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES; j++) //read 256 bytes from FLASH to rxData
{
rxData[j] = *(uint8_t *)(dstAddr + FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES * i + j);
}
//calculate sha256
// sha256_update(&ctx, rxData, strlen((char *)rxData));
sha256_update(&ctx, rxData, FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES);
}
for(uint32_t j = 0; j < (fu.numBytesToProgram % FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES); j++){
rxData[j] = *(uint8_t *)(dstAddr + FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES * i + j);
}
sha256_update(&ctx, rxData, (fu.numBytesToProgram % FSL_FEATURE_SYSCON_FLASH_PAGE_SIZE_BYTES));
sha256_final(&ctx, fu.flashHash);
//Compare fu.flashHash with fu.hostHash - FIRST HALF ONLY!
if(0 == memcmp(fu.hostHash, fu.flashHash, SHA256_BLOCK_SIZE/2)) //Failed, I don't know the reason.
// if(1) //for test, bypass verification and it works
{
//set programmed flag in EEPROM
blData.transmitterProgrammed = true;
EE_WriteMemoryUINT32(BL_PROGRAMMED_EEPROM_ADDR, &blData.transmitterProgrammed);
USB_SendString(ACK);
}
else
{
USB_SendString(NAK);
}
}
/* Reset the processor
* Works even if in ISR
*/
void FU_ResetProcessor(void)
{
//Disable interrupts.
__disable_irq();
// Memory barriers for good measure.
__ISB();
__DSB();
//Reset
NVIC_SystemReset();
}