1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/mmu/t_shadow.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,484 @@
1.4 +// Copyright (c) 1997-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\mmu\t_shadow.cpp
1.18 +// Overview:
1.19 +// Test ROM shadowing
1.20 +// API Information:
1.21 +// RBusLogicalChannel
1.22 +// Details:
1.23 +// - Load and open the logical device driver ("D_SHADOW.LDD"). Verify
1.24 +// results.
1.25 +// - Allocate a shadow ROM page, verify data is copied into shadow page
1.26 +// without altering the following page.
1.27 +// - Move the shadow page and the original rom page.
1.28 +// - Write and verify data in the shadow page.
1.29 +// - Free the shadow page and verify original ROM data is restored.
1.30 +// - Test pinning of shadow pages.
1.31 +// Platforms/Drives/Compatibility:
1.32 +// All.
1.33 +// Assumptions/Requirement/Pre-requisites:
1.34 +// Failures and causes:
1.35 +// Base Port information:
1.36 +//
1.37 +//
1.38 +
1.39 +#define __E32TEST_EXTENSION__
1.40 +
1.41 +#include <e32test.h>
1.42 +#include <e32uid.h>
1.43 +#include <e32hal.h>
1.44 +#include "d_shadow.h"
1.45 +#include "d_gobble.h"
1.46 +#include "..\defrag\d_pagemove.h"
1.47 +#include "d_memorytest.h"
1.48 +#include <dptest.h>
1.49 +#include "mmudetect.h"
1.50 +#include "freeram.h"
1.51 +
1.52 +enum TPaged
1.53 + {
1.54 + EUnpaged,
1.55 + EPaged
1.56 + };
1.57 +
1.58 +_LIT(KLddFileName, "D_SHADOW.LDD");
1.59 +_LIT(KMoveLddFileName, "D_PAGEMOVE.LDD");
1.60 +
1.61 +LOCAL_D RTest test(_L("T_SHADOW"));
1.62 +
1.63 +RPageMove PageMove;
1.64 +RShadow Shadow;
1.65 +RMemoryTestLdd MemoryTest;
1.66 +
1.67 +TInt PageSize;
1.68 +LOCAL_D TBool RomPagingSupported = EFalse;
1.69 +#ifndef __X86__
1.70 +LOCAL_D TBool PageMovingSupported = ETrue;
1.71 +#else
1.72 +LOCAL_D TBool PageMovingSupported = EFalse;
1.73 +#endif
1.74 +
1.75 +TLinAddr RomUnpagedStart = 0;
1.76 +TLinAddr RomUnpagedEnd = 0;
1.77 +TLinAddr RomPagedStart = 0;
1.78 +TLinAddr RomPagedEnd = 0;
1.79 +
1.80 +TUint8* PageBuffer1 = NULL;
1.81 +TUint8* PageBuffer2 = NULL;
1.82 +TUint8* PageBuffer3 = NULL;
1.83 +
1.84 +void TestShadowPage(TLinAddr aPageAddr, TPaged aPageType)
1.85 + {
1.86 + test.Start(_L("Test shadowing a page"));
1.87 + test.Printf(_L(" addr == 0x%08x, type == %d\n"), aPageAddr, aPageType);
1.88 +
1.89 + test.Next(_L("Copy page to be shadowed and following page to local buffers"));
1.90 + TLinAddr secondPage = aPageAddr + PageSize;
1.91 + if (secondPage >= RomPagedEnd)
1.92 + secondPage = RomUnpagedStart;
1.93 + Mem::Move(PageBuffer1,(TAny*)aPageAddr,PageSize);
1.94 + Mem::Move(PageBuffer3,(TAny*)(secondPage),PageSize);
1.95 +
1.96 + TUint origPhysAddr = 0xffffffff; // The physical address of the rom page to be shadowed
1.97 +
1.98 + if (PageMovingSupported && aPageType == EPaged)
1.99 + {
1.100 + test.Next(_L("Test page can be moved"));
1.101 + TUint dummy = *(volatile TUint32*)aPageAddr; // ensure paged in
1.102 + test_KErrNone(PageMove.TryMovingUserPage((TAny*)aPageAddr));
1.103 +
1.104 + test.Next(_L("Get page's physical address"));
1.105 + dummy += *(volatile TUint32*)aPageAddr; // ensure paged in
1.106 + test_KErrNone(PageMove.GetPhysAddr((TAny*)aPageAddr, (TAny*)&origPhysAddr));
1.107 + test.Printf(_L(" physical address: %08x\n"), origPhysAddr);
1.108 + }
1.109 +
1.110 + test.Next(_L("Allocate a shadow ROM page"));
1.111 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.112 +
1.113 + test.Next(_L("Try to shadow the page again"));
1.114 + test_Equal(KErrAlreadyExists, Shadow.Alloc(aPageAddr));
1.115 +
1.116 + if (PageMovingSupported && aPageType == EPaged)
1.117 + {
1.118 + test.Next(_L("Check page's physical address has changed"));
1.119 + TUint newPhysAddr;
1.120 + test_KErrNone(PageMove.GetPhysAddr((TAny*)aPageAddr, (TAny*)&newPhysAddr));
1.121 + test(newPhysAddr != origPhysAddr);
1.122 +
1.123 + test.Next(_L("Test moving a shadowed page is not allowed"));
1.124 + test_Equal(KErrNotSupported, PageMove.TryMovingUserPage((TAny*)aPageAddr));
1.125 +
1.126 + test.Next(_L("Test moving the original page fails (it should be pinned)"));
1.127 + test_Equal(KErrInUse, PageMove.TryMovingPhysAddr((TAny*)origPhysAddr, (TAny*)&newPhysAddr));
1.128 + }
1.129 +
1.130 + test.Next(_L("Check data copied into shadow page"));
1.131 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer1,PageSize));
1.132 +
1.133 + test.Next(_L("Check page following shadow page is unaltered"));
1.134 + test_Equal(0, Mem::Compare((TUint8*)(secondPage),PageSize,PageBuffer3,PageSize));
1.135 +
1.136 + test.Next(_L("Write data into shadow page"));
1.137 + for(TInt i=0; i<PageSize; i++)
1.138 + {
1.139 + TInt i2=i*i;
1.140 + PageBuffer2[i]=TUint8(i2^(i2>>8)^(i2>>16));
1.141 + }
1.142 + test_KErrNone(Shadow.Write(aPageAddr,PageBuffer2));
1.143 +
1.144 + test.Next(_L("Check data written into shadow page"));
1.145 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer2,PageSize));
1.146 +
1.147 + test.Next(_L("Check page following shadow page is unaltered"));
1.148 + test_Equal(0, Mem::Compare((TUint8*)(secondPage),PageSize,PageBuffer3,PageSize));
1.149 +
1.150 + test.Next(_L("Allocate another shadow ROM page"));
1.151 + test_KErrNone(Shadow.Alloc(secondPage));
1.152 +
1.153 + test.Next(_L("Free the original shadow page"));
1.154 + test_KErrNone(Shadow.Free(aPageAddr));
1.155 +
1.156 + test.Next(_L("Check original ROM data restored"));
1.157 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer1,PageSize));
1.158 +
1.159 + if (PageMovingSupported && aPageType == EPaged)
1.160 + {
1.161 + test.Next(_L("Test page can be moved again"));
1.162 + test_KErrNone(PageMove.TryMovingUserPage((TAny*)aPageAddr));
1.163 + }
1.164 +
1.165 + test.Next(_L("Free the second shadow page"));
1.166 + test_KErrNone(Shadow.Free(secondPage));
1.167 +
1.168 + test.Next(_L("Check original ROM data restored"));
1.169 + test_Equal(0, Mem::Compare((TUint8*)(secondPage),PageSize,PageBuffer3,PageSize));
1.170 + test.End();
1.171 + }
1.172 +
1.173 +/*
1.174 + Reintroduce this when RTest can report whether the test is
1.175 + being run in automatic or manual mode
1.176 +*/
1.177 +void TestFreeze(TLinAddr aPageAddr)
1.178 + {
1.179 + test.Start(_L("Test freezing a shadow page"));
1.180 + test.Printf(_L("Press 0 to test Freeze (causes kernel fault)\n"));
1.181 + test.Printf(_L("Press any other key to skip this test\n"));
1.182 + TKeyCode key=test.Getch();
1.183 + if (key==TKeyCode('0'))
1.184 + {
1.185 + test.Next(_L("Freeze first shadow page"));
1.186 + test_KErrNone(Shadow.Freeze(aPageAddr));
1.187 +
1.188 + test.Printf(_L("Press a key to attempt write after freezing\n"));
1.189 + test.Printf(_L("Should get Kernel Exception 9, Data Address 50000xxx\n"));
1.190 + test.Getch();
1.191 + Shadow.Write(aPageAddr,PageBuffer2);
1.192 + test(0);
1.193 + }
1.194 + test.End();
1.195 + }
1.196 +
1.197 +void TestNoFreeRAM(TLinAddr aPageAddr)
1.198 + {
1.199 + test.Start(_L("Test allocating a shadow page when all free RAM is in 'chunk caches'"));
1.200 +
1.201 + test.Next(_L("Load gobbler LDD"));
1.202 + TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
1.203 + test_Value(r, r==KErrNone || r==KErrAlreadyExists);
1.204 + RGobbler gobbler;
1.205 + test_KErrNone(gobbler.Open());
1.206 + TUint32 taken = gobbler.GobbleRAM(496*1024*1024);
1.207 + test.Printf(_L(" Gobbled: %dK\n"), taken/1024);
1.208 + test.Printf(_L(" Free RAM 0x%08X bytes\n"),FreeRam());
1.209 +
1.210 + // Remove limit on max size of live list
1.211 + TUint originalMin = 0;
1.212 + TUint originalMax = 0;
1.213 + TUint currentSize = 0;
1.214 + r = DPTest::CacheSize(originalMin, originalMax, currentSize);
1.215 + test_Value(r, r == KErrNone || r == KErrNotSupported);
1.216 + TBool resizeCache = r == KErrNone;
1.217 + if (resizeCache)
1.218 + test_KErrNone(DPTest::SetCacheSize(originalMin, KMaxTUint));
1.219 +
1.220 + // put all of free RAM in a chunk...
1.221 + TChunkCreateInfo createInfo;
1.222 + createInfo.SetCache(512*1024*1024);
1.223 + RChunk testChunk;
1.224 + test_KErrNone(testChunk.Create(createInfo));
1.225 + TInt commitEnd = 0;
1.226 + while(KErrNone==(r=testChunk.Commit(commitEnd,PageSize)))
1.227 + commitEnd += PageSize;
1.228 + test_Equal(KErrNoMemory,r);
1.229 +
1.230 + // no memory to allocate shadow page...
1.231 + test_Equal(KErrNoMemory,Shadow.Alloc(aPageAddr));
1.232 + // unlock all of RAM in chunk...
1.233 + test_KErrNone(testChunk.Unlock(0,commitEnd));
1.234 + // should have memory now...
1.235 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.236 + // tidy up...
1.237 + test_KErrNone(Shadow.Free(aPageAddr));
1.238 + testChunk.Close();
1.239 +
1.240 + // Restore original settings for live list size
1.241 + if (resizeCache)
1.242 + test_KErrNone(DPTest::SetCacheSize(originalMin, originalMax));
1.243 +
1.244 + gobbler.Close();
1.245 + test.End();
1.246 + }
1.247 +
1.248 +void TestShadowPageOOM(TLinAddr aPageAddr)
1.249 + {
1.250 + test.Start(_L("Test OOM while shadowing a page"));
1.251 + test.Printf(_L(" addr == 0x%08x\n"), aPageAddr);
1.252 +
1.253 + test.Next(_L("Copy page to be shadowed and following page to local buffers"));
1.254 + Mem::Move(PageBuffer1,(TAny*)aPageAddr,PageSize);
1.255 +
1.256 + __KHEAP_MARK;
1.257 +
1.258 + TInt r;
1.259 + TInt failCount = 0;
1.260 + test.Next(_L("Allocate a shadow ROM page"));
1.261 + do
1.262 + {
1.263 + __KHEAP_FAILNEXT(failCount);
1.264 + r = Shadow.Alloc(aPageAddr);
1.265 + if (r == KErrNoMemory)
1.266 + ++failCount;
1.267 + }
1.268 + while (r == KErrNoMemory);
1.269 + __KHEAP_RESET;
1.270 + test.Printf(_L(" returned %d after %d allocations\n"), r, failCount);
1.271 + test_KErrNone(r);
1.272 +
1.273 + test.Next(_L("Try to shadow the page again"));
1.274 + __KHEAP_FAILNEXT(0);
1.275 + test_Equal(KErrAlreadyExists, Shadow.Alloc(aPageAddr));
1.276 + __KHEAP_RESET;
1.277 +
1.278 + test.Next(_L("Check data copied into shadow page"));
1.279 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer1,PageSize));
1.280 +
1.281 + test.Next(_L("Write data into shadow page"));
1.282 + for(TInt i=0; i<PageSize; i++)
1.283 + {
1.284 + TInt i2=i*i;
1.285 + PageBuffer2[i]=TUint8(i2^(i2>>8)^(i2>>16));
1.286 + }
1.287 + test_KErrNone(Shadow.Write(aPageAddr,PageBuffer2));
1.288 +
1.289 + test.Next(_L("Check data written into shadow page"));
1.290 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer2,PageSize));
1.291 +
1.292 + test.Next(_L("Free the original shadow page"));
1.293 + __KHEAP_FAILNEXT(0);
1.294 + test_KErrNone(Shadow.Free(aPageAddr));
1.295 + __KHEAP_RESET;
1.296 +
1.297 + test.Next(_L("Check original ROM data restored"));
1.298 + test_Equal(0, Mem::Compare((TUint8*)aPageAddr,PageSize,PageBuffer1,PageSize));
1.299 +
1.300 + test.Next(_L("Check kernel heap balance"));
1.301 + __KHEAP_MARKEND;
1.302 +
1.303 + test.End();
1.304 + }
1.305 +
1.306 +void TestInteractionWithPinning(TLinAddr aPageAddr)
1.307 + {
1.308 + test.Start(_L("Test pinning of shadow pages"));
1.309 +
1.310 + // Create pin object to use for all pinnings
1.311 + test_KErrNone(MemoryTest.CreateVirtualPinObject());
1.312 +
1.313 + test.Next(_L("Test pin - shadow - unpin - unshadow"));
1.314 + test_Equal(KErrNone, MemoryTest.PinVirtualMemory((TLinAddr)aPageAddr, PageSize));
1.315 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.316 + test_Equal(KErrNone, MemoryTest.UnpinVirtualMemory());
1.317 + test_KErrNone(Shadow.Free(aPageAddr));
1.318 +
1.319 + test.Next(_L("Test pin - shadow - unshadow - unpin"));
1.320 + test_Equal(KErrNone, MemoryTest.PinVirtualMemory((TLinAddr)aPageAddr, PageSize));
1.321 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.322 + test_KErrNone(Shadow.Free(aPageAddr));
1.323 + test_Equal(KErrNone, MemoryTest.UnpinVirtualMemory());
1.324 +
1.325 + test.Next(_L("Test shadow - pin - unpin - unshadow"));
1.326 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.327 + test_Equal(KErrNone, MemoryTest.PinVirtualMemory((TLinAddr)aPageAddr, PageSize));
1.328 + test_Equal(KErrNone, MemoryTest.UnpinVirtualMemory());
1.329 + test_KErrNone(Shadow.Free(aPageAddr));
1.330 +
1.331 + test.Next(_L("Test shadow - pin - unshadow - unpin"));
1.332 + test_KErrNone(Shadow.Alloc(aPageAddr));
1.333 + test_Equal(KErrNone, MemoryTest.PinVirtualMemory((TLinAddr)aPageAddr, PageSize));
1.334 + test_KErrNone(Shadow.Free(aPageAddr));
1.335 + test_Equal(KErrNone, MemoryTest.UnpinVirtualMemory());
1.336 +
1.337 + test_KErrNone(MemoryTest.DestroyVirtualPinObject());
1.338 + test.End();
1.339 + }
1.340 +
1.341 +const TUint KChunkShift = 20;
1.342 +const TUint KChunkSize = 1 << KChunkShift;
1.343 +
1.344 +void TestRomIsSectionMapped()
1.345 + {
1.346 + test.Start(_L("Test ROM is section mapped"));
1.347 +
1.348 + TUint pdSize;
1.349 + TUint pdBase;
1.350 + TUint offset;
1.351 +
1.352 +#ifdef __MARM__
1.353 + test_KErrNone(Shadow.GetPdInfo(KGlobalPageDirectory, pdSize, pdBase, offset));
1.354 + test.Printf(_L("pd base == %08x, pd size == %08x, pd offset == %08x\n"), pdBase, pdSize, offset);
1.355 +
1.356 + for (TLinAddr addr = RomUnpagedStart ; addr <= RomUnpagedEnd ; addr += KChunkSize)
1.357 + {
1.358 + TUint i = (addr >> KChunkShift) - offset;
1.359 + TUint pde = Shadow.Read(pdBase + i*4);
1.360 + test.Printf(_L(" %08x: PDE %08x\n"), addr, pde);
1.361 +
1.362 + TUint expectedPdeType = (RomUnpagedEnd - addr) >= KChunkSize ? 2 : 1;
1.363 + test_Equal(expectedPdeType, pde & 3);
1.364 + }
1.365 +#else
1.366 + test.Printf(_L("Test not supported on this architecture\n"));
1.367 +#endif
1.368 +
1.369 + test.End();
1.370 + }
1.371 +
1.372 +void Initialise()
1.373 + {
1.374 + test.Start(_L("Load test LDDs"));
1.375 +
1.376 + TInt r=User::LoadLogicalDevice(KLddFileName);
1.377 + test_Value(r, r==KErrNone || r==KErrAlreadyExists);
1.378 + if (PageMovingSupported)
1.379 + {
1.380 + r=User::LoadLogicalDevice(KMoveLddFileName);
1.381 + test_Value(r, r==KErrNone || r==KErrAlreadyExists);
1.382 + }
1.383 +
1.384 + test_KErrNone(UserHal::PageSizeInBytes(PageSize));
1.385 +
1.386 + test.Next(_L("Open test LDDs"));
1.387 + test_KErrNone(Shadow.Open());
1.388 + test_KErrNone(MemoryTest.Open());
1.389 + if (PageMovingSupported)
1.390 + test_KErrNone(PageMove.Open());
1.391 +
1.392 + test.Next(_L("Allocate some RAM"));
1.393 + PageBuffer1=(TUint8*)User::Alloc(PageSize);
1.394 + test_NotNull(PageBuffer1);
1.395 + PageBuffer2=(TUint8*)User::Alloc(PageSize);
1.396 + test_NotNull(PageBuffer2);
1.397 + PageBuffer3=(TUint8*)User::Alloc(PageSize);
1.398 + test_NotNull(PageBuffer3);
1.399 +
1.400 + test.Next(_L("Discover ROM addresses"));
1.401 + TRomHeader* romHeader = (TRomHeader*)UserSvr::RomHeaderAddress();
1.402 + RomUnpagedStart = (TLinAddr)romHeader;
1.403 + test_Equal(0, RomUnpagedStart & (PageSize - 1));
1.404 +
1.405 + //Round up to page size (May already be rounded, but doesnt hurt)
1.406 + TUint romSize = (romHeader->iUncompressedSize + PageSize - 1) & ~(PageSize - 1);
1.407 +
1.408 + if (DPTest::Attributes() & DPTest::ERomPaging)
1.409 + {
1.410 + // Use paged part of rom for testing
1.411 + test_NotNull(romHeader->iPageableRomStart);
1.412 + RomUnpagedEnd = RomUnpagedStart + romHeader->iPageableRomStart;
1.413 + test_Equal(0, RomUnpagedEnd & (PageSize - 1));
1.414 + RomPagedStart = RomUnpagedEnd;
1.415 + RomPagedEnd = RomUnpagedStart + romSize;
1.416 + RomPagingSupported = ETrue;
1.417 + }
1.418 + else
1.419 + {
1.420 + RomUnpagedEnd = RomUnpagedStart + romSize;
1.421 + RomPagedStart = RomUnpagedEnd;
1.422 + RomPagedEnd = RomPagedStart;
1.423 + }
1.424 +
1.425 + test.Printf(_L("Unpaged ROM: %08x -> %08x\n"), RomUnpagedStart, RomUnpagedEnd);
1.426 + test.Printf(_L("Paged ROM: %08x -> %08x\n"), RomPagedStart, RomPagedEnd);
1.427 +
1.428 + test.End();
1.429 + }
1.430 +
1.431 +void Finalise()
1.432 + {
1.433 + PageMove.Close();
1.434 + MemoryTest.Close();
1.435 +
1.436 + User::Free(PageBuffer1);
1.437 + User::Free(PageBuffer2);
1.438 + User::Free(PageBuffer3);
1.439 + }
1.440 +
1.441 +GLDEF_C TInt E32Main()
1.442 +//
1.443 +// Test ROM shadowing
1.444 +//
1.445 + {
1.446 + test.Title();
1.447 +
1.448 + if (!HaveMMU())
1.449 + {
1.450 + test.Printf(_L("This test requires an MMU\n"));
1.451 + return KErrNone;
1.452 + }
1.453 +#ifdef __WINS__
1.454 + test.Printf(_L("Test not valid in WINS\n"));
1.455 +#else
1.456 +
1.457 + test.Start(_L("Testing ROM shadowing"));
1.458 + Initialise();
1.459 +
1.460 + TestRomIsSectionMapped();
1.461 +
1.462 + TestShadowPage(RomUnpagedStart, EUnpaged);
1.463 + TestShadowPage(RomUnpagedStart + PageSize, EUnpaged);
1.464 + TestShadowPage(RomUnpagedEnd - PageSize, EUnpaged);
1.465 + TestNoFreeRAM(RomUnpagedStart);
1.466 + TestShadowPageOOM(RomUnpagedStart);
1.467 +
1.468 + if (RomPagingSupported)
1.469 + {
1.470 + TestShadowPage(RomPagedStart, EPaged);
1.471 + TestShadowPage(RomPagedStart + PageSize, EPaged);
1.472 + TestShadowPage(RomPagedEnd - PageSize, EPaged);
1.473 + TestNoFreeRAM(RomPagedEnd - PageSize);
1.474 + TestShadowPageOOM(RomPagedStart);
1.475 + TestInteractionWithPinning(RomPagedStart);
1.476 + }
1.477 +
1.478 + // todo: add test when reforming section mappings is implemented
1.479 + // TestRomIsSectionMapped();
1.480 +
1.481 + Finalise();
1.482 + test.End();
1.483 +
1.484 +#endif
1.485 + return(KErrNone);
1.486 + }
1.487 +