|
1 // Copyright (c) 1997-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 // |
|
15 |
|
16 #include "arm_mem.h" |
|
17 #include "mm.h" |
|
18 #include "mmu.h" |
|
19 #include "mpager.h" |
|
20 |
|
21 #include "cache_maintenance.inl" |
|
22 #include "execs.h" |
|
23 |
|
24 |
|
25 #ifdef BROADCAST_TLB_MAINTENANCE |
|
26 class TTLBIPI : public TGenericIPI |
|
27 { |
|
28 public: |
|
29 TTLBIPI(); |
|
30 static void InvalidateIsr(TGenericIPI*); |
|
31 static void WaitAndInvalidateIsr(TGenericIPI*); |
|
32 void AddArg(TLinAddr aArg); |
|
33 public: |
|
34 volatile TInt iFlag; |
|
35 TLinAddr iArg; |
|
36 }; |
|
37 |
|
38 TTLBIPI::TTLBIPI() |
|
39 : iFlag(0), iArg(0) |
|
40 { |
|
41 } |
|
42 |
|
43 void TTLBIPI::InvalidateIsr(TGenericIPI* aPtr) |
|
44 { |
|
45 TRACE2(("TLBInv")); |
|
46 TTLBIPI& a = *(TTLBIPI*)aPtr; |
|
47 TLinAddr arg = a.iArg; |
|
48 if (arg==0) |
|
49 LocalInvalidateTLB(); |
|
50 else if (arg<256) |
|
51 LocalInvalidateTLBForAsid(arg); |
|
52 else |
|
53 LocalInvalidateTLBForPage(arg); |
|
54 } |
|
55 |
|
56 void TTLBIPI::WaitAndInvalidateIsr(TGenericIPI* aPtr) |
|
57 { |
|
58 TRACE2(("TLBWtInv")); |
|
59 TTLBIPI& a = *(TTLBIPI*)aPtr; |
|
60 while (!a.iFlag) |
|
61 { __chill(); } |
|
62 InvalidateIsr(aPtr); |
|
63 } |
|
64 |
|
65 void TTLBIPI::AddArg(TLinAddr aArg) |
|
66 { |
|
67 iArg = aArg; |
|
68 NKern::Lock(); |
|
69 InvalidateIsr(this); |
|
70 QueueAllOther(&InvalidateIsr); |
|
71 NKern::Unlock(); |
|
72 WaitCompletion(); |
|
73 } |
|
74 |
|
75 void BroadcastInvalidateTLB(TLinAddr aLinAddrAndAsid) |
|
76 { |
|
77 TTLBIPI ipi; |
|
78 ipi.AddArg(aLinAddrAndAsid); |
|
79 } |
|
80 #endif // BROADCAST_TLB_MAINTENANCE |
|
81 |
|
82 // |
|
83 // Functions for class Mmu |
|
84 // |
|
85 |
|
86 /** |
|
87 Return the physical address of the memory mapped by a Page Table Entry (PTE). |
|
88 |
|
89 @param aPte The value contained in the PTE. |
|
90 @param aPteIndex The index of the PTE within its page table. |
|
91 */ |
|
92 TPhysAddr Mmu::PtePhysAddr(TPte aPte, TUint aPteIndex) |
|
93 { |
|
94 if(aPte&KArmV6PteSmallPage) |
|
95 return aPte & KPteSmallPageAddrMask; |
|
96 if(aPte&KArmV6PteLargePage) |
|
97 return (aPte & KPteLargePageAddrMask) + (TPhysAddr(aPteIndex << KPageShift) & KLargePageMask); |
|
98 return KPhysAddrInvalid; |
|
99 } |
|
100 |
|
101 |
|
102 /** |
|
103 Return the virtual address of the page table referenced by the given |
|
104 Page Directory Entry (PDE) \a aPde. If the PDE doesn't refer to a |
|
105 page table then the null-pointer is returned. |
|
106 |
|
107 If the page table was not one allocated by the kernel then the |
|
108 results are unpredictable and may cause a system fault. |
|
109 |
|
110 @pre #MmuLock held. |
|
111 */ |
|
112 TPte* Mmu::PageTableFromPde(TPde aPde) |
|
113 { |
|
114 if((aPde&KPdePresentMask)==KArmV6PdePageTable) |
|
115 { |
|
116 SPageInfo* pi = SPageInfo::FromPhysAddr(aPde); |
|
117 return (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(aPde&(KPageMask&~KPageTableMask))); |
|
118 } |
|
119 return 0; |
|
120 } |
|
121 |
|
122 |
|
123 /** |
|
124 Perform the action of #PageTableFromPde but without the possibility of |
|
125 a system fault caused the page table not being one allocated by the kernel. |
|
126 |
|
127 @pre #MmuLock held. |
|
128 */ |
|
129 TPte* Mmu::SafePageTableFromPde(TPde aPde) |
|
130 { |
|
131 if((aPde&KPdeTypeMask)==KArmV6PdePageTable) |
|
132 { |
|
133 SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aPde&~KPageMask); |
|
134 if(pi) |
|
135 return (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(aPde&(KPageMask&~KPageTableMask))); |
|
136 } |
|
137 return 0; |
|
138 } |
|
139 |
|
140 |
|
141 /** |
|
142 Return the base phsical address of the section table referenced by the given |
|
143 Page Directory Entry (PDE) \a aPde. If the PDE doesn't refer to a |
|
144 section then KPhysAddrInvalid is returned. |
|
145 |
|
146 @pre #MmuLock held. |
|
147 */ |
|
148 TPhysAddr Mmu::SectionBaseFromPde(TPde aPde) |
|
149 { |
|
150 if(PdeMapsSection(aPde)) |
|
151 return aPde&KPdeSectionAddrMask; |
|
152 return KPhysAddrInvalid; |
|
153 } |
|
154 |
|
155 |
|
156 /** |
|
157 Return a pointer to the Page Table Entry (PTE) which maps the |
|
158 virtual address \a aAddress in the address space \a aOsAsid. |
|
159 |
|
160 If no page table exists or it was not one allocated by the kernel |
|
161 then the results are unpredictable and may cause a system fault. |
|
162 |
|
163 @pre #MmuLock held. |
|
164 */ |
|
165 TPte* Mmu::PtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid) |
|
166 { |
|
167 TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift]; |
|
168 SPageInfo* pi = SPageInfo::FromPhysAddr(pde); |
|
169 TPte* pt = (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(pde&(KPageMask&~KPageTableMask))); |
|
170 pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift); |
|
171 return pt; |
|
172 } |
|
173 |
|
174 |
|
175 /** |
|
176 Perform the action of #PtePtrFromLinAddr but without the possibility |
|
177 of a system fault. If the page table is not present or not one |
|
178 allocated by the kernel then the null-pointer is returned. |
|
179 |
|
180 @pre #MmuLock held. |
|
181 */ |
|
182 TPte* Mmu::SafePtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid) |
|
183 { |
|
184 TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift]; |
|
185 TPte* pt = SafePageTableFromPde(pde); |
|
186 if(pt) |
|
187 pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift); |
|
188 return pt; |
|
189 } |
|
190 |
|
191 |
|
192 /** |
|
193 Return the physical address for the page table whose virtual |
|
194 address is \a aPt. |
|
195 |
|
196 If the page table was not one allocated by the kernel then the |
|
197 results are unpredictable and may cause a system fault. |
|
198 |
|
199 @pre #MmuLock held. |
|
200 */ |
|
201 TPhysAddr Mmu::PageTablePhysAddr(TPte* aPt) |
|
202 { |
|
203 __NK_ASSERT_DEBUG(MmuLock::IsHeld() || PageTablesLockIsHeld()); |
|
204 |
|
205 TInt pdeIndex = ((TLinAddr)aPt)>>KChunkShift; |
|
206 TPde pde = PageDirectory(KKernelOsAsid)[pdeIndex]; |
|
207 __NK_ASSERT_DEBUG((pde&KPdePresentMask)==KArmV6PdePageTable); |
|
208 |
|
209 SPageInfo* pi = SPageInfo::FromPhysAddr(pde); |
|
210 TPte* pPte = (TPte*)(KPageTableBase+(pi->Index(true)<<KPageShift)+(pde&(KPageMask&~KPageTableMask))); |
|
211 TPte pte = pPte[(((TLinAddr)aPt)&KChunkMask)>>KPageShift]; |
|
212 __NK_ASSERT_DEBUG(pte & KArmV6PteSmallPage); |
|
213 |
|
214 return (pte&KPteSmallPageAddrMask)|(((TLinAddr)aPt)&(KPageMask&~KPageTableMask)); |
|
215 } |
|
216 |
|
217 |
|
218 /** |
|
219 Perform a page table walk to return the physical address of |
|
220 the memory mapped at virtual address \a aLinAddr in the |
|
221 address space \a aOsAsid. |
|
222 |
|
223 If the page table used was not one allocated by the kernel |
|
224 then the results are unpredictable and may cause a system fault. |
|
225 |
|
226 Use of this function should be avoided, use instead Mmu::LinearToPhysical |
|
227 which contains debug assertions for its preconditions. |
|
228 |
|
229 @pre #MmuLock held. |
|
230 */ |
|
231 TPhysAddr Mmu::UncheckedLinearToPhysical(TLinAddr aLinAddr, TInt aOsAsid) |
|
232 { |
|
233 TRACE2(("Mmu::UncheckedLinearToPhysical(%08x,%d)",aLinAddr,aOsAsid)); |
|
234 TInt pdeIndex = aLinAddr>>KChunkShift; |
|
235 TPde pde = PageDirectory(aOsAsid)[pdeIndex]; |
|
236 if ((pde&KPdePresentMask)==KArmV6PdePageTable) |
|
237 { |
|
238 SPageInfo* pi = SPageInfo::FromPhysAddr(pde); |
|
239 TPte* pPte = (TPte*)(KPageTableBase+(pi->Index(true)<<KPageShift)+(pde&(KPageMask&~KPageTableMask))); |
|
240 TPte pte = pPte[(aLinAddr&KChunkMask)>>KPageShift]; |
|
241 if (pte & KArmV6PteSmallPage) |
|
242 { |
|
243 TPhysAddr pa=(pte&KPteSmallPageAddrMask)|(aLinAddr&~KPteSmallPageAddrMask); |
|
244 __KTRACE_OPT(KMMU,Kern::Printf("Mapped with small page - returning %08x",pa)); |
|
245 return pa; |
|
246 } |
|
247 else if (pte & KArmV6PteLargePage) |
|
248 { |
|
249 TPhysAddr pa=(pte&KPteLargePageAddrMask)|(aLinAddr&~KPteLargePageAddrMask); |
|
250 __KTRACE_OPT(KMMU,Kern::Printf("Mapped with large page - returning %08x",pa)); |
|
251 return pa; |
|
252 } |
|
253 } |
|
254 else if ((pde&KPdePresentMask)==KArmV6PdeSection) |
|
255 { |
|
256 TPhysAddr pa=(pde&KPdeSectionAddrMask)|(aLinAddr&~KPdeSectionAddrMask); |
|
257 __KTRACE_OPT(KMMU,Kern::Printf("Mapped with section - returning %08x",pa)); |
|
258 return pa; |
|
259 } |
|
260 return KPhysAddrInvalid; |
|
261 } |
|
262 |
|
263 |
|
264 extern TUint32 TTCR(); |
|
265 extern TUint32 CPUID(TInt /*aRegNum*/); |
|
266 |
|
267 |
|
268 void Mmu::Init1() |
|
269 { |
|
270 TRACEB(("Mmu::Init1")); |
|
271 |
|
272 // check page local/global page directory split is correct... |
|
273 __NK_ASSERT_ALWAYS(TTCR()==1); |
|
274 |
|
275 // check cache type is supported and consistent with compile time macros... |
|
276 TInt iColourCount = 0; |
|
277 TInt dColourCount = 0; |
|
278 TUint32 ctr = InternalCache::TypeRegister(); |
|
279 TRACEB(("CacheTypeRegister = %08x",ctr)); |
|
280 #ifdef __CPU_ARMV6 |
|
281 __NK_ASSERT_ALWAYS((ctr>>29)==0); // check ARMv6 format |
|
282 if(ctr&0x800) |
|
283 iColourCount = 4; |
|
284 if(ctr&0x800000) |
|
285 dColourCount = 4; |
|
286 #else |
|
287 __NK_ASSERT_ALWAYS((ctr>>29)==4); // check ARMv7 format |
|
288 TUint l1ip = (ctr>>14)&3; // L1 instruction cache indexing and tagging policy |
|
289 __NK_ASSERT_ALWAYS(l1ip>=2); // check I cache is physically tagged |
|
290 |
|
291 TUint32 clidr = InternalCache::LevelIDRegister(); |
|
292 TRACEB(("CacheLevelIDRegister = %08x",clidr)); |
|
293 TUint l1type = clidr&7; |
|
294 if(l1type) |
|
295 { |
|
296 if(l1type==2 || l1type==3 || l1type==4) |
|
297 { |
|
298 // we have an L1 data cache... |
|
299 TUint32 csir = InternalCache::SizeIdRegister(0,0); |
|
300 TUint sets = ((csir>>13)&0x7fff)+1; |
|
301 TUint ways = ((csir>>3)&0x3ff)+1; |
|
302 TUint lineSizeShift = (csir&7)+4; |
|
303 // assume L1 data cache is VIPT and alias checks broken and so we need data cache colouring... |
|
304 dColourCount = (sets<<lineSizeShift)>>KPageShift; |
|
305 if(l1type==4) // unified cache, so set instruction cache colour as well... |
|
306 iColourCount = (sets<<lineSizeShift)>>KPageShift; |
|
307 TRACEB(("L1DCache = 0x%x,0x%x,%d colourCount=%d",sets,ways,lineSizeShift,(sets<<lineSizeShift)>>KPageShift)); |
|
308 } |
|
309 |
|
310 if(l1type==1 || l1type==3) |
|
311 { |
|
312 // we have a separate L1 instruction cache... |
|
313 TUint32 csir = InternalCache::SizeIdRegister(1,0); |
|
314 TUint sets = ((csir>>13)&0x7fff)+1; |
|
315 TUint ways = ((csir>>3)&0x3ff)+1; |
|
316 TUint lineSizeShift = (csir&7)+4; |
|
317 iColourCount = (sets<<lineSizeShift)>>KPageShift; |
|
318 TRACEB(("L1ICache = 0x%x,0x%x,%d colourCount=%d",sets,ways,lineSizeShift,(sets<<lineSizeShift)>>KPageShift)); |
|
319 } |
|
320 } |
|
321 if(l1ip==3) |
|
322 { |
|
323 // PIPT cache, so no colouring restrictions... |
|
324 TRACEB(("L1ICache is PIPT")); |
|
325 iColourCount = 0; |
|
326 } |
|
327 else |
|
328 { |
|
329 // VIPT cache... |
|
330 TRACEB(("L1ICache is VIPT")); |
|
331 } |
|
332 #endif |
|
333 TRACEB(("page colouring counts I=%d, D=%d",iColourCount,dColourCount)); |
|
334 __NK_ASSERT_ALWAYS(iColourCount<=KPageColourCount); |
|
335 __NK_ASSERT_ALWAYS(dColourCount<=KPageColourCount); |
|
336 #ifndef __CPU_I_CACHE_HAS_COLOUR |
|
337 __NK_ASSERT_ALWAYS(iColourCount==0); |
|
338 #endif |
|
339 #ifndef __CPU_D_CACHE_HAS_COLOUR |
|
340 __NK_ASSERT_ALWAYS(dColourCount==0); |
|
341 #endif |
|
342 #ifndef __CPU_CACHE_HAS_COLOUR |
|
343 __NK_ASSERT_ALWAYS(iColourCount==0); |
|
344 __NK_ASSERT_ALWAYS(dColourCount==0); |
|
345 #endif |
|
346 |
|
347 // check MMU attributes match our assumptions... |
|
348 if(((CPUID(-1)>>16)&0xf)==0xf) // if have new CPUID format.... |
|
349 { |
|
350 TUint mmfr1 = CPUID(5); |
|
351 TRACEB(("mmfr1 = %08x",mmfr1)); |
|
352 #ifdef __CPU_NEEDS_BTAC_FLUSH_AFTER_ASID_CHANGE |
|
353 __NK_ASSERT_ALWAYS(((mmfr1>>28)&0xf)==1); // Branch Predictor needs invalidating after ASID change |
|
354 #else |
|
355 __NK_ASSERT_ALWAYS(((mmfr1>>28)&0xf)>=2); // Branch Predictor doesn't needs invalidating after ASID change |
|
356 #endif |
|
357 |
|
358 TUint mmfr2 = CPUID(6); |
|
359 TRACEB(("mmfr2 = %08x",mmfr2)); |
|
360 __NK_ASSERT_ALWAYS(((mmfr2>>20)&0xf)>=2); // check Mem Barrier instructions are supported in CP15 |
|
361 |
|
362 TUint mmfr3 = CPUID(7); |
|
363 TRACEB(("mmfr3 = %08x",mmfr3)); |
|
364 (void)mmfr3; |
|
365 |
|
366 #if defined(__SMP__) && !defined(__CPU_ARM11MP__) |
|
367 __NK_ASSERT_ALWAYS(((mmfr3>>12)&0xf)>=2); // check Maintenance Broadcast is for all cache and TLB operations |
|
368 #endif |
|
369 #ifdef __CPU_SUPPORTS_PAGE_TABLE_WALK_TO_L1_CACHE |
|
370 __NK_ASSERT_ALWAYS(((mmfr3>>20)&0xf)>=1); // check Coherent Walk for page tables |
|
371 #endif |
|
372 } |
|
373 |
|
374 Arm::DefaultDomainAccess = KDefaultDomainAccess; |
|
375 |
|
376 #ifdef __SMP__ |
|
377 TInt i; |
|
378 for (i=0; i<KMaxCpus; ++i) |
|
379 { |
|
380 TSubScheduler& ss = TheSubSchedulers[i]; |
|
381 TLinAddr a = KIPCAlias + (i<<KChunkShift); |
|
382 ss.i_AliasLinAddr = (TAny*)a; |
|
383 ss.i_AliasPdePtr = (TAny*)(KPageDirectoryBase + (a>>KChunkShift)*sizeof(TPde)); |
|
384 } |
|
385 #endif |
|
386 |
|
387 Init1Common(); |
|
388 } |
|
389 |
|
390 void Mmu::Init2() |
|
391 { |
|
392 TRACEB(("Mmu::Init2")); |
|
393 |
|
394 Init2Common(); |
|
395 } |
|
396 |
|
397 DMemoryObject* ExceptionStacks; |
|
398 |
|
399 void Mmu::Init2Final() |
|
400 { |
|
401 TRACEB(("Mmu::Init2Final")); |
|
402 |
|
403 Init2FinalCommon(); |
|
404 |
|
405 // initialise memory object for exception stacks... |
|
406 TMappingCreateFlags mapFlags = (TMappingCreateFlags)(EMappingCreateFixedVirtual|EMappingCreateReserveAllResources); |
|
407 TMemoryAttributes memAttr = EMemoryAttributeStandard; |
|
408 TUint size = 4*2*KPageSize; // 4 exception stacks each of one guard page and one mapped page |
|
409 size |= 1; // lower bit of size is set if region to be claimed contains gaps |
|
410 TInt r = MM::InitFixedKernelMemory(ExceptionStacks, KExcptStacksLinearBase, KExcptStacksLinearEnd, size, EMemoryObjectUnpaged, EMemoryCreateNoWipe, memAttr, mapFlags); |
|
411 __NK_ASSERT_ALWAYS(r==KErrNone); |
|
412 } |
|
413 |
|
414 |
|
415 /** |
|
416 Return the page directory entry (PDE) value to use for when mapping page tables intended |
|
417 to map memory with the given attributes. |
|
418 The returned value has the physical address component being zero, so a page table's physical |
|
419 address can be simply ORed in. |
|
420 */ |
|
421 TPde Mmu::BlankPde(TMemoryAttributes aAttributes) |
|
422 { |
|
423 TPde pde = KArmV6PdePageTable; |
|
424 if(aAttributes&EMemoryAttributeUseECC) |
|
425 pde |= 1<<9; |
|
426 |
|
427 TRACE2(("Mmu::BlankPde(%x) returns 0x%x",aAttributes,pde)); |
|
428 return pde; |
|
429 } |
|
430 |
|
431 |
|
432 /** |
|
433 Return the page directory entry (PDE) value to use for when creating a section mapping for memory |
|
434 with the given attributes and #TPteType. |
|
435 The returned value has the physical address component being zero, so the section's physical address |
|
436 can be simply ORed in. |
|
437 */ |
|
438 TPde Mmu::BlankSectionPde(TMemoryAttributes aAttributes, TUint aPteType) |
|
439 { |
|
440 // reuse existing functions rather than duplicating the logic |
|
441 TPde pde = BlankPde(aAttributes); |
|
442 TPde pte = BlankPte(aAttributes, aPteType); |
|
443 return PageToSectionEntry(pte, pde); |
|
444 } |
|
445 |
|
446 |
|
447 /** |
|
448 Return the page table entry (PTE) to use when mapping memory pages |
|
449 with the given attributes and #TPteType. |
|
450 This value has the physical address component being zero, so a page's physical |
|
451 address can be simply ORed in. |
|
452 */ |
|
453 |
|
454 TPte Mmu::BlankPte(TMemoryAttributes aAttributes, TUint aPteType) |
|
455 { |
|
456 TUint attr = CanonicalMemoryAttributes(aAttributes); |
|
457 |
|
458 // common PTE setup... |
|
459 TPte pte = KArmV6PteSmallPage|KArmV6PteAP0; |
|
460 if(aPteType&EPteTypeUserAccess) |
|
461 pte |= KArmV6PteAP1; // AP1 = user access |
|
462 if((aPteType&EPteTypeWritable)==false) |
|
463 pte |= KArmV6PteAP2; // AP2 = !writable |
|
464 if(attr&EMemoryAttributeShareable) |
|
465 pte |= KArmV6PteS; |
|
466 if((aPteType&EPteTypeGlobal)==false) |
|
467 pte |= KArmV6PteNG; |
|
468 if((aPteType&EPteTypeExecutable)==false) |
|
469 pte |= KArmV6PteSmallXN; |
|
470 |
|
471 #if defined(__CPU_MEMORY_TYPE_REMAPPING) |
|
472 |
|
473 // other PTE bits... |
|
474 if(pte&KArmV6PteSmallXN) |
|
475 pte |= KArmV6PteSmallTEX1; // TEX1 is a copy of the XN |
|
476 |
|
477 // process memory type... |
|
478 TUint type = attr&EMemoryAttributeTypeMask; |
|
479 pte |= ((type&3)<<2) | ((type&4)<<4); |
|
480 |
|
481 #else |
|
482 |
|
483 // other PTE bits... |
|
484 if((pte&(KArmV6PteAP2|KArmV6PteAP1))==(KArmV6PteAP2|KArmV6PteAP1)) |
|
485 pte &= ~KArmV6PteAP0; // clear AP0 if user r/o |
|
486 |
|
487 // process memory type... |
|
488 TUint texcb; |
|
489 switch((TMemoryType)(attr&EMemoryAttributeTypeMask)) |
|
490 { |
|
491 case EMemAttStronglyOrdered: |
|
492 texcb = KArmV6MemAttSO; |
|
493 break; |
|
494 case EMemAttDevice: |
|
495 if(attr&EMemoryAttributeShareable) |
|
496 texcb = KArmV6MemAttSD; |
|
497 else |
|
498 texcb = KArmV6MemAttSD; // should be KArmV6MemAttNSD? (but this made H4 go bang) |
|
499 break; |
|
500 case EMemAttNormalUncached: |
|
501 texcb = KArmV6MemAttNCNC; |
|
502 break; |
|
503 case EMemAttNormalCached: |
|
504 texcb = KArmV6MemAttWBWAWBWA; |
|
505 break; |
|
506 default: |
|
507 __NK_ASSERT_ALWAYS(0); // undefined memory type |
|
508 texcb = KArmV6MemAttSO; |
|
509 break; |
|
510 } |
|
511 pte |= ((texcb&0x1c)<<4) | ((texcb&0x03)<<2); |
|
512 |
|
513 #endif |
|
514 |
|
515 TRACE2(("Mmu::BlankPte(%x,%x) returns 0x%x",aAttributes,aPteType,pte)); |
|
516 return pte; |
|
517 } |
|
518 |
|
519 |
|
520 /** |
|
521 Calculate PDE and PTE which represent a page table mapping for an existing |
|
522 section mapping. |
|
523 |
|
524 @param[in] aPde The PDE for the existing section mapping. |
|
525 @param[out] aPde A PDE for a page table mapping, with physical address == 0. |
|
526 |
|
527 @return The PTE value for the first entry in the page table. |
|
528 */ |
|
529 TPte Mmu::SectionToPageEntry(TPde& aPde) |
|
530 { |
|
531 TPde pde = aPde; |
|
532 |
|
533 // calculate new PTE... |
|
534 TPte pte = pde&0xc; // copy CB bits |
|
535 if(pde&KArmV6PdeSectionXN) |
|
536 pte |= KArmV6PteSmallXN; // copy XN bit |
|
537 pte |= (pde&(0xff<<10))>>6; // copy NG, S, APX, TEX, AP bits |
|
538 pte |= KArmV6PteSmallPage; |
|
539 |
|
540 // calculate new PDE... |
|
541 pde &= 0x3e0; // keep IMP and DOMAIN |
|
542 pde |= KArmV6PdePageTable; |
|
543 |
|
544 aPde = pde; |
|
545 return pte; |
|
546 } |
|
547 |
|
548 |
|
549 /** |
|
550 Calculate a PDE entry which represents a section mapping for an existing |
|
551 page table mapping. |
|
552 |
|
553 @pre The existing page table contains mappings for a chunk sized and |
|
554 aligned contiguous region. |
|
555 |
|
556 @param aPte A PTE from the existing page table. |
|
557 @param aPde The existing PDE for the page table mappings. |
|
558 (Physical address portion is ignored.) |
|
559 |
|
560 @return A PDE entry value for a section mapping. |
|
561 */ |
|
562 TPde Mmu::PageToSectionEntry(TPte aPte, TPde aPde) |
|
563 { |
|
564 TPde pde = aPde&0x3e0; // keep IMP and DOMAIN |
|
565 pde |= aPte&(KPdeSectionAddrMask|0xc); // copy address and CB bits |
|
566 if(aPte&KArmV6PteSmallXN) |
|
567 pde |= KArmV6PdeSectionXN; // copy XN bit |
|
568 pde |= (aPte&(0xff<<4))<<6; // copy NG, S, APX, TEX, AP bits |
|
569 pde |= KArmV6PdeSection; |
|
570 return pde; |
|
571 } |
|
572 |
|
573 |
|
574 /** |
|
575 Tranform the specified memory attributes into the canonical form relevant to |
|
576 the platform the code is running on. This applies defaults and overrides to |
|
577 the attributes to return what should be used with the MMU. |
|
578 */ |
|
579 TMemoryAttributes Mmu::CanonicalMemoryAttributes(TMemoryAttributes aAttr) |
|
580 { |
|
581 TUint attr = aAttr; |
|
582 if(attr&EMemoryAttributeDefaultShareable) |
|
583 { |
|
584 // sharing not specified, use default... |
|
585 #if defined (__CPU_USE_SHARED_MEMORY) |
|
586 attr |= EMemoryAttributeShareable; |
|
587 #else |
|
588 attr &= ~EMemoryAttributeShareable; |
|
589 #endif |
|
590 } |
|
591 |
|
592 #if defined(FAULTY_NONSHARED_DEVICE_MEMORY) |
|
593 if((attr&(EMemoryAttributeShareable|EMemoryAttributeTypeMask))==EMemoryAttributeDevice) |
|
594 { |
|
595 // make unshared device memory into shared strongly ordered memory... |
|
596 attr ^= EMemoryAttributeShareable; |
|
597 attr ^= EMemoryAttributeDevice^EMemoryAttributeStronglyOrdered; |
|
598 } |
|
599 #endif |
|
600 |
|
601 #if defined(__SMP__) || defined(__CPU_FORCE_SHARED_MEMORY_IF_CACHED) |
|
602 TMemoryType type = (TMemoryType)(attr&KMemoryTypeMask); |
|
603 if(CacheMaintenance::IsCached(type)) |
|
604 { |
|
605 // force cached memory to be shared memory on SMP systems... |
|
606 attr |= EMemoryAttributeShareable; |
|
607 } |
|
608 #endif |
|
609 |
|
610 return (TMemoryAttributes)(attr&EMemoryAttributeMask); |
|
611 } |
|
612 |
|
613 /** |
|
614 Method called to initialise RAM pages when they are allocated for a new use. |
|
615 This performs any cache synchronisation required to remove old entries |
|
616 and also wipes the contents of the memory (if requested via \a aFlags). |
|
617 |
|
618 @param aPageList Pointer to a list of physical addresses for the RAM pages, |
|
619 or, if the least significant bit of this value is set, then |
|
620 the rest of the value is the physical address of a contiguous |
|
621 region of RAM pages being allocated. |
|
622 |
|
623 @param aCount The number of pages. |
|
624 |
|
625 @param aFlags A set of flag values from #TRamAllocFlags which indicate |
|
626 the memory type the pages will be used for and whether |
|
627 the contents should be wiped. |
|
628 |
|
629 @param aReallocate True, if the RAM pages have already been previously allocated |
|
630 and are being reinitilised e.g. by DMemoryManager::ReAllocDecommitted. |
|
631 False, to indicate that these pages have been newly allocated (are in |
|
632 the SPageInfo::EUnused state.) |
|
633 |
|
634 @pre #RamAllocLock held. |
|
635 */ |
|
636 void Mmu::PagesAllocated(TPhysAddr* aPageList, TUint aCount, TRamAllocFlags aFlags, TBool aReallocate) |
|
637 { |
|
638 TRACE2(("Mmu::PagesAllocated(0x%08x,%d,0x%x,%d)",aPageList, aCount, aFlags, (bool)aReallocate)); |
|
639 __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); |
|
640 |
|
641 TBool wipe = !(aFlags&EAllocNoWipe); // do we need to wipe page contents? |
|
642 TUint8 wipeByte = (aFlags&EAllocUseCustomWipeByte) ? (aFlags>>EAllocWipeByteShift)&0xff : 0x03; // value to wipe memory with |
|
643 |
|
644 // process each page in turn... |
|
645 while(aCount--) |
|
646 { |
|
647 // get physical address of next page... |
|
648 TPhysAddr pagePhys; |
|
649 if((TPhysAddr)aPageList&1) |
|
650 { |
|
651 // aPageList is actually the physical address to use... |
|
652 pagePhys = (TPhysAddr)aPageList&~1; |
|
653 *(TPhysAddr*)&aPageList += KPageSize; |
|
654 } |
|
655 else |
|
656 pagePhys = *aPageList++; |
|
657 __NK_ASSERT_DEBUG((pagePhys&KPageMask)==0); |
|
658 |
|
659 // get info about page... |
|
660 SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys); |
|
661 TMemoryType oldType = (TMemoryType)(pi->Flags(true)&KMemoryTypeMask); |
|
662 TBool oldTypeNormal = CacheMaintenance::IsNormal(oldType); |
|
663 |
|
664 TRACE2(("Mmu::PagesAllocated page=0x%08x, oldType=%d, wipe=%d, colour=%d",pagePhys,oldType,wipe,pi->Index(true)&KPageColourMask)); |
|
665 if(wipe || oldTypeNormal) |
|
666 { |
|
667 // work out temporary mapping values... |
|
668 TUint colour = pi->Index(true)&KPageColourMask; |
|
669 TLinAddr tempLinAddr = iTempMap[0].iLinAddr+colour*KPageSize; |
|
670 TPte* tempPte = iTempMap[0].iPtePtr+colour; |
|
671 |
|
672 if(oldTypeNormal) |
|
673 { |
|
674 // cache maintenance required. Prepare temporary mapping. |
|
675 *tempPte = pagePhys | iTempPteCacheMaintenance; |
|
676 CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte); |
|
677 InvalidateTLBForPage(tempLinAddr|KKernelOsAsid); |
|
678 |
|
679 // will hold additional arguments in CacheMaintenance::PageToReuse call |
|
680 TInt pageToReuseMask = 0; |
|
681 |
|
682 // check if old and new mappings are the same. (Wiping needs temporary |
|
683 // mapping which may not be the same as the old and new mapping.) |
|
684 TMemoryType newType = (TMemoryType)(aFlags&KMemoryTypeMask); // memory type that pages will be used for |
|
685 if (!wipe && (newType ==oldType)) |
|
686 pageToReuseMask |= CacheMaintenance::EOldAndNewMappingMatch; |
|
687 |
|
688 MmuLock::Lock(); |
|
689 |
|
690 // decide wether to trigger maintenance of entire cache(s). |
|
691 if(CacheMaintenance::IsPageToReuseThresholdReached(iCacheInvalidatePageCount)) |
|
692 { |
|
693 // enough pages to make it worth triggering maintenance of entire cache(s) |
|
694 pageToReuseMask |= CacheMaintenance::EThresholdReached; |
|
695 ++iCacheInvalidateCounter; |
|
696 iCacheInvalidatePageCount = 0; // all pages will be partially synced |
|
697 } |
|
698 |
|
699 if(CacheMaintenance::IsCached(oldType) && !aReallocate) |
|
700 { |
|
701 if(pi->CacheInvalidateCounter()==(TUint32)iCacheInvalidateCounter) |
|
702 { |
|
703 // one less unused page in the L1 cache... |
|
704 __NK_ASSERT_DEBUG(iCacheInvalidatePageCount); |
|
705 --iCacheInvalidatePageCount; |
|
706 } |
|
707 else |
|
708 { |
|
709 // our page has been already partially maintained in cache |
|
710 // by a previous PageToReuse call. |
|
711 pageToReuseMask |= CacheMaintenance::EPageHasBeenPartiallySynced; |
|
712 } |
|
713 } |
|
714 |
|
715 MmuLock::Unlock(); |
|
716 |
|
717 TBool pageRemovedFromCache = CacheMaintenance::PageToReuse(tempLinAddr, oldType, pagePhys, pageToReuseMask); |
|
718 if(pageRemovedFromCache && !aReallocate) |
|
719 pi->SetUncached(); |
|
720 } |
|
721 |
|
722 if(wipe) |
|
723 { |
|
724 //We need uncached normal temporary mapping to wipe. Change it if necessary. |
|
725 //or , in case of !oldTypeNormal it is not configured yet. |
|
726 if (!oldTypeNormal || (CacheMaintenance::TemporaryMapping()!=EMemAttNormalUncached)) |
|
727 { |
|
728 *tempPte = pagePhys | iTempPteUncached; |
|
729 CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte); |
|
730 InvalidateTLBForPage(tempLinAddr|KKernelOsAsid); |
|
731 } |
|
732 // wipe contents of memory... |
|
733 memset((TAny*)tempLinAddr, wipeByte, KPageSize); |
|
734 CacheMaintenance::PageToReuse(tempLinAddr, EMemAttNormalUncached, pagePhys); |
|
735 } |
|
736 |
|
737 // invalidate temporary mapping... |
|
738 *tempPte = KPteUnallocatedEntry; |
|
739 CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte); |
|
740 InvalidateTLBForPage(tempLinAddr|KKernelOsAsid); |
|
741 } |
|
742 |
|
743 // indicate page has been allocated... |
|
744 if(!aReallocate) |
|
745 pi->SetAllocated(); |
|
746 |
|
747 // loop round for next page... |
|
748 } // end of while(aCount--) |
|
749 } |
|
750 |
|
751 |
|
752 /** |
|
753 Method called to update the state of a RAM page when it is freed. |
|
754 This sets the page state to SPageInfo::EUnused. |
|
755 |
|
756 @param aPageInfo The page information structure for the RAM page. |
|
757 |
|
758 @pre #MmuLock held. |
|
759 */ |
|
760 void Mmu::PageFreed(SPageInfo* aPageInfo) |
|
761 { |
|
762 __NK_ASSERT_DEBUG(MmuLock::IsHeld()); |
|
763 |
|
764 if(aPageInfo->Type()==SPageInfo::EUnused) |
|
765 return; |
|
766 |
|
767 aPageInfo->SetUnused(); |
|
768 |
|
769 TMemoryType type = (TMemoryType)(aPageInfo->Flags()&KMemoryTypeMask); |
|
770 if(CacheMaintenance::IsCached(type)) |
|
771 { |
|
772 // another unused page with L1 cache entries... |
|
773 aPageInfo->SetCacheInvalidateCounter(iCacheInvalidateCounter); |
|
774 ++iCacheInvalidatePageCount; |
|
775 } |
|
776 |
|
777 TRACE2(("Mmu::PageFreed page=0x%08x type=%d colour=%d",aPageInfo->PhysAddr(),aPageInfo->Flags()&KMemoryTypeMask,aPageInfo->Index()&KPageColourMask)); |
|
778 } |
|
779 |
|
780 /** |
|
781 Remove the contents of RAM pages from any memory caches. |
|
782 |
|
783 @param aPages Pointer to a list of physical addresses for the RAM pages, |
|
784 or, if the least significant bit of this value is set, then |
|
785 the rest of the value is the physical address of a contiguous |
|
786 region of RAM pages. |
|
787 |
|
788 @param aCount The number of pages. |
|
789 |
|
790 @param aAttributes The memory attributes of the pages. |
|
791 |
|
792 @param aColour The colour for the first page; |
|
793 consecutive pages will be coloured accordingly. |
|
794 Only #KPageColourShift least significant bits are used, |
|
795 therefore an index into a memory object's memory can be |
|
796 used for this value. |
|
797 */ |
|
798 void Mmu::CleanAndInvalidatePages(TPhysAddr* aPages, TUint aCount, TMemoryAttributes aAttributes, TUint aColour) |
|
799 { |
|
800 TMemoryType type = (TMemoryType)(aAttributes&EMemoryAttributeTypeMask); |
|
801 |
|
802 if(!CacheMaintenance::IsNormal(type)) |
|
803 { |
|
804 TRACE2(("Mmu::CleanAndInvalidatePages - nothing to do")); |
|
805 return; |
|
806 } |
|
807 |
|
808 RamAllocLock::Lock(); |
|
809 |
|
810 while(aCount--) |
|
811 { |
|
812 TPhysAddr pagePhys = *aPages++; |
|
813 TRACE2(("Mmu::CleanAndInvalidatePages 0x%08x",pagePhys)); |
|
814 |
|
815 // work out temporary mapping values... |
|
816 aColour &= KPageColourMask; |
|
817 TLinAddr tempLinAddr = iTempMap[0].iLinAddr+aColour*KPageSize; |
|
818 TPte* tempPte = iTempMap[0].iPtePtr+aColour; |
|
819 ++aColour; |
|
820 |
|
821 // temporarily map page... |
|
822 *tempPte = pagePhys | iTempPteCacheMaintenance; |
|
823 CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte); |
|
824 InvalidateTLBForPage(tempLinAddr|KKernelOsAsid); |
|
825 |
|
826 // preserve memory content and remove from cache... |
|
827 CacheMaintenance::PageToPreserveAndReuse(tempLinAddr, type, pagePhys); |
|
828 |
|
829 // invalidate temporary mapping... |
|
830 *tempPte = KPteUnallocatedEntry; |
|
831 CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte); |
|
832 InvalidateTLBForPage(tempLinAddr|KKernelOsAsid); |
|
833 |
|
834 RamAllocLock::Flash(); |
|
835 } |
|
836 RamAllocLock::Unlock(); |
|
837 } |
|
838 |
|
839 |
|
840 extern void UnlockIPCAlias(); |
|
841 extern void LockIPCAlias(); |
|
842 |
|
843 |
|
844 TInt DMemModelThread::Alias(TLinAddr aAddr, DMemModelProcess* aProcess, TInt aSize, TLinAddr& aAliasAddr, TUint& aAliasSize) |
|
845 // |
|
846 // Set up an alias mapping starting at address aAddr in specified process. |
|
847 // Note: Alias is removed if an exception is trapped by DThread::IpcExcHandler. |
|
848 // |
|
849 { |
|
850 TRACE2(("Thread %O Alias %08x+%x Process %O",this,aAddr,aSize,aProcess)); |
|
851 __NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false |
|
852 // If there is an existing alias it should be on the same process otherwise |
|
853 // the os asid reference may be leaked. |
|
854 __NK_ASSERT_DEBUG(!iAliasLinAddr || aProcess == iAliasProcess); |
|
855 |
|
856 if(TUint(aAddr^KIPCAlias)<TUint(KIPCAliasAreaSize)) |
|
857 return KErrBadDescriptor; // prevent access to alias region |
|
858 |
|
859 // Grab the mmu lock before opening a reference on os asid so that this thread |
|
860 // is in an implicit critical section and therefore can't leak the reference by |
|
861 // dying before iAliasLinAddr is set. |
|
862 MmuLock::Lock(); |
|
863 |
|
864 TInt osAsid; |
|
865 if (!iAliasLinAddr) |
|
866 {// There isn't any existing alias. |
|
867 // Open a reference on the aProcess's os asid so that it is not freed and/or reused |
|
868 // while we are aliasing an address belonging to it. |
|
869 osAsid = aProcess->TryOpenOsAsid(); |
|
870 if (osAsid < 0) |
|
871 {// Couldn't open os asid so aProcess is no longer running. |
|
872 MmuLock::Unlock(); |
|
873 return KErrBadDescriptor; |
|
874 } |
|
875 } |
|
876 else |
|
877 { |
|
878 // Just read the os asid of the process being aliased we already have a reference on it. |
|
879 osAsid = aProcess->OsAsid(); |
|
880 } |
|
881 |
|
882 // Now we have the os asid check access to kernel memory. |
|
883 if(aAddr >= KUserMemoryLimit && osAsid != (TUint)KKernelOsAsid) |
|
884 { |
|
885 if (!iAliasLinAddr) |
|
886 {// Close the new reference as RemoveAlias won't do as iAliasLinAddr is not set. |
|
887 aProcess->AsyncCloseOsAsid(); |
|
888 } |
|
889 MmuLock::Unlock(); |
|
890 return KErrBadDescriptor; // prevent access to supervisor only memory |
|
891 } |
|
892 |
|
893 // Now we know all accesses to global memory are safe so check if aAddr is global. |
|
894 if(aAddr >= KGlobalMemoryBase) |
|
895 { |
|
896 // address is in global section, don't bother aliasing it... |
|
897 if (!iAliasLinAddr) |
|
898 {// Close the new reference as not required. |
|
899 aProcess->AsyncCloseOsAsid(); |
|
900 } |
|
901 else |
|
902 {// Remove the existing alias as it is not required. |
|
903 DoRemoveAlias(iAliasLinAddr); |
|
904 } |
|
905 MmuLock::Unlock(); |
|
906 aAliasAddr = aAddr; |
|
907 TInt maxSize = KChunkSize-(aAddr&KChunkMask); |
|
908 aAliasSize = aSize<maxSize ? aSize : maxSize; |
|
909 TRACE2(("DMemModelThread::Alias() abandoned as memory is globally mapped")); |
|
910 return KErrNone; |
|
911 } |
|
912 |
|
913 TPde* pd = Mmu::PageDirectory(osAsid); |
|
914 TInt pdeIndex = aAddr>>KChunkShift; |
|
915 TPde pde = pd[pdeIndex]; |
|
916 pde = (pde&~(0xf<<5))|(KIPCAliasDomain<<5); // change domain for PDE |
|
917 // Get os asid, this is the current thread's process so no need for reference. |
|
918 TUint32 local_asid = ((DMemModelProcess*)iOwningProcess)->OsAsid(); |
|
919 #ifdef __SMP__ |
|
920 TLinAddr aliasAddr; |
|
921 #else |
|
922 TLinAddr aliasAddr = KIPCAlias+(aAddr&(KChunkMask & ~KPageMask)); |
|
923 #endif |
|
924 if(pde==iAliasPde && iAliasLinAddr) |
|
925 { |
|
926 // pde already aliased, so just update linear address... |
|
927 #ifdef __SMP__ |
|
928 __NK_ASSERT_DEBUG(iCpuRestoreCookie>=0); |
|
929 aliasAddr = iAliasLinAddr & ~KChunkMask; |
|
930 aliasAddr |= (aAddr & (KChunkMask & ~KPageMask)); |
|
931 #endif |
|
932 iAliasLinAddr = aliasAddr; |
|
933 } |
|
934 else |
|
935 { |
|
936 // alias PDE changed... |
|
937 if(!iAliasLinAddr) |
|
938 { |
|
939 UnlockIPCAlias(); |
|
940 TheMmu.iAliasList.Add(&iAliasLink); // add to list if not already aliased |
|
941 #ifdef __SMP__ |
|
942 __NK_ASSERT_DEBUG(iCpuRestoreCookie==-1); |
|
943 iCpuRestoreCookie = NKern::FreezeCpu(); // temporarily lock current thread to this processor |
|
944 #endif |
|
945 } |
|
946 iAliasPde = pde; |
|
947 iAliasProcess = aProcess; |
|
948 #ifdef __SMP__ |
|
949 TSubScheduler& ss = SubScheduler(); // OK since we are locked to this CPU |
|
950 aliasAddr = TLinAddr(ss.i_AliasLinAddr) + (aAddr & (KChunkMask & ~KPageMask)); |
|
951 iAliasPdePtr = (TPde*)(TLinAddr(ss.i_AliasPdePtr) + (local_asid << KPageDirectoryShift)); |
|
952 #endif |
|
953 iAliasLinAddr = aliasAddr; |
|
954 *iAliasPdePtr = pde; |
|
955 SinglePdeUpdated(iAliasPdePtr); |
|
956 } |
|
957 |
|
958 TRACE2(("DMemModelThread::Alias() PDEntry=%x, iAliasLinAddr=%x",pde, aliasAddr)); |
|
959 LocalInvalidateTLBForPage(aliasAddr | local_asid); |
|
960 TInt offset = aAddr&KPageMask; |
|
961 aAliasAddr = aliasAddr | offset; |
|
962 TInt maxSize = KPageSize - offset; |
|
963 aAliasSize = aSize<maxSize ? aSize : maxSize; |
|
964 iAliasTarget = aAddr & ~KPageMask; |
|
965 |
|
966 MmuLock::Unlock(); |
|
967 |
|
968 return KErrNone; |
|
969 } |
|
970 |
|
971 |
|
972 void DMemModelThread::RemoveAlias() |
|
973 // |
|
974 // Remove alias mapping (if present) |
|
975 // |
|
976 { |
|
977 TRACE2(("Thread %O RemoveAlias", this)); |
|
978 __NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false |
|
979 |
|
980 TLinAddr addr = iAliasLinAddr; |
|
981 if(addr) |
|
982 { |
|
983 MmuLock::Lock(); |
|
984 |
|
985 DoRemoveAlias(addr); |
|
986 |
|
987 MmuLock::Unlock(); |
|
988 } |
|
989 } |
|
990 |
|
991 |
|
992 /** |
|
993 Remove the alias mapping. |
|
994 |
|
995 @pre Mmulock held |
|
996 */ |
|
997 void DMemModelThread::DoRemoveAlias(TLinAddr aAddr) |
|
998 { |
|
999 LockIPCAlias(); |
|
1000 iAliasLinAddr = 0; |
|
1001 iAliasPde = KPdeUnallocatedEntry; |
|
1002 *iAliasPdePtr = KPdeUnallocatedEntry; |
|
1003 SinglePdeUpdated(iAliasPdePtr); |
|
1004 __NK_ASSERT_DEBUG((aAddr&KPageMask)==0); |
|
1005 // Invalidate the tlb using os asid, no need to open a reference as this |
|
1006 // is the current thread's process os asid. |
|
1007 LocalInvalidateTLBForPage(aAddr | ((DMemModelProcess*)iOwningProcess)->OsAsid()); |
|
1008 iAliasLink.Deque(); |
|
1009 #ifdef __SMP__ |
|
1010 __NK_ASSERT_DEBUG(iCpuRestoreCookie>=0); |
|
1011 NKern::EndFreezeCpu(iCpuRestoreCookie); |
|
1012 iCpuRestoreCookie = -1; |
|
1013 #endif |
|
1014 // Must close the os asid while the mmu lock is held to prevent it being |
|
1015 // leaked, however this requires that it is closed asynchronously as can't |
|
1016 // delete os asid with mmu lock held. |
|
1017 iAliasProcess->AsyncCloseOsAsid(); |
|
1018 } |
|
1019 |
|
1020 |
|
1021 TInt M::DemandPagingFault(TAny* aExceptionInfo) |
|
1022 { |
|
1023 TArmExcInfo& exc=*(TArmExcInfo*)aExceptionInfo; |
|
1024 |
|
1025 // permissions required by faulting memory access... |
|
1026 TUint accessPermissions = EUser; // we only allow paging of user memory |
|
1027 |
|
1028 // get faulting address... |
|
1029 TLinAddr faultAddress = exc.iFaultAddress; |
|
1030 if(exc.iExcCode==EArmExceptionPrefetchAbort) |
|
1031 { |
|
1032 // fault trying to read code to execute... |
|
1033 accessPermissions |= EExecute; |
|
1034 } |
|
1035 else if(exc.iExcCode!=EArmExceptionDataAbort) |
|
1036 return KErrUnknown; // not prefetch or data abort |
|
1037 |
|
1038 // check fault type... |
|
1039 if((exc.iFaultStatus&0x405) != 5 && (exc.iFaultStatus&0x40f) != 4) |
|
1040 return KErrUnknown; // not translation, permission or instruction cache maintenance fault. |
|
1041 |
|
1042 // check access type... |
|
1043 if(exc.iFaultStatus&(1<<11)) |
|
1044 accessPermissions |= EReadWrite; |
|
1045 |
|
1046 // let TheMmu handle the fault... |
|
1047 return TheMmu.HandlePageFault(exc.iR15, faultAddress, accessPermissions, aExceptionInfo); |
|
1048 } |
|
1049 |
|
1050 |