os/kernelhwsrv/kerneltest/e32test/lffs/tf_write.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32std.h>
    17 #include <e32std_private.h>
    18 #include <e32svr.h>
    19 #include <e32test.h>
    20 #include "randgen.h"
    21 #include "user_config.h"
    22 #include "tf_write.h"
    23 
    24 _LIT( KTestName, "TF_WRITE" );
    25 RTest test( KTestName );
    26 
    27 
    28 const TInt64 KRandomSeed1(MAKE_TINT64(0x3e000111,0xAFCBDF0F));
    29 
    30 
    31 GLDEF_C void Panic( TPanicNo aPanic )
    32 	{
    33 	User::Panic( KTestName, aPanic );
    34 	}
    35 
    36 
    37 // **********************************************************************
    38 // Implementation of the writer classes
    39 
    40 TWriteBase::TWriteBase( CWriteTest& aOwner )
    41 	: iOwner( aOwner )
    42 	{
    43 	}
    44 
    45 void TWriteBase::CheckedWrite(TInt aPos,const TDesC8& aSrc)
    46 	{
    47 	Write( aPos, aSrc );
    48 	test( iOwner.CompareAgainstFlash( aPos, aSrc ) );
    49 	}
    50 
    51 
    52 TSimpleWrite::TSimpleWrite( CWriteTest& aOwner )
    53 	: TWriteBase( aOwner ), iDrive( aOwner.Drive() )
    54 	{
    55 	}
    56 
    57 void TSimpleWrite::Write(TInt aPos,const TDesC8& aSrc)
    58 	{
    59 	TInt64	pos( aPos );
    60 //	test( KErrNone == iDrive.Write( pos, aSrc ) );
    61 	TInt rv = iDrive.Write( pos, aSrc );
    62 	if( KErrNone != rv )
    63 		{
    64 		test.Printf( _L("TBusLocalDrive::Write returned %d"), rv );
    65 		test( EFalse );
    66 		}
    67 	}
    68 
    69 
    70 	
    71 TThreadWrite::TThreadWrite( CWriteTest& aOwner )
    72 	: TWriteBase( aOwner ), iDrive( aOwner.Drive() ),
    73 	iThreadHandle( aOwner.DummyThreadHandle() )
    74 	{
    75 	}
    76 
    77 void TThreadWrite::Write(TInt aPos,const TDesC8& aSrc)
    78 	{
    79 	TInt64	pos( aPos );
    80 #if 0
    81 	test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, iThreadHandle, 0 ) );
    82 #else
    83 	test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, KLocalMessageHandle, 0 ) );
    84 #endif
    85 	}
    86 
    87 		
    88 void TThreadWrite::CheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
    89 	{
    90 	TInt64	pos( aPos );
    91 #if 0
    92 	test( KErrNone == iDrive.Write( pos, aLength, &aSrc, iThreadHandle, aDescOffset ) );
    93 #else
    94 	test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
    95 #endif
    96 	test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
    97 	}
    98 
    99 void TThreadWrite::CurrentThreadCheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
   100 	{
   101 	TInt64	pos( aPos );
   102 #if 0
   103 	test( KErrNone == iDrive.Write( pos, aLength, &aSrc, RThread().Handle(), aDescOffset ) );
   104 #else
   105 	test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
   106 #endif
   107 	test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
   108 	}
   109 
   110 // **********************************************************************
   111 // Implementation of CBlockManager
   112 
   113 CBlockManager::CBlockManager( TBusLocalDrive& aDrive, CWriteTest& aOwner )
   114 	: iDrive( aDrive ), iOwner( aOwner )
   115 	{
   116 	}
   117 
   118 CBlockManager::~CBlockManager()
   119 	{
   120 	delete[] iEraseArray;
   121 	}
   122 
   123 void CBlockManager::CreateL()
   124 	{
   125 	//
   126 	// Get size of Flash drive
   127 	//
   128 	test.Printf( _L("Reading block info...") );
   129 	TLocalDriveCapsV2Buf info;
   130     iDrive.Caps(info);
   131 	TUint flashSize = I64LOW(info().iSize);
   132 	test( 0 == I64HIGH(info().iSize));
   133 	iBlockSize = info().iEraseBlockSize;
   134 	test( 0 == (iBlockSize & 3) );
   135 	iBlockCount = flashSize / iBlockSize;
   136 	test( 0 != iBlockCount );
   137 
   138 	test.Printf( _L("Flash block size=0x%x; block count=%d\n"), iBlockSize, iBlockCount );
   139 	
   140 	iEraseArray = new(ELeave) TEraseStatus[iBlockCount];
   141 	test.Printf( _L("Erase status array created") );
   142 	}
   143 
   144 
   145 void CBlockManager::EraseBlock( TInt aBlockNumber )
   146 	{
   147 	__ASSERT_ALWAYS( aBlockNumber < iBlockCount, Panic( EPanicEraseBlockOOR ) );
   148 	__ASSERT_ALWAYS( aBlockNumber < iBlockCount, Panic( EPanicEraseBlockNeg ) );
   149 	_LIT( KEraseMsg, "Erasing block %d" );
   150 	test.Printf( KEraseMsg, aBlockNumber );
   151 	test( KErrNone == iDrive.Format( BlockAddress( aBlockNumber ), iBlockSize ) );
   152 	VerifyErased( aBlockNumber );
   153 	iEraseArray[ aBlockNumber ] = EErased;
   154 	}
   155 
   156 void CBlockManager::EraseAllBlocks()
   157 	{
   158 	_LIT( KEraseMsg, "Erasing all blocks" );
   159 	test.Printf( KEraseMsg );
   160 	for( TInt i = 0; i < iBlockCount; i++ )
   161 		{
   162 		EraseBlock( i );
   163 		}
   164 	}
   165 
   166 void CBlockManager::VerifyErased( TInt aBlockNumber )
   167 	{
   168 	TUint offset = aBlockNumber * iBlockSize;
   169 	
   170 	TBool failed = EFalse;
   171 	const TInt readBufLen = iReadBuffer.MaxLength();
   172 
   173 	for( TInt remaining = iBlockSize; remaining > 0 && !failed ;)
   174 		{
   175 		TInt r = iDrive.Read( offset, readBufLen, iReadBuffer );
   176 		if( r != KErrNone )
   177 			{
   178 			test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
   179 			test( KErrNone == r );
   180 			}
   181 		test( iReadBuffer.Length() == readBufLen );
   182 
   183 		const TUint32* p = (const TUint32*)iReadBuffer.Ptr();
   184 		for( TInt i = 0; i < readBufLen; i += 4 )
   185 			{
   186 			if( 0xFFFFFFFF != *p )
   187 				{
   188 				failed = ETrue;
   189 				test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"), 
   190 								offset+i, p[0] );
   191 				test(EFalse);
   192 				}
   193 			++p;
   194 			}
   195 		offset += readBufLen;
   196 		remaining -= readBufLen;
   197 		}
   198 	}
   199 
   200 
   201 void CBlockManager::InitialiseSequentialBlockAllocator()
   202 	//
   203 	// Clears the erase status and resets to block zero
   204 	//
   205 	{
   206 	for( TInt i = 0; i < iBlockCount; i++ )
   207 		{
   208 		iEraseArray[i] = ENotErased;
   209 		}
   210 	iNextBlock = 0;
   211 	}
   212 
   213 
   214 TInt CBlockManager::NextErasedBlock()
   215 	{
   216 	if( iNextBlock >= iBlockCount )
   217 		{
   218 		iNextBlock = 0;
   219 		}
   220 
   221 	if( ENotErased == iEraseArray[iNextBlock] )
   222 		{
   223 		EraseBlock( iNextBlock );
   224 		}
   225 	iEraseArray[iNextBlock] = ENotErased;	// assume it is going to be used
   226 	return iNextBlock;
   227 	}
   228 
   229 void CBlockManager::InitialiseDataChunkAllocator()
   230 	{
   231 	iDataBlock = NextErasedBlock();
   232 	iDataOffset = 0;
   233 	}
   234 
   235 
   236 TUint CBlockManager::NextErasedDataChunk( TInt aRequiredLength, TInt aMultiple )
   237 	//
   238 	// Request a chunk of erased flash of size aRequiredLength bytes on a
   239 	// boundary of aMultiple bytes. E,g, to allocate a buffer on 12 bytes length
   240 	// on a 32-byte boundary, aRequiredLength = 12, aMultiple=12
   241 	//
   242 	// The byte count is rounded up to a multiple of 4 bytes
   243 	//
   244 	{
   245 	aRequiredLength = (aRequiredLength + 3) & ~0x3;
   246 	
   247 	TUint chunkBase = ((iDataOffset + aMultiple - 1) / aMultiple) * aMultiple;
   248 	if( chunkBase > (TUint)iBlockSize || chunkBase + aRequiredLength > (TUint)iBlockSize )
   249 		{
   250 		iDataBlock = NextErasedBlock();
   251 		chunkBase = 0;
   252 		}
   253 	
   254 	iDataOffset = ( chunkBase + aRequiredLength + 3) & ~0x3;
   255 
   256 	return BlockAddress( iDataBlock ) + chunkBase;
   257 	}
   258 
   259 
   260 
   261 inline TInt CBlockManager::BlockCount() const
   262 	{
   263 	return iBlockCount;
   264 	}
   265 
   266 inline TInt CBlockManager::BlockSize() const
   267 	{
   268 	return iBlockSize;
   269 	}
   270 
   271 inline TInt CBlockManager::FlashSize() const
   272 	{
   273 	return iBlockSize * iBlockCount;
   274 	}
   275 
   276 inline TUint CBlockManager::BlockAddress( TInt aBlockNumber ) const
   277 	{
   278 	return (TUint)aBlockNumber * (TUint)iBlockSize;
   279 	}
   280 
   281 
   282 // **********************************************************************
   283 // Implementation of CWriteTest
   284 
   285 CWriteTest::~CWriteTest()
   286 	{
   287 	if( iDriveOpened )
   288 		{
   289 		iDrive.Disconnect();
   290 		}
   291 
   292 	delete iBlocks;
   293 	delete iSimpleWriter;
   294 	delete iThreadWriter;
   295 	}
   296 
   297 
   298 void CWriteTest::CreateL()
   299 	{
   300 	//
   301 	// Load the device drivers
   302 	//
   303 	TInt r;
   304 #ifndef SKIP_PDD_LOAD
   305 	test.Printf( _L("Loading %S\n"), &KLfsDriverName );
   306 	r = User::LoadPhysicalDevice( KLfsDriverName );
   307 	test( KErrNone == r || KErrAlreadyExists == r );
   308 #endif
   309 
   310 #ifdef UNMOUNT_DRIVE
   311 	RFs fs;
   312 	test( KErrNone == fs.Connect() );
   313 #if 0
   314 	// XXX - not EKA2
   315 	test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) );
   316 #endif
   317 	TFullName name;
   318 	fs.FileSystemName( name, KLffsLogicalDriveNumber );
   319 	if( name.Length() > 0 )
   320 		{
   321 		test.Printf( _L("Unmounting drive") );
   322 		test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) );
   323 		User::After( 2000000 );
   324 		test.Printf( _L("Drive unmounted") );
   325 		}
   326 	fs.Close();
   327 #endif
   328 
   329 	//
   330 	// Open a TBusLogicalDevice to it
   331 	//
   332 	test.Printf( _L("Opening media channel\n") );
   333 	TBool changedFlag = EFalse;
   334 	r = iDrive.Connect( KDriveNumber, changedFlag );
   335 	User::LeaveIfError( r );
   336 	iDriveOpened = ETrue;
   337 
   338 	//
   339 	// Initialise the block manager
   340 	//
   341 	iBlocks = new(ELeave) CBlockManager( iDrive, *this );
   342 	iBlocks->CreateL();
   343 
   344 	//
   345 	// Create a dummy thread that we can use to force
   346 	// other-thread write operations
   347 	//
   348 #if 0
   349 	test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, 256, KMinHeapSize, KMinHeapSize, NULL ) );
   350 #else
   351 	test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ) );
   352 #endif
   353 	test.Printf( _L("Main thread handle=%d; dummy thread handle=%d"),
   354 		RThread().Handle(), DummyThreadHandle() );
   355 
   356 	//
   357 	// Create the writer classes
   358 	//
   359 	iSimpleWriter = new(ELeave) TSimpleWrite( *this );
   360 	iThreadWriter = new(ELeave) TThreadWrite( *this );
   361 	
   362 	//
   363 	// Seed the pseudo-random number generator
   364 	//
   365 	iRandom.SetSeed( KRandomSeed1 );
   366 
   367 
   368 	test.Printf( _L("CWriteTest::CreateL complete\n") );
   369 	}
   370 
   371 
   372 TInt CWriteTest::DummyThread( TAny* /* aParam */ )
   373 	//
   374 	// Thread does nothing at all
   375 	//
   376 	{
   377 	for(;;)
   378 		{
   379 		User::WaitForAnyRequest();	// just block
   380 		}
   381 	}
   382 
   383 void CWriteTest::CreateRandomData( TDes8& aDestBuf, TInt aLength )
   384 	//
   385 	// Fills supplied descriptor with aLength bytes of pseudo-random test data
   386 	//
   387 	{
   388 	aDestBuf.SetLength( aLength );
   389 	TUint32* p = (TUint32*)aDestBuf.Ptr();
   390 	for( TInt j = aLength/4; j > 0 ; j-- )
   391 		{
   392 		*p++ = iRandom.Next();
   393 		}
   394 	
   395 	if( aLength & 0x3 )
   396 		{
   397 		TUint8* q = (TUint8*)p;
   398 		for( TInt k = aLength & 3; k > 0; k-- )
   399 			{
   400 			*q++ = (TUint8)iRandom.Next();
   401 			}
   402 		}
   403 	}
   404 
   405 
   406 TBool CWriteTest::CheckOnes( TUint aFlashOffset, TInt aLength )
   407 	//
   408 	// Checks that aLength bytes of data from offset aFlashOffset
   409 	// all contain 0xFF
   410 	//
   411 	{
   412 	TUint offset = aFlashOffset;
   413 	
   414 	TBool failed = EFalse;
   415 	const TInt readBufLen = iReadBuffer.MaxLength();
   416 
   417 	for( TInt remaining = aLength; remaining > 0 && !failed ;)
   418 		{
   419 		TInt readLen = Min( remaining, readBufLen );
   420 		TInt r = iDrive.Read( offset, readLen, iReadBuffer );
   421 		if( r != KErrNone )
   422 			{
   423 			test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
   424 			test( KErrNone == r );
   425 			}
   426 		test( iReadBuffer.Length() == readLen );
   427 
   428 		const TUint8* p = iReadBuffer.Ptr();
   429 		for( TInt i = 0; i < readLen; ++i )
   430 			{
   431 			if( 0xFF != *p )
   432 				{
   433 				failed = ETrue;
   434 				test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"), 
   435 								offset+i, p[0] );
   436 				break;
   437 				}
   438 			++p;
   439 			}
   440 		offset += readLen;
   441 		remaining -= readLen;
   442 		}
   443 	
   444 	return !failed;
   445 	}
   446 
   447 
   448 TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, TInt aLength, const TDesC8& aDes, TInt aDescOffset )
   449 	//
   450 	// Checks that the data in aDes matches that in the Flash at position
   451 	// aFlashOffset.
   452 	// The test starts at offset aDescOffset in aSampleData. aLength bytes
   453 	// are tested.
   454 	//
   455 	{
   456 	__ASSERT_ALWAYS( aDescOffset + aLength <= aDes.Length(), Panic( EPanicCompareDescOverflow ) );
   457 	TInt dataLength = aLength;
   458 	const TUint8* srcPtr = aDes.Ptr() + aDescOffset;
   459 
   460 	TUint offset = aFlashOffset;
   461 	
   462 	TBool failed = EFalse;
   463 	const TInt readBufLen = iReadBuffer.MaxLength();
   464 
   465 	while( (dataLength > 0) && !failed )
   466 		{
   467 		TInt len = Min( dataLength, readBufLen );
   468 		TInt r = iDrive.Read( offset, len, iReadBuffer );
   469 		if( r != KErrNone )
   470 			{
   471 			test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
   472 			test( KErrNone == r );
   473 			}
   474 		test( iReadBuffer.Length() == len );
   475 
   476 		if( 0 != Mem::Compare( srcPtr, len, iReadBuffer.Ptr(), len ) )
   477 			{
   478 			test.Printf( _L("... FAIL: mismatch around offset 0x%x\n"), offset );
   479 			failed = ETrue;
   480 			}
   481 		offset += len;
   482 		dataLength -= len;
   483 		srcPtr += len;
   484 		}
   485 	
   486 	return !failed;
   487 	}
   488 
   489 TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, const TDesC8& aDes )
   490 	//
   491 	// Checks that the data in aDes matches that in the Flash at position
   492 	// aFlashOffset.
   493 	// aDes->Length() bytes are tested.
   494 	//
   495 	{
   496 	return CompareAgainstFlash( aFlashOffset, aDes.Length(), aDes, 0 );
   497 	}
   498 
   499 
   500 void CWriteTest::SimpleWriteTest()
   501 	{
   502 	test.Next( _L("Simple write test, simple write function") );
   503 	DoSimpleWriteTest( *iSimpleWriter );
   504 	}
   505 
   506 void CWriteTest::SimpleThreadWriteTest()
   507 	{
   508 	test.Next( _L("Simple write test, thread write function") );
   509 	DoSimpleWriteTest( *iThreadWriter );
   510 	}
   511 
   512 
   513 void CWriteTest::DoSimpleWriteTest( MGeneralizedWrite& aWriter )
   514 	//
   515 	// Writes some random test data to the start of a block, checks that
   516 	// it is written correctly and that the source data isn't modified
   517 	//
   518 	{
   519 	TInt blockNo = iBlocks->NextErasedBlock();
   520 	TUint blockBase = iBlocks->BlockAddress( blockNo );
   521 
   522 	TBuf8<512> randomData;
   523 	CreateRandomData( randomData, randomData.MaxLength() );
   524 
   525 	TBuf8<512> randomDataDuplicate;
   526 	randomDataDuplicate.Copy( randomData );
   527 	test( randomDataDuplicate == randomData );
   528 
   529 	TBuf8<sizeof(TPtr)> ptrCopy;	// used to take copies of descriptors
   530 
   531 	//
   532 	// Write using a constant descriptor TPtrC
   533 	//
   534 	test.Printf( _L("Write using TPtrC") );
   535 	TPtrC8 ptrC( randomData );
   536 	ptrCopy.Copy( (TUint8*)&ptrC, sizeof(ptrC) );
   537 
   538 	aWriter.CheckedWrite( blockBase + 0, ptrC );
   539 
   540 	test.Printf( _L("Check descriptor not modified by write function") );
   541 	test( 0 == Mem::Compare( (TUint8*)&ptrC, sizeof(ptrC), ptrCopy.Ptr(), sizeof(ptrC) ) );
   542 
   543 	test.Printf( _L("Check data not modified by write function") );
   544 	test( randomDataDuplicate == randomData );
   545 
   546 	//
   547 	// Write using a modifiable descriptor TPtr
   548 	//
   549 	test.Printf( _L("Write using TPtr") );
   550 	TPtr8 ptr( (TUint8*)randomData.Ptr(), randomData.Length(), randomData.Length() );
   551 	ptrCopy.Copy( (TUint8*)&ptr, sizeof(ptr) );
   552 	
   553 	aWriter.CheckedWrite( blockBase + 1024, ptr );
   554 
   555 	test.Printf( _L("Check descriptor not modified by write function") );
   556 	test( 0 == Mem::Compare( (TUint8*)&ptr, sizeof(ptr), ptrCopy.Ptr(), sizeof(ptr) ) );
   557 
   558 	test.Printf( _L("Check data not modified by write function") );
   559 	test( randomDataDuplicate == randomData );
   560 
   561 	//
   562 	// Write using a modifiable descriptor TBuf
   563 	//
   564 	test.Printf( _L("Write using TBuf") );
   565 	
   566 	aWriter.CheckedWrite( blockBase + 2048, randomData );
   567 
   568 	test.Printf( _L("Check descriptor not modified by write function") );
   569 	test( ptrC.Ptr() == randomData.Ptr() );
   570 	test( 512 == randomData.Length() );
   571 	test( 512 == randomData.MaxLength() );
   572 
   573 	test.Printf( _L("Check data not modified by write function") );
   574 	test( randomDataDuplicate == randomData );
   575 
   576 	//
   577 	// Read the data back and check it matches
   578 	//
   579 	test.Printf( _L("Reading data back with TBusLocalDrive::Read") );
   580 	test( KErrNone == iDrive.Read( blockBase + 0, 512, randomDataDuplicate ) );
   581 	test( randomDataDuplicate == randomData );
   582 	test( KErrNone == iDrive.Read( blockBase + 1024, 512, randomDataDuplicate ) );
   583 	test( randomDataDuplicate == randomData );
   584 	test( KErrNone == iDrive.Read( blockBase + 2048, 512, randomDataDuplicate ) );
   585 	test( randomDataDuplicate == randomData );
   586 	}
   587 
   588 
   589 
   590 void CWriteTest::AlignedWriteTest()
   591 	{
   592 	test.Next( _L("Aligned write test, simple write function") );
   593 	DoAlignedWriteTest( *iSimpleWriter );
   594 	}
   595 
   596 void CWriteTest::AlignedThreadWriteTest()
   597 	{
   598 	test.Next( _L("Aligned write test, thread write function") );
   599 	DoAlignedWriteTest( *iThreadWriter );
   600 	}
   601 
   602 
   603 void CWriteTest::DoAlignedWriteTest( MGeneralizedWrite& aWriter )
   604 	//
   605 	// Writes data of various lengths to word-aligned addresses
   606 	//
   607 	{
   608 	iBlocks->InitialiseDataChunkAllocator();
   609 
   610 	TBuf8<512> data;	
   611 
   612 	_LIT( KWriteMsg, "  writing %d bytes @0x%x" );
   613 
   614 	test.Printf( _L("Testing small writes") );
   615 
   616 	for( TInt length = 1; length < 16; length++ )
   617 		{
   618 		CreateRandomData( data, length );
   619 		
   620 		// get a 32-byte data chunk on a word boundary
   621 		TUint offset = iBlocks->NextErasedDataChunk( 32, 4 );
   622 
   623 		test.Printf( KWriteMsg, length, offset );
   624 		aWriter.CheckedWrite( offset, data );
   625 		// check that the section after the data still contains all ones
   626 		test( CheckOnes( offset + length, 32 - length ) );
   627 		}
   628 
   629 
   630 	test.Printf( _L("Testing large writes") );
   631 	for( TInt length = 512-32; length <= 512 ; length++ )
   632 		{
   633 		CreateRandomData( data, length );
   634 		
   635 		// get a 544-byte data chunk on a word boundary
   636 		TUint offset = iBlocks->NextErasedDataChunk( 544, 4 );
   637 
   638 		test.Printf( KWriteMsg, length, offset );
   639 		aWriter.CheckedWrite( offset, data );
   640 
   641 		// check that the section after the data still contains all ones
   642 		test( CheckOnes( offset + length, 544 - length ) );
   643 		}
   644 	}
   645 
   646 
   647 
   648 
   649 void CWriteTest::UnalignedWriteTest()
   650 	{
   651 	test.Next( _L("Unaligned write test, simple write function") );
   652 	DoUnalignedWriteTest( *iSimpleWriter );
   653 	}
   654 
   655 void CWriteTest::UnalignedThreadWriteTest()
   656 	{
   657 	test.Next( _L("Unaligned write test, thread write function") );
   658 	DoUnalignedWriteTest( *iThreadWriter );
   659 	}
   660 
   661 
   662 void CWriteTest::DoUnalignedWriteTest( MGeneralizedWrite& aWriter )
   663 	//
   664 	// Tests writing to unaligned addresses. "Unaligned" here means
   665 	// addresses that are not on a word boundary.
   666 	//
   667 	{
   668 	TBuf8<32> data;
   669 
   670 	_LIT( KWriteMsg, "  writing 32 bytes @0x%x" );
   671 
   672 
   673 	for( TInt offset = 1; offset < 32; offset++ )
   674 		{
   675 		CreateRandomData( data, data.MaxLength() );
   676 		
   677 		//
   678 		// get a 64-byte data chunk on a 256-byte boundary, then
   679 		// start the write at <offset> bytes into this buffer
   680 		//
   681 		TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 256 );
   682 
   683 		test.Printf( KWriteMsg, dataChunk + offset );
   684 		aWriter.CheckedWrite( dataChunk + offset, data );
   685 
   686 		_LIT( KBeforeMsg,  " checking unused portion before data" );
   687 		test.Printf( KBeforeMsg );
   688 		test( CheckOnes( dataChunk, offset ) );
   689 
   690 		// check that the section after the data still contains all ones
   691 		_LIT( KAfterMsg, " checking unused portion after data" );
   692 		test.Printf( KAfterMsg );
   693 		test( CheckOnes( dataChunk + offset + data.Length(), 64 - offset - data.Length() ) );
   694 		}
   695 	}
   696 
   697 
   698 
   699 void CWriteTest::OffsetDescriptorAlignedWriteTest()
   700 	//
   701 	// Tests writing using an offset into the source data buffer. Writes
   702 	// are done to word-aligned destination addresses.
   703 	//
   704 	{
   705 	test.Next( _L("Offset-desc write test, aligned dest address") );
   706 
   707 	TBuf8<64> data;
   708 
   709 	_LIT( KWriteMsg, "  writing 32 bytes from offset %d to @0x%x" );
   710 
   711 //	CreateRandomData( data, data.MaxLength() );
   712 	data.SetLength(64);
   713 	for( TInt i = 0; i < 64; i++ )
   714 		{
   715 		data[i] = i;
   716 		}
   717 
   718 	for( TInt descOffset = 1; descOffset < 32; descOffset++ )
   719 		{
   720 		//
   721 		// Get a 32-byte data chunk on a word boundary.
   722 		//
   723 		TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
   724 
   725 		test.Printf( KWriteMsg, descOffset, dataChunk );
   726 		iThreadWriter->CheckedThreadWrite( dataChunk, 32, data, descOffset );
   727 
   728 		//
   729 		// Read the data back out and check it matches
   730 		//
   731 		_LIT( KReadBackMsg, "Reading back data" );
   732 		test.Printf( KReadBackMsg );
   733 		TBuf8<32> readData;
   734 		iDrive.Read( dataChunk, 32, readData );
   735 		TPtrC8 ptr( data.Ptr() + descOffset, 32 );
   736 		test( ptr == readData );
   737 		}
   738 	}
   739 
   740 
   741 void CWriteTest::OffsetDescriptorUnalignedWriteTest()
   742 	//
   743 	// This is a variation of OffsetDescriptorAlignedWriteTest that
   744 	// also writes to non-word-aligned destionation addresses.
   745 	//
   746 	{
   747 	test.Next( _L("Offset-desc write test, unaligned dest address") );
   748 
   749 	TBuf8<64> data;
   750 
   751 	_LIT( KWriteMsg, "  writing 32 bytes from offset %d to @0x%x" );
   752 
   753 	CreateRandomData( data, data.MaxLength() );
   754 
   755 	for( TInt descOffset = 1; descOffset < 32; descOffset++ )
   756 		{
   757 		for( TInt unalign = 1; unalign < 4; unalign++ )
   758 			{
   759 			//
   760 			// Get a 40-byte data chunk on a word boundary.
   761 			//
   762 			TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
   763 			TUint destOffset = dataChunk + unalign;
   764 
   765 			test.Printf( KWriteMsg, descOffset, destOffset );
   766 			iThreadWriter->CheckedThreadWrite( destOffset, 32, data, descOffset );
   767 
   768 			//
   769 			// Read the data back out and check it matches
   770 			//
   771 			_LIT( KReadBackMsg, "Reading back data" );
   772 			test.Printf( KReadBackMsg );
   773 			TBuf8<32> readData;
   774 			iDrive.Read( destOffset, 32, readData );
   775 			TPtrC8 ptr( data.Ptr() + descOffset, 32 );
   776 			test( ptr == readData );
   777 			}
   778 		}
   779 	}
   780 
   781 
   782 void CWriteTest::OffsetDescriptorCurrentThreadAlignedWriteTest()
   783 	//
   784 	// Tests writing using an offset into the source data buffer. Writes
   785 	// are done to word-aligned destination addresses. This uses the
   786 	// thread variant of the write function but passes the handle
   787 	// of this thread.
   788 	//
   789 	{
   790 	test.Next( _L("Offset-desc write test, current thread, aligned dest address") );
   791 
   792 	TBuf8<64> data;
   793 
   794 	_LIT( KWriteMsg, "  writing 32 bytes from offset %d to @0x%x" );
   795 
   796 //	CreateRandomData( data, data.MaxLength() );
   797 	data.SetLength(64);
   798 	for( TInt i = 0; i < 64; i++ )
   799 		{
   800 		data[i] = i;
   801 		}
   802 
   803 	for( TInt descOffset = 1; descOffset < 32; descOffset++ )
   804 		{
   805 		//
   806 		// Get a 32-byte data chunk on a word boundary.
   807 		//
   808 		TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
   809 
   810 		test.Printf( KWriteMsg, descOffset, dataChunk );
   811 		iThreadWriter->CurrentThreadCheckedThreadWrite( dataChunk, 32, data, descOffset );
   812 
   813 		//
   814 		// Read the data back out and check it matches
   815 		//
   816 		_LIT( KReadBackMsg, "Reading back data" );
   817 		test.Printf( KReadBackMsg );
   818 		TBuf8<32> readData;
   819 		iDrive.Read( dataChunk, 32, readData );
   820 		TPtrC8 ptr( data.Ptr() + descOffset, 32 );
   821 		test( ptr == readData );
   822 		}
   823 	}
   824 
   825 
   826 void CWriteTest::OffsetDescriptorCurrentThreadUnalignedWriteTest()
   827 	//
   828 	// This is a variation of OffsetDescriptorCurrentThreadAlignedWriteTest
   829 	// that also writes to non-word-aligned destionation addresses.
   830 	//
   831 	{
   832 	test.Next( _L("Offset-desc write test, current thread, unaligned dest address") );
   833 
   834 	TBuf8<64> data;
   835 
   836 	_LIT( KWriteMsg, "  writing 32 bytes from offset %d to @0x%x" );
   837 
   838 	CreateRandomData( data, data.MaxLength() );
   839 
   840 	for( TInt descOffset = 1; descOffset < 32; descOffset++ )
   841 		{
   842 		for( TInt unalign = 1; unalign < 4; unalign++ )
   843 			{
   844 			//
   845 			// Get a 40-byte data chunk on a word boundary.
   846 			//
   847 			TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
   848 			TUint destOffset = dataChunk + unalign;
   849 
   850 			test.Printf( KWriteMsg, descOffset, destOffset );
   851 			iThreadWriter->CurrentThreadCheckedThreadWrite( destOffset, 32, data, descOffset );
   852 
   853 			//
   854 			// Read the data back out and check it matches
   855 			//
   856 			_LIT( KReadBackMsg, "Reading back data" );
   857 			test.Printf( KReadBackMsg );
   858 			TBuf8<32> readData;
   859 			iDrive.Read( destOffset, 32, readData );
   860 			TPtrC8 ptr( data.Ptr() + descOffset, 32 );
   861 			test( ptr == readData );
   862 			}
   863 		}
   864 	}
   865 
   866 
   867 
   868 void CWriteTest::JoinedWriteTest()
   869 	//
   870 	// Makes two consecutive writes. Checks that the complete
   871 	// data block was written correctly. The data is written within
   872 	// a 64-byte window and the join position is moved along to each
   873 	// possible location
   874 	{
   875 	
   876 	test.Next( _L("Joined write test, simple writes") );
   877 	
   878 	//
   879 	// Reinitialise the chunk allocator
   880 	//
   881 	iBlocks->InitialiseDataChunkAllocator();
   882 	
   883 	for( TInt join = 1; join < 63; join++ )
   884 		{
   885 		TBuf8<64> fullData;
   886 		CreateRandomData( fullData, fullData.MaxLength() );
   887 		
   888 		//
   889 		// Create two TPtrC8s to the two parts of the data
   890 		//
   891 		TPtrC8 first( fullData.Ptr(), join );
   892 		TPtrC8 second( fullData.Ptr() + join, fullData.MaxLength() - join );
   893 		__ASSERT_ALWAYS( first.Length() + second.Length() == 64, Panic( EPanicJoinMaths ) );
   894 
   895 		//
   896 		// Get a location in the Flash to write to
   897 		//
   898 		TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
   899 
   900 		//
   901 		// Write the two halves of the data
   902 		//
   903 		_LIT( KWriteMsg, "  writing %d bytes @ 0x%x and %d bytes @ 0x%x" );
   904 		test.Printf( KWriteMsg, first.Length(), dataChunk,
   905 								second.Length(), dataChunk + first.Length() );
   906 		test( KErrNone == iDrive.Write( dataChunk, first ) );
   907 		test( KErrNone == iDrive.Write( dataChunk + first.Length(), second ) );
   908 
   909 		//
   910 		// Compare the data
   911 		//
   912 		_LIT( KCompareMsg, "  comparing data against Flash" );
   913 		test.Printf( KCompareMsg );
   914 		test( CompareAgainstFlash( dataChunk, fullData ) );
   915 		}
   916 	}
   917 
   918 
   919 void CWriteTest::JoinedThreadWriteTest()
   920 	//
   921 	// Makes two consecutive writes. Checks that the complete
   922 	// data block was written correctly. The data is written within
   923 	// a 64-byte window and the join position is moved along to each
   924 	// possible location
   925 	//
   926 	// This is similar to JoinedWriteTest except that the thread write
   927 	// function is used with a descriptor offset to chop up the
   928 	// source data
   929 	//
   930 	{
   931 	
   932 	test.Next( _L("Joined write test, thread writes") );
   933 	
   934 	//
   935 	// Reinitialise the chunk allocator
   936 	//
   937 	iBlocks->InitialiseDataChunkAllocator();
   938 	
   939 	for( TInt join = 1; join < 63; join++ )
   940 		{
   941 		TBuf8<64> fullData;
   942 		CreateRandomData( fullData, fullData.MaxLength() );
   943 		
   944 		//
   945 		// Get a location in the Flash to write to
   946 		//
   947 		TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
   948 
   949 		//
   950 		// Write the two halves of the data
   951 		//
   952 		_LIT( KWriteMsg, "  writing %d bytes @ 0x%x and %d bytes @ 0x%x" );
   953 		test.Printf( KWriteMsg, join, dataChunk, 64 - join, dataChunk + join );
   954 #if 0
   955 		test( KErrNone == iDrive.Write( dataChunk, join, &fullData, DummyThreadHandle(), 0 ) );
   956 		test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, DummyThreadHandle(), join ) );
   957 #else
   958 		test( KErrNone == iDrive.Write( dataChunk, join, &fullData, KLocalMessageHandle, 0 ) );
   959 		test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, KLocalMessageHandle, join ) );
   960 #endif
   961 
   962 
   963 		//
   964 		// Compare the data
   965 		//
   966 		_LIT( KCompareMsg, "  comparing data against Flash" );
   967 		test.Printf( KCompareMsg );
   968 		test( CompareAgainstFlash( dataChunk, fullData ) );
   969 		}
   970 	}
   971 
   972 
   973 
   974 void CWriteTest::SingleBitOverwriteTest()
   975 	//
   976 	// Tests overwriting single bits within a byte. a 32-byte
   977 	// section of Flash is filled with data, with one byte initially
   978 	// 0xFF. A bit is then written to zero and the whole data block
   979 	// is verified.
   980 	//
   981 	{
   982 	test.Next( _L("Single bit overwrite test") );
   983 
   984 	iBlocks->InitialiseDataChunkAllocator();
   985 
   986 	for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
   987 		{
   988 		for( TInt testBitNumber = 0; testBitNumber < 8; testBitNumber++ )
   989 			{
   990 			TBuf8<32> data;
   991 			CreateRandomData( data, data.MaxLength() );
   992 			data[ testByteOffset ] = 0xFF;	// force test byte to 0xFF
   993 
   994 			TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
   995 			
   996 			_LIT( KWriteMsg, "writing test data @0x%x, test byte offset=%d; test bit #%d");
   997 			test.Printf( KWriteMsg, flashOffset, testByteOffset, testBitNumber );
   998 
   999 			iSimpleWriter->CheckedWrite( flashOffset, data );
  1000 
  1001 			// clear the test bit
  1002 			TBuf8<1> byte;
  1003 			byte.SetLength(1);
  1004 			byte[0] = ~(1 << testBitNumber);
  1005 			data[ testByteOffset ] = byte[0];
  1006 			
  1007 			iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
  1008 
  1009 			// check that the contents of the Flash matches the buffer
  1010 			test( CompareAgainstFlash( flashOffset, data ) );
  1011 			}
  1012 		}
  1013 	}
  1014 
  1015 void CWriteTest::TwoBitOverwriteTest()
  1016 	//
  1017 	// Tests overwriting two bits within a byte. a 32-byte
  1018 	// section of Flash is filled with data, with one byte initially
  1019 	// 0xFF. Two bits are then written to zero and the whole data block
  1020 	// is verified.
  1021 	//
  1022 	{
  1023 	static const TUint pattConv[16] =
  1024 		{
  1025 		// used to create a string representation of binary value
  1026 		0x0000, 0x0001, 0x0010, 0x0011, 0x0100, 0x0101, 0x0110, 0x0111,
  1027 		0x1000, 0x1001, 0x1010, 0x1011, 0x1100, 0x1101, 0x1110, 0x1111
  1028 		};
  1029 	test.Next( _L("Two bit overwrite test") );
  1030 
  1031 	for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
  1032 		{
  1033 		for( TInt testBitJ = 0; testBitJ < 7; testBitJ++ )
  1034 			{
  1035 			for( TInt testBitK = testBitJ+1; testBitK < 8; testBitK++ )
  1036 				{
  1037 				TBuf8<32> data;
  1038 				CreateRandomData( data, data.MaxLength() );
  1039 				data[ testByteOffset ] = 0xFF;	// force test byte to 0xFF
  1040 
  1041 				TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
  1042 				
  1043 				TUint8 testPattern = ~((1 << testBitJ) | (1 << testBitK));
  1044 
  1045 				_LIT( KWriteMsg, "writing test data @0x%x, test byte offset=%d; test pattern = %04x%04x");
  1046 				test.Printf( KWriteMsg, flashOffset, testByteOffset, 
  1047 							pattConv[ testPattern >> 4 ], pattConv[ testPattern&0xF ] );
  1048 
  1049 				iSimpleWriter->CheckedWrite( flashOffset, data );
  1050 
  1051 				TBuf8<1> byte;
  1052 				byte.SetLength(1);
  1053 				byte[0] = testPattern;
  1054 				data[ testByteOffset ] = testPattern;
  1055 				
  1056 				iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
  1057 
  1058 				// check that the contents of the Flash matches the buffer
  1059 				test( CompareAgainstFlash( flashOffset, data ) );
  1060 				}
  1061 			}
  1062 		}
  1063 	}
  1064 
  1065 
  1066 void CWriteTest::RunSimulationTest()
  1067 	//
  1068 	// A simulation of the way the LFFS filesystem will use a Flash block
  1069 	// Alternately writes 24 bytes to bottom of block, 512 bytes to top,
  1070 	// clears a bit in the 24-byte block. Repeats until block is full.
  1071 	//
  1072 	{
  1073 	test.Next( _L("Simulation test") );
  1074 
  1075 	TUint blockBase = iBlocks->BlockAddress( iBlocks->NextErasedBlock() );
  1076 
  1077 	TUint lowAddress = blockBase;
  1078 	TUint highAddress = blockBase + iBlocks->BlockSize() - 512;
  1079 
  1080 	TBuf8<24> lowData;
  1081 	TBuf8<512> highData;
  1082 	TPtrC8 overwritePtr( lowData.Ptr(), 1 );
  1083 
  1084 	while( lowAddress + 24 < highAddress )
  1085 		{
  1086 		CreateRandomData( lowData, lowData.MaxLength() );
  1087 		CreateRandomData( highData, highData.MaxLength() );
  1088 		lowData[0] = 0xE7;	// just some non-0xFF value
  1089 
  1090 		_LIT( KWriteMsg, "Writing block size 24 @ 0x%x; block size 512 @ 0x%x" );
  1091 		test.Printf( KWriteMsg, lowAddress, highAddress );
  1092 
  1093 		iSimpleWriter->CheckedWrite( lowAddress, lowData );
  1094 		iSimpleWriter->Write( highAddress, highData );
  1095 
  1096 		// Overwrite the byte
  1097 		lowData[0] = 0xA7;
  1098 		iSimpleWriter->Write( lowAddress, overwritePtr );
  1099 
  1100 		test( CompareAgainstFlash( lowAddress, lowData ) );
  1101 		test( CompareAgainstFlash( highAddress, highData ) );
  1102 
  1103 		lowAddress += lowData.Length();
  1104 		highAddress -= highData.Length();
  1105 		}
  1106 	}
  1107 
  1108 
  1109 
  1110 void CWriteTest::DoTests()
  1111 	//
  1112 	// Main test dispatcher
  1113 	//
  1114 	{
  1115 	test.Next( _L("Erasing all blocks") );
  1116 	iBlocks->InitialiseSequentialBlockAllocator();
  1117 	iBlocks->EraseAllBlocks();
  1118 
  1119 	//
  1120 	// Basic tests that we can write data correctly without corrupting
  1121 	// the source buffer
  1122 	//
  1123 	SimpleWriteTest();
  1124 	SimpleThreadWriteTest();
  1125 
  1126 	//
  1127 	// Test aligned writes of various lengths
  1128 	//
  1129 	AlignedWriteTest();
  1130 	AlignedThreadWriteTest();
  1131 
  1132 	//
  1133 	// Test writing to unaligned locations
  1134 	//
  1135 	UnalignedWriteTest();
  1136 	UnalignedThreadWriteTest();
  1137 
  1138 	//
  1139 	// Test writes with offset into source desriptor
  1140 	//
  1141 	OffsetDescriptorCurrentThreadAlignedWriteTest();
  1142 	OffsetDescriptorCurrentThreadUnalignedWriteTest();
  1143 	OffsetDescriptorAlignedWriteTest();
  1144 	OffsetDescriptorUnalignedWriteTest();
  1145 
  1146 	//
  1147 	// Test two consecutive writes
  1148 	//
  1149 	JoinedWriteTest();
  1150 	JoinedThreadWriteTest();
  1151 
  1152 	//
  1153 	// Test that we can overwrite bits
  1154 	//
  1155 	SingleBitOverwriteTest();
  1156 	TwoBitOverwriteTest();
  1157 
  1158 	//
  1159 	// A simulation test of LFFS usage
  1160 	//
  1161 	RunSimulationTest();
  1162 	}
  1163 
  1164 
  1165 
  1166 
  1167 
  1168 
  1169 
  1170 
  1171 
  1172 
  1173 TInt E32Main()
  1174 	{
  1175 	test.Title();
  1176 	test.Start(_L("Testing media read operations"));
  1177 
  1178 	CWriteTest writeTest;
  1179 	TRAPD( ret, writeTest.CreateL() );
  1180 	test( KErrNone == ret );
  1181 	writeTest.DoTests();
  1182 	test.End();
  1183 
  1184 	return 0;
  1185 	}