#include "plsr_persistence.h" #include #include #define PLSR_HSD_BACKUP_MAGIC (0x504C4853UL) #define PLSR_HSD_BACKUP_VERSION (1U) #define PLSR_BACKUP_SLOT_A_OFFSET (0x0100UL) #define PLSR_BACKUP_SLOT_STRIDE (0x0200UL) typedef struct { uint32_t magic; uint16_t version; uint16_t payloadLength; uint32_t generation; PLSR_HSD_DATA data; uint32_t crc32; } PLSR_HSD_BACKUP_RECORD; #ifdef PLSR_HOST_TEST static PLSR_HSD_BACKUP_RECORD PlsrHostBackupSlots[2]; #else #include "stm32f4xx.h" #endif static uint32_t PlsrPersistenceCrc32(const volatile uint8_t *data, uint32_t length) { uint32_t crc = 0xFFFFFFFFUL; uint32_t index; uint8_t bit; for (index = 0U; index < length; index++) { crc ^= data[index]; for (bit = 0U; bit < 8U; bit++) { if ((crc & 1UL) != 0UL) { crc = (crc >> 1U) ^ 0xEDB88320UL; } else { crc >>= 1U; } } } return ~crc; } static volatile PLSR_HSD_BACKUP_RECORD *PlsrPersistenceGetHsdSlot( uint8_t slot) { #ifdef PLSR_HOST_TEST return &PlsrHostBackupSlots[slot]; #else uint32_t offset = PLSR_BACKUP_SLOT_A_OFFSET + (uint32_t)slot * PLSR_BACKUP_SLOT_STRIDE; return (volatile PLSR_HSD_BACKUP_RECORD *)(BKPSRAM_BASE + offset); #endif } static uint8_t PlsrPersistenceHsdRecordIsValid( const volatile PLSR_HSD_BACKUP_RECORD *record) { uint32_t expectedCrc; if ((record->magic != PLSR_HSD_BACKUP_MAGIC) || (record->version != PLSR_HSD_BACKUP_VERSION) || (record->payloadLength != sizeof(PLSR_HSD_DATA))) { return 0U; } expectedCrc = PlsrPersistenceCrc32( (const volatile uint8_t *)record, (uint32_t)offsetof(PLSR_HSD_BACKUP_RECORD, crc32)); return (expectedCrc == record->crc32) ? 1U : 0U; } static uint8_t PlsrPersistenceGenerationIsNewer(uint32_t left, uint32_t right) { return (((int32_t)(left - right)) > 0) ? 1U : 0U; } static void PlsrPersistenceCopyHsdFromVolatile( PLSR_HSD_DATA *destination, const volatile PLSR_HSD_DATA *source) { uint16_t index; for (index = 0U; index < PLSR_HSD_RUNTIME_COUNT; index++) { destination->runtime[index] = source->runtime[index]; } for (index = 0U; index < PLSR_HSD_CONFIG_COUNT; index++) { destination->config[index] = source->config[index]; } } static void PlsrPersistenceWriteRecord( volatile PLSR_HSD_BACKUP_RECORD *destination, const PLSR_HSD_BACKUP_RECORD *source) { const uint32_t *sourceWords = (const uint32_t *)source; volatile uint32_t *destinationWords = (volatile uint32_t *)destination; uint32_t wordCount = (uint32_t)(sizeof(PLSR_HSD_BACKUP_RECORD) / sizeof(uint32_t)); uint32_t index; destination->magic = 0UL; #ifndef PLSR_HOST_TEST __DMB(); #endif for (index = 1U; index < wordCount; index++) { destinationWords[index] = sourceWords[index]; } #ifndef PLSR_HOST_TEST __DMB(); #endif destination->magic = PLSR_HSD_BACKUP_MAGIC; #ifndef PLSR_HOST_TEST __DMB(); #endif } PLSR_PERSISTENCE_RESULT PlsrPersistenceLoadHsd(PLSR_HSD_DATA *data) { volatile PLSR_HSD_BACKUP_RECORD *slotA; volatile PLSR_HSD_BACKUP_RECORD *slotB; const volatile PLSR_HSD_BACKUP_RECORD *selected; uint32_t generationA; uint32_t generationB; uint8_t validA; uint8_t validB; if (data == NULL) { return PLSR_PERSISTENCE_INVALID_ARGUMENT; } slotA = PlsrPersistenceGetHsdSlot(0U); slotB = PlsrPersistenceGetHsdSlot(1U); validA = PlsrPersistenceHsdRecordIsValid(slotA); validB = PlsrPersistenceHsdRecordIsValid(slotB); if ((validA == 0U) && (validB == 0U)) { (void)memset(data, 0, sizeof(*data)); return PLSR_PERSISTENCE_DEFAULTED; } if ((validA != 0U) && (validB != 0U)) { generationA = slotA->generation; generationB = slotB->generation; selected = (PlsrPersistenceGenerationIsNewer(generationB, generationA) != 0U) ? slotB : slotA; } else { selected = (validA != 0U) ? slotA : slotB; } PlsrPersistenceCopyHsdFromVolatile(data, &selected->data); return PLSR_PERSISTENCE_OK; } PLSR_PERSISTENCE_RESULT PlsrPersistenceSaveHsd(const PLSR_HSD_DATA *data) { volatile PLSR_HSD_BACKUP_RECORD *slotA; volatile PLSR_HSD_BACKUP_RECORD *slotB; volatile PLSR_HSD_BACKUP_RECORD *target; PLSR_HSD_BACKUP_RECORD record; uint32_t newestGeneration = 0UL; uint32_t generationA; uint32_t generationB; uint8_t validA; uint8_t validB; if (data == NULL) { return PLSR_PERSISTENCE_INVALID_ARGUMENT; } if (sizeof(PLSR_HSD_BACKUP_RECORD) > PLSR_BACKUP_SLOT_STRIDE) { return PLSR_PERSISTENCE_VERIFY_FAILED; } slotA = PlsrPersistenceGetHsdSlot(0U); slotB = PlsrPersistenceGetHsdSlot(1U); validA = PlsrPersistenceHsdRecordIsValid(slotA); validB = PlsrPersistenceHsdRecordIsValid(slotB); if ((validA != 0U) && (validB != 0U)) { generationA = slotA->generation; generationB = slotB->generation; if (PlsrPersistenceGenerationIsNewer(generationB, generationA) != 0U) { newestGeneration = generationB; target = slotA; } else { newestGeneration = generationA; target = slotB; } } else if (validA != 0U) { newestGeneration = slotA->generation; target = slotB; } else if (validB != 0U) { newestGeneration = slotB->generation; target = slotA; } else { target = slotA; } (void)memset(&record, 0, sizeof(record)); record.magic = PLSR_HSD_BACKUP_MAGIC; record.version = PLSR_HSD_BACKUP_VERSION; record.payloadLength = (uint16_t)sizeof(PLSR_HSD_DATA); record.generation = newestGeneration + 1UL; record.data = *data; record.crc32 = PlsrPersistenceCrc32( (const volatile uint8_t *)&record, (uint32_t)offsetof(PLSR_HSD_BACKUP_RECORD, crc32)); PlsrPersistenceWriteRecord(target, &record); return (PlsrPersistenceHsdRecordIsValid(target) != 0U) ? PLSR_PERSISTENCE_OK : PLSR_PERSISTENCE_VERIFY_FAILED; } void PlsrPersistenceResetHsd(void) { PlsrPersistenceGetHsdSlot(0U)->magic = 0UL; PlsrPersistenceGetHsdSlot(1U)->magic = 0UL; #ifndef PLSR_HOST_TEST __DMB(); #endif } PLSR_PERSISTENCE_RESULT PlsrPersistenceLoadSfd(PLSR_SFD_DATA *data) { if (data == NULL) { return PLSR_PERSISTENCE_INVALID_ARGUMENT; } (void)memset(data, 0, sizeof(*data)); return PLSR_PERSISTENCE_NOT_IMPLEMENTED; } PLSR_PERSISTENCE_RESULT PlsrPersistenceSaveSfd(const PLSR_SFD_DATA *data) { if (data == NULL) { return PLSR_PERSISTENCE_INVALID_ARGUMENT; } return PLSR_PERSISTENCE_NOT_IMPLEMENTED; } #ifdef PLSR_HOST_TEST void PlsrPersistenceTestResetStorage(void) { (void)memset(PlsrHostBackupSlots, 0, sizeof(PlsrHostBackupSlots)); } void PlsrPersistenceTestCorruptNewestHsd(void) { volatile PLSR_HSD_BACKUP_RECORD *slotA = PlsrPersistenceGetHsdSlot(0U); volatile PLSR_HSD_BACKUP_RECORD *slotB = PlsrPersistenceGetHsdSlot(1U); uint8_t validA = PlsrPersistenceHsdRecordIsValid(slotA); uint8_t validB = PlsrPersistenceHsdRecordIsValid(slotB); volatile PLSR_HSD_BACKUP_RECORD *newest; if ((validA == 0U) && (validB == 0U)) { return; } if ((validA != 0U) && (validB != 0U)) { newest = (PlsrPersistenceGenerationIsNewer(slotB->generation, slotA->generation) != 0U) ? slotB : slotA; } else { newest = (validA != 0U) ? slotA : slotB; } newest->crc32 ^= 1UL; } #endif