os/kernelhwsrv/kernel/eka/drivers/medmmc/emmcptn.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // Partition Management for Embedded MMC devices
    15 // 
    16 //
    17 
    18 #include <drivers/emmcptn.h>
    19 #include "OstTraceDefinitions.h"
    20 #ifdef OST_TRACE_COMPILER_IN_USE
    21 #include "locmedia_ost.h"
    22 #ifdef __VC32__
    23 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
    24 #endif
    25 #include "emmcptnTraces.h"
    26 #endif
    27 
    28 
    29 const TInt KDiskSectorShift=9;
    30 
    31 class DLegacyEMMCPartitionInfo : public DEMMCPartitionInfo
    32 	{
    33 public:
    34 	 DLegacyEMMCPartitionInfo();
    35 	~DLegacyEMMCPartitionInfo();
    36 public:
    37 	virtual TInt Initialise(DMediaDriver* aDriver);
    38 	virtual TInt PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack);
    39 	virtual TInt PartitionCaps(TLocDrv& aDrive, TDes8& aInfo);
    40 	
    41 protected:
    42 	void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
    43 	
    44 private:
    45 	static void SessionEndCallBack(TAny* aSelf);
    46 		   void DoSessionEndCallBack();
    47 	virtual TInt DecodePartitionInfo();
    48 	
    49 protected:
    50 	DMediaDriver*   iDriver;
    51 	TPartitionInfo* iPartitionInfo;
    52 	TMMCCallBack	iSessionEndCallBack;
    53 	TMMCCallBack 	iCallBack;         // Where to report the PartitionInfo completion
    54 	DMMCSession*	iSession;
    55 	TMMCard*		iCard;
    56 	TUint8*			iIntBuf;
    57 	};
    58 
    59 DLegacyEMMCPartitionInfo::DLegacyEMMCPartitionInfo()
    60   : iSessionEndCallBack(DLegacyEMMCPartitionInfo::SessionEndCallBack, this)
    61 	{
    62 	OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_DLEGACYEMMCPARTITIONINFO_ENTRY );
    63 	}
    64 
    65 DLegacyEMMCPartitionInfo::~DLegacyEMMCPartitionInfo()
    66 	{
    67 	OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_DESTRUCTOR_ENTRY );
    68 	delete iSession;
    69 	OstTraceFunctionExit0( DLEGACYEMMCPARTITIONINFO_DESTRUCTOR_EXIT );
    70 	}
    71 
    72 TInt DLegacyEMMCPartitionInfo::Initialise(DMediaDriver* aDriver)
    73 	{
    74 	OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_INITIALISE_ENTRY, this );
    75 	iDriver = aDriver;
    76 
    77 	DMMCSocket* socket = ((DMMCSocket*)((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSocket);
    78 	if(socket == NULL)
    79 	    {
    80 		OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_INITIALISE_EXIT1, this, KErrNoMemory );
    81 		return KErrNoMemory;
    82 	    }
    83 
    84 	DMMCStack* stack = socket->Stack(0);
    85 	iCard = stack->CardP(((DPBusPrimaryMedia*)(iDriver->iPrimaryMedia))->iSlotNumber);
    86 	
    87 	iSession = stack->AllocSession(iSessionEndCallBack);
    88 	if (iSession == NULL)
    89 		return KErrNoMemory;
    90 
    91 	iSession->SetStack(stack);
    92 	iSession->SetCard(iCard);
    93 
    94 	// this gets used before any access
    95 	TInt bufLen, minorBufLen;
    96 	stack->BufferInfo(iIntBuf, bufLen, minorBufLen);
    97 
    98 	OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_INITIALISE_EXIT2, this, KErrNone );
    99 	return KErrNone;
   100 	}
   101 
   102 TInt DLegacyEMMCPartitionInfo::PartitionInfo(TPartitionInfo& anInfo, const TMMCCallBack& aCallBack)
   103 	{
   104 	OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_PARTITIONINFO_ENTRY, this );
   105 	iPartitionInfo = &anInfo;
   106 	iCallBack = aCallBack;
   107 	// If media driver is persistent (see EMediaDriverPersistent), 
   108 	// the card may have changed since last power down, so reset CID
   109 	iSession->SetCard(iCard);
   110 	
   111 	iSession->SetupCIMReadBlock(0, iIntBuf);
   112 
   113 	TInt r = iDriver->InCritical();
   114 	if (r == KErrNone)
   115 		r = iSession->Engage();
   116 
   117 	if(r != KErrNone)
   118 		iDriver->EndInCritical();
   119 	
   120 	OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_PARTITIONINFO_EXIT, this, r );
   121 	return r;
   122 	}
   123 
   124 TInt DLegacyEMMCPartitionInfo::PartitionCaps(TLocDrv& aDrive, TDes8& aInfo)
   125 	{
   126 	 OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_PARTITIONCAPS_ENTRY, this );
   127 	 TLocalDriveCapsV6Buf& Info = static_cast< TLocalDriveCapsV6Buf&> (aInfo);
   128 	
   129 	// is this query for the swap partition ?
   130 	if (aDrive.iPartitionType == KPartitionTypePagedData)
   131 		{
   132 		Info().iFileSystemId = KDriveFileNone;
   133 		Info().iDriveAtt|= KDriveAttHidden;
   134 		}
   135 
   136 	// is this query for the ROFS partition ?
   137 	if (aDrive.iPartitionType == KPartitionTypeRofs)
   138 		{
   139 		Info().iFileSystemId = KDriveFileSysROFS;
   140 		Info().iMediaAtt&= ~KMediaAttFormattable;
   141 		Info().iMediaAtt|= KMediaAttWriteProtected;
   142 		}
   143 	
   144 	// is this query for the ROM partition ?
   145 	if (aDrive.iPartitionType == KPartitionTypeROM)
   146 		{
   147 		Info().iFileSystemId = KDriveFileNone;
   148 		Info().iMediaAtt&= ~KMediaAttFormattable;
   149 		Info().iMediaAtt|= KMediaAttWriteProtected;
   150 		}
   151 	
   152 	OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_PARTITIONCAPS_EXIT, this, KErrNone );
   153 	return KErrNone;
   154 	}
   155 
   156 void DLegacyEMMCPartitionInfo::SessionEndCallBack(TAny* aSelf)
   157 	{
   158 	OstTraceFunctionEntry0( DLEGACYEMMCPARTITIONINFO_SESSIONENDCALLBACK_ENTRY );
   159 	DLegacyEMMCPartitionInfo& self = *static_cast<DLegacyEMMCPartitionInfo*>(aSelf);
   160 	self.DoSessionEndCallBack();
   161 	OstTraceFunctionExit0( DLEGACYEMMCPARTITIONINFO_SESSIONENDCALLBACK_EXIT );
   162 	}
   163 
   164 void DLegacyEMMCPartitionInfo::DoSessionEndCallBack()
   165 	{
   166 	OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_DOSESSIONENDCALLBACK_ENTRY, this );
   167 	iDriver->EndInCritical();
   168 
   169 	TInt r = iSession->EpocErrorCode();
   170 
   171 	if (r == KErrNone)
   172 		r = DecodePartitionInfo();
   173 
   174 	iDriver->PartitionInfoComplete(r == KErrNone ? r : KErrNotReady);
   175 	OstTraceFunctionExit1( DLEGACYEMMCPARTITIONINFO_DOSESSIONENDCALLBACK_EXIT, this );
   176 	}
   177 
   178 TInt DLegacyEMMCPartitionInfo::DecodePartitionInfo()
   179 //
   180 // decode partition info that was read into internal buffer 
   181 //
   182 	{
   183 	OstTraceFunctionEntry1( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ENTRY, this );
   184 	TUint partitionCount=iPartitionInfo->iPartitionCount=0;
   185 	TInt defaultPartitionNumber=-1;
   186 	TMBRPartitionEntry* pe;
   187 	const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3;
   188 	TInt i;
   189 
   190 	// Read of the first sector successful so check for a Master Boot Record
   191 	if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55)
   192 	    {
   193 		// If no valid signature give up now, No way to re-format an internal drive correctly
   194 		OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT1, this, KErrCorrupt );
   195 		return KErrCorrupt;
   196 	    }
   197 
   198 	__ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset);
   199 
   200 	memmove(&iIntBuf[0], &iIntBuf[2],
   201 		KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); 
   202 
   203 
   204 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
   205 		pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--)
   206 		{
   207 		if (pe->IsDefaultBootPartition())
   208 			{
   209 			SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors);
   210 			defaultPartitionNumber=i;
   211 			partitionCount++;
   212 			break;
   213 			}
   214 		}
   215 
   216 	// Now add any other partitions
   217 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
   218 		pe->iPartitionType != 0 && i < KMaxPartitionEntries; i++,pe--)
   219 		{
   220 		if (defaultPartitionNumber==i)
   221 			{
   222 			// Already sorted
   223 			}
   224 
   225 		// FAT partition ?
   226 		else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition() || pe->IsValidExFATPartition())
   227 			{
   228 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
   229 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector));
   230 			OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_FAT, "FAT partition found at sector #%x", pe->iFirstSector);
   231 			partitionCount++;
   232 			}
   233 
   234 		else if (pe->iPartitionType == KPartitionTypeROM)
   235 			{
   236 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
   237 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
   238 			partitionEntry.iPartitionType = pe->iPartitionType;
   239 			partitionCount++;				 
   240 
   241 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeROM found at sector #%u", pe->iFirstSector));
   242 			OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ROM, "KPartitionTypeROM found at sector #%x", pe->iFirstSector);
   243 			}
   244 
   245 		// ROFS partition ?
   246 		else if (pe->iPartitionType == KPartitionTypeRofs)
   247 			{
   248 			
   249 // Don't expose this for normal operation only boot?			
   250 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
   251 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
   252 			partitionEntry.iPartitionType = pe->iPartitionType;
   253 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypeRofs found at sector #%u", pe->iFirstSector));
   254 			OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_ROFS, "KPartitionTypeRofs found at sector #%x", pe->iFirstSector);
   255 			partitionCount++;
   256 			}
   257  
   258 		// Swap partition ?
   259 		else if (pe->iPartitionType == KPartitionTypePagedData)
   260 			{
   261 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: KPartitionTypePagedData found at sector #%u", pe->iFirstSector));
   262 			OstTrace1(TRACE_INTERNALS, DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_PAGED, "KPartitionTypeRofs found at sector #%x", pe->iFirstSector);
   263 			TPartitionEntry& partitionEntry = iPartitionInfo->iEntry[partitionCount];
   264 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
   265 			partitionEntry.iPartitionType = pe->iPartitionType;
   266 			partitionCount++;
   267 			}
   268 		}
   269 
   270 	// Check the validity of the partition address boundaries
   271 	// If there is any MBR errors
   272 	if(partitionCount > 0)
   273 		{
   274 		const TInt64 deviceSize = iCard->DeviceSize64();
   275 		TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1];
   276 		// Check that the card address space boundary is not exceeded by the last partition
   277 		if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize)
   278 			{
   279 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space"));
   280 			OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT2, this, KErrCorrupt );
   281 			return KErrCorrupt;
   282 			}
   283 		
   284 		// More than one partition. Go through all of them
   285 		if (partitionCount > 0)
   286 			{
   287 			for(i=partitionCount-1; i>0; i--)
   288 				{
   289 				const TPartitionEntry& curr = iPartitionInfo->iEntry[i];
   290 				TPartitionEntry& prev = iPartitionInfo->iEntry[i-1];
   291 				// Check if partitions overlap
   292 				if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen))
   293 					{
   294 					__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions"));
   295 					OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT3, this, KErrCorrupt );
   296 					return KErrCorrupt;
   297 					}
   298 				}
   299 			}
   300 		}
   301 
   302 	if (defaultPartitionNumber==(-1) && partitionCount==0)
   303 		{
   304 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("No Valid Partitions Found!"));
   305 		OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT4, this, KErrCorrupt );
   306 		return KErrCorrupt;
   307 		}
   308 
   309 	iPartitionInfo->iPartitionCount=partitionCount;
   310 	iPartitionInfo->iMediaSizeInBytes=iCard->DeviceSize64();
   311 
   312 #ifdef _DEBUG
   313 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)",partitionCount));
   314 	for (TUint x=0; x<partitionCount; x++)
   315 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition%d (B:%xH L:%xH)",x,I64LOW(iPartitionInfo->iEntry[x].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[x].iPartitionLen)));
   316 #endif
   317 
   318 	//Notify medmmc that partitioninfo is complete.
   319 	iCallBack.CallBack();
   320 	
   321 	OstTraceFunctionExitExt( DLEGACYEMMCPARTITIONINFO_DECODEPARTITIONINFO_EXIT5, this, KErrNone );
   322 	return KErrNone;
   323 	}
   324 
   325 
   326 void DLegacyEMMCPartitionInfo::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors)
   327 //
   328 // auxiliary static function to record partition information in TPartitionEntry object
   329 //
   330 	{
   331 	OstTraceFunctionEntryExt( DLEGACYEMMCPARTITIONINFO_SETPARTITIONENTRY_ENTRY, this );
   332 	aEntry->iPartitionBaseAddr=aFirstSector;
   333 	aEntry->iPartitionBaseAddr<<=KDiskSectorShift;
   334 	aEntry->iPartitionLen=aNumSectors;
   335 	aEntry->iPartitionLen<<=KDiskSectorShift;
   336 	aEntry->iPartitionType=KPartitionTypeFAT12;
   337 	OstTraceFunctionExit1( DLEGACYEMMCPARTITIONINFO_SETPARTITIONENTRY_EXIT, this );
   338 	}
   339 
   340 // End - DLegacyEMMCPartitionInfo
   341 
   342 
   343 EXPORT_C DEMMCPartitionInfo* CreateEmmcPartitionInfo()
   344 	{
   345 	OstTraceFunctionEntry0( _CREATEEMMCPARTITIONINFO_ENTRY );
   346 	return new DLegacyEMMCPartitionInfo;
   347 	}
   348 
   349 DECLARE_STANDARD_EXTENSION()
   350 	{
   351 	return KErrNone;
   352 	}