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