1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/demandpaging/t_pagingexample.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,507 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\demandpaging\t_pagingexample.cpp
1.18 +// Test device driver migration examples
1.19 +//
1.20 +//
1.21 +
1.22 +#define __E32TEST_EXTENSION__
1.23 +#include <e32test.h>
1.24 +#include <dptest.h>
1.25 +#include <e32hal.h>
1.26 +#include <u32exec.h>
1.27 +#include <e32svr.h>
1.28 +#include <e32panic.h>
1.29 +#include <e32rom.h>
1.30 +#include <e32kpan.h>
1.31 +#include "../mmu/t_codepaging_dll.h"
1.32 +#include "d_pagingexample.h"
1.33 +
1.34 +const TInt KBufferSize = KMaxTransferSize;
1.35 +_LIT(KTCodePagingDll4, "t_codepaging_dll4.dll");
1.36 +
1.37 +struct TTestData
1.38 + {
1.39 + TRequestStatus iStatus;
1.40 + RPagingExample::TConfigData iConfig;
1.41 + RPagingExample::TValueStruct iValue;
1.42 + TInt iIntValue1;
1.43 + TInt iIntValue2;
1.44 + TPtr8 iPtr;
1.45 + TUint8 iBuffer[KBufferSize];
1.46 +public:
1.47 + TTestData() : iPtr(NULL, 0) { }
1.48 + };
1.49 +
1.50 +RTest test(_L("T_PAGINGEXAMPLE"));
1.51 +TInt PageSize = 0;
1.52 +RLibrary PagedLibrary;
1.53 +TTestData* UnpagedInputData = NULL;
1.54 +TTestData* UnpagedOutputData = NULL;
1.55 +TTestData* PagedInputData = NULL;
1.56 +TTestData* PagedOutputData = NULL;
1.57 +
1.58 +void InitInputData(TTestData* aData)
1.59 + {
1.60 + aData->iConfig.iParam1 = 2;
1.61 + aData->iConfig.iParam2 = 3;
1.62 + aData->iConfig.iParam3 = 5;
1.63 + aData->iConfig.iParam4 = 7;
1.64 + for (TInt i = 0 ; i < KBufferSize ; ++i)
1.65 + aData->iBuffer[i] = (TUint8)(i + 123);
1.66 + }
1.67 +
1.68 +void DoTestDriver(const TDesC& aDriverName, const TTestData* aInputData, TTestData* aOutputData)
1.69 + {
1.70 + test.Start(_L("Load logical device"));
1.71 + TInt r = User::LoadLogicalDevice(aDriverName);
1.72 + test(r==KErrNone || r==KErrAlreadyExists);
1.73 +
1.74 + test.Next(_L("Open logical device"));
1.75 + RPagingExample ldd;
1.76 + test_KErrNone(ldd.Open(aDriverName));
1.77 +
1.78 + test.Next(_L("Set config"));
1.79 + DPTest::FlushCache();
1.80 + test_KErrNone(ldd.SetConfig(aInputData->iConfig));
1.81 +
1.82 + test.Next(_L("Get config"));
1.83 + Mem::FillZ(&aOutputData->iConfig, sizeof(RPagingExample::TConfigData));
1.84 + DPTest::FlushCache();
1.85 + test_KErrNone(ldd.GetConfig(aOutputData->iConfig));
1.86 + test_Equal(0, Mem::Compare((TUint8*)&aInputData->iConfig, sizeof(RPagingExample::TConfigData),
1.87 + (TUint8*)&aOutputData->iConfig, sizeof(RPagingExample::TConfigData)));
1.88 +
1.89 + TRequestStatus& status = aOutputData->iStatus;
1.90 +
1.91 + test.Next(_L("Notify"));
1.92 + DPTest::FlushCache();
1.93 + ldd.Notify(status);
1.94 + DPTest::FlushCache();
1.95 + User::WaitForRequest(status);
1.96 + test_Equal(KErrNone, status.Int());
1.97 +
1.98 + test.Next(_L("Async get value"));
1.99 + memclr(&aOutputData->iValue, sizeof(RPagingExample::TValueStruct));
1.100 + DPTest::FlushCache();
1.101 + ldd.AsyncGetValue(status, aOutputData->iValue);
1.102 + DPTest::FlushCache();
1.103 + User::WaitForRequest(status);
1.104 + test_Equal(KErrNone, status.Int());
1.105 + test_Equal(1, aOutputData->iValue.iValue1);
1.106 + test(aOutputData->iValue.iValue2 == _L8("shrt"));
1.107 +
1.108 + test.Next(_L("Cancel async get value"));
1.109 + ldd.AsyncGetValue(status, aOutputData->iValue);
1.110 + ldd.Cancel();
1.111 + User::WaitForRequest(status);
1.112 + test_Equal(KErrCancel, status.Int());
1.113 +
1.114 + test.Next(_L("Async get value 2"));
1.115 + aOutputData->iIntValue1 = 0;
1.116 + aOutputData->iIntValue2 = 0;
1.117 + DPTest::FlushCache();
1.118 + ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2);
1.119 + DPTest::FlushCache();
1.120 + User::WaitForRequest(status);
1.121 + test_Equal(KErrNone, status.Int());
1.122 + test_Equal(1, aOutputData->iIntValue1);
1.123 + test_Equal(2, aOutputData->iIntValue2);
1.124 +
1.125 + test.Next(_L("Cancel async get value 2"));
1.126 + ldd.AsyncGetValue2(status, aOutputData->iIntValue1, aOutputData->iIntValue2);
1.127 + ldd.Cancel();
1.128 + User::WaitForRequest(status);
1.129 + test_Equal(KErrCancel, status.Int());
1.130 +
1.131 + test.Next(_L("Write buffer too short"));
1.132 + ldd.Write(status, NULL, 0);
1.133 + User::WaitForRequest(status);
1.134 + test_Equal(KErrArgument, status.Int());
1.135 +
1.136 + test.Next(_L("Write buffer too long"));
1.137 + ldd.Write(status, NULL, KMaxTransferSize + 1);
1.138 + User::WaitForRequest(status);
1.139 + test_Equal(KErrArgument, status.Int());
1.140 +
1.141 + test.Next(_L("Write"));
1.142 + DPTest::FlushCache();
1.143 + ldd.Write(status, aInputData->iBuffer, KBufferSize);
1.144 + DPTest::FlushCache();
1.145 + User::WaitForRequest(status);
1.146 + test_KErrNone(status.Int());
1.147 +
1.148 + test.Next(_L("Cancel write"));
1.149 + ldd.Write(status, aInputData->iBuffer, KBufferSize);
1.150 + ldd.Cancel();
1.151 + User::WaitForRequest(status);
1.152 + test_Equal(KErrCancel, status.Int());
1.153 +
1.154 + test.Next(_L("Read buffer too short"));
1.155 + ldd.Read(status, NULL, 0);
1.156 + User::WaitForRequest(status);
1.157 + test_Equal(KErrArgument, status.Int());
1.158 +
1.159 + test.Next(_L("Read buffer too long"));
1.160 + ldd.Read(status, NULL, KMaxTransferSize + 1);
1.161 + User::WaitForRequest(status);
1.162 + test_Equal(KErrArgument, status.Int());
1.163 +
1.164 + test.Next(_L("Read"));
1.165 + Mem::FillZ(aOutputData->iBuffer, KBufferSize);
1.166 + DPTest::FlushCache();
1.167 + ldd.Read(status, aOutputData->iBuffer, KBufferSize);
1.168 + DPTest::FlushCache();
1.169 + User::WaitForRequest(status);
1.170 + test_KErrNone(status.Int());
1.171 + test_Equal(0, Mem::Compare(aInputData->iBuffer, KBufferSize,
1.172 + aOutputData->iBuffer, KBufferSize));
1.173 +
1.174 + test.Next(_L("Cancel read"));
1.175 + ldd.Read(status, aOutputData->iBuffer, KBufferSize);
1.176 + ldd.Cancel();
1.177 + User::WaitForRequest(status);
1.178 + test_Equal(KErrCancel, status.Int());
1.179 +
1.180 + test.Next(_L("Cancel nothing"));
1.181 + ldd.Cancel();
1.182 +
1.183 + test.Next(_L("Write while write pending"));
1.184 + TRequestStatus status2;
1.185 + ldd.Write(status, aInputData->iBuffer, KBufferSize);
1.186 + ldd.Write(status2, aInputData->iBuffer, KBufferSize);
1.187 + User::WaitForRequest(status);
1.188 + test_KErrNone(status.Int());
1.189 + User::WaitForRequest(status2);
1.190 + test_Equal(KErrInUse, status2.Int());
1.191 +
1.192 + test.Next(_L("Read while read pending"));
1.193 + ldd.Read(status, aOutputData->iBuffer, KBufferSize);
1.194 + ldd.Read(status2, aOutputData->iBuffer, KBufferSize);
1.195 + User::WaitForRequest(status);
1.196 + test_KErrNone(status.Int());
1.197 + User::WaitForRequest(status2);
1.198 + test_Equal(KErrInUse, status2.Int());
1.199 +
1.200 + test.Next(_L("Write des"));
1.201 + TPtrC8 writeDes(aInputData->iBuffer + 1, KBufferSize - 1);
1.202 + DPTest::FlushCache();
1.203 + ldd.WriteDes(status, writeDes);
1.204 + DPTest::FlushCache();
1.205 + User::WaitForRequest(status);
1.206 + test_KErrNone(status.Int());
1.207 +
1.208 + test.Next(_L("Cancel write des"));
1.209 + ldd.WriteDes(status, writeDes);
1.210 + ldd.Cancel();
1.211 + User::WaitForRequest(status);
1.212 + test_Equal(KErrCancel, status.Int());
1.213 +
1.214 + test.Next(_L("Read des"));
1.215 + TPtr8 readDes(aOutputData->iBuffer, KBufferSize - 1);
1.216 + Mem::FillZ(aOutputData->iBuffer, KBufferSize);
1.217 + DPTest::FlushCache();
1.218 + ldd.ReadDes(status, readDes);
1.219 + DPTest::FlushCache();
1.220 + User::WaitForRequest(status);
1.221 + test_KErrNone(status.Int());
1.222 + test(readDes == writeDes);
1.223 +
1.224 + test.Next(_L("Read des 2")); // has paged header but unpaged contnet, if output data is paged
1.225 + aOutputData->iPtr.Set(UnpagedOutputData->iBuffer, 0, KBufferSize - 1);
1.226 + Mem::FillZ(UnpagedOutputData->iBuffer, KBufferSize);
1.227 + DPTest::FlushCache();
1.228 + ldd.ReadDes(status, aOutputData->iPtr);
1.229 + DPTest::FlushCache();
1.230 + User::WaitForRequest(status);
1.231 + test_KErrNone(status.Int());
1.232 + test(aOutputData->iPtr == writeDes);
1.233 +
1.234 + test.Next(_L("Cancel read des"));
1.235 + ldd.ReadDes(status, readDes);
1.236 + ldd.Cancel();
1.237 + User::WaitForRequest(status);
1.238 + test_Equal(KErrCancel, status.Int());
1.239 +
1.240 + test.Next(_L("Read and write at the same time"));
1.241 + ldd.Write(status, aInputData->iBuffer, KBufferSize);
1.242 + ldd.Read(status2, aOutputData->iBuffer, KBufferSize);
1.243 + DPTest::FlushCache();
1.244 + User::WaitForRequest(status);
1.245 + test_KErrNone(status.Int());
1.246 + User::WaitForRequest(status2);
1.247 + test_KErrNone(status2.Int());
1.248 +
1.249 + test.Next(_L("Cancel read and write"));
1.250 + ldd.Write(status, aInputData->iBuffer, KBufferSize);
1.251 + ldd.Read(status2, aOutputData->iBuffer, KBufferSize);
1.252 + ldd.Cancel();
1.253 + User::WaitForRequest(status);
1.254 + test_Equal(KErrCancel, status.Int());
1.255 + User::WaitForRequest(status2);
1.256 + test_Equal(KErrCancel, status2.Int());
1.257 +
1.258 + test.Next(_L("Close and free logical device"));
1.259 + ldd.Close();
1.260 + test_KErrNone(User::FreeLogicalDevice(aDriverName));
1.261 +
1.262 + test.End();
1.263 + }
1.264 +
1.265 +void TestDriver(const TDesC& aDriverName, TBool aMigrated)
1.266 + {
1.267 + TBuf<64> string;
1.268 + string.Format(_L("Testing driver %S"), &aDriverName);
1.269 + test.Next(string);
1.270 +
1.271 + test.Start(_L("Test reading from unpaged memory and writing to unpaged memory"));
1.272 + DoTestDriver(aDriverName, UnpagedInputData, UnpagedOutputData);
1.273 +
1.274 + if (aMigrated && PagedInputData)
1.275 + {
1.276 + if (PagedOutputData)
1.277 + {
1.278 + test.Next(_L("Test reading from paged memory and writing to paged memory"));
1.279 + DoTestDriver(aDriverName, PagedInputData, PagedOutputData);
1.280 + }
1.281 + else
1.282 + {
1.283 + test.Next(_L("Test reading from paged memory and writing to unpaged memory"));
1.284 + DoTestDriver(aDriverName, PagedInputData, UnpagedOutputData);
1.285 + }
1.286 + }
1.287 +
1.288 + // todo: test pinning failures
1.289 +
1.290 + test.End();
1.291 + }
1.292 +
1.293 +enum TTestAction
1.294 + {
1.295 + ETestRequestComplete,
1.296 + ETestRawRead,
1.297 + ETestRawWrite,
1.298 + ETestDesRead,
1.299 + ETestDesWrite
1.300 + };
1.301 +
1.302 +enum TTestAccess
1.303 + {
1.304 + EAccessUnpaged,
1.305 + EAccessPaged
1.306 + };
1.307 +
1.308 +enum TTestOutcome
1.309 + {
1.310 + EOutcomeSuccess,
1.311 + EOutcomeRealtimePanic
1.312 + };
1.313 +
1.314 +TInt RealtimeTestFunc(TAny* aArg)
1.315 + {
1.316 + TTestAction action = (TTestAction)((TUint)aArg & 255);
1.317 + TTestAccess access = (TTestAccess)((TUint)aArg >> 8);
1.318 +
1.319 + TTestData* inputData = access == EAccessPaged ? PagedInputData : UnpagedInputData;
1.320 + TTestData* outputData = access == EAccessPaged ? PagedOutputData : UnpagedOutputData;
1.321 +
1.322 + RPagingExample ldd;
1.323 + TInt r = ldd.Open(KPagingExample1PreLdd);
1.324 + if (r != KErrNone)
1.325 + return r;
1.326 + ldd.SetDfcThreadRealtimeState(ETrue);
1.327 +
1.328 + TRequestStatus unpagedStatus;
1.329 + TRequestStatus* status = &unpagedStatus;
1.330 +
1.331 + switch(action)
1.332 + {
1.333 + case ETestRequestComplete:
1.334 + {
1.335 + RDebug::Printf("Test RequestComplete");
1.336 + status = &outputData->iStatus;
1.337 + RPagingExample::TValueStruct value;
1.338 + DPTest::FlushCache();
1.339 + ldd.AsyncGetValue(*status, value);
1.340 + DPTest::FlushCache();
1.341 + }
1.342 + break;
1.343 +
1.344 + case ETestRawRead:
1.345 + RDebug::Printf("Test ThreadRawRead");
1.346 + ldd.Write(*status, inputData->iBuffer, KBufferSize);
1.347 + DPTest::FlushCache();
1.348 + break;
1.349 +
1.350 + case ETestRawWrite:
1.351 + RDebug::Printf("Test ThreadRawWrite");
1.352 + ldd.Read(*status, outputData->iBuffer, KBufferSize);
1.353 + DPTest::FlushCache();
1.354 + break;
1.355 +
1.356 + case ETestDesRead:
1.357 + {
1.358 + RDebug::Printf("Test ThreadDesRead");
1.359 + TPtrC8 writeDes(inputData->iBuffer, KBufferSize);
1.360 + ldd.WriteDes(*status, writeDes);
1.361 + DPTest::FlushCache();
1.362 + }
1.363 + break;
1.364 +
1.365 + case ETestDesWrite:
1.366 + {
1.367 + RDebug::Printf("Test ThreadDesWrite");
1.368 + TPtr8 readDes(outputData->iBuffer, KBufferSize);
1.369 + ldd.ReadDes(*status, readDes);
1.370 + DPTest::FlushCache();
1.371 + }
1.372 + break;
1.373 + default:
1.374 + return KErrArgument;
1.375 + }
1.376 + User::WaitForAnyRequest();
1.377 + r = status->Int();
1.378 + ldd.Close();
1.379 + return r;
1.380 + }
1.381 +
1.382 +void RunRealtimeTestThread(TTestAction aTestAction, TTestAccess aAccess, TTestOutcome aExpectedOutcome)
1.383 + {
1.384 + RThread thread;
1.385 + TUint arg = aTestAction | (aAccess << 8);
1.386 + test_KErrNone(thread.Create(KNullDesC, RealtimeTestFunc, 4096, NULL, (TAny*)arg));
1.387 + TRequestStatus status;
1.388 + thread.Logon(status);
1.389 + thread.Resume();
1.390 + User::WaitForRequest(status);
1.391 + switch (aExpectedOutcome)
1.392 + {
1.393 + case EOutcomeSuccess:
1.394 + test_Equal(EExitKill, thread.ExitType());
1.395 + test_Equal(KErrNone, thread.ExitReason());
1.396 + break;
1.397 +
1.398 + case EOutcomeRealtimePanic:
1.399 + test_Equal(EExitPanic, thread.ExitType());
1.400 + test_Equal(EIllegalFunctionForRealtimeThread, thread.ExitReason());
1.401 + break;
1.402 +
1.403 + default:
1.404 + test(EFalse);
1.405 + }
1.406 + CLOSE_AND_WAIT(thread);
1.407 + }
1.408 +
1.409 +void TestPagedAccessInRealtimeThread()
1.410 + {
1.411 + // Test driver access to paged memory from realtime DFC thread. This can happen if a client
1.412 + // passes paged memory to a driver that doesn't expect it, and has set its realtime state to
1.413 + // enfore this. The client should be panicked in this case.
1.414 +
1.415 + test.Start(_L("Test memory access from realtime threads"));
1.416 + test.Next(_L("Load logical device"));
1.417 + TInt r = User::LoadLogicalDevice(KPagingExample1PreLdd);
1.418 + test(r==KErrNone || r==KErrAlreadyExists);
1.419 +
1.420 + test.Next(_L("Test access to unpaged memory from realtime thread"));
1.421 + RunRealtimeTestThread(ETestRequestComplete, EAccessUnpaged, EOutcomeSuccess);
1.422 + RunRealtimeTestThread(ETestRawRead, EAccessUnpaged, EOutcomeSuccess);
1.423 + RunRealtimeTestThread(ETestRawWrite, EAccessUnpaged, EOutcomeSuccess);
1.424 + RunRealtimeTestThread(ETestDesRead, EAccessUnpaged, EOutcomeSuccess);
1.425 + RunRealtimeTestThread(ETestDesWrite, EAccessUnpaged, EOutcomeSuccess);
1.426 +
1.427 + test.Next(_L("Test access to paged memory from realtime thread"));
1.428 + if (PagedInputData)
1.429 + {
1.430 + RunRealtimeTestThread(ETestRawRead, EAccessPaged, EOutcomeRealtimePanic);
1.431 + RunRealtimeTestThread(ETestDesRead, EAccessPaged, EOutcomeRealtimePanic);
1.432 + }
1.433 + if (PagedOutputData)
1.434 + {
1.435 + RunRealtimeTestThread(ETestRequestComplete, EAccessPaged, EOutcomeRealtimePanic);
1.436 + RunRealtimeTestThread(ETestRawWrite, EAccessPaged, EOutcomeRealtimePanic);
1.437 + RunRealtimeTestThread(ETestDesWrite, EAccessPaged, EOutcomeRealtimePanic);
1.438 + }
1.439 +
1.440 + test.Next(_L("Close and free logical device"));
1.441 + test_KErrNone(User::FreeLogicalDevice(KPagingExample1PreLdd));
1.442 +
1.443 + test.End();
1.444 + }
1.445 +
1.446 +TInt E32Main()
1.447 + {
1.448 + test.Title();
1.449 +
1.450 + test.Start(_L("Test device driver migration examples"));
1.451 +
1.452 + UnpagedInputData = (TTestData*)User::Alloc(sizeof(TTestData));
1.453 + test_NotNull(UnpagedInputData);
1.454 + UnpagedOutputData = (TTestData*)User::Alloc(sizeof(TTestData));
1.455 + test_NotNull(UnpagedOutputData);
1.456 +
1.457 + test_KErrNone(UserSvr::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&PageSize,0));
1.458 +
1.459 + RChunk chunk;
1.460 + if (DPTest::Attributes() & DPTest::EDataPaging)
1.461 + {
1.462 + TChunkCreateInfo info;
1.463 + TInt size = (sizeof(TTestData) + PageSize - 1) & ~(PageSize - 1);
1.464 + info.SetNormal(size, size);
1.465 + info.SetPaging(TChunkCreateInfo::EPaged);
1.466 + test_KErrNone(chunk.Create(info));
1.467 + test(chunk.IsPaged());
1.468 + PagedOutputData = (TTestData*)chunk.Base();
1.469 + test.Printf(_L("Using data pagd output buffer at %08x\n"), PagedOutputData);
1.470 + }
1.471 +
1.472 + if (DPTest::Attributes() & DPTest::ERomPaging)
1.473 + {
1.474 + // use paged part of rom for read-only data
1.475 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.476 + test(romHeader->iPageableRomStart);
1.477 + // todo: for some reason the first part of page of paged rom doesn't seem to get paged out
1.478 + // when we flush the paging cache, hence PagedInputData starts some way into this
1.479 + PagedInputData = (TTestData*)((TUint8*)romHeader + romHeader->iPageableRomStart + 64 * PageSize);
1.480 + TInt romDataSize = romHeader->iPageableRomSize - 64 * PageSize;
1.481 + test(romDataSize >= (TInt)sizeof(TTestData));
1.482 + test.Printf(_L("Using rom paged input data at %08x\n"), PagedInputData);
1.483 + }
1.484 + else if (DPTest::Attributes() & DPTest::ECodePaging)
1.485 + {
1.486 + // use code paged DLL for read-only buffer
1.487 + test_KErrNone(PagedLibrary.Load(KTCodePagingDll4));
1.488 + TGetAddressOfDataFunction func = (TGetAddressOfDataFunction)PagedLibrary.Lookup(KGetAddressOfDataFunctionOrdinal);
1.489 + TInt codeDataSize;
1.490 + PagedInputData = (TTestData*)func(codeDataSize);
1.491 + test_NotNull(PagedInputData);
1.492 + test(codeDataSize >= (TInt)sizeof(TTestData));
1.493 + test.Printf(_L("Using code paged input data at %08x\n"), PagedInputData);
1.494 + }
1.495 +
1.496 + InitInputData(UnpagedInputData);
1.497 +
1.498 + TestDriver(KPagingExample1PreLdd, EFalse);
1.499 + TestDriver(KPagingExample1PostLdd, ETrue);
1.500 + TestDriver(KPagingExample2PreLdd, EFalse);
1.501 + TestDriver(KPagingExample2PostLdd, ETrue);
1.502 + TestPagedAccessInRealtimeThread();
1.503 +
1.504 + PagedLibrary.Close();
1.505 + User::Free(UnpagedInputData);
1.506 + User::Free(UnpagedOutputData);
1.507 +
1.508 + test.End();
1.509 + return 0;
1.510 + }