]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/savearea_asm.s
xnu-201.5.tar.gz
[apple/xnu.git] / osfmk / ppc / savearea_asm.s
CommitLineData
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
49ENTRY(save_queue,TAG_NO_FRAME_USED)
50
51
150bd074
A
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
59
60 bt pfNoMSRirb,sqNoMSR ; No MSR...
61
62 mtmsr r3 ; Translation and all off
63 isync ; Toss prefetch
64 b sqNoMSRx
65
66sqNoMSR: li r0,loadMSR ; Get the MSR setter SC
67 sc ; Set it
68sqNoMSRx:
1c79356b
A
69
70#if 0
150bd074 71 rlwinm. r3,r11,0,0,19 /* (TEST/DEBUG) */
1c79356b
A
72 bne+ notraceit /* (TEST/DEBUG) */
73 BREAKPOINT_TRAP /* (TEST/DEBUG) */
74notraceit: /* (TEST/DEBUG) */
75#else
150bd074 76 rlwinm r3,r11,0,0,19 /* Make sure it's clean and tidy */
1c79356b
A
77#endif
78
1c79356b
A
79sqlck: 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... */
86
87sqlcks: 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... */
91
92sqlckd: 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 */
100
101 sync /* Make sure everything is done */
102 stw r8,SVlock(r10) /* Unlock the savearea chain */
103
104 mtmsr r12 /* Restore interrupts and translation */
105 isync /* Dump any speculations */
106
107#if 0
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) */
112#endif
113
114 blr /* Leave... */
115
116
117/*
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.
123 *
124 * We pass back the virtual address of the one we just released
125 * or a zero if none to free.
126 *
127 * Note that the savearea list should NEVER be empty
128 */
129
130ENTRY(save_dequeue,TAG_NO_FRAME_USED)
131
132
150bd074 133 mfsprg r9,2 ; Get the feature flags
1c79356b 134 mfmsr r12 /* Get the MSR */
150bd074 135 mtcrf 0x04,r9 ; Set the features
1c79356b 136 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
150bd074 137 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
1c79356b 138 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
1c79356b 139
150bd074
A
140 bt pfNoMSRirb,sdNoMSR ; No MSR...
141
142 mtmsr r3 ; Translation and all off
143 isync ; Toss prefetch
144 b sdNoMSRx
145
146sdNoMSR: li r0,loadMSR ; Get the MSR setter SC
147 sc ; Set it
148sdNoMSRx:
1c79356b
A
149
150sdqlck: 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... */
157
158sdqlcks: 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... */
162
163
765c9de3
A
164sdqlckd: isync ; Clean out the prefetches
165 lwz r3,SVfree(r10) /* Get the free save area list anchor */
1c79356b
A
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 */
169
170sdqchk: 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... */
177
178sdqperm: 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... */
182
183sdqfnd: 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 */
188
189sdqunlk: li r8,0 /* Get a free lock value */
190 sync /* Make sure everything is done */
191 stw r8,SVlock(r10) /* Unlock the savearea chain */
192
193 mtmsr r12 /* Restore interrupts and translation */
194 isync /* Dump any speculations */
195
196#if 0
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) */
201#endif
202
203 blr /* Leave... */
204
205
206
207/*
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.
213 *
214 * We pass back the virtual address of the one we just obtained
215 * or a zero if none to allocate.
216 *
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.
220 */
221
222ENTRY(save_get_phys,TAG_NO_FRAME_USED)
223
224 cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address
225 b csaveget ; Join the common...
226
227ENTRY(save_get,TAG_NO_FRAME_USED)
228
229 cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address
230
150bd074
A
231csaveget: mfsprg r9,2 ; Get the feature flags
232 mfmsr r11 ; Get the MSR
233 mtcrf 0x04,r9 ; Set the features
1c79356b 234 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
150bd074 235 andi. r3,r11,0x7FCF /* Turn off all translation and 'rupts */
1c79356b 236 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
150bd074
A
237
238 bt pfNoMSRirb,sgNoMSR ; No MSR...
239
240 mtmsr r3 ; Translation and all off
241 isync ; Toss prefetch
242 b sgNoMSRx
1c79356b 243
150bd074
A
244sgNoMSR: mr r9,r0 ; Save this
245 li r0,loadMSR ; Get the MSR setter SC
246 sc ; Set it
247 mr r0,r9 ; Restore it
248
249sgNoMSRx:
1c79356b
A
250
251sglck: 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... */
258
259sglcks: 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... */
263
264sglckd: 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 */
267
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... */
272
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... */
276
277use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */
278 mr r3,r8 /* Set the save area */
279
280gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */
281 bne nodqsave /* There's still an empty slot, don't dequeue... */
282
283 lwz r4,SACnext(r8) /* Get the next in line */
284 stw r4,SVfree(r10) /* Dequeue our now empty save area block */
285
286nodqsave: 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 */
296
297#if 0
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) */
306#endif
307
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 */
311 blr /* Leave... */
312
313
314/*
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.
320 *
321 * We take a virtual address.
322 *
323 */
324
325ENTRY(save_ret,TAG_NO_FRAME_USED)
326
327#if 0
328 cmplwi r3,0x1000 ; (TEST/DEBUG)
329 bgt+ notpage0 ; (TEST/DEBUG)
330 BREAKPOINT_TRAP /* (TEST/DEBUG) */
331
332notpage0: 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) */
340
341nodoublefret: /* (TEST/DEBUG) */
342#endif
343
150bd074 344 mfsprg r9,2 ; Get the feature flags
1c79356b
A
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 */
150bd074
A
351 mr r8,r3 ; Save the savearea address
352 mtcrf 0x04,r9 ; Set the features
1c79356b 353 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
150bd074 354 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
1c79356b 355 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
150bd074
A
356
357 bt pfNoMSRirb,srNoMSR ; No MSR...
358
359 mtmsr r3 ; Translation and all off
360 isync ; Toss prefetch
361 b srNoMSRx
362
363srNoMSR: li r0,loadMSR ; Get the MSR setter SC
364 sc ; Set it
365srNoMSRx:
1c79356b
A
366
367 mfsprg r11,1 /* Get the active save area */
150bd074 368 xor r3,r8,r5 /* Get the real address of the savearea */
1c79356b
A
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... */
372
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 */
376
1c79356b
A
377srlck: 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... */
384
385srlcks: 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... */
389
390srlckd: 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 */
399
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 */
403
404srtrest: 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 */
408 isync
409
410#if 0
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) */
415#endif
416
417 blr /* Go away... */
418
419srbigtimepanic:
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 */
426 isync
427 blrl /* Panic... */
428
429 .data
430EXT(srfreeactive):
431 STRINGD "save_ret: Attempting to release the active savearea!!!!\000"
432 .text
433
434
435/*
436 * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual
437 */
438
439 .align 5
440 .globl EXT(save_cpv)
441
442LEXT(save_cpv)
443
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
448 isync
449
450 lwz r4,SACvrswap(r4) ; Get the conversion to virtual
451 mtmsr r10 ; Interrupts and DR back on
452 isync
453 xor r3,r3,r4 ; Convert to physical
454 blr
455
456
457/*
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!
461 *
150bd074 462 * We take a virtual address in R3 to save the original MSR, and
1c79356b
A
463 * return the virtual address.
464 *
465 */
466
467ENTRY(save_deb,TAG_NO_FRAME_USED)
468
150bd074 469 mfsprg r9,2 ; Get the feature flags
1c79356b
A
470 mfmsr r12 /* Get the MSR */
471 lis r10,HIGH_ADDR(EXT(saveanchor)) /* Get the high part of the anchor */
150bd074 472 mtcrf 0x04,r9 ; Set the features
1c79356b 473 stw r12,0(r3) /* Save it */
150bd074 474 andi. r3,r12,0x7FCF /* Turn off all translation and 'rupts */
1c79356b 475 ori r10,r10,LOW_ADDR(EXT(saveanchor)) /* Bottom half of the anchor */
150bd074
A
476
477 bt pfNoMSRirb,sdbNoMSR ; No MSR...
478
479 mtmsr r3 ; Translation and all off
480 isync ; Toss prefetch
481 b sdbNoMSRx
482
483sdbNoMSR: li r0,loadMSR ; Get the MSR setter SC
484 sc ; Set it
485sdbNoMSRx:
486
1c79356b
A
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 */
492 isync
493 blr
494
495
496
497
498