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 |
EXPORT_C TMappingAttributes2::TMappingAttributes2(TMemoryType aType,
|
|
432 |
TBool aUserAccess,
|
|
433 |
TBool aWritable,
|
|
434 |
TBool aExecutable,
|
|
435 |
TInt aShared,
|
|
436 |
TInt aParity)
|
|
437 |
{
|
|
438 |
//Sort out default values:
|
|
439 |
if (aShared<0)
|
|
440 |
#if defined (__CPU_USE_SHARED_MEMORY)
|
|
441 |
aShared = 1;
|
|
442 |
#else
|
|
443 |
aShared = 0;
|
|
444 |
#endif
|
|
445 |
if (aParity<0)
|
|
446 |
aParity = 0;
|
|
447 |
|
|
448 |
// KMapAttrType2 bit marks the object as of TMappingAttributes2 type (as opposed to TMappingAttributes bitmask).
|
|
449 |
// We have to make sure that these two types can work together.
|
|
450 |
|
|
451 |
iAttributes = KMapAttrType2 | // Mark it as TMappingAttributes2 object
|
|
452 |
EMapAttrReadSup | // All memory is readable from Kernel (Supervisor) mode
|
|
453 |
(aType <<KMapAttrTypeShift) |
|
|
454 |
(aUserAccess ? EMapAttrReadUser : 0)|
|
|
455 |
(aWritable ? EMapAttrWriteSup : 0)|
|
|
456 |
((aWritable&&aUserAccess)? EMapAttrWriteUser: 0)|
|
|
457 |
#ifdef __MMU_USE_SYMMETRIC_ACCESS_PERMISSIONS
|
|
458 |
(aExecutable ? EMapAttrExecSup : 0)|
|
|
459 |
((aExecutable&&aUserAccess)? EMapAttrExecUser: 0)|
|
|
460 |
#else
|
|
461 |
(aExecutable ? EMapAttrExecUser|EMapAttrExecSup : 0)|
|
|
462 |
#endif
|
|
463 |
(aShared ? EMapAttrShared : 0)|
|
|
464 |
(aParity ? EMapAttrUseECC : 0);
|
|
465 |
|
|
466 |
// Kernel relies on TMappingAttributes bitmask when dealing with various memory mappings.
|
|
467 |
// Set cache attribute bits as they are in TMappingAttributes.
|
|
468 |
iAttributes |= InternalCache::TypeToCachingAttributes(aType);
|
|
469 |
}
|
|
470 |
|
|
471 |
TMappingAttributes2::TMappingAttributes2(TUint aMapAttr):iAttributes(aMapAttr)
|
|
472 |
{
|
|
473 |
};
|
|
474 |
|
|
475 |
TMemoryType TMappingAttributes2::Type()
|
|
476 |
{
|
|
477 |
if(iAttributes&KMapAttrType2)
|
|
478 |
return (TMemoryType)(iAttributes>>KMapAttrTypeShift & 0x7); //three bits for memory type.
|
|
479 |
|
|
480 |
switch(iAttributes&EMapAttrL1CacheMask)
|
|
481 |
{
|
|
482 |
case EMapAttrFullyBlocking:
|
|
483 |
return EMemAttStronglyOrdered;
|
|
484 |
|
|
485 |
case EMapAttrBufferedNC:
|
|
486 |
return EMemAttDevice;
|
|
487 |
|
|
488 |
case EMapAttrBufferedC:
|
|
489 |
case EMapAttrL1Uncached:
|
|
490 |
case EMapAttrCachedWTRA:
|
|
491 |
case EMapAttrCachedWTWA:
|
|
492 |
case EMapAttrAltCacheWTRA:
|
|
493 |
case EMapAttrAltCacheWTWA:
|
|
494 |
return EMemAttNormalUncached;
|
|
495 |
|
|
496 |
case EMapAttrCachedWBRA:
|
|
497 |
case EMapAttrCachedWBWA:
|
|
498 |
case EMapAttrAltCacheWBRA:
|
|
499 |
case EMapAttrAltCacheWBWA:
|
|
500 |
case EMapAttrL1CachedMax:
|
|
501 |
return EMemAttNormalCached;
|
|
502 |
|
|
503 |
default:
|
|
504 |
Panic(KErrArgument);
|
|
505 |
return EMemAttNormalCached;
|
|
506 |
}
|
|
507 |
}
|
|
508 |
|
|
509 |
TBool TMappingAttributes2::UserAccess() {return (iAttributes&EMapAttrUserRw ? (TBool)ETrue : (TBool)EFalse);}
|
|
510 |
TBool TMappingAttributes2::Writable() {return (iAttributes&EMapAttrWriteMask? (TBool)ETrue : (TBool)EFalse);}
|
|
511 |
#ifdef __MMU_USE_SYMMETRIC_ACCESS_PERMISSIONS
|
|
512 |
TBool TMappingAttributes2::Executable() {return (iAttributes&EMapAttrExecMask ? (TBool)ETrue : (TBool)EFalse);}
|
|
513 |
#else
|
|
514 |
TBool TMappingAttributes2::Executable() {return (iAttributes&EMapAttrExecUser ? (TBool)ETrue : (TBool)EFalse);}
|
|
515 |
#endif
|
|
516 |
TBool TMappingAttributes2::Shared() {return (iAttributes&EMapAttrShared ? (TBool)ETrue : (TBool)EFalse);}
|
|
517 |
TBool TMappingAttributes2::Parity() {return (iAttributes&EMapAttrUseECC ? (TBool)ETrue : (TBool)EFalse);}
|
|
518 |
TBool TMappingAttributes2::ObjectType2(){return (iAttributes&KMapAttrType2 ? (TBool)ETrue : (TBool)EFalse);}
|
|
519 |
void TMappingAttributes2::Panic(TInt aPanic) {Kern::Fault("TMappingAttributes2",aPanic);}
|
|
520 |
|
|
521 |
|
|
522 |
#ifdef __DEBUGGER_SUPPORT__
|
|
523 |
/**
|
|
524 |
Initialises the breakpoint pool.
|
|
525 |
There is only one breakpoint pool in the system. The breakpoint pool should be initialised only once - usually from
|
|
526 |
the run-mode debugger device driver.
|
|
527 |
|
|
528 |
@param aCapabilities On return this is set to a bitmask of values from enum DebugSupport::TType which represents the
|
|
529 |
supported breakpoint types. At the moment only DebugSupport::EBreakpointGlobal type is supported.
|
|
530 |
@param aMaxBreakpoints The number of breakpoints for which resources should be reserved. It represents
|
|
531 |
the maximum number of the breakpoints at a time.
|
|
532 |
|
|
533 |
@return KErrNoMemory, if not enough memory to reserve breakpoint resources.
|
|
534 |
KErrInUse, if breakpoint pool already exists. Indicates that another debug tool might be using it at the moment.
|
|
535 |
KErrNotSupported, if Kernel is not built with __DEBUGGER_SUPPORT__ option
|
|
536 |
KErrNone, on success.
|
|
537 |
|
|
538 |
@pre No fast mutex can be held.
|
|
539 |
@pre Kernel must be unlocked.
|
|
540 |
@pre Call in a thread context.
|
|
541 |
@pre Interrupts must be enabled.
|
|
542 |
*/
|
|
543 |
EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& aCapabilities, TInt aMaxBreakpoints)
|
|
544 |
{
|
|
545 |
CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::InitialiseCodeModifier");
|
|
546 |
TInt err;
|
|
547 |
NKern::ThreadEnterCS();
|
|
548 |
Kern::MutexWait(CodeModifier::Mutex());
|
|
549 |
|
|
550 |
if ( KErrNone == (err =CodeModifier::CreateAndInitialise(aMaxBreakpoints)))
|
|
551 |
aCapabilities = EBreakpointGlobal;
|
|
552 |
|
|
553 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
554 |
NKern::ThreadLeaveCS();
|
|
555 |
return err;
|
|
556 |
}
|
|
557 |
|
|
558 |
/**
|
|
559 |
Restore all breakpoints and free resources.
|
|
560 |
Must not be called before Initialise().
|
|
561 |
|
|
562 |
@panic CodeModifier 0 if called before InitialiseCodeModifier().
|
|
563 |
|
|
564 |
@pre No fast mutex can be held.
|
|
565 |
@pre Kernel must be unlocked.
|
|
566 |
@pre Call in a thread context.
|
|
567 |
@pre Interrupts must be enabled.
|
|
568 |
*/
|
|
569 |
EXPORT_C void DebugSupport::CloseCodeModifier()
|
|
570 |
{
|
|
571 |
CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::CloseCodeModifier");
|
|
572 |
NKern::ThreadEnterCS();
|
|
573 |
Kern::MutexWait(CodeModifier::Mutex());
|
|
574 |
|
|
575 |
if (!TheCodeModifier)
|
|
576 |
{
|
|
577 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
578 |
NKern::ThreadLeaveCS();
|
|
579 |
CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
|
|
580 |
}
|
|
581 |
TheCodeModifier->Close();
|
|
582 |
|
|
583 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
584 |
NKern::ThreadLeaveCS();
|
|
585 |
}
|
|
586 |
|
|
587 |
/**
|
|
588 |
Write a single breakpoint.
|
|
589 |
I.e. store aValue at location aAddress in the address space of aThread.
|
|
590 |
If the address resides in XIP code (ROM image), the memory page is shadowed before the content of the aAddress is altered.
|
|
591 |
|
|
592 |
The breakpoint should be cleared/restored by DebugSupport::RestoreCode with matching aThread and aAddress.
|
|
593 |
The breakpoints are owned by the corresponding process. Therefore:
|
|
594 |
@code
|
|
595 |
DebugSupport::ModifyCode(thread1, address, size, value, type);
|
|
596 |
and
|
|
597 |
DebugSupport::ModifyCode(thread2, address size, value, type);
|
|
598 |
@endcode
|
|
599 |
have the same effect if thread1 and thread2 belong to the same process.
|
|
600 |
|
|
601 |
Breakpoints of the diferent type(size) cannot overlap each other. For example:
|
|
602 |
@code
|
|
603 |
DebugSupport::ModifyCode(thread, address, 4, value, type); //address is word aligned address
|
|
604 |
DebugSupport::ModifyCode(thread, address, 2, value, type); //will return KErrAccessDenied
|
|
605 |
DebugSupport::ModifyCode(thread, address+2, 2, value, type); //will return KErrAccessDenied
|
|
606 |
DebugSupport::ModifyCode(thread, address+1, 1, value, type); //will return KErrAccessDenied
|
|
607 |
@endcode
|
|
608 |
|
|
609 |
After the content of aAddress is altered, instruction cache invalidation is performed on the cache line that aAddress
|
|
610 |
belongs to. Therefore, the device driver doesn't have to call Cache::IMB_Range().
|
|
611 |
|
|
612 |
If a code segment (which a valid breakpoint belongs to) is removed from the given process, the breakpoint will be
|
|
613 |
automatically removed. This occures just before EEventRemoveCodeSeg event is issued with DProcess* matching
|
|
614 |
the breakpoint's process. This also applies to the terminating/killed process, as all breakpoints belonging to it will be removed too.
|
|
615 |
|
|
616 |
@param aThread The thread in who's address space the breakpoint is to be written.
|
|
617 |
@param aAddress The linear address of the breakpoint. Must be a multiple of aSize.
|
|
618 |
@param aSize The size, in bytes, of the breakpoint. Must be 1,2 or 4.
|
|
619 |
@param aValue The value to be stored at aAddress. This value is trucated to the
|
|
620 |
number of bits relevent to aSize.
|
|
621 |
@param aType The breakpoint type required. This is a bitmask of values from enum TType.
|
|
622 |
If this specifies more than one type, then the type with least scope
|
|
623 |
(i.e. EBreakpointLocal) is used when this is supported.
|
|
624 |
|
|
625 |
@return KErrNoMemory, if no resources are available.
|
|
626 |
KErrAlreadyExists, if a breakpoint with the same address, size and the same owning process already exists in the pool.
|
|
627 |
KErrAccessDenied, if an existing breakpoint of a different size and the same owning process overlaps the specified breakpoint.
|
|
628 |
KErrNotSupported, if none of the breakpoints types specified are supported or if Kernel is not built with __DEBUGGER_SUPPORT__ option
|
|
629 |
Otherwise, a positive value from enum TType which represents the type of breakpoint written.
|
|
630 |
|
|
631 |
@panic CodeModifier 0 if called before InitialiseCodeModifier().
|
|
632 |
@panic CodeModifier 1 if aSize value or aAdress alignement is invalid.
|
|
633 |
|
|
634 |
@pre No fast mutex can be held.
|
|
635 |
@pre Kernel must be unlocked.
|
|
636 |
@pre Call in a thread context.
|
|
637 |
@pre Interrupts must be enabled.
|
|
638 |
*/
|
|
639 |
EXPORT_C TInt DebugSupport::ModifyCode(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue, TUint aType)
|
|
640 |
{
|
|
641 |
CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::ModifyCode");
|
|
642 |
switch(aSize) //Chack aSize and aValue
|
|
643 |
{
|
|
644 |
case CodeModifier::EByte:
|
|
645 |
break;
|
|
646 |
case CodeModifier::EHalfword:
|
|
647 |
if ((TInt)aAddress & 1)
|
|
648 |
CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
|
|
649 |
break;
|
|
650 |
case CodeModifier::EWord:
|
|
651 |
if ((TInt)aAddress & 3)
|
|
652 |
CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
|
|
653 |
break;
|
|
654 |
default:
|
|
655 |
CodeModifier::Fault(CodeModifier::EPanicInvalidSizeOrAlignment);
|
|
656 |
}
|
|
657 |
|
|
658 |
if (aType != DebugSupport::EBreakpointGlobal)//Check breakpoint type
|
|
659 |
return KErrNotSupported;
|
|
660 |
|
|
661 |
NKern::ThreadEnterCS();
|
|
662 |
Kern::MutexWait(CodeModifier::Mutex());
|
|
663 |
|
|
664 |
if (!TheCodeModifier)
|
|
665 |
{
|
|
666 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
667 |
NKern::ThreadLeaveCS();
|
|
668 |
CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
|
|
669 |
}
|
|
670 |
TInt r = TheCodeModifier->Modify(aThread, aAddress, aSize, aValue);
|
|
671 |
|
|
672 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
673 |
NKern::ThreadLeaveCS();
|
|
674 |
|
|
675 |
if (r)
|
|
676 |
return r;
|
|
677 |
return EBreakpointGlobal;
|
|
678 |
}
|
|
679 |
|
|
680 |
/**
|
|
681 |
Restore a previousely written breakpoint.
|
|
682 |
I.e. restore the value at location aAddress in the address space of aProcess.
|
|
683 |
|
|
684 |
After the content of aAddress is altered, instruction cache invalidation is performed on the cache line
|
|
685 |
that aAddress belongs to. Therefore, the device driver doesn't have to call Cache::IMB_Range().
|
|
686 |
|
|
687 |
If the address resides in shadowed memory, the memory page will be un-shadowed if this is the last breakpoint
|
|
688 |
in the page. However, if the page had been already shadowed before the first breakpoint in the page was applied,
|
|
689 |
the page will remain shadowed.
|
|
690 |
|
|
691 |
@param aProcess The process in who's address space aAddress lies.
|
|
692 |
@param aAddress The linear address of an existing breakpoint.
|
|
693 |
|
|
694 |
@return KErrNotFound, if the breakpoint hadn't been previously written. It is also returned if the breakpoint
|
|
695 |
was previously removed from the list because the code segment (which the breakpoint belongs to) was
|
|
696 |
unloaded/removed from the process associated with the breakpoint.
|
|
697 |
KErrNotSupported, if Kernel is not built with __DEBUGGER_SUPPORT__ option
|
|
698 |
KErrNone, on success.
|
|
699 |
|
|
700 |
@panic CodeModifier 0 if called before InitialiseCodeModifier().
|
|
701 |
|
|
702 |
@pre No fast mutex can be held.
|
|
703 |
@pre Kernel must be unlocked.
|
|
704 |
@pre Call in a thread context.
|
|
705 |
@pre Interrupts must be enabled.
|
|
706 |
*/
|
|
707 |
EXPORT_C TInt DebugSupport::RestoreCode(DThread* aThread, TLinAddr aAddress)
|
|
708 |
{
|
|
709 |
CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::RestoreCode");
|
|
710 |
NKern::ThreadEnterCS();
|
|
711 |
Kern::MutexWait(CodeModifier::Mutex());
|
|
712 |
|
|
713 |
if (!TheCodeModifier)
|
|
714 |
{
|
|
715 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
716 |
NKern::ThreadLeaveCS();
|
|
717 |
CodeModifier::Fault(CodeModifier::EPanicNotInitialised);
|
|
718 |
}
|
|
719 |
TInt r = TheCodeModifier->Restore(aThread, aAddress);
|
|
720 |
|
|
721 |
Kern::MutexSignal(CodeModifier::Mutex());
|
|
722 |
NKern::ThreadLeaveCS();
|
|
723 |
return r;
|
|
724 |
}
|
|
725 |
|
|
726 |
/**
|
|
727 |
Terminates a specified process on behalf of a debugger.
|
|
728 |
|
|
729 |
@param aProcess The process in who's address space aAddress lies.
|
|
730 |
@param aReason The reason code to supply when terminating a process
|
|
731 |
|
|
732 |
@return N/A.
|
|
733 |
|
|
734 |
@pre No fast mutex can be held.
|
|
735 |
@pre Kernel must be unlocked.
|
|
736 |
@pre Call in a thread context.
|
|
737 |
@pre Interrupts must be enabled.
|
|
738 |
*/
|
|
739 |
EXPORT_C void DebugSupport::TerminateProcess(DProcess* aProcess, const TInt aReason)
|
|
740 |
{
|
|
741 |
CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"DebugSupport::TerminateProcess");
|
|
742 |
NKern::ThreadEnterCS();
|
|
743 |
aProcess->Die(EExitTerminate,aReason,KNullDesC);
|
|
744 |
NKern::ThreadLeaveCS();
|
|
745 |
return;
|
|
746 |
}
|
|
747 |
|
|
748 |
/**
|
|
749 |
Creates CodeModifier.
|
|
750 |
@param aMaxBreakpoints The number of breakpoints to be allocated.
|
|
751 |
@return KErrInUse if code modifier already exists.
|
|
752 |
KErrNoMemory if out of memory
|
|
753 |
KErrNone on success
|
|
754 |
@pre Calling thread must be in the critical section
|
|
755 |
@pre CodeSeg mutex held
|
|
756 |
*/
|
|
757 |
TInt CodeModifier::CreateAndInitialise(TInt aMaxBreakpoints)
|
|
758 |
{
|
|
759 |
if (TheCodeModifier)
|
|
760 |
return KErrInUse;
|
|
761 |
|
|
762 |
CodeModifier* modifier = new CodeModifier;
|
|
763 |
if (!modifier)
|
|
764 |
return KErrNoMemory;
|
|
765 |
|
|
766 |
modifier->iBreakpoints = new TBreakpoint[aMaxBreakpoints];
|
|
767 |
if (!modifier->iBreakpoints)
|
|
768 |
{
|
|
769 |
delete modifier;
|
|
770 |
return KErrNoMemory;
|
|
771 |
};
|
|
772 |
|
|
773 |
modifier->iPages = new TPageInfo[aMaxBreakpoints];
|
|
774 |
if (!modifier->iPages)
|
|
775 |
{
|
|
776 |
delete[] modifier->iBreakpoints;
|
|
777 |
delete modifier;
|
|
778 |
return KErrNoMemory;
|
|
779 |
}
|
|
780 |
|
|
781 |
modifier->iPoolSize = aMaxBreakpoints;
|
|
782 |
modifier->iPageSize = Kern::RoundToPageSize(1);
|
|
783 |
modifier->iPageMask = ~(modifier->iPageSize-1);
|
|
784 |
|
|
785 |
TheCodeModifier = modifier;
|
|
786 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CreateAndInitialise() Size:%d created", aMaxBreakpoints));
|
|
787 |
return KErrNone;
|
|
788 |
}
|
|
789 |
|
|
790 |
/**
|
|
791 |
Sets breakpoint.
|
|
792 |
@pre Calling thread must be in the critical section
|
|
793 |
@pre CodeSeg mutex held
|
|
794 |
*/
|
|
795 |
TInt CodeModifier::Modify(DThread* aThread, TLinAddr aAddress, TInt aSize, TUint aValue)
|
|
796 |
{
|
|
797 |
TInt r;
|
|
798 |
TUint oldValue;
|
|
799 |
TBool overlap;
|
|
800 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Modify() T:%x Addr:%x, Size:%d Val:%x", aThread, aAddress, aSize, aValue));
|
|
801 |
|
|
802 |
TBreakpoint* brk =FindBreakpoint(aThread, aAddress,aSize,overlap);
|
|
803 |
if (overlap)
|
|
804 |
return KErrAccessDenied;
|
|
805 |
if (brk)
|
|
806 |
return KErrAlreadyExists;
|
|
807 |
|
|
808 |
if(NULL==(brk = FindEmptyBrk()))
|
|
809 |
return KErrNoMemory;
|
|
810 |
|
|
811 |
//Find the page (if exists). Shadow the page if necessery.
|
|
812 |
TInt pageIndex = -1;
|
|
813 |
|
|
814 |
#ifndef __DEMAND_PAGING__
|
|
815 |
if (IsRom(aAddress)) // If no demand paging, only need to do this if the address is in rom
|
|
816 |
#endif
|
|
817 |
{
|
|
818 |
pageIndex = FindPageInfo(aAddress);
|
|
819 |
if (pageIndex < 0)
|
|
820 |
{
|
|
821 |
pageIndex = FindEmptyPageInfo();
|
|
822 |
if (pageIndex < 0)
|
|
823 |
return KErrNoMemory;
|
|
824 |
TPageInfo& page = iPages[pageIndex];
|
|
825 |
memclr(&page, sizeof(page));
|
|
826 |
page.iAddress = aAddress & iPageMask;
|
|
827 |
|
|
828 |
if (IsRom(aAddress))
|
|
829 |
{
|
|
830 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Modify() - Shadowing Page"));
|
|
831 |
r = Epoc::AllocShadowPage(aAddress & iPageMask);
|
|
832 |
if (r==KErrAlreadyExists)
|
|
833 |
page.iWasShadowed = ETrue;
|
|
834 |
else if (r!=KErrNone)
|
|
835 |
return r;
|
|
836 |
}
|
|
837 |
#ifdef __DEMAND_PAGING__
|
|
838 |
else
|
|
839 |
{
|
|
840 |
DDemandPagingLock* lock = new DDemandPagingLock;
|
|
841 |
if (lock == NULL)
|
|
842 |
return KErrNoMemory;
|
|
843 |
r = lock->Alloc(iPageSize);
|
|
844 |
if (r != KErrNone)
|
|
845 |
{
|
|
846 |
delete lock;
|
|
847 |
return r;
|
|
848 |
}
|
|
849 |
lock->Lock(aThread, aAddress & iPageMask, iPageSize);
|
|
850 |
page.iPagingLock = lock;
|
|
851 |
}
|
|
852 |
#endif
|
|
853 |
}
|
|
854 |
iPages[pageIndex].iCounter++;
|
|
855 |
}
|
|
856 |
|
|
857 |
r = SafeWriteCode(aThread->iOwningProcess, aAddress, aSize, aValue, &oldValue);
|
|
858 |
if (r != KErrNone)
|
|
859 |
{//aAddress is invalid
|
|
860 |
if (pageIndex >= 0)
|
|
861 |
RestorePage(pageIndex);
|
|
862 |
return r;
|
|
863 |
}
|
|
864 |
|
|
865 |
//All done. Update the internal structures.
|
|
866 |
brk->iAddress = aAddress;
|
|
867 |
brk->iProcessId = (aThread->iOwningProcess)->iId;
|
|
868 |
brk->iOldValue = oldValue;
|
|
869 |
brk->iSize = aSize;
|
|
870 |
brk->iPageIndex = pageIndex;
|
|
871 |
return KErrNone;
|
|
872 |
}
|
|
873 |
|
|
874 |
/**
|
|
875 |
@pre Calling thread must be in the critical section
|
|
876 |
@pre CodeSeg mutex held
|
|
877 |
*/
|
|
878 |
TInt CodeModifier::Restore(DThread* aThread, TLinAddr aAddress)
|
|
879 |
{
|
|
880 |
TUint oldValue;
|
|
881 |
TBool overlaps;
|
|
882 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() T:%x Addr:%x", aThread, aAddress));
|
|
883 |
TInt r = KErrNone;;
|
|
884 |
TBreakpoint* br = FindBreakpoint(aThread, aAddress, 0, overlaps);
|
|
885 |
if (br==NULL)
|
|
886 |
return KErrNotFound;
|
|
887 |
|
|
888 |
r = SafeWriteCode(aThread->iOwningProcess, br->iAddress, br->iSize, br->iOldValue, &oldValue);
|
|
889 |
if (r)
|
|
890 |
r=KErrNotFound;
|
|
891 |
|
|
892 |
br->iSize = (TUint)EEmpty;
|
|
893 |
|
|
894 |
TInt pageIndex = br->iPageIndex;
|
|
895 |
if (pageIndex>=0)
|
|
896 |
RestorePage(pageIndex);
|
|
897 |
|
|
898 |
return r;
|
|
899 |
}
|
|
900 |
|
|
901 |
/*
|
|
902 |
@pre Calling thread must be in the critical section
|
|
903 |
@pre CodeSeg mutex held
|
|
904 |
*/
|
|
905 |
void CodeModifier::Close()
|
|
906 |
{
|
|
907 |
TUint oldValue;
|
|
908 |
TInt brkIndex;
|
|
909 |
|
|
910 |
TheCodeModifier = NULL;
|
|
911 |
|
|
912 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close()"));
|
|
913 |
|
|
914 |
for (brkIndex=0; brkIndex<iPoolSize; brkIndex++)
|
|
915 |
{
|
|
916 |
if (iBreakpoints[brkIndex].iSize ==(TUint16)EEmpty)
|
|
917 |
continue;
|
|
918 |
DProcess* process = Process(iBreakpoints[brkIndex].iProcessId);
|
|
919 |
|
|
920 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Close() - Removing Brk:%x",iBreakpoints[brkIndex].iAddress));
|
|
921 |
|
|
922 |
//Write back the original value
|
|
923 |
if (process)
|
|
924 |
SafeWriteCode(process, iBreakpoints[brkIndex].iAddress, iBreakpoints[brkIndex].iSize, iBreakpoints[brkIndex].iOldValue, &oldValue);
|
|
925 |
|
|
926 |
iBreakpoints[brkIndex].iSize = (TUint)EEmpty;
|
|
927 |
TInt pageIndex = iBreakpoints[brkIndex].iPageIndex;
|
|
928 |
if (pageIndex>=0)
|
|
929 |
RestorePage(pageIndex);
|
|
930 |
}
|
|
931 |
|
|
932 |
delete this;
|
|
933 |
}
|
|
934 |
|
|
935 |
/*
|
|
936 |
Destructor. The object is deleted asynchroniously from Kernel Supervisor thread.
|
|
937 |
*/
|
|
938 |
CodeModifier::~CodeModifier()
|
|
939 |
{
|
|
940 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::~CodeModifier()"));
|
|
941 |
delete[] iPages;
|
|
942 |
delete[] iBreakpoints;
|
|
943 |
}
|
|
944 |
|
|
945 |
/**
|
|
946 |
This is executed when a code segment is about to be unmapped from the process. It corresponds to EEventRemoveCodeSeg Kernel event.
|
|
947 |
Removes breakpoints that belong to the threads from aProcess. Also, removes shadow pages if there is no breakpoint left in them.
|
|
948 |
|
|
949 |
@param aCodeSeg Code Segment that is removed from aProcess.
|
|
950 |
@param aProcess Process from whom the code segment is removed.
|
|
951 |
|
|
952 |
@pre Calling thread must be in the critical section
|
|
953 |
@pre CodeSeg mutex held
|
|
954 |
*/
|
|
955 |
void CodeModifier::CodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
|
|
956 |
{
|
|
957 |
if (!TheCodeModifier)
|
|
958 |
return;
|
|
959 |
TheCodeModifier->DoCodeSegRemoved(aCodeSeg, aProcess);
|
|
960 |
}
|
|
961 |
|
|
962 |
void CodeModifier::DoCodeSegRemoved(DCodeSeg* aCodeSeg, DProcess* aProcess)
|
|
963 |
{
|
|
964 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()"));
|
|
965 |
|
|
966 |
TUint oldValue;
|
|
967 |
TUint minAddr = aCodeSeg->iRunAddress;
|
|
968 |
TUint maxAddr = aCodeSeg->iRunAddress + aCodeSeg->iSize;
|
|
969 |
|
|
970 |
TBreakpoint* bp = iBreakpoints;
|
|
971 |
TBreakpoint* bpEnd = bp+iPoolSize; //points right behind iBreakpoints
|
|
972 |
for (; bp<bpEnd; ++bp)
|
|
973 |
{
|
|
974 |
if (bp->iSize == (TUint)EEmpty) continue;
|
|
975 |
|
|
976 |
if (aProcess->iId == bp->iProcessId)
|
|
977 |
{
|
|
978 |
if (bp->iAddress >= minAddr && bp->iAddress < maxAddr)
|
|
979 |
{
|
|
980 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::CodeSegRemoved()- a breakpoint"));
|
|
981 |
|
|
982 |
//Remove breakpoint. Don't examine error code as there is nobody to report to.
|
|
983 |
SafeWriteCode(aProcess, bp->iAddress, bp->iSize, bp->iOldValue, &oldValue);
|
|
984 |
|
|
985 |
//Mark the slot as empty and decrease the counter of the shadow page slot (if there is any associated)
|
|
986 |
bp->iSize = (TUint)EEmpty;
|
|
987 |
if (bp->iPageIndex >= 0)
|
|
988 |
RestorePage(bp->iPageIndex);
|
|
989 |
}
|
|
990 |
}
|
|
991 |
}
|
|
992 |
|
|
993 |
}
|
|
994 |
|
|
995 |
/*
|
|
996 |
Finds DProcess that matches to processId
|
|
997 |
@param aProcessId ProcessId
|
|
998 |
@return Pointer to matching DProcess or NULL
|
|
999 |
*/
|
|
1000 |
DProcess* CodeModifier::Process(TUint aProcessId)
|
|
1001 |
{
|
|
1002 |
TInt i;
|
|
1003 |
DProcess* process = NULL;
|
|
1004 |
DObjectCon* processCon = Kern::Containers()[EProcess];
|
|
1005 |
processCon->Wait();
|
|
1006 |
|
|
1007 |
for (i=0;i<processCon->Count();i++)
|
|
1008 |
{
|
|
1009 |
DProcess* pr = (DProcess*)(*processCon)[i];
|
|
1010 |
if (pr->iId == aProcessId)
|
|
1011 |
{
|
|
1012 |
process=(DProcess*)pr;
|
|
1013 |
break;
|
|
1014 |
}
|
|
1015 |
}
|
|
1016 |
|
|
1017 |
processCon->Signal();
|
|
1018 |
return process;
|
|
1019 |
}
|
|
1020 |
|
|
1021 |
/*
|
|
1022 |
Returns eTrue if given virtual address belongs to rom image, EFalse otherwise
|
|
1023 |
*/
|
|
1024 |
TBool CodeModifier::IsRom(TLinAddr aAddress)
|
|
1025 |
{
|
|
1026 |
TRomHeader romHeader = Epoc::RomHeader();
|
|
1027 |
if ( (aAddress >= romHeader.iRomBase ) && (aAddress < (romHeader.iRomBase + romHeader.iUncompressedSize)) )
|
|
1028 |
return ETrue;
|
|
1029 |
return EFalse;
|
|
1030 |
}
|
|
1031 |
|
|
1032 |
/*
|
|
1033 |
Finds the first available(empty) breakpoint slot.
|
|
1034 |
@return The pointer of the empty slot or NULL if all occupied.
|
|
1035 |
*/
|
|
1036 |
CodeModifier::TBreakpoint* CodeModifier::FindEmptyBrk()
|
|
1037 |
{
|
|
1038 |
TBreakpoint* bp = TheCodeModifier->iBreakpoints;
|
|
1039 |
TBreakpoint* bpEnd = bp+TheCodeModifier->iPoolSize; //points right behind iBreakpoints
|
|
1040 |
for (; bp<bpEnd; ++bp)
|
|
1041 |
if (bp->iSize == (TInt16)EEmpty)
|
|
1042 |
return bp;
|
|
1043 |
|
|
1044 |
return NULL;
|
|
1045 |
}
|
|
1046 |
|
|
1047 |
/*
|
|
1048 |
Finds matching breakpoint.
|
|
1049 |
|
|
1050 |
@param aThread The thread who's process owns the breakpoint
|
|
1051 |
@param aAddress Address of the breakpoint.
|
|
1052 |
@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).
|
|
1053 |
@param aOverlap On return, it is true if a breakpoint is found that doesn't match the size but overlaps with
|
|
1054 |
the specified breakpoint(i.e. address and process are the same but the size is different).
|
|
1055 |
|
|
1056 |
@return - The pointer to the breakpoint slot that matches the entry (adress, size and the owning process)
|
|
1057 |
- NULL - if could't find the matching breakpoint.
|
|
1058 |
*/
|
|
1059 |
CodeModifier::TBreakpoint* CodeModifier::FindBreakpoint(DThread* aThread, TLinAddr aAddress, TInt aSize, TBool& aOverlap)
|
|
1060 |
{
|
|
1061 |
TInt bytes=0;
|
|
1062 |
aOverlap = EFalse;
|
|
1063 |
TUint processId = aThread->iOwningProcess->iId;//processId of the thread that owns aThread
|
|
1064 |
|
|
1065 |
if (aSize) //if size==0, we do not check overlaps.
|
|
1066 |
bytes = ((1<<aSize)-1)<<(aAddress&3); //bits[3-0] marks the bytes that are contained in the breakpoint:
|
|
1067 |
// address: ...00b size: 1 => bytes=0001b
|
|
1068 |
// address: ...01b size: 1 => bytes=0010b
|
|
1069 |
// address: ...10b size: 1 => bytes=0100b
|
|
1070 |
// address: ...11b size: 1 => bytes=1000b
|
|
1071 |
// address: ...00b size: 2 => bytes=0011b
|
|
1072 |
// address: ...10b size: 2 => bytes=1100b
|
|
1073 |
// address: ...00b size: 4 => bytes=1111b
|
|
1074 |
|
|
1075 |
TBreakpoint* bp = TheCodeModifier->iBreakpoints;
|
|
1076 |
TBreakpoint* bpEnd = bp+TheCodeModifier->iPoolSize; //points right behind iBreakpoints
|
|
1077 |
for (; bp<bpEnd; ++bp)
|
|
1078 |
{
|
|
1079 |
if (bp->iSize == (TInt16)EEmpty || bp->iProcessId != processId)
|
|
1080 |
continue;//Either empty or not matchng process.
|
|
1081 |
|
|
1082 |
if (!aSize)
|
|
1083 |
{ //Do not check the size. If the address does not match, do not check for overlap.
|
|
1084 |
if (bp->iAddress == aAddress)
|
|
1085 |
return bp;
|
|
1086 |
else
|
|
1087 |
continue;
|
|
1088 |
}
|
|
1089 |
|
|
1090 |
if (bp->iAddress == aAddress && bp->iSize == aSize)
|
|
1091 |
return bp;//If we find a matching breakpoint, there cannot be another one that overlaps
|
|
1092 |
|
|
1093 |
//Check if bp breakpoint overlaps with the specified one.
|
|
1094 |
if ((bp->iAddress^aAddress)>>2)
|
|
1095 |
continue;//Not in the same word
|
|
1096 |
|
|
1097 |
if (((1<<bp->iSize)-1)<<(bp->iAddress&3)&bytes)
|
|
1098 |
{//Two brakpoints are within the same word with some overlaping bytes.
|
|
1099 |
aOverlap = ETrue;
|
|
1100 |
return NULL; //If we find an overlaping breakpoint, there cannot be another one that matches exactly.
|
|
1101 |
}
|
|
1102 |
}
|
|
1103 |
return NULL;
|
|
1104 |
}
|
|
1105 |
|
|
1106 |
/*
|
|
1107 |
Finds the first available(empty) page info slot.
|
|
1108 |
@return The index of the slot or KErrNotFound if all occupied.
|
|
1109 |
*/
|
|
1110 |
TInt CodeModifier::FindEmptyPageInfo()
|
|
1111 |
{
|
|
1112 |
TInt i;
|
|
1113 |
for (i=0; i<iPoolSize; i++)
|
|
1114 |
if (!iPages[i].iCounter)
|
|
1115 |
return i;
|
|
1116 |
return KErrNotFound;
|
|
1117 |
}
|
|
1118 |
|
|
1119 |
/*
|
|
1120 |
Finds the page info structure that contains given virtual address
|
|
1121 |
@return The index of the page info slot or KErrNotFound.
|
|
1122 |
*/
|
|
1123 |
TInt CodeModifier::FindPageInfo(TLinAddr aAddress)
|
|
1124 |
{
|
|
1125 |
TInt i;
|
|
1126 |
aAddress &= iPageMask; //round down to the page base address
|
|
1127 |
for (i=0; i<iPoolSize; i++)
|
|
1128 |
if(iPages[i].iCounter)
|
|
1129 |
if (iPages[i].iAddress == aAddress)
|
|
1130 |
return i;
|
|
1131 |
return KErrNotFound;
|
|
1132 |
}
|
|
1133 |
|
|
1134 |
/**
|
|
1135 |
Decrement the count of breakpoints associated with this page, and restores page
|
|
1136 |
to its original state if there are none remaining.
|
|
1137 |
*/
|
|
1138 |
void CodeModifier::RestorePage(TInt aPageIndex)
|
|
1139 |
{
|
|
1140 |
TPageInfo& page = iPages[aPageIndex];
|
|
1141 |
if(--page.iCounter==0)
|
|
1142 |
{
|
|
1143 |
if (!page.iWasShadowed)
|
|
1144 |
{
|
|
1145 |
__KTRACE_OPT(KDEBUGGER,Kern::Printf("CodeModifier::Restore() - Freeing Shadow Page"));
|
|
1146 |
Epoc::FreeShadowPage(page.iAddress);
|
|
1147 |
}
|
|
1148 |
#ifdef __DEMAND_PAGING__
|
|
1149 |
if (page.iPagingLock)
|
|
1150 |
{
|
|
1151 |
// Release lock and free resources
|
|
1152 |
delete page.iPagingLock;
|
|
1153 |
page.iPagingLock = NULL;
|
|
1154 |
}
|
|
1155 |
#endif
|
|
1156 |
}
|
|
1157 |
}
|
|
1158 |
|
|
1159 |
void CodeModifier::Fault(TPanic aPanic)
|
|
1160 |
{
|
|
1161 |
Kern::Fault("CodeModifier", aPanic);
|
|
1162 |
}
|
|
1163 |
|
|
1164 |
#else //__DEBUGGER_SUPPORT__
|
|
1165 |
EXPORT_C TInt DebugSupport::InitialiseCodeModifier(TUint& /*aCapabilities*/, TInt /*aMinBreakpoints*/)
|
|
1166 |
{
|
|
1167 |
return KErrNotSupported;
|
|
1168 |
}
|
|
1169 |
EXPORT_C void DebugSupport::CloseCodeModifier()
|
|
1170 |
{
|
|
1171 |
}
|
|
1172 |
EXPORT_C TInt DebugSupport::ModifyCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/, TInt /*aSize*/, TUint /*aValue*/, TUint /*aType*/)
|
|
1173 |
{
|
|
1174 |
return KErrNotSupported;
|
|
1175 |
}
|
|
1176 |
EXPORT_C TInt DebugSupport::RestoreCode(DThread* /*aProcess*/, TLinAddr /*aAddress*/)
|
|
1177 |
{
|
|
1178 |
return KErrNotSupported;
|
|
1179 |
}
|
|
1180 |
EXPORT_C void DebugSupport::TerminateProcess(DProcess* /*aProcess*/, const TInt /*aReason*/)
|
|
1181 |
{
|
|
1182 |
}
|
|
1183 |
#endif
|
|
1184 |
|