// // Created by zemon on 28.05.2022. // #include #include #include "FirmwareLoader.h" #include "stdint.h" #include "BootJump.h" void FirmwareLoader_MapMetadata(tFirmwareBlock *block) { block->metadata.crc = (uint32_t *) (block->metadataMem + 0); block->metadata.size = (uint32_t *) (block->metadataMem + 4); block->metadata.nameLength = (uint8_t *) (block->metadataMem + 8); block->metadata.name = (uint8_t *) (block->metadataMem + 9); } void FirmwareLoader_Init(tFirmwareLoader *env, uint32_t fwSize, uint32_t mainFwAddr, uint32_t updateFwAddr) { env->fwSize = fwSize; env->main.address = mainFwAddr; env->update.address = updateFwAddr; env->metadataOffset = fwSize - FIRMWARE_META_LENGTH; FirmwareLoader_MapMetadata(&env->main); FirmwareLoader_MapMetadata(&env->update); } void FirmwareLoader_LoadMetadata(tFirmwareLoader *env, tFirmwareBlock *block) { sInternalFlashPage_Read(block->address + env->metadataOffset, 0, block->metadataMem, FIRMWARE_META_LENGTH); } void FirmwareLoader_CopyUpdateToMain(tFirmwareLoader *env) { bInternalFlashPage_CopyRange( env->main.address, env->update.address, env->fwSize ); } uint32_t FirmwareLoader_crc32(uint8_t *data, uint32_t size) { uint32_t crc = 0; uint8_t *dataEnd = data + size; while (data < dataEnd) { crc += *data; ++data; } return crc; } bool FirmwareLoader_CheckBlock(tFirmwareLoader *env, tFirmwareBlock *block) { FirmwareLoader_LoadMetadata(env, block); if ((*block->metadata.size <= env->metadataOffset) && (*block->metadata.size > 0)) { uint32_t calcCrc = FirmwareLoader_crc32((uint8_t *) block->address, *block->metadata.size); if (calcCrc == *block->metadata.crc) { return true; } } return false; } bool FirmwareLoader_IsUpdateAndMainAreDifferent(tFirmwareLoader *env) { //meta data must be loaded first with FirmwareLoader_LoadMetadata //метаданные должны быть подгружены заранее с использованием FirmwareLoader_LoadMetadata bool sameNames = (*env->main.metadata.nameLength == *env->update.metadata.nameLength) && memcmp(env->main.metadata.name, env->update.metadata.name, *env->update.metadata.nameLength) == 0; bool sameSrc = *env->main.metadata.crc == *env->update.metadata.crc; return !sameSrc || !sameNames; } bool FirmwareLoader_CheckUpdate(tFirmwareLoader *env) { return FirmwareLoader_CheckBlock(env, &env->update); } bool FirmwareLoader_IsLoadUpdate(tFirmwareLoader *env) { //грузим метаданные и проверяем контрольные суммы для обоих блоков прошивки bool mainFwOk = FirmwareLoader_CheckBlock(env, &env->main); bool updateFwOk = FirmwareLoader_CheckBlock(env, &env->update); //если у нас есть целая(не битая) прошивка в секции обновления if (updateFwOk) { //то смотрим нужно ли ее накатить //а имеено, накатываем в том случае если текущая прошивка неисправна/отсутствует //или если в секции обновления лежит другая (считаем что более новая) прошивка if ((!mainFwOk) || (FirmwareLoader_IsUpdateAndMainAreDifferent(env))) { return true; } } return false; } bool FirmwareLoader_CheckAndUpdate(tFirmwareLoader *env) { //если обновление есть (оно валидно) и глная прошивка битая или отличаеться от обновления if(FirmwareLoader_IsLoadUpdate(env)){ //то гурзим обновление в основню область памяти FirmwareLoader_CopyUpdateToMain(env); } //и финальная проверка, а что у нас теперь лежит в секции основной прошивки ( валидная ли прошивка там ) return FirmwareLoader_CheckBlock(env, &env->main); } //Загружаем основную прошивку void FirmwareLoader_RunFirmware(tFirmwareLoader *env) { BootJumpToAddress(env->main.address); } bool FirmwareLoader_ClearUpdateFlash(tFirmwareLoader *env) { return bInternalFlashPage_ClearRange(env->update.address, env->fwSize); } bool FirmwareLoader_WriteUpdatePortion(tFirmwareLoader *env, uint32_t offset, uint8_t *data, uint16_t dataSize) { return sInternalFlashPage_Write(env->update.address + offset, 0, data, dataSize) == dataSize; } static bool FirmwareLoader_DumpUpdateMetadata(tFirmwareLoader *env) { // return true; return FirmwareLoader_WriteUpdatePortion(env, env->metadataOffset, env->update.metadataMem, FIRMWARE_META_LENGTH); } bool FirmwareLoader_PrepareNewUpdate( tFirmwareLoader *env, uint32_t size, uint32_t crc, uint8_t *name, uint8_t nameLen ) { if (!FirmwareLoader_ClearUpdateFlash(env)) { return false; } *env->update.metadata.crc = crc; *env->update.metadata.size = size; *env->update.metadata.nameLength = nameLen; memcpy(env->update.metadata.name, name, nameLen); return FirmwareLoader_DumpUpdateMetadata(env); }