| 0 |      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 "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\putils.cpp
 | 
|  |     15 | // EPOC implementation of the ROM related parts of the system
 | 
|  |     16 | // 
 | 
|  |     17 | //
 | 
|  |     18 | 
 | 
|  |     19 | #include "plat_priv.h"
 | 
|  |     20 | #include <e32uid.h>
 | 
|  |     21 | #include "execs.h"
 | 
|  |     22 | #include "cache_maintenance.h"
 | 
|  |     23 | 
 | 
|  |     24 | _LIT(KKernelFullPathNameSysBin,"z:\\sys\\bin\\ekern.exe");
 | 
|  |     25 | 
 | 
|  |     26 | #ifdef __MARM__
 | 
|  |     27 | #define	CHECK_ROM_ENTRY_POINT(a)	__ASSERT_ALWAYS( ((a).iFlags & KRomImageEptMask) == KRomImageEpt_Eka2, PP::Panic(PP::EUnsupportedOldBinary) )
 | 
|  |     28 | #else
 | 
|  |     29 | #define	CHECK_ROM_ENTRY_POINT(a)
 | 
|  |     30 | #endif
 | 
|  |     31 | 
 | 
|  |     32 | void PP::Panic(TPlatPanic aPanic)
 | 
|  |     33 | 	{
 | 
|  |     34 | 	Kern::Fault("PLAT",aPanic);
 | 
|  |     35 | 	}
 | 
|  |     36 |  
 | 
|  |     37 | void PP::InitSuperPageFromRom(TLinAddr aRomHeader, TLinAddr aSuperPage)
 | 
|  |     38 | 	{
 | 
|  |     39 | 	RomHeaderAddress = aRomHeader;
 | 
|  |     40 | 	SuperPageAddress = aSuperPage;
 | 
|  |     41 | 
 | 
|  |     42 | 	TInt j;
 | 
|  |     43 | 	for (j = 0; j < KNumTraceMaskWords; j++)
 | 
|  |     44 | 		TheSuperPage().iDebugMask[j] = TheRomHeader().iTraceMask[j];
 | 
|  |     45 | 
 | 
|  |     46 | 	for (j = 0; j < 8; j++)
 | 
|  |     47 | 		TheSuperPage().iInitialBTraceFilter[j] = TheRomHeader().iInitialBTraceFilter[j];
 | 
|  |     48 | 
 | 
|  |     49 | 	Kern::SuperPage().iInitialBTraceBuffer = TheRomHeader().iInitialBTraceBuffer;
 | 
|  |     50 | 	Kern::SuperPage().iInitialBTraceMode = TheRomHeader().iInitialBTraceMode;
 | 
|  |     51 | 
 | 
|  |     52 | 	TheSuperPage().SetKernelConfigFlags(TheRomHeader().iKernelConfigFlags);
 | 
|  |     53 | 
 | 
|  |     54 | 	memcpy(&TheSuperPage().iDisabledCapabilities, &TheRomHeader().iDisabledCapabilities, sizeof(TheRomHeader().iDisabledCapabilities));
 | 
|  |     55 | 	}
 | 
|  |     56 | 
 | 
|  |     57 | TInt P::DefaultInitialTime()
 | 
|  |     58 | 	{
 | 
|  |     59 | //
 | 
|  |     60 | // Default implementation of the kernel hook for getting the initial system
 | 
|  |     61 | // time, can be overriden by variant.
 | 
|  |     62 | //
 | 
|  |     63 |     TInt seconds;
 | 
|  |     64 | 	if (K::ColdStart || A::SystemTimeInSecondsFrom2000(seconds)!=KErrNone)
 | 
|  |     65 | 		return KErrCorrupt;
 | 
|  |     66 | 	else
 | 
|  |     67 | 		return seconds;
 | 
|  |     68 | 	}
 | 
|  |     69 | 
 | 
|  |     70 | TInt P::InitSystemTime()
 | 
|  |     71 | 	{
 | 
|  |     72 | //
 | 
|  |     73 | //  Initialise system time
 | 
|  |     74 | //	Return the initial time in seconds from 00:00:00 01-01-2000
 | 
|  |     75 | //
 | 
|  |     76 | 
 | 
|  |     77 | 	// Reset the UTC offset (I assume this gets loaded from storage at some point after F32 loads)
 | 
|  |     78 | 	TUint dummy;
 | 
|  |     79 | 	K::SetSystemTimeAndOffset(0, 0, 0, dummy, ETimeSetOffset | ETimeSetNoTimeUpdate);
 | 
|  |     80 | 
 | 
|  |     81 | 	// Read the hardware clock value. If this is negative it means it couldnt be read.
 | 
|  |     82 |     TInt seconds = K::InitialTimeHandler()();	
 | 
|  |     83 | 
 | 
|  |     84 | 	if (seconds >= 0)
 | 
|  |     85 | 		{
 | 
|  |     86 | 		K::SecureClockStatus |= ESecureClockPresent;
 | 
|  |     87 | 		__KTRACE_OPT(KBOOT,Kern::Printf("Read initial system time"));
 | 
|  |     88 | 		// now=Hardware RTC value
 | 
|  |     89 | 		}
 | 
|  |     90 | 	else 
 | 
|  |     91 | 		{
 | 
|  |     92 | 		__KTRACE_OPT(KBOOT,Kern::Printf("Could not read initial system time - using ROM timestamp to set system time"));
 | 
|  |     93 | 		TTimeK rom_time=*(const TTimeK*)&TheRomHeader().iTime;
 | 
|  |     94 | 		rom_time -= TTimeK(K::HomeTimeOffsetSeconds)*1000000;
 | 
|  |     95 | 		TInt s;
 | 
|  |     96 | 		TInt r=K::SecondsFrom2000(rom_time,s);
 | 
|  |     97 | 		if (r!=KErrNone)
 | 
|  |     98 | 			PP::Panic(PP::EInitialSystemTimeInvalid);
 | 
|  |     99 | 		seconds=s;
 | 
|  |    100 | 
 | 
|  |    101 | 		// write the ROM timestamp to the hardware RTC
 | 
|  |    102 | 		A::SetSystemTimeInSecondsFrom2000(seconds);
 | 
|  |    103 | 		}
 | 
|  |    104 | 	return seconds;
 | 
|  |    105 | 	}
 | 
|  |    106 | 
 | 
|  |    107 | 
 | 
|  |    108 | void FindRomRootDirectory()
 | 
|  |    109 | 	{
 | 
|  |    110 | 	TUint variant = TheSuperPage().iActiveVariant;
 | 
|  |    111 | 	TUint cpu = (variant >> 16) & 0xff;
 | 
|  |    112 | 	TUint asic = (variant >> 24);
 | 
|  |    113 | 	PP::RomRootDirAddress=0;
 | 
|  |    114 | 	TRomRootDirectoryList* pL=(TRomRootDirectoryList*)TheSuperPage().iRootDirList;
 | 
|  |    115 | 	if (!pL)
 | 
|  |    116 | 		pL=(TRomRootDirectoryList*)TheRomHeader().iRomRootDirectoryList;
 | 
|  |    117 | 	TInt i;
 | 
|  |    118 | 	for (i=0; i<pL->iNumRootDirs; i++)
 | 
|  |    119 | 		{
 | 
|  |    120 | 		if (THardwareVariant(pL->iRootDir[i].iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
 | 
|  |    121 | 			{
 | 
|  |    122 | 			__KTRACE_OPT(KBOOT,Kern::Printf("Found ROM root dir index %d addr %08x",
 | 
|  |    123 | 				i, pL->iRootDir[i].iAddressLin));
 | 
|  |    124 | 			PP::RomRootDirAddress=pL->iRootDir[i].iAddressLin;
 | 
|  |    125 | 			return;
 | 
|  |    126 | 			}
 | 
|  |    127 | 		}
 | 
|  |    128 | 	}
 | 
|  |    129 | 
 | 
|  |    130 | typedef TInt (*TInitVarExtFn)(const TRomImageHeader&);
 | 
|  |    131 | 
 | 
|  |    132 | #ifdef KBOOT
 | 
|  |    133 | void DumpRomFileInfo(const TRomEntry& aRomEntry)
 | 
|  |    134 | 	{
 | 
|  |    135 | 	TBuf8<128> name;
 | 
|  |    136 | 	TInt i;
 | 
|  |    137 | 	for (i=0; i<aRomEntry.iNameLength; ++i)
 | 
|  |    138 | 		{
 | 
|  |    139 | 		name.Append(TChar(aRomEntry.iName[i<<1]&0xff));
 | 
|  |    140 | 		}
 | 
|  |    141 | 	const TRomImageHeader& img = *(const TRomImageHeader*)aRomEntry.iAddressLin;
 | 
|  |    142 | 	__KTRACE_OPT(KBOOT,Kern::Printf("File %S[%08x]", &name, TUint(img.iHardwareVariant) ));
 | 
|  |    143 | 	}
 | 
|  |    144 | #endif
 | 
|  |    145 | 
 | 
|  |    146 | void InitVarExt(TBool aVar, TInitVarExtFn aFn)
 | 
|  |    147 | 	{
 | 
|  |    148 | 	__KTRACE_OPT(KBOOT,Kern::Printf("InitVarExt var=%d, fn=%08x", aVar, aFn));
 | 
|  |    149 | 	TUint variant = TheSuperPage().iActiveVariant;
 | 
|  |    150 | 	TUint cpu = (variant >> 16) & 0xff;
 | 
|  |    151 | 	TUint asic = (variant >> 24);
 | 
|  |    152 | 	__KTRACE_OPT(KBOOT,Kern::Printf("cpu=%d, asic=%d, variant=%x", cpu, asic, variant));
 | 
|  |    153 | 	const TRomHeader& rh = TheRomHeader();
 | 
|  |    154 | 	TRomEntry* pE = aVar ? (TRomEntry*)rh.iVariantFile : (TRomEntry*)rh.iExtensionFile;
 | 
|  |    155 | 	while(pE)
 | 
|  |    156 | 		{
 | 
|  |    157 | #ifdef KBOOT
 | 
|  |    158 | 		DumpRomFileInfo(*pE);
 | 
|  |    159 | #endif
 | 
|  |    160 | 		const TRomImageHeader& img = *(const TRomImageHeader*)pE->iAddressLin;
 | 
|  |    161 | 		if (THardwareVariant(img.iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
 | 
|  |    162 | 			{
 | 
|  |    163 | 			__KTRACE_OPT(KBOOT,Kern::Printf("Processing"));
 | 
|  |    164 | 			(*aFn)(img);
 | 
|  |    165 | 			if (aVar)
 | 
|  |    166 | 				{
 | 
|  |    167 | 				__KTRACE_OPT(KBOOT,Kern::Printf("Variant installed"));
 | 
|  |    168 | 				return;
 | 
|  |    169 | 				}
 | 
|  |    170 | 			}
 | 
|  |    171 | 		pE=(TRomEntry*)img.iNextExtension;
 | 
|  |    172 | 		}
 | 
|  |    173 | 	if (aVar)
 | 
|  |    174 | 		Kern::Fault("NoVariant",0);
 | 
|  |    175 | 	}
 | 
|  |    176 | 
 | 
|  |    177 | TInt InitData(const TRomImageHeader& a)
 | 
|  |    178 | 	{
 | 
|  |    179 | 	__KTRACE_OPT(KBOOT,Kern::Printf("InitData %08x+%x->%08x", a.iDataAddress, a.iDataSize, a.iDataBssLinearBase));
 | 
|  |    180 | 	CHECK_ROM_ENTRY_POINT(a);
 | 
|  |    181 | 	if (a.iDataSize)
 | 
|  |    182 | 		memcpy((TAny*)a.iDataBssLinearBase,(TAny*)a.iDataAddress,a.iDataSize);
 | 
|  |    183 | 	TLibraryEntry ep = (TLibraryEntry)a.iEntryPoint;
 | 
|  |    184 | 	__KTRACE_OPT(KBOOT,Kern::Printf("Calling entrypoint %08x(VariantInit0)", ep));
 | 
|  |    185 | 	TInt r = ep(KModuleEntryReasonVariantInit0);
 | 
|  |    186 | 	__KTRACE_OPT(KBOOT,Kern::Printf("Entrypoint returned %d",r));
 | 
|  |    187 | 	if(!(++K::ExtensionCount&0x7fffffff))
 | 
|  |    188 | 		K::Fault(K::ETooManyExtensions);
 | 
|  |    189 | 	return r;
 | 
|  |    190 | 	}
 | 
|  |    191 | 
 | 
|  |    192 | TInt InitVariant(const TRomImageHeader& a)
 | 
|  |    193 | 	{
 | 
|  |    194 | 	TInt r = InitData(a);
 | 
|  |    195 | 	__KTRACE_OPT(KBOOT,Kern::Printf("InitVariant: entry point returns %08x", r));
 | 
|  |    196 | 	if (r<0)
 | 
|  |    197 | 		Kern::Fault("VariantEntry",r);
 | 
|  |    198 | 
 | 
|  |    199 | 	// Initialise and create the variant object
 | 
|  |    200 | 	r = A::CreateVariant(&a, r);
 | 
|  |    201 | 	if (r<0)
 | 
|  |    202 | 		Kern::Fault("VariantInit",r);
 | 
|  |    203 | 	return r;
 | 
|  |    204 | 	}
 | 
|  |    205 | 
 | 
|  |    206 | void P::CreateVariant()
 | 
|  |    207 | 	{
 | 
|  |    208 | 	__KTRACE_OPT(KBOOT,Kern::Printf("CreateVariant"));
 | 
|  |    209 | 	BTrace::Init0();
 | 
|  |    210 | 	InitVarExt(EFalse, &InitData);		// initialise .data for all extensions
 | 
|  |    211 | 	InitVarExt(ETrue, &InitVariant);	// find variant and initialise it
 | 
|  |    212 | 	FindRomRootDirectory();
 | 
|  |    213 | 	}
 | 
|  |    214 | 
 | 
|  |    215 | struct SExtInit1EntryPoint
 | 
|  |    216 | 	{
 | 
|  |    217 | 	inline SExtInit1EntryPoint() : iEntryPoint(0),iReturnCode(0)
 | 
|  |    218 | 		{}
 | 
|  |    219 | 	inline SExtInit1EntryPoint(TLibraryEntry aEp, TInt aVal) : iEntryPoint(aEp),iReturnCode(aVal)
 | 
|  |    220 | 		{}
 | 
|  |    221 | 	TLibraryEntry iEntryPoint;
 | 
|  |    222 | 	TInt iReturnCode;		// bits 7-0 used for extension startup priority order
 | 
|  |    223 | 	};
 | 
|  |    224 | 
 | 
|  |    225 | // This ordering function when used in conjunction with RArray<>::InsertInOrderAllowRepeats
 | 
|  |    226 | // orders the array of extensions as follow:
 | 
|  |    227 | //		highest priority -> lowest priority
 | 
|  |    228 | //		if same priority -> first in, lowest index
 | 
|  |    229 | //
 | 
|  |    230 | TInt priorityOrder(const SExtInit1EntryPoint& aMatch, const SExtInit1EntryPoint& aEntry)
 | 
|  |    231 | 	{
 | 
|  |    232 | 	TUint8 l=(TUint8)aMatch.iReturnCode;
 | 
|  |    233 | 	TUint8 r=(TUint8)aEntry.iReturnCode;
 | 
|  |    234 | 	if(l>r)
 | 
|  |    235 | 		return -1;
 | 
|  |    236 | 	else if(l<r)
 | 
|  |    237 | 		return 1;
 | 
|  |    238 | 	else
 | 
|  |    239 | 		return 0;
 | 
|  |    240 | 	}
 | 
|  |    241 | 
 | 
|  |    242 | TInt InitExt0(const TRomImageHeader& a)
 | 
|  |    243 | 	{
 | 
|  |    244 | 	CHECK_ROM_ENTRY_POINT(a);
 | 
|  |    245 | 	TLibraryEntry ep = (TLibraryEntry)a.iEntryPoint;
 | 
|  |    246 | 	__KTRACE_OPT(KBOOT,Kern::Printf("InitExt0 %08x ep=%08x", &a, ep));
 | 
|  |    247 | 	TInt r = (*ep)(KModuleEntryReasonExtensionInit0);
 | 
|  |    248 | 	if (r<KErrNone)
 | 
|  |    249 | 		{
 | 
|  |    250 | 		__KTRACE_OPT(KBOOT,Kern::Printf("Already started"));
 | 
|  |    251 | 		return r;
 | 
|  |    252 | 		}
 | 
|  |    253 | 	SExtInit1EntryPoint s(ep,r);
 | 
|  |    254 | 	TInt count=K::ExtensionArray->Count();
 | 
|  |    255 | 	if(count==K::ExtensionCount)					// this function is only called if extensions exist, i.e. K::ExtensionCount>0
 | 
|  |    256 | 		K::Fault(K::EExtensionArrayOverflowed);		// the first insertion will allocate space for K::ExtensionCount entries and that is the maximum number of entries allowed
 | 
|  |    257 | 	TLinearOrder<SExtInit1EntryPoint> PriorityOrder(priorityOrder);
 | 
|  |    258 | 	if(K::ExtensionArray->InsertInOrderAllowRepeats(s,PriorityOrder)!=KErrNone)
 | 
|  |    259 | 		K::Fault(K::EInsertExtensionFailed);
 | 
|  |    260 | 	__KTRACE_OPT(KBOOT,Kern::Printf("Inserted at index %d, priority %d, last index %d", K::ExtensionArray->SpecificFindInOrder(s,PriorityOrder,EArrayFindMode_Last)-1, (TUint8)r, count));
 | 
|  |    261 | 	return KErrNone;
 | 
|  |    262 | 	}
 | 
|  |    263 | 
 | 
|  |    264 | void P::StartExtensions()
 | 
|  |    265 | 	{
 | 
|  |    266 | 	// start extensions...
 | 
|  |    267 | 	__KTRACE_OPT(KBOOT, Kern::Printf("Starting kernel extensions..."));
 | 
|  |    268 | 
 | 
|  |    269 | 	K::ExtensionArray = new RArray<SExtInit1EntryPoint>(--K::ExtensionCount);	// ordered array of extensions excluding Variant
 | 
|  |    270 | 	if(!K::ExtensionArray)
 | 
|  |    271 | 		K::Fault(K::EExtensionArrayAllocationFailed);
 | 
|  |    272 | 	__KTRACE_OPT(KBOOT, Kern::Printf("Entry point array at %08x, max size %d",K::ExtensionArray,K::ExtensionCount));
 | 
|  |    273 | 
 | 
|  |    274 | 	InitVarExt(EFalse, &InitExt0);		// populates the array of entry points in priority order
 | 
|  |    275 | 
 | 
|  |    276 | 	for(TInt i=0; i<K::ExtensionArray->Count(); i++)	// call entry points in combined priority and temporal orders
 | 
|  |    277 | 		{
 | 
|  |    278 | 		TLibraryEntry ep = (*K::ExtensionArray)[i].iEntryPoint;
 | 
|  |    279 | 		__KTRACE_OPT(KBOOT,Kern::Printf("InitExt1: calling entrypoint %08x", ep));
 | 
|  |    280 | 		TInt r = ep(KModuleEntryReasonExtensionInit1);
 | 
|  |    281 | 		__KTRACE_OPT(KBOOT,Kern::Printf("Entrypoint returned %d", r));
 | 
|  |    282 | 		if (r!=KErrNone)
 | 
|  |    283 | 			K::Fault(K::EStartExtensionsFailed);
 | 
|  |    284 | 		}
 | 
|  |    285 | 	// preserve array of extensions, it contains the returned codes from ExtInit0 which may be useful for future use
 | 
|  |    286 | 	//delete K::ExtensionArray;
 | 
|  |    287 | 	//K::ExtensionArray=NULL;
 | 
|  |    288 | 	}
 | 
|  |    289 | 
 | 
|  |    290 | void P::KernelInfo(TProcessCreateInfo& aInfo, TAny*& aStack, TAny*& aHeap)
 | 
|  |    291 | //
 | 
|  |    292 | // Provide the initial supervisor data information from the ROM
 | 
|  |    293 | //
 | 
|  |    294 | 	{
 | 
|  |    295 | 	aInfo.iFileName=KKernelFullPathNameSysBin;
 | 
|  |    296 | 	aInfo.iRootNameOffset=11;
 | 
|  |    297 | 	aInfo.iRootNameLength=9;
 | 
|  |    298 | 	aInfo.iExtOffset = 16;
 | 
|  |    299 | 
 | 
|  |    300 | 	aInfo.iAttr=ECodeSegAttKernel|ECodeSegAttFixed;
 | 
|  |    301 | 
 | 
|  |    302 | 	const TRomHeader& romHdr=TheRomHeader();
 | 
|  |    303 | 	const TRomEntry* primaryEntry=(const TRomEntry*)TheSuperPage().iPrimaryEntry;
 | 
|  |    304 | 	const TRomImageHeader* primaryImageHeader=(const TRomImageHeader*)primaryEntry->iAddressLin;
 | 
|  |    305 | 	Epoc::RomProcessInfo(aInfo, *primaryImageHeader);
 | 
|  |    306 | 	aStack = (TAny*)(romHdr.iKernDataAddress + Kern::RoundToPageSize(romHdr.iTotalSvDataSize));
 | 
|  |    307 | 	aHeap = (TAny*)(TLinAddr(aStack) + Kern::RoundToPageSize(aInfo.iStackSize));
 | 
|  |    308 | 	aInfo.iTotalDataSize=romHdr.iTotalSvDataSize;
 | 
|  |    309 | 	aInfo.iHeapSizeMin=TheSuperPage().iInitialHeapSize;
 | 
|  |    310 | 	}
 | 
|  |    311 | 
 | 
|  |    312 | EXPORT_C void Epoc::RomProcessInfo(TProcessCreateInfo& aInfo, const TRomImageHeader& a)
 | 
|  |    313 | 	{
 | 
|  |    314 | 	CHECK_PAGING_SAFE;
 | 
|  |    315 | 	aInfo.iUids=*(const TUidType*)&a.iUid1;
 | 
|  |    316 | 	aInfo.iCodeSize=a.iCodeSize;
 | 
|  |    317 | 	aInfo.iTextSize=a.iTextSize;
 | 
|  |    318 | 	aInfo.iDataSize=a.iDataSize;
 | 
|  |    319 | 	aInfo.iBssSize=a.iBssSize;
 | 
|  |    320 | 	aInfo.iTotalDataSize=a.iTotalDataSize;
 | 
|  |    321 | 	aInfo.iEntryPtVeneer=a.iEntryPoint;
 | 
|  |    322 | 	aInfo.iFileEntryPoint=a.iEntryPoint;
 | 
|  |    323 | 	aInfo.iDepCount=a.iDllRefTable ? a.iDllRefTable->iNumberOfEntries : 0;
 | 
|  |    324 | 	aInfo.iExportDir=a.iExportDir;
 | 
|  |    325 | 	aInfo.iExportDirCount=a.iExportDirCount;
 | 
|  |    326 | 	aInfo.iCodeLoadAddress=(TLinAddr)&a;//a.iCodeAddress;
 | 
|  |    327 | 	aInfo.iCodeRunAddress=a.iCodeAddress;
 | 
|  |    328 | 	aInfo.iDataLoadAddress=a.iDataAddress;
 | 
|  |    329 | 	aInfo.iDataRunAddress=a.iDataBssLinearBase;
 | 
|  |    330 | 	aInfo.iExceptionDescriptor = a.iExceptionDescriptor;
 | 
|  |    331 | 	aInfo.iHeapSizeMin=a.iHeapSizeMin;
 | 
|  |    332 | 	aInfo.iHeapSizeMax=a.iHeapSizeMax;
 | 
|  |    333 | 	aInfo.iStackSize=a.iStackSize;
 | 
|  |    334 | 	aInfo.iPriority=a.iPriority;
 | 
|  |    335 | 	aInfo.iHandle=NULL;
 | 
|  |    336 | 	aInfo.iS = a.iS;
 | 
|  |    337 | 	aInfo.iModuleVersion = a.iModuleVersion;
 | 
|  |    338 | 	if (a.iFlags&KRomImageFlagsKernelMask)
 | 
|  |    339 | 		aInfo.iAttr=ECodeSegAttKernel;
 | 
|  |    340 | 	else
 | 
|  |    341 | 		aInfo.iAttr=ECodeSegAttGlobal;
 | 
|  |    342 | 	if (a.iFlags&KRomImageFlagFixedAddressExe)
 | 
|  |    343 | 		aInfo.iAttr|=ECodeSegAttFixed;
 | 
|  |    344 | 	aInfo.iAttr &= ~ECodeSegAttABIMask;
 | 
|  |    345 | 	aInfo.iAttr |= (a.iFlags & KRomImageABIMask);
 | 
|  |    346 | 	if(a.iFlags&KRomImageSMPSafe)
 | 
|  |    347 | 		aInfo.iAttr |= ECodeSegAttSMPSafe;
 | 
|  |    348 | 	aInfo.iClientHandle = KCurrentThreadHandle;
 | 
|  |    349 | 	aInfo.iClientProcessHandle = 0;
 | 
|  |    350 | 	aInfo.iFinalHandle = 0;
 | 
|  |    351 | 	aInfo.iOwnerType = EOwnerProcess;
 | 
|  |    352 | 	aInfo.iFlags &= ~(TProcessCreateInfo::EDataPagingMask);
 | 
|  |    353 | 	if(a.iFlags&KRomImageFlagDataPaged)
 | 
|  |    354 | 		aInfo.iFlags |= TProcessCreateInfo::EDataPaged;
 | 
|  |    355 | 	if(a.iFlags&KRomImageFlagDataUnpaged)
 | 
|  |    356 | 		aInfo.iFlags |= TProcessCreateInfo::EDataUnpaged;
 | 
|  |    357 | 	CHECK_ROM_ENTRY_POINT(a);
 | 
|  |    358 | 	}
 | 
|  |    359 | 
 | 
|  |    360 | EXPORT_C void Epoc::SetMonitorEntryPoint(TDfcFn aFn)
 | 
|  |    361 | 	{
 | 
|  |    362 | 	if (aFn)
 | 
|  |    363 | 		{
 | 
|  |    364 | 		TUint32 x=(TUint32)aFn;
 | 
|  |    365 | 		PP::MonitorEntryPoint[0]=x;
 | 
|  |    366 | 		PP::MonitorEntryPoint[1]=~x;
 | 
|  |    367 | 		PP::MonitorEntryPoint[2]=((x>>2)*~x);
 | 
|  |    368 | 		}
 | 
|  |    369 | 	else
 | 
|  |    370 | 		{
 | 
|  |    371 | 		PP::MonitorEntryPoint[0]=0;
 | 
|  |    372 | 		PP::MonitorEntryPoint[1]=0;
 | 
|  |    373 | 		PP::MonitorEntryPoint[2]=0;
 | 
|  |    374 | 		}
 | 
|  |    375 | 	}
 | 
|  |    376 | 
 | 
|  |    377 | EXPORT_C void Epoc::SetMonitorExceptionHandler(TLinAddr aHandler)
 | 
|  |    378 | 	{
 | 
|  |    379 | 	TheScheduler.iMonitorExceptionHandler=aHandler;
 | 
|  |    380 | 	}
 | 
|  |    381 | 
 | 
|  |    382 | EXPORT_C TAny* Epoc::ExceptionInfo()
 | 
|  |    383 | 	{
 | 
|  |    384 | #ifdef __SMP__
 | 
|  |    385 | 	return 0;	// separate for each CPU
 | 
|  |    386 | #else
 | 
|  |    387 | 	return TheScheduler.i_ExcInfo;
 | 
|  |    388 | #endif
 | 
|  |    389 | 	}
 | 
|  |    390 | 
 | 
|  |    391 | EXPORT_C const TRomHeader& Epoc::RomHeader()
 | 
|  |    392 | 	{
 | 
|  |    393 | 	return TheRomHeader();
 | 
|  |    394 | 	}
 | 
|  |    395 | 
 | 
|  |    396 | TLinAddr ExecHandler::RomHeaderAddress()
 | 
|  |    397 | 	{
 | 
|  |    398 | 	return ::RomHeaderAddress;
 | 
|  |    399 | 	}
 | 
|  |    400 | 
 | 
|  |    401 | TLinAddr ExecHandler::RomRootDirectoryAddress()
 | 
|  |    402 | 	{
 | 
|  |    403 | 	return PP::RomRootDirAddress;
 | 
|  |    404 | 	}
 | 
|  |    405 | 
 | 
|  |    406 | TBool M::IsRomAddress(const TAny* aPtr)
 | 
|  |    407 | 	{
 | 
|  |    408 |     TLinAddr start=::RomHeaderAddress;
 | 
|  |    409 |     TLinAddr end=start+TheRomHeader().iUncompressedSize;
 | 
|  |    410 | 	return ((TLinAddr)aPtr>=start) && ((TLinAddr)aPtr<end);
 | 
|  |    411 | 	}
 | 
|  |    412 | 
 | 
|  |    413 | void P::SetSuperPageSignature()
 | 
|  |    414 | 	{
 | 
|  |    415 | 	TUint32* sig = TheSuperPage().iSignature;
 | 
|  |    416 | 	const TUint32* time = (const TUint32*)&TheRomHeader().iTime;
 | 
|  |    417 | 	sig[0] = time[0] ^ 0xb504f333;
 | 
|  |    418 | 	sig[1] = time[1] ^ 0xf9de6484;
 | 
|  |    419 | 	}
 | 
|  |    420 | 
 | 
|  |    421 | TBool P::CheckSuperPageSignature()
 | 
|  |    422 | 	{
 | 
|  |    423 | 	const TUint32* sig = TheSuperPage().iSignature;
 | 
|  |    424 | 	const TUint32* time = (const TUint32*)&TheRomHeader().iTime;
 | 
|  |    425 | 	return ( (sig[0]^time[0])==0xb504f333 && (sig[1]^time[1])==0xf9de6484 );
 | 
|  |    426 | 	}
 | 
|  |    427 | 
 | 
|  |    428 | static const TUint32 KMapAttrType2 = 0x80000000;
 | 
|  |    429 | static const TUint32 KMapAttrTypeShift 		 = 26;
 | 
|  |    430 | 
 | 
|  |    431 | #if defined(__CPU_MEMORY_TYPE_REMAPPING)
 | 
|  |    432 | extern TUint32 PrimaryRegionRemapRegister();
 | 
|  |    433 | extern TUint32 NormalMemoryRemapRegister();
 | 
|  |    434 | #endif
 | 
|  |    435 | 
 | 
|  |    436 | EXPORT_C TMappingAttributes2::TMappingAttributes2(TMemoryType	aType,
 | 
|  |    437 | 														TBool	aUserAccess,
 | 
|  |    438 | 														TBool	aWritable,
 | 
|  |    439 | 														TBool	aExecutable,
 | 
|  |    440 | 														TInt	aShared,
 | 
|  |    441 | 														TInt	aParity)
 | 
|  |    442 | 	{
 | 
|  |    443 | 	//Sort out default values:
 | 
|  |    444 | 	if (aShared<0)
 | 
|  |    445 | 		#if defined	(__CPU_USE_SHARED_MEMORY)
 | 
|  |    446 | 		aShared = 1;
 | 
|  |    447 | 		#else
 | 
|  |    448 | 		aShared = 0;	
 | 
|  |    449 | 		#endif
 | 
|  |    450 | 	if (aParity<0)
 | 
|  |    451 | 		aParity = 0;
 | 
|  |    452 | 	
 | 
|  |    453 | 	// KMapAttrType2 bit marks the object as of TMappingAttributes2 type (as opposed to TMappingAttributes bitmask).
 | 
|  |    454 | 	// We have to make sure that these two types can work together.
 | 
|  |    455 | 
 | 
|  |    456 | 	iAttributes =	KMapAttrType2				|	// Mark it as TMappingAttributes2 object
 | 
|  |    457 | 					EMapAttrReadSup				|	// All memory is readable from Kernel (Supervisor) mode
 | 
|  |    458 | 					(aType <<KMapAttrTypeShift)	|
 | 
|  |    459 | 					(aUserAccess ? EMapAttrReadUser : 0)|
 | 
|  |    460 | 					(aWritable	 ? EMapAttrWriteSup : 0)|
 | 
|  |    461 | 		((aWritable&&aUserAccess)? EMapAttrWriteUser: 0)|
 | 
|  |    462 | #ifdef __MMU_USE_SYMMETRIC_ACCESS_PERMISSIONS
 | 
|  |    463 | 					(aExecutable   ? EMapAttrExecSup : 0)|
 | 
|  |    464 | 		((aExecutable&&aUserAccess)? EMapAttrExecUser: 0)|
 | 
|  |    465 | #else
 | 
|  |    466 | 					(aExecutable ? EMapAttrExecUser|EMapAttrExecSup : 0)|
 | 
|  |    467 | #endif
 | 
|  |    468 | 					(aShared	 ? EMapAttrShared	: 0)|
 | 
|  |    469 | 					(aParity	 ? EMapAttrUseECC	: 0);
 | 
|  |    470 | 	
 | 
|  |    471 | 	// Kernel relies on TMappingAttributes bitmask when dealing with various memory mappings.
 | 
|  |    472 | 	// Set cache attribute bits as they are in TMappingAttributes.
 | 
|  |    473 | 	iAttributes |= InternalCache::TypeToCachingAttributes(aType);
 | 
|  |    474 | 	}
 | 
|  |    475 | 
 | 
|  |    476 | TMappingAttributes2::TMappingAttributes2(TUint aMapAttr):iAttributes(aMapAttr)
 | 
|  |    477 | 	{
 | 
|  |    478 | 	};
 | 
|  |    479 | 
 | 
|  |    480 | TMemoryType TMappingAttributes2::Type()
 | 
|  |    481 | 	{
 | 
|  |    482 | 	if(iAttributes&KMapAttrType2)
 | 
|  |    483 | 		return (TMemoryType)(iAttributes>>KMapAttrTypeShift & 0x7); //three bits for memory type.
 | 
|  |    484 | 
 | 
|  |    485 | 	switch(iAttributes&EMapAttrL1CacheMask)
 | 
|  |    486 | 		{
 | 
|  |    487 | 	case EMapAttrFullyBlocking:
 | 
|  |    488 | 		return EMemAttStronglyOrdered;
 | 
|  |    489 | 
 | 
|  |    490 | 	case EMapAttrBufferedNC:
 | 
|  |    491 | 		return EMemAttDevice;
 | 
|  |    492 | 
 | 
|  |    493 | 	case EMapAttrBufferedC:
 | 
|  |    494 | 	case EMapAttrL1Uncached:
 | 
|  |    495 | 	case EMapAttrCachedWTRA:
 | 
|  |    496 | 	case EMapAttrCachedWTWA:
 | 
|  |    497 | 	case EMapAttrAltCacheWTRA:
 | 
|  |    498 | 	case EMapAttrAltCacheWTWA:
 | 
|  |    499 | 		return EMemAttNormalUncached;
 | 
|  |    500 | 
 | 
|  |    501 | 	case EMapAttrCachedWBRA:
 | 
|  |    502 | 	case EMapAttrCachedWBWA:
 | 
|  |    503 | 	case EMapAttrAltCacheWBRA:
 | 
|  |    504 | 	case EMapAttrAltCacheWBWA:
 | 
|  |    505 | 	case EMapAttrL1CachedMax:
 | 
|  |    506 | 		return EMemAttNormalCached;
 | 
|  |    507 | 
 | 
|  |    508 | 	default:
 | 
|  |    509 | 		Panic(KErrArgument);
 | 
|  |    510 | 		return EMemAttNormalCached;
 | 
|  |    511 | 		}
 | 
|  |    512 | 	}
 | 
|  |    513 | 
 | 
|  |    514 | TBool TMappingAttributes2::UserAccess()	{return (iAttributes&EMapAttrUserRw   ?	(TBool)ETrue : (TBool)EFalse);}
 | 
|  |    515 | TBool TMappingAttributes2::Writable()	{return (iAttributes&EMapAttrWriteMask? (TBool)ETrue : (TBool)EFalse);}
 | 
|  |    516 | #ifdef __MMU_USE_SYMMETRIC_ACCESS_PERMISSIONS
 | 
|  |    517 | TBool TMappingAttributes2::Executable()	{return (iAttributes&EMapAttrExecMask ? (TBool)ETrue : (TBool)EFalse);}
 | 
|  |    518 | #else
 | 
|  |    519 | TBool TMappingAttributes2::Executable()	{return (iAttributes&EMapAttrExecUser ? (TBool)ETrue : (TBool)EFalse);}
 | 
|  |    520 | #endif
 | 
|  |    521 | TBool TMappingAttributes2::Shared()		{return (iAttributes&EMapAttrShared   ?	(TBool)ETrue : (TBool)EFalse);}
 | 
|  |    522 | TBool TMappingAttributes2::Parity()		{return (iAttributes&EMapAttrUseECC	  ?	(TBool)ETrue : (TBool)EFalse);}
 | 
|  |    523 | TBool TMappingAttributes2::ObjectType2(){return (iAttributes&KMapAttrType2	  ?	(TBool)ETrue : (TBool)EFalse);}
 | 
|  |    524 | void  TMappingAttributes2::Panic(TInt aPanic)	{Kern::Fault("TMappingAttributes2",aPanic);}
 | 
|  |    525 | 
 | 
|  |    526 | 
 | 
|  |    527 | #ifdef __DEBUGGER_SUPPORT__
 | 
|  |    528 |  /**
 | 
|  |    529 |  Initialises the breakpoint pool.
 | 
|  |    530 |  There is only one breakpoint pool in the system. The breakpoint pool should be initialised only once - usually from
 | 
|  |    531 |  the run-mode debugger device driver.
 | 
|  |    532 | 
 | 
|  |    533 |  @param aCapabilities	On return this is set to a bitmask of values from enum DebugSupport::TType which represents the
 | 
|  |    534 |  						supported breakpoint types. At the moment only DebugSupport::EBreakpointGlobal type is supported.
 | 
|  |    535 |  @param aMaxBreakpoints The number of breakpoints for which resources should be reserved. It represents
 | 
|  |    536 |                         the maximum number of the breakpoints at a time.
 | 
|  |    537 | 
 | 
|  |    538 |  @return KErrNoMemory, 		if not enough memory to reserve breakpoint resources.
 | 
|  |    539 |    		 KErrInUse,    		if breakpoint pool already exists. Indicates that another debug tool might be using it at the moment.
 | 
|  |    540 |    		 KErrNotSupported, 	if Kernel is not built with __DEBUGGER_SUPPORT__ option
 | 
|  |    541 |    		 KErrNone,			on success.
 | 
|  |    542 | 
 | 
|  |    543 |  @pre   No fast mutex can be held.
 | 
|  |    544 |  @pre   Kernel must be unlocked.
 | 
|  |    545 |  @pre	Call in a thread context.
 | 
|  |    546 |  @pre	Interrupts must be enabled.
 | 
|  |    547 |  */
 | 
|  |    548 | EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& aCapabilities, TInt aMaxBreakpoints)
 | 
|  |    549 | 	{
 | 
|  |    550 | 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::InitialiseCodeModifier");
 | 
|  |    551 | 	TInt err;
 | 
|  |    552 | 	NKern::ThreadEnterCS();
 | 
|  |    553 | 	Kern::MutexWait(CodeModifier::Mutex());
 | 
|  |    554 | 
 | 
|  |    555 | 	if ( KErrNone == (err =CodeModifier::CreateAndInitialise(aMaxBreakpoints)))
 | 
|  |    556 | 		aCapabilities = EBreakpointGlobal;
 | 
|  |    557 | 	
 | 
|  |    558 | 	Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    559 | 	NKern::ThreadLeaveCS(); 
 | 
|  |    560 | 	return err;
 | 
|  |    561 | 	}
 | 
|  |    562 | 
 | 
|  |    563 |  /**
 | 
|  |    564 |  Restore all breakpoints and free resources.
 | 
|  |    565 |  Must not be called before Initialise().
 | 
|  |    566 | 
 | 
|  |    567 |  @panic CodeModifier 0 if called before InitialiseCodeModifier().
 | 
|  |    568 | 
 | 
|  |    569 |  @pre   No fast mutex can be held.
 | 
|  |    570 |  @pre   Kernel must be unlocked.
 | 
|  |    571 |  @pre	Call in a thread context.
 | 
|  |    572 |  @pre	Interrupts must be enabled.
 | 
|  |    573 |  */
 | 
|  |    574 | EXPORT_C void DebugSupport::CloseCodeModifier()
 | 
|  |    575 | 	{
 | 
|  |    576 | 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::CloseCodeModifier");
 | 
|  |    577 | 	NKern::ThreadEnterCS(); 
 | 
|  |    578 | 	Kern::MutexWait(CodeModifier::Mutex());
 | 
|  |    579 | 
 | 
|  |    580 | 	if (!TheCodeModifier)
 | 
|  |    581 | 		{
 | 
|  |    582 | 		Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    583 | 		NKern::ThreadLeaveCS(); 
 | 
|  |    584 | 		CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
 | 
|  |    585 | 		}
 | 
|  |    586 | 	TheCodeModifier->Close();
 | 
|  |    587 | 
 | 
|  |    588 | 	Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    589 | 	NKern::ThreadLeaveCS(); 
 | 
|  |    590 | 	}
 | 
|  |    591 | 
 | 
|  |    592 | /**
 | 
|  |    593 | Write a single breakpoint.
 | 
|  |    594 | I.e. store aValue at location aAddress in the address space of aThread.
 | 
|  |    595 | If the address resides in XIP code (ROM image), the memory page is shadowed before the content of the aAddress is altered.
 | 
|  |    596 | 
 | 
|  |    597 | The breakpoint should be cleared/restored by DebugSupport::RestoreCode with matching aThread and aAddress.
 | 
|  |    598 | The breakpoints are owned by the corresponding process. Therefore:
 | 
|  |    599 | @code 
 | 
|  |    600 | DebugSupport::ModifyCode(thread1, address, size, value, type);
 | 
|  |    601 | and
 | 
|  |    602 | DebugSupport::ModifyCode(thread2, address size, value, type);
 | 
|  |    603 | @endcode
 | 
|  |    604 | have the same effect if thread1 and thread2 belong to the same process.
 | 
|  |    605 | 
 | 
|  |    606 | Breakpoints of the diferent type(size) cannot overlap each other. For example:
 | 
|  |    607 | @code 
 | 
|  |    608 | DebugSupport::ModifyCode(thread, address,   4, value, type); //address is word aligned address
 | 
|  |    609 | DebugSupport::ModifyCode(thread, address,   2, value, type); //will return KErrAccessDenied
 | 
|  |    610 | DebugSupport::ModifyCode(thread, address+2, 2, value, type); //will return KErrAccessDenied
 | 
|  |    611 | DebugSupport::ModifyCode(thread, address+1, 1, value, type); //will return KErrAccessDenied
 | 
|  |    612 | @endcode
 | 
|  |    613 | 
 | 
|  |    614 | After the content of aAddress is altered, instruction cache invalidation is performed on the cache line that aAddress
 | 
|  |    615 | belongs to. Therefore, the device driver doesn't have to call Cache::IMB_Range().
 | 
|  |    616 | 
 | 
|  |    617 | If a code segment (which a valid breakpoint belongs to) is removed from the given process, the breakpoint will be
 | 
|  |    618 | automatically removed. This occures just before EEventRemoveCodeSeg event is issued with DProcess* matching
 | 
|  |    619 | the breakpoint's process. This also applies to the terminating/killed process, as all breakpoints belonging to it will be removed too.
 | 
|  |    620 | 
 | 
|  |    621 | @param aThread 	The thread in who's address space the breakpoint is to be written.
 | 
|  |    622 | @param aAddress The linear address of the breakpoint. Must be a multiple of aSize.
 | 
|  |    623 | @param aSize 	The size, in bytes, of the breakpoint. Must be 1,2 or 4.
 | 
|  |    624 | @param aValue 	The value to be stored at aAddress. This value is trucated to the
 | 
|  |    625 |      			number of bits relevent to aSize.
 | 
|  |    626 | @param aType 	The breakpoint type required. This is a bitmask of values from enum TType.
 | 
|  |    627 |      			If this specifies more than one type, then the type with least scope
 | 
|  |    628 |      			(i.e. EBreakpointLocal) is used when this is supported.
 | 
|  |    629 | 
 | 
|  |    630 |  @return KErrNoMemory,      if no resources are available.
 | 
|  |    631 |    		 KErrAlreadyExists, if a breakpoint with the same address, size and the same owning process already exists in the pool.
 | 
|  |    632 |    		 KErrAccessDenied, 	if an existing breakpoint of a different size and the same owning process overlaps the specified breakpoint.
 | 
|  |    633 |    		 KErrNotSupported,  if none of the breakpoints types specified are supported or if Kernel is not built with __DEBUGGER_SUPPORT__ option
 | 
|  |    634 |    		 Otherwise,         a positive value from enum TType which represents the type of breakpoint written.
 | 
|  |    635 | 
 | 
|  |    636 |  @panic CodeModifier 0 if called before InitialiseCodeModifier().
 | 
|  |    637 |  @panic CodeModifier 1 if aSize value or aAdress alignement is invalid.
 | 
|  |    638 | 
 | 
|  |    639 |  @pre   No fast mutex can be held.
 | 
|  |    640 |  @pre   Kernel must be unlocked.
 | 
|  |    641 |  @pre	Call in a thread context.
 | 
|  |    642 |  @pre	Interrupts must be enabled.
 | 
|  |    643 |  */
 | 
|  |    644 | EXPORT_C TInt DebugSupport::ModifyCode(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue, TUint aType)
 | 
|  |    645 | 	{
 | 
|  |    646 | 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::ModifyCode");
 | 
|  |    647 | 	switch(aSize) //Chack aSize and aValue
 | 
|  |    648 | 	{
 | 
|  |    649 | 	case CodeModifier::EByte:
 | 
|  |    650 | 		break;
 | 
|  |    651 | 	case CodeModifier::EHalfword:
 | 
|  |    652 | 		if ((TInt)aAddress & 1)
 | 
|  |    653 | 			CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
 | 
|  |    654 | 		break;
 | 
|  |    655 | 	case CodeModifier::EWord:	
 | 
|  |    656 | 		if ((TInt)aAddress & 3)
 | 
|  |    657 | 			CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
 | 
|  |    658 | 		break;
 | 
|  |    659 | 	default:
 | 
|  |    660 | 		CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
 | 
|  |    661 | 	}
 | 
|  |    662 | 
 | 
|  |    663 | 	if (aType != DebugSupport::EBreakpointGlobal)//Check breakpoint type
 | 
|  |    664 | 		return KErrNotSupported;
 | 
|  |    665 | 	
 | 
|  |    666 | 	NKern::ThreadEnterCS(); 
 | 
|  |    667 | 	Kern::MutexWait(CodeModifier::Mutex());
 | 
|  |    668 | 	
 | 
|  |    669 | 	if (!TheCodeModifier)
 | 
|  |    670 | 		{
 | 
|  |    671 | 		Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    672 | 		NKern::ThreadLeaveCS(); 
 | 
|  |    673 | 		CodeModifier::Fault(CodeModifier::EPanicNotInitialised);	
 | 
|  |    674 | 		}
 | 
|  |    675 | 	TInt r = TheCodeModifier->Modify(aThread, aAddress, aSize, aValue);
 | 
|  |    676 | 
 | 
|  |    677 | 	Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    678 | 	NKern::ThreadLeaveCS(); 
 | 
|  |    679 | 
 | 
|  |    680 | 	if (r)
 | 
|  |    681 | 		return r;
 | 
|  |    682 | 	return EBreakpointGlobal;
 | 
|  |    683 | 	}
 | 
|  |    684 | 
 | 
|  |    685 |  /**
 | 
|  |    686 |  Restore a previousely written breakpoint.
 | 
|  |    687 |  I.e. restore the value at location aAddress in the address space of aProcess.
 | 
|  |    688 | 
 | 
|  |    689 |  After the content of aAddress is altered, instruction cache invalidation is performed on the cache line
 | 
|  |    690 |  that aAddress belongs to. Therefore, the device driver doesn't have to call Cache::IMB_Range().
 | 
|  |    691 | 
 | 
|  |    692 |  If the address resides in shadowed memory, the memory page will be un-shadowed if this is the last breakpoint
 | 
|  |    693 |  in the page. However, if the page had been already shadowed before the first breakpoint in the page was applied,
 | 
|  |    694 |  the page will remain shadowed.
 | 
|  |    695 | 
 | 
|  |    696 |  @param aProcess The process in who's address space aAddress lies.
 | 
|  |    697 |  @param aAddress The linear address of an existing breakpoint.
 | 
|  |    698 | 
 | 
|  |    699 |  @return KErrNotFound,		if the breakpoint hadn't been previously written. It is also returned if the breakpoint
 | 
|  |    700 |                         	was previously removed from the list because the code segment (which the breakpoint belongs to) was
 | 
|  |    701 |                         	unloaded/removed from the process associated with the breakpoint.
 | 
|  |    702 |    		 KErrNotSupported, 	if Kernel is not built with __DEBUGGER_SUPPORT__ option
 | 
|  |    703 |     	 KErrNone,			on success.
 | 
|  |    704 | 
 | 
|  |    705 |  @panic CodeModifier 0 if called before InitialiseCodeModifier().
 | 
|  |    706 | 
 | 
|  |    707 |  @pre   No fast mutex can be held.
 | 
|  |    708 |  @pre   Kernel must be unlocked.
 | 
|  |    709 |  @pre	Call in a thread context.
 | 
|  |    710 |  @pre	Interrupts must be enabled.
 | 
|  |    711 |  */
 | 
|  |    712 | EXPORT_C TInt DebugSupport::RestoreCode(DThread* aThread, TLinAddr aAddress)
 | 
|  |    713 | 	{
 | 
|  |    714 | 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::RestoreCode");
 | 
|  |    715 | 	NKern::ThreadEnterCS(); 
 | 
|  |    716 | 	Kern::MutexWait(CodeModifier::Mutex());
 | 
|  |    717 | 
 | 
|  |    718 | 	if (!TheCodeModifier)
 | 
|  |    719 | 		{
 | 
|  |    720 | 		Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    721 | 		NKern::ThreadLeaveCS(); 
 | 
|  |    722 | 		CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
 | 
|  |    723 | 		}
 | 
|  |    724 | 	TInt r = TheCodeModifier->Restore(aThread, aAddress);
 | 
|  |    725 | 
 | 
|  |    726 | 	Kern::MutexSignal(CodeModifier::Mutex());
 | 
|  |    727 | 	NKern::ThreadLeaveCS(); 
 | 
|  |    728 | 	return r;
 | 
|  |    729 | 	}
 | 
|  |    730 | 
 | 
|  |    731 |  /**
 | 
|  |    732 |  Terminates a specified process on behalf of a debugger.
 | 
|  |    733 | 
 | 
|  |    734 |  @param aProcess The process in who's address space aAddress lies.
 | 
|  |    735 |  @param aReason The reason code to supply when terminating a process
 | 
|  |    736 | 
 | 
|  |    737 |  @return N/A.
 | 
|  |    738 | 
 | 
|  |    739 |  @pre   No fast mutex can be held.
 | 
|  |    740 |  @pre   Kernel must be unlocked.
 | 
|  |    741 |  @pre	Call in a thread context.
 | 
|  |    742 |  @pre	Interrupts must be enabled.
 | 
|  |    743 |  */
 | 
|  |    744 | EXPORT_C void DebugSupport::TerminateProcess(DProcess* aProcess, const TInt aReason)
 | 
|  |    745 | 	{
 | 
|  |    746 | 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::TerminateProcess");
 | 
|  |    747 | 	NKern::ThreadEnterCS(); 
 | 
|  |    748 | 	aProcess->Die(EExitTerminate,aReason,KNullDesC);
 | 
|  |    749 | 	NKern::ThreadLeaveCS(); 
 | 
|  |    750 | 	return;
 | 
|  |    751 | 	}
 | 
|  |    752 | 
 | 
|  |    753 | /**
 | 
|  |    754 | Creates CodeModifier.
 | 
|  |    755 | @param aMaxBreakpoints The number of breakpoints to be allocated.
 | 
|  |    756 | @return KErrInUse 	 if code modifier already exists.
 | 
|  |    757 | 		KErrNoMemory if out of memory
 | 
|  |    758 | 		KErrNone 	 on success
 | 
|  |    759 | @pre Calling thread must be in the critical section
 | 
|  |    760 | @pre CodeSeg mutex held
 | 
|  |    761 | */
 | 
|  |    762 | TInt CodeModifier::CreateAndInitialise(TInt aMaxBreakpoints)
 | 
|  |    763 | 	{
 | 
|  |    764 | 	if (TheCodeModifier)
 | 
|  |    765 | 		return KErrInUse;
 | 
|  |    766 | 
 | 
|  |    767 | 	CodeModifier* modifier = new CodeModifier;
 | 
|  |    768 | 	if (!modifier)
 | 
|  |    769 | 		return KErrNoMemory;
 | 
|  |    770 | 	
 | 
|  |    771 | 	modifier->iBreakpoints = new TBreakpoint[aMaxBreakpoints];
 | 
|  |    772 | 	if (!modifier->iBreakpoints)
 | 
|  |    773 | 		{
 | 
|  |    774 | 		delete modifier;	
 | 
|  |    775 | 		return KErrNoMemory;
 | 
|  |    776 | 		};
 | 
|  |    777 | 		
 | 
|  |    778 | 	modifier->iPages = new TPageInfo[aMaxBreakpoints];
 | 
|  |    779 | 	if (!modifier->iPages)
 | 
|  |    780 | 		{
 | 
|  |    781 | 		delete[] modifier->iBreakpoints;
 | 
|  |    782 | 		delete modifier;	
 | 
|  |    783 | 		return KErrNoMemory;
 | 
|  |    784 | 		}
 | 
|  |    785 | 
 | 
|  |    786 | 	modifier->iPoolSize = aMaxBreakpoints;
 | 
|  |    787 | 	modifier->iPageSize = Kern::RoundToPageSize(1);
 | 
|  |    788 | 	modifier->iPageMask = ~(modifier->iPageSize-1);
 | 
|  |    789 | 
 | 
|  |    790 | 	TheCodeModifier = modifier;
 | 
|  |    791 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CreateAndInitialise() Size:%d created", aMaxBreakpoints));
 | 
|  |    792 | 	return KErrNone;	
 | 
|  |    793 | 	}
 | 
|  |    794 | 
 | 
|  |    795 | /**
 | 
|  |    796 | Sets breakpoint.
 | 
|  |    797 | @pre Calling thread must be in the critical section
 | 
|  |    798 | @pre CodeSeg mutex held
 | 
|  |    799 | */
 | 
|  |    800 | TInt CodeModifier::Modify(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue)
 | 
|  |    801 | 	{
 | 
|  |    802 | 	TInt r;
 | 
|  |    803 | 	TUint oldValue;
 | 
|  |    804 | 	TBool overlap;
 | 
|  |    805 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Modify() T:%x Addr:%x, Size:%d Val:%x", aThread, aAddress, aSize, aValue));
 | 
|  |    806 | 	
 | 
|  |    807 | 	TBreakpoint* brk =FindBreakpoint(aThread, aAddress,aSize,overlap);
 | 
|  |    808 | 	if (overlap)
 | 
|  |    809 | 		return KErrAccessDenied;
 | 
|  |    810 | 	if (brk)
 | 
|  |    811 | 		return KErrAlreadyExists;
 | 
|  |    812 | 	
 | 
|  |    813 | 	if(NULL==(brk = FindEmptyBrk()))
 | 
|  |    814 | 		return KErrNoMemory;
 | 
|  |    815 | 	
 | 
|  |    816 | 	//Find the page (if exists). Shadow the page if necessery.
 | 
|  |    817 | 	TInt pageIndex = -1;
 | 
|  |    818 | 
 | 
|  |    819 | #ifndef __DEMAND_PAGING__ 
 | 
|  |    820 | 	if (IsRom(aAddress))  // If no demand paging, only need to do this if the address is in rom
 | 
|  |    821 | #endif
 | 
|  |    822 | 		{
 | 
|  |    823 | 		pageIndex = FindPageInfo(aAddress);
 | 
|  |    824 | 		if (pageIndex < 0)
 | 
|  |    825 | 			{
 | 
|  |    826 | 			pageIndex = FindEmptyPageInfo();
 | 
|  |    827 | 			if (pageIndex < 0)
 | 
|  |    828 | 				return KErrNoMemory;
 | 
|  |    829 | 			TPageInfo& page = iPages[pageIndex];
 | 
|  |    830 | 			memclr(&page, sizeof(page));
 | 
|  |    831 | 			page.iAddress = aAddress & iPageMask;
 | 
|  |    832 | 			
 | 
|  |    833 | 			if (IsRom(aAddress))
 | 
|  |    834 | 				{
 | 
|  |    835 | 				__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Modify() - Shadowing Page"));
 | 
|  |    836 | 				r = Epoc::AllocShadowPage(aAddress & iPageMask);
 | 
|  |    837 | 				if (r==KErrAlreadyExists)
 | 
|  |    838 | 					page.iWasShadowed = ETrue;
 | 
|  |    839 | 				else if (r!=KErrNone)
 | 
|  |    840 | 					return r;
 | 
|  |    841 | 				}
 | 
|  |    842 | #ifdef __DEMAND_PAGING__
 | 
|  |    843 | 			else
 | 
|  |    844 | 				{
 | 
|  |    845 | 				DDemandPagingLock* lock = new DDemandPagingLock;
 | 
|  |    846 | 				if (lock == NULL)
 | 
|  |    847 | 					return KErrNoMemory;
 | 
|  |    848 | 				r = lock->Alloc(iPageSize);
 | 
|  |    849 | 				if (r != KErrNone)
 | 
|  |    850 | 					{
 | 
|  |    851 | 					delete lock;
 | 
|  |    852 | 					return r;
 | 
|  |    853 | 					}
 | 
|  |    854 | 				lock->Lock(aThread, aAddress & iPageMask, iPageSize);
 | 
|  |    855 | 				page.iPagingLock = lock;
 | 
|  |    856 | 				}
 | 
|  |    857 | #endif
 | 
|  |    858 | 			}
 | 
|  |    859 | 		iPages[pageIndex].iCounter++;
 | 
|  |    860 | 		}
 | 
|  |    861 | 
 | 
|  |    862 | 	r = SafeWriteCode(aThread->iOwningProcess, aAddress, aSize, aValue, &oldValue);
 | 
|  |    863 | 	if (r != KErrNone)
 | 
|  |    864 | 		{//aAddress is invalid
 | 
|  |    865 | 		if (pageIndex >= 0)
 | 
|  |    866 | 			RestorePage(pageIndex);
 | 
|  |    867 | 		return r;
 | 
|  |    868 | 		}
 | 
|  |    869 | 
 | 
|  |    870 | 	//All done. Update the internal structures.
 | 
|  |    871 | 	brk->iAddress = aAddress;
 | 
|  |    872 | 	brk->iProcessId = (aThread->iOwningProcess)->iId;
 | 
|  |    873 | 	brk->iOldValue = oldValue;
 | 
|  |    874 | 	brk->iSize = aSize;
 | 
|  |    875 | 	brk->iPageIndex = pageIndex;
 | 
|  |    876 | 	return KErrNone;
 | 
|  |    877 | 	}
 | 
|  |    878 | 
 | 
|  |    879 | /**
 | 
|  |    880 | @pre Calling thread must be in the critical section
 | 
|  |    881 | @pre CodeSeg mutex held
 | 
|  |    882 | */
 | 
|  |    883 | TInt CodeModifier::Restore(DThread* aThread, TLinAddr aAddress)
 | 
|  |    884 | 	{
 | 
|  |    885 | 	TUint oldValue;
 | 
|  |    886 | 	TBool overlaps;
 | 
|  |    887 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() T:%x Addr:%x", aThread, aAddress));
 | 
|  |    888 | 	TInt r = KErrNone;;
 | 
|  |    889 | 	TBreakpoint* br = FindBreakpoint(aThread, aAddress, 0, overlaps);
 | 
|  |    890 | 	if (br==NULL)
 | 
|  |    891 | 		return KErrNotFound;
 | 
|  |    892 | 	
 | 
|  |    893 | 	r = SafeWriteCode(aThread->iOwningProcess, br->iAddress, br->iSize, br->iOldValue, &oldValue);
 | 
|  |    894 | 	if (r)
 | 
|  |    895 | 		r=KErrNotFound;
 | 
|  |    896 | 	
 | 
|  |    897 | 	br->iSize = (TUint)EEmpty;
 | 
|  |    898 | 		
 | 
|  |    899 | 	TInt pageIndex = br->iPageIndex;
 | 
|  |    900 | 	if (pageIndex>=0)
 | 
|  |    901 | 		RestorePage(pageIndex);
 | 
|  |    902 | 	
 | 
|  |    903 | 	return r;
 | 
|  |    904 | 	}
 | 
|  |    905 | 
 | 
|  |    906 | /*
 | 
|  |    907 | @pre Calling thread must be in the critical section
 | 
|  |    908 | @pre CodeSeg mutex held
 | 
|  |    909 | */
 | 
|  |    910 | void CodeModifier::Close()
 | 
|  |    911 | 	{
 | 
|  |    912 | 	TUint oldValue;
 | 
|  |    913 | 	TInt brkIndex;
 | 
|  |    914 | 
 | 
|  |    915 | 	TheCodeModifier = NULL;
 | 
|  |    916 | 	
 | 
|  |    917 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close()"));
 | 
|  |    918 | 
 | 
|  |    919 | 	for (brkIndex=0; brkIndex<iPoolSize; brkIndex++)	
 | 
|  |    920 | 		{
 | 
|  |    921 | 		if (iBreakpoints[brkIndex].iSize ==(TUint16)EEmpty)
 | 
|  |    922 | 			continue;
 | 
|  |    923 | 		DProcess* process = Process(iBreakpoints[brkIndex].iProcessId);
 | 
|  |    924 | 		
 | 
|  |    925 | 		__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close() - Removing Brk:%x",iBreakpoints[brkIndex].iAddress));
 | 
|  |    926 | 		
 | 
|  |    927 | 		//Write back the original value
 | 
|  |    928 | 		if (process)
 | 
|  |    929 | 			SafeWriteCode(process, iBreakpoints[brkIndex].iAddress, iBreakpoints[brkIndex].iSize, iBreakpoints[brkIndex].iOldValue, &oldValue);
 | 
|  |    930 | 			
 | 
|  |    931 | 		iBreakpoints[brkIndex].iSize = (TUint)EEmpty;
 | 
|  |    932 | 		TInt pageIndex = iBreakpoints[brkIndex].iPageIndex;
 | 
|  |    933 | 		if (pageIndex>=0)
 | 
|  |    934 | 			RestorePage(pageIndex);
 | 
|  |    935 | 		}
 | 
|  |    936 | 
 | 
|  |    937 | 	delete this;
 | 
|  |    938 | 	}
 | 
|  |    939 | 
 | 
|  |    940 | /*
 | 
|  |    941 | Destructor. The object is deleted asynchroniously from Kernel Supervisor thread.
 | 
|  |    942 | */
 | 
|  |    943 | CodeModifier::~CodeModifier()
 | 
|  |    944 | 	{
 | 
|  |    945 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::~CodeModifier()"));
 | 
|  |    946 | 	delete[] iPages;
 | 
|  |    947 | 	delete[] iBreakpoints;
 | 
|  |    948 | 	}
 | 
|  |    949 | 
 | 
|  |    950 | /**
 | 
|  |    951 | This is executed when a code segment is about to be unmapped from the process. It corresponds to EEventRemoveCodeSeg Kernel event.
 | 
|  |    952 | Removes breakpoints that belong to the threads from aProcess. Also, removes shadow pages if there is no breakpoint left in them.
 | 
|  |    953 | 
 | 
|  |    954 | @param aCodeSeg Code Segment that is removed from aProcess.
 | 
|  |    955 | @param aProcess Process from whom the code segment is removed.
 | 
|  |    956 | 
 | 
|  |    957 | @pre Calling thread must be in the critical section
 | 
|  |    958 | @pre CodeSeg mutex held
 | 
|  |    959 | */
 | 
|  |    960 | void CodeModifier::CodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
 | 
|  |    961 | 	{
 | 
|  |    962 | 	if (!TheCodeModifier)
 | 
|  |    963 | 		return;
 | 
|  |    964 | 	TheCodeModifier->DoCodeSegRemoved(aCodeSeg, aProcess);
 | 
|  |    965 | 	}
 | 
|  |    966 | 
 | 
|  |    967 | void CodeModifier::DoCodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
 | 
|  |    968 | 	{
 | 
|  |    969 | 	__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()"));
 | 
|  |    970 | 	
 | 
|  |    971 | 	TUint oldValue;
 | 
|  |    972 | 	TUint minAddr = aCodeSeg->iRunAddress;
 | 
|  |    973 | 	TUint maxAddr = aCodeSeg->iRunAddress + aCodeSeg->iSize;
 | 
|  |    974 | 
 | 
|  |    975 | 	TBreakpoint* bp = iBreakpoints;
 | 
|  |    976 | 	TBreakpoint* bpEnd = bp+iPoolSize; //points right behind iBreakpoints
 | 
|  |    977 | 	for (; bp<bpEnd; ++bp)
 | 
|  |    978 | 		{
 | 
|  |    979 | 		if (bp->iSize == (TUint)EEmpty) continue;
 | 
|  |    980 | 
 | 
|  |    981 | 		if (aProcess->iId == bp->iProcessId)
 | 
|  |    982 | 			{
 | 
|  |    983 | 			if (bp->iAddress >= minAddr && bp->iAddress <  maxAddr)   
 | 
|  |    984 | 				{
 | 
|  |    985 | 				__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()- a breakpoint"));
 | 
|  |    986 | 
 | 
|  |    987 | 				//Remove breakpoint. Don't examine error code as there is nobody to report to.
 | 
|  |    988 | 				SafeWriteCode(aProcess, bp->iAddress, bp->iSize, bp->iOldValue, &oldValue);
 | 
|  |    989 | 
 | 
|  |    990 | 				//Mark the slot as empty and decrease the counter of the shadow page slot (if there is any associated)
 | 
|  |    991 | 				bp->iSize = (TUint)EEmpty;
 | 
|  |    992 | 				if (bp->iPageIndex >= 0)
 | 
|  |    993 | 					RestorePage(bp->iPageIndex);
 | 
|  |    994 | 				}
 | 
|  |    995 | 			}
 | 
|  |    996 | 		}
 | 
|  |    997 | 
 | 
|  |    998 | 	}
 | 
|  |    999 | 
 | 
|  |   1000 | /*
 | 
|  |   1001 | Finds DProcess that matches to processId
 | 
|  |   1002 | @param aProcessId ProcessId
 | 
|  |   1003 | @return Pointer to matching DProcess or NULL
 | 
|  |   1004 | */
 | 
|  |   1005 | DProcess* CodeModifier::Process(TUint aProcessId)
 | 
|  |   1006 | 	{
 | 
|  |   1007 | 	TInt i;
 | 
|  |   1008 | 	DProcess* process = NULL;
 | 
|  |   1009 | 	DObjectCon* processCon = Kern::Containers()[EProcess];
 | 
|  |   1010 | 	processCon->Wait();
 | 
|  |   1011 | 
 | 
|  |   1012 | 	for (i=0;i<processCon->Count();i++)
 | 
|  |   1013 | 		{
 | 
|  |   1014 | 		DProcess* pr = (DProcess*)(*processCon)[i];
 | 
|  |   1015 | 		if (pr->iId == aProcessId)
 | 
|  |   1016 | 			{
 | 
|  |   1017 | 			process=(DProcess*)pr;
 | 
|  |   1018 | 			break;
 | 
|  |   1019 | 			}
 | 
|  |   1020 | 		}
 | 
|  |   1021 | 
 | 
|  |   1022 | 	processCon->Signal();
 | 
|  |   1023 | 	return process;
 | 
|  |   1024 | 	}
 | 
|  |   1025 | 
 | 
|  |   1026 | /*
 | 
|  |   1027 | Returns eTrue if given virtual address belongs to rom image, EFalse otherwise
 | 
|  |   1028 | */
 | 
|  |   1029 | TBool CodeModifier::IsRom(TLinAddr aAddress)
 | 
|  |   1030 | 	{
 | 
|  |   1031 | 	TRomHeader romHeader = Epoc::RomHeader();
 | 
|  |   1032 | 	if ( (aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iUncompressedSize)) )
 | 
|  |   1033 | 		return ETrue;
 | 
|  |   1034 | 	return EFalse;
 | 
|  |   1035 | 	}
 | 
|  |   1036 | 
 | 
|  |   1037 | /*
 | 
|  |   1038 | Finds the first available(empty) breakpoint slot.
 | 
|  |   1039 | @return The pointer of the empty slot or NULL if all occupied.
 | 
|  |   1040 | */
 | 
|  |   1041 | CodeModifier::TBreakpoint* CodeModifier::FindEmptyBrk()
 | 
|  |   1042 | 	{
 | 
|  |   1043 | 	TBreakpoint* bp = TheCodeModifier->iBreakpoints;
 | 
|  |   1044 | 	TBreakpoint* bpEnd = bp+TheCodeModifier->iPoolSize; //points right behind iBreakpoints
 | 
|  |   1045 | 	for (; bp<bpEnd; ++bp)
 | 
|  |   1046 | 		if (bp->iSize == (TInt16)EEmpty)
 | 
|  |   1047 | 			return bp;
 | 
|  |   1048 | 		
 | 
|  |   1049 | 	return NULL;	
 | 
|  |   1050 | 	}
 | 
|  |   1051 | 	
 | 
|  |   1052 | /*
 | 
|  |   1053 | Finds matching breakpoint.
 | 
|  |   1054 | 
 | 
|  |   1055 | @param aThread 		The thread who's process owns the breakpoint
 | 
|  |   1056 | @param aAddress 	Address of the breakpoint.
 | 
|  |   1057 | @param aSize 		The size of the breakpoint. Value 0, 1,2 or 4 is assumed. If 0, it doesn't check the size nor overlaps(used to remove breakpoint).
 | 
|  |   1058 | @param aOverlap 	On return, it is true if a breakpoint is found that doesn't match the size but overlaps with
 | 
|  |   1059 | 					the specified breakpoint(i.e. address and process are the same but the size is different).
 | 
|  |   1060 | 
 | 
|  |   1061 | @return - The pointer to the breakpoint slot that matches the entry (adress, size and the owning process)
 | 
|  |   1062 | 		- NULL - if could't find the matching breakpoint.
 | 
|  |   1063 | */
 | 
|  |   1064 | CodeModifier::TBreakpoint* CodeModifier::FindBreakpoint(DThread* aThread, TLinAddr aAddress, TInt aSize, TBool& aOverlap)
 | 
|  |   1065 | 	{
 | 
|  |   1066 | 	TInt bytes=0;
 | 
|  |   1067 | 	aOverlap = EFalse;
 | 
|  |   1068 | 	TUint processId = aThread->iOwningProcess->iId;//processId of the thread that owns aThread
 | 
|  |   1069 | 
 | 
|  |   1070 | 	if (aSize) //if size==0, we do not check overlaps.
 | 
|  |   1071 | 		bytes = ((1<<aSize)-1)<<(aAddress&3);	//bits[3-0] marks the bytes that are contained in the breakpoint:
 | 
|  |   1072 | 												//	address: ...00b size: 1 => bytes=0001b 
 | 
|  |   1073 | 												//	address: ...01b size: 1 => bytes=0010b 
 | 
|  |   1074 | 												//	address: ...10b size: 1 => bytes=0100b 
 | 
|  |   1075 | 												//	address: ...11b size: 1 => bytes=1000b 
 | 
|  |   1076 | 												//	address: ...00b size: 2 => bytes=0011b 
 | 
|  |   1077 | 												//	address: ...10b size: 2 => bytes=1100b 
 | 
|  |   1078 | 												//	address: ...00b size: 4 => bytes=1111b 
 | 
|  |   1079 | 
 | 
|  |   1080 | 	TBreakpoint* bp = TheCodeModifier->iBreakpoints;
 | 
|  |   1081 | 	TBreakpoint* bpEnd = bp+TheCodeModifier->iPoolSize; //points right behind iBreakpoints
 | 
|  |   1082 | 	for (; bp<bpEnd; ++bp)
 | 
|  |   1083 | 		{
 | 
|  |   1084 | 		if (bp->iSize == (TInt16)EEmpty || bp->iProcessId != processId)
 | 
|  |   1085 | 			continue;//Either empty or not matchng process. 
 | 
|  |   1086 | 
 | 
|  |   1087 | 		if (!aSize)
 | 
|  |   1088 | 			{ //Do not check the size. If the address does not match, do not check for overlap.
 | 
|  |   1089 | 			if (bp->iAddress == aAddress)
 | 
|  |   1090 | 				return bp;
 | 
|  |   1091 | 			else
 | 
|  |   1092 | 				continue;
 | 
|  |   1093 | 			}
 | 
|  |   1094 | 			
 | 
|  |   1095 | 		if (bp->iAddress == aAddress && bp->iSize == aSize)
 | 
|  |   1096 | 			return bp;//If we find a matching breakpoint, there cannot be another one that overlaps
 | 
|  |   1097 | 		
 | 
|  |   1098 | 		//Check if bp breakpoint overlaps with the specified one.
 | 
|  |   1099 | 		if ((bp->iAddress^aAddress)>>2)
 | 
|  |   1100 | 			continue;//Not in the same word
 | 
|  |   1101 | 			
 | 
|  |   1102 | 		if (((1<<bp->iSize)-1)<<(bp->iAddress&3)&bytes)
 | 
|  |   1103 | 			{//Two brakpoints are within the same word with some overlaping bytes.
 | 
|  |   1104 | 			aOverlap = ETrue;
 | 
|  |   1105 | 			return NULL; //If we find an overlaping breakpoint, there cannot be another one that matches exactly.
 | 
|  |   1106 | 			}
 | 
|  |   1107 | 		}
 | 
|  |   1108 | 	return NULL;	
 | 
|  |   1109 | 	}
 | 
|  |   1110 | 
 | 
|  |   1111 | /*
 | 
|  |   1112 | Finds the first available(empty) page info slot.
 | 
|  |   1113 | @return The index of the slot or KErrNotFound if all occupied.
 | 
|  |   1114 | */
 | 
|  |   1115 | TInt CodeModifier::FindEmptyPageInfo()
 | 
|  |   1116 | 	{
 | 
|  |   1117 | 	TInt i;
 | 
|  |   1118 | 	for (i=0; i<iPoolSize; i++)
 | 
|  |   1119 | 		if (!iPages[i].iCounter)
 | 
|  |   1120 | 			return i;
 | 
|  |   1121 | 	return KErrNotFound;
 | 
|  |   1122 | 	}
 | 
|  |   1123 | 
 | 
|  |   1124 | /*
 | 
|  |   1125 | Finds the page info structure that contains given virtual address
 | 
|  |   1126 | @return The index of the page info slot or KErrNotFound.
 | 
|  |   1127 | */
 | 
|  |   1128 | TInt CodeModifier::FindPageInfo(TLinAddr aAddress)
 | 
|  |   1129 | 	{
 | 
|  |   1130 | 	TInt i;
 | 
|  |   1131 | 	aAddress &= iPageMask; //round down to the page base address
 | 
|  |   1132 | 	for (i=0; i<iPoolSize; i++)
 | 
|  |   1133 | 		if(iPages[i].iCounter)
 | 
|  |   1134 | 			if (iPages[i].iAddress == aAddress)
 | 
|  |   1135 | 				return i;
 | 
|  |   1136 | 	return KErrNotFound;
 | 
|  |   1137 | 	}
 | 
|  |   1138 | 
 | 
|  |   1139 | /**
 | 
|  |   1140 | Decrement the count of breakpoints associated with this page, and restores page
 | 
|  |   1141 | to its original state if there are none remaining.
 | 
|  |   1142 | */
 | 
|  |   1143 | void CodeModifier::RestorePage(TInt aPageIndex)
 | 
|  |   1144 | 	{
 | 
|  |   1145 | 	TPageInfo& page = iPages[aPageIndex];
 | 
|  |   1146 | 	if(--page.iCounter==0)
 | 
|  |   1147 | 		{
 | 
|  |   1148 | 		if (!page.iWasShadowed)
 | 
|  |   1149 | 			{
 | 
|  |   1150 | 			__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() - Freeing Shadow Page"));
 | 
|  |   1151 | 			Epoc::FreeShadowPage(page.iAddress);
 | 
|  |   1152 | 			}
 | 
|  |   1153 | #ifdef __DEMAND_PAGING__
 | 
|  |   1154 | 		if (page.iPagingLock)
 | 
|  |   1155 | 			{
 | 
|  |   1156 | 			// Release lock and free resources
 | 
|  |   1157 | 			delete page.iPagingLock;
 | 
|  |   1158 | 			page.iPagingLock = NULL;
 | 
|  |   1159 | 			}
 | 
|  |   1160 | #endif
 | 
|  |   1161 | 		}
 | 
|  |   1162 | 	}
 | 
|  |   1163 | 
 | 
|  |   1164 | void CodeModifier::Fault(TPanic aPanic)
 | 
|  |   1165 | 	{
 | 
|  |   1166 | 	Kern::Fault("CodeModifier", aPanic);
 | 
|  |   1167 | 	}
 | 
|  |   1168 | 
 | 
|  |   1169 | #else //__DEBUGGER_SUPPORT__
 | 
|  |   1170 | EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& /*aCapabilities*/, TInt /*aMinBreakpoints*/)
 | 
|  |   1171 | 	{
 | 
|  |   1172 | 	return KErrNotSupported;	
 | 
|  |   1173 | 	}
 | 
|  |   1174 | EXPORT_C void DebugSupport::CloseCodeModifier()
 | 
|  |   1175 | 	{
 | 
|  |   1176 | 	}
 | 
|  |   1177 | EXPORT_C TInt DebugSupport::ModifyCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/, TInt /*aSize*/, TUint /*aValue*/, TUint /*aType*/)
 | 
|  |   1178 | 	{
 | 
|  |   1179 | 	return KErrNotSupported;	
 | 
|  |   1180 | 	}
 | 
|  |   1181 | EXPORT_C TInt DebugSupport::RestoreCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/)
 | 
|  |   1182 | 	{
 | 
|  |   1183 | 	return KErrNotSupported;	
 | 
|  |   1184 | 	}
 | 
|  |   1185 | EXPORT_C void DebugSupport::TerminateProcess(DProcess* /*aProcess*/, const TInt /*aReason*/)
 | 
|  |   1186 | 	{
 | 
|  |   1187 | 	}
 | 
|  |   1188 | #endif
 | 
|  |   1189 | 
 |