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("