/** * \brief Initializes a TranslatedNandFlash instance. * * \param translated Pointer to a TranslatedNandFlash 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. * \return 0 if successful; otherwise returns a NandCommon_ERROR_xxx code. */ unsigned char TranslatedNandFlash_Initialize( struct TranslatedNandFlash *translated, 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) { translated->currentLogicalBlock = -1; translated->previousPhysicalBlock = -1; MarkAllPagesClean(translated); /* Initialize MappedNandFlash*/ return MappedNandFlash_Initialize(MAPPED(translated), model, commandAddress, addressAddress, dataAddress, pinChipEnable, pinReadyBusy, baseBlock, sizeInBlocks); }
/** * \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; }
DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID) { crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID); if (sIndex<0 || sIndex>=cr_server.screenCount) return VERR_INVALID_PARAMETER; if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID) { crDebug("Mapped screen[%i] is being remapped.", sIndex); crVBoxServerUnmapScreen(sIndex); } SCREEN(sIndex).winID = winID; SCREEN(sIndex).x = x; SCREEN(sIndex).y = y; SCREEN(sIndex).w = w; SCREEN(sIndex).h = h; renderspuSetWindowId(SCREEN(sIndex).winID); crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex); renderspuSetWindowId(SCREEN(0).winID); crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL); #ifndef WINDOWS /*Restore FB content for clients, which have current window on a screen being remapped*/ { GLint i; for (i = 0; i < cr_server.numClients; i++) { cr_server.curClient = cr_server.clients[i]; if (cr_server.curClient->currentCtx && (cr_server.curClient->currentCtx->buffer.pFrontImg || cr_server.curClient->currentCtx->buffer.pBackImg) && cr_server.curClient->currentMural && cr_server.curClient->currentMural->screenId == sIndex && cr_server.curClient->currentCtx->buffer.storedHeight == h && cr_server.curClient->currentCtx->buffer.storedWidth == w) { int clientWindow = cr_server.curClient->currentWindow; int clientContext = cr_server.curClient->currentContextNumber; if (clientWindow && clientWindow != cr_server.currentWindow) { crServerDispatchMakeCurrent(clientWindow, 0, clientContext); } crStateApplyFBImage(cr_server.curClient->currentCtx); } } cr_server.curClient = NULL; } #endif return VINF_SUCCESS; }
/** * \brief Erase all blocks in the tranalated area of nand flash. * * \param managed Pointer to a TranslatedNandFlash instance. * \param level Erase level. * \return 0 if successful; otherwise returns error code */ unsigned char TranslatedNandFlash_EraseAll( struct TranslatedNandFlash *translated, unsigned char level) { MappedNandFlash_EraseAll(MAPPED(translated), level); if (level > NandEraseDIRTY) { translated->currentLogicalBlock = -1; translated->previousPhysicalBlock = -1; MarkAllPagesClean(translated); } return 0; }
/** * \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; }
DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex) { crDebug("crVBoxServerUnmapScreen(%i)", sIndex); if (sIndex<0 || sIndex>=cr_server.screenCount) return VERR_INVALID_PARAMETER; if (MAPPED(SCREEN(sIndex))) { SCREEN(sIndex).winID = 0; renderspuSetWindowId(0); crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex); } renderspuSetWindowId(SCREEN(0).winID); return VINF_SUCCESS; }
/** * \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; }
DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount) { int i; if (sCount>CR_MAX_GUEST_MONITORS) return VERR_INVALID_PARAMETER; /*Shouldn't happen yet, but to be safe in future*/ for (i=0; i<cr_server.screenCount; ++i) { if (MAPPED(SCREEN(i))) crWarning("Screen count is changing, but screen[%i] is still mapped", i); return VERR_NOT_IMPLEMENTED; } cr_server.screenCount = sCount; for (i=0; i<sCount; ++i) { SCREEN(i).winID = 0; } return VINF_SUCCESS; }
/** * \brief Writes the data and/or spare area of a page on a translated nandflash. * Allocates block has needed to keep the wear even between all blocks. * * \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 error code */ unsigned char TranslatedNandFlash_WritePage( struct TranslatedNandFlash *translated, unsigned short block, unsigned short page, void *data, void *spare ) { unsigned char allocate = 1; unsigned char error; TRACE_INFO("TranslatedNandFlash_WritePage(B#%d:P#%d)\n\r", block, page); /* A new block must be allocated unless:*/ /* 1. the block is not mapped and there are no more blocks to allocate*/ if (MappedNandFlash_LogicalToPhysical(MAPPED(translated), block) == -1) { /* Block is not mapped, check if it can be*/ if (!BlockCanBeAllocated(translated)) { TRACE_ERROR("TranslatedNandFlash_WritePage: Not enough free blocks\n\r"); return NandCommon_ERROR_NOMOREBLOCKS; } TRACE_DEBUG("Allocate because block not mapped\n\r"); } /* or 2. the block to write is the current one and the page to write is clean*/ else { if (translated->currentLogicalBlock == block) { if (PageIsClean(translated, page)) { TRACE_DEBUG("NO allocate because write in current block\n\r"); allocate = 0; } else { TRACE_DEBUG("Allocate because page DIRTY in current block\n\r"); } } else { TRACE_DEBUG("Allocate because block is mapped and different from current block\n\r"); } } /* Allocate block if needed*/ if ( allocate ) { /* Flush current block write (if any) and then allocate block*/ error = TranslatedNandFlash_Flush(translated); if (error) { return error; } translated->previousPhysicalBlock = MappedNandFlash_LogicalToPhysical( MAPPED(translated), block ) ; TRACE_DEBUG("Previous physical block is now #%d\n\r", translated->previousPhysicalBlock ) ; error = AllocateBlock( translated, block ) ; if ( error ) { return error; } /* Block becomes the current block with all pages clean*/ translated->currentLogicalBlock = block; MarkAllPagesClean(translated); } /* Start writing page*/ error = MappedNandFlash_WritePage(MAPPED(translated), block, page, data, spare); if ( error ) { return error; } /* If write went through, mark page as written*/ MarkPageDirty(translated, page); return 0; }
/** * \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; }