FirmwareLoader_Flagchip_FC7240/Src/FirmwareLoader.c

295 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by zemon on 28.05.2022.
//
#include <InternalFlashPage.h>
#include <memory.h>
#include "FirmwareLoader.h"
#include "stdint.h"
#include "BootJump.h"
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;
env->main.metadata.crc = (uint32_t *) (env->main.metadataMem + FIRMWARE_META_LENGTH - 4);
env->update.metadata.crc = (uint32_t *) (env->update.metadataMem + FIRMWARE_META_LENGTH - 4);
}
void FirmwareLoader_LoadMetadata(tFirmwareLoader *env, tFirmwareBlock *block) {
P_sInternalFlashPage_Read(block->address + env->metadataOffset, 0, block->metadataMem, FIRMWARE_META_LENGTH);
}
void FirmwareLoader_CopyUpdateToMain(tFirmwareLoader *env) {
P_bInternalFlashPage_CopyRange(
env->main.address,
env->update.address,
env->fwSize,
NULL,
NULL
);
}
/*
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;
}
*/
#include <stdint.h>
#include <string.h>
// Таблица CRC32, предвычисленная для полинома 0xEDB88320UL (отражённая форма 0x04C11DB7)
static const uint32_t crc_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
/**
* @brief Быстрое обновление CRC32 с обработкой по 4 байта (uint32_t)
* @param crc Текущее значение CRC
* @param data Указатель на данные
* @param len Длина данных в байтах
* @return Обновленное значение CRC (без финальной инверсии)
*/
uint32_t UdsCrc32Update(uint32_t crc, const uint8_t *data, uint32_t len) {
// Обрабатываем выровненные 4-байтовые блоки
while (len >= 4) {
uint32_t word = *(const uint32_t *) data;
// Оптимизированная обработка 4 байт за раз
crc = (crc >> 8) ^ crc_table[(crc ^ (word >> 0)) & 0xFF];
crc = (crc >> 8) ^ crc_table[(crc ^ (word >> 8)) & 0xFF];
crc = (crc >> 8) ^ crc_table[(crc ^ (word >> 16)) & 0xFF];
crc = (crc >> 8) ^ crc_table[(crc ^ (word >> 24)) & 0xFF];
data += 4;
len -= 4;
}
// Обрабатываем оставшиеся байты (0-3 байта)
while (len--) {
crc = (crc >> 8) ^ crc_table[(crc ^ *data++) & 0xFF];
}
return crc;
}
#include "fc7xxx_driver_crc.h"
/**
* @brief Hardware CRC-32 update function
*
* Configuration that works (Test 2):
* - Polynomial: 0x04C11DB7 (direct form)
* - Write data swap: BYTE_BIT (byte + bit reflection on input)
* - Read data swap: BYTE_BIT (byte + bit reflection on output)
* - Read data FXOR: FXOR (final XOR with 0xFFFFFFFF)
*
* This matches the software implementation that uses reflected polynomial 0xEDB88320.
*
* @param crc Initial CRC value (0xFFFFFFFF for new calculation)
* @param data Pointer to data buffer
* @param len Length of data in bytes
* @param update_func Callback for timeout (can be NULL)
* @param update_func_env Environment for callback
* @param timeout Timeout in milliseconds
* @return uint32_t Updated CRC value
*/
uint32_t UdsCrc32Update_Hardware(uint32_t crc, const uint8_t *data, uint32_t len)
{
CRC_InitType tInitCfg = {0};
uint32_t u32Result;
/* Конфигурация из Test 2 */
tInitCfg.u32Polynomial = 0x04C11DB7UL; /* Прямой полином */
tInitCfg.u32SeedValue = crc; /* Начальное значение */
tInitCfg.eBitWidth = CRC_BIT_32; /* 32-битный режим */
tInitCfg.eWriteDataSwap = WRITE_DATASWAP_BIT_BYTE; /* Байтовый + битовый swap на входе */
tInitCfg.eReadDataSwap = READ_DATASWAP_BIT_BYTE; /* Байтовый + битовый swap на выходе */
tInitCfg.eReadDataFXOR = READ_DATA_FXOR; /* Финальная инверсия (XOR 0xFFFFFFFF) */
CRC_Init(CRC_INSTANCE, &tInitCfg);
/* Обработка данных 32-битными словами для скорости */
while (len >= 4)
{
uint32_t u32Word = *(const uint32_t*)data;
CRC_SetCalcData_U32(CRC_INSTANCE, u32Word);
data += 4;
len -= 4;
}
/* Обработка оставшихся байтов (0-3) */
while (len--)
{
CRC_SetCalcData_U8(CRC_INSTANCE, *data++);
}
/* Получаем результат (уже с FXOR) */
u32Result = CRC_GetCrcResult(CRC_INSTANCE);
return u32Result;
}
/**
* @brief Финальная инверсия CRC32
* @param crc Значение CRC перед финализацией
* @return Финальное значение CRC32
*/
uint32_t UdsCrc32Finalize(uint32_t crc) {
return crc ^ 0xFFFFFFFF;
}
bool FirmwareLoader_CheckBlock(tFirmwareLoader *env, tFirmwareBlock *block) {
FirmwareLoader_LoadMetadata(env, block);
// uint32_t calcCrc = UdsCrc32Update(0xFFFFFFFF, (uint8_t *) block->address, env->fwSize - 4);
// calcCrc = UdsCrc32Finalize(calcCrc);
uint32_t calcCrc = UdsCrc32Update_Hardware(0xFFFFFFFF, (uint8_t *) block->address, env->fwSize - 4);
if (calcCrc == *block->metadata.crc) {
return true;
}
return false;
}
bool FirmwareLoader_IsUpdateAndMainAreDifferent(tFirmwareLoader *env) {
bool sameSrc = *env->main.metadata.crc == *env->update.metadata.crc;
return !sameSrc;
}
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 P_bInternalFlashPage_ClearRange(env->update.address, env->fwSize, NULL, NULL);
}
bool FirmwareLoader_WriteUpdatePortion(tFirmwareLoader *env, uint32_t offset, uint8_t *data, uint16_t dataSize) {
return P_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);
}
*/