diff -r 0ffb4e86fcc9 -r a179b74831c9 kerneltest/e32test/mediaext/d_nfe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/mediaext/d_nfe.cpp Thu Aug 19 11:14:22 2010 +0300 @@ -0,0 +1,1781 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\mediext\d_nfe.cpp +// +// + +#include +#include +#include +#include "nfe.h" + +#if defined(_DEBUG) +// #define TRACE_ENABLED +#define TRACE_ENABLED //*test* +#else +#endif + +#if defined(TRACE_ENABLED) +#define __KTRACE_PRINT(p) {p;} +#else +#define __KTRACE_PRINT(p) +#endif + + + + +// Variant parameters for test Media Extension Driver + + +const TInt KNfeThreadPriority = 24; // same as file server +const TInt KNfeDiskOpReady = 100; //100% +//const TInt KNfeDiskOpStart = 0; //0% + +_LIT(KPddName, "Media.NFE"); +#define NFE_DRIVENAME "NFE" +#define NFE_NUMMEDIA 1 + +// Define the array of local drives which we're attaching to +__ASSERT_COMPILE(sizeof(TNfeDeviceInfo) <= 256); // KMaxQueryDeviceLength + +// Define the array of local code-paging drives which we're attaching to +#ifdef __DEMAND_PAGING__ + __ASSERT_COMPILE(NFE_PAGEDRIVECOUNT <= TNfeDeviceInfo::ENfeMaxPartitionEntries); + __ASSERT_COMPILE(NFE_DRIVECOUNT >= NFE_PAGEDRIVECOUNT); + #define SECTOR_SHIFT 9 +#endif // #ifdef __DEMAND_PAGING__ + + + + +class DPrimaryMediaExt : public DPrimaryMediaBase + { +public: + DPrimaryMediaExt(TInt aInstance); +public: + TInt iInstance; + TDfcQue iNfeDfcQ; + }; + + + +// Get the number of drives in the drive array belonging to this instance +TInt DriveCount(TInt aInstance) + { + static const TInt NfeInstanceDriveCounts[NFE_INSTANCE_COUNT]={NFE_INSTANCE_DRIVE_COUNTS}; + return NfeInstanceDriveCounts[aInstance]; + } + +// Get a pointer to the first drive in the drive array belonging to this instance +const TInt* DriveList(TInt aInstance) + { + static const TInt NfeDriveNumbers[NFE_DRIVECOUNT]={NFE_DRIVELIST}; + TInt driveListOffset = 0; + for (TInt n=0; n= 0 && aDriveLetter <= 25 ? aDriveLetter +'A' : '?'; + } + +#ifdef __DEMAND_PAGING__ + // Get the number of drives in the paged drive array belonging to this instance + TInt PageDriveCount(TInt aInstance) + { + #if NFE_PAGEDRIVECOUNT > 0 + static const TInt NfeInstancePageDriveCounts[NFE_INSTANCE_COUNT]={NFE_INSTANCE_PAGEDRIVE_COUNTS}; + return NfeInstancePageDriveCounts[aInstance]; + #else + return 0; + #endif + } + + // Get a pointer to the first drive in the paged drive array belonging to this instance + const TInt* PageDriveList(TInt aInstance) + { + #if NFE_PAGEDRIVECOUNT > 0 + static const TInt NfePageDriveNumbers[NFE_PAGEDRIVECOUNT]={NFE_PAGEDRIVELIST}; + TInt driveListOffset = 0; + for (TInt n=0; n 0 + static const TInt NfeInstancePagingType[NFE_INSTANCE_COUNT]={NFE_INSTANCE_PAGING_TYPE}; + return NfeInstancePagingType[aInstance]; + #else + return 0; + #endif + } + + // get the instance of the swap drive + TInt SwapInstance() + { + for (TInt i=0; iDoCreate(aMediaId); + + if (r == KErrNone) + pD->OpenMediaDriverComplete(KErrNone); + + return r; + } + +TInt DPhysicalDeviceMediaNFE::Validate(TInt aDeviceType, const TDesC8* /*anInfo*/, const TVersion& aVer) + { + TInt r; + if (!Kern::QueryVersionSupported(iVersion,aVer)) + r = KErrNotSupported; + else if (aDeviceType == MEDIA_DEVICE_NFE) + return r = KErrNone; + else + r = KErrNotSupported; + +// __KTRACE_PRINT(Kern::Printf("DPhysicalDeviceMediaNFE::Validate() aDeviceType %d NfeDeviceType %d r %d", aDeviceType, MEDIA_DEVICE_NFE, r)); + return r; + } + +TInt DPhysicalDeviceMediaNFE::Info(TInt aFunction, TAny*) +// +// Return the priority of this media driver +// + { +// __KTRACE_PRINT(Kern::Printf(": DPhysicalDeviceMediaNFE::Info()")); + + if (aFunction==EPriority) + return KMediaDriverPriorityNormal; + + if (aFunction==EMediaDriverPersistent) + return KErrNone; + + return KErrNotSupported; + } + +DMediaDriverNFE::DMediaDriverNFE(TInt aMediaId) : + DMediaDriverExtension(aMediaId), + iInstance(((DPrimaryMediaExt*) iPrimaryMedia)->iInstance), + iIdleTimer(IdleTimerCallBack,this), + iTimerDfc(TimerDfcFunction,this,2), + iDriveList (DriveList(iInstance)), + iDriveLetterList (DriveLetterList(iInstance)) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DMediaDriverNFE()", iInstance)); + iInfo.iDriveCount = DriveCount(iInstance); + + __ASSERT_ALWAYS(Kern::RoundToPageSize(1) == KPageSize, NFE_FAULT()); + + // Align the buffer to a page boundary to improve efficiency for paging requests + iBuffer = &iNonPageAlignedBuffer[0]; + iBuffer = (TUint8*) ((((TUint32) &iNonPageAlignedBuffer[0]) + KPageSize-1) & ~(KPageSize-1)); + } + +DMediaDriverNFE::~DMediaDriverNFE() +// +// Destructor. +// + { + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::~DMediaDriverNFE()", iInstance)); + + TInt i; + for (i=0; iDelete(); + delete property; + } + property = (RPropertyRef*) iInfo.iDrives[i].iToUiProperty; + if (property) + { + property->Delete(); + delete property; + } + property = (RPropertyRef*) iInfo.iDrives[i].iProgressToUiProperty; + if (property) + { + property->Delete(); + delete property; + } + } + + for (i=0; iAttach(KNfeUID, aKey); + if (r != KErrNone) + return r; + + static _LIT_SECURITY_POLICY_PASS(KPassPolicy); + r = aProperty->Define( RProperty::EInt, KPassPolicy, KPassPolicy ); + if (r != KErrNone && r != KErrAlreadyExists) + return r; + return KErrNone; + } + +TInt DMediaDriverNFE::DoCreate(TInt /*aMediaId*/) +// +// Create the media driver. +// + { + __KTRACE_PRINT(Kern::Printf("NFE%d: TInt DMediaDriverNFE::DoCreate()", iInstance)); + + // Associate the idle timer DFC with our thread + iTimerDfc.SetDfcQ(iPrimaryMedia->iDfcQ); + + // Publish & Subscribe stuff - used to initiate an encryption pass from the test app + static _LIT_SECURITY_POLICY_PASS(KPassPolicy); + TInt r; + TInt i; + + TInt swapInstance = KErrNotFound; +#if defined (__DEMAND_PAGING__) + swapInstance = SwapInstance(); +#endif + + // ************************************************************************************** + // Set up P&S publishers so we can publish the status for our drives + // ************************************************************************************** + __KTRACE_PRINT(Kern::Printf("NFE%d: Setting up StatusToUi, ToUi, ProgressToUi P&S publisher & FromUi P&S observer", iInstance)); + + for (i = 0; iiDfcQ,2); + if (observer.iPropertyDfc == NULL) + return KErrNoMemory; + + r = observer.iProperty.Attach(KNfeUID, NFE_KEY(driveLetter, KNfeToThreadKey)); + if (r != KErrNone) + return r; + r = observer.iProperty.Define( + RProperty::EInt, + KPassPolicy, + KPassPolicy); + if (r != KErrNone && r != KErrAlreadyExists) + return r; + + r = observer.iProperty.Subscribe(*observer.iPropertySubsRequest); + if (r != KErrNone) + return r; + } + + // ************************************************************************************** + // If this instance owns the swap partition, + // set up P&S listeners so we can get status notification events from the other drives + // ************************************************************************************** + __KTRACE_PRINT(Kern::Printf("NFE%d: Setting up StatusToUi P&S observer", iInstance)); + + for (i = 0; i < (iInstance == swapInstance ? NFE_DRIVECOUNT : -1); i++) + { + __KTRACE_PRINT(Kern::Printf("NFE%d:drive index %d", iInstance, i)); + __KTRACE_PRINT(Kern::Printf("NFE%d:drive letter %c", iInstance, (TInt) DriveLetterToAscii(DriveLetter(i)))); + + // no point setting up P&S for the swap drive + if (DriveLetter(i) == -1) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: i %d, Skipping StatusToUi P&S observer for swap partition", iInstance, i)); + continue; + } + + __KTRACE_PRINT(Kern::Printf("NFE%d: i %d, Setting up StatusToUi P&S observer for drive %c", iInstance, i, (TInt) DriveLetterToAscii(DriveLetter(i)))); + TPropertyObserver& observer = iStatusToUiPropertyObserver[i]; + observer.iDriveIndex = i; + observer.iMediaExt = this; + observer.iPropertySubsRequest = new TPropertySubsRequest(TPropertyObserver::PropertySubsCompleteFn, &observer); + if (observer.iPropertySubsRequest == NULL) + return KErrNoMemory; + + observer.iPropertyDfc = new TDfc(StatusToUiPropertyDfcFunction,&observer,iPrimaryMedia->iDfcQ,2); + if (observer.iPropertyDfc == NULL) + return KErrNoMemory; + + r = observer.iProperty.Attach(KNfeUID, NFE_KEY(DriveLetter(i), KNfeStatusToUiKey)); + if (r != KErrNone) + return r; + r = observer.iProperty.Define( + RProperty::EInt, + KPassPolicy, + KPassPolicy); + if (r != KErrNone && r != KErrAlreadyExists) + return r; + + r = observer.iProperty.Subscribe(*observer.iPropertySubsRequest); + if (r != KErrNone) + return r; + } + + return(KErrNone); + } + +void DMediaDriverNFE::TPropertyObserver::Close() + { + iProperty.Close(); + delete iPropertyDfc; + iPropertyDfc = NULL; + delete iPropertySubsRequest; + iPropertySubsRequest = NULL; + } + +void DMediaDriverNFE::TPropertyObserver::PropertySubsCompleteFn(TAny* aPtr, TInt /*aReason*/) + { + TPropertyObserver* self = (TPropertyObserver*) aPtr; + // Queue a DFC to ensure we're running in the correct thread + self->iPropertyDfc->Enque(); + } + +void DMediaDriverNFE::FromUiPropertyDfcFunction(TAny* aObserver) + { + TPropertyObserver& observer = *(TPropertyObserver*) aObserver; + observer.iMediaExt->FromUiPropertyDfc(observer); + } + +void DMediaDriverNFE::FromUiPropertyDfc(TPropertyObserver& aObserver) + { + // Get the value of request from the UI + TInt err = aObserver.iProperty.Get(aObserver.iValue); + + TInt r = aObserver.iProperty.Subscribe(*aObserver.iPropertySubsRequest); + __ASSERT_ALWAYS(r == KErrNone, NFE_FAULT()); + + TInt driveLetter = iDriveLetterList[aObserver.iDriveIndex]; + + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::FromUiPropertyDfc() cmd %d driveLetter %c", + iInstance, aObserver.iValue, (TInt) DriveLetterToAscii(driveLetter))); + + // is this our drive letter ? + TInt driveCount = DriveCount(iInstance); + TNfeDriveInfo* driveInfo = NULL; + + for (TInt i=0; iiLocalDriveNum)); + + __ASSERT_ALWAYS(driveInfo->iProgressToUiProperty, NFE_FAULT()); + ((RPropertyRef*) (driveInfo->iProgressToUiProperty))->Set(0); + // Wake up the possibly waiting client, whether or not the request + // was successfull. + ((RPropertyRef*) (driveInfo->iToUiProperty))->Set( err ); // Return value ignored + break; + } + } + + + __KTRACE_PRINT(Kern::Printf("NFE%d: err %d aObserver.iValue %d swap %x swap state %d", iInstance, err, aObserver.iValue, GetSwapDrive(), GetSwapDrive() ? GetSwapDrive()->Status() : -1)); + + if (err == KErrNone && aObserver.iValue == ENfeEncryptDisk && driveInfo != NULL) + { + if (driveInfo->Status() == ENfeDecrypted) + { + SetStatus(*driveInfo, ENfeEncrypting); + StartEncrypting(); + } + } + if (err == KErrNone && aObserver.iValue == ENfeDecryptDisk && driveInfo != NULL) + { + if (driveInfo->Status() == ENfeEncrypted) + { + SetStatus(*driveInfo, ENfeDecrypting); + StartDecrypting(); + } + } + } + + +void DMediaDriverNFE::StatusToUiPropertyDfcFunction(TAny* aObserver) + { + TPropertyObserver& observer = *(TPropertyObserver*) aObserver; + observer.iMediaExt->StatusToUiPropertyDfc(observer); + } + +void DMediaDriverNFE::StatusToUiPropertyDfc(TPropertyObserver& aObserver) + { + // Get the value of request from the UI + TInt err = aObserver.iProperty.Get(aObserver.iValue); + + TInt r = aObserver.iProperty.Subscribe(*aObserver.iPropertySubsRequest); + __ASSERT_ALWAYS(r == KErrNone, NFE_FAULT()); + + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::StatusToUiPropertyDfc() status %d driveLetter %c", + iInstance, aObserver.iValue, DriveLetter(aObserver.iDriveIndex) >=0 ? DriveLetter(aObserver.iDriveIndex)+'A' : '?')); + + + __KTRACE_PRINT(Kern::Printf("NFE%d: err %d aObserver.iValue %d swap %x swap state %d", iInstance, err, aObserver.iValue, GetSwapDrive(), GetSwapDrive() ? GetSwapDrive()->Status() : -1)); + + if (err == KErrNone && (aObserver.iValue == ENfeEncrypted || aObserver.iValue == ENfeEncrypting)) + { + // If any drive is being or is already encrypted then we have to encrypt the swap partition... + TNfeDriveInfo* diSwap = GetSwapDrive(); + if (diSwap != NULL && diSwap->Status() == ENfeDecrypted) + { + SetStatus(*diSwap, ENfeEncrypting); + StartEncrypting(); + } + } + } + + +void DMediaDriverNFE::Close() + { + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::Close()", iInstance)); + DMediaDriverExtension::Close(); + } + + +void DMediaDriverNFE::SetStatus(TNfeDriveInfo& aDi, TNfeDiskStatus aStatus) + { + if (aStatus != aDi.Status()) + { + aDi.SetStatus(aStatus); + __KTRACE_PRINT(Kern::Printf("NFE%d: SetStatus = %s", iInstance, DriveStatus(aDi.Status()))); + } + } + +void TNfeDriveInfo::SetStatus(TNfeDiskStatus aStatus) + { + iStatus = aStatus; + if (IsUDADrive()) + { + // Update the status pub&sub variable for UI + __ASSERT_ALWAYS(iStatusToUiProperty, NFE_FAULT()); + ((RPropertyRef*) iStatusToUiProperty)->Set(aStatus); + } + } + + + + +TInt DMediaDriverNFE::Request(TLocDrvRequest& aReq) + { +// __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DoRequest() : Req %d drv %d flags %x pos %lx len %lx", iInstance, reqId, aReq.Drive()->iDriveNumber, aReq.Flags(), aReq.Pos(), aReq.Length())); + + TInt r = KErrNotSupported; + + TInt reqId = aReq.Id(); + TNfeDriveInfo& di = iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)]; + + switch (reqId) + { +#if defined(__DEMAND_PAGING__) + case DMediaPagingDevice::ERomPageInRequest: + BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_NFE,&aReq); + r=HandleRead(aReq); + break; + + case DMediaPagingDevice::ECodePageInRequest: + BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_NFE,&aReq); + r=HandleRead(aReq); + break; + +#endif // __DEMAND_PAGING__ + + case DLocalDrive::ERead: + r=HandleRead(aReq); + break; + + case DLocalDrive::EWrite: + r=HandleWrite(aReq); + break; + + case DLocalDrive::ECaps: + r = HandleCaps(aReq); + break; + + case DLocalDrive::EFormat: + r = HandleFormat(aReq); + break; + + // API used by T_NFE to query state etc. + case DLocalDrive::EQueryDevice: + switch((TInt) aReq.iArg[0]) + { + case EQueryNfeDeviceInfo: + { + TNfeDeviceInfo& deviceInfo = *(TNfeDeviceInfo*) aReq.RemoteDes(); + iInfo.iMediaSizeInBytes = iTotalSizeInBytes; + deviceInfo = iInfo; + + r = KErrCompletion; + break; + } + case RLocalDrive::EQueryFinaliseDrive: + { +// TLocalDriveFinaliseInfo& finaliseInfo = *(TLocalDriveFinaliseInfo*) aReq.RemoteDes(); +// __KTRACE_PRINT(Kern::Printf("NFE%d: EQueryFinaliseDrive iMode %d", iInstance, finaliseInfo.iMode)); + + // write to boot sector to indicate that the drive has ben finalised + WriteEncryptionStatusToBootSector(di, ETrue); + } + default: + r = KErrNotSupported; + break; + } + break; + + default: + r = ForwardRequest(aReq); + break; + } + +// __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DoRequest() : ret: %d", iInstance, r)); + + if (!di.iDriveFinalised && iBusy) + { + // Restart the idle timer after processing a request + iIdleTimer.Cancel(); + iTimerDfc.Cancel(); + iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval)); + } + + return r; + } + +/** +PartitionInfo() + + Reads the partition information from the attached drive(s). + Note: this method is also called when a removable card is removed, so can + be used to detect a memory card insertions/removals. Assumes the swap + partition is encrypted if any encrypted FAT drives are found +*/ +TInt DMediaDriverNFE::PartitionInfo(TPartitionInfo& aInfo) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::PartitionInfo()", iInstance)); + + TInt r = DoDrivePartitionInfo(aInfo); + __KTRACE_PRINT(Kern::Printf("NFE%d: DoDrivePartitionInfo() r %d", iInstance, r)); + if (r != KErrNone) + return r; + + __KTRACE_PRINT(Kern::Printf("NFE%d: *** Slave drives partition info ***", iInstance)); + __KTRACE_PRINT(Kern::Printf("NFE%d: iMediaSizeInBytes %lx", iInstance, aInfo.iMediaSizeInBytes)); + __KTRACE_PRINT(Kern::Printf("NFE%d: iPartitionCount %d", iInstance, aInfo.iPartitionCount)); + __KTRACE_PRINT(Kern::Printf("NFE%d: ", iInstance)); + + TInt i; + + __ASSERT_DEBUG(aInfo.iPartitionCount <= TNfeDeviceInfo::ENfeMaxPartitionEntries, NFE_FAULT()); + for (i=0; i slaveCapsBuf; + TLocalDriveCapsV6& slaveCaps = *(TLocalDriveCapsV6*) slaveCapsBuf.Ptr(); + slaveCapsBuf.SetMax(); + slaveCapsBuf.FillZ(); + TInt r = Caps(aReq.Drive()->iDriveNumber, slaveCapsBuf); + if (r != KErrNone) + return r; + +#ifdef COMPOSITE_DRIVES + TInt driveNum = aReq.Drive()->iDriveNumber; + TInt driveIndex = DriveIndex(driveNum); + if (iInfo.iDrives[driveIndex].iCompositeSize) + slaveCaps.iSize = iInfo.iDrives[driveIndex].iCompositeSize; +#endif + + // copy slave caps to returned caps + TLocalDriveCapsV6& caps = *(TLocalDriveCapsV6*)aReq.RemoteDes(); + caps = slaveCaps; + + // set the paging flags +#ifdef __DEMAND_PAGING__ + TLocDrv& drive = *aReq.Drive(); + if (drive.iPrimaryMedia->iPagingMedia) + caps.iMediaAtt|=KMediaAttPageable; + if (drive.iPagingDrv) + caps.iDriveAtt|=KDriveAttPageable; +#endif // __DEMAND_PAGING__ + + return KErrCompletion; + } + + +/** +AdjustRequest() - + +Adjusts position & length if a request crosses these boundaries: +- the start of the partition (if RLocalDrive::ELocDrvWholeMedia set) +- the current encrytion point (iEncryptEndPos) N.B. this will point to the end of the partition + if the drive is fully encrypted + +For composite drives, it also adjusts the position, length & drive number as appropriate to cater for +crossing partition boundaries + +returns ETrue if buffer needs encrypting/decrypting +*/ + +TBool DMediaDriverNFE::AdjustRequest(TNfeDriveInfo*& aDriveInfo, TInt64& aCurrentPos, TInt64& aCurrentLen) + { +#ifdef COMPOSITE_DRIVES + while (aCurrentPos >= aDriveInfo->iEntry.iPartitionLen) + { + aCurrentPos-= aDriveInfo->iEntry.iPartitionLen; + aDriveInfo++; + } + if (aCurrentPos + aCurrentLen > aDriveInfo->iEntry.iPartitionLen) + aCurrentLen = aDriveInfo->iEntry.iPartitionLen - aCurrentPos; +#endif + + // do we need to encrypt/decrypt this buffer ? + TBool encodeBuffer = EFalse; + + if ((aDriveInfo->Status() == ENfeEncrypted) || aDriveInfo->Status() == ENfeEncrypting) + { +// __ASSERT_DEBUG(aDriveInfo->iEncryptEndPos <= aDriveInfo->iEntry.iPartitionBaseAddr + aDriveInfo->iEntry.iPartitionLen, NFE_FAULT()); + + if (aCurrentPos < aDriveInfo->iEncryptStartPos) + { + aCurrentLen = Min(aCurrentLen, aDriveInfo->iEncryptStartPos - aCurrentPos); + encodeBuffer = EFalse; + } + else if (aCurrentPos < aDriveInfo->iEncryptEndPos) + { + aCurrentLen = Min(aCurrentLen, aDriveInfo->iEncryptEndPos - aCurrentPos); + encodeBuffer = ETrue; + } + else + { + encodeBuffer = EFalse; + } + } + + return encodeBuffer; + } + + +TInt DMediaDriverNFE::HandleRead(TLocDrvRequest& aReq) + { + TInt r = KErrNone; + TInt64 currentPos = aReq.Pos(); + TInt64 remainingLength = aReq.Length(); + TInt desPos = 0; + TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)]; + +// __KTRACE_PRINT(Kern::Printf("NFE%d: HandleRead pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status())); + + + di->iReadRequestCount++; + + if (aReq.Flags() & TLocDrvRequest::ECodePaging) + di->iCodePagingRequesCount++; + if (aReq.Flags() & TLocDrvRequest::EDataPaging) + di->iDataPagingReadRequestCount++; + + + // just forward the request if the drive is not encrypted + if (di->Status() == ENfeDecrypted) + return ForwardRequest(aReq); + + + while(remainingLength) + { + TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize); + + TBool decryptBuffer = AdjustRequest(di, currentPos, currentLength); + + // Read from attached drive +#ifdef __DEMAND_PAGING__ + if (DMediaPagingDevice::PagingRequest(aReq)) + r = ReadPaged(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength)); + else +#endif + r = Read(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength)); + if(r != KErrNone) + break; + + TPtr8 des(iBuffer, I64LOW(currentLength), I64LOW(currentLength)); + + // decrypt buffer + if (decryptBuffer) + DecryptBuffer(des); + + // write back to user + r = aReq.WriteRemote(&des, desPos); + if(r != KErrNone) + break; + + remainingLength-= currentLength; + currentPos+= currentLength; + desPos+= I64LOW(currentLength); + } + + return r == KErrNone ? KErrCompletion : r; + } + +TInt DMediaDriverNFE::HandleWrite(TLocDrvRequest& aReq) + { + TInt r = KErrNone; + TInt64 currentPos = aReq.Pos(); + TInt64 remainingLength = aReq.Length(); + TInt desPos = 0; + TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)]; + +// __KTRACE_PRINT(Kern::Printf("NFE%d: HandleWrite pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status())); + + + di->iWriteRequestCount++; + if (aReq.Flags() & TLocDrvRequest::EDataPaging) + di->iDataPagingWriteRequestCount++; + + + // just forward the request if the drive is not encrypted + if (di->Status() == ENfeDecrypted) + return ForwardRequest(aReq); + + while(remainingLength) + { + TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize); + + TBool encryptBuffer = AdjustRequest(di, currentPos, currentLength); + + // read from user + TPtr8 des(iBuffer,0,I64LOW(currentLength)); + r = aReq.ReadRemote(&des, desPos); + if(r != KErrNone) + break; + + // get the length of data read from the user in case user's + // descriptor is shorter than advertised + currentLength = des.Length(); + if (currentLength == 0) + break; + + // writing to sector zero ? + if (currentPos >= di->iEntry.iPartitionBaseAddr && + currentPos < di->iEntry.iPartitionBaseAddr + KSectorSize && + di->IsUDADrive()) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Write to sector #0 detected", iInstance)); + + + TUint8* bootSector = iBuffer; + TUint8 bootSectorBuffer[KSectorSize]; + // writing partial sector ? + if (currentPos > di->iEntry.iPartitionBaseAddr || currentLength < KSectorSize) + { + bootSector = bootSectorBuffer; + r = Read(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) bootSector, KSectorSize); + if(r != KErrNone) + break; + TInt64 readLen = KSectorSize; + TBool encryptBuffer = AdjustRequest(di, di->iEntry.iPartitionBaseAddr, readLen); + if (encryptBuffer) + { + TPtr8 des(bootSectorBuffer,KSectorSize,KSectorSize); + DecryptBuffer(des); + } + TInt sectorOffset = (TInt) (currentPos - di->iEntry.iPartitionBaseAddr); + TInt64 copyLen = currentLength; + if (copyLen > KSectorSize-sectorOffset) + copyLen = KSectorSize-sectorOffset; + memcpy(bootSectorBuffer+sectorOffset, iBuffer, (TInt) copyLen); + } + + if ((di->Status() == ENfeUnmounted || di->Status() == ENfeCorrupted) && + ValidBootSector(bootSector)) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Setting status to ENfeDecrypted", iInstance )); + di->SetStatus(ENfeDecrypted); + } + di->iUniqueID = VolumeId(bootSector); // update the Volume ID + __KTRACE_PRINT(Kern::Printf("NFE%d: Setting Volume ID to %08X", iInstance, di->iUniqueID )); + TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer; + if (di->Status() == ENfeEncrypting || di->Status() == ENfeDecrypting) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Adding NFE status record to boot sector", iInstance )); + bootSectorStatus->iSignature = TBootSectorStatus::ENfeBootSectorSignature; + bootSectorStatus->iEncryptEndPos = di->iEncryptEndPos; + bootSectorStatus->iStatus = di->Status(); + bootSectorStatus->iFinalised = EFalse; + } + } + + // encrypt the buffer + if (encryptBuffer) + EncryptBuffer(des); + + // write the data to the attached drive +#ifdef __DEMAND_PAGING__ + if (DMediaPagingDevice::PagingRequest(aReq)) + r = WritePaged(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength)); + else +#endif + r = Write(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength)); + if(r != KErrNone) + break; + + remainingLength-= currentLength; + currentPos+= currentLength; + desPos+= I64LOW(currentLength); + } + + return r == KErrNone ? KErrCompletion : r; + } + +TInt DMediaDriverNFE::HandleFormat(TLocDrvRequest& aReq) + { + TInt r = KErrNone; + TInt64 currentPos = aReq.Pos(); + TInt64 remainingLength = aReq.Length(); + TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)]; + +// __KTRACE_PRINT(Kern::Printf("NFE%d: HandleFormat pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status())); + + + // just forward the request if the drive is not encrypted + if (di->Status() == ENfeDecrypted) + return ForwardRequest(aReq); + + // otherwise create a buffer containing NULLs, encrypt it and write that to the attached drive + while(remainingLength && r == KErrNone) + { + TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize); + + TBool encryptBuffer = AdjustRequest(di, currentPos, currentLength); + + memclr(iBuffer, KBufSize); + TPtr8 des(iBuffer,KBufSize,KBufSize); + + if (encryptBuffer) + EncryptBuffer(des); + + r = Write(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength)); + if(r != KErrNone) + break; + + remainingLength-= currentLength; + currentPos+= currentLength; + } + + return r == KErrNone ? KErrCompletion : r; + } + + +void DMediaDriverNFE::EncryptBuffer(TDes8& aBuffer) + { + TInt len = aBuffer.Length(); + for(TInt i=0; iiTimerDfc.Add(); + } + +/** +Idle timer DFC +*/ +void DMediaDriverNFE::TimerDfcFunction(TAny* aMediaDriver) + { + ((DMediaDriverNFE*) aMediaDriver)->HandleDiskContent(); + } + + +TBool DMediaDriverNFE::ValidBootSector(TUint8* aBuffer) + { + if (aBuffer[0] == 0xEB || aBuffer[0] == 0xE9) + return ETrue; + else + return EFalse; + } + + +TUint32 DMediaDriverNFE::VolumeId(TUint8* aBuffer) + { + TUint16 rootDirEntries; + TUint32 uniqueID; + memcpy(&rootDirEntries,&aBuffer[17], 2); // 17 TUint16 iRootDirEntries + TBool fat32 = rootDirEntries == 0; + TInt pos = fat32 ? 67 : 39; // get position of VolumeID + memcpy(&uniqueID,&aBuffer[pos],4); + return uniqueID; + } + +void DMediaDriverNFE::CheckBootSector(TNfeDriveInfo &aDi) + { + TNfeDiskStatus fatBootSectorStatus = ENfeDecrypted; + + // Try to determine whether the FAT boot sector is encypted + if (ValidBootSector(iBuffer)) + { + fatBootSectorStatus = ENfeDecrypted; + __KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is decrypted", iInstance)); + } + else + { + TPtr8 des(iBuffer, KSectorSize, KSectorSize); + DecryptBuffer(des); + if (ValidBootSector(iBuffer)) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is encrypted", iInstance)); + fatBootSectorStatus = ENfeEncrypted; + } + else + { + __KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is corrupted", iInstance)); + fatBootSectorStatus = ENfeCorrupted; + } + } + + __KTRACE_PRINT(Kern::Printf("NFE%d: fatBootSectorStatus %d", iInstance, fatBootSectorStatus)); + + // Find out whether the volume has changed + TUint32 uniqueID = VolumeId(iBuffer); + TBool volumeChanged = uniqueID != aDi.iUniqueID; + __KTRACE_PRINT(Kern::Printf("NFE%d: Old Volume ID %08X", iInstance, aDi.iUniqueID)); + __KTRACE_PRINT(Kern::Printf("NFE%d: New Volume ID %08X", iInstance, uniqueID)); + __KTRACE_PRINT(Kern::Printf("NFE%d: volumeChanged %d", iInstance, volumeChanged)); + aDi.iUniqueID = uniqueID; + + + + TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer; + + __KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iSignature %08X", iInstance, bootSectorStatus->iSignature)); + __KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iStatus %d", iInstance, bootSectorStatus->iStatus)); + __KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iEncryptEndPos %lx", iInstance, bootSectorStatus->iEncryptEndPos)); + + + /* + If there IS NFE info in the boot sector, restore the encryption settings - + unless the 'finalised' flag is clear which indicates that the media was removed or power was lost + while encrypting the device... + + If there is no NFE info in the boot sector and there has been a volume change, then we can decide + whether the drive is encrypted/decrypted/corrupt by examining the boot sector + */ + if (volumeChanged && + fatBootSectorStatus != ENfeCorrupted && + bootSectorStatus->iSignature == TBootSectorStatus::ENfeBootSectorSignature && + !bootSectorStatus->iFinalised) + { + SetStatus(aDi, ENfeCorrupted); + } + else if (volumeChanged && + fatBootSectorStatus != ENfeCorrupted && + bootSectorStatus->iFinalised && + bootSectorStatus->iSignature == TBootSectorStatus::ENfeBootSectorSignature && + (bootSectorStatus->iStatus == ENfeDecrypting || bootSectorStatus->iStatus == ENfeEncrypting)) + { + SetStatus(aDi, bootSectorStatus->iStatus); + aDi.iEncryptEndPos = bootSectorStatus->iEncryptEndPos; + + // write to boot sector to indicate we are no longer finalised + WriteEncryptionStatusToBootSector(aDi, EFalse); + + iBusy = ETrue; + } + else if (volumeChanged || aDi.Status() == ENfeUnmounted) + { + SetStatus(aDi, fatBootSectorStatus); + if (aDi.Status() == ENfeEncrypted) + { + aDi.iEncryptStartPos = aDi.iEntry.iPartitionBaseAddr; + aDi.iEncryptEndPos = aDi.iEntry.iPartitionBaseAddr + aDi.iEntry.iPartitionLen; + } + } + } + + +TInt DMediaDriverNFE::WriteEncryptionStatusToBootSector(TNfeDriveInfo &aDi, TBool aFinalised) + { + if (!aDi.IsUDADrive()) + return KErrNone; + + aDi.iDriveFinalised = aFinalised; + + TNfeDiskStatus status = aDi.Status(); + + TInt64 currentPos = aDi.iEntry.iPartitionBaseAddr; + TInt64 currentLen = KSectorSize; + TNfeDriveInfo* di = &aDi; + TBool encodeBuffer = EFalse; + + if (status == ENfeEncrypting || status == ENfeEncrypted || status == ENfeDecrypting) + encodeBuffer = AdjustRequest(di, currentPos, currentLen); + + + TInt r = Read(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) iBuffer, KSectorSize); + if (r != KErrNone) + return r; + TPtr8 des(iBuffer, I64LOW(currentLen), I64LOW(currentLen)); + + if (encodeBuffer) + DecryptBuffer(des); + + + TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer; + + if (status == ENfeEncrypting || status == ENfeDecrypting) + { + bootSectorStatus->iSignature = TBootSectorStatus::ENfeBootSectorSignature; + bootSectorStatus->iEncryptEndPos = di->iEncryptEndPos; + bootSectorStatus->iStatus = status; + bootSectorStatus->iFinalised = aFinalised; + } + else + { + bootSectorStatus->iSignature = 0; + bootSectorStatus->iEncryptEndPos = 0; + bootSectorStatus->iStatus = ENfeUnmounted; + bootSectorStatus->iFinalised = EFalse; + } + + if (encodeBuffer) + EncryptBuffer(des); + + + r = Write(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) iBuffer, KSectorSize); + return r; + } + + +/** +HandleDiskContent - + +Called from Idle timer DFC + +Starts encrypting the current drive (iDrives[iDriveIndex]) from the current encryption position (iEncryptEndPos) +*/ +TInt DMediaDriverNFE::HandleDiskContent() + { + TNfeDriveInfo* di = &iInfo.iDrives[iDriveIndex]; + + __KTRACE_PRINT(Kern::Printf("NFE%d: Starting to encrypt Drive %d at pos %lx", iInstance, di->iLocalDriveNum, di->iEncryptEndPos)); + + if (di->iDriveFinalised) + { + __KTRACE_PRINT(Kern::Printf("HandleDiskContent aborting as drive has been finalised", iInstance)); + return KErrNone; + } + +// TInt KBackgroundPriority = 7; //*test* +// Kern::SetThreadPriority(KBackgroundPriority); //*test* + + TInt r = KErrNone; + for (;;) + { + // If we've finished encryting this drive, change the state and move on to the next drive + if (r != KErrNone || di->iEncryptEndPos >= di->iEntry.iPartitionBaseAddr + di->iEntry.iPartitionLen) + { + if (di->Status() == ENfeEncrypting) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Finished encrypting Drive %d r %d", iInstance, di->iLocalDriveNum, r)); + SetStatus(*di, r == KErrNone ? ENfeEncrypted : ENfeCorrupted); + } + if (di->Status() == ENfeDecrypting) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Finished decrypting Drive %d r %d", iInstance, di->iLocalDriveNum, r)); + SetStatus(*di, r == KErrNone ? ENfeDecrypted : ENfeCorrupted); + } + + // write to boot sector to indicate we have finished encrypting/decrypting this drive + r = WriteEncryptionStatusToBootSector(*di); + + di = NextDrive(); + if (di == NULL) + { + r = KErrCompletion; + break; + } + __KTRACE_PRINT(Kern::Printf("NFE%d: Starting to encrypt Drive %d", iInstance, iInfo.iDrives[iDriveIndex].iLocalDriveNum)); + } + + // If this media or any of the attached media are busy, stop encrypting & wait for the next idle timeout + if (MediaBusy(di->iLocalDriveNum)) + { + __KTRACE_PRINT(Kern::Printf("NFE%d: Media is busy !!!", iInstance)); + r = KErrNone; // goto sleep & wait for another timer event + break; + } + + TInt64& pos = di->iEncryptEndPos; + TInt64 partitionEnd = di->iEntry.iPartitionBaseAddr + di->iEntry.iPartitionLen; + TInt len = (TInt) Min (partitionEnd - pos, KBufSize); + +#if defined(TRACE_ENABLED) + // print position every 1/16 of the partition size + TInt64 printPos = Max((di->iEntry.iPartitionLen >> 4) & ~(KBufSize-1), KBufSize); + if (((di->iEncryptEndPos - di->iEncryptStartPos)% printPos) == 0) + __KTRACE_PRINT(Kern::Printf("NFE%d: Encrypting drive %d from %lx to %lx end %lx", iInstance, di->iLocalDriveNum, pos, pos + len, partitionEnd)); +#endif +// __KTRACE_PRINT(Kern::Printf("NFE%d: Encrypting drive %d from %lx to %lx end %lx", iInstance, di->iLocalDriveNum, pos, pos + len, partitionEnd)); + + + // Read a buffer, encrypt it, and then write it back + // retry in case of media change + const TInt KRetries = 5; + r = KErrNotReady; + for (TInt i=0; r == KErrNotReady && i < KRetries; i++) + { + r = Read(di->iLocalDriveNum, pos, (TLinAddr) iBuffer, len); + if (r != KErrNone) + continue; + + TPtr8 des(iBuffer,len,len); + if (di->Status() == ENfeEncrypting) + EncryptBuffer(des); + else + DecryptBuffer(des); + + r = Write(di->iLocalDriveNum, pos, (TLinAddr) iBuffer, len); + } + + if (r == KErrNone) + pos+= len; + + if (di->iProgressToUiProperty) // no iProgressToUiProperty for swap drive + { + TInt progress = (TInt) (KNfeDiskOpReady * (pos - di->iEntry.iPartitionBaseAddr) / di->iEntry.iPartitionLen); +// __KTRACE_PRINT(Kern::Printf("NFE%d: Progess %d ", progress)); + ((RPropertyRef*) (di->iProgressToUiProperty))->Set( progress ); // Return value ignored + } + } + + __KTRACE_PRINT(Kern::Printf("NFE%d: HandleDiskContent returned %d", iInstance, r)); + + // If not completed, start the idle timer & try again later + if (r != KErrCompletion) + iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval)); + +// Kern::SetThreadPriority(KNfeThreadPriority); //*test* + + return r; + } + + + +DECLARE_EXTENSION_PDD() + { + __KTRACE_PRINT(Kern::Printf("DECLARE_EXTENSION_PDD()")); + return new DPhysicalDeviceMediaNFE; + } + +DECLARE_STANDARD_EXTENSION() + { + __KTRACE_PRINT(Kern::Printf("DECLARE_STANDARD_EXTENSION()")); + + + // Create the media driver factory object and register this with the kernel + __KTRACE_PRINT(Kern::Printf("Creating NFE PDD")); + DPhysicalDeviceMediaNFE* device = new DPhysicalDeviceMediaNFE; + if (device == NULL) + return KErrNoMemory; + TInt r = Kern::InstallPhysicalDevice(device); + __KTRACE_PRINT(Kern::Printf("Installing NFE PDD in extension init - name %s r:%d", NFE_DRIVENAME, r)); + if (r != KErrNone) + return r; + + TInt swapInstance = KErrNotFound; +#if defined (__DEMAND_PAGING__) + swapInstance = SwapInstance(); +#endif + + DPrimaryMediaExt* primaryMedia[NFE_INSTANCE_COUNT]; + TInt instance; + + for (instance=0; instanceiNfeDfcQ,KNfeThreadPriority,pMediaThreadName); + if (r != KErrNone) + return r; + +#ifdef CPU_AFFINITY_ANY + NKern::ThreadSetCpuAffinity((NThread*)(pM->iNfeDfcQ.iThread), KCpuAffinityAny); +#endif + + + pM->iDfcQ = &pM->iNfeDfcQ; + pM->iMsgQ.Receive(); + + + const TInt* driveList = DriveList(instance); + TInt driveCount = DriveCount(instance); + + TBuf<4> driveName(_L("NFE?")); + driveName[3] = (TUint8) ('0' + (TUint8) instance); + + + r = LocDrv::RegisterMediaDevice( + MEDIA_DEVICE_NFE, + driveCount, driveList, + pM, NFE_NUMMEDIA, driveName); + if (r != KErrNone) + return r; + + +#if defined (__DEMAND_PAGING__) + if (PagingType(instance)) + { + // Define which of the drives we have already attached to have code or data paging enabled + const TInt* pageDriveList = PageDriveList(instance); + TInt pageDriveCount = PageDriveCount(instance); + + r = LocDrv::RegisterPagingDevice(pM,pageDriveList,pageDriveCount,PagingType(instance),SECTOR_SHIFT,NFE_NUM_PAGES); + __KTRACE_PRINT(Kern::Printf("NFE%d: Installing NFE PagingDevice in extension init - r:%d", pM->iInstance, r)); + // Ignore error if demand paging not supported by kernel + if (r == KErrNotSupported) + r = KErrNone; + if (r != KErrNone) + return r; + } + + +#endif // __NAND_DEMAND_PAGING__ + + /* + If there is a swap partition we need to make sure all instances have their PartitionInfo() called + so that we can flag the swap partition as 'encrypted' if there are any encrypted drives at all + */ + if (swapInstance != KErrNotFound) + { + TBuf8 capsBuf; + capsBuf.SetMax(); + capsBuf.FillZ(); + DLocalDrive::Caps(driveList[0], capsBuf); + } + } + + + // If we encounter an encrypted drive belonging to ANY NFE instance, then assume the swap partition is + // encrypted too. We need to do this because the swap partition has no equivalent of the boot sector + if (swapInstance != KErrNotFound) + { + __KTRACE_PRINT(Kern::Printf("NFE: Searching for encrypted drives to determine whether swap partition should be encrypted...")); + TBool encryptedDriveFound = EFalse; + TNfeDriveInfo* swapDriveInfo = NULL; + for (instance=0; instanceiDriver; + __ASSERT_ALWAYS(mediaDriver, NFE_FAULT()); + + if (swapDriveInfo == NULL) + swapDriveInfo = mediaDriver->GetSwapDrive(); + + for (TInt i=0; iiInfo.iDriveCount; i++) + { + TNfeDriveInfo& di = mediaDriver->iInfo.iDrives[i]; + __KTRACE_PRINT(Kern::Printf("NFE%d: Testing drive %d DriveLetter %c status %s", + instance, di.iLocalDriveNum, (TInt) DriveLetterToAscii(di.iDriveLetter), DriveStatus(di.Status()) )); + if (di.Status() == ENfeEncrypted || di.Status() == ENfeEncrypting) + encryptedDriveFound = ETrue; + } + } + if (swapDriveInfo) + { + swapDriveInfo->SetStatus(encryptedDriveFound ? ENfeEncrypted : ENfeDecrypted); + swapDriveInfo->iEncryptEndPos = swapDriveInfo->iEntry.iPartitionBaseAddr + swapDriveInfo->iEntry.iPartitionLen; + + __KTRACE_PRINT(Kern::Printf("NFE: Setting swap partition state to %s...", DriveStatus(swapDriveInfo->Status()))); + } + } + + + return r; + } + +