--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoldd.cpp Thu Sep 10 14:01:51 2009 +0300
@@ -0,0 +1,1036 @@
+/*
+* Copyright (c) 2007-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:
+*
+*/
+
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+#include <kernel/kern_priv.h>
+#include <cryptodriver.h>
+#include "cryptoldd.h"
+#include <keyhandle.h>
+#include "kmskext.h"
+
+DECLARE_STANDARD_LDD()
+ {
+ return new DCryptoLddChannelFactory;
+ }
+
+//#define HW_PERF_CHECK
+
+_LIT(KCryptoPanicCategory,"DCrypto");
+
+/**
+ Constructor
+*/
+DCryptoLddChannelFactory::DCryptoLddChannelFactory()
+ {
+ TRACE_FUNCTION("DCryptoLddChannelFactory");
+ // Set version number for this device
+ iVersion=RCryptoDriver::VersionRequired();
+ // Auto load a PDD
+ iParseMask=KDeviceAllowPhysicalDevice;
+ }
+
+/**
+ Destructor
+*/
+DCryptoLddChannelFactory::~DCryptoLddChannelFactory()
+ {
+ TRACE_FUNCTION("~DCryptoLddChannelFactory");
+ TraceFunction::DumpCounts();
+ }
+
+
+/**
+ Second stage constructor for DCryptoLddChannelFactory.
+ This must at least set a name for the driver object.
+
+ @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannelFactory::Install()
+ {
+ TRACE_FUNCTION("Install");
+ return SetName(&RCryptoDriver::Name());
+ }
+
+/**
+ Return the drivers capabilities.
+ Called in the response to an RDevice::GetCaps() request.
+
+ @param aDes Descriptor into which capabilities information is to be written.
+*/
+void DCryptoLddChannelFactory::GetCaps(TDes8& aDes) const
+ {
+ TRACE_FUNCTION("GetCaps");
+ // Create a capabilities object
+ RCryptoDriver::TCaps caps;
+ caps.iVersion = iVersion;
+
+ // We do not have a handle to the PDD, and it might not have been
+ // loaded yet, so we can't ask it for its capabilities...
+
+ // Write it back to user memory
+ Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
+ return;
+ }
+
+/**
+ Called by the kernel's device driver framework to create a Logical Channel.
+ This is called in the context of the user thread (client) which requested the creation
+ of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate).
+ The thread is in a critical section.
+
+ @param aChannel Set to point to the created Logical Channel
+
+ @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannelFactory::Create(DLogicalChannelBase*& aChannel)
+ {
+ TRACE_FUNCTION("Create");
+ aChannel=new DCryptoLddChannel;
+ if(!aChannel)
+ return KErrNoMemory;
+
+ return KErrNone;
+ }
+
+
+//
+// Logical Channel
+//
+
+/**
+ Constructor
+*/
+DCryptoLddChannel::DCryptoLddChannel()
+ : iLddChanRandom(*this),
+ iLddChanAes(*this)
+ {
+ TRACE_FUNCTION("DCryptoLddChannel");
+ // Get pointer to client thread's DThread object
+ iClient=&Kern::CurrentThread();
+
+ // Open a reference on client thread so its control block can't disappear until
+ // this driver has finished with it.
+ // Note, this call to Open() can't fail since it is the thread we are currently running in.
+ iClient->Open();
+ }
+
+
+/**
+ Destructor
+*/
+DCryptoLddChannel::~DCryptoLddChannel()
+ {
+ TRACE_FUNCTION("~DCryptoLddChannel");
+ // Cancel all processing that we may be doing
+ DoCancel(RCryptoDriver::EAllRequests);
+ // Close our reference on the client thread
+ Kern::SafeClose((DObject*&)iClient,NULL);
+ }
+
+
+/**
+ Second stage constructor called by the kernel's device driver framework.
+ This is called in the context of the user thread (client) which requested the creation
+ of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate())
+ The thread is in a critical section.
+
+ @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate()
+ @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate()
+ @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate()
+
+ @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+ {
+ TRACE_FUNCTION("DoCreate");
+ // Check Platform Security capabilities of client thread (if required).
+ //
+ // Here we handle the simple case where:
+ // 1. The device driver can only have one client thread
+ // 2. The security policy is the binary all-or-nothing policy.
+ // E.g. "If you have the right capability you can do anything with the driver
+ // and if you don't have the capability you can't do anything"
+ //
+ // If only some functionality of the driver is restricted, then the security check should
+ // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
+ // shouldn't be used because the 'current thread' isn't the client.
+ //
+ // In this example we do a check here for ECapability_None (which always passes)...
+ if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
+ return KErrPermissionDenied;
+
+ // Check version
+ if (!Kern::QueryVersionSupported(RCryptoDriver::VersionRequired(),aVer))
+ return KErrNotSupported;
+
+ // Give PDD a pointer to this channel
+ PddChan()->iCryptoLddChannel = this;
+
+ // Setup LDD for receiving client messages.
+ SetDfcQ(PddChan()->DfcQue());
+ iMsgQ.Receive();
+
+ // Done
+ return KErrNone;
+ }
+
+
+/**
+ Called when a user thread requests a handle to this channel.
+*/
+TInt DCryptoLddChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
+ {
+ TRACE_FUNCTION("RequestUserHandle");
+ // Make sure that only our client can get a handle
+ if (aType!=EOwnerThread || aThread!=iClient)
+ return KErrAccessDenied;
+ return KErrNone;
+ }
+
+
+/**
+ Process a message for this logical channel.
+ This function is called in the context of a DFC thread.
+
+ @param aMessage The message to process.
+ The iValue member of this distinguishes the message type:
+ iValue==ECloseMsg, channel close message
+ iValue==KMaxTInt, a 'DoCancel' message
+ iValue>=0, a 'DoControl' message with function number equal to iValue
+ iValue<0, a 'DoRequest' message with function number equal to ~iValue
+*/
+void DCryptoLddChannel::HandleMsg(TMessageBase* aMsg)
+ {
+ TRACE_FUNCTION("HandleMsg");
+ TThreadMessage& m=*(TThreadMessage*)aMsg;
+
+ // Get message type
+ TInt id=m.iValue;
+
+ // Decode the message type and dispatch it to the relevent handler function...
+
+ if (id==(TInt)ECloseMsg)
+ {
+ // Channel Close
+ DoCancel(RCryptoDriver::EAllRequests);
+ m.Complete(KErrNone, EFalse);
+ return;
+ }
+
+ if (id==KMaxTInt)
+ {
+ // DoCancel
+ DoCancel(m.Int0());
+ m.Complete(KErrNone,ETrue);
+ return;
+ }
+
+ if (id<0)
+ {
+ // DoRequest
+ TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+ TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
+ if (r!=KErrNone)
+ Kern::RequestComplete(iClient,pS,r);
+ m.Complete(KErrNone,ETrue);
+ }
+ else
+ {
+ // DoControl
+ TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+ m.Complete(r,ETrue);
+ }
+ }
+
+/**
+ Process synchronous 'control' requests
+*/
+TInt DCryptoLddChannel::DoControl(TInt aFunction, TAny* a1, TAny *)
+ {
+ TRACE_FUNCTION("DoControl");
+ TInt r;
+
+ switch (aFunction)
+ {
+ case RCryptoDriver::EGetHwVersions:
+ r = GetHwVersions((TDes8*)a1);
+ break;
+
+ case RCryptoDriver::EGetConfig:
+ r = GetConfig((TDes8*)a1);
+ break;
+
+ case RCryptoDriver::ESetConfig:
+ r = SetConfig((const TDesC8*)a1);
+ break;
+
+ case RCryptoDriver::EAesSetConfig:
+ r = iLddChanAes.SetAesConfig((const TDesC8*)a1);
+ break;
+
+ default:
+ r=KErrNotSupported;
+ break;
+ }
+
+ return r;
+ }
+
+
+/**
+ Process asynchronous requests
+*/
+TInt DCryptoLddChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+ {
+ TRACE_FUNCTION("DoRequest");
+ (void)a2; // a2 not used in this example
+
+ TInt r;
+
+ switch(aReqNo)
+ {
+ case RCryptoDriver::ERandom:
+ r=iLddChanRandom.Random(aStatus,(TDes8*)a1);
+ break;
+
+ case RCryptoDriver::EAesWrite:
+ r=iLddChanAes.AesWrite(aStatus,(TDesC8*)a1);
+ break;
+
+ case RCryptoDriver::EAesRead:
+ r=iLddChanAes.AesRead(aStatus,(TDes8*)a1, (TUint32)a2);
+ break;
+
+ default:
+ r=KErrNotSupported;
+ break;
+ }
+
+ return r;
+ }
+
+
+/**
+ Process cancelling of asynchronous requests
+*/
+void DCryptoLddChannel::DoCancel(TUint aMask)
+ {
+ TRACE_FUNCTION("DoCancel");
+ if(aMask&(1<<RCryptoDriver::ERandom))
+ {
+ iLddChanRandom.RandomCancel();
+ }
+
+ if(aMask&(1<<RCryptoDriver::EAesRead))
+ {
+ iLddChanAes.CancelRead();
+ }
+
+ if(aMask&(1<<RCryptoDriver::EAesWrite))
+ {
+ iLddChanAes.CancelWrite();
+ }
+
+ }
+
+
+/**
+ Process a GetHwVersions control message. This writes the crypto h/w versions to a
+ RCryptoDriver::THwVersionsBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::GetHwVersions(TDes8* aHwVersionsBuf) const
+ {
+ TRACE_FUNCTION("GetHwVersions");
+ // Create a structure giving the current configuration
+ RCryptoDriver::THwVersions versions;
+
+ PddChan()->GetHwVersions(versions);
+
+ // Write the config to the client
+ TPtrC8 ptr((const TUint8*)&versions,sizeof(versions));
+ return Kern::ThreadDesWrite(iClient,aHwVersionsBuf,ptr,0,KTruncateToMaxLength,NULL);
+ }
+
+//
+// Functions for processing configuration control messages
+//
+
+/**
+ Process a GetConfig control message. This writes the current driver configuration to a
+ RCryptoDriver::TConfigBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::GetConfig(TDes8* aConfigBuf) const
+ {
+ TRACE_FUNCTION("GetConfig");
+ // Create a structure giving the current configuration
+ RCryptoDriver::TConfig config;
+ CurrentConfig(config);
+
+ // Write the config to the client
+ TPtrC8 ptr((const TUint8*)&config,sizeof(config));
+ return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
+ }
+
+/**
+ Process a SetConfig control message. This sets the driver configuration using a
+ RCryptoDriver::TConfigBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::SetConfig(const TDesC8* aConfigBuf)
+ {
+ TRACE_FUNCTION("SetConfig");
+ // Don't allow configuration changes whilst we're busy
+ // if(iSendDataStatus || iReceiveDataStatus)
+ // return KErrInUse;
+
+ // Create a config structure.
+ RCryptoDriver::TConfig config;
+ CurrentConfig(config);
+
+ // Note: We have filled config with the current settings, this is to allow
+ // backwards compatibility when a client gives us an old (and shorter) version
+ // of the config structure.
+
+ // Read the config structure from client
+ TPtr8 ptr((TUint8*)&config,sizeof(config));
+ TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
+ if(r!=KErrNone)
+ return r;
+
+ // Use config data to setup the driver. Checking that parameters which aren't settable
+ // either contain the correct values or are zero (meaning 'default')
+ r=PddChan()->SetFakeDriverSetting(config.iFakeDriverSetting);
+ if(r!=KErrNone)
+ return r;
+
+ return r;
+ }
+
+
+/**
+ Fill a TConfig with the driver's current configuration.
+*/
+void DCryptoLddChannel::CurrentConfig(RCryptoDriver::TConfig& aConfig) const
+ {
+ TRACE_FUNCTION("TConfig");
+ aConfig.iFakeDriverSetting = PddChan()->FakeDriverSetting();
+ }
+
+
+
+//
+// Functions for processing 'Random'
+//
+
+DLddChanRandom::DLddChanRandom(DCryptoLddChannel &aParent)
+ : iParent(aParent)
+ {
+ TRACE_FUNCTION("DLddChanRandom");
+ }
+
+
+/**
+ Start processing a Random request.
+*/
+TInt DLddChanRandom::Random(TRequestStatus* aStatus,TDes8* aPtr)
+ {
+ TRACE_FUNCTION("Random");
+ // Check that a 'Random' isn't already in progress
+ if(iRandomStatus)
+ {
+ Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+ return KErrInUse;
+ }
+
+ // We only support a single outstanding Random request in this LDD
+ // channel, but the PDD supports multiple requests.
+
+ // Save the client request status and descriptor
+ iRandomStatus = aStatus;
+ iRandomDescriptor = aPtr;
+
+ // Retrieve user request length (ie. CURRENT length of user descriptor) into iRequestLength
+ TInt tmp;
+ TUint8 *tmp2;
+ TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iRandomDescriptor, iRequestLength, tmp, tmp2, ETrue);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+
+ // Set current offset into user descriptor
+ iCurrentIndex = 0;
+
+ iJob = iParent.PddChan()->GetJobRandom();
+
+ // Setup PDD job
+ iJob->SetDetails(&iParent.LddFactory()->iJSRandom, this, iRequestLength);
+ // Register it, which will also (maybe later) call DoSlice to run it
+ iParent.LddFactory()->iJSRandom.ScheduleJob(iJob);
+
+ return KErrNone;
+ }
+
+
+
+TInt DLddChanRandom::DataRequired()
+ {
+ TRACE_FUNCTION("DataRequired");
+ return KErrNone; // We never pass data to the h/w...
+ }
+
+TInt DLddChanRandom::DataAvailable()
+ {
+ TRACE_FUNCTION("DataAvailable");
+ // Kern::Printf("DLddChanRandom::DataAvailable()");
+ TInt r = KErrNone;
+
+ TUint8 *buf;
+ TUint32 bufLen;
+ TBool check = ETrue;
+ while(check)
+ {
+ iJob->GetFromPddBuffer(buf, bufLen, check);
+ if(bufLen)
+ {
+ TInt required = iRequestLength - iCurrentIndex;
+ TInt toTransfer = bufLen;
+ if(toTransfer > required)
+ {
+ toTransfer = required;
+ }
+ // Copy the current buffer to user land
+ TPtr8 des(buf, toTransfer, toTransfer);
+ r=Kern::ThreadDesWrite(iParent.iClient, iRandomDescriptor, des, iCurrentIndex);
+ if(r != KErrNone)
+ {
+ break;
+ }
+
+ // Update our index into the user descriptor
+ iCurrentIndex += toTransfer;
+
+ // Update h/w with number of bytes actually read
+ iJob->BytesReadFromPdd(toTransfer);
+
+ if(toTransfer != bufLen)
+ {
+ // We did not read all the available data, so do not
+ // re-query h/w
+ check = EFalse;
+ }
+ }
+ };
+
+ return r;
+ }
+
+void DLddChanRandom::JobComplete(TInt aResult)
+ {
+ TRACE_FUNCTION("JobComplete");
+ if(iRandomStatus)
+ {
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iRandomDescriptor = NULL;
+ // Complete client's request
+ Kern::RequestComplete(iParent.iClient,iRandomStatus, aResult);
+ }
+ }
+
+
+/**
+ Cancel a Random request.
+*/
+void DLddChanRandom::RandomCancel()
+ {
+ TRACE_FUNCTION("RandomCancel");
+ if(iRandomStatus)
+ {
+ // Tell PDD to stop processing the request
+ iParent.LddFactory()->iJSRandom.DeScheduleJob(iParent.PddChan()->GetJobRandom());
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iRandomDescriptor = NULL;
+ // Complete clients request
+ Kern::RequestComplete(iParent.iClient,iRandomStatus,KErrCancel);
+ }
+ }
+
+//
+// Functions for processing 'Aes'
+//
+
+DLddChanAes::DLddChanAes(DCryptoLddChannel &aParent)
+ : iParent(aParent)
+ {
+ TRACE_FUNCTION("DLddChanAes");
+ }
+
+
+TInt DLddChanAes::SetAesConfig(const TDesC8* aConfigBuf)
+ {
+ TRACE_FUNCTION("SetAesConfig");
+ // Note we need to validate arguments kernel side otherwise
+ // someone could easily crash the kernel...
+
+ RCryptoDriver::TAesConfig config;
+ // Read the config structure from client
+ TPtr8 ptr((TUint8*)&config,sizeof(config));
+ TInt r=Kern::ThreadDesRead(iParent.iClient,aConfigBuf,ptr,0);
+ if(r!=KErrNone)
+ {
+ return r;
+ }
+
+ // Kern::Printf("iEncrypt = 0x%x",config.iEncrypt);
+ // Kern::Printf("iMode = 0x%x",config.iMode);
+ // Kern::Printf("iKey = 0x%x",config.iKey);
+ // Kern::Printf("iIV = 0x%x",config.iIV);
+
+
+ // Remember direction
+ iEncrypt = config.iEncrypt;
+
+ // Remember mode
+ iMode = config.iMode;
+
+ //
+ // Handle key
+ //
+
+ // Retrieve user key length into iKeyLengthBytes
+ TInt tmp;
+ TUint8 *tmp2;
+ r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iKey, iKeyLengthBytes, tmp, tmp2, EFalse);
+ if(r!=KErrNone)
+ {
+ return r;
+ }
+
+ HBuf8 *embeddedKeyData = 0;
+ if(iKeyLengthBytes == 4)
+ {
+ // Some form of embedded key so value is a 32 bit handle
+ TPckgBuf<TKeyHandle> keyHandlePkg;
+
+ r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, keyHandlePkg, 0);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+
+ TKeyHandle &keyHandle = keyHandlePkg();
+
+ r = HwKeyStore::ExtractKey(iParent.iClient->iOwningProcess, keyHandle, 0 /*operation*/, embeddedKeyData);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+
+ // Update key length
+ iKeyLengthBytes = embeddedKeyData->Length();
+ }
+
+ switch(iKeyLengthBytes)
+ {
+ case 16: // 128 bits
+ break;
+ case 24: // 192 bits
+ break;
+ case 32: // 256 bits
+ break;
+ default: // Illegal length
+ if(embeddedKeyData) delete embeddedKeyData;
+ return KErrArgument;
+ }
+
+ // Make sure iJob is valid before we use it
+ iJob = iParent.PddChan()->GetJobAes();
+
+ TUint8 *keyBuffer = iJob->GetKeyBuffer();
+ TPtr8 des(keyBuffer, iKeyLengthBytes);
+
+ if(embeddedKeyData)
+ {
+ // Copy embedded key to PDD
+ des = *embeddedKeyData;
+ delete embeddedKeyData;
+ embeddedKeyData = 0;
+ }
+ else
+ {
+ // Retrieve key from user
+ r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, des, 0);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+ }
+
+
+ //
+ // Handle IV
+ //
+
+ // Retrieve IV length
+ TInt ivLength;
+ r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iIV, ivLength, tmp, tmp2, EFalse);
+ // Kern::Printf("DLddChanAes::SetAesConfig r=%d 5",r);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+
+ if((ivLength != 0) && (ivLength != 16))
+ {
+ return KErrArgument;
+ }
+
+ if(ivLength == 16)
+ {
+ TUint8 *ivBuffer = iJob->GetIVBuffer();
+ TPtr8 des(ivBuffer, 16);
+ r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iIV, des, 0);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+ }
+
+
+ // Set details
+ r = iJob->SetDetails(&iParent.LddFactory()->iJSAes, this, iEncrypt, iKeyLengthBytes, iMode);
+ if(r != KErrNone)
+ {
+ return r;
+ }
+
+ return KErrNone;
+ }
+
+/**
+ Start processing a Aes request.
+*/
+TInt DLddChanAes::AesWrite(TRequestStatus* aStatus, TDesC8* aPtr)
+ {
+ TRACE_FUNCTION("AesWrite");
+ // Kern::Printf("DLddChanAes::AesWrite");
+ // Check that an Aes Write isn't already in progress
+ if(iAesWriteStatus)
+ {
+ Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+ return KErrInUse;
+ }
+
+ // We only support a single outstanding Aes Write request in this LDD
+ // channel, but the PDD supports multiple requests.
+
+ // Save the client request status and descriptor
+ iAesWriteStatus = aStatus;
+ iAesWriteDescriptor = aPtr;
+
+
+ // Retrieve user request length (ie. current length of user descriptor) into iRequestLength
+ TInt maxLen;
+ TUint8 *aesWriteDescriptorBufferRaw;
+ TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesWriteDescriptor, iWriteRequestLength, maxLen, aesWriteDescriptorBufferRaw, EFalse);
+ if(r != KErrNone)
+ {
+ iAesWriteStatus = 0;
+ return r;
+ }
+
+ // Set current offset into user descriptor
+ iCurrentUserWriteIndex = 0;
+
+ // Make sure iJob is valid before we use it
+ iJob = iParent.PddChan()->GetJobAes();
+
+
+#ifdef HW_PERF_CHECK
+ iJob->HwPerfCheck();
+#else
+ // Feed some data to the PDD
+ r = DataRequired(); // Fake PDD callback to get data from us.
+ if(r != KErrNone)
+ {
+ iAesWriteStatus = 0;
+ return r;
+ }
+
+ // Make sure job is not stalled, and maybe (re)add to job list.
+ iJob->Resume();
+#endif
+
+ return KErrNone;
+ }
+
+
+TInt DLddChanAes::AesRead(TRequestStatus* aStatus, TDes8* aPtr, TUint32 aLength)
+ {
+ TRACE_FUNCTION("AesRead");
+ // Kern::Printf("DLddChanAes::AesRead");
+ // Check that an Aes Read isn't already in progress
+ if(iAesReadStatus)
+ {
+ Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+ return KErrInUse;
+ }
+
+ // We only support a single outstanding Aes Read request in this LDD
+ // channel, but the PDD supports multiple requests.
+
+ // Save the client request status and descriptor
+ iAesReadStatus = aStatus;
+ iAesReadDescriptor = aPtr;
+ iReadRequestLength = aLength;
+
+ // Retrieve user request length (ie. current length of user descriptor) into iRequestLength
+ // TInt iOriginalUserReadDescLength;
+ TUint8 *aesReadDescriptorBufferRaw;
+ TInt maxLen;
+ TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesReadDescriptor, iOriginalUserReadDescLength, maxLen, aesReadDescriptorBufferRaw, ETrue);
+ if(r != KErrNone)
+ {
+ iAesReadStatus = 0;
+ return r;
+ }
+
+ if(iReadRequestLength > (maxLen - iOriginalUserReadDescLength))
+ {
+ return KErrArgument;
+ }
+
+ // Set current offset into user descriptor
+ iCurrentUserReadIndex = 0;
+
+ // Tell PDD our request length so it can optimse returning the data to us.
+ iJob->NotifyReadRequestLength(iReadRequestLength);
+
+
+#ifndef HW_PERF_CHECK
+ // Make sure iJob is valid before we use it
+ iJob = iParent.PddChan()->GetJobAes();
+
+ // Process any data already available
+ r = DataAvailable(); // Fake PDD callback to read data from PDD
+ if(r != KErrNone)
+ {
+ iAesReadStatus = 0;
+ return r;
+ }
+
+ // Make sure job is not stalled (and maybe re-add to job list) We
+ // do this even if we completely satisified the read from the PDD
+ // buffer because a write might be waiting for space in the
+ // buffer...
+ iJob->Resume();
+#endif
+
+ return KErrNone;
+ }
+
+
+
+TInt DLddChanAes::DataRequired()
+ {
+ TRACE_FUNCTION("DataRequired");
+ // Kern::Printf("DLddChanAes::DataRequired");
+ if(!iAesWriteStatus)
+ {
+ return KErrNone;
+ }
+
+ TBool moreSpace = ETrue;
+ TInt toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
+ while(toWrite && moreSpace)
+ {
+ // Get details of PDD write buffer
+ TUint8 *pddBuf; // always valid, though pddBufLen might be 0
+ TUint32 pddBufLen; // maybe 0
+ iJob->GetToPddBuffer(pddBuf, pddBufLen, moreSpace);
+
+ if(toWrite > pddBufLen)
+ {
+ toWrite = pddBufLen;
+ }
+
+ // Make sure there is some data to write
+ if(toWrite == 0)
+ {
+ break;
+ }
+
+ TPtr8 des(pddBuf, toWrite);
+ TInt r=Kern::ThreadDesRead(iParent.iClient, iAesWriteDescriptor, des, iCurrentUserWriteIndex);
+ //TInt r = 0;
+ if(r!=KErrNone)
+ return r;
+ iCurrentUserWriteIndex += toWrite;
+ // Tell the PDD how many bytes we wrote to it.
+ // If we wrote data, and the job was not already queued, the
+ // PDD will call ScheduleJob for it.
+ iJob->BytesWrittenToPdd(toWrite);
+
+ // Update count of bytes left to write
+ toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
+ };
+
+ if((iWriteRequestLength - iCurrentUserWriteIndex) <= 0)
+ {
+ // Write request is complete
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesWriteDescriptor = NULL;
+ // Complete client's request
+ Kern::RequestComplete(iParent.iClient,iAesWriteStatus, KErrNone);
+ return KErrNone;
+ }
+
+ return KErrNone;
+ }
+
+TInt DLddChanAes::DataAvailable()
+ {
+ TRACE_FUNCTION("DataAvailable");
+ // Kern::Printf("DLddChanAes::DataAvailable()");
+
+ if(!iAesReadStatus)
+ {
+ return KErrNone;
+ }
+
+ TInt r = KErrNone;
+
+ TUint8 *buf;
+ TUint32 bufLen;
+ TBool check = ETrue;
+ while(check)
+ {
+ iJob->GetFromPddBuffer(buf, bufLen, check);
+ if(bufLen)
+ {
+ TInt required = iReadRequestLength - iCurrentUserReadIndex;
+ TInt toTransfer = bufLen;
+ if(toTransfer > required)
+ {
+ toTransfer = required;
+ }
+ // Copy the current buffer to user land
+ TPtr8 des(buf, toTransfer, toTransfer);
+ r=Kern::ThreadDesWrite(iParent.iClient, iAesReadDescriptor, des, iOriginalUserReadDescLength + iCurrentUserReadIndex);
+ //r = 0;
+ if(r != KErrNone)
+ {
+ break;
+ }
+
+ // Update our index into the user descriptor
+ iCurrentUserReadIndex += toTransfer;
+
+ // Update h/w with number of bytes actually read
+ iJob->BytesReadFromPdd(toTransfer);
+
+ if(toTransfer != bufLen)
+ {
+ // We did not read all the available data, so do not
+ // re-query h/w
+ check = EFalse;
+ }
+ }
+ };
+
+ if((iReadRequestLength - iCurrentUserReadIndex) <= 0)
+ {
+ // Read request is complete
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesReadDescriptor = NULL;
+ // Complete client's request
+ Kern::RequestComplete(iParent.iClient,iAesReadStatus, KErrNone);
+ return KErrNone;
+ }
+
+ return KErrNone;
+ }
+
+
+
+
+
+/**
+ Called by PDD from a DFC to indicate that a Aes operation has completed.
+*/
+void DLddChanAes::JobComplete(TInt aResult)
+ {
+ TRACE_FUNCTION("JobComplete");
+ // Normally not used for AES, instead the job keeps running and
+ // DataAvailable/DataRequired complete the AesRead/AesWrite
+ // requests.
+ //
+ // Will be called if xfer to/from user space fails (or if another
+ // fatal error occurs).
+ if(iAesReadStatus)
+ {
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesReadDescriptor = NULL;
+ // Complete clients request (nb following call set iAesReadStatus to 0)
+ Kern::RequestComplete(iParent.iClient,iAesReadStatus, aResult);
+ }
+ if(iAesWriteStatus)
+ {
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesWriteDescriptor = NULL;
+ // Complete clients request (nb following call set iAesWriteStatus to 0)
+ Kern::RequestComplete(iParent.iClient,iAesWriteStatus, aResult);
+ }
+ }
+
+
+
+/**
+ Cancel a Aes Read request.
+*/
+void DLddChanAes::CancelRead()
+ {
+ TRACE_FUNCTION("CancelRead");
+ if(iAesReadStatus)
+ {
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesReadDescriptor = NULL;
+ // Complete clients request (nb following call set iAesReadStatus to 0)
+ Kern::RequestComplete(iParent.iClient,iAesReadStatus,KErrCancel);
+ }
+ }
+
+/**
+ Cancel a Aes Write request.
+*/
+void DLddChanAes::CancelWrite()
+ {
+ TRACE_FUNCTION("CancelWrite");
+ if(iAesWriteStatus)
+ {
+ // Finished with client descriptor, so NULL it to help detect coding errors
+ iAesWriteDescriptor = NULL;
+ // Complete clients request (nb following call set iAesWriteStatus to 0)
+ Kern::RequestComplete(iParent.iClient,iAesWriteStatus,KErrCancel);
+ }
+ }
+
+// End of file