Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
support_funcs.c
00001 /* 00002 * Copyright (c) 2006-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "flash-journal-strategy-sequential/flash_journal_crc.h" 00019 #include "support_funcs.h" 00020 #include <string.h> 00021 #include <stdio.h> 00022 #include <inttypes.h> 00023 00024 struct FormatInfo_t formatInfoSingleton; 00025 00026 int32_t mtdGetStartAddr(ARM_DRIVER_STORAGE *mtd, uint64_t *startAddrP) 00027 { 00028 ARM_STORAGE_BLOCK mtdBlock; 00029 if ((mtd->GetNextBlock(NULL, &mtdBlock)) != ARM_DRIVER_OK) { 00030 return JOURNAL_STATUS_STORAGE_API_ERROR; 00031 } 00032 if (!ARM_STORAGE_VALID_BLOCK(&mtdBlock)) { 00033 return JOURNAL_STATUS_ERROR; 00034 } 00035 00036 *startAddrP = mtdBlock.addr; 00037 return JOURNAL_STATUS_OK; 00038 } 00039 00040 /** 00041 * Check the sanity of a given slot 00042 * @param journal 00043 * @param slotOffset 00044 * @param [out] headSequenceNumberP 00045 * sequence number of the slot as read from the header. 00046 * @param [out] tailP 00047 * the tail of the slot 00048 * @return 1 if the slot is valid; i.e. if head and tail match, and if CRC32 agrees. 00049 */ 00050 int32_t slotIsSane(SequentialFlashJournal_t *journal, 00051 uint64_t slotOffset, 00052 uint32_t *headSequenceNumberP, 00053 SequentialFlashJournalLogTail_t *tailP) 00054 { 00055 int32_t rc; 00056 ARM_DRIVER_STORAGE *mtd = journal->mtd; 00057 00058 SequentialFlashJournalLogHead_t head; 00059 /* TODO: add support for asynchronous read */ 00060 if (((rc = mtd->ReadData(slotOffset, &head, sizeof(SequentialFlashJournalLogHead_t))) < ARM_DRIVER_OK) || 00061 (rc != sizeof(SequentialFlashJournalLogHead_t))) { 00062 if ((rc == ARM_DRIVER_OK) && (journal->mtdCapabilities.asynchronous_ops)) { 00063 return JOURNAL_STATUS_UNSUPPORTED; 00064 } 00065 00066 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00067 } 00068 00069 /* compute the CRC32 of the header */ 00070 flashJournalCrcReset(); 00071 flashJournalCrcCummulative((const unsigned char *)&head, sizeof(SequentialFlashJournalLogHead_t)); 00072 00073 // printf("head->version: %lu\n", journal->initScan.head.version); 00074 // printf("head->magic: %lx\n", journal->initScan.head.magic); 00075 // printf("head->sequenceNumber: %lu\n", journal->initScan.head.sequenceNumber); 00076 // printf("head->reserved: %lu\n", journal->initScan.head.reserved); 00077 00078 if (SEQUENTIAL_JOURNAL_VALID_HEAD(&head)) { 00079 *headSequenceNumberP = head.sequenceNumber; 00080 // printf("found valid header with sequenceNumber %" PRIu32 "\n", *headSequenceNumberP); 00081 00082 uint64_t tailoffset = slotOffset 00083 - ((slotOffset - SLOT_ADDRESS(journal, 0)) % journal->sizeofSlot) 00084 + journal->sizeofSlot 00085 - sizeof(SequentialFlashJournalLogTail_t); 00086 // printf("hoping to read a tail at offset %lu\n", (uint32_t)tailoffset); 00087 00088 /* TODO: add support for asynchronous read */ 00089 if (((rc = mtd->ReadData(tailoffset, tailP, sizeof(SequentialFlashJournalLogTail_t))) < ARM_DRIVER_OK) || 00090 (rc != sizeof(SequentialFlashJournalLogTail_t))) { 00091 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00092 } 00093 00094 if (SEQUENTIAL_JOURNAL_VALID_TAIL(tailP) && (tailP->sequenceNumber == *headSequenceNumberP)) { 00095 // printf("found valid tail\n"); 00096 00097 /* iterate over the body of the slot computing CRC */ 00098 #define CRC_CHUNK_SIZE 64 00099 uint8_t crcBuffer[CRC_CHUNK_SIZE]; 00100 uint64_t bodyIndex = 0; 00101 uint64_t bodyOffset = slotOffset + sizeof(SequentialFlashJournalLogHead_t); 00102 while (bodyIndex < tailP->sizeofBlob) { 00103 size_t sizeofReadOperation; 00104 if ((tailP->sizeofBlob - bodyIndex) > CRC_CHUNK_SIZE) { 00105 sizeofReadOperation = CRC_CHUNK_SIZE; 00106 } else { 00107 sizeofReadOperation = (tailP->sizeofBlob - bodyIndex); 00108 } 00109 00110 /* TODO: add support for asynchronous read */ 00111 rc = mtd->ReadData(bodyOffset + bodyIndex, crcBuffer, sizeofReadOperation); 00112 if (rc != (int32_t)sizeofReadOperation) { 00113 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00114 } 00115 00116 bodyIndex += sizeofReadOperation; 00117 flashJournalCrcCummulative(crcBuffer, sizeofReadOperation); 00118 } 00119 00120 /* compute CRC32 over the tail */ 00121 /* extract existing CRC32 from the tail. The CRC32 field in the tail needs to contain 0 before CRC32 can be computed over it. */ 00122 uint32_t expectedCRC32 = tailP->crc32; 00123 tailP->crc32 = 0; 00124 00125 uint32_t crc32 = flashJournalCrcCummulative((const unsigned char *)tailP, sizeof(SequentialFlashJournalLogTail_t)); 00126 flashJournalCrcReset(); 00127 // printf("expectedCRC32: 0x%x, computedCRC32: 0x%x\n", expectedCRC32, crc32); 00128 if (crc32 == expectedCRC32) { 00129 return 1; 00130 } 00131 } 00132 } 00133 00134 return JOURNAL_STATUS_ERROR; 00135 } 00136 00137 int32_t setupSequentialJournalHeader(SequentialFlashJournalHeader_t *headerP, ARM_DRIVER_STORAGE *mtd, uint64_t totalSize, uint32_t numSlots) 00138 { 00139 ARM_STORAGE_INFO mtdInfo; 00140 if (mtd->GetInfo(&mtdInfo) < ARM_DRIVER_OK) { 00141 return JOURNAL_STATUS_STORAGE_API_ERROR; 00142 } 00143 00144 headerP->genericHeader.magic = FLASH_JOURNAL_HEADER_MAGIC; 00145 headerP->genericHeader.version = FLASH_JOURNAL_HEADER_VERSION; 00146 headerP->genericHeader.sizeofHeader = sizeof(SequentialFlashJournalHeader_t); 00147 00148 /* Determine 'journalOffset'. 00149 * Constraint: journal header should start and terminate at an erase-boundary 00150 * (so that slot-0 can be erased independently), and also a program-unit boundary. 00151 */ 00152 headerP->genericHeader.journalOffset = roundUp_uint32(headerP->genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS); 00153 if ((headerP->genericHeader.journalOffset % mtdInfo.program_unit) != 0) { 00154 //printf("setupSequentialJournalHeader: journalOffset is not a multiple of MTD's program_unit\r\n"); 00155 return JOURNAL_STATUS_PARAMETER; 00156 } 00157 00158 headerP->magic = SEQUENTIAL_FLASH_JOURNAL_HEADER_MAGIC; 00159 headerP->version = SEQUENTIAL_FLASH_JOURNAL_HEADER_VERSION; 00160 headerP->numSlots = numSlots; 00161 00162 /* Determine 'sizeofSlot'. 00163 * Constraint: slot-size should be a multiple of the erase-units of all involved storage blocks. 00164 */ 00165 uint64_t spaceAvailableForSlots = totalSize - headerP->genericHeader.journalOffset; 00166 headerP->sizeofSlot = roundDown_uint32(spaceAvailableForSlots / numSlots, LCM_OF_ALL_ERASE_UNITS); 00167 if (headerP->sizeofSlot == 0) { 00168 //printf("setupSequentialJournalHeader: not enough space to create %" PRIu32 " slots\r\n", numSlots); 00169 return JOURNAL_STATUS_PARAMETER; 00170 } 00171 00172 headerP->genericHeader.totalSize = headerP->genericHeader.journalOffset + (headerP->sizeofSlot * numSlots); 00173 //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); 00174 00175 /* compute checksum over the entire header */ 00176 headerP->genericHeader.checksum = 0; 00177 flashJournalCrcReset(); 00178 headerP->genericHeader.checksum = flashJournalCrcCummulative((const unsigned char *)&headerP->genericHeader, sizeof(SequentialFlashJournalLogHead_t)); 00179 00180 return JOURNAL_STATUS_OK; 00181 } 00182 00183 int32_t discoverLatestLoggedBlob(SequentialFlashJournal_t *journal) 00184 { 00185 /* reset top level journal metadata prior to scanning headers. */ 00186 journal->nextSequenceNumber = SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER; /* we are currently unaware of previously written blobs */ 00187 journal->currentBlobIndex = journal->numSlots; 00188 journal->info.sizeofJournaledBlob = 0; 00189 00190 /* begin header-scan from the first block of the MTD */ 00191 journal->initScan.currentOffset = SLOT_ADDRESS(journal, 0); 00192 journal->state = SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS; 00193 00194 // printf("discoverLatestLoggedBlob: start of init scan\n"); 00195 for (unsigned blobIndex = 0; 00196 blobIndex < journal->numSlots; 00197 blobIndex++, journal->initScan.currentOffset += journal->sizeofSlot) { 00198 // printf("discoverLatestLoggedBlob: blob index %u\n", blobIndex); 00199 /* TODO: it is possible that the header structure spans multiple blocks, needing multiple reads. */ 00200 00201 if (slotIsSane(journal, 00202 journal->initScan.currentOffset, 00203 &journal->initScan.headSequenceNumber, 00204 &journal->initScan.tail) == 1) { 00205 // printf("found valid blob with sequence number %lu\n", journal->initScan.headSequenceNumber); 00206 uint32_t nextSequenceNumber = journal->initScan.headSequenceNumber + 1; 00207 if (nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) { 00208 nextSequenceNumber = 0; 00209 } 00210 00211 /* Have we found the best of the slots seen so far? */ 00212 if ((journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) || 00213 /* We take advantage of properties of unsigned arithmetic in the following 00214 * expression. 00215 * 00216 * We want to calculate if (nextSequenceNumber > journal->nextSequenceNumber), 00217 * instead we use the expression ((nextSequenceNumber - journal->nextSequenceNumber) > 0) 00218 * to take wraparounds into account. 00219 */ 00220 ((int32_t)(nextSequenceNumber - journal->nextSequenceNumber) > 0)) { 00221 journal->currentBlobIndex = blobIndex; 00222 journal->nextSequenceNumber = nextSequenceNumber; 00223 journal->info.sizeofJournaledBlob = journal->initScan.tail.sizeofBlob; 00224 // printf("discoverLatestLoggedBlob: index %lu, sizeofBlob: %lu, nextSequenceNumber: %lu\n", 00225 // journal->currentBlobIndex, (uint32_t)journal->info.sizeofJournaledBlob, journal->nextSequenceNumber); 00226 } 00227 } 00228 } 00229 // printf("discoverLatestLoggedBlob: finished init scan\n"); 00230 00231 /* Handle the case where our scan hasn't yielded any results. */ 00232 if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) { 00233 // printf("discoverLatestLoggedBlob: initializing to defaults\n"); 00234 journal->currentBlobIndex = (uint32_t)-1; /* to be incremented to 0 during the first attempt to log(). */ 00235 journal->nextSequenceNumber = 0; 00236 } 00237 00238 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00239 return JOURNAL_STATUS_OK; 00240 } 00241 00242 /** 00243 * Progress the state machine for the 'format' operation. This method can also be called from an interrupt handler. 00244 * @return < JOURNAL_STATUS_OK for error 00245 * = JOURNAL_STATUS_OK to signal pending asynchronous activity 00246 * > JOURNAL_STATUS_OK for completion 00247 */ 00248 int32_t flashJournalStrategySequential_format_progress(int32_t status, ARM_STORAGE_OPERATION operationWhichJustFinshed) 00249 { 00250 int32_t rc; 00251 size_t sizeofWrite = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit); 00252 size_t sizeofErase = roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, LCM_OF_ALL_ERASE_UNITS); 00253 switch (operationWhichJustFinshed) { 00254 case ARM_STORAGE_OPERATION_INITIALIZE: 00255 if (status != ARM_DRIVER_OK) { 00256 return JOURNAL_STATUS_STORAGE_API_ERROR; 00257 } 00258 00259 // printf("erasing %u bytes from offset %u\n", roundUp_uint32(header.genericHeader.sizeofHeader, mtdInfo.program_unit), mtdAddr); 00260 rc = (formatInfoSingleton.mtd)->Erase(formatInfoSingleton.mtdAddr, sizeofErase); 00261 if (rc < ARM_DRIVER_OK) { 00262 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00263 return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00264 } else { 00265 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00266 } 00267 } else if (rc == ARM_DRIVER_OK) { 00268 return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback 00269 * where the rest of processing will take place. */ 00270 } 00271 /* handle synchronous completion of programData */ 00272 status = rc; 00273 00274 /* intentional fall-through */ 00275 00276 case ARM_STORAGE_OPERATION_ERASE: 00277 if (status != (int32_t)sizeofErase) { 00278 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00279 } 00280 00281 // printf("calling ProgramData at address %u for %u bytes\n", 00282 // formatInfoSingleton.mtdAddr, roundUp_uint32(formatInfoSingleton.header.genericHeader.sizeofHeader, formatInfoSingleton.mtdProgramUnit)); 00283 rc = (formatInfoSingleton.mtd)->ProgramData(formatInfoSingleton.mtdAddr, &(formatInfoSingleton.header), sizeofWrite); 00284 if (rc < ARM_DRIVER_OK) { 00285 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00286 return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00287 } else { 00288 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00289 } 00290 } else if (rc == ARM_DRIVER_OK) { 00291 return JOURNAL_STATUS_OK; /* An asynchronous operation is pending; it will result in a completion callback 00292 * where the rest of processing will take place. */ 00293 } 00294 /* handle synchronous completion of programData */ 00295 status = rc; 00296 00297 /* intentional fall-through */ 00298 00299 case ARM_STORAGE_OPERATION_PROGRAM_DATA: 00300 if (status != (int32_t)sizeofWrite) { 00301 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00302 } 00303 00304 return 1; /* acknowledge the completion of create */ 00305 00306 default: 00307 return JOURNAL_STATUS_STORAGE_API_ERROR; /* we don't expect to be here */ 00308 } 00309 } 00310 00311 int32_t flashJournalStrategySequential_reset_progress(void) 00312 { 00313 int32_t rc; 00314 SequentialFlashJournal_t *journal = activeJournal; 00315 00316 if ((rc = journal->mtd->Erase(SLOT_ADDRESS(journal, 0), journal->numSlots * journal->sizeofSlot)) < ARM_DRIVER_OK) { 00317 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00318 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00319 return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00320 } else { 00321 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00322 } 00323 } 00324 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) { 00325 //printf("eturning JOURNAL_STATUS_OK\n"); 00326 return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */ 00327 } 00328 /* else we fall through to handle synchronous completion */ 00329 00330 journal->nextSequenceNumber = 0; 00331 journal->currentBlobIndex = (uint32_t)-1; 00332 journal->info.sizeofJournaledBlob = 0; 00333 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00334 return 1; 00335 } 00336 00337 int32_t flashJournalStrategySequential_read_progress(void) 00338 { 00339 SequentialFlashJournal_t *journal = activeJournal; 00340 00341 // printf("flashJournalStrategySequential_read_progress\n"); 00342 if (journal->state != SEQUENTIAL_JOURNAL_STATE_READING) { 00343 return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */ 00344 } 00345 00346 int32_t rc; 00347 ARM_STORAGE_BLOCK storageBlock; 00348 00349 if ((journal->read.amountLeftToRead) && 00350 ((rc = journal->mtd->GetBlock(journal->read.mtdOffset, &storageBlock)) != ARM_DRIVER_OK)) { 00351 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00352 return JOURNAL_STATUS_STORAGE_API_ERROR; 00353 } 00354 uint64_t storageBlockAvailableCapacity = storageBlock.size - (journal->read.mtdOffset - storageBlock.addr); 00355 00356 while (journal->read.amountLeftToRead) { 00357 while (!storageBlockAvailableCapacity) { 00358 if ((rc = journal->mtd->GetNextBlock(&storageBlock, &storageBlock)) < ARM_DRIVER_OK) { 00359 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00360 return JOURNAL_STATUS_ERROR; /* We ran out of storage blocks. Journal is in an un-expected state. */ 00361 } 00362 journal->read.mtdOffset = storageBlock.addr; /* This should not be necessary since we assume 00363 * storage map manages a contiguous address space. */ 00364 storageBlockAvailableCapacity = storageBlock.size; 00365 } 00366 00367 /* compute the transfer size for this iteration. */ 00368 uint32_t xfer = (journal->read.amountLeftToRead < storageBlockAvailableCapacity) ? 00369 journal->read.amountLeftToRead : storageBlockAvailableCapacity; 00370 00371 /* perform the IO */ 00372 //printf("reading %lu bytes at offset %lu\n", xfer, (uint32_t)journal->read.mtdOffset); 00373 rc = journal->mtd->ReadData(journal->read.mtdOffset, journal->read.dataBeingRead, xfer); 00374 if (rc < ARM_DRIVER_OK) { 00375 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00376 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00377 } 00378 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) { 00379 return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */ 00380 } else { 00381 /* synchronous completion. 'rc' contains the actual number of bytes transferred. */ 00382 journal->read.mtdOffset += rc; 00383 journal->read.amountLeftToRead -= rc; 00384 journal->read.dataBeingRead += rc; 00385 journal->read.logicalOffset += rc; 00386 } 00387 } 00388 00389 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00390 return (journal->read.dataBeingRead - journal->read.blob); 00391 } 00392 00393 /** 00394 * Progress the state machine for the 'log' operation. This method can also be called from an interrupt handler. 00395 * @return < JOURNAL_STATUS_OK for error 00396 * = JOURNAL_STATUS_OK to signal pending asynchronous activity 00397 * > JOURNAL_STATUS_OK for completion 00398 */ 00399 int32_t flashJournalStrategySequential_log_progress(void) 00400 { 00401 SequentialFlashJournal_t *journal = activeJournal; 00402 00403 if ((journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) && 00404 (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD) && 00405 (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) && 00406 (journal->state != SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL)) { 00407 return JOURNAL_STATUS_ERROR; /* journal is in an un-expected state. */ 00408 } 00409 00410 uint32_t blobIndexBeingLogged = journal->currentBlobIndex + 1; 00411 if (blobIndexBeingLogged == journal->numSlots) { 00412 blobIndexBeingLogged = 0; 00413 } 00414 00415 while (true) { 00416 int32_t rc; 00417 00418 if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) { 00419 uint64_t amountLeftToErase = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - journal->log.mtdEraseOffset; 00420 // printf("journal state: erasing; offset %lu [size %lu]\n", 00421 // (uint32_t)journal->log.eraseOffset, (uint32_t)amountLeftToErase); 00422 while (amountLeftToErase) { 00423 if ((rc = journal->mtd->Erase(journal->log.mtdEraseOffset, amountLeftToErase)) < ARM_DRIVER_OK) { 00424 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00425 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00426 return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00427 } else { 00428 return JOURNAL_STATUS_ERROR; 00429 } 00430 } 00431 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) { 00432 return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */ 00433 } else { 00434 /* synchronous completion. */ 00435 journal->log.mtdEraseOffset += rc; 00436 amountLeftToErase -= rc; 00437 } 00438 } 00439 } else { 00440 ARM_STORAGE_BLOCK storageBlock; 00441 00442 /* find the available capacity in the current storage block */ 00443 while (journal->log.amountLeftToLog) { 00444 if (journal->log.amountLeftToLog < journal->info.program_unit) { 00445 /* We cannot log any smaller than info.program_unit. 'xfer' 00446 * amount of data would remain unlogged. We'll break out of this loop and report 00447 * the amount actually logged. */ 00448 break; 00449 } 00450 00451 /* check for alignment of next log offset with program_unit */ 00452 if ((rc = journal->mtd->GetBlock(journal->log.mtdOffset, &storageBlock)) != ARM_DRIVER_OK) { 00453 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00454 return JOURNAL_STATUS_STORAGE_API_ERROR; 00455 } 00456 if ((journal->log.mtdOffset - storageBlock.addr) % journal->info.program_unit) { 00457 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00458 return JOURNAL_STATUS_ERROR; /* Program offset doesn't align with info.program_unit. This would result in an IO error if attempted. */ 00459 } 00460 00461 uint32_t xfer = journal->log.amountLeftToLog; 00462 xfer -= xfer % journal->info.program_unit; /* align transfer-size with program_unit. */ 00463 00464 /* perform the IO */ 00465 // printf("programming %lu bytes at offset %lu\n", xfer, (uint32_t)journal->log.mtdOffset); 00466 rc = journal->mtd->ProgramData(journal->log.mtdOffset, journal->log.dataBeingLogged, xfer); 00467 if (rc < ARM_DRIVER_OK) { 00468 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00469 if (rc == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00470 return JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00471 } else { 00472 return JOURNAL_STATUS_STORAGE_IO_ERROR; 00473 } 00474 } 00475 if ((journal->mtdCapabilities.asynchronous_ops) && (rc == ARM_DRIVER_OK)) { 00476 return JOURNAL_STATUS_OK; /* we've got pending asynchronous activity. */ 00477 } else { 00478 /* synchronous completion. 'rc' contains the actual number of bytes transferred. */ 00479 journal->log.mtdOffset += rc; 00480 journal->log.amountLeftToLog -= rc; 00481 journal->log.dataBeingLogged += rc; 00482 if (journal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) { 00483 journal->log.tail.sizeofBlob += rc; 00484 } 00485 } 00486 } /* while (journal->log.amountLeftToLog) */ 00487 } 00488 00489 // printf("flashJournalStrategySequential_log_progress: state switch\n"); 00490 00491 /* state transition */ 00492 switch (journal->state) { 00493 case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE: 00494 journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD; 00495 journal->log.mtdOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged); 00496 journal->log.head.version = SEQUENTIAL_FLASH_JOURNAL_VERSION; 00497 journal->log.head.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC; 00498 journal->log.head.sequenceNumber = journal->nextSequenceNumber; 00499 journal->log.head.reserved = 0; 00500 journal->log.dataBeingLogged = (const uint8_t *)&journal->log.head; 00501 journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogHead_t); 00502 // printf("newstate: program HEAD; amount to log %u\n", journal->log.amountLeftToLog); 00503 break; 00504 00505 case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: /* we've finished writing the head */ 00506 /* compute CRC32 on the header */ 00507 flashJournalCrcReset(); 00508 flashJournalCrcCummulative((const unsigned char *)&journal->log.head, sizeof(SequentialFlashJournalLogHead_t)); 00509 00510 /* switch to writing the body */ 00511 00512 /* Prepare for the tail to be written out at a later time. 00513 * This will only be done once Commit() is called. */ 00514 journal->log.mtdTailOffset = SLOT_ADDRESS(journal, blobIndexBeingLogged + 1) - sizeof(SequentialFlashJournalLogTail_t); 00515 00516 journal->log.tail.magic = SEQUENTIAL_FLASH_JOURNAL_MAGIC; 00517 journal->log.tail.sequenceNumber = journal->nextSequenceNumber; 00518 journal->log.tail.sizeofBlob = 0; /* we'll update this as we complete our writes. */ 00519 journal->log.tail.crc32 = 0; 00520 00521 if (journal->prevCommand == FLASH_JOURNAL_OPCODE_COMMIT) { 00522 /* This branch is taken only when commit() is called without any preceding log() operations. */ 00523 journal->log.tail.crc32 = flashJournalCrcCummulative((const unsigned char *)&journal->log.tail, sizeof(SequentialFlashJournalLogTail_t)); 00524 flashJournalCrcReset(); 00525 00526 journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL; 00527 journal->log.dataBeingLogged = (const uint8_t *)&journal->log.tail; 00528 journal->log.amountLeftToLog = sizeof(SequentialFlashJournalLogTail_t); 00529 journal->log.mtdOffset = journal->log.mtdTailOffset; 00530 // printf("newstate: program TAIL at offset %lu\r\n", (uint32_t)journal->log.mtdOffset); 00531 } else { 00532 journal->state = SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY; 00533 journal->log.dataBeingLogged = journal->log.blob; 00534 journal->log.amountLeftToLog = journal->log.sizeofBlob; 00535 // printf("newstate: program BODY; amount to log %u\n", journal->log.amountLeftToLog); 00536 } 00537 break; 00538 00539 case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY: 00540 // printf("finished logging BODY; amount logged %u\n", journal->log.dataBeingLogged - journal->log.blob); 00541 if (journal->log.dataBeingLogged == journal->log.blob) { 00542 return JOURNAL_STATUS_SMALL_LOG_REQUEST; 00543 } else { 00544 uint32_t amountOfDataLogged = (journal->log.dataBeingLogged - journal->log.blob); 00545 flashJournalCrcCummulative(journal->log.blob, amountOfDataLogged); /* compute CRC32 on logged data */ 00546 return amountOfDataLogged; 00547 } 00548 00549 case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL: 00550 // printf("crc32 of slot: 0x%x\n", journal->log.tail.crc32); 00551 00552 journal->info.sizeofJournaledBlob = journal->log.tail.sizeofBlob; 00553 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state to allow further operations */ 00554 00555 ++journal->currentBlobIndex; 00556 if (journal->currentBlobIndex == journal->numSlots) { 00557 journal->currentBlobIndex = 0; 00558 } 00559 // printf("currentBlobIndex: %lu\n", journal->currentBlobIndex); 00560 00561 /* increment next sequence number */ 00562 ++journal->nextSequenceNumber; 00563 if (journal->nextSequenceNumber == SEQUENTIAL_FLASH_JOURNAL_INVALD_NEXT_SEQUENCE_NUMBER) { 00564 ++journal->nextSequenceNumber; 00565 } 00566 // printf("nextSequenceNumber %lu\n", journal->nextSequenceNumber); 00567 00568 return 1; /* commit returns 1 upon completion. */ 00569 00570 default: 00571 journal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00572 return JOURNAL_STATUS_ERROR; 00573 } 00574 } 00575 } 00576 00577 void formatHandler(int32_t status, ARM_STORAGE_OPERATION operation) 00578 { 00579 if (status < ARM_DRIVER_OK) { 00580 if (formatInfoSingleton.callback) { 00581 formatInfoSingleton.callback(status, FLASH_JOURNAL_OPCODE_FORMAT); 00582 } 00583 return; 00584 } 00585 00586 int32_t rc = flashJournalStrategySequential_format_progress(status, operation); 00587 if (rc != JOURNAL_STATUS_OK) { 00588 if (formatInfoSingleton.callback) { 00589 formatInfoSingleton.callback(rc, FLASH_JOURNAL_OPCODE_FORMAT); 00590 } 00591 } 00592 } 00593 00594 void mtdHandler(int32_t status, ARM_STORAGE_OPERATION operation) 00595 { 00596 int32_t rc; 00597 00598 if (status < ARM_DRIVER_OK) { 00599 /* Map integrity failures reported by the Storage driver appropriately. */ 00600 if (status == ARM_STORAGE_ERROR_RUNTIME_OR_INTEGRITY_FAILURE) { 00601 status = JOURNAL_STATUS_STORAGE_RUNTIME_OR_INTEGRITY_FAILURE; 00602 } else { 00603 status = JOURNAL_STATUS_STORAGE_IO_ERROR; 00604 } 00605 00606 // printf("journal mtdHandler: received error status %ld\n", status); 00607 switch (activeJournal->state) { 00608 case SEQUENTIAL_JOURNAL_STATE_NOT_INITIALIZED: 00609 case SEQUENTIAL_JOURNAL_STATE_INIT_SCANNING_LOG_HEADERS: 00610 if (activeJournal->callback) { 00611 activeJournal->callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE); 00612 } 00613 break; 00614 00615 case SEQUENTIAL_JOURNAL_STATE_RESETING: 00616 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00617 if (activeJournal->callback) { 00618 activeJournal->callback(status, FLASH_JOURNAL_OPCODE_RESET); 00619 } 00620 break; 00621 00622 case SEQUENTIAL_JOURNAL_STATE_INITIALIZED: 00623 case SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE: 00624 case SEQUENTIAL_JOURNAL_STATE_LOGGING_HEAD: 00625 case SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY: 00626 case SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL: 00627 /* reset journal state to allow further operation. */ 00628 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00629 00630 if (activeJournal->callback) { 00631 activeJournal->callback(status, FLASH_JOURNAL_OPCODE_LOG_BLOB); 00632 } 00633 break; 00634 case SEQUENTIAL_JOURNAL_STATE_READING: 00635 /* reset journal state to allow further operation. */ 00636 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00637 00638 if (activeJournal->callback) { 00639 activeJournal->callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB); 00640 } 00641 break; 00642 } 00643 00644 return; 00645 } 00646 00647 switch (operation) { 00648 case ARM_STORAGE_OPERATION_INITIALIZE: 00649 if (activeJournal->callback) { 00650 activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_INITIALIZE); 00651 } 00652 break; 00653 00654 case ARM_STORAGE_OPERATION_ERASE_ALL: 00655 if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) { 00656 activeJournal->nextSequenceNumber = 0; 00657 activeJournal->currentBlobIndex = (uint32_t)-1; 00658 activeJournal->info.sizeofJournaledBlob = 0; 00659 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00660 if (activeJournal->callback) { 00661 activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET); 00662 } 00663 } 00664 break; 00665 00666 case ARM_STORAGE_OPERATION_ERASE: 00667 if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_ERASE) { 00668 if (status <= ARM_DRIVER_OK) { 00669 if (activeJournal->callback) { 00670 activeJournal->callback(JOURNAL_STATUS_STORAGE_API_ERROR, FLASH_JOURNAL_OPCODE_LOG_BLOB); 00671 } 00672 return; 00673 } 00674 00675 activeJournal->log.mtdEraseOffset += status; 00676 00677 if ((rc = flashJournalStrategySequential_log_progress()) != JOURNAL_STATUS_OK) { 00678 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00679 if (activeJournal->callback) { 00680 activeJournal->callback(rc, FLASH_JOURNAL_OPCODE_LOG_BLOB); 00681 } 00682 return; 00683 } 00684 } else if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_RESETING) { 00685 activeJournal->nextSequenceNumber = 0; 00686 activeJournal->currentBlobIndex = (uint32_t)-1; 00687 activeJournal->info.sizeofJournaledBlob = 0; 00688 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; 00689 if (activeJournal->callback) { 00690 activeJournal->callback(JOURNAL_STATUS_OK, FLASH_JOURNAL_OPCODE_RESET); 00691 } 00692 } 00693 break; 00694 00695 case ARM_STORAGE_OPERATION_PROGRAM_DATA: 00696 // printf("journal mtdHandler: PROGRAM_DATA: received status of %ld\n", status); 00697 rc = status; 00698 activeJournal->log.mtdOffset += rc; 00699 activeJournal->log.amountLeftToLog -= rc; 00700 activeJournal->log.dataBeingLogged += rc; 00701 if (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_BODY) { 00702 activeJournal->log.tail.sizeofBlob += rc; 00703 } 00704 00705 if ((rc = flashJournalStrategySequential_log_progress()) < JOURNAL_STATUS_OK) { 00706 activeJournal->state = SEQUENTIAL_JOURNAL_STATE_INITIALIZED; /* reset state */ 00707 if (activeJournal->callback) { 00708 activeJournal->callback(rc, 00709 (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_LOGGING_TAIL) ? 00710 FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB); 00711 } 00712 return; 00713 } 00714 if ((rc == JOURNAL_STATUS_OK) && (activeJournal->log.amountLeftToLog > 0)) { 00715 return; /* we've got pending asynchronous activity */ 00716 } 00717 if (activeJournal->callback) { 00718 activeJournal->callback(rc, (activeJournal->state == SEQUENTIAL_JOURNAL_STATE_INITIALIZED) ? 00719 FLASH_JOURNAL_OPCODE_COMMIT : FLASH_JOURNAL_OPCODE_LOG_BLOB); 00720 } 00721 break; 00722 00723 default: 00724 //printf("mtdHandler: unknown operation %u\n", operation); 00725 break; 00726 } 00727 }
Generated on Tue Jul 12 2022 13:16:13 by
