]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/savearea_asm.s
2d7ef5e3da59d06e3e656ddee3fd9eee04b1b647
[apple/xnu.git] / osfmk / ppc / savearea_asm.s
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 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
66 sqNoMSR: li r0,loadMSR ; Get the MSR setter SC
67 sc ; Set it
68 sqNoMSRx:
69
70 #if 0
71 rlwinm. r3,r11,0,0,19 /* (TEST/DEBUG) */
72 bne+ notraceit /* (TEST/DEBUG) */
73 BREAKPOINT_TRAP /* (TEST/DEBUG) */
74 notraceit: /* (TEST/DEBUG) */
75 #else
76 rlwinm r3,r11,0,0,19 /* Make sure it's clean and tidy */
77 #endif
78
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... */
86
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... */
91
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 */
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
130 ENTRY(save_dequeue,TAG_NO_FRAME_USED)
131
132
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 */
139
140 bt pfNoMSRirb,sdNoMSR ; No MSR...
141
142 mtmsr r3 ; Translation and all off
143 isync ; Toss prefetch
144 b sdNoMSRx
145
146 sdNoMSR: li r0,loadMSR ; Get the MSR setter SC
147 sc ; Set it
148 sdNoMSRx:
149
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... */
157
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... */
162
163
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 */
168
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... */
176
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... */
181
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 */
187
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 */
191
192 mtmsr r12 /* Restore interrupts and translation */
193 isync /* Dump any speculations */
194
195 #if 0
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) */
200 #endif
201
202 blr /* Leave... */
203
204
205
206 /*
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.
212 *
213 * We pass back the virtual address of the one we just obtained
214 * or a zero if none to allocate.
215 *
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.
219 */
220
221 ENTRY(save_get_phys,TAG_NO_FRAME_USED)
222
223 cmplw cr1,r1,r1 ; Set CR1_eq to indicate we want physical address
224 b csaveget ; Join the common...
225
226 ENTRY(save_get,TAG_NO_FRAME_USED)
227
228 cmplwi cr1,r1,0 ; Set CR1_ne to indicate we want virtual address
229
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 */
236
237 bt pfNoMSRirb,sgNoMSR ; No MSR...
238
239 mtmsr r3 ; Translation and all off
240 isync ; Toss prefetch
241 b sgNoMSRx
242
243 sgNoMSR: mr r9,r0 ; Save this
244 li r0,loadMSR ; Get the MSR setter SC
245 sc ; Set it
246 mr r0,r9 ; Restore it
247
248 sgNoMSRx:
249
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... */
257
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... */
262
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 */
266
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... */
271
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... */
275
276 use1st: andis. r7,r7,0x4000 /* Mark first gone and remember if empty */
277 mr r3,r8 /* Set the save area */
278
279 gotsave: stw r7,SACalloc(r8) /* Put back the allocation bits */
280 bne nodqsave /* There's still an empty slot, don't dequeue... */
281
282 lwz r4,SACnext(r8) /* Get the next in line */
283 stw r4,SVfree(r10) /* Dequeue our now empty save area block */
284
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 */
295
296 #if 0
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) */
305 #endif
306
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 */
310 blr /* Leave... */
311
312
313 /*
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.
319 *
320 * We take a virtual address.
321 *
322 */
323
324 ENTRY(save_ret,TAG_NO_FRAME_USED)
325
326 #if 0
327 cmplwi r3,0x1000 ; (TEST/DEBUG)
328 bgt+ notpage0 ; (TEST/DEBUG)
329 BREAKPOINT_TRAP /* (TEST/DEBUG) */
330
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) */
339
340 nodoublefret: /* (TEST/DEBUG) */
341 #endif
342
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 */
355
356 bt pfNoMSRirb,srNoMSR ; No MSR...
357
358 mtmsr r3 ; Translation and all off
359 isync ; Toss prefetch
360 b srNoMSRx
361
362 srNoMSR: li r0,loadMSR ; Get the MSR setter SC
363 sc ; Set it
364 srNoMSRx:
365
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... */
371
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 */
375
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... */
383
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... */
388
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 */
398
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 */
402
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 */
407 isync
408
409 #if 0
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) */
414 #endif
415
416 blr /* Go away... */
417
418 srbigtimepanic:
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 */
425 isync
426 blrl /* Panic... */
427
428 .data
429 EXT(srfreeactive):
430 STRINGD "save_ret: Attempting to release the active savearea!!!!\000"
431 .text
432
433
434 /*
435 * struct savearea *save_cpv(struct savearea *); Converts a physical savearea address to virtual
436 */
437
438 .align 5
439 .globl EXT(save_cpv)
440
441 LEXT(save_cpv)
442
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
447 isync
448
449 lwz r4,SACvrswap(r4) ; Get the conversion to virtual
450 mtmsr r10 ; Interrupts and DR back on
451 isync
452 xor r3,r3,r4 ; Convert to physical
453 blr
454
455
456 /*
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!
460 *
461 * We take a virtual address in R3 to save the original MSR, and
462 * return the virtual address.
463 *
464 */
465
466 ENTRY(save_deb,TAG_NO_FRAME_USED)
467
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 */
475
476 bt pfNoMSRirb,sdbNoMSR ; No MSR...
477
478 mtmsr r3 ; Translation and all off
479 isync ; Toss prefetch
480 b sdbNoMSRx
481
482 sdbNoMSR: li r0,loadMSR ; Get the MSR setter SC
483 sc ; Set it
484 sdbNoMSRx:
485
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 */
491 isync
492 blr
493
494
495
496
497