|
1 // Copyright (c) 1994-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\emul\win32\mprocess.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "memmodel.h" |
|
19 #include <property.h> |
|
20 #include <emulator.h> |
|
21 #include <wchar.h> |
|
22 |
|
23 #define iMState iWaitLink.iSpare1 |
|
24 |
|
25 extern const char* JustInTime; |
|
26 extern TBool DisableWSDWarning; |
|
27 const TInt KMaxWsdDllsPerProcess = 256; |
|
28 |
|
29 /******************************************** |
|
30 * Process |
|
31 ********************************************/ |
|
32 DWin32Process::DWin32Process() |
|
33 : iDllData(KMaxWsdDllsPerProcess, _FOFF(SProcessDllDataBlock,iCodeSeg)) |
|
34 { |
|
35 // Set process JustInTime flag from the emulator property. This is not set |
|
36 // for the process containing supervisor thread. |
|
37 if (JustInTime && !_stricmp(JustInTime, "none")) |
|
38 { |
|
39 iFlags &= !KProcessFlagJustInTime; |
|
40 } |
|
41 } |
|
42 |
|
43 DWin32Process::~DWin32Process() |
|
44 { |
|
45 __KTRACE_OPT(KMMU,Kern::Printf("DWin32Process destruct")); |
|
46 Destruct(); |
|
47 RemoveDllData(); |
|
48 iDllData.Close(); |
|
49 } |
|
50 |
|
51 TInt DWin32Process::NewChunk(DChunk*& aChunk, SChunkCreateInfo& aInfo, TLinAddr& aRunAddr) |
|
52 { |
|
53 aChunk=NULL; |
|
54 DWin32Chunk* pC=new DWin32Chunk; |
|
55 if (!pC) |
|
56 return KErrNoMemory; |
|
57 pC->iChunkType=aInfo.iType; |
|
58 if (!aInfo.iGlobal && (iAttributes & DWin32Process::EPrivate)!=0) |
|
59 pC->iAttributes |= DWin32Chunk::EPrivate; |
|
60 pC->iOwningProcess=(aInfo.iGlobal)?NULL:this; |
|
61 TInt r=pC->Create(aInfo); |
|
62 if (r==KErrNone && (aInfo.iOperations & SChunkCreateInfo::EAdjust)) |
|
63 { |
|
64 __ASSERT_ALWAYS(aInfo.iRunAddress==0,MM::Panic(MM::EInvalidChunkCreate)); |
|
65 if (aInfo.iPreallocated==0) |
|
66 { |
|
67 if (pC->iAttributes & DChunk::EDisconnected) |
|
68 { |
|
69 r=pC->Commit(aInfo.iInitialBottom,aInfo.iInitialTop-aInfo.iInitialBottom); |
|
70 } |
|
71 else if (pC->iAttributes & DChunk::EDoubleEnded) |
|
72 { |
|
73 r=pC->AdjustDoubleEnded(aInfo.iInitialBottom,aInfo.iInitialTop); |
|
74 } |
|
75 else |
|
76 { |
|
77 r=pC->Adjust(aInfo.iInitialTop); |
|
78 } |
|
79 } |
|
80 if (r==KErrNone) |
|
81 { |
|
82 aRunAddr=(TLinAddr)pC->Base(); |
|
83 } |
|
84 } |
|
85 if (r==KErrNone) |
|
86 { |
|
87 pC->iDestroyedDfc = aInfo.iDestroyedDfc; |
|
88 aChunk=(DChunk*)pC; |
|
89 } |
|
90 else |
|
91 pC->Close(NULL); // NULL since chunk can't have been added to process |
|
92 return r; |
|
93 } |
|
94 |
|
95 TInt DWin32Process::DoCreate(TBool aKernelProcess, TProcessCreateInfo& /*aInfo*/) |
|
96 { |
|
97 __KTRACE_OPT(KPROC,Kern::Printf("DWin32Process::DoCreate %O",this)) |
|
98 iAttributes=aKernelProcess ? ESupervisor|EPrivate : 0; |
|
99 // force iDllData to reserve KMaxWsdDllsPerProcess. The Append will |
|
100 // create the space, the Remove will not free it. |
|
101 SProcessDllDataBlock data = {0,0,0}; |
|
102 TInt err = iDllData.Append(data); |
|
103 if(err==KErrNone) |
|
104 { |
|
105 __ASSERT_ALWAYS(iDllData.Count()==1,MM::Panic(MM::EWsdBadReserve)); |
|
106 iDllData.Remove(0); |
|
107 } |
|
108 return err; |
|
109 } |
|
110 |
|
111 TInt DWin32Process::CreateDataBssStackArea(TProcessCreateInfo& /*aInfo*/) |
|
112 // |
|
113 // This is managed for us by win32 |
|
114 // |
|
115 { |
|
116 __KTRACE_OPT(KPROC,Kern::Printf("DWin32Process::CreateDataBssStackArea %O",this)); |
|
117 return KErrNone; |
|
118 } |
|
119 |
|
120 TInt DWin32Process::AddChunk(DChunk* /*aChunk*/,TBool /*isReadOnly*/) |
|
121 { |
|
122 return KErrNone; |
|
123 } |
|
124 |
|
125 |
|
126 TInt DWin32Process::NewShPool(DShPool*& aPool, TShPoolCreateInfo& aInfo) |
|
127 { |
|
128 aPool = NULL; |
|
129 DWin32ShPool* pC = NULL; |
|
130 |
|
131 if (aInfo.iInfo.iFlags & TShPoolCreateInfo::EPageAlignedBuffer) |
|
132 { |
|
133 pC = new DWin32AlignedShPool(); |
|
134 } |
|
135 else |
|
136 { |
|
137 pC = new DWin32NonAlignedShPool(); |
|
138 } |
|
139 |
|
140 if (pC == NULL) |
|
141 { |
|
142 return KErrNoMemory; |
|
143 } |
|
144 |
|
145 TInt r = pC->Create(this, aInfo); |
|
146 |
|
147 if (r == KErrNone) |
|
148 { |
|
149 aPool = pC; |
|
150 } |
|
151 else |
|
152 { |
|
153 pC->Close(NULL); |
|
154 } |
|
155 |
|
156 return r; |
|
157 } // DWin32Process::NewShPool |
|
158 |
|
159 |
|
160 void DWin32Process::Release() |
|
161 { |
|
162 CallRuntimeHook(EWin32RuntimeProcessDetach); |
|
163 DProcess::Release(); |
|
164 } |
|
165 |
|
166 void DWin32Process::FinalRelease() |
|
167 { |
|
168 } |
|
169 |
|
170 TInt DWin32Process::MapCodeSeg(DCodeSeg* aSeg) |
|
171 { |
|
172 |
|
173 __KTRACE_OPT(KDLL,Kern::Printf("Process %O MapCodeSeg(%C)", this, aSeg)); |
|
174 if (!aSeg || !aSeg->IsDll()) |
|
175 return KErrNone; |
|
176 |
|
177 DWin32CodeSeg* seg = (DWin32CodeSeg*)aSeg; |
|
178 if (seg->iRealDataSize == 0 && seg->iRealBssSize == 0) |
|
179 return KErrNone; |
|
180 |
|
181 if (!DisableWSDWarning && this!=K::TheKernelProcess) |
|
182 Kern::Printf("WARNING!!: WSD Lib Loaded- Process %O, has loaded Lib %C" |
|
183 " which has %d bytes of WSD",this,aSeg, |
|
184 seg->iRealDataSize + seg->iRealBssSize); |
|
185 |
|
186 // remove any existing copy of this code seg (should never happen) |
|
187 UnmapCodeSeg(aSeg); |
|
188 |
|
189 SProcessDllDataBlock data; |
|
190 data.iCodeSeg = seg; |
|
191 |
|
192 TInt count=0; |
|
193 TInt err = KErrNone; |
|
194 data.iDataCopy = Kern::Alloc(seg->iRealDataSize); |
|
195 data.iBssCopy = Kern::Alloc(seg->iRealBssSize); |
|
196 if (!data.iDataCopy || !data.iBssCopy) |
|
197 { |
|
198 err = KErrNoMemory; |
|
199 goto failed; |
|
200 } |
|
201 |
|
202 memcpy(data.iDataCopy, seg->iDataCopy, seg->iRealDataSize); // start with init data |
|
203 memclr(data.iBssCopy, seg->iRealBssSize); // initialized to zeros |
|
204 |
|
205 NKern::Lock(); |
|
206 count = iDllData.Count(); |
|
207 if (count == KMaxWsdDllsPerProcess) |
|
208 err = KErrOverflow; |
|
209 if (!err) |
|
210 err = iDllData.InsertInUnsignedKeyOrder(data); |
|
211 NKern::Unlock(); |
|
212 if (err) |
|
213 goto failed; |
|
214 |
|
215 return KErrNone; |
|
216 |
|
217 failed: |
|
218 Kern::Free(data.iDataCopy); |
|
219 Kern::Free(data.iBssCopy); |
|
220 |
|
221 return err; |
|
222 } |
|
223 |
|
224 void DWin32Process::UnmapCodeSeg(DCodeSeg* aSeg) |
|
225 { |
|
226 if (!aSeg || !aSeg->IsDll()) |
|
227 return; |
|
228 |
|
229 DWin32CodeSeg* seg = (DWin32CodeSeg*)aSeg; |
|
230 if (seg->iRealDataSize == 0 && seg->iRealBssSize == 0) |
|
231 return; |
|
232 |
|
233 SProcessDllDataBlock data; |
|
234 data.iCodeSeg = seg; |
|
235 NKern::Lock(); |
|
236 if (seg->iLiveProcess == this) |
|
237 seg->iLiveProcess = NULL; |
|
238 TInt ix = iDllData.FindInUnsignedKeyOrder(data); |
|
239 if (ix >= 0) |
|
240 { |
|
241 data = iDllData[ix]; |
|
242 iDllData.Remove(ix); |
|
243 } |
|
244 NKern::Unlock(); |
|
245 |
|
246 if (ix < 0) |
|
247 return; |
|
248 |
|
249 Kern::Free(data.iDataCopy); |
|
250 Kern::Free(data.iBssCopy); |
|
251 __KTRACE_OPT(KDLL,Kern::Printf("Process %O UnmapCodeSeg(%C)", this, aSeg)); |
|
252 } |
|
253 |
|
254 void DWin32Process::RemoveDllData() |
|
255 { |
|
256 // unmap all DLL data with kernel locked |
|
257 TInt count = iDllData.Count(); |
|
258 for (TInt ii=count-1; ii>=0; ii--) |
|
259 { |
|
260 SProcessDllDataBlock data = iDllData[ii]; |
|
261 NKern::Lock(); |
|
262 if (data.iCodeSeg->iLiveProcess == this) |
|
263 data.iCodeSeg->iLiveProcess = NULL; |
|
264 NKern::Unlock(); |
|
265 iDllData.Remove(ii); |
|
266 Kern::Free(data.iDataCopy); |
|
267 Kern::Free(data.iBssCopy); |
|
268 } |
|
269 } |
|
270 |
|
271 TInt DWin32Process::AttachExistingCodeSeg(TProcessCreateInfo& /*aInfo*/) |
|
272 { |
|
273 return KErrNotSupported; // never allowed |
|
274 } |
|
275 |
|
276 void DWin32Process::CallRuntimeHook(TWin32RuntimeReason aReason) |
|
277 { |
|
278 if (iWin32RuntimeHook) |
|
279 { |
|
280 SchedulerLock(); |
|
281 TBool ok = iWin32RuntimeHook(aReason); |
|
282 SchedulerUnlock(); |
|
283 if (!ok && aReason != EWin32RuntimeProcessDetach) |
|
284 Kern::PanicCurrentThread(_L("MemModel"), MM::EWin32RuntimeError); |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 void DThread::IpcExcHandler(TExcTrap* aTrap, DThread* aThread, TAny* aContext) |
|
290 { |
|
291 aThread->iIpcClient = 0; |
|
292 TIpcExcTrap& xt=*(TIpcExcTrap*)aTrap; |
|
293 TWin32ExcInfo& info=*(TWin32ExcInfo*)aContext; |
|
294 TLinAddr va=(TLinAddr)info.iExcDataAddress; |
|
295 if (va>=xt.iRemoteBase && (va-xt.iRemoteBase)<xt.iSize) |
|
296 xt.Exception(KErrBadDescriptor); // problem accessing remote address - 'leave' so an error code will be returned |
|
297 if (xt.iLocalBase && va>=xt.iLocalBase && (va-xt.iLocalBase)<xt.iSize) |
|
298 NKern::UnlockSystem(); // problem accessing local address - return and panic current thread as usual |
|
299 // otherwise return and fault kernel |
|
300 } |
|
301 |
|
302 TInt DThread::RawRead(const TAny* aSrc, TAny* aDest, TInt aLength, TInt /*aFlags*/, TIpcExcTrap* /*aExcTrap*/) |
|
303 // |
|
304 // Read from the thread's process. |
|
305 // aSrc is run address of memory to read |
|
306 // aDest is current address of destination |
|
307 // Enter and leave with system locked |
|
308 // |
|
309 { |
|
310 if (iMState==EDead) |
|
311 return KErrDied; |
|
312 const TUint8* pS=(const TUint8*)aSrc; |
|
313 TUint8* pD=(TUint8*)aDest; |
|
314 TBool kernelLocked = EFalse; |
|
315 const TUint8* pC=(const TUint8*)MM::CurrentAddress(this,pS,aLength,EFalse,kernelLocked); |
|
316 if (kernelLocked) |
|
317 { |
|
318 // kernel locked because of DLL WSD IPC, do it all in one big block |
|
319 TInt r = KErrNone; |
|
320 __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawRead %08x",pC)); |
|
321 if (!pC) |
|
322 r = KErrBadDescriptor; |
|
323 else |
|
324 memcpy(pD,pC,aLength); |
|
325 NKern::Unlock(); |
|
326 return r; |
|
327 } |
|
328 TBool check=ETrue; |
|
329 while (aLength) |
|
330 { |
|
331 if (check) |
|
332 { |
|
333 if (iMState==EDead) |
|
334 return KErrDied; |
|
335 __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::Read %08x",pS)); |
|
336 } |
|
337 TInt l=Min(aLength,K::MaxMemCopyInOneGo); |
|
338 memcpy(pD,pS,l); |
|
339 pD+=l; |
|
340 pS+=l; |
|
341 aLength-=l; |
|
342 if (aLength) |
|
343 check=NKern::FlashSystem(); |
|
344 } |
|
345 return KErrNone; |
|
346 } |
|
347 |
|
348 TInt DThread::RawWrite(const TAny* aDest, const TAny* aSrc, TInt aLength, TInt /*aFlags*/, DThread* /*anOriginatingThread*/, TIpcExcTrap* /*aExcTrap*/) |
|
349 // |
|
350 // Write to the thread's process. |
|
351 // aDest is run address of memory to write |
|
352 // aSrc is current address of destination |
|
353 // anOriginatingThread is the thread on behalf of which this operation is performed (eg client of device driver). |
|
354 // Enter and leave with system locked |
|
355 // |
|
356 { |
|
357 if (iMState==EDead) |
|
358 return KErrDied; |
|
359 TUint8* pD=(TUint8*)aDest; |
|
360 const TUint8* pS=(const TUint8*)aSrc; |
|
361 TBool kernelLocked = EFalse; |
|
362 TUint8* pC=(TUint8*)MM::CurrentAddress(this,pD,aLength,ETrue,kernelLocked); |
|
363 if (kernelLocked) |
|
364 { |
|
365 // kernel locked because of DLL WSD IPC, do it all in one big block |
|
366 TInt r = KErrNone; |
|
367 __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::RawWrite %08x",pC)); |
|
368 if (!pC) |
|
369 r = KErrBadDescriptor; |
|
370 else |
|
371 memcpy(pC,pS,aLength); |
|
372 NKern::Unlock(); |
|
373 return r; |
|
374 } |
|
375 TBool check=ETrue; |
|
376 while (aLength) |
|
377 { |
|
378 if (check) |
|
379 { |
|
380 if (iMState==EDead) |
|
381 return KErrDied; |
|
382 __KTRACE_OPT(KTHREAD2,Kern::Printf("DThread::Write %08x",pD)); |
|
383 } |
|
384 TInt l=Min(aLength,K::MaxMemCopyInOneGo); |
|
385 memcpy(pD,pS,l); |
|
386 pD+=l; |
|
387 pS+=l; |
|
388 aLength-=l; |
|
389 if (aLength) |
|
390 check=NKern::FlashSystem(); |
|
391 } |
|
392 return KErrNone; |
|
393 } |
|
394 |
|
395 TInt DThread::ReadAndParseDesHeader(const TAny* aSrc, TDesHeader& aDest) |
|
396 // |
|
397 // Read and parse the header of a remote descriptor. |
|
398 // Enter and leave with system locked. |
|
399 // |
|
400 { |
|
401 __ASSERT_SYSTEM_LOCK; |
|
402 static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0}; |
|
403 if (iMState == EDead) |
|
404 return KErrDied; |
|
405 TBool kernelLocked = EFalse; |
|
406 const TUint32* pS=(const TUint32*)MM::CurrentAddress(this,aSrc,sizeof(TDesC8),EFalse,kernelLocked); |
|
407 if (!pS || (TInt(pS)&3)!=0) |
|
408 { |
|
409 if (kernelLocked) |
|
410 NKern::Unlock(); |
|
411 return KErrBadDescriptor; |
|
412 } |
|
413 TInt type=0; |
|
414 XTRAPD(r, XT_DEFAULT, \ |
|
415 type=*pS>>KShiftDesType8; \ |
|
416 TInt l=LengthLookup[type]; \ |
|
417 if (l==0) \ |
|
418 r=KErrBadDescriptor; \ |
|
419 else \ |
|
420 wordmove(&aDest,pS,l); \ |
|
421 ); |
|
422 if (kernelLocked) |
|
423 NKern::Unlock(); |
|
424 if (r!=KErrNone) |
|
425 return r; |
|
426 return K::ParseDesHeader(aSrc, (TRawDesHeader&)aDest, aDest); |
|
427 } |
|
428 |
|
429 DChunk* DThread::OpenSharedChunk(const TAny* aAddress, TBool /*aWrite*/, TInt& aOffset) |
|
430 { |
|
431 DWin32Chunk* chunk=0; |
|
432 DObjectCon& chunks=*K::Containers[EChunk]; |
|
433 chunks.Wait(); |
|
434 TInt count=chunks.Count(); |
|
435 TInt i; |
|
436 TUint offset=0; |
|
437 for(i=0;i<count;i++) |
|
438 { |
|
439 DWin32Chunk* pC=(DWin32Chunk*)chunks[i]; |
|
440 offset = (TUint)aAddress-(TUint)pC->Base(); |
|
441 if(offset<TUint(pC->iMaxSize)) |
|
442 { |
|
443 chunk = pC; |
|
444 break; |
|
445 } |
|
446 } |
|
447 chunks.Signal(); |
|
448 |
|
449 if(!chunk) |
|
450 return 0; |
|
451 |
|
452 if((chunk->iChunkType!=ESharedKernelSingle && chunk->iChunkType!=ESharedKernelMultiple)) |
|
453 return 0; |
|
454 if(chunk->Open()!=KErrNone) |
|
455 return 0; |
|
456 aOffset = offset; |
|
457 return chunk; |
|
458 } |
|
459 |
|
460 TInt DThread::PrepareMemoryForDMA(const TAny* /*aLinAddr*/, TInt /*aSize*/, TPhysAddr* /*aPhysicalPageList*/) |
|
461 { |
|
462 return KErrNotSupported; |
|
463 } |
|
464 |
|
465 TInt DThread::ReleaseMemoryFromDMA(const TAny* /*aLinAddr*/, TInt /*aSize*/, TPhysAddr* /*aPhysicalPageList*/) |
|
466 { |
|
467 return KErrNotSupported; |
|
468 } |
|
469 |