VOID SetBadBlock(OAL_BLMENU_ITEM *pMenu) { HANDLE hFMD = NULL; PCI_REG_INFO regInfo; FlashInfo flashInfo; BLOCK_ID blockId; WCHAR szInputLine[16]; UNREFERENCED_PARAMETER(pMenu); // Open FMD regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALLog(L" Oops, can't open FMD driver\r\n"); goto cleanUp; } if (!FMD_GetInfo(&flashInfo)) { OALLog(L" Oops, can't get flash geometry info\r\n"); goto cleanUp; } OALLog(L"\r\n Block Number: "); if (OALBLMenuReadLine(szInputLine, dimof(szInputLine)) == 0) { goto cleanUp; } // Get sector number blockId = OALStringToUINT32(szInputLine); // Check sector number if (blockId >= flashInfo.dwNumBlocks) { OALLog(L" Oops, too big block number\r\n"); goto cleanUp; } FMD_SetBlockStatus(blockId, BLOCK_STATUS_BAD); OALLog(L"\r\n Done\r\n"); cleanUp: if (hFMD != NULL) { FMD_Deinit(hFMD); } return; }
BOOL BLConfigureFlashPartitions(BOOL bForceEnable) { BOOL rc = FALSE; HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; HANDLE hPartition; PPARTENTRY pPartitionEntry; DWORD dwBootPartitionSectorCount; #ifdef IMGMULTIXIP // Variable for sector count for the new BinFS region (EXT) DWORD dwExtPartitionSectorCount; #endif memset(®Info, 0, sizeof(PCI_REG_INFO)); regInfo.MemBase.Num = 1; regInfo.MemLen.Num = 1; regInfo.MemBase.Reg[0] = g_ulFlashBase; // Get flash info hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) goto cleanUp; if (!FMD_GetInfo(&flashInfo)) goto cleanUp; FMD_Deinit(hFMD); // Initialize boot partition library if (!BP_Init((LPBYTE)g_ulBPartBase, g_ulBPartLengthBytes, NULL, ®Info, NULL)) { OALLog(L"BLConfigureFlashPartitions: Error initializing bootpart library!!\r\n"); goto cleanUp; } // Get boot partition size // Ensure boot partition uses entire blocks with no space left over // Round up to an even block size dwBootPartitionSectorCount = ((g_bootCfg.osPartitionSize + (flashInfo.dwBytesPerBlock - 1))/ flashInfo.dwBytesPerBlock) * flashInfo.wSectorsPerBlock; // Reduce by one to account for MBR, which will be the first sector in non reserved area. // This causes boot partition to end on a block boundary dwBootPartitionSectorCount -= 1; #ifdef IMGMULTIXIP // Calculation of the size for the EXT region dwExtPartitionSectorCount = ((IMAGE_WINCE_EXT_SIZE + (flashInfo.dwBytesPerBlock - 1))/ flashInfo.dwBytesPerBlock) * flashInfo.wSectorsPerBlock; dwExtPartitionSectorCount -= 1; #endif // Check for existence and size of OS boot partition hPartition = BP_OpenPartition((DWORD)NEXT_FREE_LOC, (DWORD)USE_REMAINING_SPACE, PART_BOOTSECTION, FALSE, PART_OPEN_EXISTING); if (hPartition == INVALID_HANDLE_VALUE) OALLog(L"OS partition does not exist!!\r\n"); else { pPartitionEntry = BP_GetPartitionInfo(hPartition); if (dwBootPartitionSectorCount != pPartitionEntry->Part_TotalSectors) { OALLog(L"OS partition does not match configured size!! Sector count expected: 0x%x, actual 0x%x\r\n", dwBootPartitionSectorCount, pPartitionEntry->Part_TotalSectors); // Mark handle invalid to kick us into formatting code hPartition = INVALID_HANDLE_VALUE; } } if ((hPartition == INVALID_HANDLE_VALUE) || (bForceEnable == TRUE)) { // OS binary partition either does not exist or does not match configured size OALLog(L"Formatting flash...\r\n"); // Create a new partion // Can't just call BP_OpenPartition with PART_OPEN_ALWAYS because it will erase reserved // blocks (bootloader) if MBR doesn't exist. Also, we want to ensure the boot partition // is actually the first partition on the flash. So do low level format here (note that // this destroys all other partitions on the device) // Note, we're skipping the block check for speed reasons. Might not want this in a production device... BP_LowLevelFormat (0, flashInfo.dwNumBlocks, FORMAT_SKIP_RESERVED|FORMAT_SKIP_BLOCK_CHECK); // Create the OS partition hPartition = BP_OpenPartition((DWORD)NEXT_FREE_LOC, dwBootPartitionSectorCount, PART_BOOTSECTION, FALSE, PART_CREATE_NEW); if (hPartition == INVALID_HANDLE_VALUE) { OALLog(L"Error creating OS partition!!\r\n"); goto cleanUp; } OALLog(L"NK partition created\r\n"); #ifdef IMGMULTIXIP // Creation of the BinFS partition hPartition = BP_OpenPartition((DWORD)NEXT_FREE_LOC, dwExtPartitionSectorCount, PART_BINFS, FALSE, PART_CREATE_NEW); if (hPartition == INVALID_HANDLE_VALUE) { OALLog(L"Error creating OS partition!!\r\n"); goto cleanUp; } OALLog(L"EXT partition created\r\n"); #endif // Create FAT partition on remaining flash (can be automatically mounted) hPartition = BP_OpenPartition((DWORD)NEXT_FREE_LOC, (DWORD)USE_REMAINING_SPACE, PART_DOS32, FALSE, PART_CREATE_NEW); if (hPartition == INVALID_HANDLE_VALUE) { OALLog(L"Error creating file partition!!\r\n"); goto cleanUp; } OALLog(L"Flash format complete!\r\n"); } // Done rc = TRUE; cleanUp: return rc; }
BOOL nand_ecc_test( DWORD Context, UCHAR *pInBuffer, UCHAR *p_outbuf) { NANDTEST_CONTEXT *pContext = (NANDTEST_CONTEXT *)Context; BOOL rc = FALSE; DWORD block; FlashInfo flashInfo; UCHAR outBuf[SECTOR_SIZE]; SectorInfo secInfo; UCHAR *p_gooddata, *p_baddata; /* NAND ECC test sector: pContext.test_sector data: p_gooddata, p_baddata */ p_gooddata = pInBuffer; p_baddata = pInBuffer + SECTOR_SIZE; DEBUGMSG(ZONE_FUNCTION, (L"+nand_ecc_test: p_gooddata=%x, p_baddata=%x\r\n", p_gooddata, p_baddata)); /* Step 0: Erase block */ if (!FMD_GetInfo(&flashInfo)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: FMD_GetInfo call failed!\r\n")); goto cleanUp; } block = pContext->test_sector / flashInfo.wSectorsPerBlock; rc = FMD_EraseBlock(block); if(!rc) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test ERASE block(%d) failed!\r\n", block)); goto cleanUp; } /* Step 1: flash the NAND with Good data */ rc = FMD_WriteSector(pContext->test_sector, p_gooddata, NULL, 1); if( !rc ) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test WRITE good data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } /* Step 2: read back to see if there are errors */ rc = FMD_ReadSector(pContext->test_sector, outBuf, NULL, 1); if( !rc ) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test READ good data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } if(memcmp(outBuf, p_gooddata, SECTOR_SIZE)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test READ data does not match good data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } /* Step 3: flash the NAND with Bad data WITHOUT UPDATING ecc*/ memset (&secInfo, 0, sizeof(secInfo)); secInfo.bOEMReserved = SKIP_ECC_WRITE_MAGIC_NUMBER; rc = FMD_WriteSector(pContext->test_sector, p_baddata, &secInfo, 1); if( !rc ) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test WRITE bad data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } /* Step 4: read back to see if there are errors */ rc = FMD_ReadSector(pContext->test_sector, outBuf, NULL, 1); if( !rc ) { DEBUGMSG(ZONE_ERROR, (L"ERROR: nand_ecc_test READ good data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } if(memcmp(outBuf, p_gooddata, SECTOR_SIZE)) { RETAILMSG(TRUE, (L"ERROR: nand_ecc_test READ data after correction does not match good data in sector(%d) failed!\r\n", pContext->test_sector)); goto cleanUp; } rc = TRUE; cleanUp: memcpy(p_outbuf, outBuf, SECTOR_SIZE ); return rc; }
//------------------------------------------------------------------------------ // // Function: DFT_IOControl // // This function sends a command to a device. // BOOL DFT_IOControl( DWORD context, DWORD dwCode, BYTE *pInBuffer, DWORD inSize, BYTE *pOutBuffer, DWORD outSize, DWORD *pOutSize) { NANDTEST_CONTEXT *pContext = (NANDTEST_CONTEXT *)context; HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; DWORD sector,block; BOOL rc=FALSE; UCHAR p_goodata[SECTOR_SIZE*2]; UNREFERENCED_PARAMETER(pOutSize); DEBUGMSG(ZONE_FUNCTION, (L"+DFT_IOControl(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, %d, 0x%08x)\r\n", context, dwCode, pInBuffer, inSize, pOutBuffer, outSize, pOutSize)); regInfo.MemBase.Reg[0] = OMAP_GPMC_REGS_PA; regInfo.MemLen.Reg[0] = 0x00001000; regInfo.MemBase.Reg[1] = BSP_NAND_REGS_PA; regInfo.MemLen.Reg[1] = 0x00001000; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { DEBUGMSG(ZONE_ERROR, (L"ERROR: FMD_Init call failed!\r\n")); goto cleanUp; } switch (dwCode) { case NAND_SET_SECTOR: // Checking parameter if (pInBuffer == NULL || inSize < sizeof(DWORD)) { DEBUGMSG(ZONE_ERROR, (L"+DFT_IOControl(%d): ERROR - invalid parameters\r\n", dwCode)); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: FMD_GetInfo call failed!\r\n")); goto cleanUp; } pContext->test_sector = *(DWORD*)pInBuffer; block = pContext->test_sector / flashInfo.wSectorsPerBlock; sector = pContext->test_sector % flashInfo.wSectorsPerBlock; DEBUGMSG(ZONE_ERROR, (L"Test section info: block=%d sector=%d !\r\n", block, sector)); if(block >= flashInfo.dwNumBlocks) { DEBUGMSG(ZONE_ERROR, (L"ERROR: invalid sector!\r\n")); goto cleanUp; } if(FMD_GetBlockStatus(block) & (BLOCK_STATUS_BAD |BLOCK_STATUS_RESERVED |BLOCK_STATUS_READONLY)) { DEBUGMSG(ZONE_ERROR, (L"ERROR: invalid sector status:%x!\r\n", FMD_GetBlockStatus(block) )); goto cleanUp; } rc = TRUE; break; case NAND_ECC_CORRECTION: /* Expecting 2 * 2K data, first 2K is good data, second 2K is bad data needs correction */ // Checking parameter if (pInBuffer == NULL || inSize != SECTOR_SIZE *2) { DEBUGMSG(ZONE_ERROR, (L"+DFT_IOControl(%d): ERROR - invalid in parameters\r\n", dwCode)); goto cleanUp; } memcpy(p_goodata, pInBuffer, SECTOR_SIZE * 2); if (pOutBuffer == NULL || outSize != SECTOR_SIZE) { DEBUGMSG(ZONE_ERROR, (L"+DFT_IOControl(%d): ERROR - invalid out parameters\r\n", dwCode)); goto cleanUp; } /* Call ECC test routine */ rc = nand_ecc_test(context, p_goodata, pOutBuffer); break; default: break; } cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); return rc; }
BOOL WriteFlashNK(UINT32 address, UINT32 size) { BOOL rc = FALSE; HANDLE hFMD; FlashInfo flashInfo; SectorInfo sectorInfo; BOOL ok = FALSE; BLOCK_ID block; //ROMHDR *pTOC; UINT32 *pInfo, count, sector; UINT32 blockSize, sectorSize, sectorsPerBlock; UINT8 *pData; OALMSG(OAL_INFO, (L"OEMWriteFlash: Writing NK image to flash\r\n")); // We need to know sector/block size if ((hFMD = FMD_Init(NULL, NULL, NULL)) == NULL) { OALMSG(OAL_ERROR, (L"ERROR: OEMWriteFlash: " L"FMD_Init call failed\r\n" )); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: EBOOT!OEMWriteFlash: " L"FMD_GetInfo call failed!\r\n" )); FMD_Deinit(hFMD); goto cleanUp; } // We don't need access to FMD library FMD_Deinit(hFMD); OALMSG(OAL_INFO, (L"OEMWriteFlash: " L"Flash has %d blocks, %d bytes/block, %d sectors/block\r\n", flashInfo.dwNumBlocks, flashInfo.dwBytesPerBlock, flashInfo.wSectorsPerBlock )); // Make block & sector size ready blockSize = flashInfo.dwBytesPerBlock; sectorSize = flashInfo.wDataBytesPerSector; sectorsPerBlock = flashInfo.wSectorsPerBlock; // Get data location pData = OEMMapMemAddr(address, address); // Verify that we get CE image. pInfo = (UINT32*)(pData + ROM_SIGNATURE_OFFSET); if (*pInfo++ != ROM_SIGNATURE) { OALMSG(OAL_ERROR, (L"ERROR: OEMWriteFlash: " L"Image Signature not found\r\n" )); goto cleanUp; } pInfo++; // Skip reserved blocks block = 0; while (block < flashInfo.dwNumBlocks) { if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) != 0) { OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Skip bad block %d\r\n", block )); block++; continue; } if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_RESERVED) == 0) break; block++; } OALMSG(OAL_INFO, (L"OEMWriteFlash: " L"NK image starts at block %d\r\n", block )); // Write image count = 0; while (count < size && block < flashInfo.dwNumBlocks) { // If block is bad, we have to offset it if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) != 0) { block++; OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Skip bad block %d\r\n", block )); continue; } // Erase block if (!EraseBlock(block)) { FMD_SetBlockStatus(block, BLOCK_STATUS_BAD); block++; OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Block %d erase failed, mark block as bad\r\n", block )); continue; } // Now write sectors sector = 0; while (sector < sectorsPerBlock && count < size) { // Prepare sector info memset(§orInfo, 0xFF, sizeof(sectorInfo)); sectorInfo.dwReserved1 = 0; sectorInfo.wReserved2 = 0; // Write sector if (!(ok = WriteSector( block * sectorsPerBlock + sector, pData + count, §orInfo ))) break; // Move to next sector count += sectorSize; sector++; } // When sector write failed, mark block as bad and move back if (!ok) { OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Block %d sector %d write failed, mark block as bad\r\n", block, sector )); // First move back count -= sector * flashInfo.wDataBytesPerSector; // Mark block as bad FMD_SetBlockStatus(block, BLOCK_STATUS_BAD); } // We are done with block block++; } // Erase rest of media while (block < flashInfo.dwNumBlocks) { // If block is bad, we have to offset it if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) != 0) { block++; OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Skip bad block %d\r\n", block )); continue; } // When erase failed, mark block as bad and skip it if (!EraseBlock(block)) { FMD_SetBlockStatus(block, BLOCK_STATUS_BAD); block++; OALMSG(OAL_WARN, (L"WARN: EBOOT!OEMWriteFlash: " L"Block %d erase failed, mark block as bad\r\n", block )); continue; } // Move to next block block++; } // Close FMD driver FMD_Deinit(hFMD); hFMD = NULL; OALMSG(OAL_INFO, (L"OEMWriteFlash: NK written\r\n")); // Done rc = TRUE; cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); return rc; }
static UINT32 ReadFlashNK() { UINT32 rc = BL_ERROR; HANDLE hFMD = NULL; FlashInfo flashInfo; ROMHDR *pTOC; UINT32 offset, size, toc; UINT32 blockSize, sectorSize, sectorsPerBlock; SectorInfo sectorInfo; SECTOR_ADDR sector; BLOCK_ID block; UINT8 *pImage; // Check if there is a valid image OALMSG(OAL_INFO, (L"\r\nLoad NK image from flash memory\r\n")); // Open FMD to access NAND hFMD = FMD_Init(NULL, NULL, NULL); if (hFMD == NULL) { OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: " L"FMD_Init call failed\r\n" )); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: " L"FMD_GetInfo call failed\r\n" )); goto cleanUp; } // Make block & sector size ready blockSize = flashInfo.dwBytesPerBlock; sectorSize = flashInfo.wDataBytesPerSector; sectorsPerBlock = flashInfo.wSectorsPerBlock; // Skip reserved blocks block = 0; while (block < flashInfo.dwNumBlocks) { if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) != 0) { OALMSG(OAL_WARN, (L"WARN: EBOOT!FMD_GetBlockStatus: " L"Skip bad block %d\r\n", block )); block++; continue; } if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_RESERVED) == 0) break; block++; } // Set address where to place image pImage = (UINT8*)IMAGE_WINCE_CODE_PA; size = IMAGE_WINCE_CODE_SIZE; // Read image to memory offset = 0; toc = 0; pTOC = NULL; while (offset < size && block < flashInfo.dwNumBlocks) { // Skip bad blocks if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) != 0) { block++; sector += flashInfo.wSectorsPerBlock; continue; } // Read sectors in block sector = 0; while (sector < sectorsPerBlock && offset < size) { // When block read fail, there isn't what we can do more RETAILMSG(1, (TEXT("0x%x 0x%x \r\n"), block * sectorsPerBlock + sector, pImage + offset)); if (!FMD_ReadSector( block * sectorsPerBlock + sector, pImage + offset, §orInfo, 1 )) { OALMSG(OAL_ERROR, (L"\r\nERROR: BLFlashDownload: " L"Failed read sector %d from flash\r\n", sector )); goto cleanUp; } // Move to next sector sector++; offset += sectorSize; } // Move to next block block++; } g_pTOC->id[g_dwTocEntry].dwJumpAddress = IMAGE_WINCE_CODE_PA; rc = BL_JUMP; cleanUp: return rc; }
static UINT32 ReadFlashIPL() { UINT32 rc = BL_ERROR; HANDLE hFMD = NULL; FlashInfo flashInfo; UINT32 offset; SectorInfo sectorInfo; SECTOR_ADDR sector; BLOCK_ID block; UINT8 *pImage; UINT32 *pInfo; // Check if there is a valid image OALMSG(OAL_INFO, (L"\r\nLoad IPL Image from flash memory\r\n")); // Open FMD to access NAND hFMD = FMD_Init(NULL, NULL, NULL); if (hFMD == NULL) { OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: " L"FMD_Init call failed\r\n" )); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: " L"FMD_GetInfo call failed\r\n" )); goto cleanUp; } // Start from NAND start block = 0; sector = 8; offset = 0; // Set address where to place image pImage = (UINT8*)(IMAGE_IPL_ADDR_VA); // Read image to memory while (offset < IMAGE_IPL_SIZE && block < flashInfo.dwNumBlocks) { // Read sectors in block while ( offset < IMAGE_IPL_SIZE ) { // When block read fail, there isn't what we can do more if (!FMD_ReadSector(sector, pImage, §orInfo, 1)) { OALMSG(OAL_ERROR, (L"\r\nERROR: BLFlashDownload: " L"Failed read sector %d from flash\r\n", sector )); goto cleanUp; } // Move to next sector sector++; pImage += flashInfo.wDataBytesPerSector; offset += flashInfo.wDataBytesPerSector; // OALMSG(OAL_INFO, (L".")); } // Move to next block block++; } OALMSG(OAL_INFO, (L"\r\n")); // Check if IPL is image and dump its content pInfo = (UINT32*)(IMAGE_IPL_ADDR_VA + ROM_SIGNATURE_OFFSET); if (*pInfo != ROM_SIGNATURE) { OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: " L"IPL image doesn't have ROM signature at 0x%08x\r\n", pInfo )); goto cleanUp; } g_pTOC->id[g_dwTocEntry].dwJumpAddress = IMAGE_IPL_ADDR_VA; rc = BL_JUMP; cleanUp: return rc; }
BOOL BLReserveBootBlocks( BOOT_CFG *pBootCfg ) { #ifndef BSP_NO_NAND_IN_SDBOOT BOOL rc = FALSE; HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; UINT32 size; BLOCK_ID firstblock, lastblock; UINT32 status; UNREFERENCED_PARAMETER(pBootCfg); // Automatically mark the bootloader blocks as read-only/reserved regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALMSG(OAL_ERROR, (L"ERROR: FMD_Init call failed!\r\n")); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: FMD_GetInfo call failed!\r\n")); goto cleanUp; } // Loop thru the bootloader blocks to ensure they are marked reserved firstblock = 0; size = IMAGE_BOOTLOADER_NAND_SIZE; lastblock = ((size -1) / flashInfo.dwBytesPerBlock) + 1; OALLog(L"Checking bootloader blocks are marked as reserved (Num = %d)\r\n", lastblock-firstblock); while (firstblock < lastblock) { // If block is bad, we have to offset it status = FMD_GetBlockStatus(firstblock); // Skip bad blocks if ((status & BLOCK_STATUS_BAD) != 0) { OALLog(L" Skip bad block %d\r\n", firstblock); // blocks marked bad would not have been written either, so don't include this // in the count of blocks that are reserved. firstblock++; lastblock++; continue; } // Skip already reserved blocks if ((status & BLOCK_STATUS_RESERVED) != 0) { firstblock++; continue; } // Mark block as read-only & reserved if (!FMD_SetBlockStatus(firstblock, BLOCK_STATUS_READONLY|BLOCK_STATUS_RESERVED)) { OALLog(L" Oops, can't mark block %d - as reserved\r\n", firstblock); } firstblock++; OALLog(L"."); } // Done rc = TRUE; OALLog(L"\r\n"); cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); return rc; #else UNREFERENCED_PARAMETER(pBootCfg); // Nothing to do... return TRUE; #endif }
BOOL BLReadBootCfg( BOOT_CFG *pBootCfg ) { BOOL rc = FALSE; #ifndef BSP_NO_NAND_IN_SDBOOT HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; SectorInfo sectorInfo; SECTOR_ADDR sector; BLOCK_ID block; UINT32 count, offset; UINT8 buffer[2048]; // EBOOT configuration is placed in last sector of EBOOT image regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALMSG(OAL_ERROR, (L"ERROR: FMD_Init call failed!\r\n")); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: FMD_GetInfo call failed!\r\n")); goto cleanUp; } // We can support only flash with sector size < 2048 bytes if (flashInfo.wDataBytesPerSector > sizeof(buffer)) { OALMSG(OAL_ERROR, (L"ERROR: " L"Flash sector size %d bytes bigger than supported %d bytes\r\n", flashInfo.wDataBytesPerSector, sizeof(buffer) )); goto cleanUp; } // Configuration is located in last sector of EBOOT image offset = IMAGE_XLDR_BOOTSEC_NAND_SIZE + IMAGE_EBOOT_BOOTSEC_NAND_SIZE; // Start from beginning block = 0; sector = 0; // Skip X-Loader & EBOOT code & bad blocks // Note that we also check the last eboot block in order to ensure it is good count = 0; while ((count < offset) && (block < flashInfo.dwNumBlocks)) { if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) == 0) { count += flashInfo.dwBytesPerBlock; } block++; } // We've incremented past the last eboot block in order to check it too // Back up now, the previous block is the last one containing eboot and is good block--; // Compute sector within the block where config lies sector = block * flashInfo.wSectorsPerBlock; sector += flashInfo.wSectorsPerBlock - 1; // Read sector to buffer if (!FMD_ReadSector(sector, buffer, §orInfo, 1)) { OALMSG(OAL_ERROR, (L"ERROR: EBOOT!BLReadBootCfg: " L"Flash sector %d read failed\r\n", sector )); goto cleanUp; } // Copy data to BOOT_CFG structure memcpy(pBootCfg, buffer, sizeof(BOOT_CFG)); // Done rc = TRUE; cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); #else UNREFERENCED_PARAMETER(pBootCfg); #endif return rc; }
BOOL BLWriteBootCfg( BOOT_CFG *pBootCfg ) { BOOL rc = FALSE; #ifndef BSP_NO_NAND_IN_SDBOOT HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; SectorInfo sectorInfo; SECTOR_ADDR sector; BLOCK_ID block; UINT32 count, offset, length; UINT8 buffer[2048]; UINT8 *pEBOOT; // EBOOT configuration is placed in last sector of image regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALMSG(OAL_ERROR, (L"ERROR: FMD_Init call failed!\r\n")); goto cleanUp; } // Get flash info if (!FMD_GetInfo(&flashInfo)) { OALMSG(OAL_ERROR, (L"ERROR: FMD_GetInfo call failed!\r\n")); goto cleanUp; } // We can support only flash with sector size which fit to our buffer if (flashInfo.wDataBytesPerSector > sizeof(buffer)) { OALMSG(OAL_ERROR, (L"ERROR: " L"Flash sector size %d bytes bigger that supported %d bytes\r\n", flashInfo.wDataBytesPerSector, sizeof(buffer) )); goto cleanUp; } // Configuration is located in last sector of last EBOOT block offset = IMAGE_XLDR_BOOTSEC_NAND_SIZE + IMAGE_EBOOT_BOOTSEC_NAND_SIZE; // Skip X-Loader & EBOOT code & bad blocks // Note that we also check the last eboot block in order to ensure it is good block = 0; count = 0; while ((count < offset) && (block < flashInfo.dwNumBlocks)) { if ((FMD_GetBlockStatus(block) & BLOCK_STATUS_BAD) == 0) { count += flashInfo.dwBytesPerBlock; } block++; } // We've incremented past the last eboot block in order to check it too // Back up now, the previous block is the last one containing eboot and is good block--; // Need to copy off the block contents to RAM (minus the config sector) pEBOOT = (UINT8*)IMAGE_WINCE_CODE_CA; length = flashInfo.dwBytesPerBlock - flashInfo.wDataBytesPerSector; memset((VOID*)pEBOOT, 0xFF, flashInfo.dwBytesPerBlock); sector = block * flashInfo.wSectorsPerBlock; offset = 0; while (offset < length) { // When block read fail, there isn't what we can do more if (!FMD_ReadSector(sector, pEBOOT + offset, §orInfo, 1)) { OALMSG(OAL_ERROR, (L"\r\nERROR: EBOOT!BLWriteBootCfg: " L"Failed read sector %d from flash\r\n", sector )); goto cleanUp; } // Move to next sector sector++; offset += flashInfo.wDataBytesPerSector; } // Copy the config info into last sector of saved block in RAM memcpy(pEBOOT + offset, pBootCfg, sizeof(BOOT_CFG)); // Erase block if (!FMD_EraseBlock(block)) { OALMSG(OAL_ERROR, (L"ERROR: EBOOT!BLWriteBootCfg: " L"Flash block %d erase failed\r\n", block )); goto cleanUp; } // Write contents of the save block + config sector back to flash pEBOOT = (UINT8*)IMAGE_WINCE_CODE_CA; length = flashInfo.dwBytesPerBlock; sector = block * flashInfo.wSectorsPerBlock; offset = 0; while (offset < length) { // Prepare sector info memset(§orInfo, 0xFF, sizeof(sectorInfo)); sectorInfo.bOEMReserved &= ~(OEM_BLOCK_READONLY|OEM_BLOCK_RESERVED); sectorInfo.dwReserved1 = 0; sectorInfo.wReserved2 = 0; // Write sector if (!FMD_WriteSector(sector, pEBOOT + offset, §orInfo, 1)) { OALMSG(OAL_ERROR, (L"ERROR: EBOOT!BLWriteBootCfg: " L"Flash sector %d write failed\r\n", sector )); goto cleanUp; } // Move to next sector sector++; offset += flashInfo.wDataBytesPerSector; } // Done rc = TRUE; cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); #else UNREFERENCED_PARAMETER(pBootCfg); #endif return rc; }
VOID DumpFlash(OAL_BLMENU_ITEM *pMenu) { HANDLE hFMD = NULL; PCI_REG_INFO regInfo; FlashInfo flashInfo; SectorInfo sectorInfo; SECTOR_ADDR sector; WCHAR szInputLine[16]; UINT8 buffer[2048], pOob[64]; UINT32 i, j; UNREFERENCED_PARAMETER(pMenu); // Open FMD regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALLog(L" Oops, can't open FMD driver\r\n"); goto cleanUp; } if (!FMD_GetInfo(&flashInfo)) { OALLog(L" Oops, can't get flash geometry info\r\n"); goto cleanUp; } if (flashInfo.wDataBytesPerSector > sizeof(buffer)) { OALLog(L" Oops, sector size larger than my buffer\r\n"); goto cleanUp; } for(;;) { OALLog(L"\r\n Sector Number: "); if (OALBLMenuReadLine(szInputLine, dimof(szInputLine)) == 0) { break; } // Get sector number sector = OALStringToUINT32(szInputLine); // Check sector number if (sector > flashInfo.dwNumBlocks * flashInfo.wSectorsPerBlock) { OALLog(L" Oops, too big sector number\r\n"); continue; } if (!FMD_ReadSector(sector, buffer, §orInfo, 1)) { OALLog(L" Oops, sector read failed\r\n"); continue; } OALLog( L"\r\nSector %d (sector %d in block %d)\r\n", sector, sector%flashInfo.wSectorsPerBlock, sector/flashInfo.wSectorsPerBlock ); OALLog( L"Reserved1: %08x OEMReserved: %02x Bad: %02x Reserved2: %04x\r\n", sectorInfo.dwReserved1, sectorInfo.bOEMReserved, sectorInfo.bBadBlock, sectorInfo.wReserved2 ); for (i = 0; i < flashInfo.wDataBytesPerSector; i += 16) { OALLog(L"%04x ", i); for (j = i; j < i + 16 && j < flashInfo.wDataBytesPerSector; j++) { OALLog(L" %02x", buffer[j]); } OALLog(L" "); for (j = i; j < i + 16 && j < flashInfo.wDataBytesPerSector; j++) { if (buffer[j] >= ' ' && buffer[j] < 127) { OALLog(L"%c", buffer[j]); } else { OALLog(L"."); } } OALLog(L"\r\n"); } //dump OOB data if (!FMD_ReadSectorOOB(sector, pOob)) { OALLog(L" Oops, sector read failed\r\n"); continue; } for (i = 0; i < 64; i += 16) { OALLog(L"%04x ", i); for (j = i; j < i + 16 && j < 64; j++) { OALLog(L" %02x", pOob[j]); } OALLog(L"\r\n"); } } cleanUp: if (hFMD != NULL) { FMD_Deinit(hFMD); } return; }
VOID ReserveBlock(OAL_BLMENU_ITEM *pMenu) { WCHAR key; HANDLE hFMD = NULL; PCI_REG_INFO regInfo; FlashInfo flashInfo; BLOCK_ID firstblock, lastblock=0; WCHAR szInputLine[16]; UINT32 status; UNREFERENCED_PARAMETER(pMenu); OALLog(L"\r\n First Block Number: "); if (OALBLMenuReadLine(szInputLine, dimof(szInputLine)) == 0) { goto cleanUp; } // Get block number firstblock = OALStringToUINT32(szInputLine); OALLog(L"\r\n Last Block Number: "); if (OALBLMenuReadLine(szInputLine, dimof(szInputLine)) != 0) { // Get block number lastblock = OALStringToUINT32(szInputLine); } if (lastblock < firstblock) { lastblock=firstblock; } // Open FMD regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALLog(L" Oops, can't open FMD driver\r\n"); goto cleanUp; } if (!FMD_GetInfo(&flashInfo)) { OALLog(L" Oops, can't get flash geometry info\r\n"); goto cleanUp; } if (lastblock >= flashInfo.dwNumBlocks) { OALLog(L" Oops, too big block number\r\n"); goto cleanUp; } OALLog(L" Do you want mark as reserved block %d-%d [-/y]? ", firstblock, lastblock); // Get key key = OALBLMenuReadKey(TRUE); OALLog(L"%c\r\n", key); // Depending on result if (key != L'y' && key != L'Y') { goto cleanUp; } while (firstblock<=lastblock) { // If block is bad, we have to offset it status = FMD_GetBlockStatus(firstblock); // Skip bad blocks if ((status & BLOCK_STATUS_BAD) != 0) { OALLog(L" Skip bad block %d\r\n", firstblock); // NOTE - this will cause a smaller number of blocks to actually be reserved... firstblock++; continue; } // Skip already reserved blocks if ((status & BLOCK_STATUS_RESERVED) != 0) { OALLog(L" Skip reserved block %d\r\n", firstblock); firstblock++; continue; } // Mark block as read-only & reserved if (!FMD_SetBlockStatus(firstblock, BLOCK_STATUS_READONLY|BLOCK_STATUS_RESERVED)) { OALLog(L" Oops, can't mark block %d - as reserved\r\n", firstblock); } firstblock++; OALLog(L"."); } OALLog(L" Done\r\n"); cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); return; }
VOID EraseFlash(OAL_BLMENU_ITEM *pMenu) { WCHAR key; HANDLE hFMD = NULL; PCI_REG_INFO regInfo; FlashInfo flashInfo; BLOCK_ID block; UINT32 status; UNREFERENCED_PARAMETER(pMenu); OALLog(L" Do you want to erase unreserved blocks [-/y]? "); // Get key key = OALBLMenuReadKey(TRUE); OALLog(L"%c\r\n", key); // Depending on result if (key != L'y' && key != L'Y') goto cleanUp; // Open FMD regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALLog(L" Oops, can't open FMD driver\r\n"); goto cleanUp; } if (!FMD_GetInfo(&flashInfo)) { OALLog(L" Oops, can't get flash geometry info\r\n"); goto cleanUp; } // First offset given block = 0; while (block < flashInfo.dwNumBlocks) { // If block is bad, we have to offset it status = FMD_GetBlockStatus(block); // Skip bad blocks if ((status & BLOCK_STATUS_BAD) != 0) { OALLog(L" Skip bad block %d\r\n", block); block++; continue; } // Skip reserved blocks if ((status & BLOCK_STATUS_RESERVED) != 0) { OALLog(L" Skip reserved block %d\r\n", block); block++; continue; } // Erase block if (!FMD_EraseBlock(block)) { OALLog(L" Oops, can't erase block %d - mark as bad\r\n", block); FMD_SetBlockStatus(block, BLOCK_STATUS_BAD); } block++; } OALLog(L" Done\r\n"); // Block until a keypress OALBLMenuReadKey(TRUE); cleanUp: if (hFMD != NULL) FMD_Deinit(hFMD); return; }
VOID ShowFlashGeometry(OAL_BLMENU_ITEM *pMenu) { HANDLE hFMD; PCI_REG_INFO regInfo; FlashInfo flashInfo; LPCWSTR pszType; BLOCK_ID block; UINT32 status; UINT32 listmode=0; UNREFERENCED_PARAMETER(pMenu); regInfo.MemBase.Reg[0] = g_ulFlashBase; hFMD = FMD_Init(NULL, ®Info, NULL); if (hFMD == NULL) { OALLog(L" Oops, can't open FMD driver\r\n"); goto cleanUp; } if (!FMD_GetInfo(&flashInfo)) { OALLog(L" Oops, can't get flash geometry info\r\n"); goto cleanUp; } switch (flashInfo.flashType) { case NAND: pszType = L"NAND"; break; case NOR: pszType = L"NOR"; break; default: pszType = L"Unknown"; } OALLog(L"\r\n"); OALLog(L" Flash Type: %s\r\n", pszType); OALLog(L" Blocks: %d\r\n", flashInfo.dwNumBlocks); OALLog(L" Bytes/block: %d\r\n", flashInfo.dwBytesPerBlock); OALLog(L" Sectors/block: %d\r\n", flashInfo.wSectorsPerBlock); OALLog(L" Bytes/sector: %d\r\n", flashInfo.wDataBytesPerSector); switch (g_bootCfg.ECCtype) { case 0: pszType = L"Hamming 1bit ECC"; break; case 1: pszType = L"BCH 4bit ECC"; break; case 2: pszType = L"BCH 8bit ECC"; break; default: pszType = L"Unknown"; } OALLog(L" ECC mode: %s\r\n", pszType); // now list bad/reserved sectors // First offset given block = 0; while (block < flashInfo.dwNumBlocks) { // If block is bad, we have to offset it status = FMD_GetBlockStatus(block); // bad block if ((status & BLOCK_STATUS_BAD) != 0) { if (listmode!=1) { OALLog(L"\r\n[bad] "); listmode=1; } OALLog(L" %d", block); block++; continue; } // reserved block if ((status & BLOCK_STATUS_RESERVED) != 0) { if (listmode!=2) { OALLog(L"\r\n[reserved]"); listmode=2; } OALLog(L" %d", block); block++; continue; } block++; } OALLog(L" Done\r\n"); cleanUp: if (hFMD != NULL) { FMD_Deinit(hFMD); } return; }