//------------------------------------------------------------------------------ /// Unmaps a logical block by releasing the corresponding physical block (if /// any). /// Returns 0 if successful; otherwise returns a NandCommon_ERROR code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Number of logical block to unmap. //------------------------------------------------------------------------------ unsigned char MappedNandFlash_Unmap( struct MappedNandFlash *mapped, unsigned short logicalBlock) { signed short physicalBlock = mapped->logicalMapping[logicalBlock]; unsigned char error; TRACE_INFO("MappedNandFlash_Unmap(LB#%d)\r\n", logicalBlock); ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Unmap: logicalBlock out-of-range\r\n"); if (physicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), physicalBlock); if (error) { return error; } } mapped->logicalMapping[logicalBlock] = -1; mapped->mappingModified = 1; return 0; }
//------------------------------------------------------------------------------ /// Initializes a MappedNandFlash instance. Scans the device to look for and /// existing logical block mapping; otherwise starts from scratch (no block /// mapped). /// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param model Pointer to the underlying nand chip model. Can be 0. /// \param commandAddress Address at which commands are sent. /// \param addressAddress Address at which addresses are sent. /// \param dataAddress Address at which data is sent. /// \param pinChipEnable Pin controlling the CE signal of the NandFlash. /// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand. /// \param baseBlock Basic physical block address of mapped area. /// \param sizeInBlocks Number of blocks that is mapped. //------------------------------------------------------------------------------ unsigned char MappedNandFlash_Initialize( struct MappedNandFlash *mapped, const struct NandFlashModel *model, unsigned int commandAddress, unsigned int addressAddress, unsigned int dataAddress, const Pin pinChipEnable, const Pin pinReadyBusy, unsigned short baseBlock, unsigned short sizeInBlocks) { unsigned char error; unsigned short numBlocks; unsigned short block; signed short logicalMappingBlock = 0; TRACE_INFO("MappedNandFlash_Initialize()\r\n"); // Initialize ManagedNandFlash error = ManagedNandFlash_Initialize(MANAGED(mapped), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy, baseBlock, sizeInBlocks); if (error) { return error; } // Scan to find logical mapping mapped->mappingModified = 0; error = FindLogicalMappingBlock(mapped, &logicalMappingBlock); if (!error) { // Extract mapping from block mapped->logicalMappingBlock = logicalMappingBlock; return LoadLogicalMapping(mapped, logicalMappingBlock); } else if (error == NandCommon_ERROR_NOMAPPING) { // Start with no block mapped mapped->logicalMappingBlock = -1; numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); for (block=0; block < numBlocks; block++) { mapped->logicalMapping[block] = -1; } } else { TRACE_ERROR("MappedNandFlash_Initialize: Initialize device\r\n"); return error; } return 0; }
/** * \brief Returns the number of available blocks in a translated nandflash. * * \param translated Pointer to a TranslatedNandFlash instance. * \return the number of available blocks in a translated nandflash. */ unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks( const struct TranslatedNandFlash *translated) { return ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(translated)) - MINNUMUNALLOCATEDBLOCKS - ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_BAD) - 1; /* Logical mapping block*/ }
static void managedstring_finalize( GObject *gobject ) { Managedstring *managedstring = MANAGEDSTRING( gobject ); #ifdef DEBUG printf( "managedstring_finalize: \"%s\", ", managedstring->string ); iobject_print( IOBJECT( managedstring ) ); #endif /*DEBUG*/ #ifdef DEBUG { PElement pe; PEPOINTE( &pe, &managedstring->e ); if( !PEISNOVAL( &pe ) ) managed_expanded -= 1; managed_total -= 1; } #endif /*DEBUG*/ heap_unregister_element( MANAGED( managedstring )->heap, &managedstring->e ); g_hash_table_remove( managedstring_all, managedstring ); IM_FREE( managedstring->string ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); }
static uclptr_t STRING_create (const void* sample_data) { if (sizeof(char*) <= sizeof(cell_t)) { uclptr_t storage_index = cell_alloc(); if (storage_index != NIL) { int length = strlen(sample_data) + 1; //char **storage_cell_ptr = (char**)&uclmem[storage_index]; char **storage_cell_ptr = (char**)&CONTAINER(storage_index); MANAGED(storage_index) = 1; *storage_cell_ptr = (char*)malloc(length); memset (*storage_cell_ptr, 0, length); strcpy (*storage_cell_ptr, sample_data); return storage_index; } } else /* физический указатель очень велик и не помещается даже на место целой ячейки */ { int length = strlen(sample_data) + 1; char *src = (char*)malloc(length); strcpy (src, sample_data); return chop (&src, sizeof(void*)); } return NIL; }
/** * \brief Reads the data and/or spare area of a page in a mapped logical block. * the data is valid using the ECC information contained in the spare. If one * buffer pointer is 0, the corresponding area is not saved. * \param mapped Pointer to a MappedNandFlash instance. * \param block Number of block to read from. * \param page Number of page to read inside given block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \return 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED * if the block is not mapped, or a NandCommon_ERROR_xxx code. */ unsigned char MappedNandFlash_ReadPage( const struct MappedNandFlash *mapped, unsigned short block, unsigned short page, void *data, void *spare) { signed short physicalBlock; TRACE_INFO("MappedNandFlash_ReadPage(LB#%d:P#%d)\n\r", block, page); /* Check if block is mapped*/ physicalBlock = mapped->logicalMapping[block]; if (physicalBlock == -1) { TRACE_INFO( "MappedNandFlash_ReadPage: Block %d not mapped\n\r", block); return NandCommon_ERROR_BLOCKNOTMAPPED; } /* Read page from corresponding physical block*/ return ManagedNandFlash_ReadPage(MANAGED(mapped), physicalBlock, page, data, spare); }
/** * \brief Writes the data and/or spare area of a page in a mapped logical block. * the data is valid using the ECC information contained in the spare. If one * buffer pointer is 0, the corresponding area is not saved. * \param mapped Pointer to a MappedNandFlash instance. * \param block Number of block to read from. * \param page Number of page to write inside given block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \return 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED * if the block is not mapped, or a NandCommon_ERROR_xxx code. */ unsigned char MappedNandFlash_WritePage( const struct MappedNandFlash *mapped, unsigned short block, unsigned short page, void *data, void *spare) { signed short physicalBlock; TRACE_INFO("MappedNandFlash_WritePage(LB#%d:P#%d)\n\r", block, page); /* Check if block is mapped*/ physicalBlock = mapped->logicalMapping[block]; if (physicalBlock == -1) { TRACE_ERROR("MappedNandFlash_WritePage: Block must be mapped\n\r"); return NandCommon_ERROR_BLOCKNOTMAPPED; } /* Write page on physical block*/ return ManagedNandFlash_WritePage(MANAGED(mapped), physicalBlock, page, data, spare); }
/** * \brief Reads the data and/or the spare area of a page on a translated nandflash. * If the block is not currently mapped but could be (i.e. there are available * physical blocks), then the data/spare is filled with 0xFF. * * \param translated Pointer to a TranslatedNandFlash instance. * \param block Logical block number. * \param page Number of page to read inside logical block. * \param data Data area buffer, can be 0. * \param spare Spare area buffer, can be 0. * \return 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS */ unsigned char TranslatedNandFlash_ReadPage( const struct TranslatedNandFlash *translated, unsigned short block, unsigned short page, void *data, void *spare ) { unsigned char error ; TRACE_INFO("TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page); /* If the page to read is in the current block, there is a previous physical block and the page is clean -> read the page in the old block since the new one does not contain meaningful data*/ if ( (block == translated->currentLogicalBlock) && (translated->previousPhysicalBlock != -1) && (PageIsClean(translated, page)) ) { TRACE_DEBUG("Reading page from current block\n\r"); return ManagedNandFlash_ReadPage( MANAGED( translated ), translated->previousPhysicalBlock, page, data, spare ) ; } else { /* Try to read the page from the logical block*/ error = MappedNandFlash_ReadPage(MAPPED(translated), block, page, data, spare); /* Block was not mapped*/ if ( error == NandCommon_ERROR_BLOCKNOTMAPPED ) { assert( !spare ) ; /* "Cannot read the spare information of an unmapped block\n\r" */ /* Check if a block can be allocated*/ if ( BlockCanBeAllocated( translated ) ) { /* Return 0xFF in buffers with no error*/ TRACE_DEBUG("Block #%d is not mapped but can be allocated, filling buffer with 0xFF\n\r", block); if (data) { memset(data, 0xFF, NandFlashModel_GetPageDataSize(MODEL(translated))); } if (spare) { memset(spare, 0xFF, NandFlashModel_GetPageSpareSize(MODEL(translated))); } } else { TRACE_ERROR("Block #%d is not mapped and there are no more blocks available\n\r", block); return NandCommon_ERROR_NOMOREBLOCKS; } } /* Error*/ else { if (error) { return error; } } } return 0; }
/** * \brief Returns the physical block mapped with the given logical block, or -1 if it * is not mapped. * \param mapped Pointer to a MappedNandFlash instance. * \param logicalBlock Logical block number. * \return the physical block, or -1 if it is not mapped. */ signed short MappedNandFlash_LogicalToPhysical( const struct MappedNandFlash *mapped, unsigned short logicalBlock) { assert( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\n\r" */ return mapped->logicalMapping[logicalBlock]; }
/** * \brief Erase all blocks in the mapped area of nand flash. * * \param mapped Pointer to a MappedNandFlash instance. * \param level Erase level. * \return 0. */ unsigned char MappedNandFlash_EraseAll( struct MappedNandFlash *mapped, unsigned char level) { unsigned int block; ManagedNandFlash_EraseAll(MANAGED(mapped), level); /* Reset to no block mapped*/ if (level > NandEraseDIRTY) { mapped->logicalMappingBlock = -1; mapped->mappingModified = 0; for (block=0; block < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); block++) { mapped->logicalMapping[block] = -1; } } return 0; }
//------------------------------------------------------------------------------ /// Returns the physical block mapped with the given logical block, or -1 if it /// is not mapped. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Logical block number. //------------------------------------------------------------------------------ signed short MappedNandFlash_LogicalToPhysical( const struct MappedNandFlash *mapped, unsigned short logicalBlock) { ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\r\n"); return mapped->logicalMapping[logicalBlock]; }
static unsigned char BlockCanBeAllocated( const struct TranslatedNandFlash *translated) { unsigned short count; /* Count number of free and dirty blocks (unallocated blocks)*/ count = ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_DIRTY) + ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE); /* Check that count is greater than minimum number of unallocated blocks*/ if (count > MINNUMUNALLOCATEDBLOCKS) { return 1; } else { return 0; } }
/** * \brief Allocates a free block to save the current logical mapping on it. * * \param translated Pointer to a TranslatedNandFlash instance. * \return 0 if successful; otherwise returns a NandCommon_ERROR code. */ unsigned char TranslatedNandFlash_SaveLogicalMapping( struct TranslatedNandFlash *translated) { unsigned char error; unsigned short freeBlock; TRACE_INFO("TranslatedNandFlash_SaveLogicalMapping()\n\r"); /* Save logical mapping in the youngest free block*/ /* Find the youngest block*/ error = ManagedNandFlash_FindYoungestBlock(MANAGED(translated), NandBlockStatus_FREE, &freeBlock); if (error) { TRACE_ERROR("TranNF_SaveLogicalMapping: No free block\n\r"); return error; } /* Check if this is the last free block, in which case dirty blocks are wiped prior to saving the mapping */ if (ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE) == 1) { TranslatedNandFlash_Flush(translated); error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated)); if (error) { TRACE_ERROR("TranNF_Flush: Could not erase dirty blocks\n\r"); return error; } } /* Save the mapping*/ error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock); if (error) { TRACE_ERROR("TranNF_Flush: Failed to save mapping in #%d\n\r", freeBlock); return error; } return 0; }
//------------------------------------------------------------------------------ /// Maps a logical block number to an actual physical block. This allocates /// the physical block (meaning it must be FREE), and releases the previous /// block being replaced (if any). /// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param logicalBlock Logical block number to map. /// \param physicalBlock Physical block to map to the logical one. //------------------------------------------------------------------------------ unsigned char MappedNandFlash_Map( struct MappedNandFlash *mapped, unsigned short logicalBlock, unsigned short physicalBlock) { unsigned char error; signed short oldPhysicalBlock; TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\r\n", logicalBlock, physicalBlock); ASSERT( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Map: logicalBlock out-of-range\r\n"); ASSERT( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)), "MappedNandFlash_Map: physicalBlock out-of-range\r\n"); // Allocate physical block error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); if (error) { return error; } // Release currently mapped block (if any) oldPhysicalBlock = mapped->logicalMapping[logicalBlock]; if (oldPhysicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock); if (error) { return error; } } // Set mapping mapped->logicalMapping[logicalBlock] = physicalBlock; mapped->mappingModified = 1; return 0; }
/** * \brief Returns the logical block mapped with the given logical block, or -1 if it * is not mapped. * \param mapped Pointer to a MappedNandFlash instance. * \param physicalBlock Physical block number. * \return the logical block, or -1 if it is not mapped. */ signed short MappedNandFlash_PhysicalToLogical( const struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); signed short logicalBlock; assert( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_PhysicalToLogical: physicalBlock out-of-range\n\r" */ /* Search the mapping for the desired physical block*/ for ( logicalBlock=0; logicalBlock < numBlocks; logicalBlock++ ) { if ( mapped->logicalMapping[logicalBlock] == physicalBlock ) { return logicalBlock ; } } return -1; }
uclptr_t chop (void *srcdata, int size) /* рубит указатель на некие данные и их размер */ { uclptr_t chunks = NIL; int i, num_of_chunks = size / sizeof(uclptr_t); /* количество кусков, на которые будет разбит массив */ uclptr_t *vdata = (uclptr_t *)srcdata; for (i = 0; i < num_of_chunks; i++) { chunks = cons (chunks, vdata[i]); /* здесь мы нарушаем порядок полей ячейки - для замыкания в цепь используется CAR, а не CDR! */ MANAGED(chunks) = 1; } return chunks; }
/** * \brief Maps a logical block number to an actual physical block. This allocates * the physical block (meaning it must be FREE), and releases the previous * block being replaced (if any). * \param mapped Pointer to a MappedNandFlash instance. * \param logicalBlock Logical block number to map. * \param physicalBlock Physical block to map to the logical one. * \return 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. */ unsigned char MappedNandFlash_Map( struct MappedNandFlash *mapped, unsigned short logicalBlock, unsigned short physicalBlock) { unsigned char error; signed short oldPhysicalBlock; TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\n\r", logicalBlock, physicalBlock); assert( logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_Map: logicalBlock out-of-range\n\r" */ assert( physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)) ) ; /* "MappedNandFlash_Map: physicalBlock out-of-range\n\r" */ /* Allocate physical block*/ error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); if ( error ) { return error; } /* Release currently mapped block (if any)*/ oldPhysicalBlock = mapped->logicalMapping[logicalBlock]; if (oldPhysicalBlock != -1) { error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock); if ( error ) { return error; } } /* Set mapping*/ mapped->logicalMapping[logicalBlock] = physicalBlock; mapped->mappingModified = 1; return 0; }
static uclptr_t INTEGER32_create (const void* sample_data) /* Теперь надо посмотреть, влезает ли 32-битное число в поле CDR. * Если не влезает, оно будет храниться в отдельной ячейке (сделаем смелое предположение о том, что туда-то уж оно влезет). */ { if (sizeof(int32_t) != sizeof(uclptr_t)) /* определяется на этапе компиляции */ { uclptr_t storage_index = cell_alloc(); /* возьмём ещё одну ячейку */ //int32_t **storage_cell_ptr = (int32_t**)&uclmem[storage_index]; /* представим, что это указатель на int */ int32_t **storage_cell_ptr = (int32_t**)&CONTAINER(storage_index); /* представим, что это указатель на int */ MANAGED(storage_index) = 1; *storage_cell_ptr = (int32_t*)sample_data; /* положим его туда */ return storage_index; /* вернём индекс ячейки хранения */ } else return (uint32_t)((intptr_t)sample_data); }
/** * \brief Terminates the current write operation by copying all the missing pages from * the previous physical block. * * \param translated Pointer to a TranslatedNandFlash instance. * \return 0 if successful; otherwise returns error code */ unsigned char TranslatedNandFlash_Flush(struct TranslatedNandFlash *translated) { unsigned int i; unsigned char error; unsigned int currentPhysicalBlock; /* Check if there is a current block and a previous block*/ if ((translated->currentLogicalBlock == -1) || (translated->previousPhysicalBlock == -1)) { return 0; } TRACE_INFO("TranslatedNandFlash_Flush(PB#%d -> LB#%d)\n\r", translated->previousPhysicalBlock, translated->currentLogicalBlock); /* Copy missing pages in the current block*/ currentPhysicalBlock = MappedNandFlash_LogicalToPhysical( MAPPED(translated), translated->currentLogicalBlock); for (i=0; i < NandFlashModel_GetBlockSizeInPages(MODEL(translated)); i++) { if (PageIsClean(translated, i)) { TRACE_DEBUG("Copying back page #%d of block #%d\n\r", i, translated->previousPhysicalBlock); /* Copy page*/ error = ManagedNandFlash_CopyPage(MANAGED(translated), translated->previousPhysicalBlock, i, currentPhysicalBlock, i); if (error) { TRACE_ERROR("FinishCurrentWrite: copy page #%d\n\r", i); return error; } } } translated->currentLogicalBlock = -1; translated->previousPhysicalBlock = -1; return 0; }
static uclptr_t VECTOR_create (const void* sample_data) /* параметр - uint32_t, количество выделяемых ячеек. */ /* Эта функция только создаёт пустой вектор, его наполнение - забота совершенно другой конструкции. * */ { uint32_t i, n = (uintptr_t)sample_data; uint32_t size = (n * sizeof(uclptr_t)); /* смело! А вдруг упрёмся в ограничение? */ ucl_vector_t *vector; uclptr_t storage_index; if (sizeof(void*) <= sizeof(cell_t)) /* если указатель на кучу влезает целиком в поле container, то используем эту схему хранения */ { storage_index = cell_alloc(); if (storage_index != NIL) { ucl_vector_t **storage_cell_ptr = (ucl_vector_t**)&CONTAINER(storage_index); //GC(storage_index) = GC_TRANSIENT; MANAGED(storage_index) = 1; *storage_cell_ptr = (ucl_vector_t*)malloc(sizeof(ucl_vector_t)); /* выделяем память под дескриптор ветора */ vector = *storage_cell_ptr; } else { printf ("Panic stop: no free memory left!\n"); exit(-1); } } else /* если физический указатель очень велик и не помещается даже на место целой ячейки, тогда используем другую схему хранения - чоппер! */ { vector = (ucl_vector_t*)malloc(sizeof(ucl_vector_t)); storage_index = chop (&vector, sizeof(ucl_vector_t*)); } vector->length = n; vector->ptr = (uclptr_t*)malloc(size); for (i=0; i < vector->length; i++) { vector->ptr[i] = NIL; } return storage_index; }
/** * \brief Saves the logical mapping on a FREE, unmapped physical block. Allocates the * new block, releases the previous one (if any) and save the mapping. * * \param mapped Pointer to a MappedNandFlash instance. * \param physicalBlock Physical block number. * \return 0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS * if the block is not LIVE, or a NandCommon_ERROR code. */ unsigned char MappedNandFlash_SaveLogicalMapping( struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned char error; unsigned char data[NandCommon_MAXPAGEDATASIZE]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); /*unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));*/ unsigned int i; unsigned int remainingSize; unsigned char *currentBuffer; unsigned short currentPage; unsigned int writeSize; signed short previousPhysicalBlock; TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock); /* If mapping has not been modified, do nothing*/ if (!mapped->mappingModified) { return 0; } /* Allocate new block*/ error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock); if (error) { return error; } /* Save mapping*/ previousPhysicalBlock = mapped->logicalMappingBlock; mapped->logicalMappingBlock = physicalBlock; /* Save actual mapping in pages #1-#XXX*/ currentBuffer = (unsigned char *) mapped->logicalMapping; remainingSize = sizeof(mapped->logicalMapping); currentPage = 1; while (remainingSize > 0) { writeSize = min(remainingSize, pageDataSize); memset(data, 0xFF, pageDataSize); memcpy(data, currentBuffer, writeSize); error = ManagedNandFlash_WritePage(MANAGED(mapped), physicalBlock, currentPage, data, 0); if (error) { TRACE_ERROR( "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r"); return error; } currentBuffer += writeSize; remainingSize -= writeSize; currentPage++; } /* Mark page #0 of block with a distinguishible pattern, so the mapping can be retrieved at startup*/ for (i=0; i < pageDataSize; i++) { data[i] = PATTERN(i); } error = ManagedNandFlash_WritePage(MANAGED(mapped), physicalBlock, 0, data, 0); if (error) { TRACE_ERROR( "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r"); return error; } /* Mapping is not modified anymore*/ mapped->mappingModified = 0; /* Release previous block (if any)*/ if (previousPhysicalBlock != -1) { TRACE_DEBUG("Previous physical block was #%d\n\r", previousPhysicalBlock); error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), previousPhysicalBlock); if (error) { return error; } } TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock); return 0; }
/** * \brief Loads the logical mapping contained in the given physical block. * block contains the mapping, its index is stored in the provided variable (if * pointer is not 0). * * \param mapped Pointer to a MappedNandFlash instance. * \param physicalBlock Physical block number. * \return 0 if successful; otherwise, returns a NandCommon_ERROR code. */ static unsigned char LoadLogicalMapping( struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned char error; unsigned char data[NandCommon_MAXPAGEDATASIZE]; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned int remainingSize; unsigned char *currentBuffer; unsigned short currentPage; unsigned int readSize; unsigned int i; unsigned char status; signed short logicalBlock; /*signed short firstBlock, lastBlock;*/ TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock); /* Load mapping from pages #1 - #XXX of block*/ currentBuffer = (unsigned char *) mapped->logicalMapping; remainingSize = sizeof(mapped->logicalMapping); currentPage = 1; while (remainingSize > 0) { /* Read page*/ readSize = min(remainingSize, pageDataSize); error = ManagedNandFlash_ReadPage(MANAGED(mapped), physicalBlock, currentPage, data, 0); if (error) { TRACE_ERROR( "LoadLogicalMapping: Failed to load mapping\n\r"); return error; } /* Copy page info*/ memcpy(currentBuffer, data, readSize); currentBuffer += readSize; remainingSize -= readSize; currentPage++; } /* Store mapping block index*/ mapped->logicalMappingBlock = physicalBlock; /* Power-loss recovery*/ for (i=0; i < numBlocks; i++) { /* Check that this is not the logical mapping block*/ if (i != physicalBlock) { status = mapped->managed.blockStatuses[i].status; logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i); /* Block is LIVE*/ if (status == NandBlockStatus_LIVE) { /* Block is not mapped -> release it*/ if (logicalBlock == -1) { TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r", i); ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i); } } /* Block is DIRTY*/ else if (status == NandBlockStatus_DIRTY) { /* Block is mapped -> fake it as live*/ if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r", i); mapped->managed.blockStatuses[i].status = NandBlockStatus_LIVE; } } /* Block is FREE or BAD*/ else { /* Block is mapped -> remove it from mapping*/ if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i); mapped->logicalMapping[logicalBlock] = -1; } } } } TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock); return 0; }
//------------------------------------------------------------------------------ /// Loads the logical mapping contained in the given physical block. /// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code. /// \param mapped Pointer to a MappedNandFlash instance. /// \param physicalBlock Physical block number. //------------------------------------------------------------------------------ static unsigned char LoadLogicalMapping( struct MappedNandFlash *mapped, unsigned short physicalBlock) { unsigned char error; unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned char *pDataBuffer = RawNandFlash_GetDataBuffer(RAW(mapped)); unsigned int remainingSize; unsigned char *currentBuffer; unsigned short currentPage; unsigned int readSize; unsigned int i; unsigned char status; signed short logicalBlock; //signed short firstBlock, lastBlock; TRACE_INFO("LoadLogicalMapping(B#%d)\r\n", physicalBlock); // Load mapping from pages #1 - #XXX of block currentBuffer = (unsigned char *) mapped->logicalMapping; remainingSize = sizeof(mapped->logicalMapping); currentPage = 1; while (remainingSize > 0) { // Read page readSize = min(remainingSize, pageDataSize); error = ManagedNandFlash_ReadPage(MANAGED(mapped), physicalBlock, currentPage, pDataBuffer, 0); if (error) { RawNandFlash_ReleaseDataBuffer(RAW(mapped)); TRACE_ERROR( "LoadLogicalMapping: Failed to load mapping\r\n"); return error; } // Copy page info memcpy(currentBuffer, pDataBuffer, readSize); currentBuffer += readSize; remainingSize -= readSize; currentPage++; } // Store mapping block index mapped->logicalMappingBlock = physicalBlock; // Power-loss recovery for (i=0; i < numBlocks; i++) { // Check that this is not the logical mapping block if (i != physicalBlock) { status = mapped->managed.blockStatuses[i].status; logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i); // Block is LIVE if (status == NandBlockStatus_LIVE) { // Block is not mapped -> release it if (logicalBlock == -1) { TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\r\n", i); ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i); } } // Block is DIRTY else if (status == NandBlockStatus_DIRTY) { // Block is mapped -> fake it as live if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\r\n", i); mapped->managed.blockStatuses[i].status = NandBlockStatus_LIVE; } } // Block is FREE or BAD else { // Block is mapped -> remove it from mapping if (logicalBlock != -1) { TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\r\n", i); mapped->logicalMapping[logicalBlock] = -1; } } } } RawNandFlash_ReleaseDataBuffer(RAW(mapped)); TRACE_WARNING_WP("-I- Mapping loaded from block #%d\r\n", physicalBlock); return 0; }
/** * \brief Scans a mapped nandflash to find an existing logical block mapping. If a * block contains the mapping, its index is stored in the provided variable (if * pointer is not 0). * * \param mapped Pointer to a MappedNandFlash instance. * \param logicalMappingBlock Pointer to a variable for storing the block number. * \return 0 if mapping has been found; otherwise returns * NandCommon_ERROR_NOMAPPING if no mapping exists, or another NandCommon_ERROR_xxx code. */ static unsigned char FindLogicalMappingBlock( const struct MappedNandFlash *mapped, signed short *logicalMappingBlock) { unsigned short block; unsigned char found; unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)); unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped)); unsigned char error; unsigned char data[NandCommon_MAXPAGEDATASIZE]; unsigned int i; //TRACE_INFO("FindLogicalMappingBlock ~%d\n\r", numBlocks); /* Search each LIVE block */ found = 0; block = 0; while (!found && (block < numBlocks)) { /* Check that block is LIVE*/ if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) { /* Read block*/ TRACE_INFO("Checking LIVE block #%d\n\r", block); error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0); if (!error) { /* Compare data with logical mapping pattern*/ i = 0; found = 1; while ((i < pageDataSize) && found) { if (data[i] != PATTERN(i)) { found = 0; } i++; } /* If this is the mapping, stop looking*/ if (found) { TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r", block); if (logicalMappingBlock) { *logicalMappingBlock = block; } return 0; } } else if (error != NandCommon_ERROR_WRONGSTATUS) { TRACE_ERROR( "FindLogicalMappingBlock: Failed to scan block #%d\n\r", block); return error; } } block++; } TRACE_WARNING("No logical mapping found in device\n\r"); return NandCommon_ERROR_NOMAPPING; }
/** * \brief Allocates the best-fitting physical block for the given logical block. * * \param translated Pointer to a TranslatedNandFlash instance. * \param block Logical block number. * \return 0 if successful; otherwise returns NandCommon_ERROR_NOBLOCKFOUND if * there are no more free blocks, or a NandCommon_ERROR code. */ static unsigned char AllocateBlock( struct TranslatedNandFlash *translated, unsigned short block) { unsigned short freeBlock, liveBlock; unsigned char error; signed int eraseDifference; TRACE_DEBUG("Allocating a new block\n\r"); /* Find youngest free block and youngest live block*/ if (ManagedNandFlash_FindYoungestBlock(MANAGED(translated), NandBlockStatus_FREE, &freeBlock)) { TRACE_ERROR("AllocateBlock: Could not find a free block\n\r"); return NandCommon_ERROR_NOBLOCKFOUND; } /* If this is the last free block, save the logical mapping in it and clean dirty blocks */ TRACE_DEBUG("Number of FREE blocks: %d\n\r", ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE)); if (ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE) == 1) { /* Save mapping and clean dirty blocks*/ TRACE_DEBUG("Last FREE block, cleaning up ...\n\r"); error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock); if (error) { TRACE_ERROR("AllocateBlock: Failed to save mapping\n\r"); return error; } error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated)); if (error) { TRACE_ERROR("AllocatedBlock: Failed to erase dirty blocks\n\r"); return error; } /* Allocate new block*/ return AllocateBlock(translated, block); } /* Find youngest LIVE block to check the erase count difference*/ if (!ManagedNandFlash_FindYoungestBlock(MANAGED(translated), NandBlockStatus_LIVE, &liveBlock)) { /* Calculate erase count difference*/ TRACE_DEBUG("Free block erase count = %d\n\r", MANAGED(translated)->blockStatuses[freeBlock].eraseCount); TRACE_DEBUG("Live block erase count = %d\n\r", MANAGED(translated)->blockStatuses[liveBlock].eraseCount); eraseDifference = abs(MANAGED(translated)->blockStatuses[freeBlock].eraseCount - MANAGED(translated)->blockStatuses[liveBlock].eraseCount); /* Check if it is too big*/ if (eraseDifference > MAXERASEDIFFERENCE) { TRACE_WARNING("Erase difference too big, switching blocks\n\r"); MappedNandFlash_Map( MAPPED(translated), MappedNandFlash_PhysicalToLogical( MAPPED(translated), liveBlock), freeBlock); ManagedNandFlash_CopyBlock(MANAGED(translated), liveBlock, freeBlock); /* Allocate a new block*/ return AllocateBlock(translated, block); } } /* Map block*/ TRACE_DEBUG("Allocating PB#%d for LB#%d\n\r", freeBlock, block); MappedNandFlash_Map(MAPPED(translated), block, freeBlock); return 0; }