os/kernelhwsrv/kernel/eka/memmodel/epoc/moving/mcodeseg.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) 1995-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 // e32\memmodel\epoc\moving\mcodeseg.cpp
    15 // 
    16 //
    17 
    18 #include "memmodel.h"
    19 #include "cache_maintenance.h"
    20 #include <demand_paging.h>
    21 
    22 _LIT(KLitUserCode,"USER$CODE");
    23 _LIT(KLitKernCode,"KERN$CODE");
    24 
    25 TInt MM::CreateCodeChunk(TBool aKernel)
    26 	{
    27 	__KTRACE_OPT(KDLL,Kern::Printf("MM::CreateCodeChunk %d",aKernel));
    28 	Mmu& m = Mmu::Get();
    29 	SChunkCreateInfo c;
    30 	c.iGlobal = ETrue;
    31 	c.iAtt = TChunkCreate::EDisconnected;
    32 	c.iForceFixed = EFalse;
    33 	c.iOperations = 0;
    34 	c.iPreallocated = 0;
    35 	c.iOwner = NULL;
    36 
    37 	if (aKernel)
    38 		{
    39 		c.iRunAddress = m.iKernelCodeBase;
    40 		c.iType = EKernelCode;
    41 		c.iMaxSize = m.iMaxKernelCodeSize;
    42 		c.iName.Set(KLitKernCode);
    43 		}
    44 	else
    45 		{
    46 		c.iRunAddress = m.iUserCodeBase;
    47 		c.iType = EDll;
    48 		c.iMaxSize = m.iMaxUserCodeSize;
    49 		c.iName.Set(KLitUserCode);
    50 		}
    51 
    52 	TLinAddr runAddr;
    53 	DMemModelChunk* pC = NULL;
    54 	TInt r=K::TheKernelProcess->NewChunk((DChunk*&)pC, c, runAddr);
    55 	if (r==KErrNone)
    56 		{
    57 		pC->SetFixedAddress(c.iRunAddress, 0);
    58 		if (aKernel)
    59 			MM::KernelCodeChunk = pC;
    60 		else
    61 			MM::UserCodeChunk = pC;
    62 		}
    63 	return r;
    64 	}
    65 
    66 DCodeSeg* M::NewCodeSeg(TCodeSegCreateInfo&)
    67 //
    68 // Create a new instance of this class.
    69 //
    70 	{
    71 
    72 	__KTRACE_OPT(KDLL,Kern::Printf("M::NewCodeSeg"));
    73 	return new DMemModelCodeSeg;
    74 	}
    75 
    76 
    77 DEpocCodeSegMemory* DEpocCodeSegMemory::New(DEpocCodeSeg* aCodeSeg)
    78 	{
    79 	return new DMemModelCodeSegMemory(aCodeSeg);
    80 	}
    81 
    82 	
    83 DMemModelCodeSegMemory::DMemModelCodeSegMemory(DEpocCodeSeg* aCodeSeg)
    84 	: DMmuCodeSegMemory(aCodeSeg)
    85 	{
    86 	}
    87 
    88 
    89 TInt DMemModelCodeSegMemory::Create(TCodeSegCreateInfo& aInfo)
    90 	{
    91 	TInt r = DMmuCodeSegMemory::Create(aInfo);
    92 	if(r!=KErrNone)
    93 		return r;
    94 
    95 	Mmu& m=Mmu::Get();
    96 
    97 	TInt codeSize = iPageCount<<m.iPageShift;
    98 	TInt dataSize = iDataPageCount<<m.iPageShift;
    99 	TInt totalSize = codeSize+dataSize;
   100 
   101 	DCodeSeg::Wait();
   102 	
   103 	DChunk::TCommitType commitType = iIsDemandPaged ? DChunk::ECommitVirtual : DChunk::ECommitDiscontiguous;
   104 	r=MM::UserCodeChunk->FindFree(totalSize, 0, 0);
   105 	if (r<0)
   106 		{
   107 		r = KErrNoMemory;
   108 		goto exit;
   109 		}
   110 	iCodeAllocBase = r;
   111 	r = KErrNone;
   112 	
   113 	r=MM::UserCodeChunk->Commit(iCodeAllocBase, codeSize, commitType);
   114 	if (r<0)
   115 		{
   116 		r = KErrNoMemory;
   117 		goto exit;
   118 		}
   119 	
   120 	iRamInfo.iCodeRunAddr = ((TLinAddr)MM::UserCodeChunk->Base())+iCodeAllocBase;
   121 	iRamInfo.iCodeLoadAddr = iRamInfo.iCodeRunAddr;
   122 
   123 	if (iRamInfo.iDataSize)
   124 		{
   125 		if(iDataPageCount)
   126 			iRamInfo.iDataLoadAddr = iRamInfo.iCodeLoadAddr+codeSize;
   127 		else
   128 			iRamInfo.iDataLoadAddr = iRamInfo.iCodeLoadAddr+iRamInfo.iCodeSize;
   129 		}
   130 	
   131 	if (!iIsDemandPaged)
   132 		{
   133 		TInt loadedSize = iRamInfo.iCodeSize+iRamInfo.iDataSize;
   134 		memset((TAny*)(iRamInfo.iCodeLoadAddr+loadedSize), 0x03, totalSize-loadedSize);
   135 		}
   136 	else
   137 		{
   138 		if(dataSize)
   139 			{
   140 			r=MM::UserCodeChunk->Commit(iCodeAllocBase+codeSize, dataSize, DChunk::ECommitDiscontiguous);
   141 			if (r<0)
   142 				goto exit;
   143 			memset((TAny*)(iRamInfo.iCodeLoadAddr+codeSize+iRamInfo.iDataSize), 0x03, dataSize-iRamInfo.iDataSize);
   144 			}
   145 		}
   146 
   147 exit:
   148 	DCodeSeg::Signal();
   149 	return r;
   150 	}
   151 
   152 	
   153 TInt DMemModelCodeSegMemory::Loaded(TCodeSegCreateInfo& aInfo)
   154 	{
   155 	TInt r = DMmuCodeSegMemory::Loaded(aInfo);
   156 	if(r!=KErrNone)
   157 		return r;
   158 
   159 	Mmu& m=Mmu::Get();
   160 	TInt pageShift = m.iPageShift;
   161 
   162 	if(iIsDemandPaged)
   163 		{
   164 		// apply code fixups to pages which have already been loaded...
   165 		TLinAddr loadAddr = iRamInfo.iCodeLoadAddr;
   166 		TLinAddr loadAddrEnd = loadAddr+iRamInfo.iCodeSize;
   167 		TLinAddr runAddr = iRamInfo.iCodeLoadAddr;
   168 		TInt pageSize = 1<<pageShift;
   169 		for(; loadAddr<loadAddrEnd; loadAddr+=pageSize,runAddr+=pageSize)
   170 			{
   171 			if(m.LinearToPhysical(loadAddr)!=KPhysAddrInvalid)
   172 				{
   173 				r = ApplyCodeFixupsOnLoad((TUint32*)loadAddr,runAddr);
   174 				if(r!=KErrNone)
   175 					return r;
   176 				}
   177 			}
   178 		}
   179 	CacheMaintenance::CodeChanged(iRamInfo.iCodeLoadAddr, iRamInfo.iCodeSize);
   180 
   181 	// discard any temporary pages used to store loaded data section...
   182 	if(iDataPageCount)
   183 		{
   184 		TInt codeSize = iPageCount<<pageShift;
   185 		MM::UserCodeChunk->Decommit(iCodeAllocBase+codeSize, iDataPageCount<<pageShift);
   186 		iDataPageCount = 0;
   187 		//Reduce the size of the DCodeSeg now the data section has been moved
   188 		iCodeSeg->iSize = codeSize;
   189 		}
   190 
   191 	return KErrNone;
   192 	}
   193 
   194 	
   195 void DMemModelCodeSegMemory::Destroy()
   196 	{
   197 	if(iCodeAllocBase!=KMinTInt && iDataPageCount)
   198 		{
   199 		Mmu& m=Mmu::Get();
   200 		TInt dataSize = iDataPageCount<<m.iPageShift;
   201 		TInt codeSize = iPageCount<<m.iPageShift;
   202 		if(dataSize)
   203 			MM::UserCodeChunk->Decommit(iCodeAllocBase+codeSize, dataSize);
   204 		}
   205 	}
   206 
   207 
   208 DMemModelCodeSegMemory::~DMemModelCodeSegMemory()
   209 	{
   210 	if(iCodeAllocBase!=KMinTInt)
   211 		{
   212 		Mmu& m=Mmu::Get();
   213 		TInt codeSize = iPageCount<<m.iPageShift;
   214 		DMemModelChunk::TDecommitType decommitType = iIsDemandPaged ? DChunk::EDecommitVirtual : DChunk::EDecommitNormal;
   215 		MM::UserCodeChunk->Decommit(iCodeAllocBase, codeSize, decommitType);
   216 		}
   217 	}
   218 
   219 
   220 DMemModelCodeSeg::DMemModelCodeSeg()
   221 //
   222 // Constructor
   223 //
   224 	:	iCodeAllocBase(KMinTInt),
   225 		iDataAllocBase(KMinTInt)
   226 	{
   227 	}
   228 
   229 DMemModelCodeSeg::~DMemModelCodeSeg()
   230 //
   231 // Destructor
   232 //
   233 	{
   234 	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelCodeSeg::Destruct %C", this));
   235 	Mmu& m=Mmu::Get();
   236 	if (!iXIP && iMemory)
   237 		{
   238 		SRamCodeInfo& ri=RamInfo();
   239 		DCodeSeg::Wait();
   240 		if (iCodeAllocBase!=KMinTInt)
   241 			{
   242 			TBool kernel=( (iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel );
   243 			if (kernel)
   244 				MM::KernelCodeChunk->Decommit(iCodeAllocBase, iSize);
   245 			}
   246 		Memory()->Destroy();
   247 		TInt data_alloc=(ri.iDataSize+ri.iBssSize+m.iPageMask)>>m.iPageShift;
   248 		if (iDataAllocBase>=0)
   249 			{
   250 			MM::DllDataAllocator->Free(iDataAllocBase, data_alloc);
   251 			}
   252 		else if (iDataAllocBase==-1)
   253 			{
   254 			DMemModelProcess* p=(DMemModelProcess*)iAttachProcess;
   255 			if (p->iExitType==EExitPending)
   256 				{
   257 				DMemModelChunk& c=*p->iDllDataChunk;
   258 				TInt offset=ri.iDataRunAddr-TLinAddr(c.Base());
   259 				c.Decommit(offset, data_alloc<<m.iPageShift);
   260 				if (c.iSize==0)
   261 					p->FreeDllDataChunk();
   262 				}
   263 			}
   264 		DCodeSeg::Signal();
   265 		}
   266 	Kern::Free(iKernelData);
   267 	DEpocCodeSeg::Destruct();
   268 	}
   269 
   270 
   271 TInt DMemModelCodeSeg::DoCreateRam(TCodeSegCreateInfo& aInfo, DProcess* aProcess)
   272 	{
   273 	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelCodeSeg::DoCreateRam %C proc %O", this, aProcess));
   274 	TBool kernel=( (iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel );
   275 	DMemModelProcess* p=(DMemModelProcess*)aProcess;
   276 	Mmu& m=Mmu::Get();
   277 	SRamCodeInfo& ri=RamInfo();
   278 	iSize = Mmu::RoundToPageSize(ri.iCodeSize+ri.iDataSize);
   279 	if (iSize==0)
   280 		return KErrCorrupt;
   281 	TInt total_data_size=ri.iDataSize+ri.iBssSize;
   282 	TInt r=KErrNone;
   283 	if (kernel)
   284 		{
   285 		r=MM::KernelCodeChunk->Allocate(iSize, 0, 0);
   286 		if (r<0)
   287 			return r;
   288 		iCodeAllocBase=r;
   289 		ri.iCodeRunAddr=(TUint32)MM::KernelCodeChunk->Base();
   290 		ri.iCodeRunAddr+=r;
   291 		ri.iCodeLoadAddr=ri.iCodeRunAddr;
   292 		if (ri.iDataSize)
   293 			ri.iDataLoadAddr=ri.iCodeLoadAddr+ri.iCodeSize;
   294 		if (total_data_size)
   295 			{
   296 			iKernelData=Kern::Alloc(total_data_size);
   297 			if (!iKernelData)
   298 				return KErrNoMemory;
   299 			ri.iDataRunAddr=(TLinAddr)iKernelData;
   300 			}
   301 		return KErrNone;
   302 		}
   303 
   304 	r = Memory()->Create(aInfo);
   305 	if(r!=KErrNone)
   306 		return r;
   307 
   308 	r=KErrNone;
   309 	if (total_data_size && p && p->iAttributes&DMemModelProcess::EFixedAddress)
   310 		{
   311 		SetAttachProcess(p);
   312 		}
   313 	if (total_data_size && !IsExe())
   314 		{
   315 		TInt data_alloc_size=Mmu::RoundToPageSize(total_data_size);
   316 		TInt data_alloc=data_alloc_size>>m.iPageShift;
   317 		DCodeSeg::Wait();
   318 		if (p)
   319 			{
   320 			if (p->iExitType!=EExitPending)
   321 				return KErrDied;
   322 			}
   323 		if (iAttachProcess)
   324 			{
   325 			r=KErrNone;
   326 			if (!p->iDllDataChunk)
   327 				r=p->CreateDllDataChunk();
   328 			if (r==KErrNone)
   329 				{
   330 				DMemModelChunk& c=*p->iDllDataChunk;
   331 				r=c.Allocate(data_alloc_size, 0, 0);
   332 				if (r>=0)
   333 					{
   334 					ri.iDataRunAddr=TLinAddr(c.Base())+r;
   335 					iDataAllocBase=-1;
   336 					r=KErrNone;
   337 					}
   338 				else
   339 					{
   340 					if (c.iSize==0)
   341 						p->FreeDllDataChunk();
   342 					r=KErrNoMemory;
   343 					}
   344 				}
   345 			}
   346 		else
   347 			{
   348 			r=MM::DllDataAllocator->AllocConsecutive(data_alloc, ETrue);
   349 			if (r>=0)
   350 				MM::DllDataAllocator->Alloc(r, data_alloc);
   351 			if (r>=0)
   352 				{
   353 				iDataAllocBase=r;
   354 				ri.iDataRunAddr=m.iDataSectionEnd-((r+data_alloc)<<m.iPageShift);
   355 				r=KErrNone;
   356 				}
   357 			else
   358 				r=KErrNoMemory;
   359 			}
   360 		DCodeSeg::Signal();
   361 		}
   362 	if(r!=KErrNone)
   363 		return r;
   364 	
   365 	return r;
   366 	}
   367 
   368 
   369 TInt DMemModelCodeSeg::DoCreateXIP(DProcess* aProcess)
   370 	{
   371 	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelCodeSeg::DoCreateXIP %C proc %O", this, aProcess));
   372 	DMemModelProcess* p=(DMemModelProcess*)aProcess;
   373 	TInt r=KErrNone;
   374 	TBool kernel=( (iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel );
   375 	const TRomImageHeader& rih=RomInfo();
   376 	TBool fixed=p && (p->iAttributes&DMemModelProcess::EFixedAddress);
   377 	if (!kernel && fixed)
   378 		{
   379 		// XIP images with static data loaded into fixed processes are specific to a single process
   380 		if (rih.iFlags&KRomImageFlagDataPresent)
   381 			{
   382 			if (rih.iTotalDataSize)
   383 				{
   384 				TLinAddr process_data_base=p->iDataBssRunAddress;
   385 				TUint32 process_data_maxsize=p->iDataBssStackChunk->iMaxSize;
   386 				if (rih.iDataBssLinearBase<process_data_base || 
   387 					(rih.iDataBssLinearBase+rih.iTotalDataSize)>(process_data_base+process_data_maxsize))
   388 					return KErrNotSupported;
   389 				}
   390 			SetAttachProcess(p);
   391 			iDataAllocBase=-1;
   392 			}
   393 		}
   394 	return r;
   395 	}
   396 
   397 
   398 TInt DMemModelCodeSeg::Loaded(TCodeSegCreateInfo& aInfo)
   399 	{
   400 	if (!iXIP)
   401 		{
   402 		TBool kernel=( (iAttr&(ECodeSegAttKernel|ECodeSegAttGlobal)) == ECodeSegAttKernel );
   403 		if(kernel)
   404 			{
   405 			// Clean DCache for specified area, Invalidate ICache/BTB for specified area
   406 			SRamCodeInfo& ri=RamInfo();
   407 			CacheMaintenance::CodeChanged(ri.iCodeRunAddr, ri.iCodeSize);
   408 			}
   409 		else
   410 			{
   411 			TInt r = Memory()->Loaded(aInfo);
   412 			if(r!=KErrNone)
   413 				return r;
   414 			}
   415 		}
   416 	return DEpocCodeSeg::Loaded(aInfo);
   417 	}
   418 
   419 
   420 void DMemModelCodeSeg::ReadExportDir(TUint32* aDest)
   421 	{
   422 	__KTRACE_OPT(KDLL,Kern::Printf("DMemModelCodeSeg::ReadExportDir %08x",aDest));
   423 	if (!iXIP)
   424 		{
   425 		SRamCodeInfo& ri=RamInfo();
   426 		TInt size=(ri.iExportDirCount+1)*sizeof(TLinAddr);
   427 		kumemput32(aDest, (const TUint32*)(ri.iExportDir-sizeof(TUint32)), size);
   428 		}
   429 	}
   430 
   431 TBool DMemModelCodeSeg::OpenCheck(DProcess* aProcess)
   432 	{
   433 	return FindCheck(aProcess);
   434 	}
   435 
   436 TBool DMemModelCodeSeg::FindCheck(DProcess* aProcess)
   437 	{
   438 	__KTRACE_OPT(KDLL,Kern::Printf("CSEG:%08x Compat? proc=%O",this,aProcess));
   439 	if (!aProcess)
   440 		return !iAttachProcess;	// can't reuse same code segment for a new instance of the process
   441 	DMemModelProcess& p=*(DMemModelProcess*)aProcess;
   442 	DCodeSeg* pPSeg=p.CodeSeg();
   443 	if (iAttachProcess && iAttachProcess!=aProcess)
   444 		return EFalse;
   445 	if (iExeCodeSeg && iExeCodeSeg!=pPSeg)
   446 		return EFalse;
   447 	if (!iAttachProcess && (iMark & EMarkDataPresent))
   448 		{
   449 		// code seg used for moving processes, data present
   450 		if (p.iAttributes & DMemModelProcess::EFixedAddress)
   451 			return EFalse;
   452 		}
   453 	return ETrue;
   454 	}