# HG changeset patch # User hgs # Date 1286820666 -3600 # Node ID ddfd5aa0d58ffdfdf0ae68477a3971f097b06861 # Parent 48e57fb1237e86ad0904b85b3c5460b3f60dbb17 201041_01 diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bld.inf --- a/kernel/eka/bld.inf Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/bld.inf Mon Oct 11 19:11:06 2010 +0100 @@ -264,9 +264,13 @@ include/drivers/resmanus_trace.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) include/drivers/i2s.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) - // + include/drivers/display.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) +include/drivers/rpmbdevice.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) +include/drivers/rpmbpacket.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) + + // Real Time Clock SHAI API include/drivers/rtclock.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bmarm/epbusmu.def --- a/kernel/eka/bmarm/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/bmarm/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ InitStackAfterUnlockSM__9DMMCStack @ 94 NONAME ; DMMCStack::InitStackAfterUnlockSM(void) RegisterMediaDevices__26TMMCardControllerInterfacei @ 95 NONAME ; TMMCardControllerInterface::RegisterMediaDevices(int) ModifyCardCapabilitySM__9DMMCStack @ 96 NONAME R3UNUSED ; DMMCStack::ModifyCardCapabilitySM(void) - Dummy1__9DMMCStack @ 97 NONAME R3UNUSED ; DMMCStack::Dummy1(void) + MMCGetExtInterface__F18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 97 NONAME GetInterface__9DMMCStackQ29DMMCStack12TInterfaceIdRPQ29DMMCStack10MInterface @ 98 NONAME R3UNUSED ; DMMCStack::GetInterface(DMMCStack::TInterfaceId, DMMCStack::MInterface *&) MachineInfo__9DMMCStackR5TDes8 @ 99 NONAME R3UNUSED ; DMMCStack::MachineInfo(TDes8 &) SetBusWidth__9DMMCStackUl @ 100 NONAME R3UNUSED ; DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bmarm/rpmbextu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/bmarm/rpmbextu.def Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,7 @@ +EXPORTS + Close__11DRpmbDevice @ 1 NONAME R3UNUSED ; DRpmbDevice::Close(void) + Open__11DRpmbDeviceUi @ 2 NONAME R3UNUSED ; DRpmbDevice::Open(unsigned int) + SendAccessRequest__11DRpmbDeviceR5TDes8T1 @ 3 NONAME R3UNUSED ; DRpmbDevice::SendAccessRequest(TDes8 &, TDes8 &) + "_._11DRpmbDevice" @ 4 NONAME R3UNUSED ; DRpmbDevice::~DRpmbDevice(void) + __11DRpmbDevice @ 5 NONAME R3UNUSED ; DRpmbDevice::DRpmbDevice(void) + diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bwins/epbusmu.def --- a/kernel/eka/bwins/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/bwins/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?InitStackAfterUnlockSM@DMMCStack@@MAEKXZ @ 94 NONAME ; protected: virtual unsigned long __thiscall DMMCStack::InitStackAfterUnlockSM(void) ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 95 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?ModifyCardCapabilitySM@DMMCStack@@MAEKXZ @ 96 NONAME ; unsigned long DMMCStack::ModifyCardCapabilitySM(void) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; void DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ; int MMCGetExtInterface(enum TMMCExtInterfaceId, class MMCMExtInterface * &, void *) ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bwins/rpmbextu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/bwins/rpmbextu.def Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,7 @@ +EXPORTS + ?SendAccessRequest@DRpmbDevice@@QAEHAAVTDes8@@0@Z @ 1 NONAME ; int DRpmbDevice::SendAccessRequest(class TDes8 &, class TDes8 &) + ??1DRpmbDevice@@UAE@XZ @ 2 NONAME ; DRpmbDevice::~DRpmbDevice(void) + ?Close@DRpmbDevice@@QAEXXZ @ 3 NONAME ; void DRpmbDevice::Close(void) + ??0DRpmbDevice@@QAE@XZ @ 4 NONAME ; DRpmbDevice::DRpmbDevice(void) + ?Open@DRpmbDevice@@QAEHI@Z @ 5 NONAME ; int DRpmbDevice::Open(unsigned int) + diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bx86/epbusmu.def --- a/kernel/eka/bx86/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/bx86/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 94 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?RequestAsyncPowerDown@DPBusSocket@@QAEXXZ @ 95 NONAME ; public: void __thiscall DPBusSocket::RequestAsyncPowerDown(void) ?ControlIO@DPBusSocket@@UAEHHPAX0@Z @ 96 NONAME ; public: virtual int __thiscall DPBusSocket::ControlIO(int,void *,void *) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; private: virtual void __thiscall DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/bx86/rpmbextu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/bx86/rpmbextu.def Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,7 @@ +EXPORTS + ??0DRpmbDevice@@QAE@XZ @ 1 NONAME ; public: __thiscall DRpmbDevice::DRpmbDevice(void) + ??1DRpmbDevice@@UAE@XZ @ 2 NONAME ; public: virtual __thiscall DRpmbDevice::~DRpmbDevice(void) + ?Close@DRpmbDevice@@QAEXXZ @ 3 NONAME ; public: void __thiscall DRpmbDevice::Close(void) + ?Open@DRpmbDevice@@QAEHI@Z @ 4 NONAME ; public: int __thiscall DRpmbDevice::Open(unsigned int) + ?SendAccessRequest@DRpmbDevice@@QAEHAAVTDes8@@0@Z @ 5 NONAME ; public: int __thiscall DRpmbDevice::SendAccessRequest(class TDes8 &,class TDes8 &) + diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/media/base_e32_drivers_media.mrp --- a/kernel/eka/drivers/media/base_e32_drivers_media.mrp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/media/base_e32_drivers_media.mrp Mon Oct 11 19:11:06 2010 +0100 @@ -44,6 +44,7 @@ source \sf\os\kernelhwsrv\kernel\eka\drivers\pbus\mmc\sdcard\eabi\sdcard3c\sdio\epbusmu.def source \sf\os\kernelhwsrv\kernel\eka\drivers\pbus\mmc\sdcard\eabi\sdcard3c\sdio\distribution.policy.s60 source \sf\os\kernelhwsrv\kernel\eka\drivers\pbus\mmc\sdcard\sdcard3c\sdio +source \sf\os\kernelhwsrv\kernel\eka\drivers\rpmb source \sf\os\kernelhwsrv\kernel\eka\drivers\media diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/media/bld.inf --- a/kernel/eka/drivers/media/bld.inf Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/media/bld.inf Mon Oct 11 19:11:06 2010 +0100 @@ -56,6 +56,7 @@ ../../drivers/medmmc/bgahsmmcptn ../../drivers/pbus/mmc/epbusmmc ../../drivers/medmmc/medmmc +../../drivers/rpmb/rpmbext #if !defined(WINS) && !defined(GENERIC_X86) ../../drivers/pbus/mmc/sdcard/sdcard3c/epbussd diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/bgahsmmcptn.cpp --- a/kernel/eka/drivers/medmmc/bgahsmmcptn.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/medmmc/bgahsmmcptn.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -16,11 +16,13 @@ // #include +#include "mmc.h" #include "bgahsmmcptn.h" +#include "medmmc.h" #include "toc.h" + //#define __DEBUG_PARTITIONS_ //#define __DEBUG_CHECK_PARTITION_ -const TInt KDiskSectorShift = 9; class DBB5PartitionInfo : public DEMMCPartitionInfo { @@ -39,8 +41,11 @@ private: virtual TInt ReadPartition(TUint32 aPtOffset); static void SessionEndCallBack(TAny* aSelf); - void DoSessionEndCallBack(); + void DoSessionEndCallBack(); virtual TInt DecodePartitionInfo(); + TInt GetPartitionSizeInSectors(TUint aPartition, TUint32& aSize); + TInt GetPartitionOffset(TUint32& aPtOffset); + TInt SelectNextPartition(); protected: DMediaDriver* iDriver; @@ -53,6 +58,7 @@ TUint32 iPartitionAttributes[KMaxLocalDrives]; TBool iCheckTOC; Toc* iTocPtr; + TUint32 iSelectedPartition; }; DBB5PartitionInfo::DBB5PartitionInfo() @@ -88,19 +94,169 @@ TInt bufLen, minorBufLen; stack->BufferInfo(iIntBuf, bufLen, minorBufLen); + iSelectedPartition = TExtendedCSD::ESelectUserArea; + return(KErrNone); } TInt DBB5PartitionInfo::PartitionInfo(TPartitionInfo& aInfo, const TMMCCallBack& aCallBack) { iPartitionInfo = &aInfo; + iPartitionInfo->iPartitionCount = 0; iCallBack = aCallBack; + // Always check the user partition first + iSelectedPartition = TExtendedCSD::ESelectUserArea; + iSession->SetPartition(iSelectedPartition); + // Preferred partition scheme is BB5, which is located in the last block of the media. - const TUint32 ptiOffset = (I64LOW(iCard->DeviceSize64() >> KDiskSectorShift)) - KPIOffsetFromMediaEnd; - return ReadPartition(ptiOffset); + TUint32 ptiOffset; + TInt r; + do + { + r = GetPartitionOffset(ptiOffset); + + if(r == KErrNone) + { + r = ReadPartition(ptiOffset); + return r; + } + + r = SelectNextPartition(); + } + while(r != KErrNotFound); + + return r; } +// retrieves size in terms of sectors +TInt DBB5PartitionInfo::GetPartitionSizeInSectors(TUint aPartition, TUint32& aSize) + { + TInt r = KErrNone; + + TUint32 size = 0; + + const TExtendedCSD& extCsd = iCard->ExtendedCSD(); + + switch(aPartition) + { + case TExtendedCSD::ESelectUserArea: + { + size = (TUint32)(iCard->DeviceSize64() / KSectorSize); + + if(extCsd.ExtendedCSDRev() >= TExtendedCSD::EExtendedCSDRev1_5) + { + TUint32 otherPartitionsSize = + extCsd.GeneralPurposePartition1SizeInSectors() + + extCsd.GeneralPurposePartition2SizeInSectors() + + extCsd.GeneralPurposePartition3SizeInSectors() + + extCsd.GeneralPurposePartition4SizeInSectors(); + + __ASSERT_DEBUG(size >= otherPartitionsSize, Kern::Fault("DBB5PartitionInfo size mismatch", __LINE__)); + size -= otherPartitionsSize; + } + } + break; + case TExtendedCSD::ESelectBootPartition1: + case TExtendedCSD::ESelectBootPartition2: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_3) ? + 0 : extCsd.BootSizeInSectors(); + break; + case TExtendedCSD::ESelectRPMB: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_5) ? + 0 : extCsd.RpmbSizeInSectors(); + break; + case TExtendedCSD::ESelectGPAPartition1: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_5) ? + 0 : extCsd.GeneralPurposePartition1SizeInSectors(); + break; + case TExtendedCSD::ESelectGPAPartition2: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_5) ? + 0 : extCsd.GeneralPurposePartition2SizeInSectors(); + break; + case TExtendedCSD::ESelectGPAPartition3: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_5) ? + 0 : extCsd.GeneralPurposePartition3SizeInSectors(); + break; + case TExtendedCSD::ESelectGPAPartition4: + size = (extCsd.ExtendedCSDRev() < TExtendedCSD::EExtendedCSDRev1_5) ? + 0 : extCsd.GeneralPurposePartition4SizeInSectors(); + break; + default: + // unknown partition + size = 0; + r = KErrNotSupported; + break; + } + + aSize = size; + return r; + } + +TInt DBB5PartitionInfo::GetPartitionOffset(TUint32& aPtiOffset) + { + TInt r = GetPartitionSizeInSectors(iSelectedPartition, aPtiOffset); + + if((r != KErrNone) || (aPtiOffset == 0)) + { + // error reading or partition not supported, skip + r = KErrNotSupported; + } + else + { + // need to determine correct end of the partition + aPtiOffset -= KPIOffsetFromMediaEnd; + } + + return r; + } + +TInt DBB5PartitionInfo::SelectNextPartition() + { + TExtendedCSD extCsd = iCard->ExtendedCSD(); + TUint maxPartition = TExtendedCSD::ESelectUserArea; + + if(extCsd.ExtendedCSDRev() >= TExtendedCSD::EExtendedCSDRev1_5) + { + // v4.4 supports UDA, 2x BOOT, RPMB and 4x GPAP partitions + maxPartition = TExtendedCSD::ESelectGPAPartition4; + } +#ifdef EMMC_BOOT_PARTITION_ACCESS_ENABLED + else if(extCsd.ExtendedCSDRev() >= TExtendedCSD::EExtendedCSDRev1_3) + { + // v4.3 supports up to two BOOT partitions + maxPartition = TExtendedCSD::ESelectBootPartition2; + } +#endif // EMMC_BOOT_PARTITION_ACCESS_ENABLED + + ++iSelectedPartition; + + // skip through to GPAP1 if either the currently selected partition is RPMB or + // if it is one of the BOOT partitions and boot partition access is not enabled + if((iSelectedPartition == TExtendedCSD::ESelectRPMB) +#ifndef EMMC_BOOT_PARTITION_ACCESS_ENABLED + || (iSelectedPartition == TExtendedCSD::ESelectBootPartition1) + || (iSelectedPartition == TExtendedCSD::ESelectBootPartition2) +#endif + ) + { + iSelectedPartition = TExtendedCSD::ESelectGPAPartition1; + } + + TInt r = KErrNone; + if(iSelectedPartition > maxPartition) + { + r = KErrNotFound; // no more partitions to be checked + } + else + { + iSession->SetPartition(iSelectedPartition); + } + + return r; + } + +// returns KErrCompletion on success after having checked all partitions TInt DBB5PartitionInfo::ReadPartition(TUint32 aPtOffset) { // If media driver is persistent (see EMediaDriverPersistent) @@ -167,24 +323,82 @@ TInt r = iSession->EpocErrorCode(); + + TInt& partitionCount = iPartitionInfo->iPartitionCount; + if (r == KErrNone) r = DecodePartitionInfo(); - if (!iCheckTOC) - { - iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady); - } + if (iCheckTOC) + { + //BB5 table not found need to check for TOC in this partition before continuing + if (r!=KErrNone) + { + iDriver->PartitionInfoComplete(KErrNotReady); + } + return; + } + + + if(r == KErrNone) + { + // check next partition(s) for BB5 + TUint32 ptiOffset = 0; + + r = SelectNextPartition(); + while(r != KErrNotFound) + { + if(r == KErrNone) + r = GetPartitionOffset(ptiOffset); + + if(r == KErrNone) + { + r = ReadPartition(ptiOffset); + if(r != KErrNone) + break; + + + return; + } + + r = SelectNextPartition(); + } + + + // end of partitions - reinterpret error code + if(r != KErrNotFound) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:dsc: ReadPartition() failed r=%d!", r)); + r = KErrCorrupt; + } + else if(partitionCount == 0) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:dsc: No supported partitions found!")); + r = KErrCorrupt; + } + else + r = KErrCompletion; + } + + // Notify medmmc that partitioninfo is complete + iCallBack.CallBack(); + + // All potential partitions checked - KErrCompletion + // indicates that there are no more partitions to check + r = (r == KErrCompletion) ? KErrNone : KErrNotReady; + iDriver->PartitionInfoComplete(r); } + TInt DBB5PartitionInfo::DecodePartitionInfo() // // Decode partition info that was read into internal buffer // { __KTRACE_OPT(KPBUSDRV, Kern::Printf(">Mmc:PartitionInfo()")); - TUint partitionCount = iPartitionInfo->iPartitionCount = 0; + TInt& partitionCount = iPartitionInfo->iPartitionCount; + TInt r = KErrNone; - if (iCheckTOC) { // Try utilising the TOC (Table Of Contents) partitioning scheme @@ -199,7 +413,6 @@ STocItem item; iTocPtr = reinterpret_cast(&iIntBuf[0]); iTocPtr->iTocStartSector = KTocStartSector; - TInt r = KErrNone; // USER Drive - Only 1 r = iTocPtr->GetItemByName(KTocUserName, item); @@ -262,7 +475,7 @@ } // SWAP Partition - Only 1 - r = iTocPtr->GetItemByName(KTocSwap, item); + r = iTocPtr->GetItemByName(KTocSwap, item); if (KErrNone == r) { __KTRACE_OPT(KPBUSDRV, Kern::Printf("[MD : ] (%11s) in TOC found : Start addr = 0x%X Size = 0x%X", item.iFileName, item.iStart, item.iSize)); @@ -283,6 +496,7 @@ } #endif //__DEBUG_PARTITIONS_ + r = KErrNone; iCheckTOC = EFalse; } else @@ -324,12 +538,12 @@ { iPartitionInfo->iEntry[partitionCount].iPartitionType = partitionType; iPartitionAttributes[partitionCount] = partitionTable->iPartitions[index].iPartition_attributes; - + static_cast(iDriver)->SetEMmcPartitionMapping(partitionCount, iSelectedPartition); // ROM/ROFS partitions have a BB5 checksum header that must be offset for the Symbian OS. - const TUint32 KstartOffset = ((KPartitionTypeROM == partitionType) || (KPartitionTypeRofs == partitionType) || (KPartitionTypeEmpty == partitionType)) ? KBB5HeaderSizeInSectors : 0; + const TUint32 KStartOffset = ((KPartitionTypeROM == partitionType) || (KPartitionTypeRofs == partitionType) || (KPartitionTypeEmpty == partitionType)) ? KBB5HeaderSizeInSectors : 0; - iPartitionInfo->iEntry[partitionCount].iPartitionBaseAddr = ((Int64) partitionTable->iPartitions[index].iStart_sector + KstartOffset) << KDiskSectorShift; - iPartitionInfo->iEntry[partitionCount].iPartitionLen = ((Int64) partitionTable->iPartitions[index].iSize - KstartOffset) << KDiskSectorShift; + iPartitionInfo->iEntry[partitionCount].iPartitionBaseAddr = ((Int64) partitionTable->iPartitions[index].iStart_sector + KStartOffset) << KDiskSectorShift; + iPartitionInfo->iEntry[partitionCount].iPartitionLen = ((Int64) partitionTable->iPartitions[index].iSize - KStartOffset) << KDiskSectorShift; __KTRACE_OPT(KPBUSDRV, Kern::Printf("Registering partition #%d:", partitionCount)); __KTRACE_OPT(KPBUSDRV, Kern::Printf("partitionCount....: %d", partitionCount)); @@ -339,6 +553,7 @@ __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionLen.....: 0x%lx (sectors: %d)", iPartitionInfo->iEntry[partitionCount].iPartitionLen, iPartitionInfo->iEntry[partitionCount].iPartitionLen >> KDiskSectorShift)); __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionType....: %d", iPartitionInfo->iEntry[partitionCount].iPartitionType)); __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionAttribs.: 0x%x", iPartitionAttributes[partitionCount])); + __KTRACE_OPT(KPBUSDRV, Kern::Printf("iPartitionMapping.: 0x%x", static_cast(iDriver)->GetEMmcPartitionMapping(partitionCount))); __KTRACE_OPT(KPBUSDRV, Kern::Printf(" ")); partitionCount++; @@ -361,24 +576,43 @@ if(partitionCount == 0) { __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: No supported partitions found!")); - return KErrCorrupt; + // No Supported partitions found on this physical partition + return KErrNone; } -#ifdef __DEBUG_CHECK_PARTITION_ - else + +#ifdef __DEBUG_CHECK_PARTITION_ + // Validate partition address boundaries + TUint32 eMmcPartitionSizeInSectors = 0; + if(r == KErrNone) { - // at least one entry for a supported partition found - const TInt64 deviceSize = iCard->DeviceSize64(); + // At least one entry for a supported partition found + r = GetPartitionSizeInSectors(iSelectedPartition, eMmcPartitionSizeInSectors); + + if(r != KErrNone) + { + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Could not retrieve size for eMMC partition 0x%02X", iSelectedPartition)); + r = KErrCorrupt; + } + } + + if(r == KErrNone) + { + TUint64 eMmcPartitionSize = eMmcPartitionSizeInSectors * KSectorSize; + TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1]; - - // Check that the card address space boundary is not exceeded by the last partition - if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize) + + // Check that the eMmcPartition address space boundary is not exceeded by the last partition + if(part.iPartitionBaseAddr + part.iPartitionLen > eMmcPartitionSize) { - __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space")); - return KErrCorrupt; + __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Partition #%d exceeds eMmc address space", partitionCount)); + r = KErrCorrupt; } - - // Go through all partition entries and check boundaries - for(TInt i = partitionCount - 1; i > 0; i--) + } + + if(r == KErrNone) + { + // Go through all BB5 partition entries on this eMMC partition and check boundaries + for(TInt i = partitionCount - 1; i > iPartitionInfo->iPartitionCount; i--) { const TPartitionEntry& curr = iPartitionInfo->iEntry[i]; TPartitionEntry& prev = iPartitionInfo->iEntry[i-1]; @@ -387,20 +621,20 @@ if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen)) { __KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions - check #%d", i)); - return KErrCorrupt; + r = KErrCorrupt; } } } #endif // _DEBUG_CHECK_PARTITION_ - - iPartitionInfo->iPartitionCount = partitionCount; - iPartitionInfo->iMediaSizeInBytes = iCard->DeviceSize64(); - - //Notify medmmc that partitioninfo is complete. - iCallBack.CallBack(); + + if(r == KErrNone) + { + iPartitionInfo->iPartitionCount = partitionCount; + iPartitionInfo->iMediaSizeInBytes = iCard->DeviceSize64(); + } __KTRACE_OPT(KPBUSDRV, Kern::Printf(" DMmcMediaDriverFlash::DMmcMediaDriverFlash;aMediaId=%d;iMediaId=%d", (TInt) aMediaId, (TInt) iMediaId ); + for(TInt drv = 0; drv < KMaxLocalDrives; drv++) + { + SetEMmcPartitionMapping(drv, TExtendedCSD::ESelectUserArea); + } } @@ -540,12 +313,13 @@ iMinorBuf = buf; + // reserve KRpmbOneFramePacketLength bytes after the minor buffer for RPMB requests / responses // cache buffer can use rest of blocks in buffer. Does not have to be power of 2. - iCacheBuf = iMinorBuf + minorBufLen; + iCacheBuf = iMinorBuf + minorBufLen + KRpmbOneFramePacketLength; // We need to devide up the buffer space between the media drivers. // The number of buffer sub-areas = number of physical card slots * number of media - bufLen-= minorBufLen; + bufLen-= (minorBufLen + KRpmbOneFramePacketLength); DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia; TInt physicalCardSlots = iStack->iMaxCardsInStack; TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1; @@ -1160,7 +934,8 @@ } // Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd. - if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0) + if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0 || + (iCurrentReq->Id() == DLocalDrive::EDeleteNotify && (iPhysStart - iPhysEnd) % KMMCardHighCapBlockSize == 0 )) // handle TRIM case where erase is aligned to 512 blocks { // Aligned erase // Check that erase commands are supported prior to issuing an erase command @@ -1174,6 +949,10 @@ iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector) } + if(iCurrentReq->Id() == DLocalDrive::EDeleteNotify) + { + iSession->Command().iFlags|= KMMCCmdFlagDeleteNotify; //set flags for Trim + } } else { @@ -1200,7 +979,7 @@ memset (iCacheBuf, 0x00, writeLen); iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2); } - + r = EngageAndSetWriteRequest(EMReqFormat); } OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_EXIT, this, r ); @@ -2307,6 +2086,10 @@ { iReqCur = iPhysEnd; } + else if(iCurrentReq->Id() == DLocalDrive::EDeleteNotify) //handle DeleteNotify case + { + iReqCur = iPhysEnd; + } else { // Formating to a mis-aligned boundary, so we can't make best use of @@ -2727,9 +2510,25 @@ iMedReq = aRequest; SetCurrentConsumption(aCurrent); +#ifdef EMMC_PARTITION_TEST_MODE_ENABLED + if((iSession->Partition() & TExtendedCSD::EPartitionTestMode) != 0) + { + // driver in test mode, target partition must be set by ControlIO() KMmcSwitchPartition + } + else +#endif // EMMC_PARTITION_TEST_MODE_ENABLED + if (iCurrentReq) + // if iCurrentReq is NULL then it is assuned to be a request for a removable drive + // multiple physical partitions are not supported on removable drives hence partition settting is not requied + { + TInt ptn = iCurrentReq->Drive()->iPartitionNumber; + TInt eMmcPtn = GetEMmcPartitionMapping(ptn); + iSession->SetPartition(eMmcPtn); + } + // Reset the card pointer just in case the stack has changed it. iSession->SetCard(iCard); - + TInt r = InCritical(); if (r == KErrNone) { @@ -2783,6 +2582,9 @@ aInfo.iConnectionBusType = EConnectionBusInternal; aInfo.iDriveAtt = KDriveAttLocal; aInfo.iMediaAtt = KMediaAttFormattable; + + if(iCard->ExtendedCSD().ExtendedCSDRev() >= 5 && KTRIMEnabled) //TRIM support for v4.4+ + aInfo.iMediaAtt |= KMediaAttDeleteNotify; if(iCard->iFlags & KMMCardIsLockable) aInfo.iMediaAtt |= KMediaAttLockable; @@ -2899,6 +2701,8 @@ #if defined(__DEMAND_PAGING__) && !defined(__WINS__) || DMediaPagingDevice::PageInRequest(*iCurrentReq) #endif //DEMAND_PAGING + // partition switching + || (GetEMmcPartitionMapping(iCurrentReq->Drive()->iPartitionNumber) != iSession->Partition()) ) { *aAllDone = EFalse; @@ -3745,6 +3549,12 @@ } r=DoWrite(); break; + case DLocalDrive::EDeleteNotify: + if(iCard->ExtendedCSD().ExtendedCSDRev() <5) + { + r=KErrNotSupported; + break; + } case DLocalDrive::EFormat: if (readOnly) { @@ -3908,6 +3718,13 @@ break; } +#ifdef EMMC_PARTITION_TEST_MODE_ENABLED + case KMmcSwitchPartition: + __ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull)); + InvalidateCache(); + iSession->SetPartition((TInt) aParam1); + break; +#endif // EMMC_PARTITION_TEST_MODE_ENABLED default: r=KErrNotSupported; break; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/medmmc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/medmmc/medmmc.h Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,295 @@ +// Copyright (c) 2010 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: +// drivers/medmmc/medmmc.h +// +// + +#ifndef MEDMMC_H +#define MEDMMC_H + +#include +#include + +#if defined(__DEMAND_PAGING__) + // If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO + #if defined( _DEBUG) + #define __TEST_PAGING_MEDIA_DRIVER__ + #endif + #include "mmcdp.h" +#endif + +// Enable this macro to debug cache: +// NB The greater the number of blocks, the slower this is... +//#define _DEBUG_CACHE +#ifdef _DEBUG_CACHE +#define __ASSERT_CACHE(c,p) (void)((c)||(p,0)) +#else +#define __ASSERT_CACHE(c,p) +#endif + +const TInt KDiskSectorSize = 512; +const TInt KDiskSectorShift = 9; + + +class DMmcMediaDriverFlash : public DMediaDriver + { +public: + DMmcMediaDriverFlash(TInt aMediaId); + ~DMmcMediaDriverFlash(); + // ...from DMediaDriver + virtual void Close(); + // replacing pure virtual + virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*); + virtual TInt Request(TLocDrvRequest& aRequest); + virtual TInt PartitionInfo(TPartitionInfo& anInfo); + virtual void NotifyPowerDown(); + virtual void NotifyEmergencyPowerDown(); + // For creation by DPhysicalDeviceMediaMmcFlash + TInt DoCreate(TInt aMediaId); + + +private: + enum TPanic + { + EDRInUse = 0x0000, EDRStart, EDRNotPositive, EDREnd, + ELRRequest = 0x0010, ELRStart, ELRNotPositive, ELREnd, ELRCached, + EDWInUse = 0x0020, EDWStart, EDWNotPositive, EDWEnd, + EDFInUse = 0x0030, EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket, + ELWRequest = 0x0040, ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign, + ELWLength, ELFStart, ELFEnd, ELFNotPositive, + ERPIInUse = 0x0050, + EPCInUse = 0x0060, EPCFunc, + ESECBQueued = 0x0070, + EDSEDRequest = 0x0080, EDSEDNotErrComplete, + ECRReqIdle = 0x0090, ECRRequest, + ERRBStAlign = 0x00a0, ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos, + ERRBOverflow, ERRBCchInv, ERRBExist, + ERWBStPos = 0x00b0, ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv, + EMBStPos = 0x00c0, EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign, + EMBOverflow, EMBCchInvPre, EMBCchInvPost, + EBGAStPos = 0x00d0, EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign, + EBGAOverflow, EBGACchInv, + EICMNegative = 0x00e0, EICMOverflow, ECMIOverflow, + EGCBAlign = 0x00f0, EGCBPos, EGCBCchInv, + + ECFSessPtrNull = 0x0100, // Code Fault - session pointer NULL + + EDBNotEven = 0x0110, // Not and even number of blocks in the buffer cache + EDBCBQueued = 0x0111, // The data transfer callback is already queued + EDBLength = 0x0112, // The length of data to transfer in data transfer callback is not positive + EDBLengthTooBig = 0x0113, // The length of data to transfer in data transfer callback is too big + EDBOffsetTooBig = 0x0114, // The Offset into the user data buffer is too big + EDBCacheInvalid = 0x0115, // The cache is invalid at the end of data transfer + EDBNotOptimal = 0x0116, // Due to Cache size DB functionality will never be utilised + ENoDBSupport = 0x0120, // DMA request arrived but PSL does not support double buffering + ENotDMAAligned = 0x0121, + EArrayBoundsExc = 0x0122 // Array bounds exceeded (either too small or too large) + }; + static void Panic(TPanic aPnc); + + enum TMediaRequest + { + EMReqRead = 0, + EMReqWrite = 1, + EMReqFormat = 2, + EMReqPtnInfo, + EMReqPswdCtrl, + EMReqForceErase, + EMReqUpdatePtnInfo, + EMReqWritePasswordData, + EMReqIdle, + EMReqEMMCPtnInfo, + }; + enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd}; + + enum {KWtRBMFst = 0x00000001, // iWtRBM - Read First Block only + KWtRBMLst = 0x00000002, // iWtRBM - Read Last Block only + KWtMinFst = 0x00000004, // iWtRBM - Write First Block only + KWtMinLst = 0x00000008, // iWtRBM - Write Last Block only + KIPCSetup = 0x00000010, // iRdROB - IPC Setup Next Iteration + KIPCWrite = 0x00000020}; // iRdROB - IPC Write Next Iteration + +public: + inline void SetEMmcPartitionMapping(TInt aLocalPtn, TInt aEMmcPtn) + { + __ASSERT_DEBUG((aLocalPtn >= 0) && (aLocalPtn < KMaxLocalDrives), Kern::Fault("Mmc: Array bounds exception", __LINE__)); + iEMmcPartitionMappings[aLocalPtn] = aEMmcPtn; + }; + + inline TInt GetEMmcPartitionMapping(TInt aLocalPtn) const + { + __ASSERT_DEBUG((aLocalPtn >= 0) && (aLocalPtn < KMaxLocalDrives), Kern::Fault("Mmc: Array bounds exception", __LINE__)); + return iEMmcPartitionMappings[aLocalPtn]; + }; + + +private: + // MMC device specific stuff + TInt DoRead(); + TInt DoWrite(); + TInt DoFormat(); + TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo); + + inline DMMCStack& Stack() const; + inline TInt CardNum() const; + inline TMediaRequest CurrentRequest() const; + + TInt LaunchRead(TInt64 aStart, TUint32 aLength); + TInt LaunchDBRead(); + TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength); + + TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq); + TInt LaunchFormat(TInt64 aStart, TUint32 aLength); + + TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData); + TInt LaunchRPIRead(); + TInt LaunchRPIErase(); + TInt DecodePartitionInfo(); + TInt WritePartitionInfo(); + TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry); + TInt CreateDefaultPartition(); + + +#if defined __TEST_PAGING_MEDIA_DRIVER__ + TInt HandleControlIORequest(); +#endif + + static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors); + + TInt CheckDevice(TMediaReqType aReqType); + + static void SessionEndCallBack(TAny* aMediaDriver); + static void SessionEndDfc(TAny* aMediaDriver); + void DoSessionEndDfc(); + + static void DataTransferCallBack(TAny* aMediaDriver); + static void DataTransferCallBackDfc(TAny* aMediaDriver); + + void DoReadDataTransferCallBack(); + void DoWriteDataTransferCallBack(); + void DoPhysReadDataTransferCallBack(); + void DoPhysWriteDataTransferCallBack(); + + TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength); + TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength); + void PrepareNextPhysicalFragment(); + + TInt EngageAndSetReadRequest(TMediaRequest aRequest); + TInt EngageAndSetWriteRequest(TMediaRequest aRequest); + TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent); + void CompleteRequest(TInt aReason); + + TInt ReadDataUntilCacheExhausted(TBool* aAllDone); + TInt WriteDataToUser(TUint8* aBufPtr); + TInt ReadDataFromUser(TDes8& aDes, TInt aOffset); + TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength); + TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM); + void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex); + void BuildGammaArray(TInt64 aStart, TInt64 aEnd); + void InvalidateCache(); + void InvalidateCache(TInt64 aStart, TInt64 aEnd); + TUint8* IdxToCchMem(TInt aIdx) const; + TInt CchMemToIdx(TUint8* aMemP) const; + + TInt DoPasswordOp(); + void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData); + void Reset(); + TInt AllocateSession(); + +#ifdef _DEBUG_CACHE + TBool CacheInvariant(); + TUint8* GetCachedBlock(TInt64 aAddr); +#endif +private: + DMMCStack* iStack; // controller objects + TMMCard* iCard; + DMMCSession* iSession; + DMMCSocket* iSocket; + + TInt iCardNumber; + + TUint iBlkLenLog2; // cached CSD data + TUint32 iBlkLen; + TInt64 iBlkMsk; + TBool iReadBlPartial; + TUint32 iPrWtGpLen; // preferred write group size in bytes, + TInt64 iPrWtGpMsk; + + TInt iReadCurrentInMilliAmps; // power management + TInt iWriteCurrentInMilliAmps; + + TUint8* iMinorBuf; // MBR, CMD42, partial read + TUint8* iCacheBuf; // cached buffer + TUint32 iMaxBufSize; + TInt iBlocksInBuffer; + TInt64* iCachedBlocks; + TInt* iGamma; // B lookup, ReserveReadBlocks() + TUint8* iIntBuf; // start of current buffer region + TInt iLstUsdCchEnt; // index of last used cache entry + + TLocDrvRequest* iCurrentReq; // Current Request + TMediaRequest iMedReq; + + TInt64 iReqStart; // user-requested start region + TInt64 iReqCur; // Currently requested start region + TInt64 iReqEnd; // user-requested end region + TInt64 iPhysStart; // physical region for one operation + TInt64 iPhysEnd; // physical end point for one operation + TInt64 iDbEnd; // Double buffer end point for one operation + + TUint64 iEraseUnitMsk; + + TUint iWtRBM; // Write - Read Before Modify Flags + TUint iRdROB; // Read - Read Odd Blocks Flags + + TInt iFragOfset; + TUint32 iIPCLen; + TUint32 iNxtIPCLen; + TUint32 iBufOfset; + + TUint iHiddenSectors; // bootup / password + + TMMCCallBack iSessionEndCallBack; + TDfc iSessionEndDfc; + + TPartitionInfo* iPartitionInfo; + TMMCMediaTypeEnum iMediaType; + TMMCEraseInfo iEraseInfo; + TBool iMbrMissing; + TInt iMediaId; + + DMMCStack::TDemandPagingInfo iDemandPagingInfo; + +#if defined(__TEST_PAGING_MEDIA_DRIVER__) + SMmcStats iMmcStats; +#endif // __TEST_PAGING_MEDIA_DRIVER__ + + TMMCCallBack iDataTransferCallBack; // Callback registered with the MMC stack to perform double-buffering + TDfc iDataTransferCallBackDfc; // ...and the associated DFC queue. + + TBool iSecondBuffer; // Specified the currently active buffer + TBool iDoLastRMW; // ETrue if the last double-buffer transfer requires RMW modification + TBool iDoDoubleBuffer; // ETrue if double-buffering is currently active + TBool iDoPhysicalAddress; // ETrue if Physical Addressing is currently active + TBool iCreateMbr; + TBool iReadToEndOfCard; // {Read Only} ETrue if Reading to end of Card + + TBool iInternalSlot; + + DEMMCPartitionInfo* iMmcPartitionInfo; // Responsible for decoding partitions for embedded devices + TInt iEMmcPartitionMappings[KMaxLocalDrives]; // holds the mapping of emmc partitions + }; + +#endif + diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/medmmc.mmp --- a/kernel/eka/drivers/medmmc/medmmc.mmp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/medmmc/medmmc.mmp Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1998-2010 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" @@ -28,13 +28,20 @@ //Define this macro to create an MBR when formatting low-capacity MMC cards : //macro SYMBIAN_CREATE_MBR_ON_LOW_CAPACITY_MMC +// Define this macro to bypass automatic partition switching - in this case +// switching can also be done by HandleControlIORequest() +// macro EMMC_PARTITION_TEST_MODE_ENABLED + source medmmc.cpp source mmcptn.cpp +source medmmcpatchdata.cpp library epbusmmc.lib library elocd.lib library emmcptn.lib +DEFFILE ~/medmmc.def + linkas medmmc.pdd start wins diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/medmmcpatchdata.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/medmmc/medmmcpatchdata.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,21 @@ +// Copyright (c) 2010 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: +// Media driver for MultiMediaCard Flash device, patchable constants +// +// + +#include + +// Patchable constant used to enable TRIM. The feature is enabled by default. +EXPORT_C extern const TUint KTRIMEnabled = 1; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/medmmc/mmcdp.h --- a/kernel/eka/drivers/medmmc/mmcdp.h Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/medmmc/mmcdp.h Mon Oct 11 19:11:06 2010 +0100 @@ -21,7 +21,8 @@ #ifdef __TEST_PAGING_MEDIA_DRIVER__ -const TInt KMmcGetStats = 0x00000001; +const TInt KMmcGetStats = 0x00000001; +const TInt KMmcSwitchPartition = 0x00000002; struct SMmcStats { TInt iReqPage; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/epbusm.mmh --- a/kernel/eka/drivers/pbus/mmc/epbusm.mmh Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/epbusm.mmh Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1998-2010 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" @@ -37,6 +37,7 @@ source stackbody.cpp source session.cpp source mmccd_init.cpp +source rpmbstack.cpp library elocd.lib @@ -48,4 +49,4 @@ uid 0x1000008d 0x10004087 -capability all \ No newline at end of file +capability all diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/mmccd_init.cpp --- a/kernel/eka/drivers/pbus/mmc/mmccd_init.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/mmccd_init.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1995-2010 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" @@ -17,8 +17,7 @@ #include #include - - +#include /** @@ -207,6 +206,10 @@ else __KTRACE_OPT(KPBUS1,Kern::Printf("Socket %d not MMC card",i)); } + + // set RpmbConfigRead to true and ensure that changes to RpmbConfigRead, NumberOfRpmbs + // and TheRpmbs are flushed at the same time + __e32_atomic_store_ord32(&RpmbParmsPopulated, ETrue); __KTRACE_OPT(KPBUS1,Kern::Printf("iStack->MachineInfo(mi); + // Retrieve RPMB specific information from the PSL layer + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Begin registering RPMB information from PSL layer")); + + TMMCMachineInfoV44 mi; + TMMCMachineInfoV44Pckg machineInfoPckg(mi); + pS->iStack->MachineInfo(machineInfoPckg); + + // Register each slot marked as being RPMB capable + // Code won't write beyond the end of TheRpmbs[] because 4 slots are reserved + // for each pbus socket and only 4 slots are processed for each socket + TInt rpmbSlots = (mi.iRpmbSlotCount <= 4) ? mi.iRpmbSlotCount : 4; + + // if baseport set up so that iRpmbSlotList==NULL assert now + __ASSERT_ALWAYS((((rpmbSlots>0)&&(mi.iRpmbSlotList!=NULL))||(rpmbSlots==0)), Kern::Fault(__FILE__, __LINE__)); + TInt i; + for ( i=0; i +#include + +#include "OstTraceDefinitions.h" +#ifdef OST_TRACE_COMPILER_IN_USE +#include "../../../include/drivers/locmedia_ost.h" +#ifdef __VC32__ +#pragma warning(disable: 4127) // disabling warning "conditional expression is constant" +#endif +#include "rpmbstackTraces.h" +#endif + +TMMCErr DMMCStack::CIMRpmbAccessSM() + { +enum TStates + { + EStBegin, + EStEnd + }; + + DMMCSession& s=Session(); + + //Extract the RPMB request type from the command. JEDEC specify this to be situated + //at offset 0 in the packet. When accessing the hardware, this is reversed and is + //at offset 511 + TUint8 requestType = * (s.Command().iDataMemoryP + KRpmbRequestLsbOffset); + + //There are 5 possible rpmb request types that can be passed through the state machines: + // + //Authentication Key programming request: KRpmbRequestWriteKey = 0x001 + //Reading of the write counter value request: KRpmbRequestReadWriteCounter = 0x0002; + //Authenticated data write request: KRpmbRequestWriteData = 0x0003; + //Authenticated data read request: KRpmbRequestReadData = 0x0004; + //Result read request: KRpmbRequestReadResultRegister = 0x0005; + // + + SMF_BEGIN + + switch (requestType) + { + case KRpmbRequestWriteKey: + SMF_INVOKES(CIMRpmbWriteAuthenticationKeySMST, EStEnd); + case KRpmbRequestReadWriteCounter: + SMF_INVOKES(CIMRpmbReadWrCounterSMST, EStEnd); + case KRpmbRequestWriteData: + SMF_INVOKES(CIMRpmbWriteSMST, EStEnd); + case KRpmbRequestReadData: + SMF_INVOKES(CIMRpmbReadSMST, EStEnd); + default: + break; + } + + SMF_END +} + + +TMMCErr DMMCStack::CIMRpmbWriteAuthenticationKeySM() + { + enum TStates + { + EStBegin, // Write key request + EStSetupReadRequest, + EStReadResult, + EStError, + EStEnd + }; + + DMMCSession& s=Session(); + + SMF_BEGIN + + // + // Setup write request + // CMD23 Reliable Write = 1 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendRequest(ETrue); + // + // KMMCErrByPass is routinely thrown in the ReadWriteBlocks state machine. + // It is thrown to indicate that the current command in the state machine is not CMD42(lock/unlock) + // We need to trap this error here to stop the RPMB state machines from unravelling and passing + // the error upwards. + // + m.SetTraps(KMMCErrBypass); + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM1, "RPMB: Write Key State Machine - send write key request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - send write key request packet")); + + SMF_INVOKES(CIMReadWriteBlocksSMST, EStSetupReadRequest); + + SMF_STATE(EStSetupReadRequest) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM2, "RPMB: Write Key State Machine - sent write key request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - sent write key request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM3, "RPMB: Write Key State Machine - sent write key request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - sent write key request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read result register request + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendReadResultRegisterRequest(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM4, "RPMB: Write Key State Machine - send read result register request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - send read result register request packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStReadResult) + + SMF_STATE(EStReadResult) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM5, "RPMB: Write Key State Machine - sent read result register request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - sent read result register request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM6, "RPMB: Write Key State Machine - sent read result register request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - sent read result register request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read response + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD18 + // + s.SetupRpmbReceiveResponse(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITEAUTHENTICATIONKEYSM7, "RPMB: Write Key State Machine - get read packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write Key State Machine - get read packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStEnd); + + SMF_STATE(EStError) + SMF_RETURN(err); + + SMF_END + } + + +TMMCErr DMMCStack::CIMRpmbReadWrCounterSM() + { + enum TStates + { + EStBegin, // Read counter request + EStReadResult, + EStError, + EStEnd + }; + + DMMCSession& s=Session(); + + SMF_BEGIN + + // + // Setup write request + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendRequest(EFalse); + m.SetTraps(KMMCErrBypass); + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADWRCOUNTERSM1, "RPMB: Read Write Counter State Machine - send read counter request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read Write Counter State Machine - send read counter request packet")); + + SMF_INVOKES(CIMReadWriteBlocksSMST, EStReadResult) + + SMF_STATE(EStReadResult) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADWRCOUNTERSM2, "RPMB: Read Write Counter State Machine - sent read counter request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read Write Counter State Machine - sent read counter request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBREADWRCOUNTERSM3, "RPMB: Read Write Counter State Machine - sent read counter request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read Write Counter State Machine - sent read counter request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read response + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD18 + // + s.SetupRpmbReceiveResponse(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADWRCOUNTERSM4, "RPMB: Read Write Counter State Machine - get read packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read Write Counter State Machine - get read packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStEnd); + + SMF_STATE(EStError) + SMF_RETURN(err); + + SMF_END + } + + +TMMCErr DMMCStack::CIMRpmbWriteSM() + { + enum TStates + { + EStBegin, // Write data request + EStSetupReadRequest, + EStReadResult, + EStError, + EStEnd + }; + + DMMCSession& s=Session(); + + SMF_BEGIN + + // + // Setup write request + // CMD23 Reliable Write = 1 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendRequest(ETrue); + m.SetTraps(KMMCErrBypass); + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM1, "RPMB: Write State Machine - send write request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - send write request packet")); + + SMF_INVOKES(CIMReadWriteBlocksSMST, EStSetupReadRequest); + + SMF_STATE(EStSetupReadRequest) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM2, "RPMB: Write State Machine - sent write request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - sent write request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM3, "RPMB: Write State Machine - sent write request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - sent write request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read result register request + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendReadResultRegisterRequest(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM4, "RPMB: Write State Machine - send read result register request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - send read result register request packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStReadResult) + + SMF_STATE(EStReadResult) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM5, "RPMB: Write State Machine - sent read result register request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - sent read result register request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM6, "RPMB: Write State Machine - sent read result register request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - sent read result register request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read response + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD18 + // + s.SetupRpmbReceiveResponse(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBWRITESM7, "RPMB: Write State Machine - get read packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Write State Machine - get read packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStEnd); + + SMF_STATE(EStError) + SMF_RETURN(err); + + SMF_END + } + + +TMMCErr DMMCStack::CIMRpmbReadSM() + { + enum TStates + { + EStBegin, // Read data request + EStReadResult, + EStError, + EStEnd + }; + + DMMCSession& s=Session(); + + SMF_BEGIN + + // + // Setup write request + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD25 + // + s.SetupRpmbSendRequest(EFalse); + m.SetTraps(KMMCErrBypass); + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADSM1, "RPMB: Read State Machine - send read request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read State Machine - send read request packet")); + + SMF_INVOKES(CIMReadWriteBlocksSMST, EStReadResult) + + SMF_STATE(EStReadResult) + + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADSM2, "RPMB: Read State Machine - sent read request packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read State Machine - sent read request packet")); + + if (err != KMMCErrNone) + { + OstTrace1(TRACE_FLOW, DMMCSTACK_CIMRPMBREADSM3, "RPMB: Read State Machine - sent read request packet error = %d", err); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read State Machine - sent read request packet error = %d", err)); + SMF_GOTOS(EStError); + } + // + // Setup read response + // CMD23 Reliable Write = 0 Block Count = 1 + // CMD18 + // + s.SetupRpmbReceiveResponse(); + OstTrace0(TRACE_FLOW, DMMCSTACK_CIMRPMBREADSM4, "RPMB: Read State Machine - get read packet"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: Read State Machine - get read packet")); + SMF_INVOKES(CIMReadWriteBlocksSMST, EStEnd); + + SMF_STATE(EStError) + SMF_RETURN(err); + + SMF_END + } + +TMMCErr DMMCStack::CIMRpmbAccessSMST(TAny* aStackP) + {return(static_cast(aStackP)->CIMRpmbAccessSM());} +TMMCErr DMMCStack::CIMRpmbWriteAuthenticationKeySMST(TAny* aStackP) + {return(static_cast(aStackP)->CIMRpmbWriteAuthenticationKeySM());} +TMMCErr DMMCStack::CIMRpmbReadWrCounterSMST(TAny* aStackP) + {return(static_cast(aStackP)->CIMRpmbReadWrCounterSM());} +TMMCErr DMMCStack::CIMRpmbWriteSMST(TAny* aStackP) + {return(static_cast(aStackP)->CIMRpmbWriteSM());} +TMMCErr DMMCStack::CIMRpmbReadSMST(TAny* aStackP) + {return(static_cast(aStackP)->CIMRpmbReadSM());} diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ InitStackAfterUnlockSM__9DMMCStack @ 94 NONAME ; DMMCStack::InitStackAfterUnlockSM(void) RegisterMediaDevices__26TMMCardControllerInterfacei @ 95 NONAME ; TMMCardControllerInterface::RegisterMediaDevices(int) ModifyCardCapabilitySM__9DMMCStack @ 96 NONAME R3UNUSED ; DMMCStack::ModifyCardCapabilitySM(void) - Dummy1__9DMMCStack @ 97 NONAME R3UNUSED ; DMMCStack::Dummy1(void) + MMCGetExtInterface__F18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 97 NONAME GetInterface__9DMMCStackQ29DMMCStack12TInterfaceIdRPQ29DMMCStack10MInterface @ 98 NONAME R3UNUSED ; DMMCStack::GetInterface(DMMCStack::TInterfaceId, DMMCStack::MInterface *&) MachineInfo__9DMMCStackR5TDes8 @ 99 NONAME R3UNUSED ; DMMCStack::MachineInfo(TDes8 &) SetBusWidth__9DMMCStackUl @ 100 NONAME R3UNUSED ; DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/sdio/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/sdio/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bmarm/sdcard3c/sdio/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ InitStackAfterUnlockSM__9DMMCStack @ 94 NONAME ; DMMCStack::InitStackAfterUnlockSM(void) RegisterMediaDevices__26TMMCardControllerInterfacei @ 95 NONAME ; TMMCardControllerInterface::RegisterMediaDevices(int) ModifyCardCapabilitySM__9DMMCStack @ 96 NONAME R3UNUSED ; DMMCStack::ModifyCardCapabilitySM(void) - Dummy1__9DMMCStack @ 97 NONAME R3UNUSED ; DMMCStack::Dummy1(void) + MMCGetExtInterface__F18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 97 NONAME GetInterface__9DMMCStackQ29DMMCStack12TInterfaceIdRPQ29DMMCStack10MInterface @ 98 NONAME R3UNUSED ; DMMCStack::GetInterface(DMMCStack::TInterfaceId, DMMCStack::MInterface *&) MachineInfo__9DMMCStackR5TDes8 @ 99 NONAME R3UNUSED ; DMMCStack::MachineInfo(TDes8 &) SetBusWidth__9DMMCStackUl @ 100 NONAME R3UNUSED ; DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?InitStackAfterUnlockSM@DMMCStack@@MAEKXZ @ 94 NONAME ; protected: virtual unsigned long __thiscall DMMCStack::InitStackAfterUnlockSM(void) ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 95 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?ModifyCardCapabilitySM@DMMCStack@@MAEKXZ @ 96 NONAME ; unsigned long DMMCStack::ModifyCardCapabilitySM(void) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; void DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ; int MMCGetExtInterface(enum TMMCExtInterfaceId, class MMCMExtInterface * &, void *) ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/sdio/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/sdio/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bwins/sdcard3c/sdio/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?InitStackAfterUnlockSM@DMMCStack@@MAEKXZ @ 94 NONAME ; protected: virtual unsigned long __thiscall DMMCStack::InitStackAfterUnlockSM(void) ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 95 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?ModifyCardCapabilitySM@DMMCStack@@MAEKXZ @ 96 NONAME ; unsigned long DMMCStack::ModifyCardCapabilitySM(void) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; void DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ; int MMCGetExtInterface(enum TMMCExtInterfaceId, class MMCMExtInterface * &, void *) ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 94 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?RequestAsyncPowerDown@DPBusSocket@@QAEXXZ @ 95 NONAME ; public: void __thiscall DPBusSocket::RequestAsyncPowerDown(void) ?ControlIO@DPBusSocket@@UAEHHPAX0@Z @ 96 NONAME ; public: virtual int __thiscall DPBusSocket::ControlIO(int,void *,void *) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; private: virtual void __thiscall DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/sdio/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/sdio/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/bx86/sdcard3c/sdio/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -95,7 +95,7 @@ ?RegisterMediaDevices@TMMCardControllerInterface@@MAEHH@Z @ 94 NONAME ; protected: virtual int __thiscall TMMCardControllerInterface::RegisterMediaDevices(int) ?RequestAsyncPowerDown@DPBusSocket@@QAEXXZ @ 95 NONAME ; public: void __thiscall DPBusSocket::RequestAsyncPowerDown(void) ?ControlIO@DPBusSocket@@UAEHHPAX0@Z @ 96 NONAME ; public: virtual int __thiscall DPBusSocket::ControlIO(int,void *,void *) - ?Dummy1@DMMCStack@@EAEXXZ @ 97 NONAME ; private: virtual void __thiscall DMMCStack::Dummy1(void) + ?MMCGetExtInterface@@YAHW4TMMCExtInterfaceId@@AAPAVMMCMExtInterface@@PAX@Z @ 97 NONAME ?GetInterface@DMMCStack@@MAEXW4TInterfaceId@1@AAPAVMInterface@1@@Z @ 98 NONAME ; protected: virtual void __thiscall DMMCStack::GetInterface(enum DMMCStack::TInterfaceId,class DMMCStack::MInterface * &) ?MachineInfo@DMMCStack@@UAEXAAVTDes8@@@Z @ 99 NONAME ; public: virtual void __thiscall DMMCStack::MachineInfo(class TDes8 &) ?SetBusWidth@DMMCStack@@MAEXK@Z @ 100 NONAME ; protected: virtual void __thiscall DMMCStack::SetBusWidth(unsigned long) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -120,7 +120,7 @@ _ZTV7DMMCPsu @ 119 NONAME ; vtable for DMMCPsu _ZTV9DMMCStack @ 120 NONAME ; vtable for DMMCStack _ZN9DMMCStack22ModifyCardCapabilitySMEv @ 121 NONAME ; DMMCStack::ModifyCardCapabilitySM() - _ZN9DMMCStack6Dummy1Ev @ 122 NONAME + _Z18MMCGetExtInterface18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 122 NONAME _ZN9DMMCStack12GetInterfaceENS_12TInterfaceIdERPNS_10MInterfaceE @ 123 NONAME _ZN9DMMCStack11MachineInfoER5TDes8 @ 124 NONAME _ZN9DMMCStack11SetBusWidthEm @ 125 NONAME diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/sdio/epbusmu.def --- a/kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/sdio/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/eabi/sdcard3c/sdio/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -120,7 +120,7 @@ _ZTV7DMMCPsu @ 119 NONAME ; vtable for DMMCPsu _ZTV9DMMCStack @ 120 NONAME ; vtable for DMMCStack _ZN9DMMCStack22ModifyCardCapabilitySMEv @ 121 NONAME ; DMMCStack::ModifyCardCapabilitySM() - _ZN9DMMCStack6Dummy1Ev @ 122 NONAME + _Z18MMCGetExtInterface18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 122 NONAME _ZN9DMMCStack12GetInterfaceENS_12TInterfaceIdERPNS_10MInterfaceE @ 123 NONAME _ZN9DMMCStack11MachineInfoER5TDes8 @ 124 NONAME _ZN9DMMCStack11SetBusWidthEm @ 125 NONAME diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp --- a/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -1482,8 +1482,8 @@ SMF_STATE(EstCheckController) OstTrace0( TRACE_INTERNALS, DSDSTACK_SWITCHTOHIGHSPEEDMODESM2, "EstCheckController"); // Get the clock speed supported by the controller - TMMCMachineInfoV4 machineInfo; - TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo); + TMMCMachineInfoV44 machineInfo; + TMMCMachineInfoV44Pckg machineInfoPckg(machineInfo); MachineInfo(machineInfoPckg); if (machineInfo.iVersion >= TMMCMachineInfoV4::EVersion4) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/session.cpp --- a/kernel/eka/drivers/pbus/mmc/session.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/session.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -36,6 +36,7 @@ * @param aCallBack reference to a TMMCCallback object to be called upon completion. */ : iCallBack(aCallBack), + iPartition(TExtendedCSD::ESelectUserArea), // UDA is the hardware default #ifdef __EPOC32__ iPollTimer(DMMCSession::PollTimerCallBack, this), iRetryTimer(DMMCSession::RetryTimerCallBack, this), @@ -419,7 +420,8 @@ DMMCStack::NoSessionSMST, // CIMLockStack is never really executed as a session DMMCStack::InitStackAfterUnlockSMST, DMMCStack::CIMAutoUnlockSMST, - DMMCStack::ExecSleepCommandSMST // CIMSleep + DMMCStack::ExecSleepCommandSMST, // CIMSleep + DMMCStack::CIMRpmbAccessSMST // CIMRpmbAccess }; if (aSessNum >= 0 && aSessNum < (TInt) KMMCMaxSessionTypeNumber) diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/drivers/pbus/mmc/stack.cpp --- a/kernel/eka/drivers/pbus/mmc/stack.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/drivers/pbus/mmc/stack.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -20,6 +20,23 @@ #include #include "stackbody.h" +/* + Global helper object shared by all stacks to hold device specific RPMB information + */ + static MRpmbInfo rpmbInfo; + +/* + Global counter for number or RPMB partitions. Only one partition per device +*/ + +GLDEF_D TUint NumberOfRpmbs = 0; +/* + Global holder for RPMB parameters + */ +GLDEF_D TRpmbDeviceParms TheRpmbs[KMaxPBusSockets*4]; + +GLDEF_D TBool RpmbParmsPopulated = EFalse; + #include "OstTraceDefinitions.h" #ifdef OST_TRACE_COMPILER_IN_USE #include "../../../include/drivers/locmedia_ost.h" @@ -3007,6 +3024,79 @@ } +TMMCErr DMMCStack::SwitchPartitionSM() +/** + * This SM function must be invoked before execution of any partition-specific command. + * + * @return MMC error code + */ + { + __KTRACE_OPT(KPBUS1,Kern::Printf("=mst:sp")); + + enum states + { + EStBegin=0, + EStPartitionSelected, + EStEnd + }; + + DMMCSession& s=Session(); + OstTrace1( TRACE_INTERNALS, DMMCSTACK_SWITCHPARTITIONSM1, "Current session=0x%x", &s ); + + SMF_BEGIN + + OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHPARTITIONSM2, "EStBegin" ); + + TMMCard *cardP = s.CardP(); + if(cardP) + { + TInt curPtn = cardP->ExtendedCSD().BootConfig() & KMMCSelectPartitionMask; + TInt tgtPtn = s.Partition() & KMMCSelectPartitionMask; + + if(curPtn != tgtPtn) + { + OstTraceExt2( TRACE_INTERNALS, DMMCSTACK_SWITCHPARTITIONSM3, + "EStSelectPartition: Switching partitions from 0x%02X to 0x%02X", + (TUint32) curPtn, (TUint32) tgtPtn); + + // need to preserve the non-partition related bits + tgtPtn |= cardP->ExtendedCSD().BootConfig() & ~KMMCSelectPartitionMask; + + TMMCArgument arg = TExtendedCSD::GetWriteArg( + TExtendedCSD::EWriteByte, TExtendedCSD::EBootConfigIndex, tgtPtn, 0); + + CurrentSessPushCmdStack(); + s.FillCommandDesc(ECmdSwitch, arg); + SMF_INVOKES(ExecSwitchCommandST, EStPartitionSelected) + } + } + + // no switching required + SMF_GOTOS( EStEnd ) + + SMF_STATE(EStPartitionSelected) + + OstTrace0( TRACE_INTERNALS, DMMCSTACK_SWITCHPARTITIONSM4, "EStPartitionSelected" ); + const TMMCStatus status(s.ResponseP()); + CurrentSessPopCmdStack(); + if (status.Error()) + { + OstTraceFunctionExitExt( DMMCSTACK_SWITCHPARTITIONSM_EXIT1, this, (TInt) KMMCErrStatus ); + return KMMCErrStatus; + } + else + { // update extended CSD + TInt ptn = (s.CardP()->ExtendedCSD().BootConfig() & ~KMMCSelectPartitionMask) | (s.Partition() & KMMCSelectPartitionMask); + memset( s.CardP()->iExtendedCSD.Ptr() + TExtendedCSD::EBootConfigIndex, ptn, 1); + OstTrace1( TRACE_INTERNALS, DMMCSTACK_SWITCHPARTITIONSM5, + "EStPartitionSelected: Switched to partition 0x%02X", ptn ); + } + + SMF_END + + } + + inline TMMCErr DMMCStack::AttachCardSM() /** * This SM function must be invoked by every session which is CardControlled. @@ -3045,7 +3135,6 @@ s.SynchBlock( KMMCBlockOnCardInUse ); SMF_WAIT } - if( s.iCardP->IsPresent() && s.iCardP->iCID == s.iCID ) s.iCardP->iUsingSessionP = &s; else @@ -3070,6 +3159,7 @@ SMF_STATE(EStAttStatus) + OstTrace0( TRACE_INTERNALS, DMMCSTACK_ATTACHCARDSM3, "EStAttStatus" ); CurrentSessPopCmdStack(); OstTraceFunctionExitExt( DMMCSTACK_ATTACHCARDSM_EXIT3, this, (TInt) err ); @@ -3357,53 +3447,101 @@ SMF_GOTOS(EStExit); } + + memcpy(s.CardP()->iExtendedCSD.Ptr(), iPSLBuf, KMMCExtendedCSDLength); + + // Call a licencee-specific state machine to allow the Extended CSD register to be modified. SMF_INVOKES( ModifyCardCapabilitySMST, EStGotModifiedExtendedCSD ) SMF_STATE(EStGotModifiedExtendedCSD) OstTrace0( TRACE_INTERNALS, DMMCSTACK_INITSTACKAFTERUNLOCKSM7, "EStGotExtendedCSD" ); + + const TExtendedCSD& extendedCSD = s.CardP()->ExtendedCSD(); __KTRACE_OPT(KPBUS1, Kern::Printf("Extended CSD")); - __KTRACE_OPT(KPBUS1, Kern::Printf("CSDStructureVer: %u", s.CardP()->ExtendedCSD().CSDStructureVer())); - __KTRACE_OPT(KPBUS1, Kern::Printf("ExtendedCSDRev: %u", s.CardP()->ExtendedCSD().ExtendedCSDRev())); + __KTRACE_OPT(KPBUS1, Kern::Printf("CSDStructureVer: %u", extendedCSD.CSDStructureVer())); + __KTRACE_OPT(KPBUS1, Kern::Printf("ExtendedCSDRev: %u", extendedCSD.ExtendedCSDRev())); __KTRACE_OPT(KPBUS1, Kern::Printf("-------------------------------")); - __KTRACE_OPT(KPBUS1, Kern::Printf("SupportedCmdSet: %u", s.CardP()->ExtendedCSD().SupportedCmdSet())); - __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz360V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz360V())); - __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz360V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz360V())); - __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz195V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass26Mhz195V())); - __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz195V: 0x%02X", s.CardP()->ExtendedCSD().PowerClass52Mhz195V())); - __KTRACE_OPT(KPBUS1, Kern::Printf("CardType: %u", s.CardP()->ExtendedCSD().CardType())); - __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSet: %u", s.CardP()->ExtendedCSD().CmdSet())); - __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSetRev: %u", s.CardP()->ExtendedCSD().CmdSetRev())); - __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass: %u", s.CardP()->ExtendedCSD().PowerClass())); - __KTRACE_OPT(KPBUS1, Kern::Printf("HighSpeedTiming: %u", s.CardP()->ExtendedCSD().HighSpeedTiming())); - __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapacityEraseGroupSize: %u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize())); - __KTRACE_OPT(KPBUS1, Kern::Printf("AccessSize: %u", s.CardP()->ExtendedCSD().AccessSize())); - __KTRACE_OPT(KPBUS1, Kern::Printf("BootInfo: %u", s.CardP()->ExtendedCSD().BootInfo() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("BootSizeMultiple: %u", s.CardP()->ExtendedCSD().BootSizeMultiple() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("EraseTimeoutMultiple: %u", s.CardP()->ExtendedCSD().EraseTimeoutMultiple() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("ReliableWriteSector: %u", s.CardP()->ExtendedCSD().ReliableWriteSector() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapWriteProtGroupSize: %u", s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVcc: %u", s.CardP()->ExtendedCSD().SleepCurrentVcc() )); - __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVccQ: %u", s.CardP()->ExtendedCSD().SleepCurrentVccQ())); - __KTRACE_OPT(KPBUS1, Kern::Printf("SleepAwakeTimeout: %u", s.CardP()->ExtendedCSD().SleepAwakeTimeout())); - __KTRACE_OPT(KPBUS1, Kern::Printf("BootConfig: %u", s.CardP()->ExtendedCSD().BootConfig())); - __KTRACE_OPT(KPBUS1, Kern::Printf("BootBusWidth: %u", s.CardP()->ExtendedCSD().BootBusWidth())); - __KTRACE_OPT(KPBUS1, Kern::Printf("EraseGroupDef: %u", s.CardP()->ExtendedCSD().EraseGroupDef())); + __KTRACE_OPT(KPBUS1, Kern::Printf("SupportedCmdSet: %u", extendedCSD.SupportedCmdSet())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz360V: 0x%02X", extendedCSD.PowerClass26Mhz360V())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz360V: 0x%02X", extendedCSD.PowerClass52Mhz360V())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass26Mhz195V: 0x%02X", extendedCSD.PowerClass26Mhz195V())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass52Mhz195V: 0x%02X", extendedCSD.PowerClass52Mhz195V())); + __KTRACE_OPT(KPBUS1, Kern::Printf("CardType: %u", extendedCSD.CardType())); + __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSet: %u", extendedCSD.CmdSet())); + __KTRACE_OPT(KPBUS1, Kern::Printf("CmdSetRev: %u", extendedCSD.CmdSetRev())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PowerClass: %u", extendedCSD.PowerClass())); + __KTRACE_OPT(KPBUS1, Kern::Printf("HighSpeedTiming: %u", extendedCSD.HighSpeedTiming())); + __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapacityEraseGroupSize: %u", extendedCSD.HighCapacityEraseGroupSize())); + __KTRACE_OPT(KPBUS1, Kern::Printf("AccessSize: %u", extendedCSD.AccessSize())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootInfo: %u", extendedCSD.BootInfo() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootSizeMultiple: %u", extendedCSD.BootSizeMultiple() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("EraseTimeoutMultiple: %u", extendedCSD.EraseTimeoutMultiple() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("ReliableWriteSector: %u", extendedCSD.ReliableWriteSector() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("HighCapWriteProtGroupSize: %u", extendedCSD.HighCapacityWriteProtectGroupSize() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVcc: %u", extendedCSD.SleepCurrentVcc() )); + __KTRACE_OPT(KPBUS1, Kern::Printf("SleepCurrentVccQ: %u", extendedCSD.SleepCurrentVccQ())); + __KTRACE_OPT(KPBUS1, Kern::Printf("SleepAwakeTimeout: %u", extendedCSD.SleepAwakeTimeout())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootConfig: %u", extendedCSD.BootConfig())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootBusWidth: %u", extendedCSD.BootBusWidth())); + __KTRACE_OPT(KPBUS1, Kern::Printf("EraseGroupDef: %u", extendedCSD.EraseGroupDef())); + + // 4.4 extensions + __KTRACE_OPT(KPBUS1, Kern::Printf("ErasedMemoryContent: 0x%02X", extendedCSD.ErasedMemoryContent())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootConfigProtection: 0x%02X", extendedCSD.BootConfigProt())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BootAreaWriteProtectionReg: 0x%02X", extendedCSD.BootAreaWriteProtectionReg())); + __KTRACE_OPT(KPBUS1, Kern::Printf("UserAreaWriteProtectionReg: 0x%02X", extendedCSD.UserAreaWriteProtectionReg())); + __KTRACE_OPT(KPBUS1, Kern::Printf("FWConfiguration: 0x%02X", extendedCSD.FwConfiguration())); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMBSize: 0x%04X", extendedCSD.RpmbSize())); + __KTRACE_OPT(KPBUS1, Kern::Printf("HwResetFunction: 0x%02X", extendedCSD.HwResetFunction())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PartitioningSupport: 0x%02X", extendedCSD.PartitioningSupport())); + __KTRACE_OPT(KPBUS1, Kern::Printf("MaxEnhancedAreaSize: 0x%04X", extendedCSD.MaxEnhancedAreaSize())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PartitionsAttribute: 0x%02X", extendedCSD.PartitionsAttribute())); + __KTRACE_OPT(KPBUS1, Kern::Printf("PartitioningSetting: 0x%02X", extendedCSD.PartitioningSetting())); + __KTRACE_OPT(KPBUS1, Kern::Printf("GPP1: 0x%04X", extendedCSD.GeneralPurposePartition1Size())); + __KTRACE_OPT(KPBUS1, Kern::Printf("GPP2: 0x%04X", extendedCSD.GeneralPurposePartition2Size())); + __KTRACE_OPT(KPBUS1, Kern::Printf("GPP3: 0x%04X", extendedCSD.GeneralPurposePartition3Size())); + __KTRACE_OPT(KPBUS1, Kern::Printf("GPP4: 0x%04X", extendedCSD.GeneralPurposePartition4Size())); + __KTRACE_OPT(KPBUS1, Kern::Printf("EnhancedUserDataSize: 0x%04X", extendedCSD.EnhancedUserDataAreaSize())); + __KTRACE_OPT(KPBUS1, Kern::Printf("EnhancedUserDataStartAddr: 0x%04X", extendedCSD.EnhancedUserDataStartAddress())); + __KTRACE_OPT(KPBUS1, Kern::Printf("BadBlockManagementMode: 0x%04X", extendedCSD.BadBlockManagementMode())); + + + OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM8, "CSDStructureVer=%u; ExtendedCSDRev=%u; SupportedCmdSet=%u", extendedCSD.CSDStructureVer(), extendedCSD.ExtendedCSDRev(), extendedCSD.SupportedCmdSet() ); + OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM9, "PowerClass26Mhz360V=0x%02x; PowerClass52Mhz360V=0x%02x; PowerClass26Mhz195V=0x%02x; PowerClass52Mhz195V=0x%02x", extendedCSD.PowerClass26Mhz360V(), extendedCSD.PowerClass52Mhz360V(), extendedCSD.PowerClass26Mhz195V(), extendedCSD.PowerClass52Mhz195V() ); + OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM10, "CardType=%u; CmdSet=%u; CmdSetRev=%u; PowerClass=%u; HighSpeedTiming=%u", extendedCSD.CardType(), extendedCSD.CmdSet(), extendedCSD.CmdSetRev(), extendedCSD.PowerClass(), extendedCSD.HighSpeedTiming() ); + OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM11, "HighCapacityEraseGroupSize=%u; AccessSize=%u; BootInfo=%u; BootSizeMultiple=%u; EraseTimeoutMultiple=%u", extendedCSD.HighCapacityEraseGroupSize(), extendedCSD.AccessSize(), extendedCSD.BootInfo(), extendedCSD.BootSizeMultiple(), extendedCSD.EraseTimeoutMultiple() ); + OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM12, "ReliableWriteSector=%u; HighCapWriteProtGroupSize=%u; SleepCurrentVcc=%u; SleepCurrentVccQ=%u; SleepAwakeTimeout=%u", extendedCSD.ReliableWriteSector(), extendedCSD.HighCapacityWriteProtectGroupSize(), extendedCSD.SleepCurrentVcc(), extendedCSD.SleepCurrentVccQ(), extendedCSD.SleepAwakeTimeout() ); + OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM13, "BootConfig=%u; BootBusWidth=%u; EraseGroupDef=%u", extendedCSD.BootConfig(), extendedCSD.BootBusWidth(), extendedCSD.EraseGroupDef() ); + + // 4.4 extensions + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx1, "ErasedMemoryContent: 0x%02X", extendedCSD.ErasedMemoryContent()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx2, "BootConfigProtection: 0x%02X", extendedCSD.BootConfigProt()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx3, "BootAreaWriteProtectionReg: 0x%02X", extendedCSD.BootAreaWriteProtectionReg()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx4, "UserAreaWriteProtectionReg: 0x%02X", extendedCSD.UserAreaWriteProtectionReg()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx5, "FWConfiguration: 0x%02X", extendedCSD.FwConfiguration()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx6, "RPMBSize: 0x%04X", extendedCSD.RpmbSize()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx7, "HwResetFunction: 0x%02X", extendedCSD.HwResetFunction()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx8, "PartitioningSupport: 0x%02X", extendedCSD.PartitioningSupport()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx9, "MaxEnhancedAreaSize: 0x%04X", extendedCSD.MaxEnhancedAreaSize()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx10, "PartitionsAttribute: 0x%02X", extendedCSD.PartitionsAttribute()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx11, "PartitioningSetting: 0x%02X", extendedCSD.PartitioningSetting()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx12, "GPP1: 0x%04X", extendedCSD.GeneralPurposePartition1Size()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx13, "GPP2: 0x%04X", extendedCSD.GeneralPurposePartition2Size()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx14, "GPP3: 0x%04X", extendedCSD.GeneralPurposePartition3Size()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx15, "GPP4: 0x%04X", extendedCSD.GeneralPurposePartition4Size()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx16, "EnhancedUserDataSize: 0x%04X", extendedCSD.EnhancedUserDataAreaSize()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx17, "EnhancedUserDataStartAddr: 0x%04X", extendedCSD.EnhancedUserDataStartAddress()); + OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSMx18, "BadBlockManagementMode: 0x%04X", extendedCSD.BadBlockManagementMode()); + - OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM8, "CSDStructureVer=%u; ExtendedCSDRev=%u; SupportedCmdSet=%u", s.CardP()->ExtendedCSD().CSDStructureVer(), s.CardP()->ExtendedCSD().ExtendedCSDRev(), s.CardP()->ExtendedCSD().SupportedCmdSet() ); - OstTraceDefExt4( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM9, "PowerClass26Mhz360V=0x%02x; PowerClass52Mhz360V=0x%02x; PowerClass26Mhz195V=0x%02x; PowerClass52Mhz195V=0x%02x", s.CardP()->ExtendedCSD().PowerClass26Mhz360V(), s.CardP()->ExtendedCSD().PowerClass52Mhz360V(), s.CardP()->ExtendedCSD().PowerClass26Mhz195V(), s.CardP()->ExtendedCSD().PowerClass52Mhz195V() ); - OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM10, "CardType=%u; CmdSet=%u; CmdSetRev=%u; PowerClass=%u; HighSpeedTiming=%u", s.CardP()->ExtendedCSD().CardType(), s.CardP()->ExtendedCSD().CmdSet(), s.CardP()->ExtendedCSD().CmdSetRev(), s.CardP()->ExtendedCSD().PowerClass(), s.CardP()->ExtendedCSD().HighSpeedTiming() ); - OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM11, "HighCapacityEraseGroupSize=%u; AccessSize=%u; BootInfo=%u; BootSizeMultiple=%u; EraseTimeoutMultiple=%u", s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize(), s.CardP()->ExtendedCSD().AccessSize(), s.CardP()->ExtendedCSD().BootInfo(), s.CardP()->ExtendedCSD().BootSizeMultiple(), s.CardP()->ExtendedCSD().EraseTimeoutMultiple() ); - OstTraceDefExt5( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM12, "ReliableWriteSector=%u; HighCapWriteProtGroupSize=%u; SleepCurrentVcc=%u; SleepCurrentVccQ=%u; SleepAwakeTimeout=%u", s.CardP()->ExtendedCSD().ReliableWriteSector(), s.CardP()->ExtendedCSD().HighCapacityWriteProtectGroupSize(), s.CardP()->ExtendedCSD().SleepCurrentVcc(), s.CardP()->ExtendedCSD().SleepCurrentVccQ(), s.CardP()->ExtendedCSD().SleepAwakeTimeout() ); - OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCSTACK_INITSTACKAFTERUNLOCKSM13, "BootConfig=%u; BootBusWidth=%u; EraseGroupDef=%u", s.CardP()->ExtendedCSD().BootConfig(), s.CardP()->ExtendedCSD().BootBusWidth(), s.CardP()->ExtendedCSD().EraseGroupDef() ); - - if (s.CardP()->ExtendedCSD().ExtendedCSDRev() >= 3) - { - if (!(s.CardP()->ExtendedCSD().EraseGroupDef()) && s.CardP()->ExtendedCSD().HighCapacityEraseGroupSize()) + if (extendedCSD.ExtendedCSDRev() >= 3) + { + if (!(extendedCSD.EraseGroupDef()) && extendedCSD.HighCapacityEraseGroupSize()) { // Need to ensure that media is using correct erase group sizes. TMMCArgument arg = TExtendedCSD::GetWriteArg( @@ -3429,7 +3567,7 @@ if (err == KMMCErrNone) { - // EEraseGroupDef has been updated succussfully, + // EEraseGroupDef has been updated successfully, // update the Extended CSD to reflect this memset( s.CardP()->iExtendedCSD.Ptr()+TExtendedCSD::EEraseGroupDefIndex, TExtendedCSD::EEraseGrpDefEnableHighCapSizes, 1); } @@ -3948,8 +4086,8 @@ // Get the bus widths & clocks supported by the controller // NB If the PSL doesn not support TMMCMachineInfoV4, return - TMMCMachineInfoV4 machineInfo; - TMMCMachineInfoV4Pckg machineInfoPckg(machineInfo); + TMMCMachineInfoV44 machineInfo; + TMMCMachineInfoV44Pckg machineInfoPckg(machineInfo); MachineInfo(machineInfoPckg); if (machineInfo.iVersion < TMMCMachineInfoV4::EVersion4) { @@ -5724,6 +5862,7 @@ EStBegin=0, EStRestart, EStAttached, + EStLength, EStLength1, EStLengthSet, EStIssueBlockCount, @@ -5755,7 +5894,6 @@ return KMMCErrNotSupported; } } - s.iState |= KMMCSessStateInProgress; m.SetTraps(KMMCErrInitContext); @@ -5770,9 +5908,15 @@ SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory here } + SMF_BPOINT(EStAttached) OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM4, "EStAttached" ); + SMF_INVOKES( SwitchPartitionSMST, EStLength ) // may have to switch partitions + + SMF_STATE(EStLength) + + OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM16, "EStLength" ); TMMCCommandDesc& cmd = s.Command(); const TUint32 blockLength = cmd.BlockLength(); @@ -5809,7 +5953,7 @@ SMF_STATE(EStLength1) - OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM5, "EStAttached" ); + OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM5, "EStLength" ); const TMMCStatus status(s.ResponseP()); CurrentSessPopCmdStack(); if (status.Error()) @@ -5851,17 +5995,19 @@ const TUint blocks = cmd.NumBlocks(); - SMF_NEXTS(EStBpoint1) + SMF_NEXTS(EStBpoint1) + if ( !(opType & kTypeSpecial) ) // A special session has already set its command descriptor { + if (cmd.iFlags & KMMCCmdFlagReliableWrite) //ensure multiple block commands are used for reliable writing opType |= kTypeMultiple; - if ( (blocks==1) && !(cmd.iFlags & KMMCCmdFlagReliableWrite) ) + if ( (blocks==1) && !(cmd.iFlags & KMMCCmdFlagReliableWrite) && !(cmd.iFlags & KMMCCmdFlagRpmbIO)) { - // Reliable Write requires that Multi-Block command is used. + // Reliable Write & RPMB require that Multi-Block command is used. opType &= ~kTypeMultiple; } @@ -6005,7 +6151,7 @@ // Fall through if CURRENT_STATE is not PGM or DATA SMF_STATE(EStRWFinish) - OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM15, "EStRWFinish" ); + OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMREADWRITEBLOCKSSM15, "EStRWFinish" ); if (TMMCStatus(s.ResponseP()).Error() != 0) { OstTraceFunctionExitExt( DMMCSTACK_CIMREADWRITEBLOCKSSM_EXIT8, this, (TInt) KMMCErrStatus ); @@ -6034,6 +6180,7 @@ EStBegin=0, EStRestart, EStAttached, + EStLength, EStStartTagged, EStEndTagged, EStErased, @@ -6069,13 +6216,21 @@ OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM3, "EStRestart" ); SMF_CALLMEWR(EStRestart) // Create a recursive call entry to recover from Init - - s.ResetCommandStack(); + + CurrentSessPushCmdStack(); //Push stack pointer to preserve flags for TRIM + SMF_INVOKES( AttachCardSMST, EStAttached ) // attachment is mandatory SMF_BPOINT(EStAttached) OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM4, "EStAttached" ); + SMF_INVOKES( SwitchPartitionSMST, EStLength ) // may have to switch partitions + + SMF_STATE(EStLength) + + OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM13, "EStLength" ); + + CurrentSessPopCmdStack(); TMMCCommandDesc& cmd = s.Command(); if(cmd.iTotalLength == 0) @@ -6095,6 +6250,14 @@ break; case ECIMEraseGroup: OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM6, "ECIMEraseGroup" ); + + if(cmd.iFlags & KMMCCmdFlagDeleteNotify) + { + cmd.iBlockLength = KMMCardHighCapBlockSize; //TRIM cmd blocklength + cmd.iCommand = ECmdTagEraseGroupStart; + break; + } + cmd.iBlockLength = s.iCardP->iCSD.EraseGroupSize(); if(cmd.iBlockLength == 0 || cmd.iTotalLength % cmd.iBlockLength != 0) { @@ -6123,7 +6286,7 @@ SMF_STATE(EStStartTagged) OstTrace0( TRACE_INTERNALS, DMMCSTACK_CIMERASESM7, "EStStartTagged" ); - const TMMCCommandDesc& cmd = s.Command(); + TMMCCommandDesc& cmd = s.Command(); TMMCCommandEnum command; TUint endAddr = cmd.iArgument; @@ -6134,20 +6297,29 @@ } else { - if(cmd.IsBlockCmd()) - { - endAddr += (cmd.iTotalLength - cmd.iBlockLength) >> KMMCardHighCapBlockSizeLog2; - } - else - { - endAddr += cmd.iTotalLength - cmd.iBlockLength; - } + if(cmd.iFlags & KMMCCmdFlagDeleteNotify) + { + endAddr += cmd.IsBlockCmd() ? (cmd.iTotalLength / cmd.iBlockLength - 1) : (cmd.iTotalLength - cmd.iBlockLength); + command = ECmdTagEraseGroupEnd; + } + else + { + if(cmd.IsBlockCmd()) + { + endAddr += (cmd.iTotalLength - cmd.iBlockLength) >> KMMCardHighCapBlockSizeLog2; + } + else + { + endAddr += cmd.iTotalLength - cmd.iBlockLength; + } - command = ECmdTagEraseGroupEnd; - } - - CurrentSessPushCmdStack(); + command = ECmdTagEraseGroupEnd; + } + } + + const TUint flags = cmd.iFlags; s.FillCommandDesc( command, endAddr ); + cmd.iFlags = flags; //Preserving current flags for TRIM SMF_INVOKES( ExecCommandSMST, EStEndTagged ) SMF_STATE(EStEndTagged) @@ -6159,7 +6331,16 @@ const TInt KMaxEraseTimeoutInSeconds = 30; iBody->SetInactivityTimeout(KMaxEraseTimeoutInSeconds); m.SetTraps(KMMCErrAll); - s.FillCommandDesc( ECmdErase, 0 ); + + TMMCCommandDesc& cmd = s.Command(); + + if(cmd.iFlags & KMMCCmdFlagDeleteNotify) + { + s.FillCommandDesc(ECmdErase, KMMCCmdTrim); + } + else + s.FillCommandDesc( ECmdErase, 0 ); + SMF_INVOKES( ExecCommandSMST, EStErased ) SMF_STATE(EStErased) @@ -6602,6 +6783,9 @@ TMMCErr DMMCStack::AttachCardSMST( TAny* aStackP ) { return( static_cast(aStackP)->AttachCardSM() ); } +TMMCErr DMMCStack::SwitchPartitionSMST( TAny* aStackP ) + { return( static_cast(aStackP)->SwitchPartitionSM() ); } + TMMCErr DMMCStack::ExecCommandSMST( TAny* aStackP ) { return( static_cast(aStackP)->ExecCommandSM() ); } @@ -6689,8 +6873,6 @@ return new DMMCSession(aCallBack); } -EXPORT_C void DMMCStack::Dummy1() {} - /** * Calls the PSL-implemented function SetBusWidth() if the bus width has changed * @@ -6743,8 +6925,14 @@ { } -EXPORT_C void DMMCStack::MachineInfo(TDes8& /*aMachineInfo*/) - { +EXPORT_C void DMMCStack::MachineInfo(TDes8& aMachineInfo) +/** + * Default implementation of method. Calls + * DMMCStack::MachineInfo(TMMCMachineInfo& aMachineInfo) + */ + { + TMMCMachineInfoV44Pckg& mi = static_cast (aMachineInfo); + MachineInfo(mi()); } TBusWidth DMMCStack::BusWidthEncoding(TInt aBusWidth) const @@ -7560,3 +7748,39 @@ return r; } +/** + A generic adapter function for returning an interface of specified type + The caller should set aInterfacePtr to NULL before calling + @aInterfaceId Denotes the required interface to be returned + @aInterfacePtr On completion contains an interface of type specified by aInterfaceId + @aThis Extends the interface to provide further access to DMMCSession + */ + +EXPORT_C TInt MMCGetExtInterface(TMMCExtInterfaceId aInterfaceId, MMCMExtInterface*& aInterfacePtr, TAny* /*aThis*/) + { + OstTrace1(TRACE_FLOW, MMCGETEXTINTERFACE_ENTRY, ">MMCGetExtInterface InterfaceId=%d", aInterfaceId ); + TInt r = KErrNone; + switch(aInterfaceId) + { + case KInterfaceRpmb: + { + if (RpmbParmsPopulated) + { + aInterfacePtr = (MMCMExtInterface*)(&rpmbInfo); + } + else + { + // don't hand out interface if not ready to use + aInterfacePtr = NULL; + r = KErrNotReady; + } + break; + } + default: + aInterfacePtr = NULL; + break; + } + OstTrace0(TRACE_FLOW, MMCGETEXTINTERFACE_EXIT, " +#include +#include +#include +#include + +DRpmbDevice * DRpmbDevice::DRpmbDevicePtrs[KMaxPBusSockets*4] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL}; + +EXPORT_C DRpmbDevice::DRpmbDevice(): + iSessionEndCallBack(DRpmbDevice::SessionEndCallBack, this), + iDeviceIndex(KIndexNotAssigned) + { + } + +EXPORT_C DRpmbDevice::~DRpmbDevice() + { + Close(); + } + +void DRpmbDevice::SessionEndCallBack(TAny* aSelf) + { + DRpmbDevice& self = *static_cast(aSelf); + self.DoSessionEndCallBack(); + } + +void DRpmbDevice::DoSessionEndCallBack() + { + iSocket->EndInCritical(); + Kern::SemaphoreSignal(*iRequestSemaphore); + } + +void DRpmbDevice::BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2) +{ + DRpmbDevice* device = (DRpmbDevice*)aPtr; + TPBusState busState = (TPBusState) (TInt) a1; + TInt busError = (TInt) a2; + + if(aReason == TPBusCallBack::EPBusStateChange + && busState == EPBusOn && busError == KErrNone) + { + Kern::SemaphoreSignal(*(device->iPowerUpSemaphore)); + } +} + +TInt DRpmbDevice::PowerUpStack() + { + // + // Power up the socket - This ensures that the socket is powered up + // and the functions are re-enumerated. + // + iBusCallBack.iFunction = BusCallBack; + iBusCallBack.iPtr=this; + iBusCallBack.SetSocket(iSocket->iSocketNumber); + iBusCallBack.Add(); + NKern::ThreadEnterCS(); + TInt r = Kern::SemaphoreCreate(iPowerUpSemaphore,_L("RPMBPowerUpSem"), 0); + if(r == KErrNone) + { + TInt r = iSocket->PowerUp(); + if(r==KErrNone) + { + Kern::SemaphoreWait(*iPowerUpSemaphore); + } + } + NKern::ThreadLeaveCS(); + return r; + } + +void DRpmbDevice::SetSynchronisationParms(TUint8 aDeviceIndex) + { + // Mark this instance as being associated with the requested index + iDeviceIndex = aDeviceIndex; + // Mark the requested index as being associated with this instance + // Atomic operation ensures store is flushed from cache and committed + // to global memory + __e32_atomic_store_ord_ptr(&(DRpmbDevicePtrs[iDeviceIndex]),this); + } + + +void DRpmbDevice::ClearSynchronisationParms() + { + // Serialise access to global pointer array and it's local index + NKern::FMWait(&iSynchronisationParmsMutex); + if (iDeviceIndex < KMaxPBusSockets*4) + { + // Atomic operation for load from global memory and not from cache + DRpmbDevice * ptrTableEntry = + (DRpmbDevice *)__e32_atomic_load_acq_ptr(&(DRpmbDevicePtrs[iDeviceIndex])); + // This instance of DRpmbDevice is associated with an index + // The associated index MUST be associated with this instance + __ASSERT_ALWAYS((ptrTableEntry == this), Kern::Fault(__FILE__, __LINE__)); + // Disassociate index and instance + // Atomic operation ensures store is flushed from cache and committed + // to global memory + __e32_atomic_store_ord_ptr(&(DRpmbDevicePtrs[iDeviceIndex]),NULL); + iDeviceIndex = KIndexNotAssigned; + } + // Serialise access to global pointer array and it's local index + NKern::FMSignal(&iSynchronisationParmsMutex); + } + +EXPORT_C TInt DRpmbDevice::Open(TUint aDeviceIndex) + { + // + //eMMC4.4+ devices have RPMB partitions and each MMC device may be configured as having an RPMB + //partition in the baseport + //This function creates an MMC stack session for device aDeviceIndex + //This is used to access the RPMB partition on that device + //Extensions that use this interface during system startup should be located AFTER the RPMB and MMC + //extesnions in the system ROM and should not call this interface synchronously from a system + //startup initialisation routine + //aDeviceIndex the index of the device supporting the RPMB partition + //Returns KerrNone if successful + //Returns KErrNotReady if the baseport configuration hasn't been read yet + //Returns KErrNotSupported if the baseport configuration does not have a valid RPMB partition + //or RPMB is not supported by the media device + //Otherwise retruns a systemwide error code + // + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_1, "RPMB: >DrpmbDevice::Open"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::Open")); + + TRpmbDeviceParms params; + params.iCardNumber = 0; + params.iSocketPtr = NULL; + MRpmbInfo* rpmbInterface = NULL; + + TInt r = MMCGetExtInterface(KInterfaceRpmb, (MMCMExtInterface*&) rpmbInterface); + // MMCGetExtInterface currently returns KErrNotReady with rpmbInterface == NULL if the RPMB parameters + // haven't yet been populated + // proveided any calling extension is located AFTER the RPMB and MMC extesnions in the system ROM and + // does not call this interface synchronously from a system initialisation routine the following + // shouldn't be asserted + OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_2, "RPMB: DrpmbDevice Get Interface err = %d", r); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice Get Interface err = %d", r)); + __ASSERT_ALWAYS(r == KErrNone, Kern::Fault(__FILE__, __LINE__)); + + if (rpmbInterface == NULL) + { + // unexpected error since MMCGetExtInterface didn't return an error + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_3, "RPMB: DrpmbDevice Null rpmbInterface"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice Null rpmbInterface")); + return KErrGeneral; + } + + // Interface currently supports a single device, device index = 0 + r = rpmbInterface->RpmbInfo(aDeviceIndex, params); + if(r != KErrNone) + { + // requested index non zero or baseport not configured with RPMB capable MMC device + OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_4, "RPMB: DrpmbDevice requested index non zero or baseport not configured, err = %d", r); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice requested index non zero or baseport not configured, err = %d", r)); + return r; + } + + iSocket = params.iSocketPtr; + // iSocket cannot be NULL + // TMMCardControllerInterface::RegisterMediaDevices ensures that the assigned value is not NULL + __ASSERT_ALWAYS((iSocket!=NULL), Kern::Fault(__FILE__, __LINE__)); + + // Serialise access to global pointer array and it's local index + NKern::FMWait(&iSynchronisationParmsMutex); + + if (iDeviceIndex != KIndexNotAssigned) + { + // This instance of DRpmbDevice is already open + if (iDeviceIndex == aDeviceIndex) + { + // Serialise access to global pointer array and it's local index + NKern::FMSignal(&iSynchronisationParmsMutex); + // Already open with requested index + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_5, "RPMB: DrpmbDevice already open with requested index"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice already open with requested index")); + return KErrNone; + } + else + { + // Serialise access to global pointer array and it's local index + NKern::FMSignal(&iSynchronisationParmsMutex); + // Already open with other index + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_6, "RPMB: DrpmbDevice already open with other index"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice already open with other index")); + return KErrInUse; + } + } + else + { + // This instance of DRpmbDevice is not open + + // Atomic operation for load from global memory and not from cache + DRpmbDevice * ptrTableEntry = + (DRpmbDevice *)__e32_atomic_load_acq_ptr(&(DRpmbDevicePtrs[aDeviceIndex])); + + if (ptrTableEntry == NULL) + { + SetSynchronisationParms((TUint8)(aDeviceIndex)); + } + else + { + // Requested index cannot be associated with this instance of DRpmbdevice + __ASSERT_ALWAYS(ptrTableEntry != this, Kern::Fault(__FILE__, __LINE__)); + // Serialise access to global pointer array and it's local index + NKern::FMSignal(&iSynchronisationParmsMutex); + // Requested index already associated with a different instance of DRpmbDevice + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_7, "RPMB: DrpmbDevice requested index already associated with a different instance of DrpmbDevice"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice requested index already associated with a different instance of DrpmbDevice")); + return KErrInUse; + } + } + NKern::FMSignal(&iSynchronisationParmsMutex); + + r = PowerUpStack(); + if (r != KErrNone && r != KErrCompletion) + { + // Stack wasn't already powered up and failed to power up + ClearSynchronisationParms(); + OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_8, "RPMB: DrpmbDevice wasn't already powered up and failed with err = %d", r); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice wasn't already powered up and failed with err = %d", r)); + return r; + } + + DMMCStack* stack = iSocket->Stack(KBusNumber); + if(stack == NULL) + { + // KBusNumber = 0 so iSocket->Stack() returns iSocket->iStack + // Expect this to have been pre-assigned + // Expect a socket to be bound to a stack + ClearSynchronisationParms(); + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_9, "RPMB: stack is NULL"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: stack is NULL")); + return KErrNoMemory; + } + + iCard = stack->CardP(params.iCardNumber); + if(iCard == NULL) + { + // stack->CardP() returns stack->iCardArray->CardP(params.iCardNumber) + // Expect this to have been pre-assigned + // Expect card array to point to a card + ClearSynchronisationParms(); + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_10, "RPMB: card pointer is NULL"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: card pointer is NULL")); + return KErrNoMemory; + } + + NKern::ThreadEnterCS(); + iSession = stack->AllocSession(iSessionEndCallBack); + NKern::ThreadLeaveCS(); + if (iSession == NULL) + { + // DMMCStack::AllocSession() failed to create a new instance off DMMCSession + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_11, "RPMB: failed to create a new instance of DMMCSession"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: failed to create a new instance of DMMCSession")); + return KErrNoMemory; + } + + iSession->SetStack(stack); + iSession->SetCard(iCard); + + TInt bufLen, minorBufLen; + stack->BufferInfo(iIntBuf, bufLen, minorBufLen); + // mmc media driver reserved the first KRpmbOneFramePacketLength bytes of the + // PSL buffer to be used for RPMB requests / responses + iIntBuf += minorBufLen; + + if(iCard->ExtendedCSD().ExtendedCSDRev() < 5 || iCard->ExtendedCSD().RpmbSize() == 0) + { + // RPMB is not supported on selected hardware + ClearSynchronisationParms(); + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_12, "RPMB: feature is not supported on selected hardware"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: feature is not supported on selected hardware")); + return KErrNotSupported; + } + OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_13, "RPMB: DrpmbDevice::Close"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::Close")); + + ClearSynchronisationParms(); + + iBusCallBack.Remove(); + + NKern::ThreadEnterCS(); + + if(iPowerUpSemaphore) + { + iPowerUpSemaphore->Close(NULL); + iPowerUpSemaphore = NULL; + } + + if (iSession) + { + delete iSession; + iSession = NULL; + } + + if(iRequestSemaphore) + { + iRequestSemaphore->Close(NULL); + iRequestSemaphore = NULL; + } + + NKern::ThreadLeaveCS(); + OstTrace0(TRACE_FLOW, DRPMBDEVICE_CLOSE_2, "RPMB: DrpmbDevice::SendAccessRequest"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::SendAccessRequest")); + + if ((aRpmbRequest.Length() != KRpmbOneFramePacketLength) || (aRpmbResponse.Length() != KRpmbOneFramePacketLength)) + { + // insist on single frame access as mutiple read and multiple write (reliable write) notb yet supported + return KErrArgument; + } + + if (iSession == NULL) + { + // DRpmbDevice::Open not called at all + // or not called after DRpmbDevice::Close + OstTrace0(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_2, "RPMB: DMMCSession is NULL"); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DMMCSession is NULL")); + return KErrNotReady; + } + + if (iRequestSemaphore == NULL) + { + // iRequestSemaphore zero filled prior to contruction + // create semaphore for waiting on stack + NKern::ThreadEnterCS(); + TInt r = Kern::SemaphoreCreate(iRequestSemaphore,_L("RPMBRequestSemaphore"), 0); + NKern::ThreadLeaveCS(); + if (r != KErrNone) + { + // failed to create semaphore + OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_3, "RPMB: failed to create semaphore err = %d", r); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: failed to create semaphore err = %d", r)); + return r; + } + } + + memcpy(iIntBuf, aRpmbRequest.Ptr(), KRpmbOneFramePacketLength); + + TInt r = iSocket->InCritical(); + // may be KErrNotready if MMC stack is processing a posponed power down event or a postponed media change event + if (r == KErrNone) + { + iSession->SetPartition(TExtendedCSD::ESelectRPMB); //Set RPMB Partition + iSession->ResetCommandStack(); + iSession->FillCommandArgs(KDeviceAddress, KRpmbOneFramePacketLength, iIntBuf, KRpmbOneFramePacketLength); + iSession->iSessionID = ECIMRpmbAccess; + + r = iSession->Engage(); + if(r == KErrNone) + { + Kern::SemaphoreWait(*iRequestSemaphore); + memcpy((TUint8 *)aRpmbResponse.Ptr(), iIntBuf, KRpmbOneFramePacketLength); + OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_4, "RPMB: request complete with %d", iSession->EpocErrorCode()); + __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: request complete with %d", iSession->EpocErrorCode())); + return iSession->EpocErrorCode(); + } + } + + iSocket->EndInCritical(); + + OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_5, "RPMB: +#endif diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/eabi/epbusmu.def --- a/kernel/eka/eabi/epbusmu.def Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/eabi/epbusmu.def Mon Oct 11 19:11:06 2010 +0100 @@ -120,7 +120,7 @@ _ZTV7DMMCPsu @ 119 NONAME ; vtable for DMMCPsu _ZTV9DMMCStack @ 120 NONAME ; vtable for DMMCStack _ZN9DMMCStack22ModifyCardCapabilitySMEv @ 121 NONAME ; DMMCStack::ModifyCardCapabilitySM() - _ZN9DMMCStack6Dummy1Ev @ 122 NONAME + _Z18MMCGetExtInterface18TMMCExtInterfaceIdRP16MMCMExtInterfacePv @ 122 NONAME _ZN9DMMCStack12GetInterfaceENS_12TInterfaceIdERPNS_10MInterfaceE @ 123 NONAME _ZN9DMMCStack11MachineInfoER5TDes8 @ 124 NONAME _ZN9DMMCStack11SetBusWidthEm @ 125 NONAME diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/eabi/rpmbextu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/eabi/rpmbextu.def Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,12 @@ +EXPORTS + _ZN11DRpmbDevice17SendAccessRequestER5TDes8S1_ @ 1 NONAME + _ZN11DRpmbDevice4OpenEj @ 2 NONAME + _ZN11DRpmbDevice5CloseEv @ 3 NONAME + _ZN11DRpmbDeviceC1Ev @ 4 NONAME + _ZN11DRpmbDeviceC2Ev @ 5 NONAME + _ZN11DRpmbDeviceD0Ev @ 6 NONAME + _ZN11DRpmbDeviceD1Ev @ 7 NONAME + _ZN11DRpmbDeviceD2Ev @ 8 NONAME + _ZTI11DRpmbDevice @ 9 NONAME + _ZTV11DRpmbDevice @ 10 NONAME + diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/include/drivers/mmc.h --- a/kernel/eka/include/drivers/mmc.h Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/include/drivers/mmc.h Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1999-2010 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" @@ -12,7 +12,7 @@ // // Description: // Generic MMC controller types and standard classes for MMC manipulation -// This controller follows MMC spec V2.1 +// This controller follows MMC spec V4.4+ // // @@ -26,6 +26,7 @@ #include #include +#include // MMC Card maximum system settings @@ -56,7 +57,10 @@ class TMMCPasswordStore; class TMMCEraseInfo; class TMMCMachineInfoV4; +class TMMCMachineInfoV44; +typedef TPckg TMMCardMachineInfoPckg; typedef TPckg TMMCMachineInfoV4Pckg; +typedef TPckg TMMCMachineInfoV44Pckg; enum TMMCAppCommand {EMMCNormalCmd,EMMCApplicationCmd}; @@ -104,10 +108,36 @@ */ typedef TUint32 TMMCErr; -// MMC Enums and inline functions - - - +/** +A structure to define global parameters for the initialisation of an RPMB object. +This is required for devices with emmc4.4+ +@internalComponent +*/ +struct TRpmbDeviceParms + { + DMMCSocket* iSocketPtr; + TUint iCardNumber; + }; + +/* + Global counter for number or RPMB partitions. Only one partition per device + */ +GLREF_D TUint NumberOfRpmbs; +/* + Global holder for RPMB parameters + */ +GLREF_D TRpmbDeviceParms TheRpmbs[KMaxPBusSockets*4]; + +GLREF_D TBool RpmbParmsPopulated; + +/** +Max number of RPMB devices +*/ +const TUint MaxIndexRpmb = 0; + +/** +MMC Enums and inline functions +*/ /** @publishedPartner @@ -570,6 +600,43 @@ /** + * Client InterfaceIDs for GetExtInterface + * @publishedPartner + * + */ +enum TMMCExtInterfaceId + { + KInterfaceRpmb + }; + +class MMCMExtInterface + { +public: + virtual TInt Func() = 0; + }; + +/** +Interface class to return information for an RPMB capable device. +Used for emmc v4.4+ +*/ + +class MRpmbInfo + { +public: + virtual inline TInt RpmbInfo(TUint aDeviceIndex, TRpmbDeviceParms& aParams); + }; + +/** + A generic adapter function for returning an interface of specified type + The caller should set aInterfacePtr to NULL before calling + @aInterfaceId Denotes the required interface to be returned + @aInterfacePtr On completion contains an interface of type specified by aInterfaceId + @aThis Extends the interface to provide further access to DMMCSession + */ + +IMPORT_C TInt MMCGetExtInterface(TMMCExtInterfaceId aInterfaceId, MMCMExtInterface*& aInterfacePtr, TAny* aThis = NULL); + +/** @publishedPartner @released @@ -626,10 +693,11 @@ ECIMLockStack =14, ECIMInitStackAfterUnlock =15, ECIMAutoUnlock =16, - ECIMSleep =17 + ECIMSleep =17, + ECIMRpmbAccess =18 }; -const TUint KMMCMaxSessionTypeNumber = 18; +const TUint KMMCMaxSessionTypeNumber = 19; const TUint KMMCMinCustomSession = 1024; const TUint KMMCCmdDirDirBitPosition= KBit0; //fixed - dont change it @@ -639,7 +707,7 @@ const TUint KMMCCmdDirWBitDirect= KBit7; const TUint KMMCCmdReliableWrite = KBit31; - +const TUint KMMCCmdTrim = KBit0; //Trim command arg /** @publishedPartner @@ -1463,7 +1531,7 @@ /** Extended CSD register class. For more information about this register, see the MultimediaCard System - Specification, Version 4.1+ + Specification, Version 4.4 @publishedPartner @released @@ -1503,10 +1571,28 @@ EBusWidthModeIndex = 183, /** Offset of the BOOT_CONFIG field */ EBootConfigIndex = 179, + /** Offset of the BOOT_CONFIG_PROT field */ + EBootConfigProtectionIndex = 178, /** Offset of the BOOT_BUS_WIDTH field */ EBootBusWidthIndex = 177, /** Offset of the ERASE_GROUP_DEF field */ - EEraseGroupDefIndex = 175 + EEraseGroupDefIndex = 175, + /** Offset of the BOOT_WP field */ + EBootAreaWriteProtectionIndex = 173, + /** Offset of the USER_WP field */ + EUserAreaWriteProtectionIndex = 171, + /** Offset of the FW_CONFIG field */ + EFwConfigIndex = 169, + /** Offset of the RST_n_FUNCTION field */ + EHardwareResetFunctionIndex = 162, + /** Offset of the PARTITIONS_ATTRIBUTE field */ + EPartitionsAttributeIndex = 156, + /** Offset of the PARTITION_SETTING_COMPLETED field */ + EPartitionSettingIndex = 155, + /** Offset of the GP_SIZE_MULT field */ + + + }; /** @@ -1524,6 +1610,17 @@ /** Offset of the HC_ERASE_GRP_SIZE field */ EHighCapacityEraseGroupSizeIndex = 224 }; + + /** This enum defines the values for the Extended CSD Revision register */ + enum TExtendedCSDRev + { + EExtendedCSDRev1_0 = 0, + EExtendedCSDRev1_1 = 1, + EExtendedCSDRev1_2 = 2, + EExtendedCSDRev1_3 = 3, + EExtendedCSDRev1_4 = 4, + EExtendedCSDRev1_5 = 5 + }; /** This enum defines the bus width encoding used by the BUS_WIDTH field */ enum TExtCSDBusWidths @@ -1547,15 +1644,21 @@ /** This enum defines the boot config encoding used by the BOOT_CONFIG field */ - enum TExtCSDBootConfig + enum TExtCSDBootConfig // in v4.4 this is now called PARTITION_CONFIG { ESelectUserArea = 0x00, ESelectBootPartition1 = 0x01, ESelectBootPartition2 = 0x02, + ESelectRPMB = 0x03, // R/W Replay Protected Memory Block (RPMB) + ESelectGPAPartition1 = 0x04, // Access to General Purpose Area partition 1 + ESelectGPAPartition2 = 0x05, // Access to General Purpose Area partition 2 + ESelectGPAPartition3 = 0x06, // Access to General Purpose Area partition 3 + ESelectGPAPartition4 = 0x07, // Access to General Purpose Area partition 4 EEnableBootPartition1forBoot = 0x08, EEnableBootPartition2forBoot = 0x10, EEnableUserAreaforBoot = 0x38, - EEnableBootAck = 0x40 + EEnableBootAck = 0x40, + EPartitionTestMode = 0x100 // Indicates test mode for eMMC partitions }; /** @@ -1698,6 +1801,9 @@ /** returns the contents of the BOOT_SIZE_MUTLI field */ inline TUint BootSizeMultiple() const; + /** returns the size of the boot partitions in sectors */ + inline TUint32 BootSizeInSectors() const; + /** returns the contents of the ERASE_TIMEOUT_MULT field */ inline TUint EraseTimeoutMultiple() const; @@ -1719,13 +1825,77 @@ /** returns True if the CARD_TYPE field conatains a valid value **/ inline TBool IsSupportedCardType() const; + /** returns the contents of the ERASED_MEM_CONT field */ + inline TUint ErasedMemoryContent() const; + + /** returns the contents of the BOOT_CONFIG_PROT field */ + inline TUint BootConfigProt() const; + + /** returns the contents of the BOOT_WP field */ + inline TUint BootAreaWriteProtectionReg() const; + + /** returns the contents of the USER_WP field */ + inline TUint UserAreaWriteProtectionReg() const; + + /** returns the contents of the FW_CONFIG field */ + inline TUint FwConfiguration() const; + + /** returns the RPMB size based on contents of the RPMB_SIZE_MULT field */ + inline TUint32 RpmbSize() const; + + /** returns the RPMB size in sectors */ + inline TUint32 RpmbSizeInSectors() const; + + /** returns the contents of the RST_n_FUNCTION field */ + inline TUint HwResetFunction() const; + + /** returns the contents of the PARTITIONING_SUPPORT field */ + inline TUint PartitioningSupport() const; + + /** returns the Max Enhanced Area Size base on the contents of the + MAX_ENH_SIZE_MULT field */ + inline TUint32 MaxEnhancedAreaSize() const; + + /** returns the contents of the PARTITIONS_ATTRIBUTE field */ + inline TUint PartitionsAttribute() const; + + /** returns the contents of the PARTITION_SETTING_COMPLETED field */ + inline TUint PartitioningSetting() const; + + /** returns the General purpose partition sizes based on contents of the + GP_SIZE_MULT fields */ + inline TUint64 GeneralPurposePartition1Size() const; + inline TUint64 GeneralPurposePartition2Size() const; + inline TUint64 GeneralPurposePartition3Size() const; + inline TUint64 GeneralPurposePartition4Size() const; + + /** returns the General Purpose Partition sizes in sectors */ + inline TUint32 GeneralPurposePartition1SizeInSectors() const; + inline TUint32 GeneralPurposePartition2SizeInSectors() const; + inline TUint32 GeneralPurposePartition3SizeInSectors() const; + inline TUint32 GeneralPurposePartition4SizeInSectors() const; + + /** returns the Enhanced User Data Area Size based on thec contents of the + ENH_SIZE_MULT fields */ + inline TUint64 EnhancedUserDataAreaSize() const; + + /** returns the Enhanced User Data Start Address based on the contents of + the ENH_START_ADDR fields */ + inline TUint32 EnhancedUserDataStartAddress() const; + + /** returns the contents of the SEC_BAD_BLK_MGMNT field */ + inline TUint BadBlockManagementMode() const; + private: + inline TUint64 PartitionSize(TUint8 aMult0, TUint8 aMult1, TUint8 aMult2, TUint32 aMultiplier) const; + /** @internalComponent little endian 512 byte field representing extended CSD */ TUint8 iData[KMMCExtendedCSDLength]; }; +const TInt KMMCSelectPartitionMask = KBit0 | KBit1 | KBit2; // 32 bit MMC card status field (response R1) @@ -1754,6 +1924,7 @@ const TUint32 KMMCStatErrOutOfRange= KBit31; const TUint32 KMMCStatErrorMask= KMMCStatErrOutOfRange | + KMMCStatSwitchError | KMMCStatErrAddressError | KMMCStatErrBlockLenError| KMMCStatErrEraseSeqError| @@ -2113,6 +2284,8 @@ const TUint32 KMMCCmdFlagDoubleBuffer= KBit7; // The current DT command is double-buffered const TUint32 KMMCCmdFlagPhysAddr= KBit8; // Address is a physical address const TUint32 KMMCCmdFlagReliableWrite= KBit9; // Current command is Reliable Write +const TUint32 KMMCCmdFlagDeleteNotify= KBit10; // Current command is Delete Notify +const TUint32 KMMCCmdFlagRpmbIO= KBit11; // Current command is of RPMB type const TUint32 KMMCCmdFlagASSPFlags= KMMCCmdFlagBytesValid | KMMCCmdFlagTransStopped | @@ -2948,6 +3121,11 @@ inline void SetupCIMWriteBlock(TMMCArgument aBlockAddr, TUint8* aMemoryP, TUint32 aBlocks = 1); inline void SetupCIMEraseMSector(TMMCArgument aBlockAddr, TUint32 aBlocks = 1); inline void SetupCIMEraseMGroup(TMMCArgument aBlockAddr, TUint32 aBlocks = 1); + + // RPMB access macros setup + inline void SetupRpmbSendRequest(TBool aSetReliableWrite); + inline void SetupRpmbReceiveResponse(); + inline void SetupRpmbSendReadResultRegisterRequest(); // Raw commands (must be used in the locked bus state only) // Known commands with or without (with a default) argument @@ -3008,6 +3186,9 @@ inline void PushCommandStack(); inline void PopCommandStack(); + + inline void SetPartition(TInt aPartition); + inline TInt Partition() const; // Methods for double-buffered data transfer: inline TBool RequestMoreData(); @@ -3061,8 +3242,10 @@ TMMCCallBack iDataTransferCallback; // A callback function, used to request more data when performing double-buffering - TUint32 iSpare[21]; // Spare data (stolen from iCommand) - + TUint32 iSpare[20]; // Spare data (stolen from iCommand) + + TUint32 iPartition; // The targetted partition + TMMCard* iSavedCardP; // Saved copy of iCardP TMMCStateMachine iMachine; // State Machine context @@ -3496,6 +3679,8 @@ inline TMMCErr ProgramTimerSM(); static TMMCErr GoIdleSMST(TAny* aStackP); inline TMMCErr GoIdleSM(); + static TMMCErr SwitchPartitionSMST(TAny* aStackP); + inline TMMCErr SwitchPartitionSM(); static TMMCErr SwitchToLowVoltageSMST(TAny* aStackP); @@ -3524,6 +3709,21 @@ static TMMCErr ExecBusTestSMST(TAny* aStackP); inline TMMCErr ExecBusTestSM(); + static TMMCErr CIMRpmbAccessSMST(TAny* aStackP); + TMMCErr CIMRpmbAccessSM(); + + static TMMCErr CIMRpmbWriteAuthenticationKeySMST(TAny* aStackP); + TMMCErr CIMRpmbWriteAuthenticationKeySM(); + + static TMMCErr CIMRpmbReadWrCounterSMST(TAny* aStackP); + TMMCErr CIMRpmbReadWrCounterSM(); + + static TMMCErr CIMRpmbWriteSMST(TAny* aStackP); + TMMCErr CIMRpmbWriteSM(); + + static TMMCErr CIMRpmbReadSMST(TAny* aStackP); + TMMCErr CIMRpmbReadSM(); + enum TBusWidthAndClock { E1Bit20Mhz = 0x0000, @@ -3616,11 +3816,6 @@ friend class DMMCSession; friend class TMMCardArray; -private: - // - // Dummy functions to maintain binary compatibility - IMPORT_C virtual void Dummy1(); - protected: /** Gets an interface from a derived class @@ -3651,8 +3846,8 @@ - class TMMCMachineInfo + /** Platform-specific configuration information for the MultiMediaCard stack. @@ -3814,9 +4009,6 @@ - -typedef TPckg TMMCardMachineInfoPckg; - /** Platform-specific configuration information for the MultiMediaCard stack. Contains information pertinent to @@ -3874,6 +4066,43 @@ }; + +/** + Platform-specific configuration information for the + MultiMediaCard stack. Contains information pertinent to + MMC specification version 4.4 + + An object of this type is passed to the Variant implementation + of DMMCStack::MachineInfo(), which should fill the public data + members with appropriate information and values. + +@internalComponent +*/ +class TMMCMachineInfoV44 : public TMMCMachineInfoV4 + { +public: + inline TMMCMachineInfoV44() {memclr(this, sizeof(*this));} + + /** + The version of the structure returned by the PSL in a call to + DMMStack::MachineInfo() + The fields defined in TMMCMachineInfoV44 are only valid if the + version is EVersion44 or higher + */ + enum TVersion {EVersion3, EVersion4, EVersion44}; + + /** + Use iRpmbSlotCount and iRpmbSlotList to define a list of up to + four slots for devices containing an RPMB partitions to be + exposed + */ + TUint iRpmbSlotCount; + TUint * iRpmbSlotList; + + TUint8 iSpare[14]; + }; + + class DMMCPsu : public DPBusPsuBase /** DPBusPsuBase derived abstract class to control the MMC socket's power supply. @@ -4130,6 +4359,7 @@ EMMCInvalidCardNumber =19, EMMCNotInDfcContext =20, EMMCAddressCardNotSupported =21, + EMMCInvalidPartitionNumber =22 }; IMPORT_C static void Panic(TMMCPanic aPanic); friend class DMMCStack; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/include/drivers/mmc.inl --- a/kernel/eka/include/drivers/mmc.inl Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/include/drivers/mmc.inl Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1999-2010 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" @@ -17,6 +17,9 @@ // outside the Kernel and Hardware Services package. // +const TInt KOneKiloByte = 1024; +const TInt KSectorSize = 512; + /** A static function that takes the 4 bytes that are stored in a memory location @@ -180,6 +183,132 @@ inline TUint TExtendedCSD::SleepCurrentVccQ() const {return iData[219];} inline TUint TExtendedCSD::SleepAwakeTimeout() const {return iData[217];} +inline TUint TExtendedCSD::ErasedMemoryContent() const {return iData[181];} +inline TUint TExtendedCSD::BootConfigProt() const {return iData[EBootConfigProtectionIndex];} +inline TUint TExtendedCSD::BootAreaWriteProtectionReg() const {return iData[EBootAreaWriteProtectionIndex];} +inline TUint TExtendedCSD::UserAreaWriteProtectionReg() const {return iData[EUserAreaWriteProtectionIndex];} +inline TUint TExtendedCSD::FwConfiguration() const {return iData[EFwConfigIndex];} + + +inline TUint32 TExtendedCSD::BootSizeInSectors() const + { + + return BootSizeMultiple() * 128 * KOneKiloByte / KSectorSize; + } + +inline TUint32 TExtendedCSD::RpmbSize() const + { + return static_cast(iData[168]); + } + +inline TUint32 TExtendedCSD::RpmbSizeInSectors() const + { + + return RpmbSize() * 128 * KOneKiloByte / KSectorSize; + } + +inline TUint TExtendedCSD::HwResetFunction() const {return iData[EHardwareResetFunctionIndex];} +inline TUint TExtendedCSD::PartitioningSupport() const {return iData[160];} + +inline TUint32 TExtendedCSD::MaxEnhancedAreaSize() const + { + return(iData[157] | + (static_cast(iData[158]) << 8) | + (static_cast(iData[159]) << 16) * + HighCapacityWriteProtectGroupSize()); + } + +inline TUint TExtendedCSD::PartitionsAttribute() const {return iData[EPartitionsAttributeIndex];} +inline TUint TExtendedCSD::PartitioningSetting() const {return iData[EPartitionSettingIndex];} + +inline TUint64 TExtendedCSD::PartitionSize(TUint8 aMult0, TUint8 aMult1, TUint8 aMult2, TUint32 aMultiplier) const + { + TUint64 size = static_cast(aMult2) * 8 * 8; + size += static_cast(aMult1) * 8; + size += static_cast(aMult0); + + size *= aMultiplier; + return size; + } + +inline TUint64 TExtendedCSD::GeneralPurposePartition1Size() const + { + return PartitionSize(iData[143], + iData[144], + iData[145], + (HighCapacityWriteProtectGroupSize() * HighCapacityEraseGroupSize() * 512 * 1024) + ); + } + +inline TUint32 TExtendedCSD::GeneralPurposePartition1SizeInSectors() const + { + return I64LOW(GeneralPurposePartition1Size() / KSectorSize); + } + +inline TUint64 TExtendedCSD::GeneralPurposePartition2Size() const + { + return PartitionSize(iData[146], + iData[147], + iData[148], + (HighCapacityWriteProtectGroupSize() * HighCapacityEraseGroupSize() * 512 * 1024) + ); + } + +inline TUint32 TExtendedCSD::GeneralPurposePartition2SizeInSectors() const + { + return I64LOW(GeneralPurposePartition2Size() / KSectorSize); + } + + +inline TUint64 TExtendedCSD::GeneralPurposePartition3Size() const + { + return PartitionSize(iData[149], + iData[150], + iData[151], + (HighCapacityWriteProtectGroupSize() * HighCapacityEraseGroupSize() * 512 * 1024) + ); + } + +inline TUint32 TExtendedCSD::GeneralPurposePartition3SizeInSectors() const + { + return I64LOW(GeneralPurposePartition3Size() / KSectorSize); + } + +inline TUint64 TExtendedCSD::GeneralPurposePartition4Size() const + { + return PartitionSize(iData[152], + iData[153], + iData[154], + (HighCapacityWriteProtectGroupSize() * HighCapacityEraseGroupSize() * 512 * 1024) + ); + + } + +inline TUint32 TExtendedCSD::GeneralPurposePartition4SizeInSectors() const + { + return I64LOW(GeneralPurposePartition4Size() / KSectorSize); + } + +inline TUint64 TExtendedCSD::EnhancedUserDataAreaSize() const + { + return PartitionSize(iData[140], + iData[141], + iData[142], + HighCapacityWriteProtectGroupSize() + ); + } + +inline TUint32 TExtendedCSD::EnhancedUserDataStartAddress() const + { + // note, for HC devices this is in sectors, otherwise in bytes + return(iData[136] | + (static_cast(iData[137]) << 8) | + (static_cast(iData[138]) << 16) | + (static_cast(iData[139]) << 24)); + } + +inline TUint TExtendedCSD::BadBlockManagementMode() const {return iData[134];} + // "Modes Segment" of Extended CSD - i.e. modifiable fields inline TUint TExtendedCSD::CmdSet() const {return iData[ECmdSetIndex];} inline TUint TExtendedCSD::CmdSetRev() const {return iData[ECmdSetRevIndex];} @@ -944,6 +1073,33 @@ DMMCSocket::Panic(DMMCSocket::EMMCCommandStack)); } + +/** +Sets the target partition access bits +*/ +inline void DMMCSession::SetPartition(TInt aPartition) + { + TInt partition = aPartition & ~TExtendedCSD::EPartitionTestMode; + __ASSERT_DEBUG( + partition >= TExtendedCSD::ESelectUserArea && + partition <= TExtendedCSD::ESelectGPAPartition4, + DMMCSocket::Panic(DMMCSocket::EMMCInvalidPartitionNumber)); + + iPartition = partition; + iPartition |= aPartition & TExtendedCSD::EPartitionTestMode; + } + + +/** + * Returns the target partition + * @return The partition access identifier for which this session is destined +*/ +inline TInt DMMCSession::Partition() const + { + return iPartition; + } + + inline TMMCCommandDesc& DMMCSession::Command() /** * Returns the current command, as referred to by the stack pointer. @@ -1041,6 +1197,66 @@ iSessionID = ECIMEraseGroup; } +inline void DMMCSession::SetupRpmbSendReadResultRegisterRequest() + { +/** + * Sets the session to send an RPMB read result register request to the RPMB partition. + * + * Having set-up the session for this operation, the client must invoke, SMF_INVOKES. the + * read write state machine. CIMReadWriteBlocksSM, and the operation will commence. The read + * write state machine initiates the result register read sequence by issuing the Write Multiple + * command, CMD25. Prior to this the state machine has issued CMD23 with the block count set + * to 1. + * + * + * All other RPMB request packets initiate an RPMB access and are constructed in the security code + * and sent to the stack via the security driver and the RPMB kernel extension DLL. The result + * register read request is used part ways through the program key and data write accesses to find + * out about the success of the particular operation. It is not sent via the RPMB kernel extension + * DLL so it is constructed here. Luckily it is easy to make. + */ + TUint8* readRequestPtr = Command().iDataMemoryP; + memset(readRequestPtr, 0, KRpmbOneFramePacketLength); + * (readRequestPtr + KRpmbRequestLsbOffset) = KRpmbRequestReadResultRegister; + SetupRpmbSendRequest(EFalse); + } + +inline void DMMCSession::SetupRpmbSendRequest(TBool aSetReliableWrite) +/** + * Sets the session to send an RPMB request to the RPMB partition. + * + * Having set-up the session for this operation, the client must invoke, SMF_INVOKES, the + * read write state machine, CIMReadWriteBlocksSM, and the operation will commence. The read + * write state machine initiates the result read sequence by issuing the Write Multiple + * command, CMD25. Prior to this the state machine has issued CMD23 with the block count set + * to 1 and optionally, if aSetReliableWrite is TRUE, with the arguement bit (31) set to 1. + */ + { + iSessionID=ECIMWriteMBlock; + Command().iCommand = ECmdWriteMultipleBlock; + Command().iFlags |= KMMCCmdFlagRpmbIO; + if (aSetReliableWrite) + { + Command().iFlags |= KMMCCmdFlagReliableWrite; + } + } + +inline void DMMCSession::SetupRpmbReceiveResponse() +/** + * Sets the session to receive an RPMB resposne from the RPMB partition. + * + * Having set-up the session for this operation, the client must invoke ,SMF_INVOKES. the + * read write state machine, CIMReadWriteBlocksSM, and the operation will commence. The read + * write state machine initiates the result read sequence by issuing the Read Multiple + * command, CMD18. Prior to this the state machine has issued CMD23 with the block count set + * to 1. + */ + { + iSessionID=ECIMReadMBlock; + Command().iCommand = ECmdReadMultipleBlock; + Command().iFlags |= KMMCCmdFlagRpmbIO; + } + inline void DMMCSession::EnableDoubleBuffering(TUint32 aNumBlocks) /** * When called before a data transfer operation is engaged, specifies that the data @@ -1555,3 +1771,34 @@ * @return ETrue if Erase Group commands are supported. */ {return(iEraseFlags&KMMCEraseGroupCmdsSupported);} + +/** +Return RPMB information. +@param aDeviceIndex The RPMB specific device index. Must be zero in current implementation +@param aParams Retrieves the RPMB specific information required for initialisation +*/ + +inline TInt MRpmbInfo::RpmbInfo(TUint aDeviceIndex, TRpmbDeviceParms& aParams) + { + // note that MMCGetExtInterface doesn't hand out an instance of MRpmbInfo until + // RpmbParmsPopulated is true so baseport configuration has been read and any + // changes to NumberOfRpmbs and TheRpmbs are flushed + if (aDeviceIndex>MaxIndexRpmb) + { + // currently support just one RPMB capable device at index 0 + return KErrGeneral; + } + else + { + if (NumberOfRpmbs==0) + { + // baseport configuration doesn't include an RPMB partition + return KErrNotSupported; + } + else + { + aParams = TheRpmbs[0]; + return KErrNone; + } + } + } diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/include/drivers/rpmbdevice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/drivers/rpmbdevice.h Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,66 @@ +// Copyright (c) 1994-2010 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: +// eka\include\drivers\rpmb\rpmbdevice.h + +/** + @file + @internalTechnology +*/ + + +#include +#include + +const TUint KBusNumber = 0; +const TUint KDeviceAddress = 0; //Address on card is not applicable to RPMB. This is handled on media device. +const TUint8 KIndexNotAssigned = 0xFF; + +class DRpmbDevice : public DBase + { + public: + + IMPORT_C DRpmbDevice(); + IMPORT_C ~DRpmbDevice(); + IMPORT_C TInt Open(TUint aDeviceIndex); + IMPORT_C TInt SendAccessRequest(TDes8 &aRpmbRequest, TDes8 &aRpmbResponse); + IMPORT_C void Close(); + + private: + + static void SessionEndCallBack(TAny* aSelf); + static void BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2); + void DoSessionEndCallBack(); + TInt PowerUpStack(); + void SetSynchronisationParms(TUint8 aDeviceIndex); + void ClearSynchronisationParms(); + + DSemaphore* iPowerUpSemaphore; + DSemaphore* iRequestSemaphore; + NFastMutex iSynchronisationParmsMutex; + + DMMCSession* iSession; + TMMCard* iCard; + DMMCSocket* iSocket; + + TPBusCallBack iBusCallBack; + TMMCCallBack iSessionEndCallBack; + + TUint8* iIntBuf; + + TUint8 iDeviceIndex; + static DRpmbDevice* DRpmbDevicePtrs[KMaxPBusSockets*4]; + + TUint8 iSpare[10]; //for future use + + }; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/include/drivers/rpmbpacket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/drivers/rpmbpacket.h Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,73 @@ +// Copyright (c) 2010 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: +// eka\include\drivers\rpmb\rpmbpacket.h + +/** + @file + @internalTechnology + @prototype +*/ + +#ifndef RPMBPACKET_H +#define RPMBPACKET_H + +// RPMB packet constants + +const TInt KRpmbOneFramePacketLength = 512; + +// request field offsets +const TUint KRpmbRequestLsbOffset = 511; +const TUint KRpmbRequestMsbOffset = 510; +// request field values +const TUint KRpmbRequestWriteKey = 0x0001; +const TUint KRpmbRequestReadWriteCounter = 0x0002; +const TUint KRpmbRequestWriteData = 0x0003; +const TUint KRpmbRequestReadData = 0x0004; +const TUint KRpmbRequestReadResultRegister = 0x0005; + +// response field offsets +const TUint KRpmbResponseLsbOffset = 511; +const TUint KRpmbResponseMsbOffset = 510; +// response field values +const TUint KRpmbResponseWriteKey = 0x0100; +const TUint KRpmbResponseReadWriteCounter = 0x0200; +const TUint KRpmbResponseWriteData = 0x0300; +const TUint KRpmbResponseReadData = 0x0400; + +// result field offsets +const TUint KRpmbResultLsbOffset = 509; +const TUint KRpmbResultMsbOffset = 508; +// result field counter expired mask +const TUint KRpmbResultCounterExpiredMask = 0x007F; +// result field values +const TUint KRpmbResultOk = 0x0000; +const TUint KRpmbResultGeneralFailure = 0x0001; +const TUint KRpmbResultAuthenticationFailure = 0x0002; +const TUint KRpmbResultKeyNotProgrammed = 0x0007; + +// counter field offsets +const TUint KRpmbCounterByteOneOffset = 503; +const TUint KRpmbCounterByteTwoOffset = 502; +const TUint KRpmbCounterByteThreeOffset = 501; +const TUint KRpmbCounterByteFourOffset = 500; + +// key field +const TUint KRpmbKeyLength = 32; +const TUint KRpmbKeyOffset = 196; + +// data field +const TUint KRpmbDataLength = 256; +const TUint KRpmbDataOffset = 228; + +#endif /* #ifndef RPMBPACKET_H */ \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/include/e32ver.h --- a/kernel/eka/include/e32ver.h Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/include/e32ver.h Mon Oct 11 19:11:06 2010 +0100 @@ -28,7 +28,7 @@ const TInt KE32MajorVersionNumber=2; const TInt KE32MinorVersionNumber=0; -const TInt KE32BuildVersionNumber=4008; +const TInt KE32BuildVersionNumber=4009; const TInt KMachineConfigurationMajorVersionNumber=1; const TInt KMachineConfigurationMinorVersionNumber=0; diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/release.txt --- a/kernel/eka/release.txt Mon Oct 11 17:54:41 2010 +0100 +++ b/kernel/eka/release.txt Mon Oct 11 19:11:06 2010 +0100 @@ -1,3 +1,20 @@ +Version 2.00.4009 +================= +(Made by fadhliM 07/10/2010) + +1. hengrant + 1. RP 531855 eMMC 4.4 User Data Partitions + REQ 417-54821 MMC v4.4 support for eMMC (Bridge M4) + SUB 417-73300 eMMC V4.4 + SUB 417-73303 eMMC v4.4 - User-Data partitions with Enhanced Attributes Support + 2. RP 529139 eMMC 4.4 RPMB + REQ 417-75165 MMC v4.4 support for eMMC (Bridge M5) + SUB 417-59932 eMMC v4.4 - Replay Protected Memory Block (RPMB) support + 3. RP 543420 + REQ 417-75165 MMC v4.4 support for eMMC (Bridge M5) + SUB 417-73302 eMMC v4.4 - TRIM Support + + Version 2.00.4008 ================= (Made by fadhliM 05/10/2010) @@ -38,7 +55,9 @@ (Made by vfebvre 27/09/2010) 1. erifung - 1. RP540323 REQ:405-4716 kernel side device driver staged shutdown feature + 1. RP 540346 + REQ 405-4716 Staged shutdown server monitor + SUB 417-75212 Staged shutdown server monitor - kernel-side component Version 2.00.4005 @@ -49,7 +68,10 @@ 1. ou1cimx1#584587 PRM RBusDevResManUs::ChangeResourceState() to set a resource level to "0", causes FAULT: RESMANUS 0x000001e3 (483) 2. seolney - 1. ou1cimx1#553109 REQ 405-4716, Feature 405-5174: Staged shutdown server monitor + 1. RP 506754 + REQ 405-4716 Staged shutdown server monitor + SUB 417-75146 Shutdown Monitor: Domain Manager + ou1cimx1#553109 REQ 405-4716, Feature 405-5174: Staged shutdown server monitor 3. necliffo 1. ou1cimx1#584508 Improve Code Coverage for LocalMedia Subsystem and MMC Stack diff -r 48e57fb1237e -r ddfd5aa0d58f kernel/eka/rombuild/rpmbtest.oby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/rombuild/rpmbtest.oby Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,30 @@ +/* +* Copyright (c) 2010 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: +* +*/ +#define BASE_ROM +#include + +files= + +#include +#include "user.iby" +#include +#include + +// And now the t_rpmb test +#include + +data=\epoc32\rom\e32test\rpmb\autoexec.bat \autoexec.bat \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/group/t_mmcdrv.mmp --- a/kerneltest/e32test/group/t_mmcdrv.mmp Mon Oct 11 17:54:41 2010 +0100 +++ b/kerneltest/e32test/group/t_mmcdrv.mmp Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1995-2010 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" @@ -17,6 +17,7 @@ TARGET t_mmcdrv.exe TARGETTYPE EXE +USERINCLUDE ../../../kernel/eka/drivers/medmmc SOURCEPATH ../pccd SOURCE t_mmcdrv.cpp LIBRARY euser.lib diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/pccd/t_mmcdrv.cpp --- a/kerneltest/e32test/pccd/t_mmcdrv.cpp Mon Oct 11 17:54:41 2010 +0100 +++ b/kerneltest/e32test/pccd/t_mmcdrv.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1996-2010 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" @@ -13,10 +13,12 @@ // Description: // e32test\pccd\t_mmcdrv.cpp // Test the MultiMediaCard (MMC) media driver -// Spare Test case Numbers 0513-0519 +// Spare Test case Numbers 0515-0519 // // +#define __E32TEST_EXTENSION__ + #include "../mmu/d_sharedchunk.h" #include #include @@ -1860,8 +1862,122 @@ test(SecThreadChangeFlag==EFalse); // Closed 2nd thread so shouldn't have been updated } +// Helper function for eMMC partition switching test - writes test data +TInt EMmcPartitionWriteTestData(const TInt aDriveNumber, const TChar aDataPattern) + { + TBusLocalDrive drv; + TBool chg(EFalse); + + TInt r = drv.Connect(aDriveNumber, chg); + test(r == KErrNone); + + TBuf8 buffer; + + // write pattern to sector 0 + buffer.Fill(aDataPattern, KDiskSectorSize); + r = drv.Write((TInt64) 0, buffer); + + return r; + } + +// Helper function for eMMC partition switching test - reads test data +TInt EMmcPartitionReadTestData(const TInt aDriveNumber, TDes8& aData) + { + // read pattern from sector 0 + TBusLocalDrive drv; + TBool chg(EFalse); + + TInt r = drv.Connect(aDriveNumber, chg); + test(r == KErrNone); + + aData.Fill(0x00, aData.MaxSize()); + r = drv.Read((TInt64) 0, aData.MaxSize(), aData); + + drv.Disconnect(); + return r; + } + +// Helper function for eMMC partition switching test - compares data to expected pattern +TInt EMmcPartitionReadAndCompareTestData(const TInt aDriveNumber, const TChar aExpectedPattern) + { + TBuf8 actual; + TBuf8 expected; + TInt r = EMmcPartitionReadTestData(aDriveNumber, actual); + test(r == KErrNone); + + expected.Fill(aExpectedPattern, KDiskSectorSize); + + if(expected.Compare(actual) != 0) + { + test.Printf(_L("ERROR: Comparison failed. Expected:\n")); + DumpBuffer(expected); + test.Printf(_L("\nActual:\n")); + DumpBuffer(actual); + r = KErrGeneral; + } + + return r; + } + + + +/** +@SYMTestCaseID 0514 (taken from spare test case IDs) +@SYMTestCaseDesc Test low-level partition switching capability +@SYMTestPriority normal + +@SYMTestActions + a) Precondition: Valid partitions have been flashed to BOOT 1 and BOOT 2, + these have to be mapped correctly in variantmediadef.h + b) Write Data Pattern 1 to BOOT 1 + c) Write Data Pattern 2 to BOOT 2 + d) Read data from BOOT 1 and compare to DP1 - test passes if data matches + e) Write Data Pattern 3 to BOOT 1, at the same offset as in b) + f) Read data from BOOT 2 and compare to DP2 - test passes if data matches + +@SYMTestExpectedResults All tests must pass +*/ +void TestPartitionSwitching() + { + const TInt KDriveBoot1 = 4; // see variantmediadef.h + const TInt KDriveBoot2 = 5; + const TChar KDataPattern1 = 0xD1; + const TChar KDataPattern2 = 0xD2; + const TChar KDataPattern3 = 0xD3; + + test.Start(_L("eMMC partition switching")); + + // Write data data pattern 1 to boot1 + test.Printf(_L("Writing Data Pattern 1 to BOOT 1\n")); + TInt r = EMmcPartitionWriteTestData(KDriveBoot1, KDataPattern1); + test(r == KErrNone); + + // Write data data pattern 2 to boot2 + test.Printf(_L("Writing Data Pattern 2 to BOOT 2\n")); + r = EMmcPartitionWriteTestData(KDriveBoot2, KDataPattern2); + test(r == KErrNone); + + // Read back data from boot 1 and compare it to previously written pattern + test.Printf(_L("Reading from BOOT 1\n")); + r = EMmcPartitionReadAndCompareTestData(KDriveBoot1, KDataPattern1); + test(r == KErrNone); + + // Write data data pattern 3 to boot1 + test.Printf(_L("Writing Data Pattern 3 to BOOT 1\n")); + r = EMmcPartitionWriteTestData(KDriveBoot1, KDataPattern3); + test(r == KErrNone); + + // Read back data from boot 2 and compare it to previously written pattern + test.Printf(_L("Reading from BOOT 2\n")); + r = EMmcPartitionReadAndCompareTestData(KDriveBoot2, KDataPattern2); + test(r == KErrNone); + + test.End(); + } //// End of Test + + void Format() // // Format current drive @@ -2203,39 +2319,53 @@ goto doorTest; #endif + if(ManualMode) + { + // Only test in manual mode, as the rom needs special prep anyway (drive registration + // in variantmediadef.h and flashing of BB5 partition info structures using mmcloader) + // It is possible that as a result of the changes to variantmediadef.h the + // drive-number-to-letter mapping in the appropriate estart.txt may have to be adjusted + // as well + TestPartitionSwitching(); + } + for(TInt pass = 0; pass < TMMCDrive::EMaxTestModes; pass++) { TInt r = KErrNone; + switch (pass) { - case 0 : r = TheMmcDrive.SetTestMode(TMMCDrive::ETestPartition); break; - case 1 : + case TMMCDrive::ETestPartition : + r = TheMmcDrive.SetTestMode(TMMCDrive::ETestPartition); + break; + + case TMMCDrive::ETestWholeMedia : // don't trash partition table in automated mode because... // cards in test rigs have often got deliberately small partition sizes to testing (!) if (!ManualMode) continue; r = TheMmcDrive.SetTestMode(TMMCDrive::ETestWholeMedia); break; - case 2 : { - r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemory); - AllocateSharedBuffers(EFalse,EFalse); - break; - } - case 3 : { - r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryCache); - AllocateSharedBuffers(EFalse, ETrue); - break; - } - case 4 : { - r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryFrag); - AllocateSharedBuffers(ETrue, EFalse); - break; - } - default: { - r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryFragCache); - AllocateSharedBuffers(ETrue, ETrue); - break; - } + + case TMMCDrive::ETestSharedMemory : + r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemory); + AllocateSharedBuffers(EFalse,EFalse); + break; + + case TMMCDrive::ETestSharedMemoryCache : + r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryCache); + AllocateSharedBuffers(EFalse, ETrue); + break; + + case TMMCDrive::ETestSharedMemoryFrag : + r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryFrag); + AllocateSharedBuffers(ETrue, EFalse); + break; + + default: + r = TheMmcDrive.SetTestMode(TMMCDrive::ETestSharedMemoryFragCache); + AllocateSharedBuffers(ETrue, ETrue); + break; } diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/bld.inf Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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/rpmb/bld.inf +// Kernel and User library test code +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_EXPORTS + +PRJ_TESTEXPORTS + +rpmbtestautoexec.bat \epoc32\rom\e32test\rpmb\autoexec.bat + +PRJ_TESTMMPFILES + +t_rpmb \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/driver/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/driver/bld.inf Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,34 @@ +// Copyright (c) 2010 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/rpmb/driver/bld.inf +// Kernel and User library test code +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_EXPORTS + +PRJ_TESTEXPORTS + +PRJ_TESTMMPFILES + +d_rpmb support \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/driver/d_rpmb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/driver/d_rpmb.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,1225 @@ +// Copyright (c) 2010 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/rpmb/d_rpmb.cpp +// LDD for testing RPMB kernel extension +// +// + +/** + @file + @internalComponent + @prototype +*/ + +#include "d_rpmb.h" +#include "../t_rpmb.h" + +_LIT(KRpmbTestThreadName,"RpmbTestThread"); +const TInt KRpmbTestPriority = 24; + +TDfcQue RpmbTestDfcQ; +TDfc* DfcPtr; + +// please read this before uncommenting out #define RPMBTESTS_TRY_TO_WRITE_KEY: +// Don't want to write key 'pre production' on real device as this will lock +// the system out of the RPMB partition (the key should be preprogrammed as +// part of the production process so that the system has access to the key - +// if the key has already been written it can't be written again). +// #define RPMBTESTS_TRY_TO_WRITE_KEY + + +/**************************************** + Implementation of DRpmbTestFactory class +*****************************************/ + +DRpmbTestFactory::DRpmbTestFactory() + { + } + +DRpmbTestFactory::~DRpmbTestFactory() + { + } + +TInt DRpmbTestFactory::Create(DLogicalChannelBase*& aChannel) + { + aChannel = new DRpmbTest; + return KErrNone; + } + +TInt DRpmbTestFactory::Install() + { + return SetName(&KRpmbTestLddName); + } + +void DRpmbTestFactory::GetCaps(TDes8& /*aDes*/) const +// implementation required since DLogicalDevice::GetCaps is pure virtual + { + // do nothing + } + + +static void RpmbTestDfcFunction(TAny* /*aPtr*/) + { + DRpmbDevice * rpmb; + rpmb = new DRpmbDevice; + TInt r = rpmb->Open(0); + Kern::Printf("%S Early on DRpmbDevice::Open test returned %d",&KDRpmbTestBanner, r); + // ASSERT to indicate test failure if DRpmbDevice::Open() returned error + __ASSERT_ALWAYS((r==KErrNone), Kern::Fault(__FILE__, __LINE__)); + rpmb->Close(); + delete rpmb; + // run more extensive tests early on + // note the unconventional use of a class derived from DLogicalChannelBase which is justified + // in the current context to provide more startup test coverage + DRpmbTest * test; + test = new DRpmbTest; + // while a call to DRpmbTest::DRpmbDeviceTests() works in this context + // a call to DRpmbTest::RpmbStackTests() would fail as DRpmbTest::DoCreate() wouldn't be + // called so that DRpmbTest::iStackSemPtr wouldn't get set up properly so that when it + // was uaed an exception would be generated + r = test->DRpmbDeviceTests(); + Kern::Printf("%S Early on DRpmbTest::DRpmbDeviceTests() returned %d",&KDRpmbTestBanner, r); + // ASSERT to indicate test failure + __ASSERT_ALWAYS((r==KErrNone), Kern::Fault(__FILE__, __LINE__)); + // not safe to delete test as not setup conventionally DRpmbTest::DoCreate() wasn't called + // at setup and DLogicalChannelBase::~DLogicalChannelBase__sub_object() would generate an + // exception + } + + +/******************************** + Entry point for RPMB test driver +*********************************/ + +DECLARE_STANDARD_EXTENSION() + { + TInt r = Kern::DfcQInit(&RpmbTestDfcQ,KRpmbTestPriority,&KRpmbTestThreadName);; + if (r != KErrNone) + return r; + DfcPtr = new TDfc(RpmbTestDfcFunction,NULL, &RpmbTestDfcQ, KMaxDfcPriority-7); + DfcPtr->Enque(); + return KErrNone; + } + +DECLARE_EXTENSION_LDD() + { + return new DRpmbTestFactory; + } + +/********************************* + Implementation of DRpmbTest class +**********************************/ + +DRpmbTest::DRpmbTest(): +// initialise parameters + iStackSemPtr(NULL), + iPowerSemPtr(NULL), + iSessionEndCallBack(DRpmbTest::StackCallBack, this) + { + } + +DRpmbTest::~DRpmbTest() + { + + iBusCallBack.Remove(); + + if (iPowerSemPtr) + { + iPowerSemPtr->Close(NULL); + } + if (iStackSemPtr) + { + iStackSemPtr->Close(NULL); + } + if (iSession) + { + delete iSession; + } + } + +TInt DRpmbTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) + { + TInt r = KErrNone; + r = Kern::SemaphoreCreate(iStackSemPtr, _L("DRpmbStackSem"), 0); + return r; + } + +TInt DRpmbTest::Request(TInt aFunction, TAny* /*a1*/, TAny* /*a2*/) + { + TInt r = KErrNotSupported; + switch (aFunction) + { + case RTestRpmb::ERunTests: + { + // respond to user side request + // execute tests for RPMB kernel extension + // run standatd tests that use the DRpmbDevice interface + Kern::Printf(" "); + Kern::Printf("%S << START DRpmbDevice TESTS >>", &KDRpmbTestBanner); + r = DRpmbDeviceTests(); + if (r != KErrNone) + { + Kern::Printf("%S DPrmbDevice test FAILED", &KDRpmbTestBanner); + break; + } + Kern::Printf("%S >> ALL DRpmbDevice TESTS PASSED", &KDRpmbTestBanner); + // run tests that use the MMC stack bypassing the RPMB kernel extension + Kern::Printf(" "); + Kern::Printf("%S << START STACK TESTS >>", &KDRpmbTestBanner); + r = RpmbStackTests(); + if (r != KErrNone) + { + Kern::Printf("%S stack test FAILED", &KDRpmbTestBanner); + break; + } + Kern::Printf("%S >> ALL STACK TESTS PASSED", &KDRpmbTestBanner); + break; + } + default: + break; + } + return r; + } + + +// test RPMB using the DRpmbDevice interface +TInt DRpmbTest::DRpmbDeviceTests() +// open interface and make data write, ket write, counter read and data write accesses + { + TInt size = (TInt)(2*KRpmbOneFramePacketLength); + + NKern::ThreadEnterCS(); + iRequest = (TUint8 *)Kern::Alloc(size); + NKern::ThreadLeaveCS(); + + iResponse = iRequest + KRpmbOneFramePacketLength; + + TInt r = SendAccessRequestNotOpen(); + + if (r==KErrNone) + { + r = OpenWithBadIndex(); + } + + if (r==KErrNone) + { + r = MultipleOpen(); + } + + if (r==KErrNone) + { + r = iRpmb.Open(0); + } + + if (r!=KErrNone) + { + Kern::Printf("%S DRpmbTest::DRpmbDeviceTest DRpmbDevice open error = %d", + &KDRpmbTestBanner, r); + } + else + { + r = SendAccessRequestBadParms(); + } + + if (r==KErrNone) + { + r = InvalidRequestId(); + } + + if (r==KErrNone) + { + r = IsKeyProgrammed(); + } + +// Don't want to write key 'pre production' on real device as this will lock +// the system out of the RPMB partition (the key should be preprogrammed as +// part of the production process so that the system has access to the key - +// if the key has already been written it can't be written again) +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if (r==KErrNone) + { + r = WriteKey(); + } +#endif + + if (r==KErrNone) + { + r = ReadWriteCounter(); + } + + if (r==KErrNone) + { + r = ReadData(); + } + + iRpmb.Close(); + + NKern::ThreadEnterCS(); + + Kern::Free(iRequest); + + NKern::ThreadLeaveCS(); + + return r; +} + +TInt DRpmbTest::SendAccessRequestNotOpen() +// test cases where DRpmbDevice::SendAccessRequest() is called +// 1.) before DRpmbDevice::Open() is ever called +// 2,) after DRpmbDevice::Close() has been called but before DRpmbDevice::Open() is called + { + Kern::Printf("%S DRpmbDevice::SendAccessRequest not open test", &KDRpmbTestBanner); + // wrap up IO buffers in descriptors to pass across interface + + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + + // test call DRpmbDevice::SendAccessRequest before EVER calling open + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r != KErrNotReady) + { + Kern::Printf("%S SendAccessRequest not open test, before EVER opening, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + // test open and close and call again + r = iRpmb.Open(0); + if (r != KErrNone) + { + Kern::Printf("%S SendAccessRequest not open test, opening, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + iRpmb.Close(); + + r = iRpmb.SendAccessRequest(request, response); + if (r != KErrNotReady) + { + Kern::Printf("%S SendAccessRequest not open test, before opening AFTER closing, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + Kern::Printf("%S DRpmbDevice::SendAccessRequest not open test PASS", &KDRpmbTestBanner); + return KErrNone; +} + + +TInt DRpmbTest::OpenWithBadIndex() +// test case where DRpmbDevice::Open() is called with a device index of more than zero + { + Kern::Printf("%S DRpmbDevice::Open bad index test", &KDRpmbTestBanner); + + // test index > 0 + TInt r = iRpmb.Open(1); + if (r != KErrGeneral) + { + Kern::Printf("%S RpmbDevice::Open bad index test, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + Kern::Printf("%S DRpmbDevice::Open bad index test PASS", &KDRpmbTestBanner); + return KErrNone; +} + + +TInt DRpmbTest::MultipleOpen() +// test case where DRpmbDevice::Open() is called twice with the same index parameter and +// the same instance of DRpmbDevice +// test case where DRpmbDevice::Open() is called twice with the same index parameter and +// a different instance of DRpmbDevice + { + Kern::Printf("%S DRpmbDevice::Open use more than once test", &KDRpmbTestBanner); + + TInt r = iRpmb.Open(0); + if (r != KErrNone) + { + Kern::Printf("%S RpmbDevice::Open use more than once test first open, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + r = iRpmb.Open(0); + if (r != KErrNone) + { + Kern::Printf("%S RpmbDevice::Open use more than once test second open, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + r = iRpmbSecondInstance.Open(0); + if (r != KErrInUse) + { + Kern::Printf("%S RpmbDevice::Open use more than once test third open, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + iRpmb.Close(); + iRpmbSecondInstance.Close(); + + Kern::Printf("%S DRpmbDevice::Open use more than once test PASS", &KDRpmbTestBanner); + + return KErrNone; + } + + +TInt DRpmbTest::SendAccessRequestBadParms() +// test cases where DRpmbDevice::SendAccessRequest is called with secriptor arguments with invalid lengths + { + Kern::Printf("%S DRpmbDevice::SendAccessRequest bad parms test", &KDRpmbTestBanner); + + // test both lengths != KRpmbOneFramePacketLength + TBuf request; + TBuf response; + request.SetLength(KRpmbOneFramePacketLength-1); + response.SetLength(KRpmbOneFramePacketLength+1); + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r != KErrArgument) + { + Kern::Printf("%S SendAccessRequest bad parms test, both params bad, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + // test request length != KRpmbOneFramePacketLength + TBuf request1; + TBuf response1; + request1.SetLength(KRpmbOneFramePacketLength+1); + response1.SetLength(KRpmbOneFramePacketLength); + + r = iRpmb.SendAccessRequest(request1, response1); + if (r != KErrArgument) + { + Kern::Printf("%S SendAccessRequest bad parms test, request param bad, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + // test response length !=KRpmbOneFramePacketLength + TBuf request2; + TBuf response2; + request2.SetLength(KRpmbOneFramePacketLength); + response2.SetLength(KRpmbOneFramePacketLength-1); + + r = iRpmb.SendAccessRequest(request1, response1); + if (r != KErrArgument) + { + Kern::Printf("%S SendAccessRequest bad parms test, response param bad, unexpected error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + + Kern::Printf("%S DRpmbDevice::SendAccessRequest bad parms test PASS", &KDRpmbTestBanner); + return KErrNone; +} + +TInt DRpmbTest::InvalidRequestId() +// send a request with an invalid request ID to the RPMB partition +// when SendAccessRequest returns iResponse should not have reponse or result fields filled in + { + Kern::Printf("%S invalid request ID test", &KDRpmbTestBanner); + + // set up write request packet with blank MAC + memset(iRequest, 0, KRpmbOneFramePacketLength); + * (iRequest + KRpmbRequestLsbOffset) = KRpmbRequestReadResultRegister + 1; + + // wrap up IO buffers in descriptors to pass across interface + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r != KErrNone) + { + Kern::Printf("%S invalid request ID test, send request error = %d", + &KDRpmbTestBanner, r); + return r; + } + + // check that response or result fields have not been set in response + TUint resp = DecodeResponse(iResponse); + TUint result = DecodeResult(iResponse); + + if (resp != 0x0006) + { + Kern::Printf("%S invalid request ID test, unexpected response = %d error", + &KDRpmbTestBanner, resp); + return KErrGeneral; + } + + if (result != 0x0000) + { + Kern::Printf("%S invalid request ID test, unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + + Kern::Printf("%S invalid requeset ID test PASS", &KDRpmbTestBanner); + return KErrNone; + } + + +TInt DRpmbTest::IsKeyProgrammed() +// send a data write request to the RPMB partition +// because the request has a blank MAC (not authenticated) +// the partition returns operation result authentication failure if the key is programmed +// else the partition returns authentication key not programmed + { + Kern::Printf("%S data write test", &KDRpmbTestBanner); + + // set up write request packet with blank MAC + memset(iRequest, 0, KRpmbOneFramePacketLength); + * (iRequest + KRpmbRequestLsbOffset) = KRpmbRequestWriteData; + + // wrap up IO buffers in descriptors to pass across interface + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r != KErrNone) + { + Kern::Printf("%S data write test, send request error = %d", + &KDRpmbTestBanner, r); + return r; + } + + TUint resp = DecodeResponse(iResponse); + TUint result = DecodeResult(iResponse); + + if (resp != KRpmbResponseWriteData) + { + Kern::Printf("%S data write test, unexpected response = %d error", + &KDRpmbTestBanner, resp); + return KErrGeneral; + } + + if (result == KRpmbResultKeyNotProgrammed) + { + iKeySet = EFalse; + Kern::Printf("%S data write test, key NOT programmed", + &KDRpmbTestBanner); + } + else if (result == KRpmbResultAuthenticationFailure) + { + iKeySet = ETrue; + Kern::Printf("%S data write test, key ALREADY programmed", + &KDRpmbTestBanner); + } + else + { + Kern::Printf("%S data write test, unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + Kern::Printf("%S data write test PASS", &KDRpmbTestBanner); + return KErrNone; + } + +TInt DRpmbTest::WriteKey() + { + Kern::Printf("%S write key test", &KDRpmbTestBanner); + + // set up write key request + memset(iRequest, 0, KRpmbOneFramePacketLength); + * (iRequest + KRpmbRequestLsbOffset) = KRpmbRequestWriteKey; + // key = 0x0101010101010101010101010101010101010101010101010101010101010101 + memset(iRequest+KRpmbKeyOffset,1, KRpmbKeyLength); + + // wrap up IO buffers in descriptors to pass across interface + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r != KErrNone) + { + Kern::Printf("%S write key test, send request error = %d", + &KDRpmbTestBanner, r); + return r; + } + + TUint resp = DecodeResponse(iResponse); + TUint result = DecodeResult(iResponse); + + if (resp != KRpmbResponseWriteKey) + { + Kern::Printf("%S write key test, unexpected repsponse = %d error", + &KDRpmbTestBanner, resp); + return KErrGeneral; + } + + if (iKeySet) + { + if (result == KRpmbResultGeneralFailure) + { + Kern::Printf("%S write key test, key ALREADY written", + &KDRpmbTestBanner); + Kern::Printf("%S write key test PASS", + &KDRpmbTestBanner); + return KErrNone; + } + else + { + Kern::Printf("%S write key test, unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + } + else + { + if(result == KRpmbResultOk) + { + Kern::Printf("%S write key test, key JUST written", + &KDRpmbTestBanner); + Kern::Printf("%S write key test PASS", &KDRpmbTestBanner); + return KErrNone; + } + else + { + Kern::Printf("%S write key test unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + } + } + +TInt DRpmbTest::ReadWriteCounter() + { + Kern::Printf("%S read write counter test", &KDRpmbTestBanner); + + // set up read write counter request packet + memset(iRequest, 0, KRpmbOneFramePacketLength); + * (iRequest + KRpmbRequestLsbOffset) = KRpmbRequestReadWriteCounter; + + // wrap up IO buffers in descriptors to pass across interface + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + TInt r = iRpmb.SendAccessRequest(request, response); + if (r!=KErrNone) + { + Kern::Printf("%S read write counter test, send request error = %d", + &KDRpmbTestBanner, r); + return r; + } + + TUint resp = DecodeResponse(iResponse); + TUint result = DecodeResult(iResponse); + TUint32 counter = DecodeCounter(iResponse); + + if (resp != KRpmbResponseReadWriteCounter) + { + Kern::Printf("%S read write counter test, unexpected repsponse = %d error", + &KDRpmbTestBanner, resp); + return KErrGeneral; + } + +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if (result == KRpmbResultOk) +#else + if (result == KRpmbResultOk || result == KRpmbResultKeyNotProgrammed) +#endif + { + Kern::Printf("%S read write counter test write counter = %d", + &KDRpmbTestBanner, counter); + Kern::Printf("%S read write counter test PASS", &KDRpmbTestBanner); + return KErrNone; + } + else + { + Kern::Printf("%S read write counter test, unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + } + +TInt DRpmbTest::ReadData() + { + Kern::Printf("%S read data test", &KDRpmbTestBanner); + + // set up read request packet + memset(iRequest, 0, KRpmbOneFramePacketLength); + * (iRequest + KRpmbRequestLsbOffset) = KRpmbRequestReadData; + + // wrap up IO buffers in descriptors to pass across interface + TPtr8 request(iRequest,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + TPtr8 response(iResponse,KRpmbOneFramePacketLength,KRpmbOneFramePacketLength); + + TInt r=iRpmb.SendAccessRequest(request, response); + if (r!=KErrNone) + { + Kern::Printf("%S read data test, send request error = %d", + &KDRpmbTestBanner, r); + return r; + } + + TUint resp = DecodeResponse(iResponse); + TUint result = DecodeResult(iResponse); + + if (resp != KRpmbResponseReadData) + { + Kern::Printf("%S read data test, unexpected repsponse = %d error", + &KDRpmbTestBanner, resp); + return KErrGeneral; + } + +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if (result == KRpmbResultOk) +#else + if (result == KRpmbResultOk || result == KRpmbResultKeyNotProgrammed) +#endif + { + DisplayReadData(iResponse); + Kern::Printf("%S read data test PASS", &KDRpmbTestBanner); + return KErrNone; + } + else + { + Kern::Printf("%S read data test, unexpected result = %d error", + &KDRpmbTestBanner, result); + return KErrGeneral; + } + } + +TUint DRpmbTest::DecodeResponse(TUint8 * aResp) + { + return (* (aResp + KRpmbResponseLsbOffset) + ((* (aResp + KRpmbResponseMsbOffset)) << 8)); + } + +TUint DRpmbTest::DecodeResult(TUint8 * aResp) + { + return ((* (aResp + KRpmbResultLsbOffset) + ((* (aResp + KRpmbResultMsbOffset)) << 8)) + & KRpmbResultCounterExpiredMask); + } + +TUint32 DRpmbTest::DecodeCounter(TUint8 * aResp) + { + + return ((* (aResp + KRpmbCounterByteOneOffset)) + ((* (aResp + KRpmbCounterByteTwoOffset)) << 8) + + ((* (aResp + KRpmbCounterByteThreeOffset)) << 16) + ((* (aResp + KRpmbCounterByteFourOffset)) << 24)); + } + +void DRpmbTest::DisplayReadData(TUint8 * aResp) + { + TUint8 * displayPtr = aResp + KRpmbDataOffset; + Kern::Printf("%S data field:", &KDRpmbTestBanner); + for (TInt i=0; i<8; i++) + { + Kern::Printf("%x%x%x%x %x%x%x%x %x%x%x%x %x%x%x%x %x%x%x%x %x%x%x%x %x%x%x%x %x%x%x%x", + * displayPtr , * (displayPtr + 1), * (displayPtr + 2), * (displayPtr + 3), + * (displayPtr + 4), * (displayPtr + 5), * (displayPtr + 6), * (displayPtr + 7), + * (displayPtr + 8), * (displayPtr + 9), * (displayPtr + 10), * (displayPtr + 11), + * (displayPtr + 12), * (displayPtr + 13), * (displayPtr + 14), * (displayPtr + 15), + * (displayPtr + 16), * (displayPtr + 17), * (displayPtr + 18), * (displayPtr + 19), + * (displayPtr + 20), * (displayPtr + 21), * (displayPtr + 22), * (displayPtr + 23), + * (displayPtr + 24), * (displayPtr + 25), * (displayPtr + 26), * (displayPtr + 27), + * (displayPtr + 28), * (displayPtr + 29), * (displayPtr + 30), * (displayPtr + 31)); + displayPtr +=32; + } + } + +void DRpmbTest::StackCallBack(TAny * aSelf) +// call back from MMC stack session + { + // dereference any pointer + DRpmbTest& self = *static_cast(aSelf); + // signal semaphore so that calling code progresses + Kern::SemaphoreSignal(*(self.iStackSemPtr)); + } + +TInt DRpmbTest::RpmbStackTests() +// Test code verfies all four access types through a direct connection to the MMC protocol stack + { + TInt r = SetupForStackTests(); + if (r == KErrNone) + { + r = StackBadIndex(); + } + if (r == KErrNone) + { + r = StackIsKeyProgrammed(); + } +// Don't want to write key 'pre production' on a real device as this will lock +// the system out of the RPMB partition (the key should be preprogrammed as +// part of the production process so that the system has access to the key - +// if the key has already been written it can't be written again) +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if (r == KErrNone) + { + r = StackWriteKey(); + } +#endif + if (r == KErrNone) + { + r = StackReadWriteCounter(); + } + if (r == KErrNone) + { + r = StackReadData(); + } + return r; + } + + +TInt DRpmbTest::StackBadIndex() +// Call MMCGetExtInterface with invalid device id +// - don't expect params to be returned +// - expect KErrGeneral return code + { + Kern::Printf("%S stack device index test", &KDRpmbTestBanner); + + MRpmbInfo* rpmbInterface = NULL; + TRpmbDeviceParms parms; + + TInt r = MMCGetExtInterface(KInterfaceRpmb, (MMCMExtInterface*&) rpmbInterface, this); //this pointer not used in the case of Rpmb + if (r!=KErrNone) + { + Kern::Printf("%S stack device index, MMCGetInterface returned error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + if (rpmbInterface == NULL) + { + // unexpected error since MMCGetExtInterface didn't return an error + Kern::Printf("%S stack device index, MMCGetInterface returned NULL interface pointer", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + else + { + r = rpmbInterface->RpmbInfo(1, parms); + if (r == KErrNone) + { + Kern::Printf("%S stack device index test, parmas returned for index 1 error", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + else if (r != KErrGeneral) + { + Kern::Printf("%S stack device index test, unexpected rc for index 1 error", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + } + Kern::Printf("%S stack device index test PASS", &KDRpmbTestBanner); + return KErrNone; +} + + +void DRpmbTest::BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2) +{ + DRpmbTest* lddPtr = (DRpmbTest*)aPtr; + TPBusState busState = (TPBusState) (TInt) a1; + TInt busError = (TInt) a2; + + if(aReason == TPBusCallBack::EPBusStateChange + && busState == EPBusOn && busError == KErrNone) + { + Kern::SemaphoreSignal(*(lddPtr->iPowerSemPtr)); + } +} + +TInt DRpmbTest::SetupForStackTests() + { + Kern::Printf("%S setup for stack tests", &KDRpmbTestBanner); + + TRpmbDeviceParms parms; + + parms.iCardNumber = 0; + parms.iSocketPtr = NULL; + + DMMCStack* stack = NULL; + TUint cardNumber = 0; + MRpmbInfo* rpmbInterface = NULL; + + TInt r = MMCGetExtInterface(KInterfaceRpmb, (MMCMExtInterface*&) rpmbInterface, this); //this pointer not used in the case of Rpmb + if (r!=KErrNone) + { + Kern::Printf("%S setup for stack tests, MMCGetInterface returned error = %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + if (rpmbInterface == NULL) + { + // unexpected error since MMCGetExtInterface didn't return an error + return KErrGeneral; + } + + else + { + r = rpmbInterface->RpmbInfo(0, parms); + if (r != KErrNone) + { + // requested index non zero or bseport not configured with RPMB capable MMC device + return r; + } + + cardNumber = parms.iCardNumber; + iSocket = parms.iSocketPtr; + if(iSocket == NULL) + { + Kern::Printf("%S setup for stack tests, socket pointer is NULL", + &KDRpmbTestBanner); + return KErrNoMemory; + } + + // set up to be informed of changes on bus + iBusCallBack.iFunction = BusCallBack; + iBusCallBack.iPtr=this; + iBusCallBack.SetSocket(iSocket->iSocketNumber); + iBusCallBack.Add(); + + // power up the stack + // media drivers don't have to do this at this stage because already done + NKern::ThreadEnterCS(); + + r = Kern::SemaphoreCreate(iPowerSemPtr,_L("DpmbPowerSem"), 0); + + if (r!=KErrNone) + { + NKern::ThreadLeaveCS(); + Kern::Printf("%S sese you below thentup for stack tests, SemaphoreCreate returned %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + r = iSocket->PowerUp(); + + if (r!=KErrNone && r!= KErrCompletion) + { + NKern::ThreadLeaveCS(); + Kern::Printf("%S setup for stack tests, PowerUp returned %d", + &KDRpmbTestBanner, r); + return KErrGeneral; + } + + if (r == KErrNone) + { + // wait for socket to power up + Kern::SemaphoreWait(*iPowerSemPtr); + } + + NKern::ThreadLeaveCS(); + + stack = iSocket->Stack(0); + if (stack == NULL) + { + // baseport poorly configured + Kern::Printf("%S setup for stack tests, stack pointer is NULL", + &KDRpmbTestBanner); + return KErrGeneral; + } + } + + TMMCard* card = stack->CardP(cardNumber); + + if (card == NULL) + { + // baseport poorly configured + Kern::Printf("%S setup for stack tests, card pointer is NULL", + &KDRpmbTestBanner); + return KErrGeneral; + } + + NKern::ThreadEnterCS(); + + iSession = stack->AllocSession(iSessionEndCallBack); + + NKern::ThreadLeaveCS(); + + if (iSession == NULL) + { + Kern::Printf("%S setup for stack tests, session pointer is NULL", + &KDRpmbTestBanner); + return(KErrNoMemory); + } + + iSession->SetStack(stack); + + iSession->SetCard(card); + + TUint32 revision = 0; + + // loop until extended csd becomes available in case earlier pause wasn't long enough + // this shouldn't need to be done + // a reliable method not depending on delays and or polling is required + do { + stack = iSocket->Stack(0); + if (stack) + { + card = stack->CardP(cardNumber); + if (card) + { + revision = card->ExtendedCSD().ExtendedCSDRev(); + } + } + } while (revision==0); + + TUint size = card->ExtendedCSD().RpmbSize(); + + if(revision < 5 || size == 0) + { + Kern::Printf("%S setup for stack test, rpmb partition NOT detected", &KDRpmbTestBanner); + return KErrNotSupported; + } + + // use memory from stack + TInt bufLen, minorBufLen; + stack->BufferInfo(iBufPtr, bufLen, minorBufLen); + // mmc media driver reserved the first KRpmbOneFramePacketLength bytes of the + // PSL buffer to be used for RPMB requests / responses + iBufPtr += minorBufLen; + + return KErrNone; + } + + +TInt DRpmbTest::StackIsKeyProgrammed() +// Write Data to block 0 without MACing +// - expect not MACed error if key set +// - expect key not prgrammed error if key not programmed + { + + Kern::Printf("%S write data stack test", &KDRpmbTestBanner); + + // set up write request packet in stack memory + memset(iBufPtr,0,KRpmbOneFramePacketLength); + * (iBufPtr + KRpmbRequestLsbOffset) = KRpmbRequestWriteData; + + TInt r = SendToStackAndWait(); + if (r != KErrNone) + { + return r; + } + + TUint response = DecodeResponse(iBufPtr); + TUint result = DecodeResult(iBufPtr); + + if (response == KRpmbResponseWriteData) + { + if (result == KRpmbResultAuthenticationFailure) + { + Kern::Printf("%S write data stack test, key IS written", + &KDRpmbTestBanner); + Kern::Printf("%S write data stack test PASS", &KDRpmbTestBanner); + iKeySet = ETrue; + return KErrNone; + } + else if (result == KRpmbResultKeyNotProgrammed) + { + Kern::Printf("%S write data stack test, key NOT written", + &KDRpmbTestBanner); + Kern::Printf("%S write data stack test PASS",&KDRpmbTestBanner); + iKeySet = EFalse; + return KErrNone; + } + } + Kern::Printf("%S write data stack test FAILED, response = %d, result = %d", + &KDRpmbTestBanner, response, result); + return KErrGeneral; + } + +TInt DRpmbTest::StackWriteKey() +// Write key +// - expect no error if key not programmed +// - expect general error if key already programmed + { + Kern::Printf("%S write key stack test", &KDRpmbTestBanner); + + // set up write key request packet in stack memory + memset(iBufPtr,0,KRpmbOneFramePacketLength); + * (iBufPtr + KRpmbRequestLsbOffset) = KRpmbRequestWriteKey; + + TInt r = SendToStackAndWait(); + if (r != KErrNone) + { + return r; + } + + TUint response = DecodeResponse(iBufPtr); + TUint result = DecodeResult(iBufPtr); + + if (response == KRpmbResponseWriteKey) + { + if (iKeySet && result == KRpmbResultGeneralFailure) + { + Kern::Printf("%S write key stack test, key ALREADY written", + &KDRpmbTestBanner); + Kern::Printf("%S write key stack test PASS", &KDRpmbTestBanner); + return KErrNone; + } + else if (!iKeySet && result == KRpmbResultOk) + { + Kern::Printf("%S write key stack test, key JUST written", + &KDRpmbTestBanner); + Kern::Printf("%S write key stack test PASS", &KDRpmbTestBanner); + return KErrNone; + } + } + Kern::Printf("%S write key stack test FAILED, response = %d, result = %d", + &KDRpmbTestBanner, response, result); + return KErrGeneral; + } + +TInt DRpmbTest::StackReadWriteCounter() +// Read Data Counter +// - expect no error + { + Kern::Printf("%S read write counter stack test", &KDRpmbTestBanner); + + // set up write key request packet in stack memory + memset(iBufPtr,0,KRpmbOneFramePacketLength); + * (iBufPtr + KRpmbRequestLsbOffset) = KRpmbRequestReadWriteCounter; + + TInt r = SendToStackAndWait(); + if (r != KErrNone) + { + return r; + } + + TUint response = DecodeResponse(iBufPtr); + TUint result = DecodeResult(iBufPtr); + TUint32 counter = DecodeCounter(iBufPtr); + +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if ((response == KRpmbResponseReadWriteCounter) && (result == KRpmbResultOk)) +#else + if ((response == KRpmbResponseReadWriteCounter) + && (result == KRpmbResultOk || result == KRpmbResultKeyNotProgrammed)) +#endif + { + Kern::Printf("%S read write counter stack test, counter = %d", + &KDRpmbTestBanner, counter); + Kern::Printf("%S read write counter stack test PASS", + &KDRpmbTestBanner); + return KErrNone; + } + Kern::Printf("%S read write counrter stack test FAILED, response = %d, result = %d", + &KDRpmbTestBanner, response, result); + return KErrGeneral; + } + + +TInt DRpmbTest::StackReadData() +// Read Data from block 0 +// - expect no error + { + Kern::Printf("%S read data stack test", &KDRpmbTestBanner); + + // set up write key request packet in stack memory + memset(iBufPtr,0,KRpmbOneFramePacketLength); + * (iBufPtr + KRpmbRequestLsbOffset) = KRpmbRequestReadData; + + TInt r = SendToStackAndWait(); + if (r != KErrNone) + { + return r; + } + + TUint response = DecodeResponse(iBufPtr); + TUint result = DecodeResult(iBufPtr); + +#ifdef RPMBTESTS_TRY_TO_WRITE_KEY + if ((response == KRpmbResponseReadData) && (result == KRpmbResultOk)) +#else + if ((response == KRpmbResponseReadData) + && (result == KRpmbResultOk || result == KRpmbResultKeyNotProgrammed)) +#endif + { + DisplayReadData(iBufPtr); + Kern::Printf("%S read data stack test PASS", &KDRpmbTestBanner); + return KErrNone; + } + Kern::Printf("%S read data stack test FAILED, response = %d, result = %d", + &KDRpmbTestBanner, response, result); + return KErrGeneral; + } + +TInt DRpmbTest::SendToStackAndWait() + { +// comment out to get timings with RPMB -> RPMB switches in place of User +// Area -> RPMB switces +#define RPMBSTACKTEST_FIRST_SWITCH_TO_USER_AREA +#ifdef RPMBSTACKTEST_FIRST_SWITCH_TO_USER_AREA + // in normal operation it may be necessary to switch to RPMB partition + // prior to access + // so force the switch to occur by pre switching to the user area + iSession->SetPartition(TExtendedCSD::ESelectUserArea); +#endif + + TInt start, postswitch, end; + + start = NKern::TickCount(); + + // lock stack + TInt r = iSocket->InCritical(); + if (r != KErrNone) + { + Kern::Printf("%S DRpmbTest::SendToStackAndWait, error=%d", + &KDRpmbTestBanner, r); + iSocket->EndInCritical(); + return KErrGeneral; + } + + // switch to RPMB partition + iSession->SetPartition(TExtendedCSD::ESelectRPMB); + + postswitch = NKern::TickCount(); + + // set up for write exchange + iSession->ResetCommandStack(); + iSession->FillCommandArgs(0, KRpmbOneFramePacketLength, iBufPtr, KRpmbOneFramePacketLength); + iSession->iSessionID = ECIMRpmbAccess; + iSession->Engage(); + + // wait for stack call to complete + r = Kern::SemaphoreWait(*iStackSemPtr); + + end = NKern::TickCount(); + + Kern::Printf("%S switch to RPMB took %d %d uS timer ticks", + &KDRpmbTestBanner, start - postswitch, NKern::TickPeriod()); + Kern::Printf("%S RPMB ECIMRpmbAccess took %d %d uS timer ticks", + &KDRpmbTestBanner, end - postswitch, NKern::TickPeriod()); + + if (r != KErrNone) + { + Kern::Printf("%S DRpmbTest::SendToStackAndWait, SemaphoreWait return code = %d", + &KDRpmbTestBanner, r); + iSocket->EndInCritical(); + return KErrGeneral; + } + + // check stack epoc return code + r = iSession->EpocErrorCode(); + if (r != KErrNone) + { + Kern::Printf("%S DRpmbTest::stack epoc return code = %d", + &KDRpmbTestBanner, r); + iSocket->EndInCritical(); + return KErrGeneral; + } + + // unlock stack + iSocket->EndInCritical(); + + return KErrNone; + } + diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/driver/d_rpmb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/driver/d_rpmb.h Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,89 @@ +// Copyright (c) 2010 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/rpmb/rpmb.h +// +// + +/** + @file + @internalComponent + @prototype +*/ + +#include +#include +#include + +// banner for reporting progress of these tests +_LIT(KDRpmbTestBanner,"RPMB TEST DRIVER: "); + +// RPMB test driver factory class +class DRpmbTestFactory : public DLogicalDevice + { +public: + DRpmbTestFactory(); + ~DRpmbTestFactory(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); + }; + +// RPMB test driver request handling class +class DRpmbTest : public DLogicalChannelBase + { +public: + DRpmbTest(); + virtual ~DRpmbTest(); + TInt DRpmbDeviceTests(); + TInt RpmbStackTests(); +protected: + TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + TInt Request(TInt aFunction, TAny* a1, TAny* a2); +private: + TInt SendAccessRequestNotOpen(); + TInt OpenWithBadIndex(); + TInt MultipleOpen(); + TInt SendAccessRequestBadParms(); + TInt InvalidRequestId(); + TInt IsKeyProgrammed(); + TInt WriteKey(); + TInt ReadWriteCounter(); + TInt ReadData(); + TUint DecodeResponse(TUint8 * aResp); + TUint DecodeResult(TUint8 * aResp); + TUint32 DecodeCounter(TUint8 * aResp); + void DisplayReadData(TUint8 * aResp); + static void BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2); + static void StackCallBack(TAny * aSelf); + TInt StackBadIndex(); + TInt SetupForStackTests(); + TInt StackIsKeyProgrammed(); + TInt StackWriteKey(); + TInt StackReadWriteCounter(); + TInt StackReadData(); + TInt SendToStackAndWait(); +private: + DRpmbDevice iRpmb; + DRpmbDevice iRpmbSecondInstance; + TUint8 * iRequest; + TUint8 * iResponse; + TBool iKeySet; + TUint8* iBufPtr; + DSemaphore * iStackSemPtr; + DSemaphore * iPowerSemPtr; + TPBusCallBack iBusCallBack; + TMMCCallBack iSessionEndCallBack; + DMMCSocket* iSocket; + DMMCSession* iSession; + }; diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/driver/d_rpmb.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/driver/d_rpmb.mmp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,43 @@ +/// Copyright (c) 2010 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/group/d_rpmb.mmp +// +// + +/** + @file +*/ + +#include "kernel/kern_ext.mmh" + +target d_rpmb.ldd +targettype ldd +sourcepath ./ +source d_rpmb.cpp + +library rpmbext.lib + +library epbusmmc.lib + +epocallowdlldata + +vendorid 0x70000001 + +start wins +win32_headers +end + +capability all + +SMPSAFE \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/rpmbtestautoexec.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/rpmbtestautoexec.bat Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,17 @@ +rem +rem Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +rem All rights reserved. +rem This component and the accompanying materials are made available +rem under the terms of the License "Eclipse Public License v1.0" +rem which accompanies this distribution, and is available +rem at the URL "http://www.eclipse.org/legal/epl-v10.html". +rem +rem Initial Contributors: +rem Nokia Corporation - initial contribution. +rem +rem Contributors: +rem +rem Description: +rem + +t_rpmb \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/t_rpmb.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/t_rpmb.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,58 @@ + +// Copyright (c) 2010 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/rpmb/t_rpmb.cpp +// LDD for testing RPMB kernel extension +// +// + +/** + @file + @internalComponent + @prototype +*/ + +#define __E32TEST_EXTENSION__ +#include +#include "t_rpmb.h" + +RTest test(_L("t_rpmb")); +RTestRpmb RpmbTestDeviceDriver; + +/****************************************************************************** + * Main + ******************************************************************************/ +TInt E32Main() + { +#if !defined(__WINS__) + test.Title(); + test.Start(_L("Opening device driver")); + TInt r; + r = User::LoadLogicalDevice(KRpmbTestLddName); + test_Value(r,r==KErrNone||r==KErrAlreadyExists); + r = RpmbTestDeviceDriver.Open(); + test_KErrNone(r); + test.Next(_L("Execute RPMB tests")); + r = RpmbTestDeviceDriver.RunTests(); + test_KErrNone(r); + RpmbTestDeviceDriver.Close(); + r = User::FreeLogicalDevice(KRpmbTestLddName); + test_KErrNone(r); + test.End(); +#else +test.Printf(_L("This test does not run on emulator. \n")); +#endif + return 0; + } + diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/t_rpmb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/t_rpmb.h Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,43 @@ +// Copyright (c) 2010 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/rpmb/t_rpmb.h +// +// + +/** + @file + @internalTechnology + @prototype +*/ + +// name of kernel side RPMB test driver +_LIT(KRpmbTestLddName,"d_rpmb"); + +// user side client object for accessing kernel side RPMB test driver +class RTestRpmb : public RBusLogicalChannel + { +public: + enum TControl + { + ERunTests=0, + }; +#ifndef __KERNEL_MODE__ +// these public methods are only accessed from the user side +public: + inline TInt Open() + { return DoCreate(KRpmbTestLddName,TVersion(),KNullUnit,NULL,NULL); } + inline TInt RunTests() + { return DoControl(ERunTests); } +#endif // __KERNEL_MODE__ + }; diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/e32test/rpmb/t_rpmb.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/rpmb/t_rpmb.mmp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,35 @@ +/// Copyright (c) 2010 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/group/t_rpmb.mmp +// +// + +/** + @file +*/ + +target t_rpmb.exe +targettype exe +sourcepath ../rpmb +source t_rpmb.cpp + +library euser.lib +userinclude ../rpmb +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +vendorid 0x70000001 + +capability none + +SMPSAFE \ No newline at end of file diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/f32test/bench/t_trimbm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/bench/t_trimbm.cpp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,875 @@ +// Copyright (c) 1996-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: +// f32test/bench/t_fsysbm.cpp +// +// + +#define __E32TEST_EXTENSION__ + +#include +#include +#include +#include +#include +#include +#include +#include "t_server.h" +#include "../../e32test/mmu/d_sharedchunk.h" +#include "../../e32utils/pccd/d_mmcif.h" + +#define SYMBIAN_TEST_EXTENDED_BUFFER_SIZES // test using a greater number of buffer sizes + +RTest test(_L("eMMC 4.4 TRIM Benchmark")); + +static const TUint K1K = 1024; // 1K +static const TUint K1M = K1K * K1K ; // 1M +static const TUint K2M = 2 * K1M; // 2M + + +#if defined(__WINS__) +static TInt KMaxFileSize = 256 * K1K; // 256K +#else +static TInt KMaxFileSize = K2M; // 2M +#endif + +const TTimeIntervalMicroSeconds32 KFloatingPointTestTime = 10000000; // 10 seconds + +static TPtr8 DataBuf(NULL, KMaxFileSize,KMaxFileSize); + +static RSharedChunkLdd Ldd; +static RChunk TheChunk; + +GLDEF_D RFs TheFs; +GLDEF_D TFileName gSessionPath; +GLDEF_D TChar gDriveToTest; + +static RMmcCntrlIf iDriver; +static TInt iStack = 0; +static TInt iCard = 0; +static TBool iDriverOpen = EFalse; + +enum TPanic {ECreatingConsole,ELoaderCheck,ELoadingMmcDriver,EStartingMmcDriver}; + +LOCAL_C void Panic(TPanic aPanic) +// +// Panic +// + { + User::Panic(_L("MMCTEST"),aPanic); + } + + +static RFile File; + +static TInt gFastCounterFreq; + +const TUint KMMCExtendedCSDLength=512; +class TExtendedCSD + { +public: + enum TExtCSDAccessBits {ECmdSet, ESetBits, EClearBits, EWriteByte}; + enum TExtCSDModesFieldIndex + { + ECmdSetIndex = 191, + ECmdSetRevIndex = 189, + EPowerClassIndex = 187, + EHighSpeedInterfaceTimingIndex = 185, + EBusWidthModeIndex = 183 + }; + enum TExtCSDBusWidths + { + EExtCsdBusWidth1 = 0x00, + EExtCsdBusWidth4 = 0x01, + EExtCsdBusWidth8 = 0x02 + }; + enum TCardTypes + { + EHighSpeedCard26Mhz = 0x01, + EHighSpeedCard52Mhz = 0x02 + }; +public: + inline TExtendedCSD(); // Default constructor + inline TExtendedCSD(const TUint8*); + inline TExtendedCSD& operator=(const TExtendedCSD&); + inline TExtendedCSD& operator=(const TUint8*); + inline TUint8 At(TUint anIndex) const; // Byte from CSD at anIndex +public: + inline TUint SupportedCmdSet() const; + inline TUint MinPerfWrite8Bit52Mhz() const; + inline TUint MinPerfRead8Bit52Mhz() const; + inline TUint MinPerfWrite8Bit26Mhz_4Bit52Mhz() const; + inline TUint MinPerfRead8Bit26Mhz_4Bit52Mhz() const; + inline TUint MinPerfWrite4Bit26Mhz() const; + inline TUint MinPerfRead4Bit26Mhz() const; + inline TUint PowerClass26Mhz360V() const; + inline TUint PowerClass52Mhz360V() const; + inline TUint PowerClass26Mhz195V() const; + inline TUint PowerClass52Mhz195V() const; + inline TUint CardType() const; + inline TUint CSDStructureVer() const; + inline TUint ExtendedCSDRev() const; + inline TUint CmdSet() const; + inline TUint CmdSetRev() const; + inline TUint PowerClass() const; + inline TUint HighSpeedTiming() const; + inline TUint BusWidth() const; + + inline TUint TrimMultiplier() const; + inline TUint SecureFeatureSupport() const; + inline TUint SecureEraseMultiplier() const; + inline TUint SecureTrimMultiplier() const; + +private: + /**< @internalComponent little endian 512 byte field representing extended CSD */ + TUint8 iData[KMMCExtendedCSDLength]; + }; + +inline TExtendedCSD::TExtendedCSD() // Default constructor + {} +inline TExtendedCSD::TExtendedCSD(const TUint8* aPtr) + {memcpy(&iData[0], aPtr, KMMCExtendedCSDLength);} +inline TExtendedCSD& TExtendedCSD::operator=(const TExtendedCSD& aCSD) + {memcpy(&iData[0], &aCSD.iData[0], KMMCExtendedCSDLength); return(*this);} +inline TExtendedCSD& TExtendedCSD::operator=(const TUint8* aPtr) + {memcpy(&iData[0], aPtr, KMMCExtendedCSDLength); return(*this);} +// field accessors. +// "Properties Segment" of Extended CSD - i.e. read-only fields +inline TUint TExtendedCSD::SupportedCmdSet() const {return iData[504];} +inline TUint TExtendedCSD::MinPerfWrite8Bit52Mhz() const {return iData[210];} +inline TUint TExtendedCSD::MinPerfRead8Bit52Mhz() const {return iData[209];} +inline TUint TExtendedCSD::MinPerfWrite8Bit26Mhz_4Bit52Mhz() const {return iData[208];} +inline TUint TExtendedCSD::MinPerfRead8Bit26Mhz_4Bit52Mhz() const {return iData[207];} +inline TUint TExtendedCSD::MinPerfWrite4Bit26Mhz() const {return iData[206];} +inline TUint TExtendedCSD::MinPerfRead4Bit26Mhz() const {return iData[205];} +inline TUint TExtendedCSD::PowerClass26Mhz360V() const {return iData[203];} +inline TUint TExtendedCSD::PowerClass52Mhz360V() const {return iData[202];} +inline TUint TExtendedCSD::PowerClass26Mhz195V() const {return iData[201];} +inline TUint TExtendedCSD::PowerClass52Mhz195V() const {return iData[200];} +inline TUint TExtendedCSD::CardType() const {return iData[196];} +inline TUint TExtendedCSD::CSDStructureVer() const {return iData[194];} +inline TUint TExtendedCSD::ExtendedCSDRev() const {return iData[192];} + +inline TUint TExtendedCSD::TrimMultiplier() const {return iData[232]; } +inline TUint TExtendedCSD::SecureFeatureSupport() const {return iData[231]; } +inline TUint TExtendedCSD::SecureEraseMultiplier() const {return iData[230]; } +inline TUint TExtendedCSD::SecureTrimMultiplier() const {return iData[229]; } + + +// "Modes Segment" of Extended CSD - i.e. modifiable fields +inline TUint TExtendedCSD::CmdSet() const {return iData[191];} +inline TUint TExtendedCSD::CmdSetRev() const {return iData[189];} +inline TUint TExtendedCSD::PowerClass() const {return iData[187];} +inline TUint TExtendedCSD::HighSpeedTiming() const {return iData[185];} +typedef TPckg TExtendedCSDPckg; + +static TExtendedCSD extCSD; + +GLDEF_C TInt CurrentDrive() +// +// Return the current drive number +// + { + + TInt driveNum; + TInt r=TheFs.CharToDrive(gSessionPath[0],driveNum); + test_KErrNone(r); + return(driveNum); + } + +GLDEF_C void Format(TInt aDrive) +// +// Format current drive +// + { + + TUint initTicks = User::FastCounter(); + TUint finalTicks = 0; + + TBuf<4> driveBuf=_L("?:\\"); + driveBuf[0]=(TText)(aDrive+'A'); + RFormat format; + TInt count; + + TInt r=format.Open(TheFs,driveBuf, EFullFormat,count); // EQuickFormat + test_KErrNone(r); + while(count) + { + TInt r=format.Next(count); + test_KErrNone(r); + } + format.Close(); + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to format %d ms)\n"), timeTakenInMs); + } + + + +static TInt getExtendedCSD() + { + + if (!iDriverOpen) + return(KErrNotSupported); + + + // Power the stack down & up to make sure the CardInfo is up to date + iDriver.Reset(); + User::After(1000); + iDriver.PwrDownStack(); + User::After(1000); + TRequestStatus status; + iDriver.PwrUpAndInitStack(status); + User::WaitForRequest(status); + TInt err; + if ((err=status.Int())!=KErrNone) + { + test.Printf(_L("Error Powering Stack"),err); + return(err); + } + iDriver.SelectCard(iCard); + + // Get the CSD first to check whether the ExtCSD is supported + TMmcCardInfo ci; + if ((err = iDriver.CardInfo(ci))!=KErrNone) + { + test.Printf(_L("Error getting card info"),err); + return(err); + } + //test.Printf(_L("CSD Spec version: %u\n"), ci.iSpecVers); + + if (ci.iSpecVers < 4) + { + test.Printf(_L("Error: Extended CSD not supported\n")); + return KErrNotSupported; + } + + TExtendedCSDPckg extCSDPckg(extCSD); + + iDriver.ReadExtCSD(status, extCSDPckg); + + User::WaitForRequest(status); + + if (status.Int() != KErrNone) + { + test.Printf(_L("Error getting Extended CSD\n")); + return(KErrGeneral); + } + return err; + } + + +static TUint GetSecEraseMultValue(void) + { + TUint retVal = 0; + + getExtendedCSD(); + retVal = extCSD.SecureEraseMultiplier(); + + return retVal; + } + +static TUint GetSecTrimMultValue(void) + { + TUint retVal = 0; + + getExtendedCSD(); + retVal = extCSD.SecureTrimMultiplier(); + + return retVal; + } + +static TUint GetTrimMultValue(void) + { + TUint retVal = 0; + + getExtendedCSD(); + retVal = extCSD.TrimMultiplier(); + + return retVal; + } + +static TInt64 DiskSize(TInt aDrive) +// +// +// + { + TVolumeInfo v; + TInt r=TheFs.Volume(v,aDrive); + test_KErrNone(r); + return(v.iSize); + } + +static TInt CalcEntries(TInt64 aDiskSize, TUint& aEntrySize) + { + + aEntrySize = KMaxFileSize; + TInt numFiles = (TInt)(aDiskSize / aEntrySize); + + while ( numFiles > 1000 ) + { + aEntrySize = aEntrySize << 2 ; + numFiles = (TUint)(aDiskSize / aEntrySize); + } + return numFiles; + + } + +static void WriteFull(TInt aDrive) + { + TInt64 diskSize = DiskSize(aDrive); + + RFile f; + TUint initTicks = 0; + TUint finalTicks = 0; + + TFileName sessionPath; + TInt r=TheFs.SessionPath(sessionPath); + test_KErrNone(r); + TBuf8<8> WriteData =_L8("Wibbleuy"); + + r=TheFs.MkDirAll(gSessionPath); + + + TUint entrySize = KMaxFileSize; + TInt numFiles = CalcEntries(diskSize, entrySize); + test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; + test.Printf(_L("Create %d entries\n"),numFiles); + + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + initTicks = User::FastCounter(); + + for( TInt i = 0; i < numFiles; ++i) + { + + test.Printf(_L("Create FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) ); + TFileName baseName= gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(i); + r=f.Replace(TheFs,baseName,EFileWrite); + test_KErrNone(r); + r = f.SetSize(entrySize); + if( r == KErrDiskFull) + { + numFiles = i; + break; + } + test_Value(r, r == KErrNone || r==KErrDiskFull); + r=f.Write((entrySize-30),WriteData); + test_KErrNone(r); + f.Flush(); + f.Close(); + } + + test.Printf(_L("\nTRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + + test.Printf(_L("Test all entries have been created successfully\n")); + TBuf8<8> ReadData; + TInt Size=0; + for (TInt j=0; j < numFiles; j++) + { + + test.Printf(_L("Check FILE%d\t(%3d%%)\r"), j, (100*j/numFiles) ); + TFileName baseName = gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(j); + + TInt r=f.Open(TheFs,baseName,EFileRead); + if (r!=KErrNone) + { + test_Value(r, r == KErrNotFound && j==numFiles); + return; + } + ReadData.FillZ(); + r=f.Read((entrySize-30),ReadData); + test_KErrNone(r); + test(f.Size(Size)==KErrNone); + test(entrySize == (TUint)Size); + test(ReadData==WriteData); + f.Close(); + } + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to create %d entries = %d ms (%d ms/entry)\n"), numFiles, timeTakenInMs, timeTakenInMs/numFiles ); + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + } + +static void ReWriteHalf(TInt aDrive) + { + TInt64 diskSize = DiskSize(aDrive); + + RFile f; + TUint initTicks = 0; + TUint finalTicks = 0; + + TFileName sessionPath; + TInt r=TheFs.SessionPath(sessionPath); + test_KErrNone(r); + TBuf8<8> WriteData =_L8("Wibbleuy"); + + r=TheFs.MkDirAll(gSessionPath); + + + TUint entrySize = KMaxFileSize; + TInt numFiles = CalcEntries(diskSize, entrySize); + test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; + test.Printf(_L("Create %d entries\n"),numFiles/2); + + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + initTicks = User::FastCounter(); + + for( TInt i = 0; i < numFiles; i += 2) + { + + test.Printf(_L("Create FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) ); + TFileName baseName= gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(i); + r=f.Replace(TheFs,baseName,EFileWrite); + test_KErrNone(r); + r = f.SetSize(entrySize); + if( r == KErrDiskFull) + { + numFiles = i; + break; + } + test_Value(r, r == KErrNone || r==KErrDiskFull); + r=f.Write((entrySize-30),WriteData); + test_KErrNone(r); + f.Flush(); + f.Close(); + } + + test.Printf(_L("\nTRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + + test.Printf(_L("Test all entries have been created successfully\n")); + TBuf8<8> ReadData; + TInt Size=0; + for (TInt j=0; j < numFiles; j += 2) + { + + test.Printf(_L("Check FILE%d\t(%3d%%)\r"), j, (100*j/numFiles) ); + TFileName baseName = gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(j); + + TInt r=f.Open(TheFs,baseName,EFileRead); + if (r!=KErrNone) + { + test_Value(r, r == KErrNotFound && j==numFiles); + return; + } + ReadData.FillZ(); + r=f.Read((entrySize-30),ReadData); + test_KErrNone(r); + test(f.Size(Size)==KErrNone); + test(entrySize == (TUint)Size); + test(ReadData==WriteData); + f.Close(); + } + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to create %d entries = %d ms (%d ms/entry)\n"), numFiles/2, timeTakenInMs, timeTakenInMs/numFiles/2 ); + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + } + + + +static void DeleteAll(TInt aDrive) + { + TInt64 diskSize = DiskSize(aDrive); + + TUint initTicks = 0; + TUint finalTicks = 0; + + TFileName sessionPath; + TInt r=TheFs.SessionPath(sessionPath); + test_KErrNone(r); + + TUint entrySize = KMaxFileSize; + TInt numFiles = CalcEntries(diskSize, entrySize); + test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; + test.Printf(_L("Delete %d entries\n"),numFiles); + + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + + initTicks = User::FastCounter(); + + for( TInt i = 2; i < numFiles; ++i) + { + test.Printf(_L("Delete FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) ); + TFileName baseName = gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(i); + TInt r=TheFs.Delete(baseName); + test_Value(r, r == KErrNotFound || r == KErrNone); + } + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to delete %d entries = %d ms (%d ms/entry)\n"), numFiles, timeTakenInMs, timeTakenInMs/numFiles); + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + } + +static void DeleteHalf(TInt aDrive) + { + TInt64 diskSize = DiskSize(aDrive); + + TUint initTicks = 0; + TUint finalTicks = 0; + + TFileName sessionPath; + TInt r=TheFs.SessionPath(sessionPath); + test_KErrNone(r); + + TUint entrySize = KMaxFileSize; + TInt numFiles = CalcEntries(diskSize, entrySize); + test.Printf(_L("Disk size:%ld bytes, file size: %d bytes \n"), diskSize, entrySize) ; + test.Printf(_L("Delete %d entries\n"),numFiles/2); + + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + + initTicks = User::FastCounter(); + + for( TInt i = 0; i < numFiles; i +=2) + { + test.Printf(_L("Delete FILE%d\t(%3d%%)\r"), i, (100*i/numFiles) ); + TFileName baseName = gSessionPath; + baseName.Append(_L("FILE")); + baseName.AppendNum(i); + TInt r=TheFs.Delete(baseName); + test_Value(r, r == KErrNotFound || r == KErrNone); + } + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to delete %d entries = %d ms (%d ms/entry)\n"), numFiles/2, timeTakenInMs, timeTakenInMs/numFiles/2); + test.Printf(_L("TRIM_MULT :%d\n"), GetTrimMultValue()); + test.Printf(_L("SEC_TRIM_MULT :%d\n"), GetSecTrimMultValue()); + test.Printf(_L("SEC_ERASE_MULT:%d\n"), GetSecEraseMultValue()); + } + + +static void WaitUntilTrimDone() + { + + TUint initTicks = User::FastCounter(); + TUint finalTicks = 0; + +#define READ_TO_KEEP_CARD_ON +#ifdef READ_TO_KEEP_CARD_ON + + const TInt readSize = 4096; + const TInt timeToRead = 30; + + test.Printf(_L("Read a file for %d sec to keep card power on\n"), timeToRead ); + TBuf8<4096> ReadData; + + RTimer timer; + timer.CreateLocal(); + TRequestStatus reqStat; + + //test.Printf(_L("Timer started.\n")); + + TFileName baseName = gSessionPath; + baseName.Append(_L("FILE1")); + + RFile f; + TInt r=f.Open(TheFs,baseName,EFileRead); + if (r!=KErrNone) + { + return; + } + TInt alreadyRead = 0; + TInt fileSize; + test(f.Size(fileSize)==KErrNone); + + //test.Printf(_L("File size:%d.\n"), fileSize); + + timer.After(reqStat, timeToRead*1000000); // After 30 secs + + while( reqStat==KRequestPending ) + { + + test.Printf(_L("Read pos:%d\r"), alreadyRead ); + ReadData.FillZ(); + r=f.Read(readSize,ReadData); + + test_KErrNone(r); + alreadyRead += readSize; + if( alreadyRead == fileSize) + { + alreadyRead = 0; + f.Seek(ESeekStart, alreadyRead); + } + User::After(1000); // 1 ms + } + + timer.Close(); + + f.Close(); + + test.Printf(_L("\n")); + +#else + + TInt trimMult = GetTrimMultValue(); // Get TRIM_MULT value from eMMC Extended CSD + test.Printf(_L("TRIM_MULT:%d\r"), trimMult); + while( trimMult-- > 0 ) + { + // Wait for a while + User::After(300000); // TRIM Timeout = 300ms x TRIM_MULT + test.Printf(_L("TRIM_MULT:%d\r"), trimMult); + TInt trim = GetTrimMultValue(); + } + +#endif + + finalTicks = User::FastCounter(); + TTimeIntervalMicroSeconds duration = TInt64(finalTicks - initTicks) * TInt64(1000000) / TInt64(gFastCounterFreq) ; + + TInt timeTakenInMs = I64LOW(duration.Int64() / 1000); + test.Printf(_L("Time taken to TRIM done = %d ms\n"), timeTakenInMs); + } + + + +void doExit() + { + iDriver.Close(); + + User::FreeLogicalDevice(_L("MmcIf")); + + test.End(); + test.Close(); + + } + +GLDEF_C void CallTestsL(void) +// +// Call all tests +// + { + + test.Next(gSessionPath); + + TInt err; + err=User::LoadLogicalDevice(_L("D_MMCIF")); + __ASSERT_ALWAYS((err==KErrNone||err==KErrAlreadyExists),Panic(ELoadingMmcDriver)); + test.Printf(_L("MMCIF driver loaded\n")); + + + iDriver.Close(); + TInt r=iDriver.Open(iStack,iDriver.VersionRequired()); + iDriverOpen=(r==KErrNone)?(TBool)ETrue:(TBool)EFalse; + test.Printf(_L("iDriverOpen %d\n"), iDriverOpen); + if( !iDriverOpen ) + { + doExit(); + return; + } + + test.Next(_L("Get extended CSD")); + r = getExtendedCSD(); + + if( r != KErrNone ) + { + test.Next(_L("Extended CSD doesn't exists. Exit.")); + doExit(); + return; + } + + if( extCSD.ExtendedCSDRev() < 5 ) + { + test.Next(_L("TRIM feature doesn't exists. Exit!")); + } + + + r = HAL::Get(HAL::EFastCounterFrequency, gFastCounterFreq); + test_KErrNone(r); + test.Printf(_L("HAL::EFastCounterFrequency %d\n"), gFastCounterFreq); + + + TInt currentDrive = CurrentDrive(); + + // 1. Format drive + test.Next(_L("Format drive")); + Format(currentDrive); + + // 2. Set TRIM off + //test.Next(_L("Set TRIM off")); + + + // 3. Write full with files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 4. Delete all files and measure elapsed time + test.Next(_L("Delete all files")); + DeleteAll(currentDrive); + + // 5. Rewrite all (or a set of) files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 6. Format drive + test.Next(_L("Format drive")); + Format(currentDrive); + + // 7. Set TRIM on + //test.Next(_L("Set TRIM on")); + + // 8. Write full with files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 9. Delete all files and measure elapsed time + test.Next(_L("Delete all files")); + DeleteAll(currentDrive); + + // 10. Wait for a while (give time to eMMC to do its TRIM job) + test.Next(_L("Wait for TRIM done")); + WaitUntilTrimDone(); + + // 11. Rewrite all (or same set of) files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 12. Format drive + test.Next(_L("Format drive")); + Format(currentDrive); + + // 13. Write full with files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 14. Delete half of files and measure elapsed time + test.Next(_L("Delete half of files")); + DeleteHalf(currentDrive); + + // 15. Re-write half of files and measure elapsed time + test.Next(_L("Re-write half")); + ReWriteHalf(currentDrive); + + + // 16. Format drive + test.Next(_L("Format drive")); + Format(currentDrive); + + // 17. Write full with files and measure elapsed time + test.Next(_L("Write full")); + WriteFull(currentDrive); + + // 18. Delete half of files and measure elapsed time + test.Next(_L("Delete half of files")); + DeleteHalf(currentDrive); + + // 19. Wait for a while (give time to eMMC to do its TRIM job) + test.Next(_L("Wait for TRIM done")); + WaitUntilTrimDone(); + + // 20. Re-write half of files and measure elapsed time + test.Next(_L("Re-write half")); + ReWriteHalf(currentDrive); + + // 21. Format drive + test.Next(_L("Format drive")); + Format(currentDrive); + + doExit(); + + return; + } + +GLDEF_C TInt E32Main() + { + TInt r=TheFs.Connect(); + test_KErrNone(r); + + test.Title(); + test.Start(_L("Start Benchmarking ...")); + + TInt theDrive; + gDriveToTest='E'; + r=TheFs.CharToDrive(gDriveToTest,theDrive); + test_KErrNone(r); + + gSessionPath=_L("?:\\TRIMTEST\\"); + TChar driveLetter; + r=TheFs.DriveToChar(theDrive,driveLetter); + test_KErrNone(r); + gSessionPath[0]=(TText)driveLetter; + r=TheFs.SetSessionPath(gSessionPath); + test_KErrNone(r); + + r=TheFs.MkDirAll(gSessionPath); + if(r == KErrCorrupt) + { + test.Printf(_L("Attempting to create directory \'%S\' failed, KErrCorrupt\n"), &gSessionPath); + test.Printf(_L("This could be caused by a previous failing test, or a test media defect\n")); + test.Printf(_L("Formatting drive, retrying MkDirall\nShould subsequent tests fail with KErrCorrupt (%d) as well, replace test medium !\n"), + r); + Format(theDrive); + r=TheFs.MkDirAll(gSessionPath); + test_KErrNone(r); + } + else if (r == KErrNotReady) + { + TDriveInfo d; + r=TheFs.Drive(d, theDrive); + test_KErrNone(r); + if (d.iType == EMediaNotPresent) + test.Printf(_L("%c: Medium not present - cannot perform test.\n"), (TUint)driveLetter); + else + test.Printf(_L("medium found (type %d) but drive %c: not ready\nPrevious test may have hung; else, check hardware.\n"), (TInt)d.iType, (TUint)driveLetter); + } + test_Value(r, r == KErrNone || r == KErrAlreadyExists); + + + CallTestsL(); + + TheFs.Close(); + + return(KErrNone); + } diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/f32test/group/bld.inf --- a/kerneltest/f32test/group/bld.inf Mon Oct 11 17:54:41 2010 +0100 +++ b/kerneltest/f32test/group/bld.inf Mon Oct 11 19:11:06 2010 +0100 @@ -55,6 +55,9 @@ t_fsrvbm support t_fsysbm support + +t_trimbm manual + t_whet support #ifdef ARMCC t_whetvfp support diff -r 48e57fb1237e -r ddfd5aa0d58f kerneltest/f32test/group/t_trimbm.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/group/t_trimbm.mmp Mon Oct 11 19:11:06 2010 +0100 @@ -0,0 +1,35 @@ +// Copyright (c) 1997-2010 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: +// f32test/group/t_trimbm.mmp +// +// + +TARGET t_trimbm.exe +TARGETTYPE EXE +SOURCEPATH ../bench +SOURCE t_trimbm.cpp +SOURCEPATH ../server +SOURCEPATH ../fileutils/src +SOURCE t_chlffs.cpp + +LIBRARY euser.lib efsrv.lib hal.lib +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +USERINCLUDE ../server +USERINCLUDE ../fileutils/inc + +EPOCHEAPSIZE 0x1000 0x02000000 +CAPABILITY TCB DISKADMIN ALLFILES +VENDORID 0x70000001 + +SMPSAFE