This commit includes the following CFSTORE/Flash-Journal/Storage updates and fixes:

- flash-journal basicAPI fix for ARM toolchain
- Updated storage-abstraction with version 0.4.7
  (commit c7c4a8c52298bbc006a6f53a059fb2599cad73cc).
- https://github.com/ARMmbed/storage-volume-manager at version v0.2.10.
- https://github.com/ARMmbed/mtd-k64f v0.4.2 version of flash.c (imported as storage_driver.c).
- update to CFSTORE to use the storage-volume-manager API to initialize volume manager and
  add a volume for CFSTORE to use.
- https://github.com/ARMmbed/flash-journal at version v0.5.3
  (commit 4c58165e2fa02c6ed2b9d166a9c96967e81f458f) including readFrom() support.
- Taking flash-journal-strategy-sequential v0.6.7 strategy.c
  (commit b11a718761aa9f33679956968a21aaef9179bde1).
- GCC_ARM, ARM and IAR compiler warning fixes for new versions of flash-journal code.
- Fix storage-volume-manager test cases for concurrent access from 2 volumes to use
  addresses within the 512-1024kB address range, which is within the cfstore added volume.
- Fix cfstore/storage-volume-manager IAR warnings when building with verbose flag.
pull/2701/head
Simon Hughes 2016-09-13 18:16:56 +01:00
parent 24e1218da7
commit 5e22db842f
31 changed files with 4059 additions and 400 deletions

View File

@ -32,8 +32,8 @@
using namespace utest::v1;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
/* temporary buffer to hold data for testing. */
static const unsigned BUFFER_SIZE = 16384;
@ -112,6 +112,7 @@ void test_getInfo()
TEST_ASSERT_EQUAL(0, info.security.reserved1);
TEST_ASSERT_EQUAL(0, info.security.reserved2);
TEST_ASSERT((info.program_cycles == ARM_STORAGE_PROGRAM_CYCLES_INFINITE) || (info.program_cycles > 0));
TEST_ASSERT(info.total_storage > 0);
}
@ -373,7 +374,7 @@ control_t test_programDataUsingProgramUnit(const size_t call_count)
return (call_count < REPEAT_INSTANCES) ? CaseTimeout(200) + CaseRepeatAll: CaseTimeout(200);
} else {
TEST_ASSERT_EQUAL(firstBlock.attributes.erase_unit, rc);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
static const uint32_t BYTE_PATTERN = 0xAA551122;
size_t sizeofData = info.program_unit;
@ -495,7 +496,7 @@ control_t test_programDataUsingOptimalProgramUnit(const size_t call_count)
return (call_count < REPEAT_INSTANCES) ? CaseTimeout(200) + CaseRepeatAll: CaseTimeout(200);
} else {
TEST_ASSERT_EQUAL(firstBlock.attributes.erase_unit, rc);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
static const uint8_t BYTE_PATTERN = 0xAA;
size_t sizeofData = info.optimal_program_unit;
@ -579,10 +580,12 @@ void eraseCompleteCallback(int32_t status, ARM_STORAGE_OPERATION operation)
const uint64_t addr = firstBlock.addr + eraseIteration * ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit;
++eraseIteration;
#ifndef __CC_ARM
printf("testing erased sector at addr %lu\n", (uint32_t)addr);
#endif
verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, (uint8_t)0xFF);
ARM_STORAGE_INFO info;
int32_t rc = drv->GetInfo(&info);
TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
//printf("testing erased sector at addr %lu", (uint32_t)addr);
verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
Harness::validate_callback();
}
@ -628,6 +631,10 @@ control_t test_erase(const size_t call_count)
} else {
TEST_ASSERT_EQUAL(ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, rc);
ARM_STORAGE_INFO info;
rc = drv->GetInfo(&info);
TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
/* test that the actual sector has been erased */
printf("testing erased sector at addr %lu\n", (uint32_t)addr);
verifyBytePattern(addr, ERASE_UNITS_PER_ITERATION * firstBlock.attributes.erase_unit, (uint8_t)0xFF);
@ -708,8 +715,12 @@ control_t test_eraseAll(const size_t call_count)
unsigned index = 0;
static const unsigned MAX_VERIFY_ITERATIONS = 5;
while ((index < MAX_VERIFY_ITERATIONS) && (addr < (firstBlock.addr + firstBlock.size))) {
printf("testing erased chip at addr %lu\n", (uint32_t)addr);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, (uint8_t)0xFF);
//printf("testing erased chip at addr %lu", (uint32_t)addr);
ARM_STORAGE_INFO info;
rc = drv->GetInfo(&info);
TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
verifyBytePattern(addr, firstBlock.attributes.erase_unit, info.erased_value ? (uint8_t)0xFF : (uint8_t)0);
index++;
addr += firstBlock.attributes.erase_unit;

View File

@ -279,7 +279,7 @@ control_t cfstore_add_del_test_04(const size_t call_count)
return CaseNext;
}
/** @brief Delete and attribute after an internal realloc of the cfstore memory area
/** @brief Delete an attribute after an internal realloc of the cfstore memory area
*
* This test case goes through the following steps:
* 1. Creates attribute att_1 of size x, and write some data. This causes an internal

View File

@ -234,7 +234,6 @@ typedef enum cfstore_ex_state_t {
CFSTORE_EX_STATE_UNINIT_DONE
} cfstore_ex_state_t;
typedef struct cfstore_example1_ctx_t
{
ARM_CFSTORE_CAPABILITIES caps;
@ -263,7 +262,87 @@ static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx);
/// @endcond
/* @brief test startup code to reset flash
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
#define CFSTORE_FLASH_START_FORMAT (FLASH_JOURNAL_OPCODE_RESET + 0x00010000)
typedef enum cfstore_ex_flash_state_t {
CFSTORE_EX_FLASH_STATE_STARTING = 1,
CFSTORE_EX_FLASH_STATE_FORMATTING,
CFSTORE_EX_FLASH_STATE_INITIALIZING,
CFSTORE_EX_FLASH_STATE_RESETTING,
CFSTORE_EX_FLASH_STATE_READY,
} cfstore_ex_flash_state_t;
typedef struct cfstore_example1_flash_ctx_t
{
volatile cfstore_ex_flash_state_t state;
} cfstore_example1_flash_ctx_t;
static cfstore_example1_flash_ctx_t cfstore_example1_flash_ctx_g;
static void cfstore_ex_flash_journal_callback(int32_t status, FlashJournal_OpCode_t cmd_code)
{
static FlashJournal_t jrnl;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
if(cmd_code == (FlashJournal_OpCode_t) CFSTORE_FLASH_START_FORMAT) {
CFSTORE_EX1_LOG("FORMATTING%s", "\n");
status = flashJournalStrategySequential_format(drv, 4, cfstore_ex_flash_journal_callback);
CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_format() failed (status=%d)\r\n", __func__, (int) status);
if(status == 0) {
/* async completion pending */
return;
}
/* status > 0 implies operation completed synchronously
* intentional fall through */
}
switch(cmd_code)
{
case FLASH_JOURNAL_OPCODE_FORMAT:
/* format done */
CFSTORE_EX1_TEST_ASSERT_MSG(status > JOURNAL_STATUS_OK, "%s:Error: FlashJournal_format() failed (status=%d)\r\n", __func__, (int) status);
cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_INITIALIZING;
CFSTORE_EX1_LOG("FLASH INITIALIZING%s", "\n");
status = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (status=%d)\r\n", __func__, (int) status);
if(status == 0) {
/* async completion pending */
break;
}
/* status > 0 implies operation completed synchronously
* intentional fall through */
case FLASH_JOURNAL_OPCODE_INITIALIZE:
/* initialize done */
CFSTORE_EX1_TEST_ASSERT_MSG(status > JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (status=%d)\r\n", __func__, (int) status);
cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_RESETTING;
CFSTORE_EX1_LOG("FLASH RESETTING%s", "\n");
status = FlashJournal_reset(&jrnl);
CFSTORE_EX1_TEST_ASSERT_MSG(status >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_reset() failed (status=%d)\r\n", __func__, (int) status);
/* intentional fall through */
case FLASH_JOURNAL_OPCODE_RESET:
/* reset done */
CFSTORE_EX1_LOG("FLASH RESET DONE%s", "\n");
cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_READY;
break;
default:
CFSTORE_EX1_LOG("%s:Error: notification of unsupported cmd_code event (status=%d, cmd_code=%d)\n", __func__, (int) status, (int) cmd_code);
return;
}
return;
}
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
/* @brief test startup code to reset flash for testing purposes.
*/
static int32_t cfstore_test_startup(void)
{
@ -272,16 +351,13 @@ static int32_t cfstore_test_startup(void)
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
int32_t ret = ARM_DRIVER_ERROR;
static FlashJournal_t jrnl;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
memset(&cfstore_example1_flash_ctx_g, 0, sizeof(cfstore_example1_flash_ctx_g));
cfstore_example1_flash_ctx_g.state = CFSTORE_EX_FLASH_STATE_STARTING;
cfstore_ex_flash_journal_callback(JOURNAL_STATUS_OK, (FlashJournal_OpCode_t) CFSTORE_FLASH_START_FORMAT);
while(cfstore_example1_flash_ctx_g.state != CFSTORE_EX_FLASH_STATE_READY) {
/* spin */
}
ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
CFSTORE_EX1_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (ret=%d)\r\n", __func__, (int) ret);
ret = FlashJournal_reset(&jrnl);
CFSTORE_EX1_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_reset() failed (ret=%d)\r\n", __func__, (int) ret);
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
return ARM_DRIVER_OK;

View File

@ -268,7 +268,7 @@ static control_t cfstore_example3_app_start(const size_t call_count)
ctx->hkey_prev = ctx->hkey_prev_buf;
ctx->caps = cfstore_drv->GetCapabilities();
CFSTORE_EX1_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
if(ctx->caps.asynchronous_ops == true){
if(ctx->caps.asynchronous_ops == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_EX1_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");

View File

@ -74,7 +74,7 @@ static control_t cfstore_example4_test_00(const size_t call_count)
/* initialise the context */
caps = gCfStoreDriver->GetCapabilities();
CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, caps.asynchronous_ops);
if(caps.asynchronous_ops == true){
if(caps.asynchronous_ops == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");

View File

@ -167,8 +167,8 @@ int32_t cfstore_test_startup(void)
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
int32_t ret = ARM_DRIVER_ERROR;
static FlashJournal_t jrnl;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
CFSTORE_EX5_TEST_ASSERT_MSG(ret >= JOURNAL_STATUS_OK, "%s:Error: FlashJournal_initialize() failed (ret=%d)\r\n", __func__, (int) ret);
@ -278,7 +278,7 @@ static control_t cfstore_EXAMPLE5_app_start(const size_t call_count)
ctx->hkey_prev = ctx->hkey_prev_buf;
ctx->caps = cfstore_drv->GetCapabilities();
CFSTORE_EX5_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
if(ctx->caps.asynchronous_ops == true){
if(ctx->caps.asynchronous_ops){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_EX5_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");

View File

@ -88,7 +88,8 @@ char cfstore_flash_utest_msg_g[CFSTORE_FLASH_UTEST_MSG_BUF_SIZE];
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
uint16_t cfstore_flash_mtd_async_ops_g = 0;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
/* KV data for test_01 */
static cfstore_kv_data_t cfstore_flush_test_01_kv_data[] = {
@ -279,7 +280,7 @@ void cfstore_flash_test_01_callback(int32_t status, FlashJournal_OpCode_t cmd_co
static void cfstore_flash_fsm_init_on_entry(void* context)
{
/* round up cfstore_flash_data_blob_t to nearest k64f program unit size */
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
FlashJournal_Info_t info;
FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context;

View File

@ -844,7 +844,7 @@ static control_t cfstore_flush3_test_00(const size_t call_count)
/* initialise the context */
caps = drv->GetCapabilities();
CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, caps.asynchronous_ops);
if(caps.asynchronous_ops == true){
if(caps.asynchronous_ops == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");

View File

@ -103,7 +103,7 @@ static control_t cfstore_init_app_start(const size_t call_count)
memset(ctx, 0, sizeof(cfstore_init_ctx_t));
ctx->caps = cfstore_drv->GetCapabilities();
CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops);
if(ctx->caps.asynchronous_ops == true){
if(ctx->caps.asynchronous_ops == 1){
/* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true
* This means the test will conveniently pass when run in CI as part of async mode testing */
CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n");

View File

@ -272,7 +272,7 @@ control_t cfstore_misc_test_04_start(const size_t call_count)
status = drv->GetStatus();
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() before initialisation should have reported error, but reported no error.\r\n", __func__);
TEST_ASSERT_MESSAGE(status.error == true, cfstore_misc_utest_msg_g);
TEST_ASSERT_MESSAGE(status.error == 1, cfstore_misc_utest_msg_g);
ret = drv->Initialize(cfstore_utest_default_callback, NULL);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%d)\n", __func__, (int) ret);
@ -295,10 +295,10 @@ control_t cfstore_misc_test_04_end(const size_t call_count)
status = drv->GetStatus();
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() but reported error.\r\n", __func__);
TEST_ASSERT_MESSAGE(status.error == false, cfstore_misc_utest_msg_g);
TEST_ASSERT_MESSAGE(status.error == 0, cfstore_misc_utest_msg_g);
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() reported operation in progress.\r\n", __func__);
TEST_ASSERT_MESSAGE(status.in_progress == false, cfstore_misc_utest_msg_g);
TEST_ASSERT_MESSAGE(status.in_progress == 0, cfstore_misc_utest_msg_g);
ret = drv->Uninitialize();
CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__);

View File

@ -15,10 +15,6 @@
* limitations under the License.
*/
#if !DEVICE_STORAGE
#error [NOT_SUPPORTED] Storage not supported for this target
#endif
#ifdef TARGET_LIKE_POSIX
#define AVOID_GREENTEA
#endif
@ -29,6 +25,7 @@
#include "utest/utest.h"
#include "unity/unity.h"
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
#include "flash-journal-strategy-sequential/flash_journal_private.h"
#include <string.h>
@ -36,8 +33,8 @@
using namespace utest::v1;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
FlashJournal_t journal;
@ -54,32 +51,64 @@ void callbackHandler(int32_t status, FlashJournal_OpCode_t cmd_code)
switch (cmd_code) {
case FLASH_JOURNAL_OPCODE_INITIALIZE:
// printf("journal_callbackHandler: callback for init with status %" PRId32 "\n", status);
//printf("journal_callbackHandler: callback for init with status %" PRId32 "\n", status);
break;
case FLASH_JOURNAL_OPCODE_READ_BLOB:
// printf("journal_callbackHandler: callback for read with status %" PRId32 "\n", status);
//printf("journal_callbackHandler: callback for read with status %" PRId32 "\n", status);
break;
case FLASH_JOURNAL_OPCODE_LOG_BLOB:
// printf("journal_callbackHandler: callback for log with status %" PRId32 "\n", status);
//printf("journal_callbackHandler: callback for log with status %" PRId32 "\n", status);
break;
case FLASH_JOURNAL_OPCODE_COMMIT:
// printf("journal_callbackHandler: callback for commit with status %" PRId32 "\n", status);
//printf("journal_callbackHandler: callback for commit with status %" PRId32 "\n", status);
break;
case FLASH_JOURNAL_OPCODE_RESET:
// printf("journal_callbackHandler: callback for reset with status %" PRId32 "\n", status);
//printf("journal_callbackHandler: callback for reset with status %" PRId32 "\n", status);
break;
case FLASH_JOURNAL_OPCODE_FORMAT:
//printf("journal_callbackHandler: callback for format with status %" PRId32 "\n", status);
break;
default:
// printf("journal_callbackHandler: callback for opcode %u with status %" PRId32 "\n", cmd_code, status);
//printf("journal_callbackHandler: callback for opcode %u with status %" PRId32 "\n", cmd_code, status);
break;
}
Harness::validate_callback(); // Validate the callback
}
control_t test_format(const size_t call_count)
{
int32_t rc;
//printf("test_format: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
ARM_STORAGE_INFO mtdInfo;
rc = drv->GetInfo(&mtdInfo);
TEST_ASSERT_EQUAL(ARM_DRIVER_OK, rc);
TEST_ASSERT(mtdInfo.total_storage > 0);
if (call_count == 1) {
rc = flashJournalStrategySequential_format(drv, 4 /* numSlots */, callbackHandler);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
return CaseTimeout(200) + CaseRepeatAll;
}
TEST_ASSERT_EQUAL(1, rc); /* synchronous completion is expected to return 1. */
}
return CaseNext;
}
void test_initializeBeforeCreate()
{
int32_t rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
TEST_ASSERT((rc == 1) || (rc == JOURNAL_STATUS_NOT_FORMATTED));
}
control_t test_initialize()
{
int32_t rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
@ -115,7 +144,7 @@ control_t test_resetAndInitialize(const size_t call_count)
NEEDS_VERIFICATION_FOLLOWING_INITIALIZE,
} state;
printf("test_resetAndInitialize: entered with call_count %u\n", call_count);
//printf("test_resetAndInitialize: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
if (call_count == 1) {
state = NEEDS_INITIAL_RESET;
}
@ -127,7 +156,7 @@ control_t test_resetAndInitialize(const size_t call_count)
TEST_ASSERT(info.capacity > 0);
previousCapacity = info.capacity;
printf("test_resetAndInitialize: calling reset()\n");
//printf("test_resetAndInitialize: calling reset()\n");
rc = FlashJournal_reset(&journal);
TEST_ASSERT_NOT_EQUAL(JOURNAL_STATUS_UNSUPPORTED, rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
@ -152,7 +181,7 @@ control_t test_resetAndInitialize(const size_t call_count)
TEST_ASSERT_EQUAL(0, info.sizeofJournaledBlob);
/* attempt an initialize following reset() */
printf("test_resetAndInitialize: calling initialize() after reset\n");
//printf("test_resetAndInitialize: calling initialize() after reset\n");
rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
state = NEEDS_VERIFICATION_FOLLOWING_INITIALIZE;
@ -164,7 +193,7 @@ control_t test_resetAndInitialize(const size_t call_count)
/* fall through */
case NEEDS_VERIFICATION_FOLLOWING_INITIALIZE:
default:
printf("test_resetAndInitialize: verification\n");
//printf("test_resetAndInitialize: verification\n");
TEST_ASSERT_EQUAL(0, sequentialJournal->nextSequenceNumber);
TEST_ASSERT_EQUAL((uint32_t)-1, sequentialJournal->currentBlobIndex);
TEST_ASSERT_EQUAL(SEQUENTIAL_JOURNAL_STATE_INITIALIZED, sequentialJournal->state);
@ -184,7 +213,7 @@ control_t test_commitWithoutLogs(const size_t call_count)
{
int32_t rc;
printf("test_commitWithoutLogs: entered with call_count %u\n", call_count);
//printf("test_commitWithoutLogs: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
@ -199,7 +228,7 @@ control_t test_commitWithoutLogs(const size_t call_count)
case 2:
rc = FlashJournal_commit(&journal);
// printf("commit returned %" PRId32 "\r\n", rc);
//printf("commit returned %" PRId32 "\r\n", rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
@ -221,7 +250,7 @@ control_t test_logSmallWithoutCommit(const size_t call_count)
{
int32_t rc;
printf("test_logSmallWithoutCommit: entered with call_count %u\n", call_count);
//printf("test_logSmallWithoutCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
@ -257,7 +286,7 @@ control_t test_logSmallAndCommit(const size_t call_count)
{
int32_t rc;
printf("test_logSmallAndCommit: entered with call_count %u\n", call_count);
//printf("test_logSmallAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
@ -311,13 +340,13 @@ control_t test_initializeAfterLogSmallAndCommit(const size_t call_count)
{
int32_t rc;
printf("test_initializeAfterLogSmallAndCommit: entered with call_count %u\n", call_count);
//printf("test_initializeAfterLogSmallAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
if (call_count == 1) {
rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
printf("asynchronous_ops for init\n");
//printf("asynchronous_ops for init\n");
return CaseTimeout(200) + CaseRepeatAll;
}
TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
@ -335,7 +364,7 @@ control_t test_logLargeWithoutCommit(const size_t call_count)
{
int32_t rc;
printf("test_logLargeWithoutCommit: entered with call_count %u\n", call_count);
//printf("test_logLargeWithoutCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
@ -370,7 +399,7 @@ control_t test_logLargeAndCommit(const size_t call_count)
{
int32_t rc;
printf("test_logLargeAndCommit: entered with call_count %u\n", call_count);
//printf("test_logLargeAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
@ -424,13 +453,13 @@ control_t test_initializeAfterLogLargeAndCommit(const size_t call_count)
{
int32_t rc;
printf("test_initializeAfterLogLargeAndCommit: entered with call_count %u\n", call_count);
//printf("test_initializeAfterLogLargeAndCommit: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
if (call_count == 1) {
rc = FlashJournal_initialize(&journal, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, callbackHandler);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
printf("test_initializeAfterLogLargeAndCommit: asynchronous_ops for init\n");
//printf("test_initializeAfterLogLargeAndCommit: asynchronous_ops for init\n");
return CaseTimeout(200) + CaseRepeatAll;
}
TEST_ASSERT_EQUAL(1, rc); /* synchronous completion of initialize() is expected to return 1 */
@ -449,7 +478,7 @@ control_t test_logLargeAndReadSmallChunks(const size_t call_count)
{
int32_t rc;
printf("test_logLargeAndReadSmallChunks: entered with call_count %u\n", call_count);
//printf("test_logLargeAndReadSmallChunks: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
static const size_t SMALL_CHUNK_COUNT = 4;
@ -501,7 +530,7 @@ control_t test_logLargeAndReadSmallChunks(const size_t call_count)
}
while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE / SMALL_CHUNK_COUNT)) != JOURNAL_STATUS_EMPTY) {
// printf("read returned %ld\n", rc);
// printf("read returned %" PRId32 "\n", rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
@ -523,7 +552,7 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
{
int32_t rc;
printf("test_readLargeInSmallOddChunks<0x%02x, %u>: entered with call_count %u\n", PATTERN, SIZEOF_READS, call_count);
//printf("test_readLargeInSmallOddChunks<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
if (call_count == 1) {
FlashJournal_Info_t info;
@ -546,7 +575,7 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
}
while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READS)) != JOURNAL_STATUS_EMPTY) {
// printf("read returned %ld\n", rc);
// printf("read returned %" PRId32 "\n", rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
@ -563,6 +592,205 @@ control_t test_readLargeInSmallOddChunks(const size_t call_count)
return CaseNext;
}
template<uint8_t PATTERN>
control_t test_logPattern(size_t call_count)
{
int32_t rc = JOURNAL_STATUS_OK;
//printf("test_logpattern: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
switch (call_count) {
case 1:
for (unsigned index = 0; index < SIZEOF_LARGE_WRITE; index++) {
buffer[index] = (uint8_t)(PATTERN ^ index);
}
rc = FlashJournal_log(&journal, buffer, SIZEOF_LARGE_WRITE);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
/* intentional fall-through */
call_count = 2;
case 2:
rc = FlashJournal_commit(&journal);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
callbackStatus = rc;
/* intentional fall-through */
call_count = 3;
case 3:
{
FlashJournal_Info_t info;
rc = FlashJournal_getInfo(&journal, &info);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
}
/* intentional fall-through */
call_count = 4;
case 4:
TEST_ASSERT_EQUAL(1, callbackStatus);
rc = FlashJournal_read(&journal, buffer, SIZEOF_LARGE_WRITE);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
callbackStatus = rc;
/* intentional fall-through */
call_count = 4;
case 5:
TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, rc);
for (unsigned i = 0; i < SIZEOF_LARGE_WRITE; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ i), buffer[i]);
}
break;
default:
TEST_ASSERT(false);
break;
}
return CaseNext;
}
template<uint8_t PATTERN, size_t SIZEOF_READS>
control_t test_readFromInReverse(const size_t call_count)
{
int32_t rc;
static size_t offset = SIZEOF_LARGE_WRITE;
//printf("test_readFrom<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
if (call_count == 1) {
FlashJournal_Info_t info;
rc = FlashJournal_getInfo(&journal, &info);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
TEST_ASSERT(SIZEOF_READS <= info.sizeofJournaledBlob);
rc = FlashJournal_readFrom(&journal, offset + 1, buffer, SIZEOF_READS);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_EMPTY, rc);
rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_EMPTY, rc);
offset -= SIZEOF_READS;
} else {
if (drv->GetCapabilities().asynchronous_ops) {
if (callbackStatus == 0) {
return CaseNext; /* termination condition */
}
TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
}
for (unsigned i = 0; i < SIZEOF_READS; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
}
if (offset == 0) {
return CaseNext;
}
if (offset >= SIZEOF_READS) {
offset -= SIZEOF_READS;
} else {
offset = 0;
}
}
// printf("test_readFrom: issuing read at offset %lu\n", offset);
while ((rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS)) != JOURNAL_STATUS_EMPTY) {
// printf("read returned %" PRId32 "\n", rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
TEST_ASSERT(rc <= (int32_t)SIZEOF_READS);
for (unsigned i = 0; i < (unsigned)rc; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
}
if (offset == 0) {
return CaseNext;
}
if (offset >= SIZEOF_READS) {
offset -= SIZEOF_READS;
} else {
offset = 0;
}
// printf("test_readFrom: issuing read at offset %lu\n", offset);
};
return CaseNext;
}
template<uint8_t PATTERN, size_t SIZEOF_READS>
control_t test_readFromFollowedByReads(size_t call_count)
{
//printf("test_readFrom<0x%02x, %" PRIu32 ">: entered with call_count %" PRIu32 "\n", PATTERN, (uint32_t)SIZEOF_READS, (uint32_t)call_count);
int32_t rc;
static size_t offset = SIZEOF_LARGE_WRITE / 2;
FlashJournal_Info_t info;
switch (call_count) {
case 1:
rc = FlashJournal_getInfo(&journal, &info);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
TEST_ASSERT_EQUAL(SIZEOF_LARGE_WRITE, info.sizeofJournaledBlob);
TEST_ASSERT(SIZEOF_READS <= (info.sizeofJournaledBlob - offset));
rc = FlashJournal_readFrom(&journal, offset, buffer, SIZEOF_READS);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
callbackStatus = rc;
/* intentional fall-through */
call_count = 2;
case 2:
/* verify the previous readFrom */
TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
for (unsigned i = 0; i < (unsigned)callbackStatus; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + i)), buffer[i]);
}
/* issue a sequential read to follow the previous readFrom */
rc = FlashJournal_read(&journal, buffer, SIZEOF_READS);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
callbackStatus = rc;
/* intentional fall-through */
call_count = 3;
case 3:
TEST_ASSERT_EQUAL(SIZEOF_READS, callbackStatus);
for (unsigned i = 0; i < (unsigned)callbackStatus; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL((uint8_t)(PATTERN ^ (offset + SIZEOF_READS + i)), buffer[i]);
}
break;
}
return CaseNext;
}
template<size_t SIZEOF_ODD_CHUNK, size_t N_WRITES>
control_t test_logSeveralOddSizedChunks(size_t call_count)
{
@ -573,7 +801,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
static const uint8_t PATTERN = 0xAA;
static size_t totalDataLogged = 0;
printf("test_logSeveralOddSizedChunks<%u, %u>: entered with call_count %u\n", SIZEOF_ODD_CHUNK, N_WRITES, call_count);
//printf("test_logSeveralOddSizedChunks<%" PRIu32 ", %" PRIu32 ">: entered with call_count %" PRIu32 "\n", (uint32_t)SIZEOF_ODD_CHUNK, (uint32_t)N_WRITES, (uint32_t)call_count);
TEST_ASSERT(SIZEOF_ODD_CHUNK <= BUFFER_SIZE);
/* check the status of the previous asynchronous operation */
@ -584,7 +812,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
rc = FlashJournal_getInfo(&journal, &info);
TEST_ASSERT_EQUAL(JOURNAL_STATUS_OK, rc);
TEST_ASSERT(SIZEOF_ODD_CHUNK < info.program_unit);
printf("test_logSeveralOddSizedChunks: RETURNING CaseNext\n");
//printf("test_logSeveralOddSizedChunks: RETURNING CaseNext\n");
return CaseNext;
}
@ -600,7 +828,7 @@ control_t test_logSeveralOddSizedChunks(size_t call_count)
}
while (call_count <= N_WRITES) {
printf("test_logSeveralOddSizedChunks: iteration with call_count %u\n", call_count);
//printf("test_logSeveralOddSizedChunks: iteration with call_count %" PRIu32 "\n", (uint32_t)call_count);
memset(buffer, PATTERN, SIZEOF_ODD_CHUNK);
rc = FlashJournal_log(&journal, buffer, SIZEOF_ODD_CHUNK);
// printf("test_logSeveralOddSizedChunks: called FlashJournal_log(): rc = %" PRId32 "\n", rc);
@ -663,13 +891,13 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
static const size_t SIZEOF_WRITE = BUFFER_SIZE / N_WRITES;
static const size_t SIZEOF_READ = BUFFER_SIZE / N_READS;
printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: entered with call_count %u\n", call_count);
//printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
if (call_count <= N_WRITES) {
printf("writing pattern %02x\n", PATTERN ^ call_count);
//printf("writing pattern %02" PRIx8 "\n", (uint8_t)(PATTERN ^ call_count));
memset(buffer, (PATTERN ^ call_count), SIZEOF_WRITE);
rc = FlashJournal_log(&journal, buffer, SIZEOF_WRITE);
// printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: log returned %" PRId32 "\n", rc);
//printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: log returned %" PRId32 "\n", rc);
TEST_ASSERT(rc >= JOURNAL_STATUS_OK);
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
@ -684,12 +912,12 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
return CaseTimeout(500) + CaseRepeatAll;
}
// printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: commit returned %" PRId32 "\n", rc);
//printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: commit returned %" PRId32 "\n", rc);
callbackStatus = rc; /* pass forward the return value so that the next iteration can check callbackStatus */
return CaseRepeatAll;
} else if (call_count < (N_WRITES + 1 + N_READS + 1)) {
unsigned readIteration = call_count - (N_WRITES + 1);
printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read iteration %u\n", readIteration);
//printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read iteration %u\n", readIteration);
if (call_count == (N_WRITES + 1 /* commit */ + 1 /* first iteration after commit */)) {
TEST_ASSERT_EQUAL(1, callbackStatus);
@ -706,7 +934,7 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
}
while ((rc = FlashJournal_read(&journal, buffer, SIZEOF_READ)) != JOURNAL_STATUS_EMPTY) {
// printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read returned %ld\n", rc);
// printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: read returned %" PRId32 "\n", rc);
TEST_ASSERT((rc == JOURNAL_STATUS_OK) || (rc == SIZEOF_READ));
if (rc == JOURNAL_STATUS_OK) {
TEST_ASSERT_EQUAL(1, drv->GetCapabilities().asynchronous_ops);
@ -714,7 +942,7 @@ control_t test_multipleWritesFollowedByCommitFollowedByMultipleReads(const size_
}
TEST_ASSERT_EQUAL(SIZEOF_READ, rc);
printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: checking for pattern %02x\n", PATTERN ^ readIteration);
//printf("test_multipleWritesFollowedByCommitFollowedByMultipleReads: checking for pattern %02x\n", PATTERN ^ readIteration);
for (unsigned i = 0; i < SIZEOF_READ; i++) {
// printf("index %u value %x\n", i, buffer[i]);
TEST_ASSERT_EQUAL(PATTERN ^ readIteration, buffer[i]);
@ -733,7 +961,7 @@ control_t test_failedSmallWriteFollowedByPaddedWrite(const size_t call_count)
static const uint8_t PATTERN = 0xAA;
printf("test_failedSmallWriteFollowedByPaddedWrite: entered with call_count %u\n", call_count);
//printf("test_failedSmallWriteFollowedByPaddedWrite: entered with call_count %" PRIu32 "\n", (uint32_t)call_count);
FlashJournal_Info_t info;
rc = FlashJournal_getInfo(&journal, &info);
@ -799,9 +1027,35 @@ control_t test_failedSmallWriteFollowedByPaddedWrite(const size_t call_count)
return CaseNext;
}
void test_crc32()
{
const unsigned char dummyMsg[] = "ahello world";
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xe8b7be43, flashJournalCrcCummulative(dummyMsg, 1));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x7e56a173, flashJournalCrcCummulative(dummyMsg, 2));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x26a80c7d, flashJournalCrcCummulative(dummyMsg, 3));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xb8946773, flashJournalCrcCummulative(dummyMsg, 4));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x5fb2761f, flashJournalCrcCummulative(dummyMsg, 5));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x82582cc7, flashJournalCrcCummulative(dummyMsg, 6));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xeceec07a, flashJournalCrcCummulative(dummyMsg, 7));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xac5f7df0, flashJournalCrcCummulative(dummyMsg, 8));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xb21e3e25, flashJournalCrcCummulative(dummyMsg, 9));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x27bf35e4, flashJournalCrcCummulative(dummyMsg, 10));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0x31465baa, flashJournalCrcCummulative(dummyMsg, 11));
flashJournalCrcReset(); TEST_ASSERT_EQUAL(0xaeef4661, flashJournalCrcCummulative(dummyMsg, 12));
/* check for composability */
uint32_t crc;
for (unsigned msgLen = 1; msgLen < strlen((const char *)dummyMsg); msgLen++) {
for (unsigned partitionIndex = 1; partitionIndex < msgLen; partitionIndex++) {
flashJournalCrcReset(); crc = flashJournalCrcCummulative(dummyMsg, partitionIndex); crc = flashJournalCrcCummulative(dummyMsg + partitionIndex, msgLen - partitionIndex);
flashJournalCrcReset(); TEST_ASSERT_EQUAL(flashJournalCrcCummulative(dummyMsg, msgLen), crc);
}
}
}
#ifndef AVOID_GREENTEA
// Custom setup handler required for proper Greentea support
utest::v1::status_t greentea_setup(const size_t number_of_cases)
status_t greentea_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
// Call the default reporting function
@ -816,6 +1070,9 @@ status_t default_setup(const size_t)
// Specify all your test cases here
Case cases[] = {
Case("initializeBeforeCreate", test_initializeBeforeCreate),
Case("format", test_format),
Case("initialize", test_initialize),
Case("reset and initialize1", test_resetAndInitialize),
@ -861,6 +1118,17 @@ Case cases[] = {
Case("read large item in small, odd-sized chunks3", test_readLargeInSmallOddChunks<0xAA, 1021>),
Case("read large item in small, odd-sized chunks4", test_readLargeInSmallOddChunks<0xAA, 2401>),
Case("log pattern", test_logPattern<0x55>),
Case("readFrom", test_readFromInReverse<0x55, 255>),
Case("readFrom", test_readFromInReverse<0x55, 512>),
Case("readFrom", test_readFromInReverse<0x55, ((BUFFER_SIZE / 2) - 1)>),
Case("readFrom", test_readFromInReverse<0x55, BUFFER_SIZE>),
Case("readFrom followed by sequential reads", test_readFromFollowedByReads<0x55, 255>),
Case("readFrom followed by sequential reads", test_readFromFollowedByReads<0x55, 511>),
Case("readFrom followed by sequential reads", test_readFromFollowedByReads<0x55, 512>),
Case("readFrom followed by sequential reads", test_readFromFollowedByReads<0x55, 513>),
Case("readFrom followed by sequential reads", test_readFromFollowedByReads<0x55, 1024>),
/* log odd-sized blocks which wouldn't align with program_unit at the tail */
Case("initialize3", test_initialize),
Case("log odd-sized chunk", test_logSeveralOddSizedChunks<1, 1>),
@ -876,6 +1144,7 @@ Case cases[] = {
Case("failed small write followed by padded write", test_failedSmallWriteFollowedByPaddedWrite),
Case("reset and initialize6", test_resetAndInitialize),
Case("crc32", test_crc32),
// Case("uninitialize", test_uninitialize),
};

View File

@ -56,9 +56,8 @@
#define CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
#endif
// todo: fixup for storage driver using more than the STORAGE_xxx namespace:
#if defined DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#define CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#if defined STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#define CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS
#endif

View File

@ -27,6 +27,7 @@
printf(_fmt, __VA_ARGS__); \
}while(0);
//todo: restore #define noCFSTORE_DEBUG
#define noCFSTORE_DEBUG
//#define CFSTORE_DEBUG
#ifdef CFSTORE_DEBUG

View File

@ -0,0 +1,76 @@
/*
* mbed Microcontroller Library
* Copyright (c) 2006-2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdint.h>
#include <Driver_Common.h>
#include "storage_volume_manager.h"
#include "cfstore_config.h"
#include "cfstore_debug.h"
#include "cfstore_svm.h"
/** @file cfstore_svm.cpp
*
* This module is provides a C wrapper to the C++ storage-volume-manager.h API,
* so it can be called by the C-HAL implementation configuration_store.c
*/
#define CFSTORE_SVM_VOL_01_START_OFFSET 0x80000UL
#define CFSTORE_SVM_VOL_01_SIZE 0x80000UL
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
static ARM_DRIVER_STORAGE *cfstore_svm_storage_drv = &ARM_Driver_Storage_MTD_K64F;
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
/* the storage volume manager instance used to generate virtual mtd descriptors */
static StorageVolumeManager volumeManager;
/* used only for the initialization of the volume-manager. */
static void cfstore_svm_volume_manager_initialize_callback(int32_t status)
{
CFSTORE_FENTRYLOG("%s: operation %d with status %d" , __func__, (int) operation, (int) status);
}
static void cfstore_svm_journal_mtc_callback(int32_t status, ARM_STORAGE_OPERATION operation)
{
CFSTORE_FENTRYLOG("%s: operation %d with status %d" , __func__, (int) operation, (int) status);
}
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *storage_mtd)
{
int32_t ret = ARM_DRIVER_OK;
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
ret = volumeManager.initialize(cfstore_svm_storage_drv, cfstore_svm_volume_manager_initialize_callback);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: volume-manager::initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
ret = volumeManager.addVolume_C(CFSTORE_SVM_VOL_01_START_OFFSET, CFSTORE_SVM_VOL_01_SIZE, storage_mtd);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: volume-manager::addVolume_C() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
ret = storage_mtd->Initialize(cfstore_svm_journal_mtc_callback);
if(ret < ARM_DRIVER_OK) {
CFSTORE_ERRLOG("%s:debug: storage_mtd->initialize() failed for storage_mtd=%p (ret=%d)", __func__, storage_mtd, (int) ret);
return ret;
}
return ret;
}

View File

@ -0,0 +1,41 @@
/*
* mbed Microcontroller Library
* Copyright (c) 2006-2016 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/** @file cfstore_svm.h
*
* This is the interface file to configuration store storage volume manager.
*/
#ifndef __CFSTORE_SVM_H_
#define __CFSTORE_SVM_H_
#include <Driver_Storage.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t cfstore_svm_init(struct _ARM_DRIVER_STORAGE *mtd);
#ifdef __cplusplus
}
#endif
#endif /*__CFSTORE_SVM_H_ */

View File

@ -257,8 +257,8 @@ int32_t cfstore_test_startup(void)
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
static FlashJournal_t jrnl;
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_MTD_K64F;
ret = FlashJournal_initialize(&jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, NULL);
if(ret < JOURNAL_STATUS_OK){

View File

@ -31,6 +31,7 @@
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
#include "cfstore_svm.h"
#include "flash_journal_strategy_sequential.h"
#include "flash_journal.h"
#include "Driver_Common.h"
@ -45,8 +46,10 @@
#ifdef CFSTORE_DEBUG
uint32_t cfstore_optDebug_g = 1;
uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY; */
//todo: restore uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
//uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY; */
uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY;
uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY;
#endif
@ -54,10 +57,12 @@ uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE
* Externs
*/
#ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_MTD_K64F;
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
struct _ARM_DRIVER_STORAGE cfstore_journal_mtd;
/*
* Defines
*
@ -69,7 +74,10 @@ ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
* valid sizes of areas should always be greater than the size of the header, and therefore
* greater than this value, which is defined as smaller than the header size
*
* ARM_DRIVER_OK_DONE
* CFSTORE_FLASH_NUMSLOTS
* number of flash journal slots
*
* ARM_DRIVER_OK_DONE
* value that indicates an operation has been done i.e. a value > 0
*/
#define CFSTORE_KEY_NAME_CHARS_ACCEPTABLE "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}.-_@"
@ -79,6 +87,7 @@ ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
#define CFSTORE_FILE_CREATE_MODE_DEFAULT (ARM_CFSTORE_FMODE)0
#define CFSTORE_FLASH_STACK_BUF_SIZE 64
#define CFSTORE_FLASH_AREA_SIZE_MIN (sizeof(cfstore_area_header_t) - 1)
#define CFSTORE_FLASH_NUMSLOTS 4
#define cfstore_fsm_null NULL
#define CFSTORE_SENTINEL 0x7fffffff
#define CFSTORE_CALLBACK_RET_CODE_DEFAULT 0x1
@ -169,6 +178,7 @@ typedef enum cfstore_fsm_state_t {
cfstore_fsm_state_committing,
cfstore_fsm_state_resetting,
cfstore_fsm_state_ready, /* ready for next flash journal command to arise */
cfstore_fsm_state_formatting, /* flash formatting in progress */
cfstore_fsm_state_max
} cfstore_fsm_state_t;
@ -180,6 +190,7 @@ typedef enum cfstore_fsm_event_t {
cfstore_fsm_event_commit_req,
cfstore_fsm_event_commit_done,
cfstore_fsm_event_reset_done,
cfstore_fsm_event_format_done,
cfstore_fsm_event_max,
} cfstore_fsm_event_t;
@ -198,6 +209,7 @@ typedef struct cfstore_fsm_t
/* strings used for debug trace */
static const char* cfstore_flash_opcode_str[] =
{
"FLASH_JOURNAL_OPCODE_FORMAT",
"FLASH_JOURNAL_OPCODE_INITIALIZE",
"FLASH_JOURNAL_OPCODE_GET_INFO",
"FLASH_JOURNAL_OPCODE_READ_BLOB",
@ -215,6 +227,7 @@ static const char* cfstore_flash_state_str[] =
"committing",
"resetting",
"ready",
"formatting",
"unknown"
};
@ -226,6 +239,7 @@ static const char* cfstore_flash_event_str[] =
"commit_req",
"commit_done",
"reset_done",
"format_done",
"unknown"
};
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
@ -727,7 +741,6 @@ void *cfstore_realloc(void *ptr, ARM_CFSTORE_SIZE size)
#ifdef CFSTORE_TARGET_LIKE_X86_LINUX_NATIVE
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag){ (void) tag; __sync_fetch_and_add(lock, 1); }
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag){(void) tag; __sync_fetch_and_sub(lock, 1); }
@ -764,7 +777,6 @@ static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkv
* Platform Specific Function Implementations
*/
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag)
{
(void) lock;
@ -1540,6 +1552,9 @@ static void cfstore_flash_journal_callback(int32_t status, FlashJournal_OpCode_t
CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]);
switch(cmd_code)
{
case FLASH_JOURNAL_OPCODE_FORMAT:
ctx->fsm.event = cfstore_fsm_event_format_done;
break;
case FLASH_JOURNAL_OPCODE_INITIALIZE:
ctx->fsm.event = cfstore_fsm_event_init_done;
break;
@ -1595,14 +1610,30 @@ static int32_t cfstore_fsm_stop_on_entry(void* context)
static int32_t cfstore_fsm_init_on_entry(void* context)
{
int32_t ret = ARM_DRIVER_ERROR;
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
ret = FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
ret = cfstore_svm_init(&cfstore_journal_mtd);
if(ret < ARM_DRIVER_OK){
CFSTORE_DBGLOG("%s:Error: Unable to initialize storage volume manager\n", __func__);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
return ARM_DRIVER_OK;
}
ret = FlashJournal_initialize(&ctx->jrnl, (ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
CFSTORE_TP(CFSTORE_TP_FSM, "%s:FlashJournal_initialize ret=%d\n", __func__, (int) ret);
if(ret < ARM_DRIVER_OK){
if(ret == JOURNAL_STATUS_NOT_FORMATTED) {
CFSTORE_DBGLOG("%s:Error: flash not formatted\n", __func__);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
return ARM_DRIVER_OK;
}
if(ret == JOURNAL_STATUS_METADATA_ERROR) {
CFSTORE_ERRLOG("%s:Error: flash meta-data (CRC) error detected when initializing flash. Reformatting flash.\n", __func__);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
return ARM_DRIVER_OK;
}
CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
}
@ -1993,18 +2024,64 @@ static int32_t cfstore_fsm_ready_on_commit_req(void* context)
/* int32_t cfstore_fsm_ready_on_exit(void* context){ (void) context;} */
/** @brief fsm handler when entering the formatting state
*/
static int32_t cfstore_fsm_format_on_entry(void* context)
{
int32_t ret = ARM_DRIVER_ERROR;
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
ret = flashJournalStrategySequential_format((ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, CFSTORE_FLASH_NUMSLOTS, cfstore_flash_journal_callback);
CFSTORE_TP(CFSTORE_TP_FSM, "%s:flashJournalStrategySequential_format ret=%d\n", __func__, (int) ret);
if(ret < ARM_DRIVER_OK){
CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ret);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
}
else if(ret > 0){
/* operation completed synchronously*/
cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_FORMAT);
}
return ret;
}
/** @brief fsm handler when in formatting state
*/
int32_t cfstore_fsm_formatting(void* context)
{
int32_t ret = ARM_DRIVER_OK;
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_formatting);
CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_FORMAT);
/* only change state if status > 0*/
if(ctx->status > 0){
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx);
} else if(ctx->status < 0) {
CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ctx->status);
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
}
return ret;
}
/* int32_t cfstore_fsm_format_on_exit(void* context){ (void) context;} */
/* handler functions while in state */
static cfstore_fsm_handler cfstore_flash_fsm[cfstore_fsm_state_max][cfstore_fsm_event_max] =
{
/* state\event: init_done read_done log_done commit_req commit_done reset_done */
/* stopped */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* init */ {cfstore_fsm_initing, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* reading */ {cfstore_fsm_null, cfstore_fsm_reading, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* logging */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_logging, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* committing */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_committing, cfstore_fsm_null },
/* resetting */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* ready */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_ready_on_commit_req, cfstore_fsm_null, cfstore_fsm_null },
/* state\event: init_done read_done log_done commit_req commit_done reset_done format_done, */
/* stopped */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* init */ {cfstore_fsm_initing, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* reading */ {cfstore_fsm_null, cfstore_fsm_reading, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* logging */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_logging, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* committing */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_committing, cfstore_fsm_null, cfstore_fsm_null },
/* resetting */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* ready */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_ready_on_commit_req, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
/* formatting */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_formatting },
};
/* handler functions for entering the state*/
@ -2016,7 +2093,8 @@ cfstore_fsm_handler cfstore_fsm_on_entry[cfstore_fsm_state_max] =
cfstore_fsm_log_on_entry,
cfstore_fsm_commit_on_entry,
cfstore_fsm_null, /* cfstore_fsm_reset_on_entry */
cfstore_fsm_null /* cfstore_fsm_ready_on_entry */
cfstore_fsm_null, /* cfstore_fsm_ready_on_entry */
cfstore_fsm_format_on_entry /* cfstore_fsm_format_on_entry */
};
/* handler functions for exiting state, currently none used */
@ -2028,7 +2106,8 @@ cfstore_fsm_handler cfstore_fsm_on_exit[cfstore_fsm_state_max] =
cfstore_fsm_log_on_exit,
cfstore_fsm_commit_on_exit,
cfstore_fsm_null, /* cfstore_fsm_reset_on_exit */
cfstore_fsm_null /* cfstore_fsm_ready_on_exit */
cfstore_fsm_null, /* cfstore_fsm_ready_on_exit */
cfstore_fsm_null /* cfstore_fsm_format_on_exit */
};
@ -2425,8 +2504,8 @@ static bool cfstore_file_is_empty(ARM_CFSTORE_HANDLE hkey)
/* @brief See definition in configuration_store.h for description. */
ARM_CFSTORE_CAPABILITIES cfstore_get_capabilities(void)
{
/* getting capabilities doesnt change the sram area so this can happen independently of
* an oustanding async operation. its unnecessary to check the fsm state */
/* getting capabilities doesn't change the sram area so this can happen independently of
* an outstanding async operation. its unnecessary to check the fsm state */
return cfstore_caps_g;
}
@ -3866,9 +3945,7 @@ static int32_t cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void* client_co
ctx->init_ref_count++;
/* initially there is no memory allocated for the area */
CFSTORE_INIT_LIST_HEAD(&ctx->file_list);
/* This is not required here are the lock is statically initialised to 0
* cfstore_critical_section_init(&ctx->rw_area0_lock);
*/
/* ctx->rw_area0_lock initialisation is not required here as the lock is statically initialised to 0 */
ctx->area_0_head = NULL;
ctx->area_0_tail = NULL;

View File

@ -1,25 +0,0 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FLASH_JOURNAL_CONFIG_H__
#define __FLASH_JOURNAL_CONFIG_H__
#ifndef SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS
#define SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS 4
#endif
#endif /* __FLASH_JOURNAL_CONFIG_H__ */

View File

@ -0,0 +1,220 @@
/**********************************************************************
*
* Filename: flash_journal_crc.c
*
* Description: Slow and fast implementations of the CRC standards.
*
* Notes: The parameters for each supported CRC standard are
* defined in the header file crc.h. The implementations
* here should stand up to further additions to that list.
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#define FALSE 0
#define TRUE !FALSE
#define CRC_NAME "CRC-32"
#define POLYNOMIAL 0x04C11DB7
#define INITIAL_REMAINDER 0xFFFFFFFF
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA TRUE
#define REFLECT_REMAINDER TRUE
#define CHECK_VALUE 0xCBF43926
/*
* Derive parameters from the standard-specific parameters in crc.h.
*/
#define WIDTH (8 * sizeof(flash_journal_crc32_t))
/* U postfix required to suppress the following warning with TOOLCHAIN_ARM:
* #61-D: integer operation result is out of range
*/
#define TOPBIT 0x80000000U
#if (REFLECT_DATA == TRUE)
#undef REFLECT_DATA
#define REFLECT_DATA(X) ((unsigned char) reflect((X), 8))
#else
#undef REFLECT_DATA
#define REFLECT_DATA(X) (X)
#endif
#if (REFLECT_REMAINDER == TRUE)
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) ((flash_journal_crc32_t) reflect((X), WIDTH))
#else
#undef REFLECT_REMAINDER
#define REFLECT_REMAINDER(X) (X)
#endif
/*********************************************************************
*
* Function: reflect()
*
* Description: Reorder the bits of a binary sequence, by reflecting
* them about the middle position.
*
* Notes: No checking is done that nBits <= 32.
*
* Returns: The reflection of the original data.
*
*********************************************************************/
static uint32_t
reflect(uint32_t data, unsigned char nBits)
{
uint32_t reflection = 0x00000000;
unsigned char bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < nBits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
{
reflection |= (1 << ((nBits - 1) - bit));
}
data = (data >> 1);
}
return (reflection);
} /* reflect() */
static flash_journal_crc32_t crcTable[256];
static flash_journal_crc32_t crcEngineRemainder = INITIAL_REMAINDER;
/*********************************************************************
*
* Function: flashJournalCrcInit()
*
* Description: Populate the partial CRC lookup table.
*
* Notes: This function must be rerun any time the CRC standard
* is changed. If desired, it can be run "offline" and
* the table results stored in an embedded system's ROM.
*
* Returns: None defined.
*
*********************************************************************/
void
flashJournalCrcInit(void)
{
flash_journal_crc32_t remainder;
int dividend;
unsigned char bit;
/*
* Compute the remainder of each possible dividend.
*/
for (dividend = 0; dividend < 256; ++dividend)
{
/*
* Start with the dividend followed by zeros.
*/
remainder = dividend << (WIDTH - 8);
/*
* Perform modulo-2 division, a bit at a time.
*/
for (bit = 8; bit > 0; --bit)
{
/*
* Try to divide the current data bit.
*/
if (remainder & TOPBIT)
{
remainder = (remainder << 1) ^ POLYNOMIAL;
}
else
{
remainder = (remainder << 1);
}
}
/*
* Store the result into the table.
*/
crcTable[dividend] = remainder;
}
} /* flashJournalCrcInit() */
/*********************************************************************
*
* Function: flashJournalCrcReset()
*
* Description: Resets internal state before calling crcCummulative().
*
* Notes: See the notes to crcCummulative().
*
* Returns: None defined.
*
*********************************************************************/
void
flashJournalCrcReset(void)
{
static unsigned initCalled = 0;
if (!initCalled) {
flashJournalCrcInit();
initCalled = 1;
}
crcEngineRemainder = INITIAL_REMAINDER;
} /* flashJournalCrcReset() */
/*********************************************************************
*
* Function: crcCummulative()
*
* Description: Compute the CRC of a group of messages.
*
* Notes:
* This function is intended to be used in the following way:
* - crcReset() is called first to reset internal state before the first
* fragment of a new message is processed with crcCummulative().
* - crcCummulative() called successfully appending additional message
* fragments to those previously supplied (in order), and returning
* the current crc for the message payload so far.
*
* Returns: The CRC of the message.
*
*********************************************************************/
flash_journal_crc32_t
flashJournalCrcCummulative(unsigned char const message[], int nBytes)
{
unsigned char data;
int byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < nBytes; ++byte)
{
data = REFLECT_DATA(message[byte]) ^ (crcEngineRemainder >> (WIDTH - 8));
crcEngineRemainder = crcTable[data] ^ (crcEngineRemainder << 8);
}
/*
* The final remainder is the CRC.
*/
return (REFLECT_REMAINDER(crcEngineRemainder) ^ FINAL_XOR_VALUE);
} /* crcCummulative() */

View File

@ -0,0 +1,34 @@
/**********************************************************************
*
* Filename: flash_journal_crc.h.h
*
* Description: A header file describing the various CRC standards.
*
* Notes:
*
*
* Copyright (c) 2000 by Michael Barr. This software is placed into
* the public domain and may be used for any purpose. However, this
* notice must not be changed or removed and no warranty is either
* expressed or implied by its publication or distribution.
**********************************************************************/
#ifndef _flash_journal_crc_h
#define _flash_journal_crc_h
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t flash_journal_crc32_t;
void flashJournalCrcReset(void);
flash_journal_crc32_t flashJournalCrcCummulative(unsigned char const message[], int nBytes);
#ifdef __cplusplus
}
#endif
#endif /* _flash_journal_crc_h */

View File

@ -23,11 +23,22 @@ extern "C" {
#endif // __cplusplus
#include "flash-journal/flash_journal.h"
#include "flash-journal-strategy-sequential/config.h"
static inline uint32_t roundUp_uint32(uint32_t N, uint32_t BOUNDARY) {
return ((((N) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY));
}
static inline uint32_t roundDown_uint32(uint32_t N, uint32_t BOUNDARY) {
return (((N) / (BOUNDARY)) * (BOUNDARY));
}
#define LCM_OF_ALL_ERASE_UNITS 4096 /* Assume an LCM of erase_units for now. This will be generalized later. */
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER = 0xFFFFFFFFUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_VERSION = 1;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_MAGIC = 0xCE02102AUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_MAGIC = 0xCE02102AUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_VERSION = 1;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC = 0xCEA00AEEUL;
static const uint32_t SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION = 1;
typedef enum {
SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED,
@ -41,6 +52,20 @@ typedef enum {
SEQUENTIAL_JOURNAL_STATE_READING,
} SequentialFlashJournalState_t;
/**
* Meta-data placed at the head of a Journal. The actual header would be an
* extension of this generic header, and would depend on the implementation
* strategy. Initialization algorithms can expect to find this generic header at
* the start of every Journal.
*/
typedef struct _SequentialFlashJournalHeader {
FlashJournalHeader_t genericHeader; /** Generic meta-data placed at the head of a Journal; common to all journal types. */
uint32_t magic; /** Sequential journal header specific magic code. */
uint32_t version; /** Revision number for this sequential journal header. */
uint32_t numSlots; /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
uint32_t sizeofSlot; /** Slot size. Each slot holds a header, blob-payload, and a tail. */
} SequentialFlashJournalHeader_t;
/**
* Meta-data placed at the head of a sequential-log entry.
*/
@ -62,9 +87,12 @@ typedef struct _SequentialFlashJournalLogHead {
* a partially written log-entry-tail won't be accepted as valid.
*/
typedef struct _SequentialFlashJournalLogTail {
uint64_t sizeofBlob; /**< the size of the payload in this blob. */
uint32_t sizeofBlob; /**< the size of the payload in this blob. */
uint32_t magic;
uint32_t sequenceNumber;
uint32_t crc32; /**< This field contains the CRC of the header, body (only including logged data),
* and the tail. The 'CRC32' field is assumed to hold 0x0 for the purpose of
* computing the CRC */
} SequentialFlashJournalLogTail_t;
#define SEQUENTIAL_JOURNAL_VALID_TAIL(TAIL_PTR) ((TAIL_PTR)->magic == SEQUENTIAL_FLASH_JOURNAL_MAGIC)
@ -76,7 +104,9 @@ typedef struct _SequentialFlashJournal_t {
ARM_DRIVER_STORAGE *mtd; /**< The underlying Memory-Technology-Device. */
ARM_STORAGE_CAPABILITIES mtdCapabilities; /**< the return from mtd->GetCapabilities(); held for quick reference. */
uint64_t mtdStartOffset; /**< the start of the address range maintained by the underlying MTD. */
uint32_t sequentialSkip; /**< size of the log stride. */
uint32_t firstSlotOffset; /** Offset from the start of the journal header to the actual logged journal. */
uint32_t numSlots; /** Maximum number of logged blobs; i.e. maximum number of versions of the journaled payload. */
uint32_t sizeofSlot; /**< size of the log stride. */
uint32_t nextSequenceNumber; /**< the next valid sequence number to be used when logging the next blob. */
uint32_t currentBlobIndex; /**< index of the most recently written blob. */
SequentialFlashJournalState_t state; /**< state of the journal. SEQUENTIAL_JOURNAL_STATE_INITIALIZED being the default. */
@ -90,12 +120,9 @@ typedef struct _SequentialFlashJournal_t {
/** state relevant to initialization. */
struct {
uint64_t currentOffset;
union {
SequentialFlashJournalLogHead_t head;
struct {
uint32_t headSequenceNumber;
SequentialFlashJournalLogTail_t tail;
};
struct {
uint32_t headSequenceNumber;
SequentialFlashJournalLogTail_t tail;
};
} initScan;
@ -105,11 +132,11 @@ typedef struct _SequentialFlashJournal_t {
size_t sizeofBlob;
union {
struct {
uint64_t eraseOffset;
uint64_t mtdEraseOffset;
};
struct {
uint64_t offset; /**< the current offset at which data is being written. */
uint64_t tailOffset; /**< offset at which the SequentialFlashJournalLogTail_t will be logged for this log-entry. */
uint64_t mtdOffset; /**< the current Storage offset at which data will be written. */
uint64_t mtdTailOffset; /**< Storage offset at which the SequentialFlashJournalLogTail_t will be logged for this log-entry. */
const uint8_t *dataBeingLogged; /**< temporary pointer aimed at the next data to be logged. */
size_t amountLeftToLog;
union {
@ -124,10 +151,10 @@ typedef struct _SequentialFlashJournal_t {
struct {
const uint8_t *blob; /**< the original buffer holding source data. */
size_t sizeofBlob;
uint64_t offset; /**< the current offset at which data is being written. */
uint64_t mtdOffset; /**< the current Storage offset from which data is being read. */
uint8_t *dataBeingRead; /**< temporary pointer aimed at the next data to be read-into. */
size_t amountLeftToRead;
size_t totalDataRead; /**< the total data that has been read off the blob so far. */
size_t logicalOffset; /**< the logical offset within the blob at which the next read will occur. */
} read;
};
} SequentialFlashJournal_t;
@ -139,6 +166,8 @@ typedef struct _SequentialFlashJournal_t {
*/
typedef char AssertSequentialJournalSizeLessThanOrEqualToGenericJournal[sizeof(SequentialFlashJournal_t)<=sizeof(FlashJournal_t)?1:-1];
#define SLOT_ADDRESS(JOURNAL, INDEX) ((JOURNAL)->mtdStartOffset + (JOURNAL)->firstSlotOffset + ((INDEX) * (JOURNAL)->sizeofSlot))
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@ -24,12 +24,118 @@ extern "C" {
#include "flash-journal/flash_journal.h"
/**
* Create/format a sequential flash journal at a given offset within a storage
* device and with a given slot-cardinality.
*
* This function must be called *once* for each incarnation of a sequential
* journal.
*
* @param[in] mtd
* The underlying Storage driver.
*
* @param[in] numSlots
* Number of slots in the sequential journal. Each slot holds a header, blob-payload, and a tail.
*
* @param[in] callback
* Caller-defined callback to be invoked upon command completion
* in case the storage device executes operations asynchronously.
* Use a NULL pointer when no callback signals are required.
*
* @note: this is an asynchronous operation, but it can finish
* synchronously if the underlying MTD supports that.
*
* @return
* The function executes in the following ways:
* - When the operation is asynchronous, the function only starts the
* initialization and control returns to the caller with an
* JOURNAL_STATUS_OK before the actual completion of the operation (or with
* an appropriate error code in case of failure). When the operation is
* completed the command callback is invoked with 1 passed in as the
* 'status' parameter of the callback. In case of errors, the completion
* callback is invoked with an error status.
* - When the operation is executed by the journal in a blocking (i.e.
* synchronous) manner, control returns to the caller only upon the actual
* completion of the operation or the discovery of a failure condition. In
* this case, the function returns 1 to signal successful synchronous
* completion or an appropriate error code, and no further
* invocation of the completion callback should be expected at a later time.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
* int32_t returnValue = flashJournalStrategySequential_format(MTD, numSlots, callbackHandler);
* if (returnValue < JOURNAL_STATUS_OK) {
* // handle error
* } else if (returnValue == JOURNAL_STATUS_OK) {
* ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
* // handle early return from asynchronous execution
* } else {
* ASSERT(returnValue == 1);
* // handle synchronous completion
* }
* \endcode
*
* +-------------------------------+ ^
* | | |
* | Journal Header | |
* | starts with generic header | |
* | followed by specific header | |
* | | | multiple of program_unit
* +-------------------------------+ | and erase-boundary
* +-------------------------------+ |
* | | |
* | padding to allow alignment | |
* | | |
* +-------------------------------+ v
* +-------------------------------+
* | +---------------------------+ | ^
* | | slot header | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | | slot 0
* | | | aligned with LCM of all erase boundaries
* | | |
* | | |
* | | |
* | BLOB0 | |
* | | |
* | | |
* | +---------------------------+ | |
* | | slot tail | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | |
* +-------------------------------+ v
* +-------------------------------+
* | +---------------------------+ | ^
* | | slot header | | |
* | | aligned with program_unit| | |
* | +---------------------------+ | | slot 1
* | | | aligned with LCM of all erase boundaries
* | BLOB1 | |
* | | |
* . . .
* . . .
*
* . . .
* . BLOB(N-1) . .
* | | |
* | +---------------------------+ | | slot 'N - 1'
* | | slot tail | | | aligned with LCM of all erase boundaries
* | | aligned with program_unit| | |
* | +---------------------------+ | |
* +-------------------------------+ v
*/
int32_t flashJournalStrategySequential_format(ARM_DRIVER_STORAGE *mtd,
uint32_t numSlots,
FlashJournal_Callback_t callback);
int32_t flashJournalStrategySequential_initialize(FlashJournal_t *journal,
ARM_DRIVER_STORAGE *mtd,
const FlashJournal_Ops_t *ops,
FlashJournal_Callback_t callback);
FlashJournal_Status_t flashJournalStrategySequential_getInfo(FlashJournal_t *journal, FlashJournal_Info_t *info);
int32_t flashJournalStrategySequential_read(FlashJournal_t *journal, void *blob, size_t n);
int32_t flashJournalStrategySequential_readFrom(FlashJournal_t *journal, size_t offset, void *blob, size_t n);
int32_t flashJournalStrategySequential_log(FlashJournal_t *journal, const void *blob, size_t n);
int32_t flashJournalStrategySequential_commit(FlashJournal_t *journal);
int32_t flashJournalStrategySequential_reset(FlashJournal_t *journal);
@ -38,6 +144,7 @@ static const FlashJournal_Ops_t FLASH_JOURNAL_STRATEGY_SEQUENTIAL = {
flashJournalStrategySequential_initialize,
flashJournalStrategySequential_getInfo,
flashJournalStrategySequential_read,
flashJournalStrategySequential_readFrom,
flashJournalStrategySequential_log,
flashJournalStrategySequential_commit,
flashJournalStrategySequential_reset

View File

@ -15,6 +15,7 @@
* limitations under the License.
*/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#include "flash-journal-strategy-sequential/flash_journal_private.h"
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
#include "support_funcs.h"
@ -23,82 +24,101 @@
SequentialFlashJournal_t *activeJournal;
/* forward declarations */
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
/*
* forward declarations of static-inline helper functions.
*/
static inline int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP);
static inline int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots);
static inline int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
static inline int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob);
static inline int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal);
static inline int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP)
int32_t flashJournalStrategySequential_format(ARM_DRIVER_STORAGE *mtd,
uint32_t numSlots,
FlashJournal_Callback_t callback)
{
/* fetch MTD's INFO */
int32_t rc;
if ((rc = flashJournalStrategySequential_format_sanityChecks(mtd, numSlots)) != JOURNAL_STATUS_OK) {
return rc;
}
ARM_STORAGE_INFO mtdInfo;
int32_t rc = mtd->GetInfo(&mtdInfo);
if (rc != ARM_DRIVER_OK) {
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t mtdAddr;
if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
*capacityP = mtdInfo.total_storage;
return JOURNAL_STATUS_OK;
formatInfoSingleton.mtd = mtd;
formatInfoSingleton.mtdAddr = mtdAddr;
formatInfoSingleton.callback = callback;
formatInfoSingleton.mtdProgramUnit = mtdInfo.program_unit;
if ((rc = setupSequentialJournalHeader(&formatInfoSingleton.header, mtd, mtdInfo.total_storage, numSlots)) != JOURNAL_STATUS_OK) {
return rc;
}
/* initialize MTD */
rc = mtd->Initialize(formatHandler);
if (rc < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
if (rc != 1) {
return JOURNAL_STATUS_STORAGE_API_ERROR; /* synchronous completion is expected to return 1 */
}
/* progress the rest of the create state-machine */
return flashJournalStrategySequential_format_progress(ARM_DRIVER_OK, ARM_STORAGE_OPERATION_INITIALIZE);
}
static inline int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
/**
* Validate a header at the start of the MTD.
*
* @param [in/out] headerP
* Caller-allocated header which gets filled in during validation.
* @return JOURNAL_STATUS_OK if the header is sane. As a side-effect, the memory
* pointed to by 'headerP' is initialized with the header.
*/
int32_t readAndVerifyJournalHeader(SequentialFlashJournal_t *journal, SequentialFlashJournalHeader_t *headerP)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
if (headerP == NULL) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if (journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
// printf("read sanity checks: totalDataRead = %lu, sizeofJournaledBlob = %lu\n", (uint32_t)journal->read.totalDataRead, (uint32_t)journal->info.sizeofJournaledBlob);
if ((journal->info.sizeofJournaledBlob == 0) || (journal->read.totalDataRead == journal->info.sizeofJournaledBlob)) {
journal->read.totalDataRead = 0;
return JOURNAL_STATUS_EMPTY;
int32_t rc = journal->mtd->ReadData(journal->mtdStartOffset, headerP, sizeof(SequentialFlashJournalHeader_t));
if (rc < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
} else if (rc == ARM_DRIVER_OK) {
ARM_STORAGE_CAPABILITIES mtdCaps = journal->mtd->GetCapabilities();
if (!mtdCaps.asynchronous_ops) {
return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
}
return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
}
return JOURNAL_STATUS_OK;
}
static inline int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if ((journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) && (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
if (sizeofBlob > journal->info.capacity) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
} else if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->log.offset + sizeofBlob > journal->log.tailOffset) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
if ((headerP->genericHeader.magic != FLASH_JOURNAL_HEADER_MAGIC) ||
(headerP->genericHeader.version != FLASH_JOURNAL_HEADER_VERSION) ||
(headerP->genericHeader.sizeofHeader != sizeof(SequentialFlashJournalHeader_t)) ||
(headerP->magic != SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC) ||
(headerP->version != SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION)) {
return JOURNAL_STATUS_NOT_FORMATTED;
}
return JOURNAL_STATUS_OK;
}
static inline int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal)
{
if (journal == NULL) {
return JOURNAL_STATUS_PARAMETER;
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
return JOURNAL_STATUS_ERROR;
}
if ((journal->log.offset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.tailOffset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.tailOffset < journal->log.offset) ||
(journal->log.tail.sizeofBlob == 0) ||
(journal->log.tail.sizeofBlob > journal->info.capacity)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
uint32_t expectedCRC = headerP->genericHeader.checksum;
headerP->genericHeader.checksum = 0;
flashJournalCrcReset();
uint32_t computedCRC = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
if (computedCRC != expectedCRC) {
//printf("readAndVerifyJournalHeader: checksum mismatch during header verification: expected = %u, computed = %u\n", (unsigned int) expectedCRC, (unsigned int) computedCRC);
return JOURNAL_STATUS_METADATA_ERROR;
}
return JOURNAL_STATUS_OK;
@ -111,9 +131,30 @@ int32_t flashJournalStrategySequential_initialize(FlashJournal_t *_jou
{
int32_t rc;
/* initialize MTD */
rc = mtd->Initialize(mtdHandler);
if (rc < ARM_DRIVER_OK) {
memset(_journal, 0, sizeof(FlashJournal_t));
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (rc == ARM_DRIVER_OK) {
ARM_STORAGE_CAPABILITIES mtdCaps = mtd->GetCapabilities();
if (!mtdCaps.asynchronous_ops) {
return JOURNAL_STATUS_ERROR; /* asynchronous_ops must be set if MTD returns ARM_DRIVER_OK. */
}
return JOURNAL_STATUS_ERROR; /* TODO: handle init with pending asynchronous activity. */
}
SequentialFlashJournal_t *journal;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
journal->state = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
journal->state = SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED;
journal->mtd = mtd;
/* Setup start address within MTD. */
if ((rc = mtdGetStartAddr(journal->mtd, &journal->mtdStartOffset)) != JOURNAL_STATUS_OK) {
return rc;
}
/* fetch MTD's total capacity */
uint64_t mtdCapacity;
@ -125,27 +166,27 @@ int32_t flashJournalStrategySequential_initialize(FlashJournal_t *_jou
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
SequentialFlashJournalHeader_t journalHeader;
if ((rc = readAndVerifyJournalHeader(journal, &journalHeader)) != JOURNAL_STATUS_OK) {
return rc;
}
/* initialize the journal structure */
memcpy(&journal->ops, ops, sizeof(FlashJournal_Ops_t));
journal->mtd = mtd;
journal->mtdCapabilities = mtd->GetCapabilities(); /* fetch MTD's capabilities */
journal->sequentialSkip = mtdCapacity / SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
journal->info.capacity = journal->sequentialSkip - (sizeof(SequentialFlashJournalLogHead_t) + sizeof(SequentialFlashJournalLogTail_t)); /* effective capacity */
journal->firstSlotOffset = journalHeader.genericHeader.journalOffset;
journal->numSlots = journalHeader.numSlots;
journal->sizeofSlot = journalHeader.sizeofSlot;
/* effective capacity */
journal->info.capacity = journal->sizeofSlot
- roundUp_uint32(sizeof(SequentialFlashJournalLogHead_t), mtdInfo.program_unit)
- roundUp_uint32(sizeof(SequentialFlashJournalLogTail_t), mtdInfo.program_unit);
journal->info.program_unit = mtdInfo.program_unit;
journal->callback = callback;
journal->prevCommand = FLASH_JOURNAL_OPCODE_INITIALIZE;
/* initialize MTD */
ARM_STORAGE_CAPABILITIES mtdCaps = mtd->GetCapabilities();
rc = mtd->Initialize(mtdHandler);
if (rc < ARM_DRIVER_OK) {
memset(journal, 0, sizeof(FlashJournal_t));
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if ((mtdCaps.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
}
if ((rc = discoverLatestLoggedBlob(journal)) != JOURNAL_STATUS_OK) {
return rc;
}
@ -167,6 +208,10 @@ int32_t flashJournalStrategySequential_read(FlashJournal_t *_journal, void *blob
SequentialFlashJournal_t *journal;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_READ_BLOB) {
journal->read.logicalOffset = 0;
}
int32_t rc;
if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
return rc;
@ -175,18 +220,53 @@ int32_t flashJournalStrategySequential_read(FlashJournal_t *_journal, void *blob
journal->read.blob = blob;
journal->read.sizeofBlob = sizeofBlob;
if ((journal->prevCommand != FLASH_JOURNAL_OPCODE_READ_BLOB) || (journal->read.totalDataRead == 0)) {
journal->read.offset = journal->mtdStartOffset
+ (journal->currentBlobIndex * journal->sequentialSkip)
+ sizeof(SequentialFlashJournalLogHead_t);
journal->read.totalDataRead = 0;
if (journal->read.logicalOffset == 0) {
{ /* Establish the sanity of this slot before proceeding with the read. */
uint32_t headSequenceNumber;
SequentialFlashJournalLogTail_t tail;
if (slotIsSane(journal,
SLOT_ADDRESS(journal, journal->currentBlobIndex),
&headSequenceNumber,
&tail) != 1) {
/* TODO: rollback to an older slot. */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
}
journal->read.mtdOffset = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t);
} else {
/* journal->read.offset is already set from the previous read execution */
// printf("flashJournalStrategySequential_read: continuing read of %lu from offset %lu\n", sizeofBlob, (uint32_t)journal->read.offset);
}
journal->read.dataBeingRead = blob;
journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.totalDataRead) < sizeofBlob) ?
(journal->info.sizeofJournaledBlob - journal->read.totalDataRead) : sizeofBlob;
journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
(journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
// printf("amount left to read %u\n", journal->read.amountLeftToRead);
journal->state = SEQUENTIAL_JOURNAL_STATE_READING;
journal->prevCommand = FLASH_JOURNAL_OPCODE_READ_BLOB;
return flashJournalStrategySequential_read_progress();
}
int32_t flashJournalStrategySequential_readFrom(FlashJournal_t *_journal, size_t offset, void *blob, size_t sizeofBlob)
{
SequentialFlashJournal_t *journal;
activeJournal = journal = (SequentialFlashJournal_t *)_journal;
journal->read.logicalOffset = offset;
int32_t rc;
if ((rc = flashJournalStrategySequential_read_sanityChecks(journal, blob, sizeofBlob)) != JOURNAL_STATUS_OK) {
return rc;
}
journal->read.blob = blob;
journal->read.sizeofBlob = sizeofBlob;
journal->read.mtdOffset = SLOT_ADDRESS(journal, journal->currentBlobIndex) + sizeof(SequentialFlashJournalLogHead_t) + offset;
journal->read.dataBeingRead = blob;
journal->read.amountLeftToRead = ((journal->info.sizeofJournaledBlob - journal->read.logicalOffset) < sizeofBlob) ?
(journal->info.sizeofJournaledBlob - journal->read.logicalOffset) : sizeofBlob;
// printf("amount left to read %u\n", journal->read.amountLeftToRead);
journal->state = SEQUENTIAL_JOURNAL_STATE_READING;
@ -208,24 +288,27 @@ int32_t flashJournalStrategySequential_log(FlashJournal_t *_journal, const void
journal->log.sizeofBlob = size;
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
/*
* This is the first log in the sequence. We have to begin by identifying a new slot and erasing it.
*/
/* choose the next slot */
uint32_t logBlobIndex = journal->currentBlobIndex + 1;
if (logBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
if (logBlobIndex == journal->numSlots) {
logBlobIndex = 0;
}
journal->log.eraseOffset = journal->mtdStartOffset + (logBlobIndex * journal->sequentialSkip);
/* ensure that the request is at least as large as the minimum program unit */
if (size < journal->info.program_unit) {
return JOURNAL_STATUS_SMALL_LOG_REQUEST;
}
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE; /* start with erasing the log region */
journal->prevCommand = FLASH_JOURNAL_OPCODE_LOG_BLOB;
/* setup an erase for the slot */
journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE; /* start with erasing the log region */
journal->prevCommand = FLASH_JOURNAL_OPCODE_LOG_BLOB;
} else {
/* This is a continuation of an ongoing logging sequence. */
journal->log.dataBeingLogged = blob;
journal->log.amountLeftToLog = size;
}
/* progress the state machine for log() */
return flashJournalStrategySequential_log_progress();
}
@ -240,17 +323,21 @@ int32_t flashJournalStrategySequential_commit(FlashJournal_t *_journal)
}
if (journal->prevCommand == FLASH_JOURNAL_OPCODE_LOG_BLOB) {
journal->log.offset = journal->log.tailOffset;
/* the tail has already been setup during previous calls to log(); we can now include it in the crc32. */
journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
journal->log.mtdOffset = journal->log.mtdTailOffset;
journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
} else {
uint32_t logBlobIndex = journal->currentBlobIndex + 1;
if (logBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
if (logBlobIndex == journal->numSlots) {
logBlobIndex = 0;
}
journal->log.eraseOffset = journal->mtdStartOffset + (logBlobIndex * journal->sequentialSkip);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE;
journal->log.mtdEraseOffset = SLOT_ADDRESS(journal, logBlobIndex);
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE;
}
journal->prevCommand = FLASH_JOURNAL_OPCODE_COMMIT;
@ -267,3 +354,124 @@ int32_t flashJournalStrategySequential_reset(FlashJournal_t *_journal)
journal->prevCommand = FLASH_JOURNAL_OPCODE_RESET;
return flashJournalStrategySequential_reset_progress();
}
int32_t mtdGetTotalCapacity(ARM_DRIVER_STORAGE *mtd, uint64_t *capacityP)
{
/* fetch MTD's INFO */
ARM_STORAGE_INFO mtdInfo;
int32_t rc = mtd->GetInfo(&mtdInfo);
if (rc != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
*capacityP = mtdInfo.total_storage;
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_format_sanityChecks(ARM_DRIVER_STORAGE *mtd, uint32_t numSlots)
{
/*
* basic parameter checking
*/
if ((mtd == NULL) || (numSlots == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
ARM_STORAGE_INFO mtdInfo;
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (mtdInfo.total_storage == 0) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t mtdAddr;
if (mtdGetStartAddr(mtd, &mtdAddr) < JOURNAL_STATUS_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if (mtd->GetBlock(mtdAddr, NULL) < ARM_DRIVER_OK) { /* check validity of journal's start address */
return JOURNAL_STATUS_PARAMETER;
}
if (mtd->GetBlock(mtdAddr + mtdInfo.total_storage - 1, NULL) < ARM_DRIVER_OK) { /* check validity of the journal's end address */
return JOURNAL_STATUS_PARAMETER;
}
if ((mtdAddr % mtdInfo.program_unit) != 0) { /* ensure that the journal starts at a programmable unit */
return JOURNAL_STATUS_PARAMETER;
}
if ((mtdAddr % LCM_OF_ALL_ERASE_UNITS) != 0) { /* ensure that the journal starts and ends at an erase-boundary */
return JOURNAL_STATUS_PARAMETER;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_read_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if (journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
// printf("read sanity checks: logicalOffset = %lu, sizeofJournaledBlob = %lu\n", (uint32_t)journal->read.logicalOffset, (uint32_t)journal->info.sizeofJournaledBlob);
if ((journal->info.sizeofJournaledBlob == 0) || (journal->read.logicalOffset >= journal->info.sizeofJournaledBlob)) {
journal->read.logicalOffset = 0;
return JOURNAL_STATUS_EMPTY;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_log_sanityChecks(SequentialFlashJournal_t *journal, const void *blob, size_t sizeofBlob)
{
if ((journal == NULL) || (blob == NULL) || (sizeofBlob == 0)) {
return JOURNAL_STATUS_PARAMETER;
}
if ((journal->state == SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED) || (journal->state == SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS)) {
return JOURNAL_STATUS_NOT_INITIALIZED;
}
if ((journal->state != SEQUENTIAL_JOURNAL_STATE_INITIALIZED) && (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) {
if (sizeofBlob > journal->info.capacity) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
} else if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->log.mtdOffset + sizeofBlob > journal->log.mtdTailOffset) {
return JOURNAL_STATUS_BOUNDED_CAPACITY; /* adding this log chunk would cause us to exceed capacity (write past the tail). */
}
}
/* ensure that the request is at least as large as the minimum program unit */
if (sizeofBlob < journal->info.program_unit) {
return JOURNAL_STATUS_SMALL_LOG_REQUEST;
}
return JOURNAL_STATUS_OK;
}
int32_t flashJournalStrategySequential_commit_sanityChecks(SequentialFlashJournal_t *journal)
{
if (journal == NULL) {
return JOURNAL_STATUS_PARAMETER;
}
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
if (journal->prevCommand != FLASH_JOURNAL_OPCODE_LOG_BLOB) {
return JOURNAL_STATUS_ERROR;
}
if ((journal->log.mtdOffset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.mtdTailOffset == ARM_STORAGE_INVALID_OFFSET) ||
(journal->log.mtdTailOffset < journal->log.mtdOffset) ||
(journal->log.tail.sizeofBlob == 0) ||
(journal->log.tail.sizeofBlob > journal->info.capacity)) {
return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */
}
}
return JOURNAL_STATUS_OK;
}

View File

@ -15,12 +15,15 @@
* limitations under the License.
*/
#include "flash-journal-strategy-sequential/flash_journal_crc.h"
#include "support_funcs.h"
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
static inline int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
struct FormatInfo_t formatInfoSingleton;
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP)
{
ARM_STORAGE_BLOCK mtdBlock;
if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) {
@ -34,130 +37,295 @@ static inline int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAd
return JOURNAL_STATUS_OK;
}
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
/**
* Check the sanity of a given slot
* @param journal
* @param slotOffset
* @param [out] headSequenceNumberP
* sequence number of the slot as read from the header.
* @param [out] tailP
* the tail of the slot
* @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
*/
int32_t slotIsSane(SequentialFlashJournal_t *journal,
uint64_t slotOffset,
uint32_t *headSequenceNumberP,
SequentialFlashJournalLogTail_t *tailP)
{
int32_t rc;
ARM_DRIVER_STORAGE *mtd = journal->mtd;
SequentialFlashJournalLogHead_t head;
/* TODO: add support for asynchronous read */
if (((rc = mtd->ReadData(slotOffset, &head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogHead_t))) {
if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
return JOURNAL_STATUS_UNSUPPORTED;
}
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
/* compute the CRC32 of the header */
flashJournalCrcReset();
flashJournalCrcCummulative((const unsigned char *)&head, sizeof(SequentialFlashJournalLogHead_t));
// printf("head->version: %lu\n", journal->initScan.head.version);
// printf("head->magic: %lx\n", journal->initScan.head.magic);
// printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
// printf("head->reserved: %lu\n", journal->initScan.head.reserved);
if (SEQUENTIAL_JOURNAL_VALID_HEAD(&head)) {
*headSequenceNumberP = head.sequenceNumber;
// printf("found valid header with sequenceNumber %" PRIu32 "\n", *headSequenceNumberP);
uint64_t tailoffset = slotOffset
- ((slotOffset - SLOT_ADDRESS(journal, 0)) % journal->sizeofSlot)
+ journal->sizeofSlot
- sizeof(SequentialFlashJournalLogTail_t);
// printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
/* TODO: add support for asynchronous read */
if (((rc = mtd->ReadData(tailoffset, tailP, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogTail_t))) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
if (SEQUENTIAL_JOURNAL_VALID_TAIL(tailP) && (tailP->sequenceNumber == *headSequenceNumberP)) {
// printf("found valid tail\n");
/* iterate over the body of the slot computing CRC */
#define CRC_CHUNK_SIZE 64
uint8_t crcBuffer[CRC_CHUNK_SIZE];
uint64_t bodyIndex = 0;
uint64_t bodyOffset = slotOffset + sizeof(SequentialFlashJournalLogHead_t);
while (bodyIndex < tailP->sizeofBlob) {
size_t sizeofReadOperation;
if ((tailP->sizeofBlob - bodyIndex) > CRC_CHUNK_SIZE) {
sizeofReadOperation = CRC_CHUNK_SIZE;
} else {
sizeofReadOperation = (tailP->sizeofBlob - bodyIndex);
}
/* TODO: add support for asynchronous read */
rc = mtd->ReadData(bodyOffset + bodyIndex, crcBuffer, sizeofReadOperation);
if (rc != (int32_t)sizeofReadOperation) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
bodyIndex += sizeofReadOperation;
flashJournalCrcCummulative(crcBuffer, sizeofReadOperation);
}
/* compute CRC32 over the tail */
/* extract existing CRC32 from the tail. The CRC32 field in the tail needs to contain 0 before CRC32 can be computed over it. */
uint32_t expectedCRC32 = tailP->crc32;
tailP->crc32 = 0;
uint32_t crc32 = flashJournalCrcCummulative((const unsigned char *)tailP, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
// printf("expectedCRC32: 0x%x, computedCRC32: 0x%x\n", expectedCRC32, crc32);
if (crc32 == expectedCRC32) {
return 1;
}
}
}
return JOURNAL_STATUS_ERROR;
}
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots)
{
ARM_STORAGE_INFO mtdInfo;
if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
headerP->genericHeader.magic = FLASH_JOURNAL_HEADER_MAGIC;
headerP->genericHeader.version = FLASH_JOURNAL_HEADER_VERSION;
headerP->genericHeader.sizeofHeader = sizeof(SequentialFlashJournalHeader_t);
/* Determine 'journalOffset'.
* Constraint: journal header should start and terminate at an erase-boundary
* (so that slot-0 can be erased independently), and also a program-unit boundary.
*/
headerP->genericHeader.journalOffset = roundUp_uint32(headerP->genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
if ((headerP->genericHeader.journalOffset % mtdInfo.program_unit) != 0) {
//printf("setupSequentialJournalHeader: journalOffset is not a multiple of MTD's program_unit\r\n");
return JOURNAL_STATUS_PARAMETER;
}
headerP->magic = SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC;
headerP->version = SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION;
headerP->numSlots = numSlots;
/* Determine 'sizeofSlot'.
* Constraint: slot-size should be a multiple of the erase-units of all involved storage blocks.
*/
uint64_t spaceAvailableForSlots = totalSize - headerP->genericHeader.journalOffset;
headerP->sizeofSlot = roundDown_uint32(spaceAvailableForSlots / numSlots, LCM_OF_ALL_ERASE_UNITS);
if (headerP->sizeofSlot == 0) {
//printf("setupSequentialJournalHeader: not enough space to create %" PRIu32 " slots\r\n", numSlots);
return JOURNAL_STATUS_PARAMETER;
}
headerP->genericHeader.totalSize = headerP->genericHeader.journalOffset + (headerP->sizeofSlot * numSlots);
//printf("setupSequentialJournalHeader: header size = %" PRIu32 ", journalOffset = %" PRIu32 ", sizeofSlot = %" PRIu32 ", totalSize = %lu\n", headerP->genericHeader.sizeofHeader, headerP->genericHeader.journalOffset, headerP->sizeofSlot, (uint32_t)headerP->genericHeader.totalSize);
/* compute checksum over the entire header */
headerP->genericHeader.checksum = 0;
flashJournalCrcReset();
headerP->genericHeader.checksum = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t));
return JOURNAL_STATUS_OK;
}
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal)
{
/* reset top level journal metadata prior to scanning headers. */
journal->nextSequenceNumber = SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER; /* we are currently unaware of previously written blobs */
journal->currentBlobIndex = SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
journal->currentBlobIndex = journal->numSlots;
journal->info.sizeofJournaledBlob = 0;
/* begin header-scan from the first block of the MTD */
ARM_DRIVER_STORAGE *mtd = journal->mtd;
if ((rc = mtdGetStartAddr(journal->mtd, &journal->mtdStartOffset)) != JOURNAL_STATUS_OK) {
return rc;
}
journal->initScan.currentOffset = journal->mtdStartOffset;
journal->state = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
journal->initScan.currentOffset = SLOT_ADDRESS(journal, 0);
journal->state = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS;
// printf("start of init scan\n");
// printf("discoverLatestLoggedBlob: start of init scan\n");
for (unsigned blobIndex = 0;
blobIndex < SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS;
blobIndex++, journal->initScan.currentOffset += journal->sequentialSkip) {
// printf("blob index %u\n", blobIndex);
blobIndex < journal->numSlots;
blobIndex++, journal->initScan.currentOffset += journal->sizeofSlot) {
// printf("discoverLatestLoggedBlob: blob index %u\n", blobIndex);
/* TODO: it is possible that the header structure spans multiple blocks, needing multiple reads. */
if (((rc = mtd->ReadData(journal->initScan.currentOffset, &journal->initScan.head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogHead_t))) {
/* TODO: add support for asynchronous scan */
if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) {
return JOURNAL_STATUS_UNSUPPORTED;
if (slotIsSane(journal,
journal->initScan.currentOffset,
&journal->initScan.headSequenceNumber,
&journal->initScan.tail) == 1) {
// printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
nextSequenceNumber = 0;
}
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
// printf("head->version: %lu\n", journal->initScan.head.version);
// printf("head->magic: %lx\n", journal->initScan.head.magic);
// printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber);
// printf("head->reserved: %lu\n", journal->initScan.head.reserved);
if (SEQUENTIAL_JOURNAL_VALID_HEAD(&journal->initScan.head)) {
journal->initScan.headSequenceNumber = journal->initScan.head.sequenceNumber;
// printf("found valid header with sequenceNumber %lu\n", journal->initScan.headSequenceNumber);
uint64_t tailoffset = journal->initScan.currentOffset
- ((journal->initScan.currentOffset - journal->mtdStartOffset) % journal->sequentialSkip)
+ journal->sequentialSkip
- sizeof(SequentialFlashJournalLogTail_t);
// printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset);
if (((rc = mtd->ReadData(tailoffset, &journal->initScan.tail, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) ||
(rc != sizeof(SequentialFlashJournalLogTail_t))) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
if (SEQUENTIAL_JOURNAL_VALID_TAIL(&journal->initScan.tail) &&
(journal->initScan.tail.sequenceNumber == journal->initScan.headSequenceNumber)) {
// printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber);
uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1;
if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
nextSequenceNumber = 0;
}
if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
/* We take advantage of properties of unsigned arithmetic in the following
* expression.
*
* We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
* instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
* to take wraparounds into account.
*/
((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
journal->currentBlobIndex = blobIndex;
journal->nextSequenceNumber = nextSequenceNumber;
journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
// printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
// journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
}
/* Have we found the best of the slots seen so far? */
if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) ||
/* We take advantage of properties of unsigned arithmetic in the following
* expression.
*
* We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber),
* instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0)
* to take wraparounds into account.
*/
((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) {
journal->currentBlobIndex = blobIndex;
journal->nextSequenceNumber = nextSequenceNumber;
journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob;
// printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n",
// journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber);
}
}
}
// printf("finished init scan\n");
// printf("discoverLatestLoggedBlob: finished init scan\n");
/* Handle the case where our scan hasn't yielded any results. */
if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) {
// printf("discoverLatestLoggedBlob: initializing to defaults\n");
journal->currentBlobIndex = (uint32_t)-1; /* to be incremented to 0 during the first attempt to log(). */
journal->nextSequenceNumber = 0;
/* setup info.current_program_unit */
ARM_STORAGE_BLOCK storageBlock;
if ((rc = journal->mtd->GetBlock(journal->mtdStartOffset, &storageBlock)) != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
}
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
return JOURNAL_STATUS_OK;
}
/**
* Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed)
{
int32_t rc;
size_t sizeofWrite = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit);
size_t sizeofErase = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS);
switch (operationWhichJustFinshed) {
case ARM_STORAGE_OPERATION_INITIALIZE:
if (status != ARM_DRIVER_OK) {
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
// printf("erasing %u bytes from offset %u\n", roundUp_uint32(header.genericHeader.sizeofHeader, mtdInfo.program_unit), mtdAddr);
rc = (formatInfoSingleton.mtd)->Erase(formatInfoSingleton.mtdAddr, sizeofErase);
if (rc < ARM_DRIVER_OK) {
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
/* handle synchronous completion of programData */
status = rc;
/* intentional fall-through */
case ARM_STORAGE_OPERATION_ERASE:
if (status != (int32_t)sizeofErase) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
// printf("calling ProgramData at address %u for %u bytes\n",
// formatInfoSingleton.mtdAddr, roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit));
rc = (formatInfoSingleton.mtd)->ProgramData(formatInfoSingleton.mtdAddr, &(formatInfoSingleton.header), sizeofWrite);
if (rc < ARM_DRIVER_OK) {
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
} else if (rc == ARM_DRIVER_OK) {
return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback
* where the rest of processing will take place. */
}
/* handle synchronous completion of programData */
status = rc;
/* intentional fall-through */
case ARM_STORAGE_OPERATION_PROGRAM_DATA:
if (status != (int32_t)sizeofWrite) {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
return 1; /* acknowledge the completion of create */
default:
return JOURNAL_STATUS_STORAGE_API_ERROR; /* we don't expect to be here */
}
}
int32_t flashJournalStrategySequential_reset_progress(void)
{
int32_t rc;
SequentialFlashJournal_t *journal = activeJournal;
if (journal->mtdCapabilities.erase_all) {
if ((rc = journal->mtd->EraseAll()) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if ((rc = journal->mtd->Erase(SLOT_ADDRESS(journal, 0), journal->numSlots * journal->sizeofSlot)) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
}
/* else we fall through to handle synchronous completion */
} else {
if ((rc = journal->mtd->Erase(journal->mtdStartOffset, SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS * journal->sequentialSkip)) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
printf("eturning JOURNAL_STATUS_OK\n");
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
}
/* else we fall through to handle synchronous completion */
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
//printf("eturning JOURNAL_STATUS_OK\n");
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
}
/* else we fall through to handle synchronous completion */
journal->nextSequenceNumber = 0;
journal->currentBlobIndex = (uint32_t)-1;
@ -179,11 +347,11 @@ int32_t flashJournalStrategySequential_read_progress(void)
ARM_STORAGE_BLOCK storageBlock;
if ((journal->read.amountLeftToRead) &&
((rc = journal->mtd->GetBlock(journal->read.offset, &storageBlock)) != ARM_DRIVER_OK)) {
((rc = journal->mtd->GetBlock(journal->read.mtdOffset, &storageBlock)) != ARM_DRIVER_OK)) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.offset - storageBlock.addr);
uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.mtdOffset - storageBlock.addr);
while (journal->read.amountLeftToRead) {
while (!storageBlockAvailableCapacity) {
@ -191,7 +359,7 @@ int32_t flashJournalStrategySequential_read_progress(void)
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */
}
journal->read.offset = storageBlock.addr; /* This should not be necessary since we assume
journal->read.mtdOffset = storageBlock.addr; /* This should not be necessary since we assume
* storage map manages a contiguous address space. */
storageBlockAvailableCapacity = storageBlock.size;
}
@ -201,8 +369,8 @@ int32_t flashJournalStrategySequential_read_progress(void)
journal->read.amountLeftToRead : storageBlockAvailableCapacity;
/* perform the IO */
//printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.offset);
rc = journal->mtd->ReadData(journal->read.offset, journal->read.dataBeingRead, xfer);
//printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.mtdOffset);
rc = journal->mtd->ReadData(journal->read.mtdOffset, journal->read.dataBeingRead, xfer);
if (rc < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
@ -211,10 +379,10 @@ int32_t flashJournalStrategySequential_read_progress(void)
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
} else {
/* synchronous completion. 'rc' contains the actual number of bytes transferred. */
journal->read.offset += rc;
journal->read.mtdOffset += rc;
journal->read.amountLeftToRead -= rc;
journal->read.dataBeingRead += rc;
journal->read.totalDataRead += rc;
journal->read.logicalOffset += rc;
}
}
@ -222,6 +390,12 @@ int32_t flashJournalStrategySequential_read_progress(void)
return (journal->read.dataBeingRead - journal->read.blob);
}
/**
* Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_log_progress(void)
{
SequentialFlashJournal_t *journal = activeJournal;
@ -234,7 +408,7 @@ int32_t flashJournalStrategySequential_log_progress(void)
}
uint32_t blobIndexBeingLogged = journal->currentBlobIndex + 1;
if (blobIndexBeingLogged == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
if (blobIndexBeingLogged == journal->numSlots) {
blobIndexBeingLogged = 0;
}
@ -242,22 +416,24 @@ int32_t flashJournalStrategySequential_log_progress(void)
int32_t rc;
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) {
uint64_t amountLeftToErase = journal->mtdStartOffset
+ (blobIndexBeingLogged + 1) * journal->sequentialSkip
- journal->log.eraseOffset;
uint64_t amountLeftToErase = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - journal->log.mtdEraseOffset;
// printf("journal state: erasing; offset %lu [size %lu]\n",
// (uint32_t)journal->log.eraseOffset, (uint32_t)amountLeftToErase);
while (amountLeftToErase) {
if ((rc = journal->mtd->Erase(journal->log.eraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
if ((rc = journal->mtd->Erase(journal->log.mtdEraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_ERROR;
}
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
} else {
/* synchronous completion. */
journal->log.eraseOffset += rc;
amountLeftToErase -= rc;
journal->log.mtdEraseOffset += rc;
amountLeftToErase -= rc;
}
}
} else {
@ -273,11 +449,11 @@ int32_t flashJournalStrategySequential_log_progress(void)
}
/* check for alignment of next log offset with program_unit */
if ((rc = journal->mtd->GetBlock(journal->log.offset, &storageBlock)) != ARM_DRIVER_OK) {
if ((rc = journal->mtd->GetBlock(journal->log.mtdOffset, &storageBlock)) != ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_API_ERROR;
}
if ((journal->log.offset - storageBlock.addr) % journal->info.program_unit) {
if ((journal->log.mtdOffset - storageBlock.addr) % journal->info.program_unit) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_ERROR; /* Program offset doesn't align with info.program_unit. This would result in an IO error if attempted. */
}
@ -286,17 +462,21 @@ int32_t flashJournalStrategySequential_log_progress(void)
xfer -= xfer % journal->info.program_unit; /* align transfer-size with program_unit. */
/* perform the IO */
// printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.offset);
rc = journal->mtd->ProgramData(journal->log.offset, journal->log.dataBeingLogged, xfer);
// printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.mtdOffset);
rc = journal->mtd->ProgramData(journal->log.mtdOffset, journal->log.dataBeingLogged, xfer);
if (rc < ARM_DRIVER_OK) {
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
return JOURNAL_STATUS_STORAGE_IO_ERROR;
if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
return JOURNAL_STATUS_STORAGE_IO_ERROR;
}
}
if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) {
return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */
} else {
/* synchronous completion. 'rc' contains the actual number of bytes transferred. */
journal->log.offset += rc;
journal->log.mtdOffset += rc;
journal->log.amountLeftToLog -= rc;
journal->log.dataBeingLogged += rc;
if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
@ -312,7 +492,7 @@ int32_t flashJournalStrategySequential_log_progress(void)
switch (journal->state) {
case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE:
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD;
journal->log.offset = journal->mtdStartOffset + blobIndexBeingLogged * journal->sequentialSkip;
journal->log.mtdOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged);
journal->log.head.version = SEQUENTIAL_FLASH_JOURNAL_VERSION;
journal->log.head.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
journal->log.head.sequenceNumber = journal->nextSequenceNumber;
@ -322,23 +502,32 @@ int32_t flashJournalStrategySequential_log_progress(void)
// printf("newstate: program HEAD; amount to log %u\n", journal->log.amountLeftToLog);
break;
case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* switch to writing the body */
case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* we've finished writing the head */
/* compute CRC32 on the header */
flashJournalCrcReset();
flashJournalCrcCummulative((const unsigned char *)&journal->log.head, sizeof(SequentialFlashJournalLogHead_t));
/* switch to writing the body */
/* Prepare for the tail to be written out at a later time.
* This will only be done once Commit() is called. */
journal->log.tailOffset = journal->mtdStartOffset
+ (blobIndexBeingLogged + 1) * journal->sequentialSkip
- sizeof(SequentialFlashJournalLogTail_t);
journal->log.mtdTailOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - sizeof(SequentialFlashJournalLogTail_t);
journal->log.tail.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC;
journal->log.tail.sequenceNumber = journal->nextSequenceNumber;
journal->log.tail.sizeofBlob = 0; /* we'll update this as we complete our writes. */
journal->log.tail.crc32 = 0;
if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) {
/* This branch is taken only when commit() is called without any preceding log() operations. */
journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t));
flashJournalCrcReset();
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL;
journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail;
journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t);
journal->log.offset = journal->log.tailOffset;
// printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.offset);
journal->log.mtdOffset = journal->log.mtdTailOffset;
// printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.mtdOffset);
} else {
journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY;
journal->log.dataBeingLogged = journal->log.blob;
@ -352,15 +541,19 @@ int32_t flashJournalStrategySequential_log_progress(void)
if (journal->log.dataBeingLogged == journal->log.blob) {
return JOURNAL_STATUS_SMALL_LOG_REQUEST;
} else {
return (journal->log.dataBeingLogged - journal->log.blob);
uint32_t amountOfDataLogged = (journal->log.dataBeingLogged - journal->log.blob);
flashJournalCrcCummulative(journal->log.blob, amountOfDataLogged); /* compute CRC32 on logged data */
return amountOfDataLogged;
}
case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL:
// printf("crc32 of slot: 0x%x\n", journal->log.tail.crc32);
journal->info.sizeofJournaledBlob = journal->log.tail.sizeofBlob;
journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state to allow further operations */
++journal->currentBlobIndex;
if (journal->currentBlobIndex == SEQUENTIAL_FLASH_JOURNAL_MAX_LOGGED_BLOBS) {
if (journal->currentBlobIndex == journal->numSlots) {
journal->currentBlobIndex = 0;
}
// printf("currentBlobIndex: %lu\n", journal->currentBlobIndex);
@ -381,24 +574,48 @@ int32_t flashJournalStrategySequential_log_progress(void)
}
}
void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation)
{
if (status < ARM_DRIVER_OK) {
if (formatInfoSingleton.callback) {
formatInfoSingleton.callback(status, FLASH_JOURNAL_OPCODE_FORMAT);
}
return;
}
int32_t rc = flashJournalStrategySequential_format_progress(status, operation);
if (rc != JOURNAL_STATUS_OK) {
if (formatInfoSingleton.callback) {
formatInfoSingleton.callback(rc, FLASH_JOURNAL_OPCODE_FORMAT);
}
}
}
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
{
int32_t rc;
if (status < ARM_DRIVER_OK) {
printf("mtdHandler: received error status %" PRId32 "\n", status);
/* Map integrity failures reported by the Storage driver appropriately. */
if (status == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) {
status = JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE;
} else {
status = JOURNAL_STATUS_STORAGE_IO_ERROR;
}
// printf("journal mtdHandler: received error status %ld\n", status);
switch (activeJournal->state) {
case SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED:
case SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS:
if (activeJournal->callback) {
activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_INITIALIZE);
activeJournal->callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE);
}
break;
case SEQUENTIAL_JOURNAL_STATE_RESETING:
activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
if (activeJournal->callback) {
activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_RESET);
activeJournal->callback(status, FLASH_JOURNAL_OPCODE_RESET);
}
break;
@ -411,7 +628,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
if (activeJournal->callback) {
activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB);
activeJournal->callback(status, FLASH_JOURNAL_OPCODE_LOG_BLOB);
}
break;
case SEQUENTIAL_JOURNAL_STATE_READING:
@ -419,7 +636,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED;
if (activeJournal->callback) {
activeJournal->callback(JOURNAL_STATUS_STORAGE_IO_ERROR, FLASH_JOURNAL_OPCODE_READ_BLOB);
activeJournal->callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
}
break;
}
@ -455,7 +672,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
return;
}
activeJournal->log.eraseOffset += status;
activeJournal->log.mtdEraseOffset += status;
if ((rc = flashJournalStrategySequential_log_progress()) != JOURNAL_STATUS_OK) {
activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */
@ -476,9 +693,9 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
break;
case ARM_STORAGE_OPERATION_PROGRAM_DATA:
// printf("PROGRAM_DATA: received status of %ld\n", status);
// printf("journal mtdHandler: PROGRAM_DATA: received status of %ld\n", status);
rc = status;
activeJournal->log.offset += rc;
activeJournal->log.mtdOffset += rc;
activeJournal->log.amountLeftToLog -= rc;
activeJournal->log.dataBeingLogged += rc;
if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) {
@ -504,7 +721,7 @@ void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation)
break;
default:
printf("mtdHandler: unknown operation %u\n", operation);
//printf("mtdHandler: unknown operation %u\n", operation);
break;
}
}

View File

@ -21,12 +21,58 @@
#include "flash-journal-strategy-sequential/flash_journal_private.h"
#include "flash-journal-strategy-sequential/flash_journal_strategy_sequential.h"
/* The following singleton captures the state of the format machine. Format is
* handled differently because it executes even before a journal exists (or a
* Journal_t can be initialized. */
extern struct FormatInfo_t {
ARM_DRIVER_STORAGE *mtd;
SequentialFlashJournalHeader_t header;
FlashJournal_Callback_t callback;
uint64_t mtdAddr;
uint32_t mtdProgramUnit;
} formatInfoSingleton;
extern SequentialFlashJournal_t *activeJournal;
/**
* Check the sanity of a given slot
* @param journal
* @param slotOffset
* @param [out] headSequenceNumberP
* sequence number of the slot as read from the header.
* @param [out] tailP
* the tail of the slot
* @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees.
*/
int32_t slotIsSane(SequentialFlashJournal_t *journal,
uint64_t slotOffset,
uint32_t *headSequenceNumberP,
SequentialFlashJournalLogTail_t *tailP);
int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP);
int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots);
int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal);
/**
* Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed);
/**
* Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler.
* @return < JOURNAL_STATUS_OK for error
* = JOURNAL_STATUS_OK to signal pending asynchronous activity
* > JOURNAL_STATUS_OK for completion
*/
int32_t flashJournalStrategySequential_log_progress(void);
int32_t flashJournalStrategySequential_reset_progress(void);
int32_t flashJournalStrategySequential_read_progress(void);
int32_t flashJournalStrategySequential_log_progress(void);
void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation);
void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation);
#endif /*__FLASH_JOURNAL_SEQUENTIAL_STRATEGY_SUPPORT_FUNCTIONS_H__*/

View File

@ -23,7 +23,6 @@ extern "C" {
#endif // __cplusplus
#include "storage_abstraction/Driver_Storage.h"
#include <stdint.h>
/**
* General return codes. All Flash-Journal APIs return an int32_t to allow for
@ -44,6 +43,9 @@ typedef enum _FlashJournal_Status
JOURNAL_STATUS_NOT_INITIALIZED = -9, ///< journal not initialized
JOURNAL_STATUS_EMPTY = -10, ///< There is no further data to read
JOURNAL_STATUS_SMALL_LOG_REQUEST = -11, ///< log request is smaller than the program_unit of the underlying MTD block.
JOURNAL_STATUS_NOT_FORMATTED = -12, ///< need to call xxx_format() before using the journal.
JOURNAL_STATUS_METADATA_ERROR = -13, ///< sanity checks for the journal metadata failed.
JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE = -14, ///< validation or run-time errors arising from the badkend media.
} FlashJournal_Status_t;
/**
@ -51,6 +53,7 @@ typedef enum _FlashJournal_Status
* completing commands. Refer to \ref ARM_Flash_Callback_t.
*/
typedef enum _FlashJournal_OpCode {
FLASH_JOURNAL_OPCODE_FORMAT,
FLASH_JOURNAL_OPCODE_INITIALIZE,
FLASH_JOURNAL_OPCODE_GET_INFO,
FLASH_JOURNAL_OPCODE_READ_BLOB,
@ -76,6 +79,29 @@ typedef struct _FlashJournal_Info {
///< the requested amount).
} FlashJournal_Info_t;
static const uint32_t FLASH_JOURNAL_HEADER_MAGIC = 0xA00AEE1DUL;
static const uint32_t FLASH_JOURNAL_HEADER_VERSION = 1;
/**
* Meta-data placed at the head of a Journal. The actual header would be an
* extension of this generic header, and would depend on the implementation
* strategy. Initialization algorithms can expect to find this generic header at
* the start of every Journal.
*/
typedef struct _FlashJournalHeader {
uint32_t magic; /** Journal-header specific magic code */
uint32_t version; /** Revision number for this generic journal header. */
uint64_t totalSize; /** Total space (in bytes) occupied by the journal, including the header.
* Both 'mtdOffset' and 'mtdOffset + totalSize' should
* lie on erase boundaries. */
uint32_t sizeofHeader; /** The size of the journal header; this is expected to be larger than this generic header. */
uint32_t journalOffset; /** Offset from the start of the journal header to the actual logged journal. */
uint32_t checksum; /** CRC32 over the entire flash-journal-header, including the implementation
* specific extension (i.e. over 'sizeofHeader' bytes). The value of the
* field is taken to be 0 for the purpose of computing the checksum. */
} FlashJournalHeader_t;
/**
* This is the type of the command completion callback handler for the
* asynchronous flash-journal APIs: initialize(), read(), log(), commit() and
@ -95,8 +121,7 @@ typedef struct _FlashJournal_Info {
typedef void (*FlashJournal_Callback_t)(int32_t status, FlashJournal_OpCode_t cmd_code);
/* forward declarations. */
typedef struct _FlashJournal_t FlashJournal_t;
typedef struct _FlashJournal_Ops_t FlashJournal_Ops_t;
struct FlashJournal_t;
/**
* @ref FlashJournal_t is an abstraction implemented by a table of generic
@ -111,44 +136,53 @@ typedef struct _FlashJournal_Ops_t FlashJournal_Ops_t;
* strategy-specific metadata. The value of this MAX_SIZE may need to be
* increased if some future journal-strategy needs more metadata.
*/
#define FLASH_JOURNAL_HANDLE_MAX_SIZE 140
#define FLASH_JOURNAL_HANDLE_MAX_SIZE 160
/**
* This is the set of operations offered by the flash-journal abstraction. A set
* of implementations for these operations defines a logging strategy.
*/
typedef struct _FlashJournal_Ops_t {
typedef struct FlashJournal_Ops_t {
/**
* \brief Initialize the flash journal. Refer to @ref FlashJournal_initialize.
*/
int32_t (*initialize)(FlashJournal_t *journal, ARM_DRIVER_STORAGE *mtd, const FlashJournal_Ops_t *ops, FlashJournal_Callback_t callback);
int32_t (*initialize)(struct FlashJournal_t *journal,
ARM_DRIVER_STORAGE *mtd,
const struct FlashJournal_Ops_t *ops,
FlashJournal_Callback_t callback);
/**
* \brief fetch journal metadata. Refer to @ref FlashJournal_getInfo.
*/
FlashJournal_Status_t (*getInfo) (FlashJournal_t *journal, FlashJournal_Info_t *info);
FlashJournal_Status_t (*getInfo) (struct FlashJournal_t *journal, FlashJournal_Info_t *info);
/**
* @brief Read from the most recently logged blob. Refer to @ref FlashJournal_read.
*/
int32_t (*read) (FlashJournal_t *journal, void *buffer, size_t size);
int32_t (*read) (struct FlashJournal_t *journal, void *buffer, size_t size);
/**
* @brief Read from the most recently logged blob from a particular offset. Refer to @ref FlashJournal_readFrom.
*/
int32_t (*readFrom) (struct FlashJournal_t *journal, size_t offset, void *buffer, size_t size);
/**
* @brief Start logging a new blob or append to the one currently being logged. Refer to @ref FlashJournal_log.
*/
int32_t (*log) (FlashJournal_t *journal, const void *blob, size_t size);
int32_t (*log) (struct FlashJournal_t *journal, const void *blob, size_t size);
/**
* @brief commit a blob accumulated through a non-empty sequence of
* previously successful log() operations. Refer to @ref FlashJournal_commit.
*/
int32_t (*commit) (FlashJournal_t *journal);
int32_t (*commit) (struct FlashJournal_t *journal);
/**
* @brief Reset the journal. This has the effect of erasing all valid blobs.
* Refer to @ref FlashJournal_reset.
*/
int32_t (*reset) (FlashJournal_t *journal);
int32_t (*reset) (struct FlashJournal_t *journal);
} FlashJournal_Ops_t;
/**
@ -167,7 +201,7 @@ typedef struct _FlashJournal_Ops_t {
* @note: there is a risk of overallocation in case an implementation doesn't
* need FLASH_JOURNAL_HANDLE_MAX_SIZE bytes, but the impact should be small.
*/
typedef struct _FlashJournal_t {
typedef struct FlashJournal_t {
FlashJournal_Ops_t ops;
union {
@ -224,7 +258,7 @@ typedef struct _FlashJournal_t {
* JOURNAL_STATUS_OK before the actual completion of the operation (or
* with an appropriate error code in case of failure). When the
* operation is completed the command callback is invoked with
* JOURNAL_STATUS_OK passed in as the 'status' parameter of the
* 1 passed in as the 'status' parameter of the
* callback. In case of errors, the completion callback is invoked with
* an error status.
* - When the operation is executed by the journal in a blocking (i.e.
@ -234,6 +268,11 @@ typedef struct _FlashJournal_t {
* completion or an appropriate error code, and no further
* invocation of the completion callback should be expected at a later time.
*
* @note The user must call an appropriate xxx_format() to format underlying
* storage before initializing it for use. If Initialize() is called on
* unformatted storage, an error value of JOURNAL_STATUS_NOT_FORMATTED will be
* returned.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
@ -377,6 +416,88 @@ static inline int32_t FlashJournal_read(FlashJournal_t *journal, void *blob, siz
return journal->ops.read(journal, blob, n);
}
/**
* @brief Read from the most recently logged blob at a given offset. A front-end
* for @ref FlashJournal_Ops_t::readFrom().
*
* @details Read off a chunk of the logged blob from a given offset. The journal
* maintains a read-pointer internally to allow reads to continue where the
* previous one left off. This call effectively sets the read-counter before
* fetching data. Subsequent reads continue sequentially from where the
* readFrom() left off.
*
* @note: If the given offset stands at (or is beyond) the end of the previously
* logged blob, readFrom() returns the error JOURNAL_STATUS_EMPTY (or passes
* that value as the status of a completion callback) and resets the read-
* pointer to allow re-reading the blob from the start.
*
* @param [in] journal
* A previously initialized journal.
*
* @param [in] offset
* The logical offset (within the blob) at which to read data from.
*
* @param [out] buffer
* The destination of the read operation. The memory is owned
* by the caller and should remain valid for the lifetime
* of this operation.
*
* @param [in] size
* The maximum amount of data which can be read in this
* operation. The memory pointed to by 'buffer' should be as
* large as this amount.
*
* @return
* The function executes in the following ways:
* - When the operation is asynchronous--i.e. when the underlying MTD's
* ARM_STOR_CAPABILITIES::asynchronous_ops is set to 1--and the operation
* executed by the journal in a non-blocking (i.e. asynchronous) manner,
* control returns to the caller with JOURNAL_STATUS_OK before the actual
* completion of the operation (or with an appropriate error code in case of
* failure). When the operation completes, the command callback is
* invoked with the number of successfully transferred bytes passed in as
* the 'status' parameter of the callback. If any error is encountered
* after the launch of an asynchronous operation, the completion callback
* is invoked with an error status.
* - When the operation is executed by the journal in a blocking (i.e.
* synchronous) manner, control returns to the caller only upon the
* actual completion of the operation, or the discovery of a failure
* condition. In synchronous mode, the function returns the number
* of data items read or an appropriate error code.
*
* @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
* is set then this operation may execute asynchronously. In the case of
* asynchronous operation, the invocation returns early (with
* JOURNAL_STATUS_OK) and results in a completion callback later.
*
* @note If the underlying MTD's ARM_STORAGE_CAPABILITIES::asynchronous_ops
* is set, the journal is not required to operate asynchronously. A Read
* operation can be finished synchronously in spite of
* ARM_STORAGE_CAPABILITIES::asynchronous_ops being set, returning the
* number of data items read to indicate successful completion, or an
* appropriate error code. In this case no further invocation of a
* completion callback should be expected at a later time.
*
* Here's a code snippet to suggest how this API might be used by callers:
* \code
* ASSERT(JOURNAL_STATUS_OK == 0); // this is a precondition; it doesn't need to be put in code
* int32_t returnValue = FlashJournal_readFrom(&journal, offset, buffer, size);
* if (returnValue < JOURNAL_STATUS_OK) {
* // handle error
* } else if (returnValue == JOURNAL_STATUS_OK) {
* ASSERT(MTD->GetCapabilities().asynchronous_ops == 1);
* // handle early return from asynchronous execution
* } else {
* ASSERT(returnValue == size);
* // handle synchronous completion
* }
* \endcode
*/
static inline int32_t FlashJournal_readFrom(struct FlashJournal_t *journal, size_t offset, void *blob, size_t n)
{
return journal->ops.readFrom(journal, offset, blob, n);
}
/**
* @brief Start logging a new blob or append to the one currently being logged.
* A front-end for @ref FlashJournal_Ops_t::log().

View File

@ -0,0 +1,252 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "storage-volume-manager/storage_volume_manager.h"
#include <string.h>
#include <inttypes.h>
/* redefine tr_debug() to a printf() equivalent to emit trace */
#define tr_debug(...)
void StorageVolume::setup(uint64_t _addr, uint64_t _size, StorageVolumeManager *_volumeManager)
{
volumeOffset = _addr;
volumeSize = _size;
volumeManager = _volumeManager;
allocated = true;
}
ARM_DRIVER_VERSION StorageVolume::GetVersion(void)
{
ARM_DRIVER_VERSION bad_ver = {0, 0};
if (!allocated) {
return bad_ver;
}
return volumeManager->getStorage()->GetVersion();
}
ARM_STORAGE_CAPABILITIES StorageVolume::GetCapabilities(void)
{
ARM_STORAGE_CAPABILITIES bad_cap;
if (!allocated) {
memset(&bad_cap, 0, sizeof(ARM_STORAGE_CAPABILITIES));
return bad_cap;
}
return volumeManager->getStorage()->GetCapabilities();
}
int32_t StorageVolume::Initialize(ARM_Storage_Callback_t _callback)
{
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
callback = _callback; /* nothing else to do since we've already initialized the storage */
return 1; /* synchronous completion. */
}
int32_t StorageVolume::Uninitialize(void)
{
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
return 1; /* synchronous completion. */
}
int32_t StorageVolume::PowerControl(ARM_POWER_STATE state)
{
tr_debug("called powerControl(%u)", state);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->PowerControl(state);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::ReadData(uint64_t addr, void *data, uint32_t size)
{
tr_debug("called ReadData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->ReadData(volumeOffset + addr, data, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::ProgramData(uint64_t addr, const void *data, uint32_t size)
{
tr_debug("called ProgramData(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->ProgramData(volumeOffset + addr, data, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::Erase(uint64_t addr, uint32_t size)
{
tr_debug("called erase(%" PRIu32 ", %" PRIu32 ")", (uint32_t)addr, size);
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
if ((size > volumeSize) || ((addr + size) > volumeSize)) {
return ARM_DRIVER_ERROR_PARAMETER;
}
volumeManager->activeVolume = this;
int32_t rc = volumeManager->getStorage()->Erase(volumeOffset + addr, size);
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
int32_t StorageVolume::EraseAll(void)
{
tr_debug("called eraseAll");
if (!allocated) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED;
}
if (volumeManager->activeVolume != NULL) {
return ARM_DRIVER_ERROR_BUSY;
}
int32_t rc;
/* Allow EraseAll() only if the volume spans the entire storage. */
{
ARM_STORAGE_INFO info;
rc = volumeManager->getStorage()->GetInfo(&info);
if (rc != ARM_DRIVER_OK) {
return ARM_DRIVER_ERROR;
}
if ((volumeOffset != 0) || (volumeSize != info.total_storage)) {
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
}
volumeManager->activeVolume = this;
rc = volumeManager->getStorage()->EraseAll();
if (rc != ARM_DRIVER_OK) {
volumeManager->activeVolume = NULL; /* we're certain that there is no more pending asynch. activity */
}
return rc;
}
ARM_STORAGE_STATUS StorageVolume::GetStatus(void)
{
const uint32_t busy = ((volumeManager->activeVolume != NULL) ? (uint32_t)1 : (uint32_t)0);
ARM_STORAGE_STATUS status = {0, 0};
status.busy = busy;
return status;
}
int32_t StorageVolume::GetInfo(ARM_STORAGE_INFO *infoP)
{
int32_t rc;
rc = volumeManager->getStorage()->GetInfo(infoP);
if (rc != ARM_DRIVER_OK) {
return ARM_DRIVER_ERROR;
}
infoP->total_storage = volumeSize;
return ARM_DRIVER_OK;
}
uint32_t StorageVolume::ResolveAddress(uint64_t addr) {
return (uint32_t)(volumeOffset + addr);
}
int32_t StorageVolume::GetNextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP)
{
int32_t rc;
ARM_STORAGE_BLOCK tmpBlock;
do {
/* iterate forward */
rc = volumeManager->getStorage()->GetNextBlock(prevP, &tmpBlock);
if (rc != ARM_DRIVER_OK) {
return rc;
}
/* Stop iteration if we have progressed past the boundary of this volume. */
if (tmpBlock.addr >= (volumeOffset + volumeSize)) {
return ARM_DRIVER_ERROR;
}
} while (!this->overlapsWithBlock(&tmpBlock));
if (nextP) {
memcpy(nextP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
transformBlockToVolume(nextP);
}
return ARM_DRIVER_OK;
}
int32_t StorageVolume::GetBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP)
{
ARM_STORAGE_BLOCK tmpBlock;
int32_t rc = volumeManager->getStorage()->GetBlock(ResolveAddress(addr), &tmpBlock);
if (rc != ARM_DRIVER_OK) {
return rc;
}
if (!this->overlapsWithBlock(&tmpBlock)) {
return ARM_DRIVER_ERROR;
}
if (blockP) {
memcpy(blockP, &tmpBlock, sizeof(ARM_STORAGE_BLOCK));
transformBlockToVolume(blockP);
}
return ARM_DRIVER_OK;
}

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "storage-volume-manager/storage_volume_manager.h"
#include <string.h>
#include <inttypes.h>
/* redefine these macros to a printf() equivalent to emit trace */
#define tr_debug(...)
#define tr_error(...)
/*
* The following variable records the volume-manager instance which last setup
* StorageVolumeManager::storageCallback() as a callback for a storage driver.
* We use this value in the callback handler to de-multiplex the callback into a
* volume-manager.
*/
static StorageVolumeManager *activeVolumeManager;
InitializeCallback_t initializeCallback;
#define STORAGE_API_DEFINITIONS_FOR_VOLUME(N) \
extern "C" ARM_DRIVER_VERSION GetVersion_ ## N(void) { \
return activeVolumeManager->volumes[(N)].GetVersion(); \
} \
ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void) { \
return activeVolumeManager->volumes[(N)].GetCapabilities(); \
} \
int32_t Initialize_ ## N(ARM_Storage_Callback_t callback) { \
return activeVolumeManager->volumes[(N)].Initialize(callback); \
} \
int32_t Uninitialize_ ## N(void) { \
return activeVolumeManager->volumes[(N)].Uninitialize(); \
} \
int32_t PowerControl_ ## N(ARM_POWER_STATE state) { \
return activeVolumeManager->volumes[(N)].PowerControl(state); \
} \
int32_t ReadData_ ## N(uint64_t addr, void *data, uint32_t size) { \
return activeVolumeManager->volumes[(N)].ReadData(addr, data, size); \
} \
int32_t ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size) { \
return activeVolumeManager->volumes[(N)].ProgramData(addr, data, size); \
} \
int32_t Erase_ ## N(uint64_t addr, uint32_t size) { \
return activeVolumeManager->volumes[(N)].Erase(addr, size); \
} \
int32_t EraseAll_ ## N(void) { \
return activeVolumeManager->volumes[(N)].EraseAll(); \
} \
ARM_STORAGE_STATUS GetStatus_ ## N(void) { \
return activeVolumeManager->volumes[(N)].GetStatus(); \
} \
int32_t GetInfo_ ## N(ARM_STORAGE_INFO *infoP) { \
return activeVolumeManager->volumes[(N)].GetInfo(infoP); \
} \
uint32_t ResolveAddress_ ## N(uint64_t addr) { \
return activeVolumeManager->volumes[(N)].ResolveAddress(addr); \
} \
int32_t GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP) { \
return activeVolumeManager->volumes[(N)].GetNextBlock(prevP, nextP); \
} \
int32_t GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP) { \
return activeVolumeManager->volumes[(N)].GetBlock(addr, blockP); \
} \
ARM_DRIVER_STORAGE VIRTUAL_MTD_ ## N = { \
.GetVersion = GetVersion_ ## N, \
.GetCapabilities = GetCapabilities_ ## N, \
.Initialize = Initialize_ ## N, \
.Uninitialize = Uninitialize_ ## N, \
.PowerControl = PowerControl_ ## N, \
.ReadData = ReadData_ ## N, \
.ProgramData = ProgramData_ ## N, \
.Erase = Erase_ ## N, \
.EraseAll = EraseAll_ ## N, \
.GetStatus = GetStatus_ ## N, \
.GetInfo = GetInfo_ ## N, \
.ResolveAddress = ResolveAddress_ ## N, \
.GetNextBlock = GetNextBlock_ ## N, \
.GetBlock = GetBlock_ ## N, \
};
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_1 STORAGE_API_DEFINITIONS_FOR_VOLUME(0)
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_2 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_1 STORAGE_API_DEFINITIONS_FOR_VOLUME(1)
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_3 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_2 STORAGE_API_DEFINITIONS_FOR_VOLUME(2)
#define STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_4 STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_3 STORAGE_API_DEFINITIONS_FOR_VOLUME(3)
/* ... add more of the above if ever needed */
#define STORAGE_API_DEFINITIONS_FOR_VOLUMES(N) EXPAND(CONCATENATE(STORAGE_API_DEFINITIONS_LIST_FOR_VOLUME_, N))
STORAGE_API_DEFINITIONS_FOR_VOLUMES(MAX_VOLUMES);
int32_t StorageVolumeManager::initialize(ARM_DRIVER_STORAGE *mtd, InitializeCallback_t callback)
{
activeVolume = NULL;
initializeCallback = callback;
storage = mtd;
storageCapabilities = mtd->GetCapabilities();
int32_t rc = mtd->GetInfo(&storageInfo);
if (rc != ARM_DRIVER_OK) {
tr_error("StorageVolumeManager::initialize: call to GetInfo() failed with %" PRId32, rc);
return ARM_DRIVER_ERROR;
}
rc = mtd->Initialize(storageCallback);
if (rc < ARM_DRIVER_OK) {
tr_error("Initialize() failed with error %" PRId32, rc);
return ARM_DRIVER_ERROR;
}
activeVolumeManager = this;
if (rc == ARM_DRIVER_OK) {
/* there is pending asynchronous activity which will result in a callback later */
return ARM_DRIVER_OK;
}
/* Clear previously allocated volumes */
for (size_t i = 0; i < MAX_VOLUMES; i++) {
if (volumes[i].isAllocated()) {
volumes[i].deallocate();
}
}
/* synchronous completion */
initialized = true;
return 1;
}
int32_t StorageVolumeManager::addVolume(uint64_t addr, uint64_t size, StorageVolume **volumePP)
{
tr_debug("StorageVolumeManager_addVolume: addr = %" PRIu32 ", size = %" PRIu32, (uint32_t)addr, (uint32_t)size);
*volumePP = NULL;
/*
* sanity checks for arguments
*/
ARM_STORAGE_INFO info;
int32_t rc;
rc = storage->GetInfo(&info);
if (rc != ARM_DRIVER_OK) {
tr_error("StorageVolumeManager_addVolume: storage->GetInfo() failed with %" PRId32, rc);
return ARM_DRIVER_ERROR;
}
if (size > info.total_storage) {
tr_error("StorageVolumeManager_addVolume: 'size' parameter too large: %" PRIu32, (uint32_t)size);
return ARM_DRIVER_ERROR;
}
ARM_STORAGE_BLOCK firstBlock;
rc = storage->GetNextBlock(NULL, &firstBlock);
if (rc != ARM_DRIVER_OK) {
tr_error("StorageVolumeManager_addVolume: storage->GetNextBlock() failed with %" PRId32, rc);
return ARM_DRIVER_ERROR;
}
if ((addr < firstBlock.addr) || ((addr + size) > (firstBlock.addr + info.total_storage))) {
tr_error("StorageVolumeManager_addVolume: given range [%" PRIu32 ", %" PRIu32 ") isn't entirely contained within available storage range [%" PRIu32 ", %" PRIu32 ")",
(uint32_t)addr, (uint32_t)(addr + size), (uint32_t)firstBlock.addr, (uint32_t)(firstBlock.addr + info.total_storage));
return ARM_DRIVER_ERROR;
}
/* Find an unused volume. */
uint32_t index = findIndexOfUnusedVolume();
if (index == MAX_VOLUMES) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES;
}
/* setup volume */
StorageVolume *volumeP = &volumes[index];
volumeP->setup(addr, size, this);
*volumePP = volumeP;
tr_debug("StorageVolumeManager_addVolume: setup volume at index %" PRIu32, index);
return ARM_DRIVER_OK;
}
int32_t StorageVolumeManager::addVolume_C(uint64_t addr, uint64_t size, _ARM_DRIVER_STORAGE *mtd)
{
int32_t rc;
StorageVolume *volumeP;
if ((rc = addVolume(addr, size, &volumeP)) < ARM_DRIVER_OK) {
return rc;
}
/* locate index of the allocated volume */
size_t index;
for (index = 0; index < MAX_VOLUMES; index++) {
if (volumes[index].isAllocated() && (&volumes[index] == volumeP)) {
break;
}
}
if (index == MAX_VOLUMES) {
return STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES;
}
if (index == 0) {
*mtd = VIRTUAL_MTD_0;
} else if (index == 1) {
*mtd = VIRTUAL_MTD_1;
} else if (index == 2) {
*mtd = VIRTUAL_MTD_2;
} else if (index == 3) {
*mtd = VIRTUAL_MTD_3;
} else {
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
int32_t StorageVolumeManager::lookupVolume(uint64_t addr, StorageVolume **volumePP)
{
/*
* Traverse the volumes in reverse order of creation; this allows newly created volumes to supersede the older ones.
*/
for (size_t index = MAX_VOLUMES - 1; index > 0; --index) {
StorageVolume *volume = &volumes[index];
if ((addr >= volume->getVolumeOffset()) && (addr < (volume->getVolumeOffset() + volume->getVolumeSize()))) {
*volumePP = volume;
return ARM_DRIVER_OK;
}
}
return ARM_DRIVER_ERROR;
}
void StorageVolumeManager::storageCallback(int32_t status, ARM_STORAGE_OPERATION operation)
{
tr_debug("StorageVolumeManager_callback: operation = %u", operation);
StorageVolumeManager *volumeManager = activeVolumeManager;
switch (operation) {
case ARM_STORAGE_OPERATION_INITIALIZE:
volumeManager->initialized = true;
if (initializeCallback != NULL) {
initializeCallback(status);
}
break;
case ARM_STORAGE_OPERATION_POWER_CONTROL:
case ARM_STORAGE_OPERATION_READ_DATA:
case ARM_STORAGE_OPERATION_PROGRAM_DATA:
case ARM_STORAGE_OPERATION_ERASE:
case ARM_STORAGE_OPERATION_ERASE_ALL:
if (volumeManager->activeVolume != NULL) {
/* Reset activeVolume and invoke callback. We reset activeVolume before the
* callback because the callback may attempt to launch another asynchronous
* operation, which requires 'activeVolume' to be NULL. */
StorageVolume *callbackVolume = volumeManager->activeVolume; /* remember the volume which will receive the callback. */
volumeManager->activeVolume = NULL;
if (callbackVolume->isAllocated() && callbackVolume->getCallback()) {
(callbackVolume->getCallback())(status, operation);
}
}
break;
default:
tr_error("StorageVolumeManager_callback: unknown operation %u", operation);
break;
}
}
size_t StorageVolumeManager::findIndexOfUnusedVolume(void) const {
size_t index;
for (index = 0; index < MAX_VOLUMES; index++) {
if (!volumes[index].isAllocated()) {
break;
}
}
return index;
}

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __STORAGE_VOLUME_MANAGER_H__
#define __STORAGE_VOLUME_MANAGER_H__
#ifndef __cplusplus
#error "This abstraction requires a C++ toolchain"
#endif // __cplusplus
#include "storage_abstraction/Driver_Storage.h"
#if !defined(YOTTA_CFG_STORAGE_VOLUME_MANAGER_MAX_VOLUMES)
#define MAX_VOLUMES 4
#else
#define MAX_VOLUMES YOTTA_CFG_STORAGE_VOLUME_MANAGER_MAX_VOLUMES
#endif
/**<
* A static assert to ensure that the size of SequentialJournal is smaller than
* FlashJournal_t. The caller will only allocate a FlashJournal_t and expect the
* Sequential Strategy to reuse that space for a SequentialFlashJournal_t.
*/
#ifndef TOOLCHAIN_IAR
typedef char AssertStorageVolumeManagerMaxVolumesIsSane[(((MAX_VOLUMES) > 0) && ((MAX_VOLUMES) <= 8)) ? 0:-1];
#endif
#define CONCATENATE(A, B) A ## B
#define EXPAND(X) X /* this adds a level of indirection needed to allow macro-expansion following a token-paste operation (see use of CONCATENATE() below). */
#define STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(N) \
extern "C" ARM_DRIVER_VERSION GetVersion_ ## N(void); \
extern "C" ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void); \
extern "C" int32_t Initialize_ ## N(ARM_Storage_Callback_t callback); \
extern "C" int32_t Uninitialize_ ## N(void); \
extern "C" int32_t PowerControl_ ## N(ARM_POWER_STATE state); \
extern "C" int32_t ReadData_ ## N(uint64_t addr, void *data, uint32_t size); \
extern "C" int32_t ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size); \
extern "C" int32_t Erase_ ## N(uint64_t addr, uint32_t size); \
extern "C" int32_t EraseAll_ ## N(void); \
extern "C" ARM_STORAGE_STATUS GetStatus_ ## N(void); \
extern "C" int32_t GetInfo_ ## N(ARM_STORAGE_INFO *infoP); \
extern "C" uint32_t ResolveAddress_ ## N(uint64_t addr); \
extern "C" int32_t GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP); \
extern "C" int32_t GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_1 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(0)
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_2 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_1 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(1)
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_3 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_2 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(2)
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_4 STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_3 STORAGE_API_EXTERN_C_DECLARATIONS_FOR_VOLUME(3)
/* ... add more of the above if ever needed */
#define STORAGE_API_EXTERN_C_DECLARATIONS_LIST(N) EXPAND(CONCATENATE(STORAGE_API_EXTERN_C_DECLARATIONS_LIST_FOR_, N))
STORAGE_API_EXTERN_C_DECLARATIONS_LIST(MAX_VOLUMES);
/**
* Error return codes specific to the Storage volume manager. These extend the
* common error codes from ARM_DRIVER_STORAGE. All Volume-manager APIs return an
* int32_t to allow for both error and success status returns. This enumeration
* contains all possible error status values.
*/
typedef enum _StorageVolumeManager_Status
{
STORAGE_VOLUME_MANAGER_STATUS_ERROR_EXHASTED_VOLUMES = -7, ///< exhausted the supply of available volumes
STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_ERASABLE = -8, ///< Part (or all) of the range provided to Erase() isn't erasable.
STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_PROGRAMMABLE = -9, ///< Part (or all) of the range provided to ProgramData() isn't programmable.
STORAGE_VOLUME_MANAGER_STATUS_ERROR_PROTECTED = -10, ///< Part (or all) of the range to Erase() or ProgramData() is protected.
STORAGE_VOLUME_MANAGER_STATUS_ERROR_NOT_INITIALIZED = -11, ///< underlying storage not initialized
STORAGE_VOLUME_MANAGER_STATUS_ERROR_VOLUME_NOT_ALLOCATED = -12, ///< attempt to operate on an unallocated volume
} StorageVolumeManager_Status_t;
typedef void (*InitializeCallback_t)(int32_t status);
class StorageVolumeManager; /* forward declaration */
class StorageVolume {
public:
StorageVolume() : allocated(false) { /* empty */ }
public:
void setup(uint64_t addr, uint64_t size, StorageVolumeManager *volumeManager);
/*
* Mimic the API of ARM_DRIVER_STORAGE
*/
public:
ARM_DRIVER_VERSION GetVersion(void);
ARM_STORAGE_CAPABILITIES GetCapabilities(void);
int32_t Initialize(ARM_Storage_Callback_t callback);
int32_t Uninitialize(void);
int32_t PowerControl(ARM_POWER_STATE state);
int32_t ReadData(uint64_t addr, void *data, uint32_t size);
int32_t ProgramData(uint64_t addr, const void *data, uint32_t size);
int32_t Erase(uint64_t addr, uint32_t size);
int32_t EraseAll(void);
ARM_STORAGE_STATUS GetStatus(void);
int32_t GetInfo(ARM_STORAGE_INFO *infoP);
uint32_t ResolveAddress(uint64_t addr);
int32_t GetNextBlock(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP);
int32_t GetBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
public:
bool isAllocated(void) const {
return allocated;
}
void deallocate(void) {
allocated = false;
}
/*
* Accessor methods.
*/
uint64_t getVolumeOffset(void) const {
return volumeOffset;
}
uint64_t getVolumeSize(void) const {
return volumeSize;
}
const ARM_Storage_Callback_t &getCallback(void) const {
return callback;
}
private:
bool overlapsWithBlock(const ARM_STORAGE_BLOCK* blockP) const {
return (((blockP->addr + blockP->size) <= volumeOffset) || ((volumeOffset + volumeSize) <= blockP->addr)) ? false : true;
}
void transformBlockToVolume(ARM_STORAGE_BLOCK *blockP) const {
if (blockP->addr < volumeOffset) {
blockP->addr = volumeOffset;
}
if ((blockP->addr + blockP->size) > (volumeOffset + volumeSize)) {
blockP->size = (volumeOffset + volumeSize) - blockP->addr;
}
blockP->addr -= volumeOffset;
}
private:
bool allocated;
uint64_t volumeOffset;
uint64_t volumeSize;
ARM_Storage_Callback_t callback;
StorageVolumeManager *volumeManager;
};
class StorageVolumeManager {
public:
StorageVolumeManager() { /* empty */ }
~StorageVolumeManager() { /* empty */ }
/**
* Initialize the storage MTD and prepare it for operation within the context of the volume manager.
*
* @param[in] storage
* The underlying MTD.
* @param[in] callback
* A callback to be invoked upon completion of initialization.
*
* @return If asynchronous activity is launched, an invocation returns
* ARM_DRIVER_OK, and the caller can expect to receive a
* callback in the future with a status value of ARM_DRIVER_OK or an error-
* code. In the case of synchronous execution, control returns after
* completion with a value of 1. Return values less than
* ARM_DRIVER_OK (0) signify errors.
*/
int32_t initialize(ARM_DRIVER_STORAGE *mtd, InitializeCallback_t callback);
int32_t addVolume(uint64_t addr, uint64_t size, StorageVolume **volumePP);
int32_t addVolume_C(uint64_t addr, uint64_t size, _ARM_DRIVER_STORAGE *mtd);
int32_t lookupVolume(uint64_t addr, StorageVolume **volumePP);
/*
* Accessor methods.
*/
bool isInitialized() const {
return initialized;
}
ARM_DRIVER_STORAGE *getStorage(void) const {
return storage;
}
const ARM_STORAGE_INFO &getStorageInfo(void) const {
return storageInfo;
}
const ARM_STORAGE_CAPABILITIES &getStorageCapabilities(void) const {
return storageCapabilities;
}
StorageVolume *volumeAtIndex(size_t index) {
return &volumes[index];
}
public:
static void storageCallback(int32_t status, ARM_STORAGE_OPERATION operation);
private:
friend int32_t StorageVolume::PowerControl(ARM_POWER_STATE state);
friend int32_t StorageVolume::ReadData(uint64_t addr, void *data, uint32_t size);
friend int32_t StorageVolume::ProgramData(uint64_t addr, const void *data, uint32_t size);
friend int32_t StorageVolume::Erase(uint64_t addr, uint32_t size);
friend int32_t StorageVolume::EraseAll(void);
friend ARM_STORAGE_STATUS StorageVolume::GetStatus(void);
StorageVolume *activeVolume; /* This state-variable is set to point to a volume
* while there is pending activity. It tracks
* the volume which is at the source of the
* activity. Once the activity finishes, this
* variable is reset. Having this variable set
* might be used as an indication that the
* underlying storage is busy. */
#define FRIEND_DECLARATIONS_FOR_VOLUME(N) \
friend ARM_DRIVER_VERSION GetVersion_ ## N(void); \
friend ARM_STORAGE_CAPABILITIES GetCapabilities_ ## N(void); \
friend int32_t Initialize_ ## N(ARM_Storage_Callback_t callback); \
friend int32_t Uninitialize_ ## N(void); \
friend int32_t PowerControl_ ## N(ARM_POWER_STATE state); \
friend int32_t ReadData_ ## N(uint64_t addr, void *data, uint32_t size); \
friend int32_t ProgramData_ ## N(uint64_t addr, const void *data, uint32_t size); \
friend int32_t Erase_ ## N(uint64_t addr, uint32_t size); \
friend int32_t EraseAll_ ## N(void); \
friend ARM_STORAGE_STATUS GetStatus_ ## N(void); \
friend int32_t GetInfo_ ## N(ARM_STORAGE_INFO *infoP); \
friend uint32_t ResolveAddress_ ## N(uint64_t addr); \
friend int32_t GetNextBlock_ ## N(const ARM_STORAGE_BLOCK* prevP, ARM_STORAGE_BLOCK *nextP); \
friend int32_t GetBlock_ ## N(uint64_t addr, ARM_STORAGE_BLOCK *blockP);
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_1 FRIEND_DECLARATIONS_FOR_VOLUME(0)
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_2 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_1 FRIEND_DECLARATIONS_FOR_VOLUME(1)
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_3 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_2 FRIEND_DECLARATIONS_FOR_VOLUME(2)
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_4 FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_3 FRIEND_DECLARATIONS_FOR_VOLUME(3)
/* ... add more of the above if ever needed */
#define FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(N) EXPAND(CONCATENATE(FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES_FOR_, N))
//todo: remove FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(MAX_VOLUMES);
FRIEND_DECLARATIONS_FOR_STORAGE_API_INSTANCES(MAX_VOLUMES)
private:
size_t findIndexOfUnusedVolume(void) const;
private:
bool initialized;
ARM_DRIVER_STORAGE *storage;
ARM_STORAGE_INFO storageInfo;
ARM_STORAGE_CAPABILITIES storageCapabilities;
StorageVolume volumes[MAX_VOLUMES];
};
#endif /* __STORAGE_VOLUME_MANAGER_H__ */

View File

@ -15,9 +15,7 @@
* limitations under the License.
*/
#if DEVICE_STORAGE
#include "Driver_Storage.h"
#include "storage_abstraction/Driver_Storage.h"
#include "cmsis_nvic.h"
#include "MK64F12.h"
@ -33,6 +31,10 @@
#include <string.h>
/* Redefine this macro to a printf equivalent to print trace */
#define tr_debug(...)
#ifdef USING_KSDK2
/*!
* @name Misc utility defines
@ -142,6 +144,76 @@ extern volatile uint32_t *const kFCCOBx;
#define SIZEOF_DOUBLE_PHRASE (16)
#endif /* #ifdef USING_KSDK2 */
/* While the K64F flash controller is capable of launching operations asynchronously and
* allowing program execution to continue while an erase/program is active, it
* doesn't allow simultaneous read accesses while and erase/program is active on
* the same block of flash.
*
* Read/fetch accesses can originate arbitrarily as a result of program
* execution. This means that code which operates on flash should not reside in
* flash; or at least it should not reside in the same bank of flash as it is
* operating upon. The only way to ensure that application code and flash driver
* are residing on separate banks of flash is to reserve bank-0 (or BLOCK0) for
* the application and bank-1 (BLOCK1) for the driver--this also happens to be
* the default setting.
*
* But it is quite likely that this default will be over-ridden by the use of
* config options depending upon the actual application. If we don't have a
* clean separation between the application and the space managed by this
* driver, then we need to enforce the following:
*
* - Force synchronous mode of execution in the storage_driver.
* - Disable interrupts during erase/program operations.
* - Ensure all code and data structures used in the storage driver execute
* out of RAM. Refer to __RAMFUNC (below) which allows for this.
*
* It is difficult to determine the application's span of internal-flash at
* compile time. Therefore we assume that STORAGE_START_ADDR is the
* boundary between application and this driver. When this boundary is set to
* lie at BLOCK1_START_ADDR, there is no possibility of read-while-write run-
* time errors.
*
* In the following, caps.asynchronous_ops is defined to be 1 if and only if
* asynchronous operation mode is requested and there doesn't exist the
* possibility of concurrent reads.
*/
#if (defined(STORAGE_START_ADDR) && (STORAGE_START_ADDR != BLOCK1_START_ADDR))
#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 1
#else
#define EXISTS_POSSIBILITY_OF_CONCURRENT_READ 0
#endif
/* Define '__RAMFUNC' as an attribute to mark a function as residing in RAM.
* Use of __RAMFUNC puts a function in the .data section--i.e. the
* initialized data section. This will be copied into RAM automatically by the
* startup sequence. */
#ifndef __RAMFUNC
#if defined(__GNUC__) || defined(__clang__) // GCC and llvm/clang
#define __RAMFUNC __attribute__ ((section (".data#"), noinline)) /* The '#' following ".data" needs a bit of
* explanation. Without it, we are liable to get the following warning 'Warning: ignoring
* changed section attributes for .data'. This is because __attribute__((section(".data")))
* generates the following assembly:
*
* .section .data,"ax",%progbits
*
* But .data doesn't need the 'x' (execute) attribute bit. To remove the warning, we specify
* the attribute with a '#' at the tail, which emits:
*
* .section .data#,"ax",%progbits
*
* Note that '#' (in the above) acts like a comment-start, and masks the additional
* attributes which don't apply to '.data'.
*/
#elif defined (__CC_ARM)
#define __RAMFUNC __attribute__ ((section(".ramfunc"), noinline))
#elif defined ( __ICCARM__ )
#define __RAMFUNC __ramfunc
#else // unknown compiler
#error "This compiler is not yet supported. If you can contribute support for defining a function to be RAM resident, please provide a definition for __RAMFUNC"
#endif
#endif /* #ifndef __RAMFUNC */
/*
* forward declarations
*/
@ -169,16 +241,16 @@ struct mtd_k64f_data {
static const ARM_STORAGE_BLOCK blockTable[] = {
{
/**< This is the start address of the flash block. */
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR
.addr = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR,
#ifdef STORAGE_START_ADDR
.addr = STORAGE_START_ADDR,
#else
.addr = BLOCK1_START_ADDR,
#endif
/**< This is the size of the flash block, in units of bytes.
* Together with addr, it describes a range [addr, addr+size). */
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
.size = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE,
#ifdef STORAGE_SIZE
.size = STORAGE_SIZE,
#else
.size = BLOCK1_SIZE,
#endif
@ -200,7 +272,8 @@ static const ARM_DRIVER_VERSION version = {
};
#if (!defined(DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS)
#if ((!defined(STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) || STORAGE_CONFIG_HARDWARE_MTD_K64F_ASYNC_OPS) && \
!EXISTS_POSSIBILITY_OF_CONCURRENT_READ)
#define ASYNC_OPS 1
#else
#define ASYNC_OPS 0
@ -219,8 +292,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
.asynchronous_ops = ASYNC_OPS,
/* Enable chip-erase functionality if we own all of block-1. */
#if ((!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_START_ADDR == BLOCK1_START_ADDR)) && \
(!defined (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE) || (DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE == BLOCK1_SIZE)))
#if ((!defined (STORAGE_START_ADDR) || (STORAGE_START_ADDR == BLOCK1_START_ADDR)) && \
(!defined (STORAGE_SIZE) || (STORAGE_SIZE == BLOCK1_SIZE)))
.erase_all = 1, /**< Supports EraseChip operation. */
#else
.erase_all = 0, /**< Supports EraseChip operation. */
@ -228,8 +301,8 @@ static const ARM_STORAGE_CAPABILITIES caps = {
};
static const ARM_STORAGE_INFO info = {
#ifdef DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE
.total_storage = DEVICE_STORAGE_CONFIG_HARDWARE_MTD_K64F_SIZE, /**< Total available storage, in units of octets. */
#ifdef STORAGE_SIZE
.total_storage = STORAGE_SIZE, /**< Total available storage, in units of octets. */
#else
.total_storage = BLOCK1_SIZE, /**< Total available storage, in units of octets. By default, BLOCK0 is reserved to hold program code. */
#endif
@ -410,6 +483,10 @@ static inline void launchCommand(void)
#else /* #if !ASYNC_OPS */
#if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
/* This function needs to execute from RAM to avoid read-while-write errors. */
__RAMFUNC
#endif
static void launchCommandAndWaitForCompletion()
{
// It contains the inlined equivalent of the following code snippet:
@ -418,10 +495,17 @@ static void launchCommandAndWaitForCompletion()
// /* Spin waiting for the command execution to complete. */
// }
#ifdef USING_KSDK2
FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; /* launchcommand() */
while ((FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK) == 0) {
/* Spin waiting for the command execution to complete. */
}
#else
BW_FTFE_FSTAT_CCIF(FTFE, 1); /* launchCommand() */
while (BR_FTFE_FSTAT_CCIF(FTFE) == 0) {
/* Spin waiting for the command execution to complete. */
}
#endif
}
#endif /* #if !ASYNC_OPS */
@ -562,6 +646,7 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
if ((context->amountLeftToOperate == PROGRAM_PHRASE_SIZEOF_INLINE_DATA) ||
((context->currentOperatingStorageAddress % SIZEOF_DOUBLE_PHRASE) == PROGRAM_PHRASE_SIZEOF_INLINE_DATA)) {
setup8ByteWrite(context->currentOperatingStorageAddress, context->currentOperatingData);
tr_debug("setupNextProgramData: W8, [%lu]", (uint32_t)context->currentOperatingStorageAddress);
context->amountLeftToOperate -= PROGRAM_PHRASE_SIZEOF_INLINE_DATA;
context->currentOperatingStorageAddress += PROGRAM_PHRASE_SIZEOF_INLINE_DATA;
@ -569,6 +654,7 @@ static inline void setupNextProgramData(struct mtd_k64f_data *context)
} else {
size_t amount = sizeofLargestProgramSection(context->currentOperatingStorageAddress, context->amountLeftToOperate);
setupProgramSection(context->currentOperatingStorageAddress, context->currentOperatingData, amount);
tr_debug("setupNextProgramData: W%u, [%lu]", amount, (uint32_t)context->currentOperatingStorageAddress);
context->amountLeftToOperate -= amount;
context->currentOperatingStorageAddress += amount;
@ -607,6 +693,8 @@ static inline void setupNextErase(struct mtd_k64f_data *context)
static int32_t executeCommand(struct mtd_k64f_data *context)
{
tr_debug("executeCommand: top");
#if ASYNC_OPS
/* Asynchronous operation */
(void)context; /* avoid compiler warning about un-used variables */
@ -624,12 +712,21 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
enableCommandCompletionInterrupt();
tr_debug("executeCommand: async. return");
return ARM_DRIVER_OK; /* signal asynchronous completion. An interrupt will signal completion later. */
#else /* #if ASYNC_OPS */
/* Synchronous operation. */
/* Synchronous operation. This is the common case. */
while (1) {
tr_debug("executeCommand: synchronous iteration");
#if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
__disable_irq();
#endif
launchCommandAndWaitForCompletion();
#if EXISTS_POSSIBILITY_OF_CONCURRENT_READ
__enable_irq();
#endif
/* Execution may result in failure. Check for errors */
if (failedWithAccessError() || failedWithProtectionError()) {
@ -664,6 +761,7 @@ static int32_t executeCommand(struct mtd_k64f_data *context)
break;
} else {
/* erase can be skipped since this sector is already erased. */
tr_debug("fast forward erase");
progressEraseContextByEraseUnit(context);
}
}
@ -691,6 +789,7 @@ static inline void launchCommandFromIRQ(const struct mtd_k64f_data *context)
if (failedWithAccessError() || failedWithProtectionError()) {
clearErrorStatusBits();
if (context->commandCompletionCallback) {
tr_debug("irq: invoking callback with error");
context->commandCompletionCallback(ARM_DRIVER_ERROR_PARAMETER, context->currentCommand);
}
return;
@ -726,6 +825,7 @@ static void ftfe_ccie_irq_handler(void)
case ARM_STORAGE_OPERATION_PROGRAM_DATA:
if (context->amountLeftToOperate == 0) {
if (context->commandCompletionCallback) {
tr_debug("irq: [PROGRAM] invoking callback");
context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_PROGRAM_DATA);
}
return;
@ -745,11 +845,13 @@ static void ftfe_ccie_irq_handler(void)
break;
} else {
/* erase can be skipped since this sector is already erased. */
tr_debug("fast forward erase");
progressEraseContextByEraseUnit(context);
}
}
if (context->amountLeftToOperate == 0) {
if (context->commandCompletionCallback) {
tr_debug("irq: [ERASE] invoking callback");
context->commandCompletionCallback(context->sizeofCurrentOperation, ARM_STORAGE_OPERATION_ERASE);
}
return;
@ -761,6 +863,7 @@ static void ftfe_ccie_irq_handler(void)
default:
if (context->commandCompletionCallback) {
tr_debug("irq: [default] invoking callback");
context->commandCompletionCallback(ARM_DRIVER_OK, context->currentCommand);
}
break;
@ -827,6 +930,8 @@ static ARM_STORAGE_CAPABILITIES getCapabilities(void)
static int32_t initialize(ARM_Storage_Callback_t callback)
{
tr_debug("called initialize(%p)", callback);
struct mtd_k64f_data *context = &mtd_k64f_data;
memset(context, 0, sizeof(mtd_k64f_data));
context->currentCommand = ARM_STORAGE_OPERATION_INITIALIZE;
@ -860,6 +965,8 @@ static int32_t initialize(ARM_Storage_Callback_t callback)
}
static int32_t uninitialize(void) {
tr_debug("called uninitialize");
struct mtd_k64f_data *context = &mtd_k64f_data;
context->currentCommand = ARM_STORAGE_OPERATION_UNINITIALIZE;
@ -883,6 +990,8 @@ static int32_t uninitialize(void) {
static int32_t powerControl(ARM_POWER_STATE state)
{
tr_debug("called powerControl(%u)", state);
struct mtd_k64f_data *context = &mtd_k64f_data;
context->currentCommand = ARM_STORAGE_OPERATION_POWER_CONTROL;
@ -892,6 +1001,8 @@ static int32_t powerControl(ARM_POWER_STATE state)
static int32_t readData(uint64_t addr, void *data, uint32_t size)
{
tr_debug("called ReadData(%lu, %lu)", (uint32_t)addr, size);
struct mtd_k64f_data *context = &mtd_k64f_data;
context->currentCommand = ARM_STORAGE_OPERATION_READ_DATA;
@ -914,6 +1025,8 @@ static int32_t readData(uint64_t addr, void *data, uint32_t size)
static int32_t programData(uint64_t addr, const void *data, uint32_t size)
{
tr_debug("called ProgramData(%lu, %lu)", (uint32_t)addr, size);
struct mtd_k64f_data *context = &mtd_k64f_data;
if (!context->initialized) {
return (int32_t)ARM_DRIVER_ERROR; /* illegal */
@ -955,6 +1068,8 @@ static int32_t programData(uint64_t addr, const void *data, uint32_t size)
static int32_t erase(uint64_t addr, uint32_t size)
{
tr_debug("called erase(%lu, %lu)", (uint32_t)addr, size);
struct mtd_k64f_data *context = &mtd_k64f_data;
if (!context->initialized) {
@ -995,6 +1110,8 @@ static int32_t erase(uint64_t addr, uint32_t size)
static int32_t eraseAll(void)
{
tr_debug("called eraseAll");
struct mtd_k64f_data *context = &mtd_k64f_data;
if (!context->initialized) {
@ -1105,7 +1222,7 @@ int32_t getBlock(uint64_t addr, ARM_STORAGE_BLOCK *blockP)
return ARM_DRIVER_ERROR;
}
ARM_DRIVER_STORAGE ARM_Driver_Storage_(0) = {
ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F = {
.GetVersion = getVersion,
.GetCapabilities = getCapabilities,
.Initialize = initialize,
@ -1121,5 +1238,3 @@ ARM_DRIVER_STORAGE ARM_Driver_Storage_(0) = {
.GetNextBlock = nextBlock,
.GetBlock = getBlock
};
#endif /* #if DEVICE_STORAGE */