|
1 // Copyright (c) 2003-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 // e32test\mmu\d_sharedio.cpp |
|
15 // LDD for testing SharedIoBuffers |
|
16 // |
|
17 // |
|
18 |
|
19 #include <kernel/kern_priv.h> |
|
20 #include "d_sharedio.h" |
|
21 |
|
22 // |
|
23 // LDD factory |
|
24 // |
|
25 |
|
26 class DSharedIoTestFactory : public DLogicalDevice |
|
27 { |
|
28 public: |
|
29 DSharedIoTestFactory(); |
|
30 ~DSharedIoTestFactory(); |
|
31 virtual TInt Install(); |
|
32 virtual void GetCaps(TDes8& aDes) const; |
|
33 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
34 public: |
|
35 DSharedIoBuffer* iGlobalBuffer; |
|
36 }; |
|
37 |
|
38 // |
|
39 // Logical Channel |
|
40 // |
|
41 |
|
42 class DSharedIoTest : public DLogicalChannelBase |
|
43 { |
|
44 public: |
|
45 virtual ~DSharedIoTest(); |
|
46 protected: |
|
47 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
48 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); |
|
49 public: |
|
50 DSharedIoBuffer* iIoBuffer; |
|
51 DSharedIoBuffer* iGlobalBuffer; |
|
52 DSharedIoTestFactory* iFactory; |
|
53 #ifndef __WINS__ |
|
54 TPhysAddr iPhysAddress; |
|
55 #endif |
|
56 }; |
|
57 |
|
58 // |
|
59 // LDD factory |
|
60 // |
|
61 |
|
62 DSharedIoTestFactory::DSharedIoTestFactory() |
|
63 { |
|
64 iGlobalBuffer=NULL; |
|
65 } |
|
66 |
|
67 DSharedIoTestFactory::~DSharedIoTestFactory() |
|
68 { |
|
69 delete iGlobalBuffer; |
|
70 } |
|
71 TInt DSharedIoTestFactory::Create(DLogicalChannelBase*& aChannel) |
|
72 { |
|
73 __KTRACE_OPT(KMMU,Kern::Printf(">DSharedIoTestFactory::Create iGlobalBuffer=%x",iGlobalBuffer)); |
|
74 if(!iGlobalBuffer) |
|
75 { |
|
76 #ifdef __WINS__ |
|
77 TUint aAttribs=0; |
|
78 #else |
|
79 TUint aAttribs=EMapAttrSupRw | EMapAttrFullyBlocking; |
|
80 #endif |
|
81 TInt r=DSharedIoBuffer::New(iGlobalBuffer,KSizeGlobalBuffer,aAttribs); |
|
82 if(r!=KErrNone) |
|
83 return r; |
|
84 } |
|
85 aChannel=new DSharedIoTest; |
|
86 if(!aChannel) |
|
87 return KErrNoMemory; |
|
88 ((DSharedIoTest*)aChannel)->iGlobalBuffer=iGlobalBuffer; |
|
89 ((DSharedIoTest*)aChannel)->iFactory=this; |
|
90 __KTRACE_OPT(KMMU,Kern::Printf("<DSharedIoTestFactory::Create iGlobalBuffer=%x",iGlobalBuffer)); |
|
91 return KErrNone; |
|
92 } |
|
93 |
|
94 TInt DSharedIoTestFactory::Install() |
|
95 { |
|
96 return SetName(&KSharedIoTestLddName); |
|
97 } |
|
98 |
|
99 void DSharedIoTestFactory::GetCaps(TDes8& /* aDes */) const |
|
100 { |
|
101 //aDes.FillZ(aDes.MaxLength()); |
|
102 } |
|
103 |
|
104 DECLARE_STANDARD_LDD() |
|
105 { |
|
106 return new DSharedIoTestFactory; |
|
107 } |
|
108 |
|
109 // |
|
110 // Logical Channel |
|
111 // |
|
112 |
|
113 TInt DSharedIoTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
114 { |
|
115 return KErrNone; |
|
116 } |
|
117 |
|
118 DSharedIoTest::~DSharedIoTest() |
|
119 { |
|
120 delete iIoBuffer; |
|
121 } |
|
122 |
|
123 TInt checkBuffer(TAny* buffer, TUint32 aSize, TUint32 key) |
|
124 { |
|
125 TInt r=KErrNone; |
|
126 TUint8* m=(TUint8*)buffer; |
|
127 for(TUint32 size=0;size<aSize;size++,key+=5,m++) |
|
128 { |
|
129 if(*m!=(TUint8)(key%256)) |
|
130 { |
|
131 r=KErrCorrupt; |
|
132 break; |
|
133 } |
|
134 } |
|
135 return r; |
|
136 } |
|
137 |
|
138 TInt fillBuffer(TAny* buffer, TUint32 aSize, TUint32 key) |
|
139 { |
|
140 TUint8* m=(TUint8*)buffer; |
|
141 for(TUint32 size=0;size<aSize;size++,key+=5,m++) |
|
142 { |
|
143 *m=(TUint8)(key%256); |
|
144 } |
|
145 return KErrNone; |
|
146 } |
|
147 |
|
148 static void AppendNumToBuf(TDes8& aDes, const TDesC& aNum, TInt width, char fill) |
|
149 { |
|
150 TInt l = aNum.Length(); |
|
151 for (; l < width; ++l) |
|
152 aDes.Append(TChar(fill)); |
|
153 aDes.Append(aNum); |
|
154 } |
|
155 |
|
156 static void DumpMemory(TUint8* aStart, TInt aSize) |
|
157 { |
|
158 TBuf8<80> line; |
|
159 TBuf8<24> val; |
|
160 TChar space(' '); |
|
161 |
|
162 TInt i = (TInt)aStart & 0xF; // first byte in this line to dump |
|
163 TInt n = 16; // end byte in this line |
|
164 |
|
165 while (aSize > 0) |
|
166 { |
|
167 if (i + aSize < 16) |
|
168 n = i + aSize; |
|
169 |
|
170 val.Num((TUint32)aStart & ~0xF, EHex); |
|
171 AppendNumToBuf(line, val, 8, '0'); |
|
172 line.Append(space); |
|
173 line.Append(space); |
|
174 |
|
175 TInt j; |
|
176 |
|
177 for (j = 0; j < i; ++j) |
|
178 { |
|
179 line.Append(space); |
|
180 line.Append(space); |
|
181 line.Append(space); |
|
182 |
|
183 if (j == 7) line.Append(space); |
|
184 } |
|
185 |
|
186 for (; j < n; ++j) |
|
187 { |
|
188 val.Num(aStart[j-i], EHex); |
|
189 line.Append(space); |
|
190 AppendNumToBuf(line, val, 2, '0'); |
|
191 |
|
192 if (j == 7) line.Append(space); |
|
193 } |
|
194 |
|
195 for (; j < 16; ++j) |
|
196 { |
|
197 line.Append(space); |
|
198 line.Append(space); |
|
199 line.Append(space); |
|
200 |
|
201 if (j == 7) line.Append(space); |
|
202 } |
|
203 |
|
204 line.Append(space); |
|
205 line.Append(space); |
|
206 |
|
207 for (j = 0; j < i; ++j) |
|
208 line.Append(space); |
|
209 |
|
210 for (; j < n; ++j) |
|
211 { |
|
212 char c = aStart[j-i]; |
|
213 if (c < ' ' || c > 126) c = '.'; |
|
214 line.Append(TChar(c)); |
|
215 } |
|
216 |
|
217 Kern::Printf("%S", &line); |
|
218 |
|
219 line.SetLength(0); |
|
220 |
|
221 aStart += (n - i); |
|
222 aSize -= (n - i); |
|
223 |
|
224 i = 0; |
|
225 } |
|
226 } |
|
227 |
|
228 TBool CheckMemCleared(TLinAddr aAddress, TInt aSize) |
|
229 { |
|
230 TUint8* aPtr = (TUint8*)aAddress; |
|
231 for(TInt i = 0; i<aSize; i++) |
|
232 { |
|
233 if(aPtr[i] != 0x03) |
|
234 { |
|
235 Kern::Printf("CheckMemCleared(0x%x, %d) failed at i = 0x%x", aAddress, aSize, i); |
|
236 // Start on current line & ~0xF, run for 16 lines x 16 bytes |
|
237 TUint8 *p = (TUint8*)((aAddress + i) & ~0x0F); |
|
238 TInt n = 256; |
|
239 |
|
240 if (p < aPtr) p = aPtr; |
|
241 if (p - aPtr > aSize - n) // if (p + n > aPtr + aSize) rearranged (to avoid overflow) |
|
242 n = aPtr + aSize - p; |
|
243 |
|
244 DumpMemory(p, n); |
|
245 return EFalse; |
|
246 } |
|
247 } |
|
248 return ETrue; |
|
249 } |
|
250 |
|
251 TInt DSharedIoTest::Request(TInt aFunction, TAny* a1, TAny* a2) |
|
252 { |
|
253 TInt r=KErrNone; |
|
254 switch (aFunction) |
|
255 { |
|
256 case RTestLdd::ECreateBuffer: |
|
257 { |
|
258 TUint32 size = (TUint32)a1; |
|
259 r = KErrNoMemory; |
|
260 #ifdef __WINS__ |
|
261 TUint aAttribs1=0; |
|
262 TUint aAttribs2=0; |
|
263 TUint aAttribs3=0; |
|
264 #else |
|
265 TUint aAttribs1=EMapAttrSupRw | EMapAttrBufferedNC; |
|
266 TUint aAttribs2=EMapAttrSupRw | EMapAttrFullyBlocking; |
|
267 TUint aAttribs3=EMapAttrSupRw | EMapAttrCachedMax; |
|
268 #endif |
|
269 NKern::ThreadEnterCS(); |
|
270 r=DSharedIoBuffer::New(iIoBuffer,size,aAttribs1); |
|
271 if(r!=KErrNone) |
|
272 { |
|
273 Kern::Printf("Error creating buffer r=%d\n",r); |
|
274 NKern::ThreadLeaveCS(); |
|
275 return r; |
|
276 } |
|
277 |
|
278 //Check the buffer is properly initialized (the previous content |
|
279 //deleted by inserting all 0x03s) |
|
280 if (!CheckMemCleared(iIoBuffer->iAddress, iIoBuffer->iSize)) |
|
281 { |
|
282 Kern::Printf("Error memory zeroing test for shared io buffers"); |
|
283 NKern::ThreadLeaveCS(); |
|
284 return KErrCorrupt; |
|
285 } |
|
286 |
|
287 //just test that we can construct a second shared buffer |
|
288 DSharedIoBuffer* ptr; |
|
289 r=DSharedIoBuffer::New(ptr,size,aAttribs2); |
|
290 if(r!=KErrNone) |
|
291 { |
|
292 Kern::Printf("Error creating the 2nd buffer r=%d\n",r); |
|
293 delete iIoBuffer; |
|
294 iIoBuffer=NULL; |
|
295 NKern::ThreadLeaveCS(); |
|
296 return r; |
|
297 } |
|
298 delete ptr; //creation successfull, simply delete the object |
|
299 |
|
300 // and the third one, this time fully cached. |
|
301 r=DSharedIoBuffer::New(ptr,size,aAttribs3); |
|
302 if(r!=KErrNone) |
|
303 { |
|
304 Kern::Printf("Error creating the 3rd buffer r=%d\n",r); |
|
305 delete iIoBuffer; |
|
306 iIoBuffer=NULL; |
|
307 NKern::ThreadLeaveCS(); |
|
308 return r; |
|
309 } |
|
310 delete ptr; //creation successfull, simply delete the object |
|
311 |
|
312 NKern::ThreadLeaveCS(); |
|
313 if(iIoBuffer->iSize!=size) // test |
|
314 { |
|
315 Kern::Printf("Error checking size iIoBuffer->iSize=%d size=%d\n",iIoBuffer->iSize,size); |
|
316 return KErrGeneral; |
|
317 } |
|
318 memset((void*)iIoBuffer->iAddress,0,size); |
|
319 } |
|
320 return r; |
|
321 |
|
322 case RTestLdd::EMapInGlobalBuffer: |
|
323 { |
|
324 if(!iGlobalBuffer) |
|
325 return KErrGeneral; |
|
326 |
|
327 TUint id; |
|
328 kumemget32(&id,a1,sizeof(TUint)); |
|
329 |
|
330 NKern::ThreadEnterCS(); |
|
331 Kern::Containers()[EProcess]->Wait(); |
|
332 DProcess* process=Kern::ProcessFromId(id); |
|
333 if(process) |
|
334 process->Open(); |
|
335 Kern::Containers()[EProcess]->Signal(); |
|
336 if(process) |
|
337 { |
|
338 r=iGlobalBuffer->UserMap(process); |
|
339 process->Close(0); |
|
340 } |
|
341 else |
|
342 r = KErrGeneral; |
|
343 NKern::ThreadLeaveCS(); |
|
344 |
|
345 if(r!=KErrNone) |
|
346 return r; |
|
347 |
|
348 if(iGlobalBuffer->UserToKernel(iGlobalBuffer->iUserAddress,iGlobalBuffer->iSize)!=iGlobalBuffer->iAddress) |
|
349 return KErrGeneral; |
|
350 |
|
351 if(iGlobalBuffer->UserToKernel(iGlobalBuffer->iUserAddress,iGlobalBuffer->iSize+1)!=NULL) |
|
352 return KErrGeneral; |
|
353 |
|
354 if(iGlobalBuffer->KernelToUser(iGlobalBuffer->iAddress)!=iGlobalBuffer->iUserAddress) |
|
355 return KErrGeneral; |
|
356 |
|
357 kumemput32(a1,&iGlobalBuffer->iUserAddress,sizeof(TAny*)); |
|
358 kumemput32(a2,&iGlobalBuffer->iSize,sizeof(TInt)); |
|
359 |
|
360 return KErrNone; |
|
361 } |
|
362 |
|
363 case RTestLdd::EMapOutGlobalBuffer: |
|
364 { |
|
365 if(!iGlobalBuffer) |
|
366 return KErrGeneral; |
|
367 r=iGlobalBuffer->UserUnmap(); |
|
368 if(r==KErrNone) |
|
369 if(iGlobalBuffer->iUserProcess) |
|
370 r = KErrGeneral; |
|
371 return r; |
|
372 } |
|
373 |
|
374 case RTestLdd::EDestroyGlobalBuffer: |
|
375 { |
|
376 NKern::ThreadEnterCS(); |
|
377 delete iGlobalBuffer; |
|
378 iGlobalBuffer = NULL; |
|
379 iFactory->iGlobalBuffer=NULL; |
|
380 NKern::ThreadLeaveCS(); |
|
381 return KErrNone; |
|
382 } |
|
383 |
|
384 case RTestLdd::ECreateBufferPhysAddr: |
|
385 { |
|
386 #ifdef __WINS__ |
|
387 return KErrNotSupported; |
|
388 #else |
|
389 TUint32 size=Kern::RoundToPageSize(1); |
|
390 NKern::ThreadEnterCS(); |
|
391 r=Epoc::AllocPhysicalRam(size,iPhysAddress); |
|
392 Kern::Printf("phys addr = %X!\n",iPhysAddress); |
|
393 if(r!=KErrNone) |
|
394 { |
|
395 NKern::ThreadLeaveCS(); |
|
396 return r; |
|
397 } |
|
398 r = KErrNoMemory; |
|
399 |
|
400 //test that we can construct a fully cached sharedio |
|
401 DSharedIoBuffer* ptr; |
|
402 r=DSharedIoBuffer::New(ptr,iPhysAddress,size,EMapAttrSupRw|EMapAttrCachedMax); |
|
403 if(r!=KErrNone) |
|
404 { |
|
405 Kern::Printf("Error creating the physical cached buffer r=%d\n",r); |
|
406 Epoc::FreePhysicalRam(iPhysAddress,size); |
|
407 iPhysAddress=0; |
|
408 NKern::ThreadLeaveCS(); |
|
409 return r; |
|
410 } |
|
411 delete ptr; //creation successfull, simply delete the object |
|
412 |
|
413 |
|
414 r=DSharedIoBuffer::New(iIoBuffer,iPhysAddress,size,EMapAttrSupRw|EMapAttrFullyBlocking); |
|
415 if(r!=KErrNone) |
|
416 { |
|
417 Epoc::FreePhysicalRam(iPhysAddress,size); |
|
418 iPhysAddress=0; |
|
419 NKern::ThreadLeaveCS(); |
|
420 return r; |
|
421 } |
|
422 |
|
423 if(iIoBuffer->iSize!=size) // test |
|
424 { |
|
425 delete iIoBuffer; |
|
426 iIoBuffer=NULL; |
|
427 Epoc::FreePhysicalRam(iPhysAddress,size); |
|
428 iPhysAddress=0; |
|
429 NKern::ThreadLeaveCS(); |
|
430 return KErrGeneral; |
|
431 } |
|
432 |
|
433 fillBuffer((TAny*)iIoBuffer->iAddress,size,180); |
|
434 |
|
435 DPlatChunkHw* hwChunk; |
|
436 r=DPlatChunkHw::New(hwChunk, iPhysAddress, size, EMapAttrSupRw|EMapAttrFullyBlocking); |
|
437 if(r!=KErrNone) |
|
438 { |
|
439 delete iIoBuffer; |
|
440 iIoBuffer=NULL; |
|
441 Epoc::FreePhysicalRam(iPhysAddress,size); |
|
442 iPhysAddress=0; |
|
443 NKern::ThreadLeaveCS(); |
|
444 return r; |
|
445 } |
|
446 |
|
447 r=checkBuffer((TAny*)hwChunk->LinearAddress(),size,180); |
|
448 if(r!=KErrNone) |
|
449 { |
|
450 delete iIoBuffer; |
|
451 iIoBuffer=NULL; |
|
452 hwChunk->Close(NULL); |
|
453 Epoc::FreePhysicalRam(iPhysAddress,size); |
|
454 iPhysAddress=0; |
|
455 NKern::ThreadLeaveCS(); |
|
456 return r; |
|
457 } |
|
458 |
|
459 hwChunk->Close(NULL); |
|
460 NKern::ThreadLeaveCS(); |
|
461 return r; |
|
462 #endif |
|
463 } |
|
464 |
|
465 case RTestLdd::EDestroyBufferPhysAddr: |
|
466 { |
|
467 #ifdef __WINS__ |
|
468 return KErrNotSupported; |
|
469 #else |
|
470 TUint32 size=Kern::RoundToPageSize(1); |
|
471 NKern::ThreadEnterCS(); |
|
472 delete iIoBuffer; |
|
473 iIoBuffer = NULL; |
|
474 r=Epoc::FreePhysicalRam(iPhysAddress,size); |
|
475 iPhysAddress=0; |
|
476 NKern::ThreadLeaveCS(); |
|
477 return r; |
|
478 #endif |
|
479 } |
|
480 |
|
481 |
|
482 case RTestLdd::EMapInBuffer: |
|
483 { |
|
484 r=iIoBuffer->UserMap(&Kern::CurrentProcess()); |
|
485 if(r!=KErrNone) |
|
486 return r; |
|
487 |
|
488 TAny** p = (TAny**)iIoBuffer->iAddress; |
|
489 TAny* ua = (TAny*)iIoBuffer->iUserAddress; |
|
490 TAny** end = (TAny**)((TInt)p+iIoBuffer->iSize); |
|
491 while(p<end) |
|
492 { |
|
493 *p++ = ua; |
|
494 ua = (TAny*)((TInt)ua+sizeof(TAny*)); |
|
495 } |
|
496 if(iIoBuffer->UserToKernel(iIoBuffer->iUserAddress,iIoBuffer->iSize)!=iIoBuffer->iAddress) |
|
497 return KErrGeneral; |
|
498 |
|
499 if(iIoBuffer->UserToKernel(iIoBuffer->iUserAddress,iIoBuffer->iSize+1)!=NULL) |
|
500 return KErrGeneral; |
|
501 |
|
502 if(iIoBuffer->KernelToUser(iIoBuffer->iAddress)!=iIoBuffer->iUserAddress) |
|
503 return KErrGeneral; |
|
504 kumemput32(a1,&iIoBuffer->iUserAddress,sizeof(TAny*)); |
|
505 kumemput32(a2,&iIoBuffer->iSize,sizeof(TInt)); |
|
506 return r; |
|
507 } |
|
508 |
|
509 case RTestLdd::EMapOutBuffer: |
|
510 { |
|
511 r=iIoBuffer->UserUnmap(); |
|
512 if(r==KErrNone) |
|
513 if(iIoBuffer->iUserProcess) |
|
514 r = KErrGeneral; |
|
515 return r; |
|
516 } |
|
517 |
|
518 case RTestLdd::EDestroyBuffer: |
|
519 NKern::ThreadEnterCS(); |
|
520 delete iIoBuffer; |
|
521 iIoBuffer = NULL; |
|
522 NKern::ThreadLeaveCS(); |
|
523 return KErrNone; |
|
524 |
|
525 case RTestLdd::ECheckBuffer: |
|
526 if(!iIoBuffer->iAddress || !iIoBuffer->iUserAddress || !iIoBuffer->iUserProcess) |
|
527 return KErrGeneral; |
|
528 return checkBuffer((TAny*)iIoBuffer->iAddress,iIoBuffer->iSize,(TUint32)a1); |
|
529 |
|
530 case RTestLdd::EFillBuffer: |
|
531 if(!iIoBuffer->iAddress || !iIoBuffer->iUserAddress || !iIoBuffer->iUserProcess) |
|
532 return KErrGeneral; |
|
533 return fillBuffer((TAny*)iIoBuffer->iAddress,iIoBuffer->iSize,(TUint32)a1); |
|
534 |
|
535 case RTestLdd::EThreadRW: |
|
536 { |
|
537 TInt dummy; |
|
538 TPckg<TInt> a(dummy); |
|
539 DThread* pT; |
|
540 if((TInt)a2==-1) |
|
541 { |
|
542 pT=&Kern::CurrentThread(); |
|
543 } |
|
544 else |
|
545 { |
|
546 NKern::ThreadEnterCS(); |
|
547 DObjectCon* pC=Kern::Containers()[EThread]; |
|
548 pC->Wait(); |
|
549 pT=Kern::ThreadFromId((TInt)a2); |
|
550 pC->Signal(); |
|
551 if(!pT) |
|
552 return KErrNotFound; |
|
553 NKern::ThreadLeaveCS(); |
|
554 } |
|
555 r=Kern::ThreadDesRead(pT,a1,a,0,KChunkShiftBy0); |
|
556 if(r!=KErrNone) |
|
557 return r; |
|
558 if(dummy!=KMagic1) |
|
559 return KErrCorrupt; |
|
560 dummy=KMagic2; |
|
561 r=Kern::ThreadDesWrite(pT,a1,a,0,KChunkShiftBy0,&Kern::CurrentThread()); |
|
562 if(r!=KErrNone) |
|
563 return r; |
|
564 return KErrNone; |
|
565 } |
|
566 |
|
567 default: |
|
568 r=KErrNotSupported; |
|
569 break; |
|
570 } |
|
571 return r; |
|
572 } |
|
573 |