First public contribution.
1 // Copyright (c) 2004-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\mmu\d_memorytest.cpp
18 #include <kernel/kern_priv.h>
19 #include <kernel/cache.h>
20 #include "d_memorytest.h"
26 class DMemoryTestFactory : public DLogicalDevice
29 ~DMemoryTestFactory();
30 virtual TInt Install();
31 virtual void GetCaps(TDes8& aDes) const;
32 virtual TInt Create(DLogicalChannelBase*& aChannel);
35 class DMemoryTestChannel : public DLogicalChannelBase
39 ~DMemoryTestChannel();
40 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
41 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
43 TInt TestAllocZerosMemory();
44 TInt TestReAllocZerosMemory();
47 TInt ReAllocTest2(TUint8*& mem1, TUint8*& mem2, TUint8*& mem3);
48 TInt AllocPhysTest(TUint32 aIters, TUint32 aSize);
49 TInt AllocPhysTest1(TUint32 aIters, TUint32 aSize);
51 DMemoryTestFactory* iFactory;
52 TVirtualPinObject* iVirtualPinObject;
55 TPhysicalPinObject* iObject;
57 TPhysAddr iPhysPageList[KUCPageCount];
59 TUint32 iActualMapAttr;
63 TKernelMapObject* iObject;
64 TPhysAddr iPhysPageList[KUCPageCount];
75 TInt DMemoryTestFactory::Install()
77 return SetName(&KMemoryTestLddName);
80 DMemoryTestFactory::~DMemoryTestFactory()
84 void DMemoryTestFactory::GetCaps(TDes8& /*aDes*/) const
86 // Not used but required as DLogicalDevice::GetCaps is pure virtual
89 TInt DMemoryTestFactory::Create(DLogicalChannelBase*& aChannel)
92 DMemoryTestChannel* channel=new DMemoryTestChannel;
95 channel->iFactory = this;
100 DECLARE_STANDARD_LDD()
102 return new DMemoryTestFactory;
106 // DMemoryTestChannel
109 TInt DMemoryTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
114 DMemoryTestChannel::DMemoryTestChannel()
116 iPageSize = Kern::RoundToPageSize(1);
119 DMemoryTestChannel::~DMemoryTestChannel()
121 Kern::DestroyVirtualPinObject(iVirtualPinObject);
125 TInt DMemoryTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
127 TInt r=KErrNotSupported;
131 case RMemoryTestLdd::EReadWriteMemory:
132 case RMemoryTestLdd::EReadMemory:
133 case RMemoryTestLdd::EWriteMemory:
135 TUint32 value=(TUint32)a2;
137 TInt debugMask = Kern::CurrentThread().iDebugMask;
138 Kern::CurrentThread().iDebugMask = debugMask&~(1<<KPANIC);
141 if(aFunction==RMemoryTestLdd::EReadWriteMemory)
143 kumemget32(&value,a1,4);
144 kumemput32(a1,&value,4);
146 else if(aFunction==RMemoryTestLdd::EReadMemory)
147 kumemget32(&value,a1,4);
148 else if(aFunction==RMemoryTestLdd::EWriteMemory)
149 kumemput32(a1,&value,4);
152 Kern::CurrentThread().iDebugMask = debugMask;
154 if(aFunction==RMemoryTestLdd::EReadMemory)
155 kumemput32(a2,&value,sizeof(value));
160 case RMemoryTestLdd::ETestAllocZerosMemory:
161 case RMemoryTestLdd::ETestReAllocZerosMemory:
163 NKern::ThreadEnterCS();
165 if (aFunction==RMemoryTestLdd::ETestAllocZerosMemory)
166 r=TestAllocZerosMemory();
168 r=TestReAllocZerosMemory();
169 NKern::ThreadLeaveCS();
173 case RMemoryTestLdd::ETestAllocPhysTest:
175 NKern::ThreadEnterCS();
176 r=AllocPhysTest((TUint32)a1,(TUint32)a2);
177 NKern::ThreadLeaveCS();
181 case RMemoryTestLdd::ETestAllocPhysTest1:
183 NKern::ThreadEnterCS();
184 r=AllocPhysTest1((TUint32)a1,(TUint32)a2);
185 NKern::ThreadLeaveCS();
189 case RMemoryTestLdd::ECreateVirtualPinObject:
191 NKern::ThreadEnterCS();
192 r=Kern::CreateVirtualPinObject(iVirtualPinObject);
193 NKern::ThreadLeaveCS();
197 case RMemoryTestLdd::EPinVirtualMemory:
198 return Kern::PinVirtualMemory(iVirtualPinObject, (TLinAddr)a1, (TUint)a2);
200 case RMemoryTestLdd::EUnpinVirtualMemory:
201 Kern::UnpinVirtualMemory(iVirtualPinObject);
204 case RMemoryTestLdd::EDestroyVirtualPinObject:
206 NKern::ThreadEnterCS();
207 Kern::DestroyVirtualPinObject(iVirtualPinObject);
208 NKern::ThreadLeaveCS();
212 case RMemoryTestLdd::ESetPanicTrace:
216 DThread& thread = Kern::CurrentThread();
217 TInt debugMask = thread.iDebugMask;
218 if(debugMask&(1<<KPANIC))
221 debugMask |= (1<<KPANIC);
223 debugMask &= ~(1<<KPANIC);
224 thread.iDebugMask = debugMask;
229 case RMemoryTestLdd::EIsMemoryPresent:
231 return Epoc::LinearToPhysical((TLinAddr)a1) != KPhysAddrInvalid;
233 Kern::PanicCurrentThread(_L("IsMemoryPresent should not be used on the emulator"), KErrNotSupported);
234 return KErrNotSupported;
237 case RMemoryTestLdd::ECreatePhysicalPinObject:
239 NKern::ThreadEnterCS();
240 r=Kern::CreatePhysicalPinObject(iPhysicalPinning.iObject);
241 NKern::ThreadLeaveCS();
245 case RMemoryTestLdd::EPinPhysicalMemory:
246 return Kern::PinPhysicalMemory(iPhysicalPinning.iObject, (TLinAddr)a1, (TUint)a2, EFalse, iPhysicalPinning.iPhysAddr,
247 iPhysicalPinning.iPhysPageList, iPhysicalPinning.iActualMapAttr, iPhysicalPinning.iColour, NULL);
249 case RMemoryTestLdd::EPinPhysicalMemoryRO:
250 return Kern::PinPhysicalMemory(iPhysicalPinning.iObject, (TLinAddr)a1, (TUint)a2, ETrue, iPhysicalPinning.iPhysAddr,
251 iPhysicalPinning.iPhysPageList, iPhysicalPinning.iActualMapAttr, iPhysicalPinning.iColour, NULL);
253 case RMemoryTestLdd::ECheckPageList:
256 return KErrNotSupported;
259 for (i=0;i<KUCPageCount; i++)
261 TPhysAddr addr = Epoc::LinearToPhysical((TLinAddr)a1 + i*iPageSize);
262 if (addr==KPhysAddrInvalid) return KErrGeneral;
263 if (addr!=iPhysicalPinning.iPhysPageList[i]) return KErrNotFound;
269 case RMemoryTestLdd::ESyncPinnedPhysicalMemory:
270 return Cache::SyncPhysicalMemoryBeforeDmaWrite(iPhysicalPinning.iPhysPageList,
271 iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
273 case RMemoryTestLdd::EMovePinnedPhysicalMemory:
276 return KErrNotSupported;
279 NKern::ThreadEnterCS();
280 r = Epoc::MovePhysicalPage(iPhysicalPinning.iPhysPageList[(TUint)a1], newPage);
281 NKern::ThreadLeaveCS();
286 case RMemoryTestLdd::EInvalidatePinnedPhysicalMemory:
288 r = Cache::SyncPhysicalMemoryBeforeDmaRead(iPhysicalPinning.iPhysPageList,
289 iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
291 r = Cache::SyncPhysicalMemoryAfterDmaRead(iPhysicalPinning.iPhysPageList,
292 iPhysicalPinning.iColour, (TUint)a1, (TUint)a2, iPhysicalPinning.iActualMapAttr);
296 case RMemoryTestLdd::EUnpinPhysicalMemory:
297 return Kern::UnpinPhysicalMemory(iPhysicalPinning.iObject);
299 case RMemoryTestLdd::EDestroyPhysicalPinObject:
301 NKern::ThreadEnterCS();
302 r=Kern::DestroyPhysicalPinObject(iPhysicalPinning.iObject);
303 NKern::ThreadLeaveCS();
307 case RMemoryTestLdd::EPinKernelPhysicalMemory:
309 TPhysicalPinObject* pinObject;
313 TUint32 actualMemAttr;
314 NKern::ThreadEnterCS();
315 Kern::CreatePhysicalPinObject(pinObject);
316 r = Kern::PinPhysicalMemory(pinObject, (TLinAddr)&aAddress, 4, EFalse, aAddress, aPages, actualMemAttr, aColour, NULL);
317 Cache::SyncPhysicalMemoryBeforeDmaWrite(aPages, aColour, 10, 30, actualMemAttr);
318 Kern::UnpinPhysicalMemory(pinObject);
319 Kern::DestroyPhysicalPinObject(pinObject);
320 NKern::ThreadLeaveCS();
324 case RMemoryTestLdd::ECreateKernelMapObject:
326 NKern::ThreadEnterCS();
327 r=Kern::CreateKernelMapObject(iKernelMapping.iObject, (TUint)a1);
328 NKern::ThreadLeaveCS();
332 case RMemoryTestLdd::EKernelMapMemory:
333 return Kern::MapAndPinMemory( iKernelMapping.iObject, NULL, (TLinAddr)a1, (TUint)a2, 0,
334 iKernelMapping.iLinAddr, iKernelMapping.iPhysPageList);
336 case RMemoryTestLdd::EKernelMapMemoryRO:
337 return Kern::MapAndPinMemory( iKernelMapping.iObject, NULL, (TLinAddr)a1, (TUint)a2, Kern::EKernelMap_ReadOnly,
338 iKernelMapping.iLinAddr, iKernelMapping.iPhysPageList);
340 case RMemoryTestLdd::EKernelMapMemoryInvalid:
341 return Kern::MapAndPinMemory( iKernelMapping.iObject, NULL, (TLinAddr)a1, (TUint)a2, (TUint)~Kern::EKernelMap_ReadOnly,
342 iKernelMapping.iLinAddr, iKernelMapping.iPhysPageList);
344 case RMemoryTestLdd::EKernelMapCheckPageList:
347 return KErrNotSupported;
350 for (; i < (TUint)KUCPageCount; i++)
352 // Compare the user side address to physical addresses
353 TPhysAddr addr = Epoc::LinearToPhysical((TLinAddr)a1 + i*iPageSize);
354 if (addr == KPhysAddrInvalid)
356 if (addr != iKernelMapping.iPhysPageList[i])
358 // Compare the kernel side address to physical addresses
359 addr = Epoc::LinearToPhysical(iKernelMapping.iLinAddr + i*iPageSize);
360 if (addr == KPhysAddrInvalid)
362 if (addr != iKernelMapping.iPhysPageList[i])
369 case RMemoryTestLdd::EKernelMapSyncMemory:
370 Cache::SyncMemoryBeforeDmaWrite(iKernelMapping.iLinAddr, KUCPageCount*iPageSize);
373 case RMemoryTestLdd::EKernelMapInvalidateMemory:
375 Cache::SyncMemoryBeforeDmaRead(iKernelMapping.iLinAddr, KUCPageCount*iPageSize);
376 Cache::SyncMemoryAfterDmaRead(iKernelMapping.iLinAddr, KUCPageCount*iPageSize);
380 case RMemoryTestLdd::EKernelMapMoveMemory:
383 return KErrNotSupported;
386 NKern::ThreadEnterCS();
387 r = Epoc::MovePhysicalPage(iKernelMapping.iPhysPageList[(TUint)a1], newPage);
388 NKern::ThreadLeaveCS();
393 case RMemoryTestLdd::EKernelMapReadModifyMemory:
395 TUint8* p = (TUint8*)iKernelMapping.iLinAddr;
396 // Verify the contents of the data when accessed via the kernel mapping.
398 for (i = 0; i < KUCPageCount*iPageSize; i++)
400 if (*p++ != (TUint8)i)
403 // Modify the data via the kernel mapping.
404 p = (TUint8*)iKernelMapping.iLinAddr;
405 for (i = 0; i < KUCPageCount*iPageSize; i++)
407 *p++ = (TUint8)(i + 1);
412 case RMemoryTestLdd::EKernelUnmapMemory:
413 Kern::UnmapAndUnpinMemory(iKernelMapping.iObject);
416 case RMemoryTestLdd::EDestroyKernelMapObject:
418 NKern::ThreadEnterCS();
419 Kern::DestroyKernelMapObject(iKernelMapping.iObject);
420 NKern::ThreadLeaveCS();
425 return KErrNotSupported;
429 // Fail a test by returning an error code indicating the problem
430 #define FAIL_ALLOC_TEST(testIndex, byteOffset, unexepectedValue) \
431 err = ((testIndex) << 16) | ((byteOffset) << 8) | (unexepectedValue)
433 TInt DMemoryTestChannel::TestAllocZerosMemory()
436 TInt r = KErrNotSupported;
438 do { //re-try up to 100 times if memory conditions are not correct
440 } while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
445 TInt DMemoryTestChannel::AllocTest1()
447 const TInt KSize = 256;
449 TUint8* mem1 = (TUint8*)Kern::Alloc(KSize);
452 memset(mem1, KSize, 0xff);
454 TUint8* mem2 = (TUint8*)Kern::Alloc(KSize);
458 err = KErrUnknown; // Test inconclusive, can retry
459 for (TInt i = 0 ; i<KSize && err==KErrNone; ++i)
462 FAIL_ALLOC_TEST(1, i, mem2[i]);
469 TInt DMemoryTestChannel::TestReAllocZerosMemory()
472 TInt r = KErrNotSupported;
474 do { //re-try up to 100 times if memory conditions are not correct
476 } while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
482 do { // re-try up to 100 times if memory conditions are not correct
486 r=ReAllocTest2(mem1, mem2, mem3);
493 } while(((r == KErrNoMemory)||(r == KErrUnknown)) && --count);
498 // The actual size of the block allocated given the size requested.
499 #define ALIGNED_SIZE(aReqSize) (_ALIGN_UP(aReqSize + RHeap::EAllocCellSize, RHeap::ECellAlignment) - RHeap::EAllocCellSize)
501 // We only acllocate blocks where the size we get is the size we ask for - this
502 // just makes testing easier.
503 const TInt KSize = ALIGNED_SIZE(200), KHalfSize = ALIGNED_SIZE(100), KSmallSize = ALIGNED_SIZE(50);
505 TInt DMemoryTestChannel::ReAllocTest1()
507 // Test case where cell grows
509 // Expected heap layout:
515 TUint8* mem1 = (TUint8*)Kern::Alloc(KSize); // 1
518 memset(mem1, 0xff, KSize);
519 TUint8* mem2 = (TUint8*)Kern::ReAlloc(mem1, KHalfSize); // 2
524 return KErrUnknown; // Don't expect move on shrink
526 mem2 = (TUint8*)Kern::ReAlloc(mem1, KSize); // 3
531 return KErrUnknown; // Expect growth into original area
535 for (i = 0 ; i<KHalfSize && err==KErrNone; ++i)
538 FAIL_ALLOC_TEST(2, i, mem1[i]);
540 for (i = KHalfSize ; i<KSize && err==KErrNone; ++i)
543 FAIL_ALLOC_TEST(3, i, mem1[i]);
550 TInt DMemoryTestChannel::ReAllocTest2(TUint8*& mem1, TUint8*& mem2, TUint8*& mem3)
552 // Test case where cell is moved
554 // Expected heap layout:
556 // 2: [ mem1 ] [ mem2 ]
557 // 3: [ mem1 ] [ mem2 ] [ mem3 ]
558 // 4: [ mem2 ] [ mem1 ]
560 mem1 = (TUint8*)Kern::Alloc(KSmallSize); // 1
563 memset(mem1, 0xff, KSmallSize);
564 mem2 = (TUint8*)Kern::Alloc(KSmallSize); // 2
567 if (mem2 <= (mem1 + KSmallSize))
568 return KErrUnknown; // Expect mem2 higher than mem1
569 memset(mem2, 0xee, KSmallSize);
570 mem3 = (TUint8*)Kern::Alloc(KSize); // 3
573 if (mem3 <= (mem2 + KSmallSize))
574 return KErrUnknown; // Expect mem3 higher than mem2
575 memset(mem3, 0xdd, KSize);
579 TUint8* mem4 = (TUint8*)Kern::ReAlloc(mem1, KSize); // 4
583 return KErrUnknown; // Expect move on grow
586 return KErrUnknown; // Expect to realloc to use old mem3 space
590 for (i = 0 ; i<KSmallSize && err==KErrNone; ++i)
593 FAIL_ALLOC_TEST(4, i, mem1[i]);
595 for (i = KSmallSize; i<KSize && err==KErrNone; ++i)
598 FAIL_ALLOC_TEST(5, i, mem1[i]);
605 #define CHECK(c) { if(!(c)) { Kern::Printf("Fail %d", __LINE__); ; ret = __LINE__;} }
607 TInt DMemoryTestChannel::AllocPhysTest(TUint32 aIters, TUint32 aSize)
612 TUint32 pageSize = 0;
613 CHECK(Kern::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0)==KErrNone);
614 TUint32 numPages = aSize / pageSize;
616 TPhysAddr* addrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * numPages);
623 for (index = 0; index < aIters; index ++)
625 for (pageIndex = 0; pageIndex < numPages; pageIndex ++)
627 ret = Epoc::AllocPhysicalRam(pageSize, addrArray[pageIndex], 0);
633 for (pageIndex = 0; pageIndex < numPages; pageIndex ++)
635 if (addrArray[pageIndex])
637 Epoc::FreePhysicalRam(addrArray[pageIndex], pageSize);
638 addrArray[pageIndex] = NULL;
647 Kern::Free(addrArray);
653 TInt DMemoryTestChannel::AllocPhysTest(TUint32 , TUint32 )
662 TInt DMemoryTestChannel::AllocPhysTest1(TUint32 aIters, TUint32 aSize)
667 TUint32 pageSize = 0;
668 CHECK(Kern::HalFunction(EHalGroupKernel,EKernelHalPageSizeInBytes,&pageSize,0)==KErrNone);
669 TUint32 numPages = aSize / pageSize;
670 TPhysAddr* addrArray = (TPhysAddr *)Kern::AllocZ(sizeof(TPhysAddr) * numPages);
671 for (index = 0; index < aIters; index ++)
673 ret = Epoc::AllocPhysicalRam(numPages, addrArray);
678 Epoc::FreePhysicalRam(numPages, addrArray);
680 Kern::Free(addrArray);
685 TInt DMemoryTestChannel::AllocPhysTest1(TUint32 , TUint32 )