os/kernelhwsrv/kerneltest/e32test/mmu/d_gobble.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2007-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\misc\d_gobble.cpp
    15 // LDD for gobbling RAM
    16 // 
    17 //
    18 
    19 #include "platform.h"
    20 #include <kernel/kern_priv.h>
    21 #include "d_gobble.h"
    22 
    23 const TInt KMajorVersionNumber=0;
    24 const TInt KMinorVersionNumber=1;
    25 const TInt KBuildVersionNumber=1;
    26 
    27 class DGobblerFactory : public DLogicalDevice
    28 //
    29 // Gobbler LDD factory
    30 //
    31 	{
    32 public:
    33 	DGobblerFactory();
    34 	~DGobblerFactory();
    35 	virtual TInt Install();
    36 	virtual void GetCaps(TDes8& aDes) const;
    37 	virtual TInt Create(DLogicalChannelBase*& aChannel);
    38 	};
    39 
    40 class DGobbler : public DLogicalChannelBase
    41 //
    42 // RAM Gobbler LDD channel
    43 //
    44 	{
    45 public:
    46 	DGobbler();
    47 	virtual ~DGobbler();
    48 private:
    49 	virtual TInt Request(TInt aFunc, TAny* a1, TAny* a2);
    50 	virtual TInt DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer);
    51 private:
    52 	enum {ESmallBufferSize = 64};
    53 
    54 	TUint32 Gobble(TUint32 aLeave);
    55 #ifdef __EPOC32__
    56 	TInt GobbleMultiPages(TUint32& aTake, TUint32* aMultiPageBuf, TInt aMaxMultiPages);
    57 	void FreeMultiPage(TPhysAddr aMultiPage);
    58 	TUint32 AllocMultiPage(TUint32 aSize);
    59 	TUint32 Size(TUint32 aMultiPage);
    60 #endif
    61 private:
    62 #ifdef __EPOC32__
    63 	TPhysAddr iPhys[ESmallBufferSize];
    64 #endif
    65 	DChunk* iSharedChunk;
    66 	TUint32 iPageShift;
    67 	TUint32 iPageSize;
    68 	};
    69 
    70 DGobblerFactory::DGobblerFactory()
    71     {
    72     iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
    73     //iParseMask=0;//No units, no info, no PDD
    74     //iUnitsMask=0;//Only one thing
    75     }
    76 
    77 DGobblerFactory::~DGobblerFactory()
    78 	{
    79 	}
    80 
    81 TInt DGobblerFactory::Create(DLogicalChannelBase*& aChannel)
    82     {
    83 	aChannel = new DGobbler;
    84     return aChannel ? KErrNone : KErrNoMemory;
    85     }
    86 
    87 TInt DGobblerFactory::Install()
    88 //
    89 // Install the LDD - overriding pure virtual
    90 //
    91     {
    92     return SetName(&KGobblerLddName);
    93     }
    94 
    95 void DGobblerFactory::GetCaps(TDes8& aDes) const
    96 //
    97 // Get capabilities - overriding pure virtual
    98 //
    99     {
   100     TCapsGobblerV01 b;
   101     b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
   102     Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
   103     }
   104 
   105 DGobbler::DGobbler()
   106     {
   107 	iPageSize = Kern::RoundToPageSize(1);
   108 	iPageShift = __e32_find_ms1_32(iPageSize);
   109     }
   110 
   111 DGobbler::~DGobbler()
   112 	{
   113 	// Free all the RAM we've gobbled
   114 
   115 #ifdef __EPOC32__
   116 	// Free the addresses held in the shared chunk
   117 	if (iSharedChunk)
   118 		{
   119 		TLinAddr ka;
   120 		TInt r = Kern::ChunkAddress(iSharedChunk, 0, 1, ka);
   121 		if (r==KErrNone)
   122 			{
   123 			const TUint32* p = (const TUint32*)ka;
   124 			const TUint32* pE = p + (iSharedChunk->Size() / sizeof(TUint32));
   125 			while (p<pE)
   126 				{
   127 				TUint32 mp = *p++;
   128 				if (mp)
   129 					FreeMultiPage(mp);
   130 				}
   131 			}
   132 		}
   133 #endif
   134 	if (iSharedChunk)
   135 		Kern::ChunkClose(iSharedChunk);
   136 #ifdef __EPOC32__
   137 	TInt i;
   138 	for (i=0; i<ESmallBufferSize; ++i)
   139 		{
   140 		TUint32 mp = iPhys[i];
   141 		if (mp)
   142 			FreeMultiPage(mp);
   143 		}
   144 #endif
   145 	}
   146 
   147 TInt DGobbler::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
   148 //
   149 // Create channel
   150 //
   151     {
   152 
   153     if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
   154     	return KErrNotSupported;
   155 	return KErrNone;
   156 	}
   157 
   158 
   159 #ifdef __EPOC32__
   160 void DGobbler::FreeMultiPage(TPhysAddr aMultiPage)
   161 	{
   162 	TPhysAddr base = (aMultiPage>>iPageShift) << iPageShift;
   163 	TUint32 size = Size(aMultiPage);
   164 	Epoc::FreePhysicalRam(base, size);
   165 	}
   166 
   167 TUint32 DGobbler::AllocMultiPage(TUint32 aSize)
   168 	{
   169 	TUint32 sz = 1u << __e32_find_ms1_32(aSize);	// round size down to power of 2
   170 	while (sz > iPageSize)
   171 		{
   172 		TPhysAddr pa;
   173 		TInt r = Epoc::AllocPhysicalRam(sz, pa);
   174 		if (r == KErrNone)
   175 			return pa | __e32_find_ms1_32(sz);
   176 		sz >>= 1;
   177 		}
   178 	return 0;
   179 	}
   180 
   181 TUint32 DGobbler::Size(TUint32 aMultiPage)
   182 	{
   183 	return 1u << (aMultiPage & 0x1f);
   184 	}
   185 #endif
   186 
   187 #ifdef __EPOC32__
   188 TInt DGobbler::GobbleMultiPages(TUint32& aTake, TUint32* aMultiPageBuf, TInt aMaxMultiPages)
   189 	{
   190 	TInt i = 0;
   191 	TUint32 mp = 0;
   192 	while (i<aMaxMultiPages && aTake)
   193 		{
   194 		mp = AllocMultiPage(aTake);
   195 		if (mp==0)
   196 			break;	// someone else gobbled all the RAM
   197 		aTake -= Size(mp);
   198 		aMultiPageBuf[i] = mp;
   199 		++i;
   200 		}
   201 	if (mp == 0)
   202 		return KErrNoMemory;	// someone else gobbled all the RAM
   203 	if (aTake==0)
   204 		return KErrNone;
   205 	return KErrOverflow;		// buffer filled up
   206 	}
   207 #endif
   208 
   209 TUint32 DGobbler::Gobble(TUint32 aLeave)
   210 	{
   211 	TUint32 free = Kern::FreeRamInBytes();
   212 	if (free < aLeave)
   213 		return 0;	// no need to gobble anything
   214 	TUint32 take = free - aLeave;
   215 	TUint32 take2 = take;
   216 	TInt r = KErrNone;
   217 #ifdef __EPOC32__
   218 	r = GobbleMultiPages(take2, iPhys, ESmallBufferSize);
   219 	if (r==KErrNoMemory)
   220 		return take - take2;	// someone else gobbled all the RAM
   221 	if (r==KErrNone)
   222 		return take;			// small buffer did the job
   223 
   224 	TUint32 chunkMax = (take >> iPageShift) * sizeof(TPhysAddr);
   225 #else
   226 	TUint32 chunkMax = take;
   227 #endif
   228 	TChunkCreateInfo info;
   229 	info.iType = TChunkCreateInfo::ESharedKernelSingle;
   230 	info.iMaxSize = chunkMax;
   231 #ifdef __EPOC32__
   232 	info.iMapAttr = EMapAttrCachedMax;
   233 #else
   234 	info.iMapAttr = 0;
   235 #endif
   236 	info.iOwnsMemory = 1;
   237 	info.iDestroyedDfc = 0;
   238 	TLinAddr ka = 0;
   239 	TUint32 ma = 0;
   240 	r = Kern::ChunkCreate(info, iSharedChunk, ka, ma);
   241 	if (r!=KErrNone)
   242 		return take - take2;	// someone else gobbled all the RAM
   243 	TUint32 chunkSz = (chunkMax + iPageSize - 1) &~ (iPageSize - 1);
   244 	r = Kern::ChunkCommit(iSharedChunk, 0, chunkSz);
   245 	if (r!=KErrNone)
   246 		return take - take2;	// someone else gobbled all the RAM
   247 #ifndef __EPOC32__
   248 	return take;				// on emulator we are finished here
   249 #else
   250 	TUint32* p = (TUint32*)ka;
   251 	memclr(p, chunkSz);
   252 	r = GobbleMultiPages(take2, p, chunkSz/sizeof(TUint32));
   253 	if (r==KErrNoMemory)
   254 		return take - take2;	// someone else gobbled all the RAM
   255 	return take; // done
   256 #endif
   257 	}
   258 
   259 TInt DGobbler::Request(TInt aFunc, TAny* a1, TAny*)
   260 	{
   261 	if (aFunc == RGobbler::EControlGobbleRAM)
   262 		{
   263 		NKern::ThreadEnterCS();
   264 		TUint32 ret = Gobble(TUint32(a1));
   265 		NKern::ThreadLeaveCS();
   266 		return ret;
   267 		}
   268 	else
   269 		return KErrNotSupported;
   270 	}
   271 
   272 DECLARE_STANDARD_LDD()
   273 	{
   274     return new DGobblerFactory;
   275     }
   276