]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | #include <assym.s> | |
23 | #include <debug.h> | |
24 | #include <cpus.h> | |
25 | #include <db_machine_commands.h> | |
26 | #include <mach_rt.h> | |
27 | ||
28 | #include <mach_debug.h> | |
29 | #include <ppc/asm.h> | |
30 | #include <ppc/proc_reg.h> | |
31 | #include <ppc/exception.h> | |
32 | #include <ppc/Performance.h> | |
33 | #include <ppc/exception.h> | |
34 | #include <ppc/pmap_internals.h> | |
35 | #include <mach/ppc/vm_param.h> | |
36 | ||
37 | .text | |
38 | ||
39 | /* | |
40 | * This routine will add a savearea block to the free list. | |
41 | * Note really well: we can take NO exceptions of any kind, | |
42 | * including a PTE miss once the savearea lock is held. That's | |
43 | * a guaranteed deadlock. That means we must disable for interrutions | |
44 | * and turn all translation off. | |
45 | * | |
46 | * Note that the savearea list should NEVER be empty | |
47 | */ | |
48 | ||
49 | ENTRY(save_queue,TAG_NO_FRAME_USED) | |
50 | ||
51 | ||
52 | mfmsr r12 /* Get the MSR */ | |
53 | lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ | |
54 | andi. r11,r12,0x7FCF /* Turn off all translation and 'rupts */ | |
55 | ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ | |
56 | mtmsr r11 /* Make the MSR current */ | |
57 | ||
58 | isync | |
59 | ||
60 | #if 0 | |
61 | rlwinm. r3,r3,0,0,19 /* (TEST/DEBUG) */ | |
62 | bne+ notraceit /* (TEST/DEBUG) */ | |
63 | BREAKPOINT_TRAP /* (TEST/DEBUG) */ | |
64 | notraceit: /* (TEST/DEBUG) */ | |
65 | #else | |
66 | rlwinm r3,r3,0,0,19 /* Make sure it's clean and tidy */ | |
67 | #endif | |
68 | ||
69 | lwarx r9,0,r10 ; ? | |
70 | ||
71 | sqlck: lwarx r9,0,r10 /* Grab the lock value */ | |
72 | li r8,1 /* Use part of the delay time */ | |
73 | mr. r9,r9 /* Is it locked? */ | |
74 | bne- sqlcks /* Yeah, wait for it to clear... */ | |
75 | stwcx. r8,0,r10 /* Try to seize that there durn lock */ | |
76 | beq+ sqlckd /* Got it... */ | |
77 | b sqlck /* Collision, try again... */ | |
78 | ||
79 | sqlcks: lwz r9,SVlock(r10) /* Get that lock in here */ | |
80 | mr. r9,r9 /* Is it free yet? */ | |
81 | beq+ sqlck /* Yeah, try for it again... */ | |
82 | b sqlcks /* Sniff away... */ | |
83 | ||
84 | sqlckd: isync /* Make sure translation is off */ | |
85 | lwz r7,SVfree(r10) /* Get the free save area list anchor */ | |
86 | lwz r6,SVcount(r10) /* Get the total count of saveareas */ | |
87 | stw r3,SVfree(r10) /* Queue in the new one */ | |
88 | addi r6,r6,sac_cnt /* Count the ones we are linking in */ | |
89 | stw r7,SACnext(r3) /* Queue the old first one off of us */ | |
90 | li r8,0 /* Get a free lock value */ | |
91 | stw r6,SVcount(r10) /* Save the new count */ | |
92 | ||
93 | sync /* Make sure everything is done */ | |
94 | stw r8,SVlock(r10) /* Unlock the savearea chain */ | |
95 | ||
96 | mtmsr r12 /* Restore interrupts and translation */ | |
97 | isync /* Dump any speculations */ | |
98 | ||
99 | #if 0 | |
100 | lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
101 | li r2,0x2201 ; (TEST/DEBUG) | |
102 | oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
103 | sc /* (TEST/DEBUG) */ | |
104 | #endif | |
105 | ||
106 | blr /* Leave... */ | |
107 | ||
108 | ||
109 | /* | |
110 | * This routine will find and remove an empty savearea block from the free list. | |
111 | * Note really well: we can take NO exceptions of any kind, | |
112 | * including a PTE miss once the savearea lock is held. That's | |
113 | * a guaranteed deadlock. That means we must disable for interrutions | |
114 | * and turn all translation off. | |
115 | * | |
116 | * We pass back the virtual address of the one we just released | |
117 | * or a zero if none to free. | |
118 | * | |
119 | * Note that the savearea list should NEVER be empty | |
120 | */ | |
121 | ||
122 | ENTRY(save_dequeue,TAG_NO_FRAME_USED) | |
123 | ||
124 | ||
125 | mfmsr r12 /* Get the MSR */ | |
126 | lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ | |
127 | andi. r11,r12,0x7FCF /* Turn off all translation and 'rupts */ | |
128 | ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ | |
129 | mtmsr r11 /* Make the MSR current */ | |
130 | isync /* Make sure translation is off */ | |
131 | ||
132 | lwarx r9,0,r10 ; ? | |
133 | ||
134 | sdqlck: lwarx r9,0,r10 /* Grab the lock value */ | |
135 | li r8,1 /* Use part of the delay time */ | |
136 | mr. r9,r9 /* Is it locked? */ | |
137 | bne- sdqlcks /* Yeah, wait for it to clear... */ | |
138 | stwcx. r8,0,r10 /* Try to seize that there durn lock */ | |
139 | beq+ sdqlckd /* Got it... */ | |
140 | b sdqlck /* Collision, try again... */ | |
141 | ||
142 | sdqlcks: lwz r9,SVlock(r10) /* Get that lock in here */ | |
143 | mr. r9,r9 /* Is it free yet? */ | |
144 | beq+ sdqlck /* Yeah, try for it again... */ | |
145 | b sdqlcks /* Sniff away... */ | |
146 | ||
147 | ||
148 | sdqlckd: lwz r3,SVfree(r10) /* Get the free save area list anchor */ | |
149 | la r5,SVfree(r10) /* Remember that the we're just starting out */ | |
150 | lwz r6,SVcount(r10) /* Get the total count of saveareas for later */ | |
151 | lis r8,sac_empty>>16 /* Get the empty block indication */ | |
152 | ||
153 | sdqchk: lwz r4,SACalloc(r3) /* Get the allocation flags */ | |
154 | lwz r9,SACflags(r3) /* Get the flags */ | |
155 | lwz r7,SACnext(r3) /* Point on to the next one */ | |
156 | andis. r9,r9,hi16(sac_perm) /* Is this permanently allocated? */ | |
157 | cmplw cr1,r4,r8 /* Does this look empty? */ | |
158 | bne- sdqperm /* It's permanent, can't release... */ | |
159 | beq- cr1,sdqfnd /* Yeah, empty... */ | |
160 | ||
161 | sdqperm: la r5,SACnext(r3) /* Remember the last guy */ | |
162 | mr. r3,r7 /* Any more left? */ | |
163 | bne+ sdqchk /* Yeah... */ | |
164 | b sdqunlk /* Nope, just go unlock and leave... */ | |
165 | ||
166 | sdqfnd: subi r6,r6,sac_cnt /* Back off the number of saveareas in here */ | |
167 | stw r7,0(r5) /* Dequeue our guy */ | |
168 | lwz r9,SACvrswap(r3) /* Get addressing conversion */ | |
169 | stw r6,SVcount(r10) /* Back off the count for this block */ | |
170 | xor r3,r3,r9 /* Flip to virtual addressing */ | |
171 | ||
172 | sdqunlk: li r8,0 /* Get a free lock value */ | |
173 | sync /* Make sure everything is done */ | |
174 | stw r8,SVlock(r10) /* Unlock the savearea chain */ | |
175 | ||
176 | mtmsr r12 /* Restore interrupts and translation */ | |
177 | isync /* Dump any speculations */ | |
178 | ||
179 | #if 0 | |
180 | lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
181 | li r2,0x2202 ; (TEST/DEBUG) | |
182 | oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
183 | sc /* (TEST/DEBUG) */ | |
184 | #endif | |
185 | ||
186 | blr /* Leave... */ | |
187 | ||
188 | ||
189 | ||
190 | /* | |
191 | * This routine will obtain a savearea from the free list. | |
192 | * Note really well: we can take NO exceptions of any kind, | |
193 | * including a PTE miss once the savearea lock is held. That's | |
194 | * a guaranteed deadlock. That means we must disable for interrutions | |
195 | * and turn all translation off. | |
196 | * | |
197 | * We pass back the virtual address of the one we just obtained | |
198 | * or a zero if none to allocate. | |
199 | * | |
200 | * Note that the savearea list should NEVER be empty | |
201 | * NOTE!!! NEVER USE R0, R2, or R12 IN HERE THAT WAY WE DON'T NEED A | |
202 | * STACK FRAME IN FPU_SAVE, FPU_SWITCH, VEC_SAVE, OR VEC_SWITCH. | |
203 | */ | |
204 | ||
205 | ENTRY(save_get_phys,TAG_NO_FRAME_USED) | |
206 | ||
207 | cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address | |
208 | b csaveget ; Join the common... | |
209 | ||
210 | ENTRY(save_get,TAG_NO_FRAME_USED) | |
211 | ||
212 | cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address | |
213 | ||
214 | csaveget: mfmsr r11 /* Get the MSR */ | |
215 | lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ | |
216 | andi. r8,r11,0x7FCF /* Turn off all translation and 'rupts */ | |
217 | ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ | |
218 | mtmsr r8 /* Make the MSR current */ | |
219 | isync ; Make sure it is done | |
220 | ||
221 | lwarx r9,0,r10 ; ? | |
222 | ||
223 | sglck: lwarx r9,0,r10 /* Grab the lock value */ | |
224 | li r7,1 /* Use part of the delay time */ | |
225 | mr. r9,r9 /* Is it locked? */ | |
226 | bne- sglcks /* Yeah, wait for it to clear... */ | |
227 | stwcx. r7,0,r10 /* Try to seize that there durn lock */ | |
228 | beq+ sglckd /* Got it... */ | |
229 | b sglck /* Collision, try again... */ | |
230 | ||
231 | sglcks: lwz r9,SVlock(r10) /* Get that lock in here */ | |
232 | mr. r9,r9 /* Is it free yet? */ | |
233 | beq+ sglck /* Yeah, try for it again... */ | |
234 | b sglcks /* Sniff away... */ | |
235 | ||
236 | sglckd: isync /* Make sure translation is off */ | |
237 | lwz r8,SVfree(r10) /* Get the head of the save area list */ | |
238 | lwz r9,SVinuse(r10) /* Get the inuse field */ | |
239 | ||
240 | lwz r7,SACalloc(r8) /* Pick up the allocation bits */ | |
241 | lwz r5,SACvrswap(r8) /* Get real to virtual translation */ | |
242 | mr. r7,r7 /* Can we use the first one? */ | |
243 | blt use1st /* Yeah... */ | |
244 | ||
245 | andis. r7,r7,0x8000 /* Show we used the second and remember if it was the last */ | |
246 | addi r3,r8,0x0800 /* Point to the first one */ | |
247 | b gotsave /* We have the area now... */ | |
248 | ||
249 | use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */ | |
250 | mr r3,r8 /* Set the save area */ | |
251 | ||
252 | gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */ | |
253 | bne nodqsave /* There's still an empty slot, don't dequeue... */ | |
254 | ||
255 | lwz r4,SACnext(r8) /* Get the next in line */ | |
256 | stw r4,SVfree(r10) /* Dequeue our now empty save area block */ | |
257 | ||
258 | nodqsave: lis r6,HIGH_ADDR(SAVattach) /* Show that it is attached for now */ | |
259 | li r4,0 /* Clear this for the lock */ | |
260 | stw r6,SAVflags(r3) /* Set the flags to attached */ | |
261 | addi r9,r9,1 /* Bump up the inuse count */ | |
262 | stw r4,SAVprev(r3) /* Make sure that backchain is clear */ | |
263 | stw r9,SVinuse(r10) /* Set the inuse field */ | |
264 | sync /* Make sure all stores are done */ | |
265 | stw r4,SVlock(r10) /* Unlock both save and trace areas */ | |
266 | mtmsr r11 /* Restore translation and exceptions */ | |
267 | isync /* Make sure about it */ | |
268 | ||
269 | #if 0 | |
270 | mr r11,r0 /* (TEST/DEBUG) */ | |
271 | mr r7,r2 /* (TEST/DEBUG) */ | |
272 | lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
273 | li r2,0x2203 ; (TEST/DEBUG) | |
274 | oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
275 | sc /* (TEST/DEBUG) */ | |
276 | mr r0,r11 /* (TEST/DEBUG) */ | |
277 | mr r2,r7 /* (TEST/DEBUG) */ | |
278 | #endif | |
279 | ||
280 | li r7,0 ; NOTE WELL: we set R7 to zero for vector and float saving code in cswtch.s | |
281 | beqlr- cr1 ; Return now if we want the physical address | |
282 | xor r3,r3,r5 /* Get the virtual address */ | |
283 | blr /* Leave... */ | |
284 | ||
285 | ||
286 | /* | |
287 | * This routine will return a savearea to the free list. | |
288 | * Note really well: we can take NO exceptions of any kind, | |
289 | * including a PTE miss once the savearea lock is held. That's | |
290 | * a guaranteed deadlock. That means we must disable for interrutions | |
291 | * and turn all translation off. | |
292 | * | |
293 | * We take a virtual address. | |
294 | * | |
295 | */ | |
296 | ||
297 | ENTRY(save_ret,TAG_NO_FRAME_USED) | |
298 | ||
299 | #if 0 | |
300 | cmplwi r3,0x1000 ; (TEST/DEBUG) | |
301 | bgt+ notpage0 ; (TEST/DEBUG) | |
302 | BREAKPOINT_TRAP /* (TEST/DEBUG) */ | |
303 | ||
304 | notpage0: rlwinm r6,r3,0,0,19 /* (TEST/DEBUG) */ | |
305 | rlwinm r7,r3,21,31,31 /* (TEST/DEBUG) */ | |
306 | lis r8,0x8000 /* (TEST/DEBUG) */ | |
307 | lwz r6,SACalloc(r6) /* (TEST/DEBUG) */ | |
308 | srw r8,r8,r7 /* (TEST/DEBUG) */ | |
309 | and. r8,r8,r6 /* (TEST/DEBUG) */ | |
310 | beq+ nodoublefret /* (TEST/DEBUG) */ | |
311 | BREAKPOINT_TRAP /* (TEST/DEBUG) */ | |
312 | ||
313 | nodoublefret: /* (TEST/DEBUG) */ | |
314 | #endif | |
315 | ||
316 | lwz r7,SAVflags(r3) /* Get the flags */ | |
317 | rlwinm r6,r3,0,0,19 /* Round back down to the savearea page block */ | |
318 | andis. r7,r7,HIGH_ADDR(SAVinuse) /* Still in use? */ | |
319 | mfmsr r12 /* Get the MSR */ | |
320 | bnelr- /* Still in use, just leave... */ | |
321 | lwz r5,SACvrswap(r6) /* Get the conversion to real */ | |
322 | lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ | |
323 | andi. r11,r12,0x7FCF /* Turn off all translation and 'rupts */ | |
324 | ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ | |
325 | mtmsr r11 /* Make the MSR current */ | |
326 | isync /* Make sure translation is off */ | |
327 | ||
328 | mfsprg r11,1 /* Get the active save area */ | |
329 | xor r3,r3,r5 /* Get the real address of the savearea */ | |
330 | cmplw r11,r3 /* Are we trying to toss the active one? */ | |
331 | xor r6,r6,r5 /* Make the savearea block real also */ | |
332 | beq- srbigtimepanic /* This is a no-no... */ | |
333 | ||
334 | rlwinm r7,r3,21,31,31 /* Get position of savearea in block */ | |
335 | lis r8,0x8000 /* Build a bit mask and assume first savearea */ | |
336 | srw r8,r8,r7 /* Get bit position of do deallocate */ | |
337 | ||
338 | lwarx r11,0,r10 ; ? | |
339 | ||
340 | srlck: lwarx r11,0,r10 /* Grab the lock value */ | |
341 | li r7,1 /* Use part of the delay time */ | |
342 | mr. r11,r11 /* Is it locked? */ | |
343 | bne- srlcks /* Yeah, wait for it to clear... */ | |
344 | stwcx. r7,0,r10 /* Try to seize that there durn lock */ | |
345 | beq+ srlckd /* Got it... */ | |
346 | b srlck /* Collision, try again... */ | |
347 | ||
348 | srlcks: lwz r11,SVlock(r10) /* Get that lock in here */ | |
349 | mr. r11,r11 /* Is it free yet? */ | |
350 | beq+ srlck /* Yeah, try for it again... */ | |
351 | b srlcks /* Sniff away... */ | |
352 | ||
353 | srlckd: isync /* Toss preexecutions */ | |
354 | lwz r11,SACalloc(r6) /* Get the allocation for this block */ | |
355 | lwz r7,SVinuse(r10) /* Get the in use count */ | |
356 | or r11,r11,r8 /* Turn on our bit */ | |
357 | subi r7,r7,1 /* We released one, adjust count */ | |
358 | cmplw r11,r8 /* Is our's the only one free? */ | |
359 | stw r7,SVinuse(r10) /* Save out count */ | |
360 | stw r11,SACalloc(r6) /* Save it out */ | |
361 | bne+ srtrest /* Nope, then the block is already on the free list */ | |
362 | ||
363 | lwz r11,SVfree(r10) /* Get the old head of the free list */ | |
364 | stw r6,SVfree(r10) /* Point the head at us now */ | |
365 | stw r11,SACnext(r6) /* Point us at the old last */ | |
366 | ||
367 | srtrest: li r8,0 /* Get set to clear the savearea lock */ | |
368 | sync /* Make sure it's all out there */ | |
369 | stw r8,SVlock(r10) /* Unlock it */ | |
370 | mtmsr r12 /* Restore interruptions and translation */ | |
371 | isync | |
372 | ||
373 | #if 0 | |
374 | lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
375 | li r2,0x2204 ; (TEST/DEBUG) | |
376 | oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */ | |
377 | sc /* (TEST/DEBUG) */ | |
378 | #endif | |
379 | ||
380 | blr /* Go away... */ | |
381 | ||
382 | srbigtimepanic: | |
383 | lis r6,HIGH_ADDR(EXT(panic)) /* First half of panic call */ | |
384 | lis r3,HIGH_ADDR(EXT(srfreeactive)) /* First half of panic string */ | |
385 | ori r6,r6,LOW_ADDR(EXT(panic)) /* Second half of panic call */ | |
386 | ori r3,r3,LOW_ADDR(EXT(srfreeactive)) /* Second half of panic string */ | |
387 | mtlr r6 /* Get the address of the panic routine */ | |
388 | mtmsr r12 /* Restore interruptions and translation */ | |
389 | isync | |
390 | blrl /* Panic... */ | |
391 | ||
392 | .data | |
393 | EXT(srfreeactive): | |
394 | STRINGD "save_ret: Attempting to release the active savearea!!!!\000" | |
395 | .text | |
396 | ||
397 | ||
398 | /* | |
399 | * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual | |
400 | */ | |
401 | ||
402 | .align 5 | |
403 | .globl EXT(save_cpv) | |
404 | ||
405 | LEXT(save_cpv) | |
406 | ||
407 | mfmsr r10 ; Get the current MSR | |
408 | rlwinm r4,r3,0,0,19 ; Round back to the start of the physical savearea block | |
409 | andi. r9,r10,0x7FEF ; Turn off interrupts and data translation | |
410 | mtmsr r9 ; Disable DR and EE | |
411 | isync | |
412 | ||
413 | lwz r4,SACvrswap(r4) ; Get the conversion to virtual | |
414 | mtmsr r10 ; Interrupts and DR back on | |
415 | isync | |
416 | xor r3,r3,r4 ; Convert to physical | |
417 | blr | |
418 | ||
419 | ||
420 | /* | |
421 | * This routine will return the virtual address of the first free savearea | |
422 | * block and disable for interruptions. | |
423 | * Note really well: this is only for debugging, don't expect it to always work! | |
424 | * | |
425 | * We take a virtual address in R4 to save the original MSR, and | |
426 | * return the virtual address. | |
427 | * | |
428 | */ | |
429 | ||
430 | ENTRY(save_deb,TAG_NO_FRAME_USED) | |
431 | ||
432 | mfmsr r12 /* Get the MSR */ | |
433 | lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */ | |
434 | stw r12,0(r3) /* Save it */ | |
435 | andi. r11,r12,0x7FCF /* Turn off all translation and 'rupts */ | |
436 | ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */ | |
437 | mtmsr r11 /* Make the MSR current */ | |
438 | isync /* Make sure translation is off */ | |
439 | lwz r3,SVfree(r10) /* Get the physical first in list */ | |
440 | andi. r11,r12,0x7FFF /* Clear only interruption */ | |
441 | lwz r5,SACvrswap(r3) /* Get the conversion to virtual */ | |
442 | mtmsr r11 /* Restore DAT but not INT */ | |
443 | xor r3,r3,r5 /* Make it virtual */ | |
444 | isync | |
445 | blr | |
446 | ||
447 | ||
448 | ||
449 | ||
450 |