]>
Commit | Line | Data |
---|---|---|
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 |