153 lines
5.3 KiB
C
153 lines
5.3 KiB
C
//
|
||
// Created by zemon on 28.05.2022.
|
||
//
|
||
#include <InternalFlashPage.h>
|
||
#include <memory.h>
|
||
#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);
|
||
} |