2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
25 #include <db_machine_commands.h>
28 #include <mach_debug.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>
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.
46 * Note that the savearea list should NEVER be empty
49 ENTRY(save_queue,TAG_NO_FRAME_USED)
52 mfsprg r9,2 ; Get the feature flags
53 mr r11,r3 ; Save the block
54 mtcrf 0x04,r9 ; Set the features
55 mfmsr r12 ; Get the MSR
56 lis r10,HIGH_ADDR(EXT(saveanchor)) ; Get the high part of the anchor
57 andi. r3,r12,0x7FCF ; Turn off all translation and rupts
58 ori r10,r10,LOW_ADDR(EXT(saveanchor)) ; Bottom half of the anchor
60 bt pfNoMSRirb,sqNoMSR ; No MSR...
62 mtmsr r3 ; Translation and all off
66 sqNoMSR: li r0,loadMSR ; Get the MSR setter SC
71 rlwinm. r3,r11,0,0,19 /* (TEST/DEBUG) */
72 bne+ notraceit /* (TEST/DEBUG) */
73 BREAKPOINT_TRAP /* (TEST/DEBUG) */
74 notraceit: /* (TEST/DEBUG) */
76 rlwinm r3,r11,0,0,19 /* Make sure it's clean and tidy */
79 sqlck: lwarx r9,0,r10 /* Grab the lock value */
80 li r8,1 /* Use part of the delay time */
81 mr. r9,r9 /* Is it locked? */
82 bne- sqlcks /* Yeah, wait for it to clear... */
83 stwcx. r8,0,r10 /* Try to seize that there durn lock */
84 beq+ sqlckd /* Got it... */
85 b sqlck /* Collision, try again... */
87 sqlcks: lwz r9,SVlock(r10) /* Get that lock in here */
88 mr. r9,r9 /* Is it free yet? */
89 beq+ sqlck /* Yeah, try for it again... */
90 b sqlcks /* Sniff away... */
92 sqlckd: isync /* Make sure translation is off */
93 lwz r7,SVfree(r10) /* Get the free save area list anchor */
94 lwz r6,SVcount(r10) /* Get the total count of saveareas */
95 stw r3,SVfree(r10) /* Queue in the new one */
96 addi r6,r6,sac_cnt /* Count the ones we are linking in */
97 stw r7,SACnext(r3) /* Queue the old first one off of us */
98 li r8,0 /* Get a free lock value */
99 stw r6,SVcount(r10) /* Save the new count */
101 sync /* Make sure everything is done */
102 stw r8,SVlock(r10) /* Unlock the savearea chain */
104 mtmsr r12 /* Restore interrupts and translation */
105 isync /* Dump any speculations */
108 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
109 li r2,0x2201 ; (TEST/DEBUG)
110 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
111 sc /* (TEST/DEBUG) */
118 * This routine will find and remove an empty savearea block from the free list.
119 * Note really well: we can take NO exceptions of any kind,
120 * including a PTE miss once the savearea lock is held. That's
121 * a guaranteed deadlock. That means we must disable for interrutions
122 * and turn all translation off.
124 * We pass back the virtual address of the one we just released
125 * or a zero if none to free.
127 * Note that the savearea list should NEVER be empty
130 ENTRY(save_dequeue,TAG_NO_FRAME_USED)
133 mfsprg r9,2 ; Get the feature flags
134 mfmsr r12 /* Get the MSR */
135 mtcrf 0x04,r9 ; Set the features
136 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
137 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
138 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
140 bt pfNoMSRirb,sdNoMSR ; No MSR...
142 mtmsr r3 ; Translation and all off
143 isync ; Toss prefetch
146 sdNoMSR: li r0,loadMSR ; Get the MSR setter SC
150 sdqlck: lwarx r9,0,r10 /* Grab the lock value */
151 li r8,1 /* Use part of the delay time */
152 mr. r9,r9 /* Is it locked? */
153 bne- sdqlcks /* Yeah, wait for it to clear... */
154 stwcx. r8,0,r10 /* Try to seize that there durn lock */
155 beq+ sdqlckd /* Got it... */
156 b sdqlck /* Collision, try again... */
158 sdqlcks: lwz r9,SVlock(r10) /* Get that lock in here */
159 mr. r9,r9 /* Is it free yet? */
160 beq+ sdqlck /* Yeah, try for it again... */
161 b sdqlcks /* Sniff away... */
164 sdqlckd: isync ; Clean out the prefetches
165 lwz r3,SVfree(r10) /* Get the free save area list anchor */
166 la r5,SVfree(r10) /* Remember that the we're just starting out */
167 lwz r6,SVcount(r10) /* Get the total count of saveareas for later */
168 lis r8,sac_empty>>16 /* Get the empty block indication */
170 sdqchk: lwz r4,SACalloc(r3) /* Get the allocation flags */
171 lwz r9,SACflags(r3) /* Get the flags */
172 lwz r7,SACnext(r3) /* Point on to the next one */
173 andis. r9,r9,hi16(sac_perm) /* Is this permanently allocated? */
174 cmplw cr1,r4,r8 /* Does this look empty? */
175 bne- sdqperm /* It's permanent, can't release... */
176 beq- cr1,sdqfnd /* Yeah, empty... */
178 sdqperm: la r5,SACnext(r3) /* Remember the last guy */
179 mr. r3,r7 /* Any more left? */
180 bne+ sdqchk /* Yeah... */
181 b sdqunlk /* Nope, just go unlock and leave... */
183 sdqfnd: subi r6,r6,sac_cnt /* Back off the number of saveareas in here */
184 stw r7,0(r5) /* Dequeue our guy */
185 lwz r9,SACvrswap(r3) /* Get addressing conversion */
186 stw r6,SVcount(r10) /* Back off the count for this block */
187 xor r3,r3,r9 /* Flip to virtual addressing */
189 sdqunlk: li r8,0 /* Get a free lock value */
190 sync /* Make sure everything is done */
191 stw r8,SVlock(r10) /* Unlock the savearea chain */
193 mtmsr r12 /* Restore interrupts and translation */
194 isync /* Dump any speculations */
197 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
198 li r2,0x2202 ; (TEST/DEBUG)
199 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
200 sc /* (TEST/DEBUG) */
208 * This routine will obtain a savearea from the free list.
209 * Note really well: we can take NO exceptions of any kind,
210 * including a PTE miss once the savearea lock is held. That's
211 * a guaranteed deadlock. That means we must disable for interrutions
212 * and turn all translation off.
214 * We pass back the virtual address of the one we just obtained
215 * or a zero if none to allocate.
217 * Note that the savearea list should NEVER be empty
218 * NOTE!!! NEVER USE R0, R2, or R12 IN HERE THAT WAY WE DON'T NEED A
219 * STACK FRAME IN FPU_SAVE, FPU_SWITCH, VEC_SAVE, OR VEC_SWITCH.
222 ENTRY(save_get_phys,TAG_NO_FRAME_USED)
224 cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address
225 b csaveget ; Join the common...
227 ENTRY(save_get,TAG_NO_FRAME_USED)
229 cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address
231 csaveget: mfsprg r9,2 ; Get the feature flags
232 mfmsr r11 ; Get the MSR
233 mtcrf 0x04,r9 ; Set the features
234 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
235 andi. r3,r11,0x7FCF /* Turn off all translation and 'rupts */
236 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
238 bt pfNoMSRirb,sgNoMSR ; No MSR...
240 mtmsr r3 ; Translation and all off
241 isync ; Toss prefetch
244 sgNoMSR: mr r9,r0 ; Save this
245 li r0,loadMSR ; Get the MSR setter SC
247 mr r0,r9 ; Restore it
251 sglck: lwarx r9,0,r10 /* Grab the lock value */
252 li r7,1 /* Use part of the delay time */
253 mr. r9,r9 /* Is it locked? */
254 bne- sglcks /* Yeah, wait for it to clear... */
255 stwcx. r7,0,r10 /* Try to seize that there durn lock */
256 beq+ sglckd /* Got it... */
257 b sglck /* Collision, try again... */
259 sglcks: lwz r9,SVlock(r10) /* Get that lock in here */
260 mr. r9,r9 /* Is it free yet? */
261 beq+ sglck /* Yeah, try for it again... */
262 b sglcks /* Sniff away... */
264 sglckd: isync /* Make sure translation is off */
265 lwz r8,SVfree(r10) /* Get the head of the save area list */
266 lwz r9,SVinuse(r10) /* Get the inuse field */
268 lwz r7,SACalloc(r8) /* Pick up the allocation bits */
269 lwz r5,SACvrswap(r8) /* Get real to virtual translation */
270 mr. r7,r7 /* Can we use the first one? */
271 blt use1st /* Yeah... */
273 andis. r7,r7,0x8000 /* Show we used the second and remember if it was the last */
274 addi r3,r8,0x0800 /* Point to the first one */
275 b gotsave /* We have the area now... */
277 use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */
278 mr r3,r8 /* Set the save area */
280 gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */
281 bne nodqsave /* There's still an empty slot, don't dequeue... */
283 lwz r4,SACnext(r8) /* Get the next in line */
284 stw r4,SVfree(r10) /* Dequeue our now empty save area block */
286 nodqsave: lis r6,HIGH_ADDR(SAVattach) /* Show that it is attached for now */
287 li r4,0 /* Clear this for the lock */
288 stw r6,SAVflags(r3) /* Set the flags to attached */
289 addi r9,r9,1 /* Bump up the inuse count */
290 stw r4,SAVprev(r3) /* Make sure that backchain is clear */
291 stw r9,SVinuse(r10) /* Set the inuse field */
292 sync /* Make sure all stores are done */
293 stw r4,SVlock(r10) /* Unlock both save and trace areas */
294 mtmsr r11 /* Restore translation and exceptions */
295 isync /* Make sure about it */
298 mr r11,r0 /* (TEST/DEBUG) */
299 mr r7,r2 /* (TEST/DEBUG) */
300 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
301 li r2,0x2203 ; (TEST/DEBUG)
302 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
303 sc /* (TEST/DEBUG) */
304 mr r0,r11 /* (TEST/DEBUG) */
305 mr r2,r7 /* (TEST/DEBUG) */
308 li r7,0 ; NOTE WELL: we set R7 to zero for vector and float saving code in cswtch.s
309 beqlr- cr1 ; Return now if we want the physical address
310 xor r3,r3,r5 /* Get the virtual address */
315 * This routine will return a savearea to the free list.
316 * Note really well: we can take NO exceptions of any kind,
317 * including a PTE miss once the savearea lock is held. That's
318 * a guaranteed deadlock. That means we must disable for interrutions
319 * and turn all translation off.
321 * We take a virtual address.
325 ENTRY(save_ret,TAG_NO_FRAME_USED)
328 cmplwi r3,0x1000 ; (TEST/DEBUG)
329 bgt+ notpage0 ; (TEST/DEBUG)
330 BREAKPOINT_TRAP /* (TEST/DEBUG) */
332 notpage0: rlwinm r6,r3,0,0,19 /* (TEST/DEBUG) */
333 rlwinm r7,r3,21,31,31 /* (TEST/DEBUG) */
334 lis r8,0x8000 /* (TEST/DEBUG) */
335 lwz r6,SACalloc(r6) /* (TEST/DEBUG) */
336 srw r8,r8,r7 /* (TEST/DEBUG) */
337 and. r8,r8,r6 /* (TEST/DEBUG) */
338 beq+ nodoublefret /* (TEST/DEBUG) */
339 BREAKPOINT_TRAP /* (TEST/DEBUG) */
341 nodoublefret: /* (TEST/DEBUG) */
344 mfsprg r9,2 ; Get the feature flags
345 lwz r7,SAVflags(r3) /* Get the flags */
346 rlwinm r6,r3,0,0,19 /* Round back down to the savearea page block */
347 andis. r7,r7,HIGH_ADDR(SAVinuse) /* Still in use? */
348 mfmsr r12 /* Get the MSR */
349 bnelr- /* Still in use, just leave... */
350 lwz r5,SACvrswap(r6) /* Get the conversion to real */
351 mr r8,r3 ; Save the savearea address
352 mtcrf 0x04,r9 ; Set the features
353 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
354 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
355 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
357 bt pfNoMSRirb,srNoMSR ; No MSR...
359 mtmsr r3 ; Translation and all off
360 isync ; Toss prefetch
363 srNoMSR: li r0,loadMSR ; Get the MSR setter SC
367 mfsprg r11,1 /* Get the active save area */
368 xor r3,r8,r5 /* Get the real address of the savearea */
369 cmplw r11,r3 /* Are we trying to toss the active one? */
370 xor r6,r6,r5 /* Make the savearea block real also */
371 beq- srbigtimepanic /* This is a no-no... */
373 rlwinm r7,r3,21,31,31 /* Get position of savearea in block */
374 lis r8,0x8000 /* Build a bit mask and assume first savearea */
375 srw r8,r8,r7 /* Get bit position of do deallocate */
377 srlck: lwarx r11,0,r10 /* Grab the lock value */
378 li r7,1 /* Use part of the delay time */
379 mr. r11,r11 /* Is it locked? */
380 bne- srlcks /* Yeah, wait for it to clear... */
381 stwcx. r7,0,r10 /* Try to seize that there durn lock */
382 beq+ srlckd /* Got it... */
383 b srlck /* Collision, try again... */
385 srlcks: lwz r11,SVlock(r10) /* Get that lock in here */
386 mr. r11,r11 /* Is it free yet? */
387 beq+ srlck /* Yeah, try for it again... */
388 b srlcks /* Sniff away... */
390 srlckd: isync /* Toss preexecutions */
391 lwz r11,SACalloc(r6) /* Get the allocation for this block */
392 lwz r7,SVinuse(r10) /* Get the in use count */
393 or r11,r11,r8 /* Turn on our bit */
394 subi r7,r7,1 /* We released one, adjust count */
395 cmplw r11,r8 /* Is our's the only one free? */
396 stw r7,SVinuse(r10) /* Save out count */
397 stw r11,SACalloc(r6) /* Save it out */
398 bne+ srtrest /* Nope, then the block is already on the free list */
400 lwz r11,SVfree(r10) /* Get the old head of the free list */
401 stw r6,SVfree(r10) /* Point the head at us now */
402 stw r11,SACnext(r6) /* Point us at the old last */
404 srtrest: li r8,0 /* Get set to clear the savearea lock */
405 sync /* Make sure it's all out there */
406 stw r8,SVlock(r10) /* Unlock it */
407 mtmsr r12 /* Restore interruptions and translation */
411 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
412 li r2,0x2204 ; (TEST/DEBUG)
413 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
414 sc /* (TEST/DEBUG) */
420 lis r6,HIGH_ADDR(EXT(panic)) /* First half of panic call */
421 lis r3,HIGH_ADDR(EXT(srfreeactive)) /* First half of panic string */
422 ori r6,r6,LOW_ADDR(EXT(panic)) /* Second half of panic call */
423 ori r3,r3,LOW_ADDR(EXT(srfreeactive)) /* Second half of panic string */
424 mtlr r6 /* Get the address of the panic routine */
425 mtmsr r12 /* Restore interruptions and translation */
431 STRINGD "save_ret: Attempting to release the active savearea!!!!\000"
436 * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual
444 mfmsr r10 ; Get the current MSR
445 rlwinm r4,r3,0,0,19 ; Round back to the start of the physical savearea block
446 andi. r9,r10,0x7FEF ; Turn off interrupts and data translation
447 mtmsr r9 ; Disable DR and EE
450 lwz r4,SACvrswap(r4) ; Get the conversion to virtual
451 mtmsr r10 ; Interrupts and DR back on
453 xor r3,r3,r4 ; Convert to physical
458 * This routine will return the virtual address of the first free savearea
459 * block and disable for interruptions.
460 * Note really well: this is only for debugging, don't expect it to always work!
462 * We take a virtual address in R3 to save the original MSR, and
463 * return the virtual address.
467 ENTRY(save_deb,TAG_NO_FRAME_USED)
469 mfsprg r9,2 ; Get the feature flags
470 mfmsr r12 /* Get the MSR */
471 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
472 mtcrf 0x04,r9 ; Set the features
473 stw r12,0(r3) /* Save it */
474 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
475 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
477 bt pfNoMSRirb,sdbNoMSR ; No MSR...
479 mtmsr r3 ; Translation and all off
480 isync ; Toss prefetch
483 sdbNoMSR: li r0,loadMSR ; Get the MSR setter SC
487 lwz r3,SVfree(r10) /* Get the physical first in list */
488 andi. r11,r12,0x7FFF /* Clear only interruption */
489 lwz r5,SACvrswap(r3) /* Get the conversion to virtual */
490 mtmsr r11 /* Restore DAT but not INT */
491 xor r3,r3,r5 /* Make it virtual */