kernel/eka/drivers/rpmb/rpmbdevice.cpp
changeset 287 ddfd5aa0d58f
equal deleted inserted replaced
286:48e57fb1237e 287:ddfd5aa0d58f
       
     1 // Copyright (c) 2010 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 // /os/kernelhwsrv/kernel/eka/drivers/rpmb/rpmbdevice.cpp
       
    15 // Kernel extension entry point for RPMB driver.
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalTechnology
       
    22 */
       
    23 
       
    24 #include "OstTraceDefinitions.h"
       
    25 #ifdef OST_TRACE_COMPILER_IN_USE
       
    26 #include "../../include/drivers/locmedia_ost.h"
       
    27 #ifdef __VC32__
       
    28 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
       
    29 #endif
       
    30 #include "rpmbdeviceTraces.h"
       
    31 #endif
       
    32 
       
    33 #include <kernel/kernel.h>
       
    34 #include <drivers/rpmbdevice.h>
       
    35 #include <drivers/sdcard.h>
       
    36 #include <drivers/sdio/sdio.h>
       
    37 #include <drivers/mmc.h>
       
    38 
       
    39 DRpmbDevice * DRpmbDevice::DRpmbDevicePtrs[KMaxPBusSockets*4] = {
       
    40 	NULL, NULL, NULL, NULL,
       
    41 	NULL, NULL, NULL, NULL,
       
    42 	NULL, NULL, NULL, NULL,
       
    43 	NULL, NULL, NULL, NULL};
       
    44 
       
    45 EXPORT_C DRpmbDevice::DRpmbDevice():
       
    46 	iSessionEndCallBack(DRpmbDevice::SessionEndCallBack, this),
       
    47 	iDeviceIndex(KIndexNotAssigned)
       
    48     {
       
    49 	}
       
    50 
       
    51 EXPORT_C DRpmbDevice::~DRpmbDevice()
       
    52     {
       
    53     Close();
       
    54 	}
       
    55 
       
    56 void DRpmbDevice::SessionEndCallBack(TAny* aSelf)
       
    57     {
       
    58     DRpmbDevice& self = *static_cast<DRpmbDevice*>(aSelf);
       
    59     self.DoSessionEndCallBack();
       
    60     }
       
    61 
       
    62 void DRpmbDevice::DoSessionEndCallBack()
       
    63     {   
       
    64     iSocket->EndInCritical();
       
    65     Kern::SemaphoreSignal(*iRequestSemaphore);
       
    66     }
       
    67 
       
    68 void DRpmbDevice::BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2)
       
    69 {
       
    70     DRpmbDevice* device = (DRpmbDevice*)aPtr;
       
    71     TPBusState busState = (TPBusState) (TInt) a1;
       
    72 	TInt busError = (TInt) a2;
       
    73 
       
    74     if(aReason == TPBusCallBack::EPBusStateChange 
       
    75 		&& busState == EPBusOn && busError == KErrNone)
       
    76 		{
       
    77 		Kern::SemaphoreSignal(*(device->iPowerUpSemaphore));
       
    78         }
       
    79 }
       
    80 
       
    81 TInt DRpmbDevice::PowerUpStack()
       
    82     {
       
    83     //
       
    84     // Power up the socket - This ensures that the socket is powered up 
       
    85     // and the functions are re-enumerated.
       
    86     //  
       
    87     iBusCallBack.iFunction = BusCallBack;
       
    88     iBusCallBack.iPtr=this;
       
    89     iBusCallBack.SetSocket(iSocket->iSocketNumber);
       
    90     iBusCallBack.Add();
       
    91 	NKern::ThreadEnterCS();
       
    92     TInt r = Kern::SemaphoreCreate(iPowerUpSemaphore,_L("RPMBPowerUpSem"), 0);
       
    93     if(r == KErrNone)
       
    94         {
       
    95 		TInt r = iSocket->PowerUp();
       
    96         if(r==KErrNone)
       
    97             {
       
    98             Kern::SemaphoreWait(*iPowerUpSemaphore);
       
    99             }
       
   100         }
       
   101 	NKern::ThreadLeaveCS();
       
   102     return r;
       
   103     }
       
   104 
       
   105 void DRpmbDevice::SetSynchronisationParms(TUint8 aDeviceIndex)
       
   106 	{
       
   107 	// Mark this instance as being associated with the requested index 
       
   108 	iDeviceIndex = aDeviceIndex;
       
   109 	// Mark the requested index as being associated with this instance
       
   110 	// Atomic operation ensures store is flushed from cache and committed 
       
   111 	// to global memory
       
   112 	__e32_atomic_store_ord_ptr(&(DRpmbDevicePtrs[iDeviceIndex]),this);
       
   113 	}
       
   114 
       
   115 
       
   116 void DRpmbDevice::ClearSynchronisationParms()
       
   117 	{
       
   118 	// Serialise access to global pointer array and it's local index
       
   119 	NKern::FMWait(&iSynchronisationParmsMutex);
       
   120 	if (iDeviceIndex < KMaxPBusSockets*4)
       
   121 		{
       
   122 		// Atomic operation for load from global memory and not from cache
       
   123 		DRpmbDevice * ptrTableEntry = 
       
   124 			(DRpmbDevice *)__e32_atomic_load_acq_ptr(&(DRpmbDevicePtrs[iDeviceIndex]));
       
   125 		// This instance of DRpmbDevice is associated with an index
       
   126 		// The associated index MUST be associated with this instance
       
   127 		__ASSERT_ALWAYS((ptrTableEntry == this), Kern::Fault(__FILE__, __LINE__));
       
   128 		// Disassociate index and instance
       
   129 		// Atomic operation ensures store is flushed from cache and committed 
       
   130 		// to global memory
       
   131 		__e32_atomic_store_ord_ptr(&(DRpmbDevicePtrs[iDeviceIndex]),NULL);
       
   132 		iDeviceIndex = KIndexNotAssigned;
       
   133 		}
       
   134 	// Serialise access to global pointer array and it's local index
       
   135 	NKern::FMSignal(&iSynchronisationParmsMutex);
       
   136 	}
       
   137 
       
   138 EXPORT_C TInt DRpmbDevice::Open(TUint aDeviceIndex)
       
   139     {
       
   140     //
       
   141     //eMMC4.4+ devices have RPMB partitions and each MMC device may be configured as having an RPMB 
       
   142 	//partition in the baseport
       
   143 	//This function creates an MMC stack session for device aDeviceIndex
       
   144 	//This is used to access the RPMB partition on that device
       
   145 	//Extensions that use this interface during system startup should be located AFTER the RPMB and MMC
       
   146 	//extesnions in the system ROM and should not call this interface synchronously from a system
       
   147 	//startup initialisation routine
       
   148 	//aDeviceIndex the index of the device supporting the RPMB partition
       
   149 	//Returns KerrNone if successful
       
   150 	//Returns KErrNotReady if the baseport configuration hasn't been read yet
       
   151     //Returns KErrNotSupported if the baseport configuration does not have a valid RPMB partition 
       
   152 	//or RPMB is not supported by the media device
       
   153 	//Otherwise retruns a systemwide error code
       
   154     //
       
   155     OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_1, "RPMB: >DrpmbDevice::Open");
       
   156     __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::Open"));
       
   157 	
       
   158 	TRpmbDeviceParms params;
       
   159 	params.iCardNumber = 0;
       
   160 	params.iSocketPtr = NULL;	
       
   161     MRpmbInfo* rpmbInterface = NULL;
       
   162 	
       
   163 	TInt r = MMCGetExtInterface(KInterfaceRpmb, (MMCMExtInterface*&) rpmbInterface);
       
   164 	// MMCGetExtInterface currently returns KErrNotReady with rpmbInterface == NULL if the RPMB parameters 
       
   165 	// haven't yet been populated
       
   166 	// proveided any calling extension is located AFTER the RPMB and MMC extesnions in the system ROM and 
       
   167 	// does not call this interface synchronously from a system initialisation routine the following 
       
   168 	// shouldn't be asserted 
       
   169 	OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_2, "RPMB: DrpmbDevice Get Interface err = %d", r);
       
   170 	__KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice Get Interface err = %d", r));
       
   171 	__ASSERT_ALWAYS(r == KErrNone, Kern::Fault(__FILE__, __LINE__));
       
   172 		
       
   173 	if (rpmbInterface == NULL)
       
   174 		{
       
   175 		// unexpected error since MMCGetExtInterface didn't return an error
       
   176 	    OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_3, "RPMB: DrpmbDevice Null rpmbInterface");
       
   177 	    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice Null rpmbInterface"));
       
   178 		return KErrGeneral;
       
   179 		}
       
   180 		
       
   181 	// Interface currently supports a single device, device index = 0   
       
   182 	r = rpmbInterface->RpmbInfo(aDeviceIndex, params);
       
   183     if(r != KErrNone)
       
   184         {
       
   185 		// requested index non zero or baseport not configured with RPMB capable MMC device
       
   186         OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_4, "RPMB: DrpmbDevice requested index non zero or baseport not configured, err = %d", r);
       
   187         __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice requested index non zero or baseport not configured, err = %d", r));
       
   188 		return r;
       
   189 		}
       
   190    
       
   191     iSocket = params.iSocketPtr;
       
   192 	// iSocket cannot be NULL 
       
   193 	// TMMCardControllerInterface::RegisterMediaDevices ensures that the assigned value is not NULL
       
   194 	__ASSERT_ALWAYS((iSocket!=NULL), Kern::Fault(__FILE__, __LINE__));
       
   195     
       
   196 	// Serialise access to global pointer array and it's local index
       
   197 	NKern::FMWait(&iSynchronisationParmsMutex);
       
   198 
       
   199 	if (iDeviceIndex != KIndexNotAssigned)
       
   200 		{
       
   201 		// This instance of DRpmbDevice is already open
       
   202 		if (iDeviceIndex == aDeviceIndex)
       
   203 			{
       
   204 			// Serialise access to global pointer array and it's local index
       
   205 			NKern::FMSignal(&iSynchronisationParmsMutex);
       
   206 			// Already open with requested index
       
   207 		    OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_5, "RPMB: DrpmbDevice already open with requested index");
       
   208 		    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice already open with requested index"));
       
   209 			return KErrNone;
       
   210 			}
       
   211 		else
       
   212 			{
       
   213 			// Serialise access to global pointer array and it's local index
       
   214 			NKern::FMSignal(&iSynchronisationParmsMutex);
       
   215 			// Already open with other index
       
   216 	        OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_6, "RPMB: DrpmbDevice already open with other index");
       
   217 	        __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice already open with other index"));
       
   218 			return KErrInUse;
       
   219 			}
       
   220 		}
       
   221 	else
       
   222 		{
       
   223 		// This instance of DRpmbDevice is not open
       
   224 
       
   225 		// Atomic operation for load from global memory and not from cache
       
   226 		DRpmbDevice * ptrTableEntry = 
       
   227 			(DRpmbDevice *)__e32_atomic_load_acq_ptr(&(DRpmbDevicePtrs[aDeviceIndex]));
       
   228 
       
   229 		if (ptrTableEntry == NULL)
       
   230 			{
       
   231 			SetSynchronisationParms((TUint8)(aDeviceIndex));
       
   232 			}
       
   233 		else
       
   234 			{
       
   235 			// Requested index cannot be associated with this instance of DRpmbdevice  
       
   236 			__ASSERT_ALWAYS(ptrTableEntry != this, Kern::Fault(__FILE__, __LINE__));
       
   237 			// Serialise access to global pointer array and it's local index
       
   238 			NKern::FMSignal(&iSynchronisationParmsMutex);
       
   239 			// Requested index already associated with a different instance of DRpmbDevice
       
   240 	        OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_7, "RPMB: DrpmbDevice requested index already associated with a different instance of DrpmbDevice");
       
   241 	        __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice requested index already associated with a different instance of DrpmbDevice"));
       
   242 			return KErrInUse;
       
   243 			}
       
   244 		}
       
   245 	NKern::FMSignal(&iSynchronisationParmsMutex);
       
   246 
       
   247 	r = PowerUpStack();
       
   248     if (r != KErrNone && r != KErrCompletion)
       
   249         {
       
   250         // Stack wasn't already powered up and failed to power up
       
   251 		ClearSynchronisationParms();
       
   252 	    OstTrace1(TRACE_FLOW, DRPMBDEVICE_OPEN_8, "RPMB: DrpmbDevice wasn't already powered up and failed with err = %d", r);
       
   253 	    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DrpmbDevice wasn't already powered up and failed with err = %d", r));
       
   254 		return r;
       
   255         }
       
   256     
       
   257     DMMCStack* stack = iSocket->Stack(KBusNumber);
       
   258     if(stack == NULL)
       
   259         {
       
   260 		// KBusNumber = 0 so iSocket->Stack() returns iSocket->iStack 
       
   261 		// Expect this to have been pre-assigned
       
   262 		// Expect a socket to be bound to a stack
       
   263         ClearSynchronisationParms();
       
   264         OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_9, "RPMB: stack is NULL");
       
   265         __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: stack is NULL"));
       
   266         return KErrNoMemory;
       
   267         }
       
   268     
       
   269     iCard = stack->CardP(params.iCardNumber);
       
   270     if(iCard == NULL) 
       
   271         {
       
   272 		// stack->CardP() returns stack->iCardArray->CardP(params.iCardNumber)
       
   273 		// Expect this to have been pre-assigned
       
   274 		// Expect card array to point to a card
       
   275         ClearSynchronisationParms();
       
   276         OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_10, "RPMB: card pointer is NULL");
       
   277         __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: card pointer is NULL"));
       
   278         return KErrNoMemory;
       
   279         }
       
   280     
       
   281 	NKern::ThreadEnterCS(); 
       
   282     iSession = stack->AllocSession(iSessionEndCallBack);
       
   283 	NKern::ThreadLeaveCS(); 
       
   284     if (iSession == NULL)
       
   285         {
       
   286 		// DMMCStack::AllocSession() failed to create a new instance off DMMCSession
       
   287         OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_11, "RPMB: failed to create a new instance of DMMCSession");
       
   288         __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: failed to create a new instance of DMMCSession"));
       
   289         return KErrNoMemory; 
       
   290         }
       
   291 
       
   292     iSession->SetStack(stack);
       
   293     iSession->SetCard(iCard);
       
   294     
       
   295     TInt bufLen, minorBufLen;
       
   296     stack->BufferInfo(iIntBuf, bufLen, minorBufLen);
       
   297 	// mmc media driver reserved the first KRpmbOneFramePacketLength bytes of the 
       
   298 	// PSL buffer to be used for RPMB requests / responses
       
   299 	iIntBuf += minorBufLen;
       
   300     
       
   301     if(iCard->ExtendedCSD().ExtendedCSDRev() < 5 || iCard->ExtendedCSD().RpmbSize() == 0)
       
   302         {
       
   303 		// RPMB is not supported on selected hardware
       
   304         ClearSynchronisationParms();
       
   305         OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_12, "RPMB: feature is not supported on selected hardware");
       
   306         __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: feature is not supported on selected hardware"));
       
   307         return KErrNotSupported;
       
   308         }
       
   309     OstTrace0(TRACE_FLOW, DRPMBDEVICE_OPEN_13, "RPMB: <DrpmbDevice::Open");
       
   310     __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: <DrpmbDevice::Open"));
       
   311     return KErrNone;
       
   312     }
       
   313 
       
   314 EXPORT_C void DRpmbDevice::Close()
       
   315     {
       
   316 	//
       
   317     //Closes an interaction with an RPMB configured device 
       
   318     //
       
   319     OstTrace0(TRACE_FLOW, DRPMBDEVICE_CLOSE_1, "RPMB: >DrpmbDevice::Close");
       
   320     __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::Close"));
       
   321  	
       
   322 	ClearSynchronisationParms();
       
   323     
       
   324 	iBusCallBack.Remove();
       
   325 
       
   326 	NKern::ThreadEnterCS();
       
   327 
       
   328     if(iPowerUpSemaphore)
       
   329 		{
       
   330         iPowerUpSemaphore->Close(NULL);
       
   331 		iPowerUpSemaphore = NULL;
       
   332 		}
       
   333 
       
   334 	if (iSession)
       
   335 		{
       
   336 		delete iSession;
       
   337 		iSession = NULL;
       
   338 		}
       
   339 
       
   340 	if(iRequestSemaphore)
       
   341 		{
       
   342         iRequestSemaphore->Close(NULL);
       
   343 		iRequestSemaphore = NULL;
       
   344 		}
       
   345    
       
   346 	NKern::ThreadLeaveCS();
       
   347 	OstTrace0(TRACE_FLOW, DRPMBDEVICE_CLOSE_2, "RPMB: <DrpmbDevice::Close");
       
   348 	__KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: <DrpmbDevice::Close"));
       
   349     }
       
   350 
       
   351 EXPORT_C TInt DRpmbDevice::SendAccessRequest(TDes8& aRpmbRequest, TDes8& aRpmbResponse)
       
   352     {
       
   353     //
       
   354     //sends a request to be handled by the RPMB partition
       
   355     //aRpmbRequest - the physically contiguous region of memory containg the request to be handled
       
   356     //aRpmbResponse - the physically contiguous region memory to where the response from the hardware will be written
       
   357 	//returns KErrNone if successful
       
   358 	//returns system wide epoc error code if set on call back from stack
       
   359 	//returns KErrArgument for invalid descriptor argument length
       
   360 	//returns KErrNotReady if not opened
       
   361 	//retruns KErrNotready if MMC stack is processing a posponed power down or a postponed media change event
       
   362 	//otherwise returns system wide error code 
       
   363 	//
       
   364     
       
   365     OstTrace0(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_1, "RPMB: >DrpmbDevice::SendAccessRequest");
       
   366     __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: >DrpmbDevice::SendAccessRequest"));
       
   367 
       
   368 	if ((aRpmbRequest.Length() != KRpmbOneFramePacketLength) || (aRpmbResponse.Length() != KRpmbOneFramePacketLength))
       
   369 		{
       
   370 		// insist on single frame access as mutiple read and multiple write (reliable write) notb yet supported
       
   371 		return KErrArgument;
       
   372 		}
       
   373 
       
   374 	if (iSession == NULL)
       
   375         {
       
   376 		// DRpmbDevice::Open not called at all
       
   377 		// or not called after DRpmbDevice::Close
       
   378 	    OstTrace0(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_2, "RPMB: DMMCSession is NULL");
       
   379 	    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: DMMCSession is NULL"));
       
   380         return KErrNotReady;
       
   381         }
       
   382 
       
   383 	if (iRequestSemaphore == NULL)
       
   384 		{
       
   385 		// iRequestSemaphore zero filled prior to contruction
       
   386 		// create semaphore for waiting on stack
       
   387 		NKern::ThreadEnterCS();
       
   388 		TInt r = Kern::SemaphoreCreate(iRequestSemaphore,_L("RPMBRequestSemaphore"), 0);
       
   389 		NKern::ThreadLeaveCS();
       
   390 		if (r != KErrNone)
       
   391 			{
       
   392 			// failed to create semaphore 
       
   393 		    OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_3, "RPMB: failed to create semaphore err = %d", r);
       
   394 		    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: failed to create semaphore err = %d", r));
       
   395 			return r;
       
   396 			}
       
   397 		}
       
   398 
       
   399     memcpy(iIntBuf, aRpmbRequest.Ptr(), KRpmbOneFramePacketLength);
       
   400      
       
   401     TInt r = iSocket->InCritical();
       
   402 	// may be KErrNotready if MMC stack is processing a posponed power down event or a postponed media change event
       
   403 	if (r == KErrNone)
       
   404        {
       
   405     iSession->SetPartition(TExtendedCSD::ESelectRPMB);            //Set RPMB Partition
       
   406     iSession->ResetCommandStack();
       
   407     iSession->FillCommandArgs(KDeviceAddress, KRpmbOneFramePacketLength, iIntBuf, KRpmbOneFramePacketLength);
       
   408     iSession->iSessionID = ECIMRpmbAccess;
       
   409 
       
   410         r = iSession->Engage();
       
   411         if(r == KErrNone)
       
   412             {
       
   413 			Kern::SemaphoreWait(*iRequestSemaphore);
       
   414 			memcpy((TUint8 *)aRpmbResponse.Ptr(), iIntBuf, KRpmbOneFramePacketLength);
       
   415 		    OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_4, "RPMB: request complete with %d", iSession->EpocErrorCode());
       
   416 		    __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: request complete with %d", iSession->EpocErrorCode()));
       
   417 			return iSession->EpocErrorCode();  
       
   418             }
       
   419         }
       
   420  
       
   421     iSocket->EndInCritical();
       
   422     
       
   423     OstTrace1(TRACE_FLOW, DRPMBDEVICE_SENDACCESSREQUEST_5, "RPMB: <DrpmbDevice::SendAccessRequest complete %d", r);
       
   424     __KTRACE_OPT(KPBUS1, Kern::Printf("RPMB: <DrpmbDevice::SendAccessRequest complete %d", r));
       
   425     
       
   426     return r;
       
   427     }
       
   428 
       
   429 DECLARE_STANDARD_EXTENSION()
       
   430     {
       
   431     __KTRACE_OPT(KBOOT,Kern::Printf("RPMBEXT.DLL DECLARE_STANDARD_EXTENSION entry point"));      
       
   432 	return KErrNone;
       
   433     }
       
   434