kernel/eka/memmodel/epoc/moving/mcodeseg.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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 	}