|
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 |