First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\memmodel\epoc\putils.cpp
15 // EPOC implementation of the ROM related parts of the system
19 #include "plat_priv.h"
22 #include "cache_maintenance.h"
24 _LIT(KKernelFullPathNameSysBin,"z:\\sys\\bin\\ekern.exe");
27 #define CHECK_ROM_ENTRY_POINT(a) __ASSERT_ALWAYS( ((a).iFlags & KRomImageEptMask) == KRomImageEpt_Eka2, PP::Panic(PP::EUnsupportedOldBinary) )
29 #define CHECK_ROM_ENTRY_POINT(a)
32 void PP::Panic(TPlatPanic aPanic)
34 Kern::Fault("PLAT",aPanic);
37 void PP::InitSuperPageFromRom(TLinAddr aRomHeader, TLinAddr aSuperPage)
39 RomHeaderAddress = aRomHeader;
40 SuperPageAddress = aSuperPage;
43 for (j = 0; j < KNumTraceMaskWords; j++)
44 TheSuperPage().iDebugMask[j] = TheRomHeader().iTraceMask[j];
46 for (j = 0; j < 8; j++)
47 TheSuperPage().iInitialBTraceFilter[j] = TheRomHeader().iInitialBTraceFilter[j];
49 Kern::SuperPage().iInitialBTraceBuffer = TheRomHeader().iInitialBTraceBuffer;
50 Kern::SuperPage().iInitialBTraceMode = TheRomHeader().iInitialBTraceMode;
52 TheSuperPage().SetKernelConfigFlags(TheRomHeader().iKernelConfigFlags);
54 memcpy(&TheSuperPage().iDisabledCapabilities, &TheRomHeader().iDisabledCapabilities, sizeof(TheRomHeader().iDisabledCapabilities));
57 TInt P::DefaultInitialTime()
60 // Default implementation of the kernel hook for getting the initial system
61 // time, can be overriden by variant.
64 if (K::ColdStart || A::SystemTimeInSecondsFrom2000(seconds)!=KErrNone)
70 TInt P::InitSystemTime()
73 // Initialise system time
74 // Return the initial time in seconds from 00:00:00 01-01-2000
77 // Reset the UTC offset (I assume this gets loaded from storage at some point after F32 loads)
79 K::SetSystemTimeAndOffset(0, 0, 0, dummy, ETimeSetOffset | ETimeSetNoTimeUpdate);
81 // Read the hardware clock value. If this is negative it means it couldnt be read.
82 TInt seconds = K::InitialTimeHandler()();
86 K::SecureClockStatus |= ESecureClockPresent;
87 __KTRACE_OPT(KBOOT,Kern::Printf("Read initial system time"));
88 // now=Hardware RTC value
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;
96 TInt r=K::SecondsFrom2000(rom_time,s);
98 PP::Panic(PP::EInitialSystemTimeInvalid);
101 // write the ROM timestamp to the hardware RTC
102 A::SetSystemTimeInSecondsFrom2000(seconds);
108 void FindRomRootDirectory()
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;
116 pL=(TRomRootDirectoryList*)TheRomHeader().iRomRootDirectoryList;
118 for (i=0; i<pL->iNumRootDirs; i++)
120 if (THardwareVariant(pL->iRootDir[i].iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
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;
130 typedef TInt (*TInitVarExtFn)(const TRomImageHeader&);
133 void DumpRomFileInfo(const TRomEntry& aRomEntry)
137 for (i=0; i<aRomEntry.iNameLength; ++i)
139 name.Append(TChar(aRomEntry.iName[i<<1]&0xff));
141 const TRomImageHeader& img = *(const TRomImageHeader*)aRomEntry.iAddressLin;
142 __KTRACE_OPT(KBOOT,Kern::Printf("File %S[%08x]", &name, TUint(img.iHardwareVariant) ));
146 void InitVarExt(TBool aVar, TInitVarExtFn aFn)
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;
158 DumpRomFileInfo(*pE);
160 const TRomImageHeader& img = *(const TRomImageHeader*)pE->iAddressLin;
161 if (THardwareVariant(img.iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
163 __KTRACE_OPT(KBOOT,Kern::Printf("Processing"));
167 __KTRACE_OPT(KBOOT,Kern::Printf("Variant installed"));
171 pE=(TRomEntry*)img.iNextExtension;
174 Kern::Fault("NoVariant",0);
177 TInt InitData(const TRomImageHeader& a)
179 __KTRACE_OPT(KBOOT,Kern::Printf("InitData %08x+%x->%08x", a.iDataAddress, a.iDataSize, a.iDataBssLinearBase));
180 CHECK_ROM_ENTRY_POINT(a);
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);
192 TInt InitVariant(const TRomImageHeader& a)
194 TInt r = InitData(a);
195 __KTRACE_OPT(KBOOT,Kern::Printf("InitVariant: entry point returns %08x", r));
197 Kern::Fault("VariantEntry",r);
199 // Initialise and create the variant object
200 r = A::CreateVariant(&a, r);
202 Kern::Fault("VariantInit",r);
206 void P::CreateVariant()
208 __KTRACE_OPT(KBOOT,Kern::Printf("CreateVariant"));
210 InitVarExt(EFalse, &InitData); // initialise .data for all extensions
211 InitVarExt(ETrue, &InitVariant); // find variant and initialise it
212 FindRomRootDirectory();
215 struct SExtInit1EntryPoint
217 inline SExtInit1EntryPoint() : iEntryPoint(0),iReturnCode(0)
219 inline SExtInit1EntryPoint(TLibraryEntry aEp, TInt aVal) : iEntryPoint(aEp),iReturnCode(aVal)
221 TLibraryEntry iEntryPoint;
222 TInt iReturnCode; // bits 7-0 used for extension startup priority order
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
230 TInt priorityOrder(const SExtInit1EntryPoint& aMatch, const SExtInit1EntryPoint& aEntry)
232 TUint8 l=(TUint8)aMatch.iReturnCode;
233 TUint8 r=(TUint8)aEntry.iReturnCode;
242 TInt InitExt0(const TRomImageHeader& a)
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);
250 __KTRACE_OPT(KBOOT,Kern::Printf("Already started"));
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));
264 void P::StartExtensions()
266 // start extensions...
267 __KTRACE_OPT(KBOOT, Kern::Printf("Starting kernel extensions..."));
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));
274 InitVarExt(EFalse, &InitExt0); // populates the array of entry points in priority order
276 for(TInt i=0; i<K::ExtensionArray->Count(); i++) // call entry points in combined priority and temporal orders
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));
283 K::Fault(K::EStartExtensionsFailed);
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;
290 void P::KernelInfo(TProcessCreateInfo& aInfo, TAny*& aStack, TAny*& aHeap)
292 // Provide the initial supervisor data information from the ROM
295 aInfo.iFileName=KKernelFullPathNameSysBin;
296 aInfo.iRootNameOffset=11;
297 aInfo.iRootNameLength=9;
298 aInfo.iExtOffset = 16;
300 aInfo.iAttr=ECodeSegAttKernel|ECodeSegAttFixed;
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;
312 EXPORT_C void Epoc::RomProcessInfo(TProcessCreateInfo& aInfo, const TRomImageHeader& a)
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;
337 aInfo.iModuleVersion = a.iModuleVersion;
338 if (a.iFlags&KRomImageFlagsKernelMask)
339 aInfo.iAttr=ECodeSegAttKernel;
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);
360 EXPORT_C void Epoc::SetMonitorEntryPoint(TDfcFn aFn)
364 TUint32 x=(TUint32)aFn;
365 PP::MonitorEntryPoint[0]=x;
366 PP::MonitorEntryPoint[1]=~x;
367 PP::MonitorEntryPoint[2]=((x>>2)*~x);
371 PP::MonitorEntryPoint[0]=0;
372 PP::MonitorEntryPoint[1]=0;
373 PP::MonitorEntryPoint[2]=0;
377 EXPORT_C void Epoc::SetMonitorExceptionHandler(TLinAddr aHandler)
379 TheScheduler.iMonitorExceptionHandler=aHandler;
382 EXPORT_C TAny* Epoc::ExceptionInfo()
385 return 0; // separate for each CPU
387 return TheScheduler.i_ExcInfo;
391 EXPORT_C const TRomHeader& Epoc::RomHeader()
393 return TheRomHeader();
396 TLinAddr ExecHandler::RomHeaderAddress()
398 return ::RomHeaderAddress;
401 TLinAddr ExecHandler::RomRootDirectoryAddress()
403 return PP::RomRootDirAddress;
406 TBool M::IsRomAddress(const TAny* aPtr)
408 TLinAddr start=::RomHeaderAddress;
409 TLinAddr end=start+TheRomHeader().iUncompressedSize;
410 return ((TLinAddr)aPtr>=start) && ((TLinAddr)aPtr<end);
413 void P::SetSuperPageSignature()
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;
421 TBool P::CheckSuperPageSignature()
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 );
428 static const TUint32 KMapAttrType2 = 0x80000000;
429 static const TUint32 KMapAttrTypeShift = 26;
431 #if defined(__CPU_MEMORY_TYPE_REMAPPING)
432 extern TUint32 PrimaryRegionRemapRegister();
433 extern TUint32 NormalMemoryRemapRegister();
436 EXPORT_C TMappingAttributes2::TMappingAttributes2(TMemoryType aType,
443 //Sort out default values:
445 #if defined (__CPU_USE_SHARED_MEMORY)
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.
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)|
466 (aExecutable ? EMapAttrExecUser|EMapAttrExecSup : 0)|
468 (aShared ? EMapAttrShared : 0)|
469 (aParity ? EMapAttrUseECC : 0);
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);
476 TMappingAttributes2::TMappingAttributes2(TUint aMapAttr):iAttributes(aMapAttr)
480 TMemoryType TMappingAttributes2::Type()
482 if(iAttributes&KMapAttrType2)
483 return (TMemoryType)(iAttributes>>KMapAttrTypeShift & 0x7); //three bits for memory type.
485 switch(iAttributes&EMapAttrL1CacheMask)
487 case EMapAttrFullyBlocking:
488 return EMemAttStronglyOrdered;
490 case EMapAttrBufferedNC:
491 return EMemAttDevice;
493 case EMapAttrBufferedC:
494 case EMapAttrL1Uncached:
495 case EMapAttrCachedWTRA:
496 case EMapAttrCachedWTWA:
497 case EMapAttrAltCacheWTRA:
498 case EMapAttrAltCacheWTWA:
499 return EMemAttNormalUncached;
501 case EMapAttrCachedWBRA:
502 case EMapAttrCachedWBWA:
503 case EMapAttrAltCacheWBRA:
504 case EMapAttrAltCacheWBWA:
505 case EMapAttrL1CachedMax:
506 return EMemAttNormalCached;
510 return EMemAttNormalCached;
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);}
519 TBool TMappingAttributes2::Executable() {return (iAttributes&EMapAttrExecUser ? (TBool)ETrue : (TBool)EFalse);}
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);}
527 #ifdef __DEBUGGER_SUPPORT__
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.
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.
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.
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.
548 EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& aCapabilities, TInt aMaxBreakpoints)
550 CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::InitialiseCodeModifier");
552 NKern::ThreadEnterCS();
553 Kern::MutexWait(CodeModifier::Mutex());
555 if ( KErrNone == (err =CodeModifier::CreateAndInitialise(aMaxBreakpoints)))
556 aCapabilities = EBreakpointGlobal;
558 Kern::MutexSignal(CodeModifier::Mutex());
559 NKern::ThreadLeaveCS();
564 Restore all breakpoints and free resources.
565 Must not be called before Initialise().
567 @panic CodeModifier 0 if called before InitialiseCodeModifier().
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.
574 EXPORT_C void DebugSupport::CloseCodeModifier()
576 CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::CloseCodeModifier");
577 NKern::ThreadEnterCS();
578 Kern::MutexWait(CodeModifier::Mutex());
580 if (!TheCodeModifier)
582 Kern::MutexSignal(CodeModifier::Mutex());
583 NKern::ThreadLeaveCS();
584 CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
586 TheCodeModifier->Close();
588 Kern::MutexSignal(CodeModifier::Mutex());
589 NKern::ThreadLeaveCS();
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.
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:
600 DebugSupport::ModifyCode(thread1, address, size, value, type);
602 DebugSupport::ModifyCode(thread2, address size, value, type);
604 have the same effect if thread1 and thread2 belong to the same process.
606 Breakpoints of the diferent type(size) cannot overlap each other. For example:
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
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().
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.
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.
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.
636 @panic CodeModifier 0 if called before InitialiseCodeModifier().
637 @panic CodeModifier 1 if aSize value or aAdress alignement is invalid.
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.
644 EXPORT_C TInt DebugSupport::ModifyCode(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue, TUint aType)
646 CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::ModifyCode");
647 switch(aSize) //Chack aSize and aValue
649 case CodeModifier::EByte:
651 case CodeModifier::EHalfword:
652 if ((TInt)aAddress & 1)
653 CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
655 case CodeModifier::EWord:
656 if ((TInt)aAddress & 3)
657 CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
660 CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
663 if (aType != DebugSupport::EBreakpointGlobal)//Check breakpoint type
664 return KErrNotSupported;
666 NKern::ThreadEnterCS();
667 Kern::MutexWait(CodeModifier::Mutex());
669 if (!TheCodeModifier)
671 Kern::MutexSignal(CodeModifier::Mutex());
672 NKern::ThreadLeaveCS();
673 CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
675 TInt r = TheCodeModifier->Modify(aThread, aAddress, aSize, aValue);
677 Kern::MutexSignal(CodeModifier::Mutex());
678 NKern::ThreadLeaveCS();
682 return EBreakpointGlobal;
686 Restore a previousely written breakpoint.
687 I.e. restore the value at location aAddress in the address space of aProcess.
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().
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.
696 @param aProcess The process in who's address space aAddress lies.
697 @param aAddress The linear address of an existing breakpoint.
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.
705 @panic CodeModifier 0 if called before InitialiseCodeModifier().
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.
712 EXPORT_C TInt DebugSupport::RestoreCode(DThread* aThread, TLinAddr aAddress)
714 CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::RestoreCode");
715 NKern::ThreadEnterCS();
716 Kern::MutexWait(CodeModifier::Mutex());
718 if (!TheCodeModifier)
720 Kern::MutexSignal(CodeModifier::Mutex());
721 NKern::ThreadLeaveCS();
722 CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
724 TInt r = TheCodeModifier->Restore(aThread, aAddress);
726 Kern::MutexSignal(CodeModifier::Mutex());
727 NKern::ThreadLeaveCS();
732 Terminates a specified process on behalf of a debugger.
734 @param aProcess The process in who's address space aAddress lies.
735 @param aReason The reason code to supply when terminating a process
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.
744 EXPORT_C void DebugSupport::TerminateProcess(DProcess* aProcess, const TInt aReason)
746 CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::TerminateProcess");
747 NKern::ThreadEnterCS();
748 aProcess->Die(EExitTerminate,aReason,KNullDesC);
749 NKern::ThreadLeaveCS();
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
759 @pre Calling thread must be in the critical section
760 @pre CodeSeg mutex held
762 TInt CodeModifier::CreateAndInitialise(TInt aMaxBreakpoints)
767 CodeModifier* modifier = new CodeModifier;
771 modifier->iBreakpoints = new TBreakpoint[aMaxBreakpoints];
772 if (!modifier->iBreakpoints)
778 modifier->iPages = new TPageInfo[aMaxBreakpoints];
779 if (!modifier->iPages)
781 delete[] modifier->iBreakpoints;
786 modifier->iPoolSize = aMaxBreakpoints;
787 modifier->iPageSize = Kern::RoundToPageSize(1);
788 modifier->iPageMask = ~(modifier->iPageSize-1);
790 TheCodeModifier = modifier;
791 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CreateAndInitialise() Size:%d created", aMaxBreakpoints));
797 @pre Calling thread must be in the critical section
798 @pre CodeSeg mutex held
800 TInt CodeModifier::Modify(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue)
805 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Modify() T:%x Addr:%x, Size:%d Val:%x", aThread, aAddress, aSize, aValue));
807 TBreakpoint* brk =FindBreakpoint(aThread, aAddress,aSize,overlap);
809 return KErrAccessDenied;
811 return KErrAlreadyExists;
813 if(NULL==(brk = FindEmptyBrk()))
816 //Find the page (if exists). Shadow the page if necessery.
819 #ifndef __DEMAND_PAGING__
820 if (IsRom(aAddress)) // If no demand paging, only need to do this if the address is in rom
823 pageIndex = FindPageInfo(aAddress);
826 pageIndex = FindEmptyPageInfo();
829 TPageInfo& page = iPages[pageIndex];
830 memclr(&page, sizeof(page));
831 page.iAddress = aAddress & iPageMask;
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)
842 #ifdef __DEMAND_PAGING__
845 DDemandPagingLock* lock = new DDemandPagingLock;
848 r = lock->Alloc(iPageSize);
854 lock->Lock(aThread, aAddress & iPageMask, iPageSize);
855 page.iPagingLock = lock;
859 iPages[pageIndex].iCounter++;
862 r = SafeWriteCode(aThread->iOwningProcess, aAddress, aSize, aValue, &oldValue);
864 {//aAddress is invalid
866 RestorePage(pageIndex);
870 //All done. Update the internal structures.
871 brk->iAddress = aAddress;
872 brk->iProcessId = (aThread->iOwningProcess)->iId;
873 brk->iOldValue = oldValue;
875 brk->iPageIndex = pageIndex;
880 @pre Calling thread must be in the critical section
881 @pre CodeSeg mutex held
883 TInt CodeModifier::Restore(DThread* aThread, TLinAddr aAddress)
887 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() T:%x Addr:%x", aThread, aAddress));
889 TBreakpoint* br = FindBreakpoint(aThread, aAddress, 0, overlaps);
893 r = SafeWriteCode(aThread->iOwningProcess, br->iAddress, br->iSize, br->iOldValue, &oldValue);
897 br->iSize = (TUint)EEmpty;
899 TInt pageIndex = br->iPageIndex;
901 RestorePage(pageIndex);
907 @pre Calling thread must be in the critical section
908 @pre CodeSeg mutex held
910 void CodeModifier::Close()
915 TheCodeModifier = NULL;
917 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close()"));
919 for (brkIndex=0; brkIndex<iPoolSize; brkIndex++)
921 if (iBreakpoints[brkIndex].iSize ==(TUint16)EEmpty)
923 DProcess* process = Process(iBreakpoints[brkIndex].iProcessId);
925 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close() - Removing Brk:%x",iBreakpoints[brkIndex].iAddress));
927 //Write back the original value
929 SafeWriteCode(process, iBreakpoints[brkIndex].iAddress, iBreakpoints[brkIndex].iSize, iBreakpoints[brkIndex].iOldValue, &oldValue);
931 iBreakpoints[brkIndex].iSize = (TUint)EEmpty;
932 TInt pageIndex = iBreakpoints[brkIndex].iPageIndex;
934 RestorePage(pageIndex);
941 Destructor. The object is deleted asynchroniously from Kernel Supervisor thread.
943 CodeModifier::~CodeModifier()
945 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::~CodeModifier()"));
947 delete[] iBreakpoints;
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.
954 @param aCodeSeg Code Segment that is removed from aProcess.
955 @param aProcess Process from whom the code segment is removed.
957 @pre Calling thread must be in the critical section
958 @pre CodeSeg mutex held
960 void CodeModifier::CodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
962 if (!TheCodeModifier)
964 TheCodeModifier->DoCodeSegRemoved(aCodeSeg, aProcess);
967 void CodeModifier::DoCodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
969 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()"));
972 TUint minAddr = aCodeSeg->iRunAddress;
973 TUint maxAddr = aCodeSeg->iRunAddress + aCodeSeg->iSize;
975 TBreakpoint* bp = iBreakpoints;
976 TBreakpoint* bpEnd = bp+iPoolSize; //points right behind iBreakpoints
977 for (; bp<bpEnd; ++bp)
979 if (bp->iSize == (TUint)EEmpty) continue;
981 if (aProcess->iId == bp->iProcessId)
983 if (bp->iAddress >= minAddr && bp->iAddress < maxAddr)
985 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()- a breakpoint"));
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);
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);
1001 Finds DProcess that matches to processId
1002 @param aProcessId ProcessId
1003 @return Pointer to matching DProcess or NULL
1005 DProcess* CodeModifier::Process(TUint aProcessId)
1008 DProcess* process = NULL;
1009 DObjectCon* processCon = Kern::Containers()[EProcess];
1012 for (i=0;i<processCon->Count();i++)
1014 DProcess* pr = (DProcess*)(*processCon)[i];
1015 if (pr->iId == aProcessId)
1017 process=(DProcess*)pr;
1022 processCon->Signal();
1027 Returns eTrue if given virtual address belongs to rom image, EFalse otherwise
1029 TBool CodeModifier::IsRom(TLinAddr aAddress)
1031 TRomHeader romHeader = Epoc::RomHeader();
1032 if ( (aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iUncompressedSize)) )
1038 Finds the first available(empty) breakpoint slot.
1039 @return The pointer of the empty slot or NULL if all occupied.
1041 CodeModifier::TBreakpoint* CodeModifier::FindEmptyBrk()
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)
1053 Finds matching breakpoint.
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).
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.
1064 CodeModifier::TBreakpoint* CodeModifier::FindBreakpoint(DThread* aThread, TLinAddr aAddress, TInt aSize, TBool& aOverlap)
1068 TUint processId = aThread->iOwningProcess->iId;//processId of the thread that owns aThread
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
1080 TBreakpoint* bp = TheCodeModifier->iBreakpoints;
1081 TBreakpoint* bpEnd = bp+TheCodeModifier->iPoolSize; //points right behind iBreakpoints
1082 for (; bp<bpEnd; ++bp)
1084 if (bp->iSize == (TInt16)EEmpty || bp->iProcessId != processId)
1085 continue;//Either empty or not matchng process.
1088 { //Do not check the size. If the address does not match, do not check for overlap.
1089 if (bp->iAddress == aAddress)
1095 if (bp->iAddress == aAddress && bp->iSize == aSize)
1096 return bp;//If we find a matching breakpoint, there cannot be another one that overlaps
1098 //Check if bp breakpoint overlaps with the specified one.
1099 if ((bp->iAddress^aAddress)>>2)
1100 continue;//Not in the same word
1102 if (((1<<bp->iSize)-1)<<(bp->iAddress&3)&bytes)
1103 {//Two brakpoints are within the same word with some overlaping bytes.
1105 return NULL; //If we find an overlaping breakpoint, there cannot be another one that matches exactly.
1112 Finds the first available(empty) page info slot.
1113 @return The index of the slot or KErrNotFound if all occupied.
1115 TInt CodeModifier::FindEmptyPageInfo()
1118 for (i=0; i<iPoolSize; i++)
1119 if (!iPages[i].iCounter)
1121 return KErrNotFound;
1125 Finds the page info structure that contains given virtual address
1126 @return The index of the page info slot or KErrNotFound.
1128 TInt CodeModifier::FindPageInfo(TLinAddr aAddress)
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)
1136 return KErrNotFound;
1140 Decrement the count of breakpoints associated with this page, and restores page
1141 to its original state if there are none remaining.
1143 void CodeModifier::RestorePage(TInt aPageIndex)
1145 TPageInfo& page = iPages[aPageIndex];
1146 if(--page.iCounter==0)
1148 if (!page.iWasShadowed)
1150 __KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() - Freeing Shadow Page"));
1151 Epoc::FreeShadowPage(page.iAddress);
1153 #ifdef __DEMAND_PAGING__
1154 if (page.iPagingLock)
1156 // Release lock and free resources
1157 delete page.iPagingLock;
1158 page.iPagingLock = NULL;
1164 void CodeModifier::Fault(TPanic aPanic)
1166 Kern::Fault("CodeModifier", aPanic);
1169 #else //__DEBUGGER_SUPPORT__
1170 EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& /*aCapabilities*/, TInt /*aMinBreakpoints*/)
1172 return KErrNotSupported;
1174 EXPORT_C void DebugSupport::CloseCodeModifier()
1177 EXPORT_C TInt DebugSupport::ModifyCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/, TInt /*aSize*/, TUint /*aValue*/, TUint /*aType*/)
1179 return KErrNotSupported;
1181 EXPORT_C TInt DebugSupport::RestoreCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/)
1183 return KErrNotSupported;
1185 EXPORT_C void DebugSupport::TerminateProcess(DProcess* /*aProcess*/, const TInt /*aReason*/)