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: lwz r3,SVfree(r10) /* Get the free save area list anchor */
165 la r5,SVfree(r10) /* Remember that the we're just starting out */
166 lwz r6,SVcount(r10) /* Get the total count of saveareas for later */
167 lis r8,sac_empty>>16 /* Get the empty block indication */
169 sdqchk: lwz r4,SACalloc(r3) /* Get the allocation flags */
170 lwz r9,SACflags(r3) /* Get the flags */
171 lwz r7,SACnext(r3) /* Point on to the next one */
172 andis. r9,r9,hi16(sac_perm) /* Is this permanently allocated? */
173 cmplw cr1,r4,r8 /* Does this look empty? */
174 bne- sdqperm /* It's permanent, can't release... */
175 beq- cr1,sdqfnd /* Yeah, empty... */
177 sdqperm: la r5,SACnext(r3) /* Remember the last guy */
178 mr. r3,r7 /* Any more left? */
179 bne+ sdqchk /* Yeah... */
180 b sdqunlk /* Nope, just go unlock and leave... */
182 sdqfnd: subi r6,r6,sac_cnt /* Back off the number of saveareas in here */
183 stw r7,0(r5) /* Dequeue our guy */
184 lwz r9,SACvrswap(r3) /* Get addressing conversion */
185 stw r6,SVcount(r10) /* Back off the count for this block */
186 xor r3,r3,r9 /* Flip to virtual addressing */
188 sdqunlk: li r8,0 /* Get a free lock value */
189 sync /* Make sure everything is done */
190 stw r8,SVlock(r10) /* Unlock the savearea chain */
192 mtmsr r12 /* Restore interrupts and translation */
193 isync /* Dump any speculations */
196 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
197 li r2,0x2202 ; (TEST/DEBUG)
198 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
199 sc /* (TEST/DEBUG) */
207 * This routine will obtain a savearea from the free list.
208 * Note really well: we can take NO exceptions of any kind,
209 * including a PTE miss once the savearea lock is held. That's
210 * a guaranteed deadlock. That means we must disable for interrutions
211 * and turn all translation off.
213 * We pass back the virtual address of the one we just obtained
214 * or a zero if none to allocate.
216 * Note that the savearea list should NEVER be empty
217 * NOTE!!! NEVER USE R0, R2, or R12 IN HERE THAT WAY WE DON'T NEED A
218 * STACK FRAME IN FPU_SAVE, FPU_SWITCH, VEC_SAVE, OR VEC_SWITCH.
221 ENTRY(save_get_phys,TAG_NO_FRAME_USED)
223 cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address
224 b csaveget ; Join the common...
226 ENTRY(save_get,TAG_NO_FRAME_USED)
228 cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address
230 csaveget: mfsprg r9,2 ; Get the feature flags
231 mfmsr r11 ; Get the MSR
232 mtcrf 0x04,r9 ; Set the features
233 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
234 andi. r3,r11,0x7FCF /* Turn off all translation and 'rupts */
235 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
237 bt pfNoMSRirb,sgNoMSR ; No MSR...
239 mtmsr r3 ; Translation and all off
240 isync ; Toss prefetch
243 sgNoMSR: mr r9,r0 ; Save this
244 li r0,loadMSR ; Get the MSR setter SC
246 mr r0,r9 ; Restore it
250 sglck: lwarx r9,0,r10 /* Grab the lock value */
251 li r7,1 /* Use part of the delay time */
252 mr. r9,r9 /* Is it locked? */
253 bne- sglcks /* Yeah, wait for it to clear... */
254 stwcx. r7,0,r10 /* Try to seize that there durn lock */
255 beq+ sglckd /* Got it... */
256 b sglck /* Collision, try again... */
258 sglcks: lwz r9,SVlock(r10) /* Get that lock in here */
259 mr. r9,r9 /* Is it free yet? */
260 beq+ sglck /* Yeah, try for it again... */
261 b sglcks /* Sniff away... */
263 sglckd: isync /* Make sure translation is off */
264 lwz r8,SVfree(r10) /* Get the head of the save area list */
265 lwz r9,SVinuse(r10) /* Get the inuse field */
267 lwz r7,SACalloc(r8) /* Pick up the allocation bits */
268 lwz r5,SACvrswap(r8) /* Get real to virtual translation */
269 mr. r7,r7 /* Can we use the first one? */
270 blt use1st /* Yeah... */
272 andis. r7,r7,0x8000 /* Show we used the second and remember if it was the last */
273 addi r3,r8,0x0800 /* Point to the first one */
274 b gotsave /* We have the area now... */
276 use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */
277 mr r3,r8 /* Set the save area */
279 gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */
280 bne nodqsave /* There's still an empty slot, don't dequeue... */
282 lwz r4,SACnext(r8) /* Get the next in line */
283 stw r4,SVfree(r10) /* Dequeue our now empty save area block */
285 nodqsave: lis r6,HIGH_ADDR(SAVattach) /* Show that it is attached for now */
286 li r4,0 /* Clear this for the lock */
287 stw r6,SAVflags(r3) /* Set the flags to attached */
288 addi r9,r9,1 /* Bump up the inuse count */
289 stw r4,SAVprev(r3) /* Make sure that backchain is clear */
290 stw r9,SVinuse(r10) /* Set the inuse field */
291 sync /* Make sure all stores are done */
292 stw r4,SVlock(r10) /* Unlock both save and trace areas */
293 mtmsr r11 /* Restore translation and exceptions */
294 isync /* Make sure about it */
297 mr r11,r0 /* (TEST/DEBUG) */
298 mr r7,r2 /* (TEST/DEBUG) */
299 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
300 li r2,0x2203 ; (TEST/DEBUG)
301 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
302 sc /* (TEST/DEBUG) */
303 mr r0,r11 /* (TEST/DEBUG) */
304 mr r2,r7 /* (TEST/DEBUG) */
307 li r7,0 ; NOTE WELL: we set R7 to zero for vector and float saving code in cswtch.s
308 beqlr- cr1 ; Return now if we want the physical address
309 xor r3,r3,r5 /* Get the virtual address */
314 * This routine will return a savearea to the free list.
315 * Note really well: we can take NO exceptions of any kind,
316 * including a PTE miss once the savearea lock is held. That's
317 * a guaranteed deadlock. That means we must disable for interrutions
318 * and turn all translation off.
320 * We take a virtual address.
324 ENTRY(save_ret,TAG_NO_FRAME_USED)
327 cmplwi r3,0x1000 ; (TEST/DEBUG)
328 bgt+ notpage0 ; (TEST/DEBUG)
329 BREAKPOINT_TRAP /* (TEST/DEBUG) */
331 notpage0: rlwinm r6,r3,0,0,19 /* (TEST/DEBUG) */
332 rlwinm r7,r3,21,31,31 /* (TEST/DEBUG) */
333 lis r8,0x8000 /* (TEST/DEBUG) */
334 lwz r6,SACalloc(r6) /* (TEST/DEBUG) */
335 srw r8,r8,r7 /* (TEST/DEBUG) */
336 and. r8,r8,r6 /* (TEST/DEBUG) */
337 beq+ nodoublefret /* (TEST/DEBUG) */
338 BREAKPOINT_TRAP /* (TEST/DEBUG) */
340 nodoublefret: /* (TEST/DEBUG) */
343 mfsprg r9,2 ; Get the feature flags
344 lwz r7,SAVflags(r3) /* Get the flags */
345 rlwinm r6,r3,0,0,19 /* Round back down to the savearea page block */
346 andis. r7,r7,HIGH_ADDR(SAVinuse) /* Still in use? */
347 mfmsr r12 /* Get the MSR */
348 bnelr- /* Still in use, just leave... */
349 lwz r5,SACvrswap(r6) /* Get the conversion to real */
350 mr r8,r3 ; Save the savearea address
351 mtcrf 0x04,r9 ; Set the features
352 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
353 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
354 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
356 bt pfNoMSRirb,srNoMSR ; No MSR...
358 mtmsr r3 ; Translation and all off
359 isync ; Toss prefetch
362 srNoMSR: li r0,loadMSR ; Get the MSR setter SC
366 mfsprg r11,1 /* Get the active save area */
367 xor r3,r8,r5 /* Get the real address of the savearea */
368 cmplw r11,r3 /* Are we trying to toss the active one? */
369 xor r6,r6,r5 /* Make the savearea block real also */
370 beq- srbigtimepanic /* This is a no-no... */
372 rlwinm r7,r3,21,31,31 /* Get position of savearea in block */
373 lis r8,0x8000 /* Build a bit mask and assume first savearea */
374 srw r8,r8,r7 /* Get bit position of do deallocate */
376 srlck: lwarx r11,0,r10 /* Grab the lock value */
377 li r7,1 /* Use part of the delay time */
378 mr. r11,r11 /* Is it locked? */
379 bne- srlcks /* Yeah, wait for it to clear... */
380 stwcx. r7,0,r10 /* Try to seize that there durn lock */
381 beq+ srlckd /* Got it... */
382 b srlck /* Collision, try again... */
384 srlcks: lwz r11,SVlock(r10) /* Get that lock in here */
385 mr. r11,r11 /* Is it free yet? */
386 beq+ srlck /* Yeah, try for it again... */
387 b srlcks /* Sniff away... */
389 srlckd: isync /* Toss preexecutions */
390 lwz r11,SACalloc(r6) /* Get the allocation for this block */
391 lwz r7,SVinuse(r10) /* Get the in use count */
392 or r11,r11,r8 /* Turn on our bit */
393 subi r7,r7,1 /* We released one, adjust count */
394 cmplw r11,r8 /* Is our's the only one free? */
395 stw r7,SVinuse(r10) /* Save out count */
396 stw r11,SACalloc(r6) /* Save it out */
397 bne+ srtrest /* Nope, then the block is already on the free list */
399 lwz r11,SVfree(r10) /* Get the old head of the free list */
400 stw r6,SVfree(r10) /* Point the head at us now */
401 stw r11,SACnext(r6) /* Point us at the old last */
403 srtrest: li r8,0 /* Get set to clear the savearea lock */
404 sync /* Make sure it's all out there */
405 stw r8,SVlock(r10) /* Unlock it */
406 mtmsr r12 /* Restore interruptions and translation */
410 lis r0,HIGH_ADDR(CutTrace) /* (TEST/DEBUG) */
411 li r2,0x2204 ; (TEST/DEBUG)
412 oris r0,r0,LOW_ADDR(CutTrace) /* (TEST/DEBUG) */
413 sc /* (TEST/DEBUG) */
419 lis r6,HIGH_ADDR(EXT(panic)) /* First half of panic call */
420 lis r3,HIGH_ADDR(EXT(srfreeactive)) /* First half of panic string */
421 ori r6,r6,LOW_ADDR(EXT(panic)) /* Second half of panic call */
422 ori r3,r3,LOW_ADDR(EXT(srfreeactive)) /* Second half of panic string */
423 mtlr r6 /* Get the address of the panic routine */
424 mtmsr r12 /* Restore interruptions and translation */
430 STRINGD "save_ret: Attempting to release the active savearea!!!!\000"
435 * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual
443 mfmsr r10 ; Get the current MSR
444 rlwinm r4,r3,0,0,19 ; Round back to the start of the physical savearea block
445 andi. r9,r10,0x7FEF ; Turn off interrupts and data translation
446 mtmsr r9 ; Disable DR and EE
449 lwz r4,SACvrswap(r4) ; Get the conversion to virtual
450 mtmsr r10 ; Interrupts and DR back on
452 xor r3,r3,r4 ; Convert to physical
457 * This routine will return the virtual address of the first free savearea
458 * block and disable for interruptions.
459 * Note really well: this is only for debugging, don't expect it to always work!
461 * We take a virtual address in R3 to save the original MSR, and
462 * return the virtual address.
466 ENTRY(save_deb,TAG_NO_FRAME_USED)
468 mfsprg r9,2 ; Get the feature flags
469 mfmsr r12 /* Get the MSR */
470 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
471 mtcrf 0x04,r9 ; Set the features
472 stw r12,0(r3) /* Save it */
473 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
474 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
476 bt pfNoMSRirb,sdbNoMSR ; No MSR...
478 mtmsr r3 ; Translation and all off
479 isync ; Toss prefetch
482 sdbNoMSR: li r0,loadMSR ; Get the MSR setter SC
486 lwz r3,SVfree(r10) /* Get the physical first in list */
487 andi. r11,r12,0x7FFF /* Clear only interruption */
488 lwz r5,SACvrswap(r3) /* Get the conversion to virtual */
489 mtmsr r11 /* Restore DAT but not INT */
490 xor r3,r3,r5 /* Make it virtual */