|
1 // Copyright (c) 2008-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\demandpaging\t_pagingexample.cpp |
|
15 // Test device driver migration examples |
|
16 // |
|
17 // |
|
18 |
|
19 #define __E32TEST_EXTENSION__ |
|
20 #include <e32test.h> |
|
21 #include <dptest.h> |
|
22 #include <e32hal.h> |
|
23 #include <u32exec.h> |
|
24 #include <e32svr.h> |
|
25 #include <e32panic.h> |
|
26 #include <e32rom.h> |
|
27 #include <e32kpan.h> |
|
28 #include "../mmu/t_codepaging_dll.h" |
|
29 #include "d_pagingexample.h" |
|
30 |
|
31 const TInt KBufferSize = KMaxTransferSize; |
|
32 _LIT(KTCodePagingDll4, "t_codepaging_dll4.dll"); |
|
33 |
|
34 struct TTestData |
|
35 { |
|
36 TRequestStatus iStatus; |
|
37 RPagingExample::TConfigData iConfig; |
|
38 RPagingExample::TValueStruct iValue; |
|
39 TInt iIntValue1; |
|
40 TInt iIntValue2; |
|
41 TPtr8 iPtr; |
|
42 TUint8 iBuffer[KBufferSize]; |
|
43 public: |
|
44 TTestData() : iPtr(NULL, 0) { } |
|
45 }; |
|
46 |
|
47 RTest test(_L("T_PAGINGEXAMPLE")); |
|
48 TInt PageSize = 0; |
|
49 RLibrary PagedLibrary; |
|
50 TTestData* UnpagedInputData = NULL; |
|
51 TTestData* UnpagedOutputData = NULL; |
|
52 TTestData* PagedInputData = NULL; |
|
53 TTestData* PagedOutputData = NULL; |
|
54 |
|
55 void InitInputData(TTestData* aData) |
|
56 { |
|
57 aData->iConfig.iParam1 = 2; |
|
58 aData->iConfig.iParam2 = 3; |
|
59 aData->iConfig.iParam3 = 5; |
|
60 aData->iConfig.iParam4 = 7; |
|
61 for (TInt i = 0 ; i < KBufferSize ; ++i) |
|
62 aData->iBuffer[i] = (TUint8)(i + 123); |
|
63 } |
|
64 |
|
65 void DoTestDriver(const TDesC& aDriverName, const TTestData* aInputData, TTestData* aOutputData) |
|
66 { |
|
67 test.Start(_L("Load logical device")); |
|
68 TInt r = User::LoadLogicalDevice(aDriverName); |
|
69 test(r==KErrNone || r==KErrAlreadyExists); |
|
70 |
|
71 test.Next(_L("Open logical device")); |
|
72 RPagingExample ldd; |
|
73 test_KErrNone(ldd.Open(aDriverName)); |
|
74 |
|
75 test.Next(_L("Set config")); |
|
76 DPTest::FlushCache(); |
|
77 test_KErrNone(ldd.SetConfig(aInputData->iConfig)); |
|
78 |
|
79 test.Next(_L("Get config")); |
|
80 Mem::FillZ(&aOutputData->iConfig, sizeof(RPagingExample::TConfigData)); |
|
81 DPTest::FlushCache(); |
|
82 test_KErrNone(ldd.GetConfig(aOutputData->iConfig)); |
|
83 test_Equal(0, Mem::Compare((TUint8*)&aInputData->iConfig, sizeof(RPagingExample::TConfigData), |
|
84 (TUint8*)&aOutputData->iConfig, sizeof(RPagingExample::TConfigData))); |
|
85 |
|
86 TRequestStatus& status = aOutputData->iStatus; |
|
87 |
|
88 test.Next(_L("Notify")); |
|
89 DPTest::FlushCache(); |
|
90 ldd.Notify(status); |
|
91 DPTest::FlushCache(); |
|
92 User::WaitForRequest(status); |
|
93 test_Equal(KErrNone, status.Int()); |
|
94 |
|
95 test.Next(_L("Async get value")); |
|
96 memclr(&aOutputData->iValue, sizeof(RPagingExample::TValueStruct)); |
|
97 DPTest::FlushCache(); |
|
98 ldd.AsyncGetValue(status, aOutputData->iValue); |
|
99 DPTest::FlushCache(); |
|
100 User::WaitForRequest(status); |
|
101 test_Equal(KErrNone, status.Int()); |
|
102 test_Equal(1, aOutputData->iValue.iValue1); |
|
103 test(aOutputData->iValue.iValue2 == _L8("shrt")); |
|
104 |
|
105 test.Next(_L("Cancel async get value")); |
|
106 ldd.AsyncGetValue(status, aOutputData->iValue); |
|
107 ldd.Cancel(); |
|
108 User::WaitForRequest(status); |
|
109 test_Equal(KErrCancel, status.Int()); |
|
110 |
|
111 test.Next(_L("Async get value 2")); |
|
112 aOutputData->iIntValue1 = 0; |
|
113 aOutputData->iIntValue2 = 0; |
|
114 DPTest::FlushCache(); |
|
115 ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2); |
|
116 DPTest::FlushCache(); |
|
117 User::WaitForRequest(status); |
|
118 test_Equal(KErrNone, status.Int()); |
|
119 test_Equal(1, aOutputData->iIntValue1); |
|
120 test_Equal(2, aOutputData->iIntValue2); |
|
121 |
|
122 test.Next(_L("Cancel async get value 2")); |
|
123 ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2); |
|
124 ldd.Cancel(); |
|
125 User::WaitForRequest(status); |
|
126 test_Equal(KErrCancel, status.Int()); |
|
127 |
|
128 test.Next(_L("Write buffer too short")); |
|
129 ldd.Write(status, NULL, 0); |
|
130 User::WaitForRequest(status); |
|
131 test_Equal(KErrArgument, status.Int()); |
|
132 |
|
133 test.Next(_L("Write buffer too long")); |
|
134 ldd.Write(status, NULL, KMaxTransferSize + 1); |
|
135 User::WaitForRequest(status); |
|
136 test_Equal(KErrArgument, status.Int()); |
|
137 |
|
138 test.Next(_L("Write")); |
|
139 DPTest::FlushCache(); |
|
140 ldd.Write(status, aInputData->iBuffer, KBufferSize); |
|
141 DPTest::FlushCache(); |
|
142 User::WaitForRequest(status); |
|
143 test_KErrNone(status.Int()); |
|
144 |
|
145 test.Next(_L("Cancel write")); |
|
146 ldd.Write(status, aInputData->iBuffer, KBufferSize); |
|
147 ldd.Cancel(); |
|
148 User::WaitForRequest(status); |
|
149 test_Equal(KErrCancel, status.Int()); |
|
150 |
|
151 test.Next(_L("Read buffer too short")); |
|
152 ldd.Read(status, NULL, 0); |
|
153 User::WaitForRequest(status); |
|
154 test_Equal(KErrArgument, status.Int()); |
|
155 |
|
156 test.Next(_L("Read buffer too long")); |
|
157 ldd.Read(status, NULL, KMaxTransferSize + 1); |
|
158 User::WaitForRequest(status); |
|
159 test_Equal(KErrArgument, status.Int()); |
|
160 |
|
161 test.Next(_L("Read")); |
|
162 Mem::FillZ(aOutputData->iBuffer, KBufferSize); |
|
163 DPTest::FlushCache(); |
|
164 ldd.Read(status, aOutputData->iBuffer, KBufferSize); |
|
165 DPTest::FlushCache(); |
|
166 User::WaitForRequest(status); |
|
167 test_KErrNone(status.Int()); |
|
168 test_Equal(0, Mem::Compare(aInputData->iBuffer, KBufferSize, |
|
169 aOutputData->iBuffer, KBufferSize)); |
|
170 |
|
171 test.Next(_L("Cancel read")); |
|
172 ldd.Read(status, aOutputData->iBuffer, KBufferSize); |
|
173 ldd.Cancel(); |
|
174 User::WaitForRequest(status); |
|
175 test_Equal(KErrCancel, status.Int()); |
|
176 |
|
177 test.Next(_L("Cancel nothing")); |
|
178 ldd.Cancel(); |
|
179 |
|
180 test.Next(_L("Write while write pending")); |
|
181 TRequestStatus status2; |
|
182 ldd.Write(status, aInputData->iBuffer, KBufferSize); |
|
183 ldd.Write(status2, aInputData->iBuffer, KBufferSize); |
|
184 User::WaitForRequest(status); |
|
185 test_KErrNone(status.Int()); |
|
186 User::WaitForRequest(status2); |
|
187 test_Equal(KErrInUse, status2.Int()); |
|
188 |
|
189 test.Next(_L("Read while read pending")); |
|
190 ldd.Read(status, aOutputData->iBuffer, KBufferSize); |
|
191 ldd.Read(status2, aOutputData->iBuffer, KBufferSize); |
|
192 User::WaitForRequest(status); |
|
193 test_KErrNone(status.Int()); |
|
194 User::WaitForRequest(status2); |
|
195 test_Equal(KErrInUse, status2.Int()); |
|
196 |
|
197 test.Next(_L("Write des")); |
|
198 TPtrC8 writeDes(aInputData->iBuffer + 1, KBufferSize - 1); |
|
199 DPTest::FlushCache(); |
|
200 ldd.WriteDes(status, writeDes); |
|
201 DPTest::FlushCache(); |
|
202 User::WaitForRequest(status); |
|
203 test_KErrNone(status.Int()); |
|
204 |
|
205 test.Next(_L("Cancel write des")); |
|
206 ldd.WriteDes(status, writeDes); |
|
207 ldd.Cancel(); |
|
208 User::WaitForRequest(status); |
|
209 test_Equal(KErrCancel, status.Int()); |
|
210 |
|
211 test.Next(_L("Read des")); |
|
212 TPtr8 readDes(aOutputData->iBuffer, KBufferSize - 1); |
|
213 Mem::FillZ(aOutputData->iBuffer, KBufferSize); |
|
214 DPTest::FlushCache(); |
|
215 ldd.ReadDes(status, readDes); |
|
216 DPTest::FlushCache(); |
|
217 User::WaitForRequest(status); |
|
218 test_KErrNone(status.Int()); |
|
219 test(readDes == writeDes); |
|
220 |
|
221 test.Next(_L("Read des 2")); // has paged header but unpaged contnet, if output data is paged |
|
222 aOutputData->iPtr.Set(UnpagedOutputData->iBuffer, 0, KBufferSize - 1); |
|
223 Mem::FillZ(UnpagedOutputData->iBuffer, KBufferSize); |
|
224 DPTest::FlushCache(); |
|
225 ldd.ReadDes(status, aOutputData->iPtr); |
|
226 DPTest::FlushCache(); |
|
227 User::WaitForRequest(status); |
|
228 test_KErrNone(status.Int()); |
|
229 test(aOutputData->iPtr == writeDes); |
|
230 |
|
231 test.Next(_L("Cancel read des")); |
|
232 ldd.ReadDes(status, readDes); |
|
233 ldd.Cancel(); |
|
234 User::WaitForRequest(status); |
|
235 test_Equal(KErrCancel, status.Int()); |
|
236 |
|
237 test.Next(_L("Read and write at the same time")); |
|
238 ldd.Write(status, aInputData->iBuffer, KBufferSize); |
|
239 ldd.Read(status2, aOutputData->iBuffer, KBufferSize); |
|
240 DPTest::FlushCache(); |
|
241 User::WaitForRequest(status); |
|
242 test_KErrNone(status.Int()); |
|
243 User::WaitForRequest(status2); |
|
244 test_KErrNone(status2.Int()); |
|
245 |
|
246 test.Next(_L("Cancel read and write")); |
|
247 ldd.Write(status, aInputData->iBuffer, KBufferSize); |
|
248 ldd.Read(status2, aOutputData->iBuffer, KBufferSize); |
|
249 ldd.Cancel(); |
|
250 User::WaitForRequest(status); |
|
251 test_Equal(KErrCancel, status.Int()); |
|
252 User::WaitForRequest(status2); |
|
253 test_Equal(KErrCancel, status2.Int()); |
|
254 |
|
255 test.Next(_L("Close and free logical device")); |
|
256 ldd.Close(); |
|
257 test_KErrNone(User::FreeLogicalDevice(aDriverName)); |
|
258 |
|
259 test.End(); |
|
260 } |
|
261 |
|
262 void TestDriver(const TDesC& aDriverName, TBool aMigrated) |
|
263 { |
|
264 TBuf<64> string; |
|
265 string.Format(_L("Testing driver %S"), &aDriverName); |
|
266 test.Next(string); |
|
267 |
|
268 test.Start(_L("Test reading from unpaged memory and writing to unpaged memory")); |
|
269 DoTestDriver(aDriverName, UnpagedInputData, UnpagedOutputData); |
|
270 |
|
271 if (aMigrated && PagedInputData) |
|
272 { |
|
273 if (PagedOutputData) |
|
274 { |
|
275 test.Next(_L("Test reading from paged memory and writing to paged memory")); |
|
276 DoTestDriver(aDriverName, PagedInputData, PagedOutputData); |
|
277 } |
|
278 else |
|
279 { |
|
280 test.Next(_L("Test reading from paged memory and writing to unpaged memory")); |
|
281 DoTestDriver(aDriverName, PagedInputData, UnpagedOutputData); |
|
282 } |
|
283 } |
|
284 |
|
285 // todo: test pinning failures |
|
286 |
|
287 test.End(); |
|
288 } |
|
289 |
|
290 enum TTestAction |
|
291 { |
|
292 ETestRequestComplete, |
|
293 ETestRawRead, |
|
294 ETestRawWrite, |
|
295 ETestDesRead, |
|
296 ETestDesWrite |
|
297 }; |
|
298 |
|
299 enum TTestAccess |
|
300 { |
|
301 EAccessUnpaged, |
|
302 EAccessPaged |
|
303 }; |
|
304 |
|
305 enum TTestOutcome |
|
306 { |
|
307 EOutcomeSuccess, |
|
308 EOutcomeRealtimePanic |
|
309 }; |
|
310 |
|
311 TInt RealtimeTestFunc(TAny* aArg) |
|
312 { |
|
313 TTestAction action = (TTestAction)((TUint)aArg & 255); |
|
314 TTestAccess access = (TTestAccess)((TUint)aArg >> 8); |
|
315 |
|
316 TTestData* inputData = access == EAccessPaged ? PagedInputData : UnpagedInputData; |
|
317 TTestData* outputData = access == EAccessPaged ? PagedOutputData : UnpagedOutputData; |
|
318 |
|
319 RPagingExample ldd; |
|
320 TInt r = ldd.Open(KPagingExample1PreLdd); |
|
321 if (r != KErrNone) |
|
322 return r; |
|
323 ldd.SetDfcThreadRealtimeState(ETrue); |
|
324 |
|
325 TRequestStatus unpagedStatus; |
|
326 TRequestStatus* status = &unpagedStatus; |
|
327 |
|
328 switch(action) |
|
329 { |
|
330 case ETestRequestComplete: |
|
331 { |
|
332 RDebug::Printf("Test RequestComplete"); |
|
333 status = &outputData->iStatus; |
|
334 RPagingExample::TValueStruct value; |
|
335 DPTest::FlushCache(); |
|
336 ldd.AsyncGetValue(*status, value); |
|
337 DPTest::FlushCache(); |
|
338 } |
|
339 break; |
|
340 |
|
341 case ETestRawRead: |
|
342 RDebug::Printf("Test ThreadRawRead"); |
|
343 ldd.Write(*status, inputData->iBuffer, KBufferSize); |
|
344 DPTest::FlushCache(); |
|
345 break; |
|
346 |
|
347 case ETestRawWrite: |
|
348 RDebug::Printf("Test ThreadRawWrite"); |
|
349 ldd.Read(*status, outputData->iBuffer, KBufferSize); |
|
350 DPTest::FlushCache(); |
|
351 break; |
|
352 |
|
353 case ETestDesRead: |
|
354 { |
|
355 RDebug::Printf("Test ThreadDesRead"); |
|
356 TPtrC8 writeDes(inputData->iBuffer, KBufferSize); |
|
357 ldd.WriteDes(*status, writeDes); |
|
358 DPTest::FlushCache(); |
|
359 } |
|
360 break; |
|
361 |
|
362 case ETestDesWrite: |
|
363 { |
|
364 RDebug::Printf("Test ThreadDesWrite"); |
|
365 TPtr8 readDes(outputData->iBuffer, KBufferSize); |
|
366 ldd.ReadDes(*status, readDes); |
|
367 DPTest::FlushCache(); |
|
368 } |
|
369 break; |
|
370 default: |
|
371 return KErrArgument; |
|
372 } |
|
373 User::WaitForAnyRequest(); |
|
374 r = status->Int(); |
|
375 ldd.Close(); |
|
376 return r; |
|
377 } |
|
378 |
|
379 void RunRealtimeTestThread(TTestAction aTestAction, TTestAccess aAccess, TTestOutcome aExpectedOutcome) |
|
380 { |
|
381 RThread thread; |
|
382 TUint arg = aTestAction | (aAccess << 8); |
|
383 test_KErrNone(thread.Create(KNullDesC, RealtimeTestFunc, 4096, NULL, (TAny*)arg)); |
|
384 TRequestStatus status; |
|
385 thread.Logon(status); |
|
386 thread.Resume(); |
|
387 User::WaitForRequest(status); |
|
388 switch (aExpectedOutcome) |
|
389 { |
|
390 case EOutcomeSuccess: |
|
391 test_Equal(EExitKill, thread.ExitType()); |
|
392 test_Equal(KErrNone, thread.ExitReason()); |
|
393 break; |
|
394 |
|
395 case EOutcomeRealtimePanic: |
|
396 test_Equal(EExitPanic, thread.ExitType()); |
|
397 test_Equal(EIllegalFunctionForRealtimeThread, thread.ExitReason()); |
|
398 break; |
|
399 |
|
400 default: |
|
401 test(EFalse); |
|
402 } |
|
403 CLOSE_AND_WAIT(thread); |
|
404 } |
|
405 |
|
406 void TestPagedAccessInRealtimeThread() |
|
407 { |
|
408 // Test driver access to paged memory from realtime DFC thread. This can happen if a client |
|
409 // passes paged memory to a driver that doesn't expect it, and has set its realtime state to |
|
410 // enfore this. The client should be panicked in this case. |
|
411 |
|
412 test.Start(_L("Test memory access from realtime threads")); |
|
413 test.Next(_L("Load logical device")); |
|
414 TInt r = User::LoadLogicalDevice(KPagingExample1PreLdd); |
|
415 test(r==KErrNone || r==KErrAlreadyExists); |
|
416 |
|
417 test.Next(_L("Test access to unpaged memory from realtime thread")); |
|
418 RunRealtimeTestThread(ETestRequestComplete, EAccessUnpaged, EOutcomeSuccess); |
|
419 RunRealtimeTestThread(ETestRawRead, EAccessUnpaged, EOutcomeSuccess); |
|
420 RunRealtimeTestThread(ETestRawWrite, EAccessUnpaged, EOutcomeSuccess); |
|
421 RunRealtimeTestThread(ETestDesRead, EAccessUnpaged, EOutcomeSuccess); |
|
422 RunRealtimeTestThread(ETestDesWrite, EAccessUnpaged, EOutcomeSuccess); |
|
423 |
|
424 test.Next(_L("Test access to paged memory from realtime thread")); |
|
425 if (PagedInputData) |
|
426 { |
|
427 RunRealtimeTestThread(ETestRawRead, EAccessPaged, EOutcomeRealtimePanic); |
|
428 RunRealtimeTestThread(ETestDesRead, EAccessPaged, EOutcomeRealtimePanic); |
|
429 } |
|
430 if (PagedOutputData) |
|
431 { |
|
432 RunRealtimeTestThread(ETestRequestComplete, EAccessPaged, EOutcomeRealtimePanic); |
|
433 RunRealtimeTestThread(ETestRawWrite, EAccessPaged, EOutcomeRealtimePanic); |
|
434 RunRealtimeTestThread(ETestDesWrite, EAccessPaged, EOutcomeRealtimePanic); |
|
435 } |
|
436 |
|
437 test.Next(_L("Close and free logical device")); |
|
438 test_KErrNone(User::FreeLogicalDevice(KPagingExample1PreLdd)); |
|
439 |
|
440 test.End(); |
|
441 } |
|
442 |
|
443 TInt E32Main() |
|
444 { |
|
445 test.Title(); |
|
446 |
|
447 test.Start(_L("Test device driver migration examples")); |
|
448 |
|
449 UnpagedInputData = (TTestData*)User::Alloc(sizeof(TTestData)); |
|
450 test_NotNull(UnpagedInputData); |
|
451 UnpagedOutputData = (TTestData*)User::Alloc(sizeof(TTestData)); |
|
452 test_NotNull(UnpagedOutputData); |
|
453 |
|
454 test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0)); |
|
455 |
|
456 RChunk chunk; |
|
457 if (DPTest::Attributes() & DPTest::EDataPaging) |
|
458 { |
|
459 TChunkCreateInfo info; |
|
460 TInt size = (sizeof(TTestData) + PageSize - 1) & ~(PageSize - 1); |
|
461 info.SetNormal(size, size); |
|
462 info.SetPaging(TChunkCreateInfo::EPaged); |
|
463 test_KErrNone(chunk.Create(info)); |
|
464 test(chunk.IsPaged()); |
|
465 PagedOutputData = (TTestData*)chunk.Base(); |
|
466 test.Printf(_L("Using data pagd output buffer at %08x\n"), PagedOutputData); |
|
467 } |
|
468 |
|
469 if (DPTest::Attributes() & DPTest::ERomPaging) |
|
470 { |
|
471 // use paged part of rom for read-only data |
|
472 TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress(); |
|
473 test(romHeader->iPageableRomStart); |
|
474 // todo: for some reason the first part of page of paged rom doesn't seem to get paged out |
|
475 // when we flush the paging cache, hence PagedInputData starts some way into this |
|
476 PagedInputData = (TTestData*)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize); |
|
477 TInt romDataSize = romHeader->iPageableRomSize - 64 * PageSize; |
|
478 test(romDataSize >= (TInt)sizeof(TTestData)); |
|
479 test.Printf(_L("Using rom paged input data at %08x\n"), PagedInputData); |
|
480 } |
|
481 else if (DPTest::Attributes() & DPTest::ECodePaging) |
|
482 { |
|
483 // use code paged DLL for read-only buffer |
|
484 test_KErrNone(PagedLibrary.Load(KTCodePagingDll4)); |
|
485 TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal); |
|
486 TInt codeDataSize; |
|
487 PagedInputData = (TTestData*)func(codeDataSize); |
|
488 test_NotNull(PagedInputData); |
|
489 test(codeDataSize >= (TInt)sizeof(TTestData)); |
|
490 test.Printf(_L("Using code paged input data at %08x\n"), PagedInputData); |
|
491 } |
|
492 |
|
493 InitInputData(UnpagedInputData); |
|
494 |
|
495 TestDriver(KPagingExample1PreLdd, EFalse); |
|
496 TestDriver(KPagingExample1PostLdd, ETrue); |
|
497 TestDriver(KPagingExample2PreLdd, EFalse); |
|
498 TestDriver(KPagingExample2PostLdd, ETrue); |
|
499 TestPagedAccessInRealtimeThread(); |
|
500 |
|
501 PagedLibrary.Close(); |
|
502 User::Free(UnpagedInputData); |
|
503 User::Free(UnpagedOutputData); |
|
504 |
|
505 test.End(); |
|
506 return 0; |
|
507 } |