kernel/eka/memmodel/epoc/flexible/mmu/mramalloc.cpp
changeset 31 56f325a607ea
parent 15 4122176ea935
child 32 c9417927a896
child 33 0173bcd7697c
equal deleted inserted replaced
15:4122176ea935 31:56f325a607ea
     1 // Copyright (c) 1998-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 "Symbian Foundation License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <plat_priv.h>
       
    17 #include "mramalloc.h"
       
    18 
       
    19 struct SGroup
       
    20 	{
       
    21 	TBitMapAllocator* iBma;
       
    22 	TPhysAddr iPhysBase;
       
    23 	TInt iNumBase;
       
    24 	TUint8 iPwrBlock;
       
    25 	};
       
    26 
       
    27 class DRamAllocator : public DRamAllocatorBase
       
    28 	{
       
    29 public:
       
    30 	virtual TInt Create(const SRamInfo& aInfo, const SRamBank* aPowerBanks);
       
    31 	virtual TInt MarkPageAllocated(TPhysAddr aAddr);
       
    32 	virtual TInt FreeRamPage(TPhysAddr aAddr);
       
    33 	virtual void FreeRamPages(TPhysAddr* aPageList, TInt aNumPages);
       
    34 	virtual TInt AllocRamPages(TPhysAddr* aPageList, TInt aNumPages);
       
    35 	virtual TInt AllocContiguousRam(TInt aNumPages, TPhysAddr& aPhysAddr, TInt aAlign=0);
       
    36 	virtual TInt SetPhysicalRamState(TPhysAddr aBase, TInt aSize, TBool aState);
       
    37 	virtual TUint TotalPhysicalRamPages() {return iTotalRamPages;};
       
    38 #ifdef KMMU
       
    39 	void DebugDump();
       
    40 #endif
       
    41 private:
       
    42 	SGroup* GetGroupAndOffset(TPhysAddr aAddr, TInt& aOffset);
       
    43 	void MarkPagesAllocated(TInt aPageNum, TInt aCount);
       
    44 	TInt FindContiguousRam(TInt aNumPages, TInt aAlignWrtPage, TUint8* aPermute, TInt& aPageNum);
       
    45 private:
       
    46 	enum TPanic
       
    47 		{
       
    48 		// don't use 0
       
    49 		EDoNotUse=0,
       
    50 		EBytesFromStartInvalid,
       
    51 		EBytesFromEndInvalid,
       
    52 		EAreasTooSmall,
       
    53 		ETooManyPowerBlocks,
       
    54 		EInvalidPowerBlocks,
       
    55 		EDoMarkPagesAllocated1,
       
    56 		EAllocRamPagesInconsistent,
       
    57 		};
       
    58 private:
       
    59 	TInt iTotalRamPages;
       
    60 	TInt iNumGroups;				// group corresponds to BMA
       
    61 	TInt iAreaSize;					// size of an area in bytes
       
    62 	TInt iAreaShift;				// log2(areasize)
       
    63 	TUint32 iAreaMask;				// iAreaSize-1
       
    64 	TInt iAreaPages;				// size of an area in pages
       
    65 	TInt iAreaPageShift;			// log2(areapages)
       
    66 	TUint32 iAreaPageMask;			// iAreaPages-1
       
    67 	TInt iNumAreas;					// number of areas recognised (size of iPhysAddrLUT)
       
    68 	SGroup* iGroups;				// per-group info
       
    69 	TUint8* iGroupPowerOrder;		// table of indices into above tables in power block order
       
    70 	TUint8* iPhysAddrLUT;			// table of indices indexed by (physaddr-physaddrbase)>>areashift
       
    71 	TUint8* iPageNumLUT;			// table of indices indexed by pagenum>>areapageshift
       
    72 	TPhysAddr iPhysAddrBase;		// lowest valid physical address
       
    73 	TPhysAddr iPhysAddrTop;			// highest valid physical address+1
       
    74 	};
       
    75 
       
    76 DRamAllocatorBase* DRamAllocatorBase::New()
       
    77 	{
       
    78 	return new DRamAllocator;
       
    79 	}
       
    80 
       
    81 DRamAllocatorBase* DRamAllocatorBase::New(const SRamInfo& aInfo, TInt aPageShift, const SRamBank* aPowerBanks)
       
    82 	{
       
    83 	DRamAllocatorBase* pA=New();
       
    84 	if (!pA)
       
    85 		Panic(KErrNoMemory);
       
    86 	pA->iPageShift=aPageShift;
       
    87 	pA->iPageSize=1<<aPageShift;
       
    88 	TInt r=pA->Create(aInfo,aPowerBanks);
       
    89 	if (r!=KErrNone)
       
    90 		Panic(r);
       
    91 	return pA;
       
    92 	}
       
    93 
       
    94 void DRamAllocatorBase::Panic(TInt aPanic)
       
    95 	{
       
    96 	Kern::Fault("RAM-ALLOC", aPanic);
       
    97 	}
       
    98 
       
    99 #ifdef KMMU
       
   100 void HexDump32(const TAny* a, TInt n, const char* s)
       
   101 	{
       
   102 	const TUint32* p=(const TUint32*)a;
       
   103 	Kern::Printf(s);
       
   104 	TInt i=0;
       
   105 	while(n)
       
   106 		{
       
   107 		TBuf8<80> b;
       
   108 		b.AppendNumFixedWidth(i,EHex,4);
       
   109 		b.Append(':');
       
   110 		TInt m=Min(n,4);
       
   111 		n-=m;
       
   112 		i+=m;
       
   113 		while(m--)
       
   114 			{
       
   115 			b.Append(' ');
       
   116 			b.AppendNumFixedWidth(*p++,EHex,8);
       
   117 			}
       
   118 		Kern::Printf("%S",&b);
       
   119 		}
       
   120 	}
       
   121 
       
   122 void HexDump8(const TAny* a, TInt n, const char* s)
       
   123 	{
       
   124 	const TUint8* p=(const TUint8*)a;
       
   125 	Kern::Printf(s);
       
   126 	TInt i=0;
       
   127 	while(n)
       
   128 		{
       
   129 		TBuf8<80> b;
       
   130 		b.AppendNumFixedWidth(i,EHex,4);
       
   131 		b.Append(':');
       
   132 		TInt m=Min(n,16);
       
   133 		n-=m;
       
   134 		i+=m;
       
   135 		while(m--)
       
   136 			{
       
   137 			b.Append(' ');
       
   138 			b.AppendNumFixedWidth(*p++,EHex,2);
       
   139 			}
       
   140 		Kern::Printf("%S",&b);
       
   141 		}
       
   142 	}
       
   143 
       
   144 void DRamAllocator::DebugDump()
       
   145 	{
       
   146 	Kern::Printf("PageSize=%08x PageShift=%d",iPageSize,iPageShift);
       
   147 	Kern::Printf("AreaSize=%08x AreaShift=%d AreaMask=%08x",iAreaSize,iAreaShift,iAreaMask);
       
   148 	Kern::Printf("AreaPages=%08x AreaPageShift=%d AreaPageMask=%08x",iAreaPages,iAreaPageShift,iAreaPageMask);
       
   149 	Kern::Printf("Total Pages=%08x Total Free=%08x",iTotalRamPages,iTotalFreeRamPages);
       
   150 	Kern::Printf("Number of areas=%08x, number of groups=%08x",iNumAreas,iNumGroups);
       
   151 	Kern::Printf("Number of power blocks=%d, PowerState=%08x",iNumPowerBlocks,iPowerState);
       
   152 	Kern::Printf("PhysAddrBase=%08x, PhysAddrTop=%08x",iPhysAddrBase,iPhysAddrTop);
       
   153 
       
   154 	TInt i;
       
   155 	Kern::Printf("Group Info:");
       
   156 	for (i=0; i<iNumGroups; ++i)
       
   157 		{
       
   158 		SGroup& g=iGroups[i];
       
   159 		TBitMapAllocator& b=*g.iBma;
       
   160 		Kern::Printf("%02x: Avail %08x Size %08x Phys %08x Num %08x Pwr %02x",i,b.iAvail,b.iSize,
       
   161 										g.iPhysBase,g.iNumBase,g.iPwrBlock);
       
   162 		}
       
   163 	if (iGroupPowerOrder)
       
   164 		HexDump8(iGroupPowerOrder,iNumGroups,"GroupPowerOrder:");
       
   165 	HexDump8(iPhysAddrLUT,iNumAreas,"PhysAddrLUT:");
       
   166 	HexDump8(iPageNumLUT,iTotalRamPages>>iAreaPageShift,"PageNumLUT:");
       
   167 	HexDump32(iPowerBlockPages,iNumPowerBlocks,"PowerBlockPages:");
       
   168 	}
       
   169 #endif
       
   170 
       
   171 TInt CountBanks(const SRamBank* aBankList)
       
   172 	{
       
   173 	TInt banks=0;
       
   174 	for (; aBankList->iSize; ++banks, ++aBankList);
       
   175 	return banks;
       
   176 	}
       
   177 
       
   178 TInt CalcAreaShift(const SRamBank* aBankList)
       
   179 	{
       
   180 	TUint32 mask=0;
       
   181 	for (; aBankList->iSize; ++aBankList)
       
   182 		{
       
   183 		TUint32 base=aBankList->iBase;
       
   184 		TUint32 end=base+aBankList->iSize-1;
       
   185 		__KTRACE_OPT(KBOOT,Kern::Printf("Base=%08x End=%08x",base,end));
       
   186 		mask|=base;
       
   187 		mask|=~end;
       
   188 		}
       
   189 	return __e32_find_ls1_32(mask);
       
   190 	}
       
   191 
       
   192 TUint32 TotalBankSize(const SRamBank* aBankList)
       
   193 	{
       
   194 	TUint32 size=0;
       
   195 	for (; aBankList->iSize; ++aBankList)
       
   196 		size+=aBankList->iSize;
       
   197 	return size;
       
   198 	}
       
   199 
       
   200 TInt DRamAllocator::Create(const SRamInfo& a, const SRamBank* aP)
       
   201 	{
       
   202 	__KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::Create"));
       
   203 
       
   204 	TInt num_boot_banks=CountBanks(a.iBanks);
       
   205 	TUint32 total_ram_size=TotalBankSize(a.iBanks);
       
   206 	__KTRACE_OPT(KMMU,Kern::Printf("#banks from bootstrap=%d",num_boot_banks));
       
   207 	__KTRACE_OPT(KMMU,Kern::Printf("Total size=%08x",total_ram_size));
       
   208 	iTotalRamPages=total_ram_size>>iPageShift;
       
   209 	iTotalFreeRamPages=iTotalRamPages;
       
   210 	__KTRACE_OPT(KMMU,Kern::Printf("Total size=%08x, total pages=%08x",total_ram_size,iTotalRamPages));
       
   211 
       
   212 	__KTRACE_OPT(KMMU,Kern::Printf("Calculate area shift from bootstrap blocks"));
       
   213 	iAreaShift=CalcAreaShift(a.iBanks);
       
   214 	__KTRACE_OPT(KMMU,Kern::Printf("iAreaShift=%d",iAreaShift));
       
   215 	iNumPowerBlocks=1;
       
   216 	if (aP)
       
   217 		{
       
   218 		iNumPowerBlocks=CountBanks(aP);
       
   219 		__KTRACE_OPT(KMMU,Kern::Printf("iNumPowerBlocks=%d",iNumPowerBlocks));
       
   220 		if (iNumPowerBlocks>32)
       
   221 			return ETooManyPowerBlocks;
       
   222 		__KTRACE_OPT(KMMU,Kern::Printf("Calculate area shift from power blocks"));
       
   223 		TInt as=CalcAreaShift(aP);
       
   224 		__KTRACE_OPT(KMMU,Kern::Printf("area shift=%d",as));
       
   225 		if (as<iAreaShift)
       
   226 			iAreaShift=as;
       
   227 		}
       
   228 	if (iAreaShift<16 || iAreaShift<iPageShift)
       
   229 		return EAreasTooSmall;
       
   230 	iAreaSize=1<<iAreaShift;
       
   231 	iAreaMask=iAreaSize-1;
       
   232 	iAreaPageShift=iAreaShift-iPageShift;
       
   233 	iAreaPages=1<<iAreaPageShift;
       
   234 	iAreaPageMask=iAreaPages-1;
       
   235 	__KTRACE_OPT(KMMU,Kern::Printf("iAreaShift=%d",iAreaShift));
       
   236 	
       
   237 	iPhysAddrBase=a.iBanks[0].iBase;
       
   238 	const SRamBank& last_boot_bank=a.iBanks[num_boot_banks-1];
       
   239 	iPhysAddrTop=last_boot_bank.iBase+last_boot_bank.iSize;
       
   240 	__KTRACE_OPT(KMMU,Kern::Printf("PA base=%08x, PA top=%08x",iPhysAddrBase,iPhysAddrTop));
       
   241 	iNumAreas=(iPhysAddrTop-iPhysAddrBase)>>iAreaShift;
       
   242 	__KTRACE_OPT(KMMU,Kern::Printf("iNumAreas=%08x",iNumAreas));
       
   243 
       
   244 	iPhysAddrLUT=(TUint8*)Kern::Alloc(iNumAreas);
       
   245 	if (!iPhysAddrLUT)
       
   246 		return KErrNoMemory;
       
   247 	iPageNumLUT=(TUint8*)Kern::Alloc(iNumAreas);	// overallocate temporarily
       
   248 	if (!iPageNumLUT)
       
   249 		return KErrNoMemory;
       
   250 	iPowerBlockPages=(TInt*)Kern::AllocZ(iNumPowerBlocks*sizeof(TInt));
       
   251 	if (!iPowerBlockPages)
       
   252 		return KErrNoMemory;
       
   253 
       
   254 	// coalesce contiguous boot banks
       
   255 	SRamBank* phys_banks = (SRamBank*)Kern::Alloc(num_boot_banks*sizeof(SRamBank));
       
   256 	if (!phys_banks)
       
   257 		return KErrNoMemory;
       
   258 	SRamBank* pD=phys_banks;
       
   259 	const SRamBank* pBoot=a.iBanks;
       
   260 	const SRamBank* pE=pBoot+num_boot_banks;
       
   261 	TPhysAddr base=0;
       
   262 	TPhysAddr end=0;
       
   263 	for (; pBoot<=pE; ++pBoot)
       
   264 		{
       
   265 		if (pBoot==pE || pBoot->iBase!=end)
       
   266 			{
       
   267 			if (end)
       
   268 				{
       
   269 				pD->iBase=base;
       
   270 				pD->iSize=end-base;
       
   271 				++pD;
       
   272 				__KTRACE_OPT(KMMU,Kern::Printf("Coalesced bank: %08x-%08x",base,end));
       
   273 				}
       
   274 			if (pBoot<pE)
       
   275 				{
       
   276 				base=pBoot->iBase;
       
   277 				end=base+pBoot->iSize;
       
   278 				}
       
   279 			}
       
   280 		else
       
   281 			end+=pBoot->iSize;
       
   282 		}
       
   283 	SRamBank* pPhysEnd=pD;
       
   284 	__KTRACE_OPT(KMMU,Kern::Printf("#Coalesced banks: %d",pD-phys_banks));
       
   285 
       
   286 	// work out groups
       
   287 	TInt start_area;
       
   288 	TInt num_areas;
       
   289 	TInt phys_bank;
       
   290 	TInt pwr_bank;
       
   291 	memset(iPhysAddrLUT,0xff,iNumAreas);
       
   292 	pD=phys_banks;
       
   293 	for (; pD<pPhysEnd; ++pD)
       
   294 		{
       
   295 		start_area=(pD->iBase-iPhysAddrBase)>>iAreaShift;
       
   296 		num_areas=pD->iSize>>iAreaShift;
       
   297 		phys_bank=pD-phys_banks;
       
   298 		memset(iPhysAddrLUT+start_area, phys_bank, num_areas);
       
   299 		}
       
   300 
       
   301 	if (aP)
       
   302 		{
       
   303 		memset(iPageNumLUT,0xff,iNumAreas);
       
   304 		const SRamBank* pB=aP;
       
   305 		const SRamBank* pPwrEnd=aP+iNumPowerBlocks;
       
   306 		for (; pB<pPwrEnd; ++pB)
       
   307 			{
       
   308 			start_area=(Max(pB->iBase,iPhysAddrBase)-iPhysAddrBase)>>iAreaShift;
       
   309 			num_areas=(TInt)Min(TUint32(pB->iSize)>>iAreaShift, TUint32(iNumAreas-start_area));
       
   310 			pwr_bank=pB-aP;
       
   311 			memset(iPageNumLUT+start_area, pwr_bank, num_areas);
       
   312 			}
       
   313 		}
       
   314 	Kern::Free(phys_banks);
       
   315 
       
   316 	phys_bank=0xff;
       
   317 	pwr_bank=-1;
       
   318 	TInt area;
       
   319 	iNumGroups=0;
       
   320 	for (area=0; area<=iNumAreas; ++area)
       
   321 		{
       
   322 		TInt pb=(area<iNumAreas)?iPhysAddrLUT[area]:0xff;
       
   323 		TInt pwb=aP?((area<iNumAreas)?iPageNumLUT[area]:0xff):-1;
       
   324 		__KTRACE_OPT(KMMU,Kern::Printf("Area %04x (%08x) : pb=%02x pwb=%02x",area,iPhysAddrBase+(area<<iAreaShift),pb,pwb));
       
   325 		if (pb!=phys_bank || pwb!=pwr_bank)
       
   326 			{
       
   327 			if (pb!=0xff && pwb==0xff)
       
   328 				return EInvalidPowerBlocks;
       
   329 			if (phys_bank!=0xff)
       
   330 				++iNumGroups;
       
   331 			phys_bank=pb;
       
   332 			if (aP)
       
   333 				pwr_bank=pwb;
       
   334 			}
       
   335 		}
       
   336 	__KTRACE_OPT(KMMU,Kern::Printf("iNumGroups=%d",iNumGroups));
       
   337 	iGroups=(SGroup*)Kern::Alloc(iNumGroups*sizeof(SGroup));
       
   338 	if (!iGroups)
       
   339 		return KErrNoMemory;
       
   340 	if (aP)
       
   341 		{
       
   342 		iGroupPowerOrder = (TUint8*)Kern::Alloc(iNumGroups);
       
   343 		if (!iGroupPowerOrder)
       
   344 			return KErrNoMemory;
       
   345 		}
       
   346 	start_area=0;
       
   347 	phys_bank=0xff;
       
   348 	pwr_bank=0;
       
   349 	TInt group=0;
       
   350 	TInt page_number=0;
       
   351 	for (area=0; area<=iNumAreas; ++area)
       
   352 		{
       
   353 		TInt pb=(area<iNumAreas)?iPhysAddrLUT[area]:0xff;
       
   354 		TInt pwb=aP?((area<iNumAreas)?iPageNumLUT[area]:0xff):0;
       
   355 		if (pb!=phys_bank || (aP && pwb!=pwr_bank))
       
   356 			{
       
   357 			TInt group_num_areas=area-start_area;
       
   358 			if (phys_bank!=0xff)
       
   359 				{
       
   360 				SGroup& g=iGroups[group];
       
   361 				TInt group_num_pages=TUint32(group_num_areas)<<iAreaPageShift;
       
   362 				g.iBma=TBitMapAllocator::New(group_num_pages, ETrue);
       
   363 				if (!g.iBma)
       
   364 					return KErrNoMemory;
       
   365 				g.iPhysBase=(TPhysAddr(start_area)<<iAreaShift)+iPhysAddrBase;
       
   366 				g.iNumBase=page_number;
       
   367 				memset(iPhysAddrLUT+start_area, group, group_num_areas);
       
   368 				memset(iPageNumLUT+(page_number>>iAreaPageShift), group, group_num_areas);
       
   369 				page_number+=group_num_pages;
       
   370 				g.iPwrBlock=pwr_bank;
       
   371 				__KTRACE_OPT(KMMU,Kern::Printf("Group %d: PhysBase=%08x NumBase=%08x PwrBlock=%02x NumPages=%08x",
       
   372 													group, g.iPhysBase, g.iNumBase, g.iPwrBlock, group_num_pages));
       
   373 				++group;
       
   374 				}
       
   375 			start_area=area;
       
   376 			phys_bank=pb;
       
   377 			if (aP)
       
   378 				pwr_bank=pwb;
       
   379 			}
       
   380 		}
       
   381 
       
   382 	// shrink iPageNumLUT to correct size
       
   383 	iPageNumLUT=(TUint8*)Kern::ReAlloc(iPageNumLUT, iTotalRamPages>>iAreaPageShift);
       
   384 
       
   385 	if (aP)
       
   386 		{
       
   387 		// work out power block ordering of groups
       
   388 		TBool identity=ETrue;
       
   389 		TInt last_pwb=-1;
       
   390 		group=0;
       
   391 		while(group<iNumGroups)
       
   392 			{
       
   393 			TInt first_pwb=256;
       
   394 			TInt i=0;
       
   395 			TInt j=0;
       
   396 			for (; i<iNumGroups; ++i)
       
   397 				{
       
   398 				TInt gpwb=iGroups[i].iPwrBlock;
       
   399 				if (gpwb>last_pwb && gpwb<first_pwb)
       
   400 					{
       
   401 					j=i;
       
   402 					first_pwb=gpwb;
       
   403 					}
       
   404 				}
       
   405 			do	{
       
   406 				if (j!=group)
       
   407 					identity=EFalse;
       
   408 				iGroupPowerOrder[group++]=j++;
       
   409 				} while (j<iNumGroups && iGroups[j].iPwrBlock==first_pwb);
       
   410 			last_pwb=first_pwb;
       
   411 			}
       
   412 		if (identity)
       
   413 			{
       
   414 			// power order and physical address order coincide so no need to keep iGroupPowerOrder
       
   415 			Kern::Free(iGroupPowerOrder);
       
   416 			iGroupPowerOrder=NULL;
       
   417 			}
       
   418 		}
       
   419 
       
   420 	// Now mark any reserved regions as allocated
       
   421 	const SRamBank* pB = pE + 1;	// first reserved block specifier
       
   422 	for (; pB->iSize; ++pB)
       
   423 		{
       
   424 		__KTRACE_OPT(KMMU, Kern::Printf("Reserve physical block %08x+%x", pB->iBase, pB->iSize));
       
   425 		TInt r = SetPhysicalRamState(pB->iBase, pB->iSize, EFalse);
       
   426 		__KTRACE_OPT(KMMU, Kern::Printf("Reserve returns %d", r));
       
   427 		if (r!=KErrNone)
       
   428 			return r;
       
   429 		}
       
   430 
       
   431 	__KTRACE_OPT(KMMU,DebugDump());
       
   432 	return KErrNone;
       
   433 	}
       
   434 
       
   435 SGroup* DRamAllocator::GetGroupAndOffset(TPhysAddr aAddr, TInt& aOffset)
       
   436 	{
       
   437 	if (aAddr<iPhysAddrBase || aAddr>=iPhysAddrTop)
       
   438 		return NULL;
       
   439 	TInt area=TInt((aAddr-iPhysAddrBase)>>iAreaShift);
       
   440 	TInt group=iPhysAddrLUT[area];
       
   441 	if (group==0xff)
       
   442 		return NULL;
       
   443 	SGroup& g=iGroups[group];
       
   444 	aOffset=(aAddr-g.iPhysBase)>>iPageShift;
       
   445 	return &g;
       
   446 	}
       
   447 
       
   448 void DRamAllocator::MarkPagesAllocated(TInt aPageNum, TInt aCount)
       
   449 	{
       
   450 	__KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::MarkPagesAllocated(%x+%x)",aPageNum,aCount));
       
   451 	if ((TUint32(aPageNum)>=TUint32(iTotalRamPages)) || (TUint32(aCount)>TUint32(iTotalRamPages-aPageNum)))
       
   452 		Panic(EDoMarkPagesAllocated1);
       
   453 	TInt area=aPageNum>>iAreaPageShift;
       
   454 	SGroup* pG=iGroups+iPageNumLUT[area];
       
   455 	iTotalFreeRamPages-=aCount;
       
   456 	while(aCount)
       
   457 		{
       
   458 		TInt gpnb=pG->iNumBase;
       
   459 		TBitMapAllocator& bma=*pG->iBma;
       
   460 		TInt gsz=bma.iSize;
       
   461 		TInt ix=aPageNum-gpnb;
       
   462 		TInt count=Min(gsz-ix,aCount);
       
   463 		bma.Alloc(ix,count);
       
   464 		TInt pwb=pG->iPwrBlock;
       
   465 		iPowerBlockPages[pwb]+=count;
       
   466 		iPowerState|=(1u<<pwb);
       
   467 		aCount-=count;
       
   468 		aPageNum+=count;
       
   469 		++pG;
       
   470 		}
       
   471 	}
       
   472 
       
   473 TInt DRamAllocator::MarkPageAllocated(TPhysAddr aAddr)
       
   474 	{
       
   475 	__KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::MarkPageAllocated %08x",aAddr));
       
   476 	TInt n;
       
   477 	SGroup* g=GetGroupAndOffset(aAddr,n);
       
   478 	if (!g)
       
   479 		return KErrArgument;
       
   480 	__KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %04x",g-iGroups,n));
       
   481 	TBitMapAllocator& bma=*g->iBma;
       
   482 	if (bma.NotFree(n,1))
       
   483 		{
       
   484 		__KTRACE_OPT(KMMU,Kern::Printf("Page already allocated"));
       
   485 		return KErrAlreadyExists;			// page is already allocated
       
   486 		}
       
   487 	bma.Alloc(n,1);
       
   488 	--iTotalFreeRamPages;
       
   489 	TInt pwb=g->iPwrBlock;
       
   490 	if (++iPowerBlockPages[pwb]==1)
       
   491 		iPowerState|=(1u<<pwb);
       
   492 	__KTRACE_OPT(KMMU,Kern::Printf("Total free RAM pages now = %d",iTotalFreeRamPages));
       
   493 	return KErrNone;
       
   494 	}
       
   495 
       
   496 TInt DRamAllocator::FreeRamPage(TPhysAddr aAddr)
       
   497 	{
       
   498 	__KTRACE_OPT(KMMU,Kern::Printf("FreeRamPage %08x",aAddr));
       
   499 	TInt n;
       
   500 	SGroup* g=GetGroupAndOffset(aAddr,n);
       
   501 	if (!g)
       
   502 		return KErrArgument;
       
   503 	__KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %04x",g-iGroups,n));
       
   504 	TBitMapAllocator& bma=*g->iBma;
       
   505 	bma.Free(n);
       
   506 	++iTotalFreeRamPages;
       
   507 	TInt pwb=g->iPwrBlock;
       
   508 	if (--iPowerBlockPages[pwb]==0)
       
   509 		iPowerState&=~(1u<<pwb);
       
   510 	return KErrNone;
       
   511 	}
       
   512 
       
   513 void DRamAllocator::FreeRamPages(TPhysAddr* aPageList, TInt aNumPages)
       
   514 	{
       
   515 	__KTRACE_OPT(KMMU,Kern::Printf("FreeRamPages count=%08x",aNumPages));
       
   516 	while(aNumPages--)
       
   517 		{
       
   518 		TPhysAddr first_pa=*aPageList++;
       
   519 		if (first_pa==NULL_PAGE)
       
   520 			continue;
       
   521 		TInt ix;
       
   522 		SGroup* g=GetGroupAndOffset(first_pa,ix);
       
   523 		if (!g)
       
   524 			continue;
       
   525 		TBitMapAllocator& bma=*g->iBma;
       
   526 		TInt gp_rem=bma.iSize-ix;
       
   527 		__KTRACE_OPT(KMMU,Kern::Printf("1st PA=%08x Group %d index %04x",first_pa,g-iGroups,ix));
       
   528 		TInt n=1;
       
   529 		TPhysAddr pa=first_pa+iPageSize;
       
   530 		while (--gp_rem && aNumPages && *aPageList==pa)
       
   531 			{
       
   532 			++n;
       
   533 			--aNumPages;
       
   534 			++aPageList;
       
   535 			pa+=iPageSize;
       
   536 			}
       
   537 		__KTRACE_OPT(KMMU2,Kern::Printf("%d consecutive pages, gp_rem=%x, %d remaining pages",n,gp_rem,aNumPages));
       
   538 		bma.Free(ix,n);
       
   539 		iTotalFreeRamPages+=n;
       
   540 		TInt pwb=g->iPwrBlock;
       
   541 		if ((iPowerBlockPages[pwb]-=n)==0)
       
   542 			iPowerState&=~(1u<<pwb);
       
   543 		}
       
   544 	}
       
   545 
       
   546 /**
       
   547 @return 0 on success, on failure, the number of extra pages required to fulfill the request
       
   548 */
       
   549 TInt DRamAllocator::AllocRamPages(TPhysAddr* aPageList, TInt aNumPages)
       
   550 	{
       
   551 	__KTRACE_OPT(KMMU,Kern::Printf("AllocRamPages %x",aNumPages));
       
   552 	TInt numMissing = aNumPages-iTotalFreeRamPages;
       
   553 	if (numMissing>0)
       
   554 		return numMissing;
       
   555 	iTotalFreeRamPages-=aNumPages;
       
   556 	TInt gix;
       
   557 	for (gix=0; aNumPages && gix<iNumGroups; ++gix)
       
   558 		{
       
   559 		TInt group=iGroupPowerOrder?iGroupPowerOrder[gix]:gix;
       
   560 		SGroup& g=iGroups[group];
       
   561 		TBitMapAllocator& bma=*g.iBma;
       
   562 		TPhysAddr gpb=g.iPhysBase;
       
   563 		TInt got=bma.AllocList(aNumPages, (TInt*)aPageList);
       
   564 		if (got)
       
   565 			{
       
   566 			TInt pwb=g.iPwrBlock;
       
   567 			TPhysAddr* pE=aPageList+got;
       
   568 			while(aPageList<pE)
       
   569 				{
       
   570 				TInt ix=*aPageList;
       
   571 				*aPageList++=gpb+(ix<<iPageShift);
       
   572 				__KTRACE_OPT(KMMU,Kern::Printf("Got page @%08x",gpb+(ix<<iPageShift)));
       
   573 				}
       
   574 			aNumPages-=got;
       
   575 			iPowerBlockPages[pwb]+=got;
       
   576 			iPowerState |= (1u<<pwb);
       
   577 			}
       
   578 		}
       
   579 	__ASSERT_ALWAYS(aNumPages==0, Panic(EAllocRamPagesInconsistent));
       
   580 	return 0;
       
   581 	}
       
   582 
       
   583 TInt DRamAllocator::FindContiguousRam(TInt aNumPages, TInt aAlignWrtPage, TUint8* aPermute, TInt& aPageNum)
       
   584 	{
       
   585 	__KTRACE_OPT(KMMU,Kern::Printf("FindContiguousRam np=%d align=%d",aNumPages,aAlignWrtPage));
       
   586 	TUint32 alignsize=1u<<aAlignWrtPage;
       
   587 	TUint32 alignmask=alignsize-1;
       
   588 	__KTRACE_OPT(KMMU,Kern::Printf("alignsize=%08x alignmask=%08x",alignsize,alignmask));
       
   589 	TInt base=KErrNotFound;
       
   590 	TInt gplen=0;
       
   591 	TInt carry=0;
       
   592 	TInt gix;
       
   593 	for (gix=0; gix<iNumGroups; ++gix)
       
   594 		{
       
   595 		TInt group=aPermute?aPermute[gix]:gix;
       
   596 		SGroup& g=iGroups[group];
       
   597 		TBitMapAllocator& bma=*g.iBma;
       
   598 		TInt gpb=TInt(g.iPhysBase>>iPageShift);
       
   599 		if (gpb!=base+gplen)
       
   600 			{
       
   601 			// this group is not contiguous with previous one
       
   602 			carry=0;
       
   603 			}
       
   604 		base=gpb;
       
   605 		gplen=bma.iSize;
       
   606 		__KTRACE_OPT(KMMU,Kern::Printf("FCR: base=%08x gplen=%08x carry=%08x",base,gplen,carry));
       
   607 		TInt l;
       
   608 		TInt r=bma.AllocAligned(aNumPages, aAlignWrtPage, base, EFalse, carry, l);
       
   609 		__KTRACE_OPT(KMMU,Kern::Printf("FCR: r=%08x",r));
       
   610 		if (r>=0)
       
   611 			{
       
   612 			TInt p=(base+r-carry+alignmask)&~alignmask;
       
   613 			aPageNum=g.iNumBase+p-base;
       
   614 			return p;
       
   615 			}
       
   616 		}
       
   617 	return KErrNotFound;
       
   618 	}
       
   619 
       
   620 TInt DRamAllocator::AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign)
       
   621 	{
       
   622 	__KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam size %08x align %d",aSize,aAlign));
       
   623 	TInt npages=(aSize+iPageSize-1)>>iPageShift;
       
   624 	TInt align_wrt_page=Max(aAlign-iPageShift,0);
       
   625 
       
   626 	TInt pagenum;
       
   627 	TInt found=FindContiguousRam(npages, align_wrt_page, iGroupPowerOrder, pagenum);
       
   628 	if (found<0 && iGroupPowerOrder)
       
   629 		found=FindContiguousRam(npages, align_wrt_page, NULL, pagenum);
       
   630 	if (found<0)
       
   631 		return KErrNoMemory;
       
   632 	aPhysAddr=TPhysAddr(found)<<iPageShift;
       
   633 	__KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x(%x)",aPhysAddr,pagenum));
       
   634 	MarkPagesAllocated(pagenum, npages);
       
   635 	return KErrNone;
       
   636 	}
       
   637 
       
   638 TInt DRamAllocator::SetPhysicalRamState(TPhysAddr aBase, TInt aSize, TBool aState)
       
   639 	{
       
   640 	__KTRACE_OPT(KMMU,Kern::Printf("SetPhysicalRamState(%08x,%x,%d)",aBase,aSize,aState?1:0));
       
   641 	TUint32 m=iPageSize-1;
       
   642 	aSize+=(aBase&m);
       
   643 	aBase&=~m;
       
   644 	TInt npages=(aSize+m)>>iPageShift;
       
   645 	__KTRACE_OPT(KMMU,Kern::Printf("Rounded base %08x npages=%x",aBase,npages));
       
   646 	TInt ix0;
       
   647 	SGroup* g0=GetGroupAndOffset(aBase,ix0);
       
   648 	if (!g0)
       
   649 		return KErrArgument;
       
   650 	if ((TUint32)aSize>iPhysAddrTop-aBase)
       
   651 		return KErrArgument;
       
   652 	SGroup* g=g0;
       
   653 	SGroup* gE=iGroups+iNumGroups;
       
   654 	TPhysAddr base=aBase;
       
   655 	TInt n=npages;
       
   656 	TInt ix=ix0;
       
   657 	TInt r=KErrNone;
       
   658 	TInt c=-1;
       
   659 	__KTRACE_OPT(KMMU2,Kern::Printf("Group %d index %x g=%08x gE=%08x n=%x base=%08x",g-iGroups,ix,g,gE,n,base));
       
   660 	for (; n && g<gE && g->iPhysBase+(ix<<iPageShift)==base ; ++g, n-=c, ix=0, base+=(TPhysAddr(c)<<iPageShift))
       
   661 		{
       
   662 		TBitMapAllocator& bma=*g->iBma;
       
   663 		TInt gp_rem=bma.iSize-ix;
       
   664 		c=Min(n, gp_rem);
       
   665 		__KTRACE_OPT(KMMU2,Kern::Printf("Group %d pages %x+%x base %08x",g-iGroups,ix,c,base));
       
   666 		if(aState)
       
   667 			{
       
   668 			if(bma.NotAllocated(ix,c))
       
   669 				r=KErrGeneral;
       
   670 			}
       
   671 		else
       
   672 			{
       
   673 			if(bma.NotFree(ix,c))
       
   674 				r=KErrInUse;
       
   675 			}
       
   676 		}
       
   677 	if (n)
       
   678 		return KErrArgument;	// not all of the specified range exists
       
   679 	if (r!=KErrNone)
       
   680 		return r;				// some pages were already free/allocated
       
   681 	iTotalFreeRamPages += (aState ? npages : -npages);
       
   682 	for (g=g0, n=npages, ix=ix0; n; ++g, n-=c, ix=0)
       
   683 		{
       
   684 		TBitMapAllocator& bma=*g->iBma;
       
   685 		TInt pwb=g->iPwrBlock;
       
   686 		TInt& p=iPowerBlockPages[pwb];
       
   687 		TUint32 pm=1u<<pwb;
       
   688 		TInt gp_rem=bma.iSize-ix;
       
   689 		c=Min(n, gp_rem);
       
   690 		__KTRACE_OPT(KMMU2,Kern::Printf("Group %d pages %x+%x base %08x",g-iGroups,ix,c,base));
       
   691 		aState ? (bma.Free(ix,c), (p||(iPowerState|=pm)), p+=c) : (bma.Alloc(ix,c), ((p-=c)||(iPowerState&=~pm)) );
       
   692 		}
       
   693 	return KErrNone;
       
   694 	}
       
   695