|
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\epoc\moving\arm\xkernel.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "arm_mem.h" |
|
19 |
|
20 |
|
21 /******************************************** |
|
22 * Thread |
|
23 ********************************************/ |
|
24 |
|
25 TInt DArmPlatThread::SetupContext(SThreadCreateInfo& anInfo) |
|
26 { |
|
27 switch(iThreadType) |
|
28 { |
|
29 case EThreadSupervisor: |
|
30 case EThreadMinimalSupervisor: |
|
31 iNThread.SetDacr(Arm::DefaultDomainAccess); |
|
32 case EThreadInitial: |
|
33 break; |
|
34 case EThreadUser: |
|
35 { |
|
36 DArmPlatProcess* pP=(DArmPlatProcess*)iOwningProcess; |
|
37 iNThread.SetDacr(pP->iDacr); |
|
38 if (pP->iAttributes & DMemModelProcess::EVariableAccess) |
|
39 iNThread.SetAttributes(KThreadAttImplicitSystemLock|KThreadAttAddressSpace); |
|
40 #ifndef __SMP__ |
|
41 iNThread.iSpare3 /*iUserContextType*/ = NThread::EContextUndefined; |
|
42 #endif |
|
43 break; |
|
44 } |
|
45 } |
|
46 iNThread.SetAddressSpace(iOwningProcess); |
|
47 __KTRACE_OPT(KTHREAD,Kern::Printf("Thread %O DACR %08x Attrib %02x",this,iNThread.Dacr(),iNThread.Attributes())); |
|
48 return KErrNone; |
|
49 } |
|
50 |
|
51 DArmPlatProcess::DArmPlatProcess() |
|
52 : iDomain(-1), iDacr(Arm::DefaultDomainAccess|0x3) // manager access to domain 0 |
|
53 {} |
|
54 |
|
55 DArmPlatProcess::~DArmPlatProcess() |
|
56 { |
|
57 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatProcess destruct, Domain=%d",iDomain)); |
|
58 if (iDomain>=0) |
|
59 ArmMmu::FreeDomain(iDomain); |
|
60 DMemModelProcess::Destruct(); |
|
61 } |
|
62 |
|
63 TInt DArmPlatProcess::GetNewChunk(DMemModelChunk*& aChunk, SChunkCreateInfo& aInfo) |
|
64 { |
|
65 aChunk=NULL; |
|
66 DArmPlatChunk* pC=new DArmPlatChunk; |
|
67 if (!pC) |
|
68 return KErrNoMemory; |
|
69 aChunk=pC; |
|
70 pC->iChunkType=aInfo.iType; |
|
71 switch(pC->iChunkType) |
|
72 { |
|
73 case EKernelData: |
|
74 case EKernelStack: |
|
75 case EKernelCode: |
|
76 case EKernelMessage: |
|
77 pC->iAttributes |= DMemModelChunk::EFixedAccess; |
|
78 break; |
|
79 case ERamDrive: |
|
80 pC->iDomain=3; |
|
81 pC->iAttributes |= DMemModelChunk::EFixedAccess; |
|
82 break; |
|
83 case EUserCode: |
|
84 case EUserSelfModCode: |
|
85 pC->iAttributes |= DMemModelChunk::EFixedAddress; |
|
86 if (iDomain>=0) |
|
87 { |
|
88 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create code chunk, owning process domain %d",iDomain)); |
|
89 pC->iDomain=iDomain; |
|
90 pC->iAttributes |= DMemModelChunk::EFixedAccess; |
|
91 } |
|
92 break; |
|
93 case EDll: |
|
94 break; |
|
95 case EUserData: |
|
96 case EDllData: |
|
97 if (aInfo.iGlobal && (iAttributes & DMemModelProcess::EFixedAddress || aInfo.iForceFixed)) |
|
98 { |
|
99 TInt domain=ArmMmu::AllocDomain(); |
|
100 if (domain>=0) |
|
101 { |
|
102 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create global chunk, Domain %d allocated",domain)); |
|
103 pC->iDomain=domain; |
|
104 pC->iAttributes |= DMemModelChunk::EFixedAccess; |
|
105 } |
|
106 } |
|
107 else if (!aInfo.iGlobal && iDomain>=0) |
|
108 { |
|
109 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk create local chunk, owning process domain %d",iDomain)); |
|
110 pC->iDomain=iDomain; |
|
111 pC->iAttributes |= DMemModelChunk::EFixedAccess; |
|
112 } |
|
113 break; |
|
114 case ESharedKernelSingle: |
|
115 case ESharedKernelMultiple: |
|
116 case ESharedIo: |
|
117 break; |
|
118 default: |
|
119 FAULT(); |
|
120 } |
|
121 return KErrNone; |
|
122 } |
|
123 |
|
124 DArmPlatChunk::DArmPlatChunk() |
|
125 : iDomain(-1) |
|
126 {} |
|
127 |
|
128 DArmPlatChunk::~DArmPlatChunk() |
|
129 { |
|
130 if (!iOwningProcess && iDomain>=0) |
|
131 { |
|
132 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatChunk destruct, Domain %d freed",iDomain)); |
|
133 ArmMmu::FreeDomain(iDomain); |
|
134 } |
|
135 DMemModelChunk::Destruct(); |
|
136 } |
|
137 |
|
138 TInt DArmPlatChunk::SetupPermissions() |
|
139 { |
|
140 Mmu& m = Mmu::Get(); |
|
141 if(iChunkType==ESharedKernelSingle || iChunkType==ESharedKernelMultiple || iChunkType==ESharedIo) |
|
142 { |
|
143 // override map attributes for shared kernel chunks |
|
144 TUint ma = (iMapAttr &~ EMapAttrAccessMask) | EMapAttrSupRw; |
|
145 TPde pde; |
|
146 TInt r = m.PdePtePermissions(ma, pde, iPtePermissions); |
|
147 if (r != KErrNone) |
|
148 return r; |
|
149 iMapAttr = ma; |
|
150 } |
|
151 else |
|
152 iPtePermissions=m.PtePermissions(iChunkType); |
|
153 // PDE may need to set P bit for ECC in ARMv5 and later. |
|
154 if (iDomain<0) |
|
155 { |
|
156 iPdePermissions[0]=m.PdePermissions(iChunkType,ENotRunning); |
|
157 iPdePermissions[1]=m.PdePermissions(iChunkType,ERunningRO); |
|
158 iPdePermissions[2]=m.PdePermissions(iChunkType,ERunningRW); |
|
159 } |
|
160 else |
|
161 { |
|
162 TPde pdePermissions = PT_PDE(iDomain); |
|
163 iPdePermissions[0]=pdePermissions; |
|
164 iPdePermissions[1]=pdePermissions; |
|
165 iPdePermissions[2]=pdePermissions; |
|
166 } |
|
167 __KTRACE_OPT(KMMU,Kern::Printf("Chunk permissions PTE=%08x PDE0=%08x PDE1=%08x PDE2=%08x", |
|
168 iPtePermissions,iPdePermissions[0],iPdePermissions[1],iPdePermissions[2])); |
|
169 return KErrNone; |
|
170 } |
|
171 |
|
172 |
|
173 // must hold process lock while iterating through thread list |
|
174 void DArmPlatProcess::AdjustDomainAccess(TUint32 aClearMask, TUint32 aSetMask) |
|
175 { |
|
176 __KTRACE_OPT(KMMU,Kern::Printf("Process %O AdjustDomainAccess, clear %08x set %08x", |
|
177 this,aClearMask,aSetMask)); |
|
178 iDacr=(iDacr & ~aClearMask)|aSetMask; |
|
179 __KTRACE_OPT(KMMU,Kern::Printf("DACR set to %08x",iDacr)); |
|
180 SDblQueLink* pLink=iThreadQ.First(); |
|
181 while (pLink!=&iThreadQ.iA) |
|
182 { |
|
183 DArmPlatThread* pT=_LOFF(pLink,DArmPlatThread,iProcessLink); |
|
184 pLink=pLink->iNext; |
|
185 pT->iNThread.ModifyDacr(aClearMask,aSetMask); |
|
186 } |
|
187 } |
|
188 |
|
189 // must hold process lock while iterating through thread list |
|
190 void DArmPlatProcess::AdjustThreadAttributes(TUint8 aClearMask, TUint8 aSetMask) |
|
191 { |
|
192 __KTRACE_OPT(KMMU,Kern::Printf("Process %O AdjustThreadAttributes, clear %02x set %02x", |
|
193 this,aClearMask,aSetMask)); |
|
194 SDblQueLink* pLink=iThreadQ.First(); |
|
195 NKern::LockSystem(); |
|
196 while (pLink!=&iThreadQ.iA) |
|
197 { |
|
198 DArmPlatThread* pT=_LOFF(pLink,DArmPlatThread,iProcessLink); |
|
199 pLink=pLink->iNext; |
|
200 pT->iNThread.ModifyAttributes(aClearMask,aSetMask); |
|
201 NKern::FlashSystem(); |
|
202 } |
|
203 NKern::UnlockSystem(); |
|
204 } |
|
205 |
|
206 TInt DArmPlatProcess::AddFixedAccessChunk(DMemModelChunk *aChunk) |
|
207 { |
|
208 DArmPlatChunk* pC=(DArmPlatChunk*)aChunk; |
|
209 if (pC->iChunkType==ESharedKernelSingle || pC->iChunkType==ESharedIo) |
|
210 { |
|
211 if (iDomain<0) |
|
212 return KErrGeneral; |
|
213 pC->iDomain = iDomain; |
|
214 TInt r = pC->SetupPermissions(); |
|
215 __ASSERT_ALWAYS(r==KErrNone, MM::Panic(MM::EAddFixedBadPerm)); |
|
216 } |
|
217 |
|
218 __KTRACE_OPT(KMMU,Kern::Printf("Add fixed access chunk, domain=%d",pC->iDomain)); |
|
219 |
|
220 // if this is one of process's local chunks, nothing to do |
|
221 if (pC->iDomain!=iDomain && !(iAttributes&ESupervisor)) |
|
222 { |
|
223 AdjustDomainAccess(0,2<<(pC->iDomain<<1)); // grant manager access to chunk's domain |
|
224 } |
|
225 return KErrNone; |
|
226 } |
|
227 |
|
228 TInt DArmPlatProcess::RemoveFixedAccessChunk(DMemModelChunk *aChunk) |
|
229 { |
|
230 DArmPlatChunk* pC=(DArmPlatChunk*)aChunk; |
|
231 __KTRACE_OPT(KMMU,Kern::Printf("Remove fixed access chunk, domain=%d",pC->iDomain)); |
|
232 if (pC->iChunkType==ESharedKernelSingle || pC->iChunkType==ESharedIo) |
|
233 { |
|
234 if (iDomain<0) |
|
235 return KErrGeneral; |
|
236 pC->iDomain = -1; |
|
237 TInt r = pC->SetupPermissions(); |
|
238 __ASSERT_ALWAYS(r==KErrNone, MM::Panic(MM::ERemoveFixedBadPerm)); |
|
239 return KErrNone; |
|
240 } |
|
241 |
|
242 // if this is one of process's local chunks, nothing to do |
|
243 if (pC->iDomain!=iDomain && !(iAttributes&ESupervisor)) |
|
244 { |
|
245 AdjustDomainAccess(2<<(pC->iDomain<<1),0); // remove manager access to chunk's domain |
|
246 } |
|
247 return KErrNone; |
|
248 } |
|
249 |
|
250 void DArmPlatProcess::CheckForFixedAccess() |
|
251 { |
|
252 TInt domain=ArmMmu::AllocDomain(); |
|
253 if (domain>=0) |
|
254 { |
|
255 __KTRACE_OPT(KMMU,Kern::Printf("DArmPlatProcess create, Domain %d allocated",domain)); |
|
256 iDomain=domain; |
|
257 iDacr |= (2<<(domain<<1)); // grant manager access to allocated domain |
|
258 iDacr &= ~2; // demote domain 0 to client access |
|
259 } |
|
260 } |
|
261 |
|
262 void DArmPlatProcess::DoAttributeChange() |
|
263 { |
|
264 // Called when a process changes from fixed to variable access or vice-versa. |
|
265 TBool variable=iAttributes & EVariableAccess; |
|
266 if (variable) |
|
267 { |
|
268 // process changing from fixed access to variable access |
|
269 __KTRACE_OPT(KMMU,Kern::Printf("Process %O becomes variable access",this)); |
|
270 AdjustThreadAttributes(0,KThreadAttImplicitSystemLock|KThreadAttAddressSpace); |
|
271 AdjustDomainAccess(0,2); // promote domain 0 to manager access |
|
272 } |
|
273 else |
|
274 { |
|
275 // process changing from variable access to fixed access |
|
276 __KTRACE_OPT(KMMU,Kern::Printf("Process %O becomes fixed access",this)); |
|
277 AdjustDomainAccess(2,0); // demote domain 0 to client access |
|
278 AdjustThreadAttributes(KThreadAttImplicitSystemLock|KThreadAttAddressSpace,0); |
|
279 } |
|
280 } |
|
281 |
|
282 TIpcExcTrap::TExcLocation TIpcExcTrap::ExcLocation(DThread* /*aThread*/, TAny* aContext) |
|
283 { |
|
284 TArmExcInfo& info=*(TArmExcInfo*)aContext; |
|
285 |
|
286 if (info.iExcCode==EArmExceptionDataAbort) |
|
287 { |
|
288 TLinAddr va=(TLinAddr)info.iFaultAddress; |
|
289 if (va>=iRemoteBase && (va-iRemoteBase)<iSize) |
|
290 return EExcRemote; |
|
291 if (iLocalBase && va>=iLocalBase && (va-iLocalBase)<iSize) |
|
292 return EExcLocal; |
|
293 } |
|
294 return EExcUnknown; |
|
295 } |