]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
31 | ||
32 | #include <ppc/asm.h> | |
33 | #include <ppc/proc_reg.h> | |
1c79356b A |
34 | #include <assym.s> |
35 | #include <debug.h> | |
36 | #include <mach/ppc/vm_param.h> | |
37 | #include <ppc/exception.h> | |
9bccf70c | 38 | #include <ppc/savearea.h> |
1c79356b A |
39 | |
40 | #define FPVECDBG 0 | |
1c79356b A |
41 | |
42 | .text | |
43 | ||
44 | /* | |
55e303ae | 45 | * void machine_load_context(thread_t thread) |
1c79356b | 46 | * |
55e303ae A |
47 | * Load the context for the first thread to run on a |
48 | * cpu, and go. | |
1c79356b A |
49 | */ |
50 | ||
9bccf70c | 51 | .align 5 |
55e303ae | 52 | .globl EXT(machine_load_context) |
1c79356b | 53 | |
55e303ae | 54 | LEXT(machine_load_context) |
91447636 A |
55 | mfsprg r6,1 ; Get the current activation |
56 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block | |
1c79356b | 57 | lwz r0,PP_INTSTACK_TOP_SS(r6) |
1c79356b | 58 | stw r0,PP_ISTACKPTR(r6) |
91447636 | 59 | mr r9,r3 /* Set up the current thread */ |
55e303ae | 60 | mtsprg 1,r9 |
1c79356b | 61 | li r0,0 /* Clear a register */ |
55e303ae | 62 | lwz r3,ACT_MACT_PCB(r9) /* Get the savearea used */ |
1c79356b | 63 | mfmsr r5 /* Since we are passing control, get our MSR values */ |
55e303ae A |
64 | lwz r11,SAVprev+4(r3) /* Get the previous savearea */ |
65 | lwz r1,saver1+4(r3) /* Load new stack pointer */ | |
ab86ba33 | 66 | lwz r10,ACT_MACT_SPF(r9) /* Get the special flags */ |
55e303ae | 67 | stw r0,saver3+4(r3) /* Make sure we pass in a 0 for the continuation */ |
1c79356b | 68 | stw r0,FM_BACKPTR(r1) /* zero backptr */ |
55e303ae | 69 | stw r5,savesrr1+4(r3) /* Pass our MSR to the new guy */ |
1c79356b | 70 | stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */ |
ab86ba33 | 71 | oris r10,r10,hi16(OnProc) /* Set OnProc bit */ |
55e303ae | 72 | stw r0,ACT_PREEMPT_CNT(r9) /* Enable preemption */ |
ab86ba33 A |
73 | stw r10,ACT_MACT_SPF(r9) /* Update the special flags */ |
74 | stw r10,spcFlags(r6) /* Set per_proc copy of the special flags */ | |
55e303ae | 75 | b EXT(exception_exit) /* Go for it */ |
1c79356b | 76 | |
55e303ae A |
77 | /* thread_t Switch_context(thread_t old, |
78 | * void (*cont)(void), | |
79 | * thread_t new) | |
1c79356b A |
80 | * |
81 | * Switch from one thread to another. If a continuation is supplied, then | |
82 | * we do not need to save callee save registers. | |
83 | * | |
84 | */ | |
85 | ||
91447636 | 86 | /* void Call_continuation( void (*continuation)(void), void *param, wait_result_t wresult, vm_offset_t stack_ptr) |
1c79356b A |
87 | */ |
88 | ||
9bccf70c A |
89 | .align 5 |
90 | .globl EXT(Call_continuation) | |
91 | ||
92 | LEXT(Call_continuation) | |
91447636 A |
93 | mtlr r3 /* continuation */ |
94 | mr r3,r4 /* parameter */ | |
95 | mr r4,r5 /* wait result */ | |
96 | mr r1,r6 /* Load new stack pointer */ | |
97 | blrl /* Jump to the continuation */ | |
98 | mfsprg r3,1 | |
99 | b EXT(thread_terminate) | |
1c79356b A |
100 | |
101 | /* | |
102 | * Get the old kernel stack, and store into the thread structure. | |
103 | * See if a continuation is supplied, and skip state save if so. | |
55e303ae A |
104 | * |
105 | * Note that interrupts must be disabled before we get here (i.e., splsched) | |
1c79356b A |
106 | */ |
107 | ||
b36670ce A |
108 | /* |
109 | * Switch_context(old, continuation, new) | |
110 | * | |
111 | * Context switches are double jumps. We pass the following to the | |
1c79356b A |
112 | * context switch firmware call: |
113 | * | |
55e303ae | 114 | * R3 = switchee's savearea, virtual if continuation, low order physical for full switch |
1c79356b A |
115 | * R4 = old thread |
116 | * R5 = new SRR0 | |
117 | * R6 = new SRR1 | |
55e303ae | 118 | * R7 = high order physical address of savearea for full switch |
1c79356b A |
119 | * |
120 | * savesrr0 is set to go to switch_in | |
121 | * savesrr1 is set to uninterruptible with translation on | |
122 | */ | |
123 | ||
124 | ||
9bccf70c A |
125 | .align 5 |
126 | .globl EXT(Switch_context) | |
1c79356b | 127 | |
9bccf70c A |
128 | LEXT(Switch_context) |
129 | ||
91447636 | 130 | lwz r12,ACT_PER_PROC(r3) ; Get the per_proc block |
1c79356b | 131 | #if DEBUG |
55e303ae A |
132 | lwz r0,PP_ISTACKPTR(r12) ; (DEBUG/TRACE) make sure we are not |
133 | mr. r0,r0 ; (DEBUG/TRACE) on the interrupt | |
134 | bne++ notonintstack ; (DEBUG/TRACE) stack | |
1c79356b A |
135 | BREAKPOINT_TRAP |
136 | notonintstack: | |
137 | #endif | |
de355530 | 138 | lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy |
91447636 | 139 | lwz r9,umwSpace(r5) ; Get user memory window address space |
55e303ae | 140 | cmpwi cr1,r4,0 ; Remeber if there is a continuation - used waaaay down below |
91447636 A |
141 | lwz r0,CTHREAD_SELF+0(r5) ; Pick up the user assist "word" (actually a double) |
142 | lwz r7,CTHREAD_SELF+4(r5) ; both halves | |
55e303ae | 143 | lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment |
91447636 A |
144 | lwz r6,umwRelo(r5) ; Get user memory window relocation top |
145 | stw r12,ACT_PER_PROC(r5) ; Set per_proc in new activation | |
55e303ae | 146 | mtsprg 1,r5 |
91447636 | 147 | lwz r2,umwRelo+4(r5) ; Get user memory window relocation bottom |
de355530 | 148 | |
91447636 A |
149 | stw r0,UAW+0(r12) ; Save the assist word for the "ultra fast path" |
150 | stw r7,UAW+4(r12) | |
55e303ae | 151 | |
1c79356b A |
152 | lwz r7,ACT_MACT_SPF(r5) ; Get the special flags |
153 | ||
91447636 A |
154 | sth r9,ppUMWmp+mpSpace(r12) ; Save the space |
155 | stw r6,ppUMWmp+mpNestReloc(r12) ; Save top part of physical address | |
156 | stw r2,ppUMWmp+mpNestReloc+4(r12) ; Save bottom part of physical address | |
9bccf70c | 157 | stw r11,ppbbTaskEnv(r12) ; Save the bb task env |
55e303ae | 158 | lwz r2,traceMask(0) ; Get the enabled traces |
9bccf70c | 159 | stw r7,spcFlags(r12) ; Set per_proc copy of the special flags |
1c79356b | 160 | lis r0,hi16(CutTrace) ; Trace FW call |
55e303ae A |
161 | mr. r2,r2 ; Any tracing going on? |
162 | lwz r11,SAVprev+4(r8) ; Get the previous of the switchee savearea | |
1c79356b | 163 | ori r0,r0,lo16(CutTrace) ; Trace FW call |
55e303ae | 164 | beq++ cswNoTrc ; No trace today, dude... |
b36670ce A |
165 | |
166 | li r2,0x4400 ; Trace ID | |
167 | mr r6,r11 ; Trace prev savearea | |
1c79356b | 168 | sc ; Cut trace entry of context switch |
1c79356b | 169 | |
55e303ae | 170 | cswNoTrc: lwz r2,curctx(r5) ; Grab our current context pointer |
9bccf70c A |
171 | lwz r10,FPUowner(r12) ; Grab the owner of the FPU |
172 | lwz r9,VMXowner(r12) ; Grab the owner of the vector | |
55e303ae A |
173 | mfmsr r6 ; Get the MSR because the switched to thread should inherit it |
174 | stw r11,ACT_MACT_PCB(r5) ; Dequeue the savearea we are switching to | |
175 | li r0,1 ; Get set to hold off quickfret | |
176 | ||
177 | rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off the FP | |
9bccf70c A |
178 | cmplw r10,r2 ; Do we have the live float context? |
179 | lwz r10,FPUlevel(r2) ; Get the live level | |
55e303ae | 180 | mr r4,r3 ; Save our old thread to pass back |
9bccf70c | 181 | cmplw cr5,r9,r2 ; Do we have the live vector context? |
55e303ae A |
182 | rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off the vector |
183 | stw r0,holdQFret(r12) ; Make sure we hold off releasing quickfret | |
184 | bne++ cswnofloat ; Float is not ours... | |
9bccf70c A |
185 | |
186 | cmplw r10,r11 ; Is the level the same? | |
91447636 | 187 | lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number |
9bccf70c | 188 | lwz r5,FPUcpu(r2) ; Get the owning cpu |
55e303ae | 189 | bne++ cswnofloat ; Level not the same, this is not live... |
9bccf70c A |
190 | |
191 | cmplw r5,r0 ; Still owned by this cpu? | |
b36670ce | 192 | lwz r10,FPUsave(r2) ; Get the pointer to next saved context |
55e303ae | 193 | bne++ cswnofloat ; CPU claimed by someone else... |
9bccf70c A |
194 | |
195 | mr. r10,r10 ; Is there a savearea here? | |
196 | ori r6,r6,lo16(MASK(MSR_FP)) ; Enable floating point | |
197 | ||
55e303ae | 198 | beq-- cswnofloat ; No savearea to check... |
9bccf70c A |
199 | |
200 | lwz r3,SAVlevel(r10) ; Get the level | |
55e303ae | 201 | lwz r5,SAVprev+4(r10) ; Get the previous of this savearea |
9bccf70c A |
202 | cmplw r3,r11 ; Is it for the current level? |
203 | ||
55e303ae | 204 | bne++ cswnofloat ; Nope... |
9bccf70c A |
205 | |
206 | stw r5,FPUsave(r2) ; Pop off this savearea | |
55e303ae A |
207 | |
208 | rlwinm r3,r10,0,0,19 ; Move back to start of page | |
209 | ||
210 | lwz r5,quickfret(r12) ; Get the first in quickfret list (top) | |
211 | lwz r9,quickfret+4(r12) ; Get the first in quickfret list (bottom) | |
212 | lwz r7,SACvrswap(r3) ; Get the virtual to real conversion (top) | |
213 | lwz r3,SACvrswap+4(r3) ; Get the virtual to real conversion (bottom) | |
214 | stw r5,SAVprev(r10) ; Link the old in (top) | |
215 | stw r9,SAVprev+4(r10) ; Link the old in (bottom) | |
216 | xor r3,r10,r3 ; Convert to physical | |
217 | stw r7,quickfret(r12) ; Set the first in quickfret list (top) | |
218 | stw r3,quickfret+4(r12) ; Set the first in quickfret list (bottom) | |
9bccf70c A |
219 | |
220 | #if FPVECDBG | |
221 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
55e303ae | 222 | mr r7,r2 ; (TEST/DEBUG) |
9bccf70c A |
223 | li r2,0x4401 ; (TEST/DEBUG) |
224 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
225 | sc ; (TEST/DEBUG) | |
226 | lhz r0,PP_CPU_NUMBER(r12) ; (TEST/DEBUG) | |
55e303ae | 227 | mr r2,r7 ; (TEST/DEBUG) |
9bccf70c A |
228 | #endif |
229 | ||
55e303ae | 230 | cswnofloat: bne++ cr5,cswnovect ; Vector is not ours... |
9bccf70c A |
231 | |
232 | lwz r10,VMXlevel(r2) ; Get the live level | |
233 | ||
234 | cmplw r10,r11 ; Is the level the same? | |
91447636 | 235 | lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number |
9bccf70c | 236 | lwz r5,VMXcpu(r2) ; Get the owning cpu |
55e303ae | 237 | bne++ cswnovect ; Level not the same, this is not live... |
9bccf70c A |
238 | |
239 | cmplw r5,r0 ; Still owned by this cpu? | |
240 | lwz r10,VMXsave(r2) ; Get the level | |
55e303ae | 241 | bne++ cswnovect ; CPU claimed by someone else... |
9bccf70c A |
242 | |
243 | mr. r10,r10 ; Is there a savearea here? | |
244 | oris r6,r6,hi16(MASK(MSR_VEC)) ; Enable vector | |
245 | ||
55e303ae | 246 | beq-- cswnovect ; No savearea to check... |
9bccf70c A |
247 | |
248 | lwz r3,SAVlevel(r10) ; Get the level | |
55e303ae | 249 | lwz r5,SAVprev+4(r10) ; Get the previous of this savearea |
9bccf70c A |
250 | cmplw r3,r11 ; Is it for the current level? |
251 | ||
55e303ae | 252 | bne++ cswnovect ; Nope... |
9bccf70c A |
253 | |
254 | stw r5,VMXsave(r2) ; Pop off this savearea | |
55e303ae A |
255 | rlwinm r3,r10,0,0,19 ; Move back to start of page |
256 | ||
257 | lwz r5,quickfret(r12) ; Get the first in quickfret list (top) | |
258 | lwz r9,quickfret+4(r12) ; Get the first in quickfret list (bottom) | |
259 | lwz r2,SACvrswap(r3) ; Get the virtual to real conversion (top) | |
260 | lwz r3,SACvrswap+4(r3) ; Get the virtual to real conversion (bottom) | |
261 | stw r5,SAVprev(r10) ; Link the old in (top) | |
262 | stw r9,SAVprev+4(r10) ; Link the old in (bottom) | |
263 | xor r3,r10,r3 ; Convert to physical | |
264 | stw r2,quickfret(r12) ; Set the first in quickfret list (top) | |
265 | stw r3,quickfret+4(r12) ; Set the first in quickfret list (bottom) | |
9bccf70c A |
266 | |
267 | #if FPVECDBG | |
268 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
269 | li r2,0x4501 ; (TEST/DEBUG) | |
270 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
271 | sc ; (TEST/DEBUG) | |
272 | #endif | |
273 | ||
55e303ae A |
274 | cswnovect: li r0,0 ; Get set to release quickfret holdoff |
275 | rlwinm r11,r8,0,0,19 ; Switch to savearea base | |
276 | lis r9,hi16(EXT(switch_in)) ; Get top of switch in routine | |
277 | lwz r5,savesrr0+4(r8) ; Set up the new SRR0 | |
b36670ce A |
278 | ; |
279 | ; Note that the low-level code requires the R7 contain the high order half of the savearea's | |
280 | ; physical address. This is hack city, but it is the way it is. | |
281 | ; | |
55e303ae A |
282 | lwz r7,SACvrswap(r11) ; Get the high order V to R translation |
283 | lwz r11,SACvrswap+4(r11) ; Get the low order V to R translation | |
284 | ori r9,r9,lo16(EXT(switch_in)) ; Bottom half of switch in | |
285 | stw r0,holdQFret(r12) ; Make sure we release quickfret holdoff | |
286 | stw r9,savesrr0+4(r8) ; Make us jump to the switch in routine | |
9bccf70c | 287 | |
55e303ae | 288 | lwz r9,SAVflags(r8) /* Get the flags */ |
9bccf70c | 289 | lis r0,hi16(SwitchContextCall) /* Top part of switch context */ |
91447636 | 290 | li r10,(MASK(MSR_ME)|MASK(MSR_DR)) /* Get the switcher's MSR */ |
de355530 | 291 | ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */ |
55e303ae A |
292 | stw r10,savesrr1+4(r8) /* Set up for switch in */ |
293 | rlwinm r9,r9,0,15,13 /* Reset the syscall flag */ | |
294 | xor r3,r11,r8 /* Get the physical address of the new context save area */ | |
1c79356b | 295 | stw r9,SAVflags(r8) /* Set the flags */ |
9bccf70c A |
296 | |
297 | bne cr1,swtchtocont ; Switch to the continuation | |
1c79356b A |
298 | sc /* Switch to the new context */ |
299 | ||
300 | /* We come back here in the new thread context | |
301 | * R4 was set to hold the old thread pointer, but switch_in will put it into | |
302 | * R3 where it belongs. | |
303 | */ | |
304 | blr /* Jump into the new thread */ | |
9bccf70c A |
305 | |
306 | ; | |
307 | ; This is where we go when a continuation is set. We are actually | |
308 | ; killing off the old context of the new guy so we need to pop off | |
309 | ; any float or vector states for the ditched level. | |
310 | ; | |
311 | ; Note that we do the same kind of thing a chkfac in hw_exceptions.s | |
312 | ; | |
313 | ||
1c79356b | 314 | |
9bccf70c | 315 | swtchtocont: |
55e303ae A |
316 | |
317 | stw r5,savesrr0+4(r8) ; Set the pc | |
318 | stw r6,savesrr1+4(r8) ; Set the next MSR to use | |
319 | stw r4,saver3+4(r8) ; Make sure we pass back the old thread | |
320 | mr r3,r8 ; Pass in the virtual address of savearea | |
9bccf70c A |
321 | |
322 | b EXT(exception_exit) ; Blocking on continuation, toss old context... | |
1c79356b A |
323 | |
324 | ||
325 | ||
326 | /* | |
327 | * All switched to threads come here first to clean up the old thread. | |
328 | * We need to do the following contortions because we need to keep | |
329 | * the LR clean. And because we need to manipulate the savearea chain | |
330 | * with translation on. If we could, this should be done in lowmem_vectors | |
331 | * before translation is turned on. But we can't, dang it! | |
332 | * | |
91447636 A |
333 | * switch_in() runs with DR on and IR off |
334 | * | |
55e303ae | 335 | * R3 = switcher's savearea (32-bit virtual) |
1c79356b A |
336 | * saver4 = old thread in switcher's save |
337 | * saver5 = new SRR0 in switcher's save | |
338 | * saver6 = new SRR1 in switcher's save | |
339 | ||
340 | ||
341 | */ | |
342 | ||
9bccf70c A |
343 | |
344 | .align 5 | |
345 | .globl EXT(switch_in) | |
346 | ||
347 | LEXT(switch_in) | |
1c79356b | 348 | |
55e303ae A |
349 | lwz r4,saver4+4(r3) ; Get the old thread |
350 | lwz r5,saver5+4(r3) ; Get the srr0 value | |
351 | ||
352 | mfsprg r0,2 ; Get feature flags | |
91447636 | 353 | mr r9,r4 ; Get the switched from ACT |
55e303ae A |
354 | lwz r6,saver6+4(r3) ; Get the srr1 value |
355 | rlwinm. r0,r0,0,pf64Bitb,pf64Bitb ; Check for 64-bit | |
356 | lwz r10,ACT_MACT_PCB(r9) ; Get the top PCB on the old thread | |
1c79356b | 357 | |
55e303ae A |
358 | stw r3,ACT_MACT_PCB(r9) ; Put the new one on top |
359 | stw r10,SAVprev+4(r3) ; Chain on the old one | |
de355530 | 360 | |
55e303ae | 361 | mr r3,r4 ; Pass back the old thread |
1c79356b | 362 | |
55e303ae A |
363 | mtsrr0 r5 ; Set return point |
364 | mtsrr1 r6 ; Set return MSR | |
365 | ||
366 | bne++ siSixtyFour ; Go do 64-bit... | |
1c79356b | 367 | |
55e303ae A |
368 | rfi ; Jam... |
369 | ||
370 | siSixtyFour: | |
371 | rfid ; Jam... | |
1c79356b A |
372 | |
373 | /* | |
9bccf70c | 374 | * void fpu_save(facility_context ctx) |
1c79356b | 375 | * |
9bccf70c A |
376 | * Note that there are some oddities here when we save a context we are using. |
377 | * It is really not too cool to do this, but what the hey... Anyway, | |
378 | * we turn fpus and vecs off before we leave., The oddity is that if you use fpus after this, the | |
379 | * savearea containing the context just saved will go away. So, bottom line is | |
380 | * that don't use fpus until after you are done with the saved context. | |
1c79356b | 381 | */ |
9bccf70c A |
382 | .align 5 |
383 | .globl EXT(fpu_save) | |
1c79356b | 384 | |
9bccf70c A |
385 | LEXT(fpu_save) |
386 | ||
55e303ae A |
387 | lis r2,hi16(MASK(MSR_VEC)) ; Get the vector enable |
388 | li r12,lo16(MASK(MSR_EE)) ; Get the EE bit | |
389 | ori r2,r2,lo16(MASK(MSR_FP)) ; Get FP | |
9bccf70c A |
390 | |
391 | mfmsr r0 ; Get the MSR | |
55e303ae A |
392 | andc r0,r0,r2 ; Clear FP, VEC |
393 | andc r2,r0,r12 ; Clear EE | |
9bccf70c | 394 | ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also |
9bccf70c | 395 | mtmsr r2 ; Set the MSR |
1c79356b | 396 | isync |
9bccf70c | 397 | |
91447636 A |
398 | mfsprg r6,1 ; Get the current activation |
399 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block | |
9bccf70c A |
400 | lwz r12,FPUowner(r6) ; Get the context ID for owner |
401 | ||
1c79356b | 402 | #if FPVECDBG |
9bccf70c A |
403 | mr r7,r0 ; (TEST/DEBUG) |
404 | li r4,0 ; (TEST/DEBUG) | |
405 | mr r10,r3 ; (TEST/DEBUG) | |
406 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
407 | mr. r3,r12 ; (TEST/DEBUG) | |
408 | li r2,0x6F00 ; (TEST/DEBUG) | |
409 | li r5,0 ; (TEST/DEBUG) | |
55e303ae | 410 | beq-- noowneryet ; (TEST/DEBUG) |
9bccf70c A |
411 | lwz r4,FPUlevel(r12) ; (TEST/DEBUG) |
412 | lwz r5,FPUsave(r12) ; (TEST/DEBUG) | |
413 | ||
414 | noowneryet: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
415 | sc ; (TEST/DEBUG) | |
416 | mr r0,r7 ; (TEST/DEBUG) | |
417 | mr r3,r10 ; (TEST/DEBUG) | |
1c79356b | 418 | #endif |
9bccf70c A |
419 | mflr r2 ; Save the return address |
420 | ||
b36670ce | 421 | cmplw r3,r12 ; Is the specified context live? |
9bccf70c | 422 | lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number |
b36670ce A |
423 | lwz r9,FPUcpu(r3) ; Get the cpu that context was last on |
424 | bne-- fsret ; Nobody owns the FPU, no save required... | |
1c79356b | 425 | |
b36670ce A |
426 | cmplw r9,r11 ; Was the context for this processor? |
427 | la r5,FPUsync(r3) ; Point to the sync word | |
428 | bne-- fsret ; Facility not last used on this processor... | |
0b4e3aa0 | 429 | |
b36670ce A |
430 | ; |
431 | ; It looks like we need to save this one. | |
432 | ; | |
433 | ; First, make sure that the live context block is not mucked with while | |
434 | ; we are trying to save it on out. Then we will give it the final check. | |
435 | ; | |
436 | ||
437 | lis r9,ha16(EXT(LockTimeOut)) ; Get the high part | |
438 | mftb r8 ; Get the time now | |
439 | lwz r9,lo16(EXT(LockTimeOut))(r9) ; Get the timeout value | |
440 | b fssync0a ; Jump to the lock... | |
1c79356b | 441 | |
9bccf70c | 442 | .align 5 |
1c79356b | 443 | |
b36670ce A |
444 | fssync0: li r7,lgKillResv ; Get killing field |
445 | stwcx. r7,0,r7 ; Kill reservation | |
446 | ||
447 | fssync0a: lwz r7,0(r5) ; Sniff the lock | |
448 | mftb r10 ; Is it time yet? | |
449 | cmplwi cr1,r7,0 ; Is it locked? | |
450 | sub r10,r10,r8 ; How long have we been spinning? | |
451 | cmplw r10,r9 ; Has it been too long? | |
452 | bgt-- fstimeout ; Way too long, panic... | |
453 | bne-- cr1,fssync0a ; Yea, still locked so sniff harder... | |
454 | ||
455 | fssync1: lwarx r7,0,r5 ; Get the sync word | |
456 | li r12,1 ; Get the lock | |
457 | mr. r7,r7 ; Is it unlocked? | |
458 | bne-- fssync0 | |
459 | stwcx. r12,0,r5 ; Store lock and test reservation | |
460 | bne-- fssync1 ; Try again if lost reservation... | |
461 | ||
462 | isync ; Toss speculation | |
463 | ||
464 | lwz r12,FPUowner(r6) ; Get the context ID for owner | |
465 | cmplw r3,r12 ; Check again if we own the FPU? | |
466 | bne-- fsretlk ; Go unlock and return since we no longer own context | |
467 | ||
468 | lwz r5,FPUcpu(r12) ; Get the cpu that context was last on | |
469 | lwz r7,FPUsave(r12) ; Get the current FPU savearea for the thread | |
470 | cmplw r5,r11 ; Is this for the same processor? | |
9bccf70c | 471 | lwz r9,FPUlevel(r12) ; Get our current level indicator |
b36670ce | 472 | bne-- fsretlk ; Not the same processor, skip any save... |
1c79356b | 473 | |
b36670ce A |
474 | cmplwi r7,0 ; Have we ever saved this facility context? |
475 | beq-- fsneedone ; Never saved it, so go do it... | |
1c79356b | 476 | |
b36670ce A |
477 | lwz r8,SAVlevel(r7) ; Get the level of this savearea |
478 | cmplw r9,r8 ; Correct level? | |
479 | beq-- fsretlk ; The current level is already saved, bail out... | |
1c79356b | 480 | |
9bccf70c A |
481 | fsneedone: bl EXT(save_get) ; Get a savearea for the context |
482 | ||
91447636 A |
483 | mfsprg r6,1 ; Get the current activation |
484 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block | |
9bccf70c A |
485 | li r4,SAVfloat ; Get floating point tag |
486 | lwz r12,FPUowner(r6) ; Get back our thread | |
487 | stb r4,SAVflags+2(r3) ; Mark this savearea as a float | |
9bccf70c | 488 | lwz r4,facAct(r12) ; Get the activation associated with live context |
9bccf70c A |
489 | lwz r8,FPUsave(r12) ; Get the current top floating point savearea |
490 | stw r4,SAVact(r3) ; Indicate the right activation for this context | |
491 | lwz r9,FPUlevel(r12) ; Get our current level indicator again | |
492 | stw r3,FPUsave(r12) ; Set this as the most current floating point context | |
55e303ae | 493 | stw r8,SAVprev+4(r3) ; And then chain this in front |
1c79356b | 494 | |
9bccf70c | 495 | stw r9,SAVlevel(r3) ; Show level in savearea |
1c79356b | 496 | |
55e303ae A |
497 | bl fp_store ; save all 32 FPRs in the save area at r3 |
498 | mtlr r2 ; Restore return | |
b36670ce A |
499 | |
500 | fsretlk: li r7,0 ; Get the unlock value | |
501 | eieio ; Make sure that these updates make it out | |
502 | stw r7,FPUsync(r12) ; Unlock it | |
503 | ||
9bccf70c | 504 | fsret: mtmsr r0 ; Put interrupts on if they were and floating point off |
1c79356b A |
505 | isync |
506 | ||
507 | blr | |
508 | ||
b36670ce A |
509 | fstimeout: mr r4,r5 ; Set the lock address |
510 | mr r5,r7 ; Set the lock word data | |
511 | lis r3,hi16(fstimeout_str) ; Get the failed lck message | |
512 | ori r3,r3,lo16(fstimeout_str) ; Get the failed lck message | |
513 | bl EXT(panic) | |
514 | BREAKPOINT_TRAP ; We die here anyway | |
515 | ||
516 | .data | |
517 | fstimeout_str: | |
518 | STRINGD "fpu_save: timeout on sync lock (0x%08X), value = 0x%08X\n\000" | |
519 | .text | |
520 | ||
9bccf70c | 521 | |
1c79356b A |
522 | /* |
523 | * fpu_switch() | |
524 | * | |
525 | * Entered to handle the floating-point unavailable exception and | |
526 | * switch fpu context | |
527 | * | |
528 | * This code is run in virtual address mode on with interrupts off. | |
529 | * | |
530 | * Upon exit, the code returns to the users context with the floating | |
531 | * point facility turned on. | |
532 | * | |
533 | * ENTRY: VM switched ON | |
534 | * Interrupts OFF | |
535 | * State is saved in savearea pointed to by R4. | |
536 | * All other registers are free. | |
537 | * | |
538 | */ | |
539 | ||
9bccf70c A |
540 | .align 5 |
541 | .globl EXT(fpu_switch) | |
542 | ||
543 | LEXT(fpu_switch) | |
544 | ||
1c79356b | 545 | #if DEBUG |
1c79356b A |
546 | lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter |
547 | ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter | |
548 | lwz r1,0(r3) | |
549 | addi r1,r1,1 | |
550 | stw r1,0(r3) | |
1c79356b A |
551 | #endif /* DEBUG */ |
552 | ||
91447636 A |
553 | mfsprg r17,1 ; Get the current activation |
554 | lwz r26,ACT_PER_PROC(r17) ; Get the per_proc block | |
55e303ae | 555 | mfmsr r19 ; Get the current MSR |
1c79356b | 556 | |
9bccf70c A |
557 | mr r25,r4 ; Save the entry savearea |
558 | lwz r22,FPUowner(r26) ; Get the thread that owns the FPU | |
9bccf70c | 559 | ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature |
1c79356b | 560 | |
9bccf70c | 561 | mtmsr r19 ; Enable floating point instructions |
1c79356b | 562 | isync |
1c79356b | 563 | |
9bccf70c A |
564 | lwz r27,ACT_MACT_PCB(r17) ; Get the current level |
565 | lwz r29,curctx(r17) ; Grab the current context anchor of the current thread | |
0b4e3aa0 | 566 | |
9bccf70c A |
567 | ; R22 has the "old" context anchor |
568 | ; R29 has the "new" context anchor | |
0b4e3aa0 | 569 | |
1c79356b | 570 | #if FPVECDBG |
9bccf70c A |
571 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
572 | li r2,0x7F01 ; (TEST/DEBUG) | |
573 | mr r3,r22 ; (TEST/DEBUG) | |
574 | mr r5,r29 ; (TEST/DEBUG) | |
575 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
576 | sc ; (TEST/DEBUG) | |
1c79356b | 577 | #endif |
9bccf70c A |
578 | |
579 | lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number | |
1c79356b | 580 | |
b36670ce A |
581 | mr. r22,r22 ; See if there is any live FP status |
582 | la r15,FPUsync(r22) ; Point to the sync word | |
1c79356b | 583 | |
b36670ce | 584 | beq-- fsnosave ; No live context, so nothing to save... |
1c79356b | 585 | |
9bccf70c | 586 | lwz r18,FPUcpu(r22) ; Get the last CPU we ran on |
b36670ce A |
587 | cmplw cr2,r22,r29 ; Are both old and new the same context? |
588 | lwz r30,FPUsave(r22) ; Get the top savearea | |
9bccf70c A |
589 | cmplw r18,r16 ; Make sure we are on the right processor |
590 | lwz r31,FPUlevel(r22) ; Get the context level | |
b36670ce | 591 | cmplwi cr1,r30,0 ; Anything saved yet? |
1c79356b | 592 | |
b36670ce | 593 | bne-- fsnosave ; No, not on the same processor... |
9bccf70c | 594 | |
1c79356b | 595 | ; |
9bccf70c A |
596 | ; Check to see if the live context has already been saved. |
597 | ; Also check to see if all we are here just to re-enable the MSR | |
598 | ; and handle specially if so. | |
1c79356b | 599 | ; |
9bccf70c A |
600 | |
601 | cmplw r31,r27 ; See if the current and active levels are the same | |
602 | crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same | |
1c79356b | 603 | |
b36670ce A |
604 | beq-- fsthesame ; New and old are the same, just go enable... |
605 | ||
606 | ||
607 | ; | |
608 | ; Note it turns out that on a G5, the following load has about a 50-50 chance of | |
609 | ; taking a segment exception in a system that is doing heavy file I/O. We | |
610 | ; make a dummy access right now in order to get that resolved before we take the lock. | |
611 | ; We do not use the data returned because it may change over the lock | |
612 | ; | |
613 | ||
614 | beq-- cr1,fswsync ; Nothing saved, skip the probe attempt... | |
615 | lwz r11,SAVlevel(r30) ; Touch the context in order to fault in the segment | |
616 | ||
617 | ; | |
618 | ; Make sure that the live context block is not mucked with while | |
619 | ; we are trying to save it on out | |
620 | ; | |
621 | ||
622 | fswsync: lis r11,ha16(EXT(LockTimeOut)) ; Get the high part | |
623 | mftb r3 ; Get the time now | |
624 | lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value | |
625 | b fswsync0a ; Jump to the lock... | |
626 | ||
627 | .align 5 | |
628 | ||
629 | fswsync0: li r19,lgKillResv ; Get killing field | |
630 | stwcx. r19,0,r19 ; Kill reservation | |
631 | ||
632 | fswsync0a: lwz r19,0(r15) ; Sniff the lock | |
633 | mftb r18 ; Is it time yet? | |
634 | cmplwi cr1,r19,0 ; Is it locked? | |
635 | sub r18,r18,r3 ; How long have we been spinning? | |
636 | cmplw r18,r11 ; Has it been too long? | |
637 | bgt-- fswtimeout ; Way too long, panic... | |
638 | bne-- cr1,fswsync0a ; Yea, still locked so sniff harder... | |
639 | ||
640 | fswsync1: lwarx r19,0,r15 ; Get the sync word | |
641 | li r0,1 ; Get the lock | |
642 | mr. r19,r19 ; Is it unlocked? | |
643 | bne-- fswsync0 | |
644 | stwcx. r0,0,r15 ; Store lock and test reservation | |
645 | bne-- fswsync1 ; Try again if lost reservation... | |
646 | ||
647 | isync ; Toss speculation | |
9bccf70c | 648 | |
b36670ce A |
649 | ; |
650 | ; Note that now that we have the lock, we need to check if anything changed. | |
651 | ; Also note that the possible changes are limited. The context owner can | |
652 | ; never change to a different thread or level although it can be invalidated. | |
653 | ; A new context can not be pushed on top of us, but it can be popped. The | |
654 | ; cpu indicator will always change if another processor mucked with any | |
655 | ; contexts. | |
656 | ; | |
657 | ; It should be very rare that any of the context stuff changes across the lock. | |
658 | ; | |
659 | ||
660 | lwz r0,FPUowner(r26) ; Get the thread that owns the FPU again | |
661 | lwz r11,FPUsave(r22) ; Get the top savearea again | |
662 | lwz r18,FPUcpu(r22) ; Get the last CPU we ran on again | |
663 | sub r0,r0,r22 ; Non-zero if we lost ownership, 0 if not | |
664 | xor r11,r11,r30 ; Non-zero if saved context changed, 0 if not | |
665 | xor r18,r18,r16 ; Non-zero if cpu changed, 0 if not | |
666 | cmplwi cr1,r30,0 ; Is anything saved? | |
667 | or r0,r0,r11 ; Zero only if both owner and context are unchanged | |
668 | or. r0,r0,r18 ; Zero only if nothing has changed | |
669 | li r3,0 ; Clear this | |
1c79356b | 670 | |
b36670ce A |
671 | bne-- fsnosavelk ; Something has changed, so this is not ours to save... |
672 | beq-- cr1,fsmstsave ; There is no context saved yet... | |
673 | ||
9bccf70c | 674 | lwz r11,SAVlevel(r30) ; Get the level of top saved context |
1c79356b | 675 | |
9bccf70c A |
676 | cmplw r31,r11 ; Are live and saved the same? |
677 | ||
1c79356b | 678 | #if FPVECDBG |
9bccf70c A |
679 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
680 | li r2,0x7F02 ; (TEST/DEBUG) | |
b36670ce | 681 | mr r3,r11 ; (TEST/DEBUG) |
9bccf70c A |
682 | mr r5,r31 ; (TEST/DEBUG) |
683 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
684 | sc ; (TEST/DEBUG) | |
55e303ae | 685 | li r3,0 ; (TEST/DEBUG) |
1c79356b | 686 | #endif |
9bccf70c | 687 | |
b36670ce | 688 | beq++ fsnosavelk ; Same level, so already saved... |
1c79356b | 689 | |
9bccf70c A |
690 | fsmstsave: stw r3,FPUowner(r26) ; Kill the context now |
691 | eieio ; Make sure everyone sees it | |
692 | bl EXT(save_get) ; Go get a savearea | |
55e303ae | 693 | |
b36670ce | 694 | lwz r12,facAct(r22) ; Get the activation associated with the context |
55e303ae | 695 | stw r30,SAVprev+4(r3) ; Point us to the old context |
9bccf70c A |
696 | stw r31,SAVlevel(r3) ; Tag our level |
697 | li r7,SAVfloat ; Get the floating point ID | |
698 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
699 | stb r7,SAVflags+2(r3) ; Set that we have a floating point save area | |
b36670ce | 700 | stw r3,FPUsave(r22) ; Set this as the latest context savearea for the thread |
55e303ae | 701 | |
1c79356b | 702 | #if FPVECDBG |
9bccf70c A |
703 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
704 | li r2,0x7F03 ; (TEST/DEBUG) | |
705 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
706 | sc ; (TEST/DEBUG) | |
1c79356b A |
707 | #endif |
708 | ||
55e303ae | 709 | bl fp_store ; store all 32 FPRs |
1c79356b | 710 | |
b36670ce A |
711 | fsnosavelk: li r7,0 ; Get the unlock value |
712 | eieio ; Make sure that these updates make it out | |
713 | stw r7,FPUsync(r22) ; Unlock it. | |
714 | ||
1c79356b A |
715 | ; |
716 | ; The context is all saved now and the facility is free. | |
717 | ; | |
b36670ce | 718 | ; Check if we need to fill the registers with junk, because this level has |
1c79356b A |
719 | ; never used them before and some thieving bastard could hack the old values |
720 | ; of some thread! Just imagine what would happen if they could! Why, nothing | |
721 | ; would be safe! My God! It is terrifying! | |
722 | ; | |
b36670ce A |
723 | ; Make sure that the live context block is not mucked with while |
724 | ; we are trying to load it up | |
725 | ; | |
726 | ||
727 | fsnosave: la r15,FPUsync(r29) ; Point to the sync word | |
728 | lis r11,ha16(EXT(LockTimeOut)) ; Get the high part | |
729 | mftb r3 ; Get the time now | |
730 | lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value | |
731 | b fsnsync0a ; Jump to the lock... | |
732 | ||
733 | .align 5 | |
734 | ||
735 | fsnsync0: li r19,lgKillResv ; Get killing field | |
736 | stwcx. r19,0,r19 ; Kill reservation | |
737 | ||
738 | fsnsync0a: lwz r19,0(r15) ; Sniff the lock | |
739 | mftb r18 ; Is it time yet? | |
740 | cmplwi cr1,r19,0 ; Is it locked? | |
741 | sub r18,r18,r3 ; How long have we been spinning? | |
742 | cmplw r18,r11 ; Has it been too long? | |
743 | bgt-- fsntimeout ; Way too long, panic... | |
744 | bne-- cr1,fsnsync0a ; Yea, still locked so sniff harder... | |
1c79356b | 745 | |
b36670ce A |
746 | fsnsync1: lwarx r19,0,r15 ; Get the sync word |
747 | li r0,1 ; Get the lock | |
748 | mr. r19,r19 ; Is it unlocked? | |
749 | bne-- fsnsync0 ; Unfortunately, it is locked... | |
750 | stwcx. r0,0,r15 ; Store lock and test reservation | |
751 | bne-- fsnsync1 ; Try again if lost reservation... | |
752 | ||
753 | isync ; Toss speculation | |
0b4e3aa0 | 754 | |
b36670ce | 755 | lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one |
9bccf70c A |
756 | lwz r19,FPUcpu(r29) ; Get the last CPU we ran on |
757 | lwz r14,FPUsave(r29) ; Point to the top of the "new" context stack | |
0b4e3aa0 | 758 | |
9bccf70c A |
759 | stw r16,FPUcpu(r29) ; Claim context for us |
760 | eieio | |
0b4e3aa0 | 761 | |
1c79356b | 762 | #if FPVECDBG |
9bccf70c A |
763 | lwz r13,FPUlevel(r29) ; (TEST/DEBUG) |
764 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
765 | li r2,0x7F04 ; (TEST/DEBUG) | |
766 | mr r1,r15 ; (TEST/DEBUG) | |
767 | mr r3,r14 ; (TEST/DEBUG) | |
768 | mr r5,r13 ; (TEST/DEBUG) | |
769 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
770 | sc ; (TEST/DEBUG) | |
1c79356b | 771 | #endif |
9bccf70c | 772 | |
91447636 A |
773 | lis r18,hi16(EXT(PerProcTable)) ; Set base PerProcTable |
774 | mulli r19,r19,ppeSize ; Find offset to the owner per_proc_entry | |
775 | ori r18,r18,lo16(EXT(PerProcTable)) ; Set base PerProcTable | |
9bccf70c | 776 | li r16,FPUowner ; Displacement to float owner |
91447636 A |
777 | add r19,r18,r19 ; Point to the owner per_proc_entry |
778 | lwz r19,ppe_vaddr(r19) ; Point to the owner per_proc | |
9bccf70c A |
779 | |
780 | fsinvothr: lwarx r18,r16,r19 ; Get the owner | |
55e303ae A |
781 | sub r0,r18,r29 ; Subtract one from the other |
782 | sub r11,r29,r18 ; Subtract the other from the one | |
783 | or r11,r11,r0 ; Combine them | |
784 | srawi r11,r11,31 ; Get a 0 if equal or -1 of not | |
785 | and r18,r18,r11 ; Make 0 if same, unchanged if not | |
786 | stwcx. r18,r16,r19 ; Try to invalidate it | |
787 | bne-- fsinvothr ; Try again if there was a collision... | |
9bccf70c | 788 | |
55e303ae | 789 | cmplwi cr1,r14,0 ; Do we possibly have some context to load? |
9bccf70c A |
790 | la r11,savefp0(r14) ; Point to first line to bring in |
791 | stw r15,FPUlevel(r29) ; Set the "new" active level | |
792 | eieio | |
793 | stw r29,FPUowner(r26) ; Mark us as having the live context | |
1c79356b | 794 | |
55e303ae | 795 | beq++ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load... |
9bccf70c A |
796 | |
797 | dcbt 0,r11 ; Touch line in | |
798 | ||
9bccf70c | 799 | lwz r0,SAVlevel(r14) ; Get the level of first facility savearea |
b36670ce | 800 | lwz r3,SAVprev+4(r14) ; Get the previous context |
9bccf70c | 801 | cmplw r0,r15 ; Top level correct to load? |
b36670ce | 802 | li r7,0 ; Get the unlock value |
55e303ae | 803 | bne-- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize... |
9bccf70c A |
804 | |
805 | stw r3,FPUsave(r29) ; Pop the context (we will toss the savearea later) | |
1c79356b A |
806 | |
807 | #if FPVECDBG | |
9bccf70c A |
808 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
809 | li r2,0x7F05 ; (TEST/DEBUG) | |
810 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
811 | sc ; (TEST/DEBUG) | |
1c79356b A |
812 | #endif |
813 | ||
b36670ce A |
814 | eieio ; Make sure that these updates make it out |
815 | stw r7,FPUsync(r29) ; Unlock context now that the context save has been removed | |
816 | ||
55e303ae A |
817 | // Note this code is used both by 32- and 128-byte processors. This means six extra DCBTs |
818 | // are executed on a 128-byte machine, but that is better than a mispredicted branch. | |
819 | ||
9bccf70c A |
820 | la r11,savefp4(r14) ; Point to next line |
821 | dcbt 0,r11 ; Touch line in | |
1c79356b A |
822 | lfd f0, savefp0(r14) |
823 | lfd f1,savefp1(r14) | |
1c79356b | 824 | lfd f2,savefp2(r14) |
9bccf70c | 825 | la r11,savefp8(r14) ; Point to next line |
1c79356b | 826 | lfd f3,savefp3(r14) |
9bccf70c | 827 | dcbt 0,r11 ; Touch line in |
1c79356b A |
828 | lfd f4,savefp4(r14) |
829 | lfd f5,savefp5(r14) | |
830 | lfd f6,savefp6(r14) | |
9bccf70c | 831 | la r11,savefp12(r14) ; Point to next line |
1c79356b | 832 | lfd f7,savefp7(r14) |
9bccf70c | 833 | dcbt 0,r11 ; Touch line in |
1c79356b A |
834 | lfd f8,savefp8(r14) |
835 | lfd f9,savefp9(r14) | |
836 | lfd f10,savefp10(r14) | |
9bccf70c | 837 | la r11,savefp16(r14) ; Point to next line |
1c79356b | 838 | lfd f11,savefp11(r14) |
9bccf70c | 839 | dcbt 0,r11 ; Touch line in |
1c79356b A |
840 | lfd f12,savefp12(r14) |
841 | lfd f13,savefp13(r14) | |
842 | lfd f14,savefp14(r14) | |
9bccf70c | 843 | la r11,savefp20(r14) ; Point to next line |
1c79356b | 844 | lfd f15,savefp15(r14) |
9bccf70c | 845 | dcbt 0,r11 ; Touch line in |
1c79356b A |
846 | lfd f16,savefp16(r14) |
847 | lfd f17,savefp17(r14) | |
848 | lfd f18,savefp18(r14) | |
9bccf70c | 849 | la r11,savefp24(r14) ; Point to next line |
1c79356b | 850 | lfd f19,savefp19(r14) |
9bccf70c | 851 | dcbt 0,r11 ; Touch line in |
1c79356b A |
852 | lfd f20,savefp20(r14) |
853 | lfd f21,savefp21(r14) | |
9bccf70c | 854 | la r11,savefp28(r14) ; Point to next line |
1c79356b A |
855 | lfd f22,savefp22(r14) |
856 | lfd f23,savefp23(r14) | |
9bccf70c | 857 | dcbt 0,r11 ; Touch line in |
1c79356b A |
858 | lfd f24,savefp24(r14) |
859 | lfd f25,savefp25(r14) | |
860 | lfd f26,savefp26(r14) | |
861 | lfd f27,savefp27(r14) | |
862 | lfd f28,savefp28(r14) | |
863 | lfd f29,savefp29(r14) | |
864 | lfd f30,savefp30(r14) | |
865 | lfd f31,savefp31(r14) | |
866 | ||
9bccf70c A |
867 | mr r3,r14 ; Get the old savearea (we popped it before) |
868 | bl EXT(save_ret) ; Toss it | |
869 | ||
55e303ae | 870 | fsenable: lwz r8,savesrr1+4(r25) ; Get the msr of the interrupted guy |
9bccf70c | 871 | ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature |
d7e50217 A |
872 | lwz r10,ACT_MACT_SPF(r17) ; Get the act special flags |
873 | lwz r11,spcFlags(r26) ; Get per_proc spec flags cause not in sync with act | |
1c79356b | 874 | oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point |
d7e50217 | 875 | oris r11,r11,hi16(floatUsed|floatCng) ; Set that we used floating point |
9bccf70c | 876 | rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state |
55e303ae A |
877 | stw r8,savesrr1+4(r25) ; Set the msr of the interrupted guy |
878 | mr r3,r25 ; Pass the virtual addres of savearea | |
b4c24cb9 | 879 | beq- fsnuser ; We are not user state... |
9bccf70c | 880 | stw r10,ACT_MACT_SPF(r17) ; Set the activation copy |
d7e50217 | 881 | stw r11,spcFlags(r26) ; Set per_proc copy |
1c79356b A |
882 | |
883 | fsnuser: | |
884 | #if FPVECDBG | |
9bccf70c A |
885 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
886 | li r2,0x7F07 ; (TEST/DEBUG) | |
887 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
888 | sc ; (TEST/DEBUG) | |
1c79356b | 889 | #endif |
1c79356b | 890 | |
9bccf70c | 891 | b EXT(exception_exit) ; Exit to the fray... |
1c79356b A |
892 | |
893 | /* | |
894 | * Initialize the registers to some bogus value | |
895 | */ | |
896 | ||
897 | MakeSureThatNoTerroristsCanHurtUsByGod: | |
0b4e3aa0 | 898 | |
1c79356b | 899 | #if FPVECDBG |
9bccf70c A |
900 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
901 | li r2,0x7F06 ; (TEST/DEBUG) | |
902 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
903 | sc ; (TEST/DEBUG) | |
1c79356b | 904 | #endif |
9bccf70c | 905 | lis r5,hi16(EXT(FloatInit)) ; Get top secret floating point init value address |
b36670ce | 906 | li r7,0 ; Get the unlock value |
9bccf70c | 907 | ori r5,r5,lo16(EXT(FloatInit)) ; Slam bottom |
b36670ce A |
908 | eieio ; Make sure that these updates make it out |
909 | stw r7,FPUsync(r29) ; Unlock it now that the context has been removed | |
910 | ||
9bccf70c A |
911 | lfd f0,0(r5) ; Initialize FP0 |
912 | fmr f1,f0 ; Do them all | |
1c79356b A |
913 | fmr f2,f0 |
914 | fmr f3,f0 | |
915 | fmr f4,f0 | |
916 | fmr f5,f0 | |
917 | fmr f6,f0 | |
918 | fmr f7,f0 | |
919 | fmr f8,f0 | |
920 | fmr f9,f0 | |
921 | fmr f10,f0 | |
922 | fmr f11,f0 | |
923 | fmr f12,f0 | |
924 | fmr f13,f0 | |
925 | fmr f14,f0 | |
926 | fmr f15,f0 | |
927 | fmr f16,f0 | |
928 | fmr f17,f0 | |
1c79356b A |
929 | fmr f18,f0 |
930 | fmr f19,f0 | |
931 | fmr f20,f0 | |
1c79356b A |
932 | fmr f21,f0 |
933 | fmr f22,f0 | |
934 | fmr f23,f0 | |
935 | fmr f24,f0 | |
936 | fmr f25,f0 | |
937 | fmr f26,f0 | |
938 | fmr f27,f0 | |
939 | fmr f28,f0 | |
940 | fmr f29,f0 | |
941 | fmr f30,f0 | |
942 | fmr f31,f0 | |
9bccf70c A |
943 | b fsenable ; Finish setting it all up... |
944 | ||
1c79356b A |
945 | |
946 | ; | |
9bccf70c | 947 | ; We get here when we are switching to the same context at the same level and the context |
b36670ce | 948 | ; is still live. Essentially, all we are doing is turning on the facility. It may have |
9bccf70c A |
949 | ; gotten turned off due to doing a context save for the current level or a context switch |
950 | ; back to the live guy. | |
1c79356b | 951 | ; |
9bccf70c A |
952 | |
953 | .align 5 | |
1c79356b | 954 | |
b36670ce A |
955 | |
956 | fsthesamel: li r7,0 ; Get the unlock value | |
957 | eieio ; Make sure that these updates make it out | |
958 | stw r7,FPUsync(r22) ; Unlock it. | |
959 | ||
9bccf70c | 960 | fsthesame: |
1c79356b | 961 | |
9bccf70c A |
962 | #if FPVECDBG |
963 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
964 | li r2,0x7F0A ; (TEST/DEBUG) | |
965 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
966 | sc ; (TEST/DEBUG) | |
967 | #endif | |
968 | beq- cr1,fsenable ; Not saved yet, nothing to pop, go enable and exit... | |
1c79356b | 969 | |
9bccf70c | 970 | lwz r11,SAVlevel(r30) ; Get the level of top saved context |
55e303ae | 971 | lwz r14,SAVprev+4(r30) ; Get the previous savearea |
1c79356b | 972 | |
9bccf70c | 973 | cmplw r11,r31 ; Are live and saved the same? |
1c79356b | 974 | |
b36670ce | 975 | bne++ fsenable ; Level not the same, nothing to pop, go enable and exit... |
1c79356b | 976 | |
9bccf70c | 977 | mr r3,r30 ; Get the old savearea (we popped it before) |
55e303ae | 978 | stw r14,FPUsave(r22) ; Pop the savearea from the stack |
9bccf70c A |
979 | bl EXT(save_ret) ; Toss it |
980 | b fsenable ; Go enable and exit... | |
981 | ||
b36670ce A |
982 | ; |
983 | ; Note that we need to choke in this code rather than panic because there is no | |
984 | ; stack. | |
985 | ; | |
986 | ||
987 | fswtimeout: lis r0,hi16(Choke) ; Choke code | |
988 | ori r0,r0,lo16(Choke) ; and the rest | |
989 | li r3,failTimeout ; Timeout code | |
990 | sc ; System ABEND | |
991 | ||
992 | fsntimeout: lis r0,hi16(Choke) ; Choke code | |
993 | ori r0,r0,lo16(Choke) ; and the rest | |
994 | li r3,failTimeout ; Timeout code | |
995 | sc ; System ABEND | |
996 | ||
997 | vswtimeout0: | |
998 | lis r0,hi16(Choke) ; Choke code | |
999 | ori r0,r0,lo16(Choke) ; and the rest | |
1000 | li r3,failTimeout ; Timeout code | |
1001 | sc ; System ABEND | |
1002 | ||
1003 | vswtimeout1: | |
1004 | lis r0,hi16(Choke) ; Choke code | |
1005 | ori r0,r0,lo16(Choke) ; and the rest | |
1006 | li r3,failTimeout ; Timeout code | |
1007 | sc ; System ABEND | |
9bccf70c A |
1008 | |
1009 | ; | |
1010 | ; This function invalidates any live floating point context for the passed in facility_context. | |
1011 | ; This is intended to be called just before act_machine_sv_free tosses saveareas. | |
1012 | ; | |
1013 | ||
1014 | .align 5 | |
1015 | .globl EXT(toss_live_fpu) | |
1016 | ||
1017 | LEXT(toss_live_fpu) | |
1018 | ||
55e303ae | 1019 | lis r0,hi16(MASK(MSR_VEC)) ; Get VEC |
9bccf70c | 1020 | mfmsr r9 ; Get the MSR |
55e303ae | 1021 | ori r0,r0,lo16(MASK(MSR_FP)) ; Add in FP |
9bccf70c | 1022 | rlwinm. r8,r9,0,MSR_FP_BIT,MSR_FP_BIT ; Are floats on right now? |
55e303ae A |
1023 | andc r9,r9,r0 ; Force off VEC and FP |
1024 | ori r0,r0,lo16(MASK(MSR_EE)) ; Turn off EE | |
1025 | andc r0,r9,r0 ; Turn off EE now | |
9bccf70c A |
1026 | mtmsr r0 ; No interruptions |
1027 | isync | |
1028 | beq+ tlfnotours ; Floats off, can not be live here... | |
1029 | ||
91447636 A |
1030 | mfsprg r8,1 ; Get the current activation |
1031 | lwz r8,ACT_PER_PROC(r8) ; Get the per_proc block | |
9bccf70c A |
1032 | |
1033 | ; | |
1034 | ; Note that at this point, since floats are on, we are the owner | |
1035 | ; of live state on this processor | |
1c79356b | 1036 | ; |
9bccf70c A |
1037 | |
1038 | lwz r6,FPUowner(r8) ; Get the thread that owns the floats | |
1039 | li r0,0 ; Clear this just in case we need it | |
1040 | cmplw r6,r3 ; Are we tossing our own context? | |
55e303ae | 1041 | bne-- tlfnotours ; Nope... |
9bccf70c | 1042 | |
55e303ae | 1043 | lfd f1,Zero(0) ; Make a 0 |
9bccf70c A |
1044 | mtfsf 0xFF,f1 ; Clear it |
1045 | ||
1046 | tlfnotours: lwz r11,FPUcpu(r3) ; Get the cpu on which we last loaded context | |
91447636 A |
1047 | lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable |
1048 | mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry | |
1049 | ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable | |
9bccf70c | 1050 | li r10,FPUowner ; Displacement to float owner |
91447636 A |
1051 | add r11,r12,r11 ; Point to the owner per_proc_entry |
1052 | lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc | |
9bccf70c A |
1053 | |
1054 | tlfinvothr: lwarx r12,r10,r11 ; Get the owner | |
9bccf70c | 1055 | |
55e303ae A |
1056 | sub r0,r12,r3 ; Subtract one from the other |
1057 | sub r8,r3,r12 ; Subtract the other from the one | |
1058 | or r8,r8,r0 ; Combine them | |
1059 | srawi r8,r8,31 ; Get a 0 if equal or -1 of not | |
1060 | and r12,r12,r8 ; Make 0 if same, unchanged if not | |
1061 | stwcx. r12,r10,r11 ; Try to invalidate it | |
1062 | bne-- tlfinvothr ; Try again if there was a collision... | |
1063 | ||
1064 | mtmsr r9 ; Restore interruptions | |
9bccf70c A |
1065 | isync ; Could be turning off floats here |
1066 | blr ; Leave... | |
1067 | ||
1c79356b A |
1068 | |
1069 | /* | |
1070 | * Altivec stuff is here. The techniques used are pretty identical to | |
1071 | * the floating point. Except that we will honor the VRSAVE register | |
1072 | * settings when loading and restoring registers. | |
1073 | * | |
1074 | * There are two indications of saved VRs: the VRSAVE register and the vrvalid | |
1075 | * mask. VRSAVE is set by the vector user and represents the VRs that they | |
1076 | * say that they are using. The vrvalid mask indicates which vector registers | |
1077 | * are saved in the savearea. Whenever context is saved, it is saved according | |
1078 | * to the VRSAVE register. It is loaded based on VRSAVE anded with | |
1079 | * vrvalid (all other registers are splatted with 0s). This is done because we | |
1080 | * don't want to load any registers we don't have a copy of, we want to set them | |
1081 | * to zero instead. | |
1082 | * | |
9bccf70c A |
1083 | * Note that there are some oddities here when we save a context we are using. |
1084 | * It is really not too cool to do this, but what the hey... Anyway, | |
1085 | * we turn vectors and fpu off before we leave. | |
1086 | * The oddity is that if you use vectors after this, the | |
1087 | * savearea containing the context just saved will go away. So, bottom line is | |
1088 | * that don't use vectors until after you are done with the saved context. | |
1089 | * | |
1c79356b A |
1090 | */ |
1091 | ||
9bccf70c A |
1092 | .align 5 |
1093 | .globl EXT(vec_save) | |
1094 | ||
1095 | LEXT(vec_save) | |
1c79356b | 1096 | |
55e303ae A |
1097 | |
1098 | lis r2,hi16(MASK(MSR_VEC)) ; Get VEC | |
9bccf70c | 1099 | mfmsr r0 ; Get the MSR |
55e303ae A |
1100 | ori r2,r2,lo16(MASK(MSR_FP)) ; Add in FP |
1101 | andc r0,r0,r2 ; Force off VEC and FP | |
1102 | ori r2,r2,lo16(MASK(MSR_EE)) ; Clear EE | |
1103 | andc r2,r0,r2 ; Clear EE for now | |
9bccf70c | 1104 | oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also |
9bccf70c | 1105 | mtmsr r2 ; Set the MSR |
1c79356b A |
1106 | isync |
1107 | ||
91447636 A |
1108 | mfsprg r6,1 ; Get the current activation |
1109 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block | |
9bccf70c A |
1110 | lwz r12,VMXowner(r6) ; Get the context ID for owner |
1111 | ||
1c79356b | 1112 | #if FPVECDBG |
b36670ce | 1113 | mr r11,r6 ; (TEST/DEBUG) |
9bccf70c A |
1114 | mr r7,r0 ; (TEST/DEBUG) |
1115 | li r4,0 ; (TEST/DEBUG) | |
1116 | mr r10,r3 ; (TEST/DEBUG) | |
1117 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
1118 | mr. r3,r12 ; (TEST/DEBUG) | |
1119 | li r2,0x5F00 ; (TEST/DEBUG) | |
1120 | li r5,0 ; (TEST/DEBUG) | |
b36670ce A |
1121 | lwz r6,liveVRS(r6) ; (TEST/DEBUG) |
1122 | beq-- noowneryeu ; (TEST/DEBUG) | |
9bccf70c A |
1123 | lwz r4,VMXlevel(r12) ; (TEST/DEBUG) |
1124 | lwz r5,VMXsave(r12) ; (TEST/DEBUG) | |
1125 | ||
1126 | noowneryeu: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1127 | sc ; (TEST/DEBUG) | |
1128 | mr r0,r7 ; (TEST/DEBUG) | |
1129 | mr r3,r10 ; (TEST/DEBUG) | |
b36670ce | 1130 | mr r6,r11 ; (TEST/DEBUG) |
1c79356b | 1131 | #endif |
9bccf70c A |
1132 | mflr r2 ; Save the return address |
1133 | ||
b36670ce | 1134 | cmplw r3,r12 ; Is the specified context live? |
9bccf70c | 1135 | lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number |
b36670ce | 1136 | bne-- vsret ; We do not own the vector, no save required... |
9bccf70c | 1137 | lwz r9,VMXcpu(r12) ; Get the cpu that context was last on |
9bccf70c | 1138 | |
b36670ce A |
1139 | cmplw r9,r11 ; Was the context for this processor? |
1140 | la r5,VMXsync(r3) ; Point to the sync word | |
1141 | bne-- vsret ; Specified context is not live | |
9bccf70c | 1142 | |
b36670ce A |
1143 | ; |
1144 | ; It looks like we need to save this one. Or possibly toss a saved one if | |
1145 | ; the VRSAVE is 0. | |
1146 | ; | |
1147 | ; First, make sure that the live context block is not mucked with while | |
1148 | ; we are trying to save it on out. Then we will give it the final check. | |
1149 | ; | |
1150 | ||
1151 | lis r9,ha16(EXT(LockTimeOut)) ; Get the high part | |
1152 | mftb r8 ; Get the time now | |
1153 | lwz r9,lo16(EXT(LockTimeOut))(r9) ; Get the timeout value | |
1154 | b vssync0a ; Jump to the lock... | |
9bccf70c A |
1155 | |
1156 | .align 5 | |
1157 | ||
b36670ce A |
1158 | vssync0: li r7,lgKillResv ; Get killing field |
1159 | stwcx. r7,0,r7 ; Kill reservation | |
1160 | ||
1161 | vssync0a: lwz r7,0(r5) ; Sniff the lock | |
1162 | mftb r10 ; Is it time yet? | |
1163 | cmplwi cr1,r7,0 ; Is it locked? | |
1164 | sub r10,r10,r8 ; How long have we been spinning? | |
1165 | cmplw r10,r9 ; Has it been too long? | |
1166 | bgt-- vswtimeout0 ; Way too long, panic... | |
1167 | bne-- cr1,vssync0a ; Yea, still locked so sniff harder... | |
1168 | ||
1169 | vssync1: lwarx r7,0,r5 ; Get the sync word | |
1170 | li r12,1 ; Get the lock | |
1171 | mr. r7,r7 ; Is it unlocked? | |
1172 | bne-- vssync0 ; No, it is unlocked... | |
1173 | stwcx. r12,0,r5 ; Store lock and test reservation | |
1174 | bne-- vssync1 ; Try again if lost reservation... | |
1175 | ||
1176 | isync ; Toss speculation | |
1177 | ||
1178 | lwz r12,VMXowner(r6) ; Get the context ID for owner | |
1179 | cmplw r3,r12 ; Check again if we own VMX? | |
9bccf70c | 1180 | lwz r10,liveVRS(r6) ; Get the right VRSave register |
b36670ce | 1181 | bne-- vsretlk ; Go unlock and return since we no longer own context |
9bccf70c | 1182 | |
b36670ce A |
1183 | lwz r5,VMXcpu(r12) ; Get the cpu that context was last on |
1184 | lwz r7,VMXsave(r12) ; Get the current vector savearea for the thread | |
1185 | cmplwi cr1,r10,0 ; Is VRsave set to 0? | |
1186 | cmplw r5,r11 ; Is this for the same processor? | |
1187 | lwz r9,VMXlevel(r12) ; Get our current level indicator | |
1188 | bne-- vsretlk ; Not the same processor, skip any save... | |
9bccf70c | 1189 | |
b36670ce A |
1190 | cmplwi r7,0 ; Have we ever saved this facility context? |
1191 | beq-- vsneedone ; Never saved it, so we need an area... | |
9bccf70c | 1192 | |
b36670ce A |
1193 | lwz r8,SAVlevel(r7) ; Get the level this savearea is for |
1194 | cmplw r9,r8 ; Correct level? | |
1195 | bne-- vsneedone ; Different level, so we need to save... | |
1c79356b | 1196 | |
b36670ce | 1197 | bne++ cr1,vsretlk ; VRsave is non-zero so we need to keep what is saved... |
0b4e3aa0 | 1198 | |
b36670ce A |
1199 | lwz r4,SAVprev+4(r7) ; Pick up the previous area |
1200 | li r5,0 ; Assume we just dumped the last | |
1201 | mr. r4,r4 ; Is there one? | |
9bccf70c | 1202 | stw r4,VMXsave(r12) ; Dequeue this savearea |
b36670ce A |
1203 | beq-- vsnomore ; We do not have another... |
1204 | ||
1205 | lwz r5,SAVlevel(r4) ; Get the level associated with save | |
1206 | ||
1207 | vsnomore: stw r5,VMXlevel(r12) ; Save the level | |
1208 | li r7,0 ; Clear | |
1209 | stw r7,VMXowner(r6) ; Show no live context here | |
9bccf70c | 1210 | |
55e303ae | 1211 | vsbackout: mr r4,r0 ; restore the saved MSR |
b36670ce A |
1212 | eieio |
1213 | stw r7,VMXsync(r12) ; Unlock the context | |
1214 | ||
55e303ae | 1215 | b EXT(save_ret_wMSR) ; Toss the savearea and return from there... |
9bccf70c A |
1216 | |
1217 | .align 5 | |
1218 | ||
b36670ce | 1219 | vsneedone: beq-- cr1,vsclrlive ; VRSave is zero, go blow away the context... |
9bccf70c A |
1220 | |
1221 | bl EXT(save_get) ; Get a savearea for the context | |
1222 | ||
91447636 A |
1223 | mfsprg r6,1 ; Get the current activation |
1224 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block | |
9bccf70c A |
1225 | li r4,SAVvector ; Get vector tag |
1226 | lwz r12,VMXowner(r6) ; Get back our context ID | |
1227 | stb r4,SAVflags+2(r3) ; Mark this savearea as a vector | |
1228 | mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it... | |
b36670ce A |
1229 | li r7,0 ; Clear |
1230 | beq-- vsbackout ; If disowned, just toss savearea... | |
9bccf70c | 1231 | lwz r4,facAct(r12) ; Get the activation associated with live context |
9bccf70c A |
1232 | lwz r8,VMXsave(r12) ; Get the current top vector savearea |
1233 | stw r4,SAVact(r3) ; Indicate the right activation for this context | |
1234 | lwz r9,VMXlevel(r12) ; Get our current level indicator again | |
1235 | stw r3,VMXsave(r12) ; Set this as the most current floating point context | |
55e303ae | 1236 | stw r8,SAVprev+4(r3) ; And then chain this in front |
9bccf70c A |
1237 | |
1238 | stw r9,SAVlevel(r3) ; Set level in savearea | |
55e303ae A |
1239 | mfcr r12 ; save CRs across call to vr_store |
1240 | lwz r10,liveVRS(r6) ; Get the right VRSave register | |
1241 | ||
1242 | bl vr_store ; store live VRs into savearea as required (uses r4-r11) | |
9bccf70c | 1243 | |
b36670ce | 1244 | mfsprg r6,1 ; Get the current activation |
55e303ae | 1245 | mtcrf 255,r12 ; Restore the non-volatile CRs |
b36670ce A |
1246 | lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block |
1247 | mtlr r2 ; Restore return address | |
1248 | lwz r12,VMXowner(r6) ; Get back our context ID | |
1249 | ||
1250 | vsretlk: li r7,0 ; Get the unlock value | |
1251 | eieio ; Make sure that these updates make it out | |
1252 | stw r7,VMXsync(r12) ; Unlock it | |
55e303ae A |
1253 | |
1254 | vsret: mtmsr r0 ; Put interrupts on if they were and vector off | |
1c79356b A |
1255 | isync |
1256 | ||
1257 | blr | |
1258 | ||
b36670ce A |
1259 | vsclrlive: li r7,0 ; Clear |
1260 | stw r7,VMXowner(r6) ; Show no live context here | |
1261 | b vsretlk ; Go unlock and leave... | |
1262 | ||
1c79356b A |
1263 | /* |
1264 | * vec_switch() | |
1265 | * | |
1266 | * Entered to handle the vector unavailable exception and | |
1267 | * switch vector context | |
1268 | * | |
1269 | * This code is run with virtual address mode on and interrupts off. | |
1270 | * | |
1271 | * Upon exit, the code returns to the users context with the vector | |
1272 | * facility turned on. | |
1273 | * | |
1274 | * ENTRY: VM switched ON | |
1275 | * Interrupts OFF | |
1276 | * State is saved in savearea pointed to by R4. | |
1277 | * All other registers are free. | |
1278 | * | |
1279 | */ | |
1280 | ||
9bccf70c A |
1281 | .align 5 |
1282 | .globl EXT(vec_switch) | |
1283 | ||
1284 | LEXT(vec_switch) | |
1c79356b A |
1285 | |
1286 | #if DEBUG | |
1c79356b A |
1287 | lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter |
1288 | ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter | |
1289 | lwz r1,0(r3) | |
1290 | addi r1,r1,1 | |
1291 | stw r1,0(r3) | |
1c79356b A |
1292 | #endif /* DEBUG */ |
1293 | ||
91447636 A |
1294 | mfsprg r17,1 ; Get the current activation |
1295 | lwz r26,ACT_PER_PROC(r17) ; Get the per_proc block | |
55e303ae | 1296 | mfmsr r19 ; Get the current MSR |
1c79356b | 1297 | |
9bccf70c | 1298 | mr r25,r4 ; Save the entry savearea |
9bccf70c | 1299 | oris r19,r19,hi16(MASK(MSR_VEC)) ; Enable the vector feature |
55e303ae | 1300 | lwz r22,VMXowner(r26) ; Get the thread that owns the vector |
9bccf70c A |
1301 | |
1302 | mtmsr r19 ; Enable vector instructions | |
1c79356b A |
1303 | isync |
1304 | ||
9bccf70c A |
1305 | lwz r27,ACT_MACT_PCB(r17) ; Get the current level |
1306 | lwz r29,curctx(r17) ; Grab the current context anchor of the current thread | |
0b4e3aa0 | 1307 | |
9bccf70c A |
1308 | ; R22 has the "old" context anchor |
1309 | ; R29 has the "new" context anchor | |
0b4e3aa0 | 1310 | |
1c79356b | 1311 | #if FPVECDBG |
9bccf70c A |
1312 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) |
1313 | li r2,0x5F01 ; (TEST/DEBUG) | |
1314 | mr r3,r22 ; (TEST/DEBUG) | |
1315 | mr r5,r29 ; (TEST/DEBUG) | |
b36670ce | 1316 | lwz r6,liveVRS(r26) ; (TEST/DEBUG) |
9bccf70c A |
1317 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) |
1318 | sc ; (TEST/DEBUG) | |
1c79356b A |
1319 | #endif |
1320 | ||
9bccf70c | 1321 | lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number |
1c79356b | 1322 | |
b36670ce A |
1323 | mr. r22,r22 ; See if there is any live vector status |
1324 | la r15,VMXsync(r22) ; Point to the sync word | |
1c79356b | 1325 | |
b36670ce | 1326 | beq-- vswnosave ; No live context, so nothing to save... |
1c79356b | 1327 | |
9bccf70c | 1328 | lwz r18,VMXcpu(r22) ; Get the last CPU we ran on |
b36670ce A |
1329 | cmplw cr2,r22,r29 ; Are both old and new the same context? |
1330 | lwz r30,VMXsave(r22) ; Get the top savearea | |
9bccf70c | 1331 | cmplwi cr1,r30,0 ; Anything saved yet? |
9bccf70c | 1332 | lwz r31,VMXlevel(r22) ; Get the context level |
b36670ce | 1333 | cmplw r18,r16 ; Make sure we are on the right processor |
1c79356b | 1334 | |
9bccf70c A |
1335 | lwz r10,liveVRS(r26) ; Get the right VRSave register |
1336 | ||
b36670ce | 1337 | bne-- vswnosave ; No, not on the same processor... |
9bccf70c | 1338 | |
1c79356b | 1339 | ; |
9bccf70c A |
1340 | ; Check to see if the live context has already been saved. |
1341 | ; Also check to see if all we are here just to re-enable the MSR | |
1342 | ; and handle specially if so. | |
1c79356b | 1343 | ; |
9bccf70c A |
1344 | |
1345 | cmplw r31,r27 ; See if the current and active levels are the same | |
b36670ce A |
1346 | crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same |
1347 | ||
1348 | beq-- vswthesame ; New and old are the same, just go enable... | |
1349 | ||
1350 | ; | |
1351 | ; Make sure that the live context block is not mucked with while | |
1352 | ; we are trying to save it on out | |
1353 | ; | |
1354 | ||
1355 | lis r11,ha16(EXT(LockTimeOut)) ; Get the high part | |
1356 | mftb r3 ; Get the time now | |
1357 | lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value | |
1358 | b vswsync0a ; Jump to the lock... | |
1359 | ||
1360 | .align 5 | |
1c79356b | 1361 | |
b36670ce A |
1362 | vswsync0: li r19,lgKillResv ; Get killing field |
1363 | stwcx. r19,0,r19 ; Kill reservation | |
1364 | ||
1365 | vswsync0a: lwz r19,0(r15) ; Sniff the lock | |
1366 | mftb r18 ; Is it time yet? | |
1367 | cmplwi cr1,r19,0 ; Is it locked? | |
1368 | sub r18,r18,r3 ; How long have we been spinning? | |
1369 | cmplw r18,r11 ; Has it been too long? | |
1370 | bgt-- vswtimeout0 ; Way too long, panic... | |
1371 | bne-- cr1,vswsync0a ; Yea, still locked so sniff harder... | |
1372 | ||
1373 | vswsync1: lwarx r19,0,r15 ; Get the sync word | |
1374 | li r0,1 ; Get the lock | |
1375 | mr. r19,r19 ; Is it unlocked? | |
1376 | bne-- vswsync0 | |
1377 | stwcx. r0,0,r15 ; Store lock and test reservation | |
1378 | bne-- vswsync1 ; Try again if lost reservation... | |
1379 | ||
1380 | isync ; Toss speculation | |
1381 | ||
1382 | ; | |
1383 | ; Note that now that we have the lock, we need to check if anything changed. | |
1384 | ; Also note that the possible changes are limited. The context owner can | |
1385 | ; never change to a different thread or level although it can be invalidated. | |
1386 | ; A new context can not be pushed on top of us, but it can be popped. The | |
1387 | ; cpu indicator will always change if another processor mucked with any | |
1388 | ; contexts. | |
1389 | ; | |
1390 | ; It should be very rare that any of the context stuff changes across the lock. | |
1391 | ; | |
9bccf70c | 1392 | |
b36670ce A |
1393 | lwz r0,VMXowner(r26) ; Get the thread that owns the vectors again |
1394 | lwz r11,VMXsave(r22) ; Get the top savearea again | |
1395 | lwz r18,VMXcpu(r22) ; Get the last CPU we ran on again | |
1396 | sub r0,r0,r22 ; Non-zero if we lost ownership, 0 if not | |
1397 | xor r11,r11,r30 ; Non-zero if saved context changed, 0 if not | |
1398 | xor r18,r18,r16 ; Non-zero if cpu changed, 0 if not | |
1399 | cmplwi cr1,r30,0 ; Is anything saved? | |
1400 | or r0,r0,r11 ; Zero only if both owner and context are unchanged | |
1401 | or. r0,r0,r18 ; Zero only if nothing has changed | |
9bccf70c | 1402 | cmplwi cr2,r10,0 ; Check VRSave to see if we really need to save anything... |
b36670ce A |
1403 | li r8,0 ; Clear |
1404 | ||
1405 | bne-- vswnosavelk ; Something has changed, so this is not ours to save... | |
1406 | beq-- cr1,vswmstsave ; There is no context saved yet... | |
1c79356b | 1407 | |
9bccf70c | 1408 | lwz r11,SAVlevel(r30) ; Get the level of top saved context |
1c79356b | 1409 | |
9bccf70c A |
1410 | cmplw r31,r11 ; Are live and saved the same? |
1411 | ||
1c79356b | 1412 | #if FPVECDBG |
9bccf70c A |
1413 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
1414 | li r2,0x5F02 ; (TEST/DEBUG) | |
1415 | mr r3,r30 ; (TEST/DEBUG) | |
1416 | mr r5,r31 ; (TEST/DEBUG) | |
1417 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1418 | sc ; (TEST/DEBUG) | |
1c79356b | 1419 | #endif |
9bccf70c | 1420 | |
b36670ce A |
1421 | beq++ vswnosavelk ; Same level, already saved... |
1422 | bne-- cr2,vswnosavelk ; Live context saved and VRSave not 0, no save and keep context... | |
1c79356b | 1423 | |
55e303ae | 1424 | lwz r4,SAVprev+4(r30) ; Pick up the previous area |
9bccf70c A |
1425 | li r5,0 ; Assume this is the only one (which should be the ususal case) |
1426 | mr. r4,r4 ; Was this the only one? | |
1427 | stw r4,VMXsave(r22) ; Dequeue this savearea | |
b36670ce | 1428 | beq++ vswonlyone ; This was the only one... |
9bccf70c A |
1429 | lwz r5,SAVlevel(r4) ; Get the level associated with previous save |
1430 | ||
b36670ce | 1431 | vswonlyone: stw r5,VMXlevel(r22) ; Save the level |
9bccf70c | 1432 | stw r8,VMXowner(r26) ; Clear owner |
b36670ce | 1433 | |
9bccf70c A |
1434 | mr r3,r30 ; Copy the savearea we are tossing |
1435 | bl EXT(save_ret) ; Toss the savearea | |
b36670ce | 1436 | b vswnosavelk ; Go load up the context... |
9bccf70c A |
1437 | |
1438 | .align 5 | |
1c79356b | 1439 | |
b36670ce A |
1440 | vswmstsave: stw r8,VMXowner(r26) ; Clear owner |
1441 | beq-- cr2,vswnosavelk ; The VRSave was 0, so there is nothing to save... | |
9bccf70c A |
1442 | |
1443 | bl EXT(save_get) ; Go get a savearea | |
1444 | ||
b36670ce | 1445 | lwz r12,facAct(r22) ; Get the activation associated with the context |
55e303ae | 1446 | stw r3,VMXsave(r22) ; Set this as the latest context savearea for the thread |
55e303ae | 1447 | stw r30,SAVprev+4(r3) ; Point us to the old context |
9bccf70c A |
1448 | stw r31,SAVlevel(r3) ; Tag our level |
1449 | li r7,SAVvector ; Get the vector ID | |
1450 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
1451 | stb r7,SAVflags+2(r3) ; Set that we have a vector save area | |
1c79356b | 1452 | |
1c79356b | 1453 | #if FPVECDBG |
9bccf70c A |
1454 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
1455 | li r2,0x5F03 ; (TEST/DEBUG) | |
1456 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1457 | sc ; (TEST/DEBUG) | |
1c79356b A |
1458 | #endif |
1459 | ||
9bccf70c | 1460 | lwz r10,liveVRS(r26) ; Get the right VRSave register |
55e303ae | 1461 | bl vr_store ; store VRs into savearea according to vrsave (uses r4-r11) |
1c79356b | 1462 | |
9bccf70c A |
1463 | ; |
1464 | ; The context is all saved now and the facility is free. | |
1465 | ; | |
b36670ce | 1466 | ; Check if we need to fill the registers with junk, because this level has |
9bccf70c A |
1467 | ; never used them before and some thieving bastard could hack the old values |
1468 | ; of some thread! Just imagine what would happen if they could! Why, nothing | |
1469 | ; would be safe! My God! It is terrifying! | |
1470 | ; | |
1471 | ; Also, along the way, thanks to Ian Ollmann, we generate the 0x7FFFDEAD (QNaNbarbarian) | |
1472 | ; constant that we may need to fill unused vector registers. | |
1473 | ; | |
b36670ce A |
1474 | ; Make sure that the live context block is not mucked with while |
1475 | ; we are trying to load it up | |
1476 | ; | |
1c79356b | 1477 | |
b36670ce A |
1478 | vswnosavelk: |
1479 | li r7,0 ; Get the unlock value | |
1480 | eieio ; Make sure that these updates make it out | |
1481 | stw r7,VMXsync(r22) ; Unlock the old context | |
1482 | ||
1483 | vswnosave: la r15,VMXsync(r29) ; Point to the sync word | |
1484 | lis r11,ha16(EXT(LockTimeOut)) ; Get the high part | |
1485 | mftb r3 ; Get the time now | |
1486 | lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value | |
1487 | b vswnsync0a ; Jump to the lock... | |
1488 | ||
1489 | .align 5 | |
1490 | ||
1491 | vswnsync0: li r19,lgKillResv ; Get killing field | |
1492 | stwcx. r19,0,r19 ; Kill reservation | |
0b4e3aa0 | 1493 | |
b36670ce A |
1494 | vswnsync0a: lwz r19,0(r15) ; Sniff the lock |
1495 | mftb r18 ; Is it time yet? | |
1496 | cmplwi cr1,r19,0 ; Is it locked? | |
1497 | sub r18,r18,r3 ; How long have we been spinning? | |
1498 | cmplw r18,r11 ; Has it been too long? | |
1499 | bgt-- vswtimeout1 ; Way too long, panic... | |
1500 | bne-- cr1,vswnsync0a ; Yea, still locked so sniff harder... | |
0b4e3aa0 | 1501 | |
b36670ce A |
1502 | vswnsync1: lwarx r19,0,r15 ; Get the sync word |
1503 | li r0,1 ; Get the lock | |
1504 | mr. r19,r19 ; Is it unlocked? | |
1505 | bne-- vswnsync0 ; Unfortunately, it is locked... | |
1506 | stwcx. r0,0,r15 ; Store lock and test reservation | |
1507 | bne-- vswnsync1 ; Try again if lost reservation... | |
1508 | ||
1509 | isync ; Toss speculation | |
0b4e3aa0 | 1510 | |
b36670ce | 1511 | vspltisb v31,-10 ; Get 0xF6F6F6F6 |
9bccf70c A |
1512 | lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one |
1513 | vspltisb v30,5 ; Get 0x05050505 | |
1514 | lwz r19,VMXcpu(r29) ; Get the last CPU we ran on | |
1515 | vspltish v29,4 ; Get 0x00040004 | |
1516 | lwz r14,VMXsave(r29) ; Point to the top of the "new" context stack | |
1517 | vrlb v31,v31,v30 ; Get 0xDEDEDEDE | |
1518 | ||
1519 | stw r16,VMXcpu(r29) ; Claim context for us | |
1520 | eieio | |
1c79356b A |
1521 | |
1522 | #if FPVECDBG | |
9bccf70c A |
1523 | lwz r13,VMXlevel(r29) ; (TEST/DEBUG) |
1524 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
1525 | li r2,0x5F04 ; (TEST/DEBUG) | |
1526 | mr r1,r15 ; (TEST/DEBUG) | |
1527 | mr r3,r14 ; (TEST/DEBUG) | |
1528 | mr r5,r13 ; (TEST/DEBUG) | |
1529 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1530 | sc ; (TEST/DEBUG) | |
1c79356b | 1531 | #endif |
9bccf70c | 1532 | |
91447636 | 1533 | lis r18,hi16(EXT(PerProcTable)) ; Set base PerProcTable |
9bccf70c | 1534 | vspltisb v28,-2 ; Get 0xFEFEFEFE |
91447636 | 1535 | mulli r19,r19,ppeSize ; Find offset to the owner per_proc_entry |
9bccf70c | 1536 | vsubuhm v31,v31,v29 ; Get 0xDEDADEDA |
91447636 | 1537 | ori r18,r18,lo16(EXT(PerProcTable)) ; Set base PerProcTable |
9bccf70c A |
1538 | vpkpx v30,v28,v3 ; Get 0x7FFF7FFF |
1539 | li r16,VMXowner ; Displacement to vector owner | |
91447636 A |
1540 | add r19,r18,r19 ; Point to the owner per_proc_entry |
1541 | lwz r19,ppe_vaddr(r19) ; Point to the owner per_proc | |
9bccf70c | 1542 | vrlb v31,v31,v29 ; Get 0xDEADDEAD |
9bccf70c | 1543 | |
b36670ce | 1544 | vswinvothr: lwarx r18,r16,r19 ; Get the owner |
55e303ae A |
1545 | |
1546 | sub r0,r18,r29 ; Subtract one from the other | |
1547 | sub r11,r29,r18 ; Subtract the other from the one | |
1548 | or r11,r11,r0 ; Combine them | |
1549 | srawi r11,r11,31 ; Get a 0 if equal or -1 of not | |
1550 | and r18,r18,r11 ; Make 0 if same, unchanged if not | |
1551 | stwcx. r18,r16,r19 ; Try to invalidate it | |
b36670ce | 1552 | bne-- vswinvothr ; Try again if there was a collision... |
9bccf70c | 1553 | |
55e303ae | 1554 | cmplwi cr1,r14,0 ; Do we possibly have some context to load? |
9bccf70c A |
1555 | vmrghh v31,v30,v31 ; Get 0x7FFFDEAD. V31 keeps this value until the bitter end |
1556 | stw r15,VMXlevel(r29) ; Set the "new" active level | |
1557 | eieio | |
1558 | stw r29,VMXowner(r26) ; Mark us as having the live context | |
1c79356b | 1559 | |
55e303ae | 1560 | beq-- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... |
9bccf70c | 1561 | |
55e303ae | 1562 | lwz r3,SAVprev+4(r14) ; Get the previous context |
9bccf70c A |
1563 | lwz r0,SAVlevel(r14) ; Get the level of first facility savearea |
1564 | cmplw r0,r15 ; Top level correct to load? | |
55e303ae | 1565 | bne-- ProtectTheAmericanWay ; No, go initialize... |
1c79356b | 1566 | |
9bccf70c A |
1567 | stw r3,VMXsave(r29) ; Pop the context (we will toss the savearea later) |
1568 | ||
1c79356b | 1569 | #if FPVECDBG |
9bccf70c A |
1570 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
1571 | li r2,0x5F05 ; (TEST/DEBUG) | |
1572 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1573 | sc ; (TEST/DEBUG) | |
1c79356b A |
1574 | #endif |
1575 | ||
de355530 | 1576 | lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea |
55e303ae | 1577 | lwz r22,savevrsave(r25) ; Get the most current VRSAVE |
9bccf70c | 1578 | and r10,r10,r22 ; Figure out just what registers need to be loaded |
55e303ae A |
1579 | mr r3,r14 ; r3 <- ptr to savearea with VRs |
1580 | bl vr_load ; load VRs from save area based on vrsave in r10 | |
1581 | ||
1582 | bl EXT(save_ret) ; Toss the save area after loading VRs | |
b36670ce A |
1583 | |
1584 | vrenablelk: li r7,0 ; Get the unlock value | |
1585 | eieio ; Make sure that these updates make it out | |
1586 | stw r7,VMXsync(r29) ; Unlock the new context | |
de355530 | 1587 | |
55e303ae | 1588 | vrenable: lwz r8,savesrr1+4(r25) ; Get the msr of the interrupted guy |
9bccf70c | 1589 | oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility |
d7e50217 A |
1590 | lwz r10,ACT_MACT_SPF(r17) ; Get the act special flags |
1591 | lwz r11,spcFlags(r26) ; Get per_proc spec flags cause not in sync with act | |
1c79356b | 1592 | oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors |
d7e50217 | 1593 | oris r11,r11,hi16(vectorUsed|vectorCng) ; Set that we used vectors |
9bccf70c | 1594 | rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state |
55e303ae A |
1595 | stw r8,savesrr1+4(r25) ; Set the msr of the interrupted guy |
1596 | mr r3,r25 ; Pass virtual address of the savearea | |
b4c24cb9 | 1597 | beq- vrnuser ; We are not user state... |
9bccf70c | 1598 | stw r10,ACT_MACT_SPF(r17) ; Set the activation copy |
d7e50217 | 1599 | stw r11,spcFlags(r26) ; Set per_proc copy |
1c79356b A |
1600 | |
1601 | vrnuser: | |
1602 | #if FPVECDBG | |
9bccf70c A |
1603 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
1604 | li r2,0x5F07 ; (TEST/DEBUG) | |
1605 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1606 | sc ; (TEST/DEBUG) | |
1c79356b | 1607 | #endif |
9bccf70c | 1608 | b EXT(exception_exit) ; Exit to the fray... |
1c79356b A |
1609 | |
1610 | /* | |
1611 | * Initialize the registers to some bogus value | |
1c79356b A |
1612 | */ |
1613 | ||
1614 | ProtectTheAmericanWay: | |
1615 | ||
1616 | #if FPVECDBG | |
9bccf70c A |
1617 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) |
1618 | li r2,0x5F06 ; (TEST/DEBUG) | |
1619 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1620 | sc ; (TEST/DEBUG) | |
1c79356b | 1621 | #endif |
9bccf70c A |
1622 | |
1623 | vor v0,v31,v31 ; Copy into the next register | |
1624 | vor v1,v31,v31 ; Copy into the next register | |
1625 | vor v2,v31,v31 ; Copy into the next register | |
1626 | vor v3,v31,v31 ; Copy into the next register | |
1627 | vor v4,v31,v31 ; Copy into the next register | |
1628 | vor v5,v31,v31 ; Copy into the next register | |
1629 | vor v6,v31,v31 ; Copy into the next register | |
1630 | vor v7,v31,v31 ; Copy into the next register | |
1631 | vor v8,v31,v31 ; Copy into the next register | |
1632 | vor v9,v31,v31 ; Copy into the next register | |
1633 | vor v10,v31,v31 ; Copy into the next register | |
1634 | vor v11,v31,v31 ; Copy into the next register | |
1635 | vor v12,v31,v31 ; Copy into the next register | |
1636 | vor v13,v31,v31 ; Copy into the next register | |
1637 | vor v14,v31,v31 ; Copy into the next register | |
1638 | vor v15,v31,v31 ; Copy into the next register | |
1639 | vor v16,v31,v31 ; Copy into the next register | |
1640 | vor v17,v31,v31 ; Copy into the next register | |
1641 | vor v18,v31,v31 ; Copy into the next register | |
1642 | vor v19,v31,v31 ; Copy into the next register | |
1643 | vor v20,v31,v31 ; Copy into the next register | |
1644 | vor v21,v31,v31 ; Copy into the next register | |
1645 | vor v22,v31,v31 ; Copy into the next register | |
1646 | vor v23,v31,v31 ; Copy into the next register | |
1647 | vor v24,v31,v31 ; Copy into the next register | |
1648 | vor v25,v31,v31 ; Copy into the next register | |
1649 | vor v26,v31,v31 ; Copy into the next register | |
1650 | vor v27,v31,v31 ; Copy into the next register | |
1651 | vor v28,v31,v31 ; Copy into the next register | |
1652 | vor v29,v31,v31 ; Copy into the next register | |
1653 | vor v30,v31,v31 ; Copy into the next register | |
b36670ce | 1654 | b vrenablelk ; Finish setting it all up... |
9bccf70c A |
1655 | |
1656 | ||
1657 | ||
1658 | ; | |
1659 | ; We get here when we are switching to the same context at the same level and the context | |
1660 | ; is still live. Essentially, all we are doing is turning on the faility. It may have | |
1661 | ; gotten turned off due to doing a context save for the current level or a context switch | |
1662 | ; back to the live guy. | |
1663 | ; | |
1664 | ||
1665 | .align 5 | |
1666 | ||
b36670ce | 1667 | vswthesame: |
9bccf70c A |
1668 | |
1669 | #if FPVECDBG | |
1670 | lis r0,hi16(CutTrace) ; (TEST/DEBUG) | |
1671 | li r2,0x5F0A ; (TEST/DEBUG) | |
1672 | oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) | |
1673 | sc ; (TEST/DEBUG) | |
1674 | #endif | |
1675 | beq- cr1,vrenable ; Not saved yet, nothing to pop, go enable and exit... | |
1676 | ||
1677 | lwz r11,SAVlevel(r30) ; Get the level of top saved context | |
55e303ae | 1678 | lwz r14,SAVprev+4(r30) ; Get the previous savearea |
9bccf70c A |
1679 | |
1680 | cmplw r11,r31 ; Are live and saved the same? | |
1681 | ||
1682 | bne+ vrenable ; Level not the same, nothing to pop, go enable and exit... | |
1683 | ||
1684 | mr r3,r30 ; Get the old savearea (we popped it before) | |
55e303ae | 1685 | stw r11,VMXsave(r22) ; Pop the vector stack |
9bccf70c A |
1686 | bl EXT(save_ret) ; Toss it |
1687 | b vrenable ; Go enable and exit... | |
1688 | ||
1689 | ||
1690 | ; | |
1691 | ; This function invalidates any live vector context for the passed in facility_context. | |
1692 | ; This is intended to be called just before act_machine_sv_free tosses saveareas. | |
1c79356b | 1693 | ; |
1c79356b | 1694 | |
9bccf70c A |
1695 | .align 5 |
1696 | .globl EXT(toss_live_vec) | |
1c79356b | 1697 | |
9bccf70c A |
1698 | LEXT(toss_live_vec) |
1699 | ||
55e303ae | 1700 | lis r0,hi16(MASK(MSR_VEC)) ; Get VEC |
9bccf70c | 1701 | mfmsr r9 ; Get the MSR |
55e303ae A |
1702 | ori r0,r0,lo16(MASK(MSR_FP)) ; Add in FP |
1703 | rlwinm. r8,r9,0,MSR_VEC_BIT,MSR_VEC_BIT ; Are vectors on right now? | |
1704 | andc r9,r9,r0 ; Force off VEC and FP | |
1705 | ori r0,r0,lo16(MASK(MSR_EE)) ; Turn off EE | |
1706 | andc r0,r9,r0 ; Turn off EE now | |
9bccf70c A |
1707 | mtmsr r0 ; No interruptions |
1708 | isync | |
1709 | beq+ tlvnotours ; Vector off, can not be live here... | |
1c79356b | 1710 | |
91447636 A |
1711 | mfsprg r8,1 ; Get the current activation |
1712 | lwz r8,ACT_PER_PROC(r8) ; Get the per_proc block | |
9bccf70c A |
1713 | |
1714 | ; | |
1715 | ; Note that at this point, since vecs are on, we are the owner | |
1716 | ; of live state on this processor | |
1717 | ; | |
1718 | ||
1719 | lwz r6,VMXowner(r8) ; Get the thread that owns the vector | |
1720 | li r0,0 ; Clear this just in case we need it | |
1721 | cmplw r6,r3 ; Are we tossing our own context? | |
1722 | bne- tlvnotours ; Nope... | |
1723 | ||
1724 | vspltish v1,1 ; Turn on the non-Java bit and saturate | |
1725 | vspltisw v0,1 ; Turn on the saturate bit | |
1726 | vxor v1,v1,v0 ; Turn off saturate | |
1727 | mtspr vrsave,r0 ; Clear VRSAVE | |
1728 | mtvscr v1 ; Set the non-java, no saturate status | |
1729 | ||
1730 | tlvnotours: lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context | |
91447636 A |
1731 | lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable |
1732 | mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry | |
1733 | ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable | |
9bccf70c | 1734 | li r10,VMXowner ; Displacement to vector owner |
91447636 A |
1735 | add r11,r12,r11 ; Point to the owner per_proc_entry |
1736 | lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc | |
9bccf70c A |
1737 | li r0,0 ; Set a 0 to invalidate context |
1738 | ||
1739 | tlvinvothr: lwarx r12,r10,r11 ; Get the owner | |
9bccf70c | 1740 | |
55e303ae A |
1741 | sub r0,r12,r3 ; Subtract one from the other |
1742 | sub r8,r3,r12 ; Subtract the other from the one | |
1743 | or r8,r8,r0 ; Combine them | |
1744 | srawi r8,r8,31 ; Get a 0 if equal or -1 of not | |
1745 | and r12,r12,r8 ; Make 0 if same, unchanged if not | |
1746 | stwcx. r12,r10,r11 ; Try to invalidate it | |
1747 | bne-- tlvinvothr ; Try again if there was a collision... | |
1748 | ||
1749 | mtmsr r9 ; Restore interruptions | |
9bccf70c A |
1750 | isync ; Could be turning off vectors here |
1751 | blr ; Leave.... | |
1752 | ||
1753 | #if 0 | |
1754 | ; | |
1755 | ; This function invalidates any live vector context for the passed in facility_context | |
1756 | ; if the level is current. It also tosses the corresponding savearea if there is one. | |
1757 | ; This function is primarily used whenever we detect a VRSave that is all zeros. | |
1758 | ; | |
1759 | ||
1760 | .align 5 | |
1761 | .globl EXT(vec_trash) | |
1762 | ||
1763 | LEXT(vec_trash) | |
1764 | ||
1765 | lwz r12,facAct(r3) ; Get the activation | |
1766 | lwz r11,VMXlevel(r3) ; Get the context level | |
1767 | lwz r10,ACT_MACT_PCB(r12) ; Grab the current level for the thread | |
1768 | lwz r9,VMXsave(r3) ; Get the savearea, if any | |
1769 | cmplw r10,r11 ; Are we at the right level? | |
1770 | cmplwi cr1,r9,0 ; Remember if there is a savearea | |
1771 | bnelr+ ; No, we do nothing... | |
1772 | ||
1773 | lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context | |
91447636 A |
1774 | lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable |
1775 | mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry | |
1776 | ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable | |
9bccf70c | 1777 | li r10,VMXowner ; Displacement to vector owner |
91447636 A |
1778 | add r11,r12,r11 ; Point to the owner per_proc_entry |
1779 | lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc | |
9bccf70c A |
1780 | |
1781 | vtinvothr: lwarx r12,r10,r11 ; Get the owner | |
9bccf70c | 1782 | |
55e303ae A |
1783 | sub r0,r12,r3 ; Subtract one from the other |
1784 | sub r8,r3,r12 ; Subtract the other from the one | |
1785 | or r8,r8,r0 ; Combine them | |
1786 | srawi r8,r8,31 ; Get a 0 if equal or -1 of not | |
1787 | and r12,r12,r8 ; Make 0 if same, unchanged if not | |
1788 | stwcx. r12,r10,r11 ; Try to invalidate it | |
1789 | bne-- vtinvothr ; Try again if there was a collision... | |
1790 | ||
1791 | ||
1792 | beqlr++ cr1 ; Leave if there is no savearea | |
9bccf70c A |
1793 | lwz r8,SAVlevel(r9) ; Get the level of the savearea |
1794 | cmplw r8,r11 ; Savearea for the current level? | |
55e303ae | 1795 | bnelr++ ; No, nothing to release... |
9bccf70c | 1796 | |
55e303ae | 1797 | lwz r8,SAVprev+4(r9) ; Pick up the previous area |
9bccf70c | 1798 | mr. r8,r8 ; Is there a previous? |
55e303ae | 1799 | beq-- vtnoprev ; Nope... |
9bccf70c A |
1800 | lwz r7,SAVlevel(r8) ; Get the level associated with save |
1801 | ||
1802 | vtnoprev: stw r8,VMXsave(r3) ; Dequeue this savearea | |
1803 | stw r7,VMXlevel(r3) ; Pop the level | |
1804 | ||
1805 | mr r3,r9 ; Get the savearea to release | |
1806 | b EXT(save_ret) ; Go and toss the save area (note, we will return from there)... | |
1807 | #endif | |
1808 | ||
1809 | ; | |
1810 | ; Just some test code to force vector and/or floating point in the kernel | |
1811 | ; | |
1812 | ||
1813 | .align 5 | |
1814 | .globl EXT(fctx_test) | |
1c79356b | 1815 | |
9bccf70c A |
1816 | LEXT(fctx_test) |
1817 | ||
55e303ae | 1818 | mfsprg r3,1 ; Get the current thread |
9bccf70c A |
1819 | mr. r3,r3 ; Are we actually up and running? |
1820 | beqlr- ; No... | |
1821 | ||
1822 | fmr f0,f0 ; Use floating point | |
1823 | mftb r4 ; Get time base for a random number | |
1824 | li r5,1 ; Get a potential vrsave to use | |
1825 | andi. r4,r4,0x3F ; Get a number from 0 - 63 | |
1826 | slw r5,r5,r4 ; Choose a register to save (should be 0 half the time) | |
1827 | mtspr vrsave,r5 ; Set VRSave | |
1828 | vor v0,v0,v0 ; Use vectors | |
1829 | blr | |
55e303ae A |
1830 | |
1831 | ||
1832 | // ******************* | |
1833 | // * f p _ s t o r e * | |
1834 | // ******************* | |
1835 | // | |
1836 | // Store FPRs into a save area. Called by fpu_save and fpu_switch. | |
1837 | // | |
1838 | // When called: | |
1839 | // floating pt is enabled | |
1840 | // r3 = ptr to save area | |
1841 | // | |
1842 | // We destroy: | |
1843 | // r11. | |
1844 | ||
1845 | fp_store: | |
1846 | mfsprg r11,2 ; get feature flags | |
1847 | mtcrf 0x02,r11 ; put cache line size bits in cr6 | |
1848 | la r11,savefp0(r3) ; point to 1st line | |
1849 | dcbz128 0,r11 ; establish 1st line no matter what linesize is | |
1850 | bt-- pf32Byteb,fp_st32 ; skip if a 32-byte machine | |
1851 | ||
1852 | // Store the FPRs on a 128-byte machine. | |
1853 | ||
1854 | stfd f0,savefp0(r3) | |
1855 | stfd f1,savefp1(r3) | |
1856 | la r11,savefp16(r3) ; Point to the 2nd cache line | |
1857 | stfd f2,savefp2(r3) | |
1858 | stfd f3,savefp3(r3) | |
1859 | dcbz128 0,r11 ; establish 2nd line | |
1860 | stfd f4,savefp4(r3) | |
1861 | stfd f5,savefp5(r3) | |
1862 | stfd f6,savefp6(r3) | |
1863 | stfd f7,savefp7(r3) | |
1864 | stfd f8,savefp8(r3) | |
1865 | stfd f9,savefp9(r3) | |
1866 | stfd f10,savefp10(r3) | |
1867 | stfd f11,savefp11(r3) | |
1868 | stfd f12,savefp12(r3) | |
1869 | stfd f13,savefp13(r3) | |
1870 | stfd f14,savefp14(r3) | |
1871 | stfd f15,savefp15(r3) | |
1872 | stfd f16,savefp16(r3) | |
1873 | stfd f17,savefp17(r3) | |
1874 | stfd f18,savefp18(r3) | |
1875 | stfd f19,savefp19(r3) | |
1876 | stfd f20,savefp20(r3) | |
1877 | stfd f21,savefp21(r3) | |
1878 | stfd f22,savefp22(r3) | |
1879 | stfd f23,savefp23(r3) | |
1880 | stfd f24,savefp24(r3) | |
1881 | stfd f25,savefp25(r3) | |
1882 | stfd f26,savefp26(r3) | |
1883 | stfd f27,savefp27(r3) | |
1884 | stfd f28,savefp28(r3) | |
1885 | stfd f29,savefp29(r3) | |
1886 | stfd f30,savefp30(r3) | |
1887 | stfd f31,savefp31(r3) | |
1888 | blr | |
1889 | ||
1890 | // Store FPRs on a 32-byte machine. | |
1891 | ||
1892 | fp_st32: | |
1893 | la r11,savefp4(r3) ; Point to the 2nd line | |
1894 | stfd f0,savefp0(r3) | |
1895 | dcbz 0,r11 ; Allocate cache | |
1896 | stfd f1,savefp1(r3) | |
1897 | stfd f2,savefp2(r3) | |
1898 | la r11,savefp8(r3) ; Point to the 3rd line | |
1899 | stfd f3,savefp3(r3) | |
1900 | dcbz 0,r11 ; Allocate cache | |
1901 | stfd f4,savefp4(r3) | |
1902 | stfd f5,savefp5(r3) | |
1903 | stfd f6,savefp6(r3) | |
1904 | la r11,savefp12(r3) ; Point to the 4th line | |
1905 | stfd f7,savefp7(r3) | |
1906 | dcbz 0,r11 ; Allocate cache | |
1907 | stfd f8,savefp8(r3) | |
1908 | stfd f9,savefp9(r3) | |
1909 | stfd f10,savefp10(r3) | |
1910 | la r11,savefp16(r3) ; Point to the 5th line | |
1911 | stfd f11,savefp11(r3) | |
1912 | dcbz 0,r11 ; Allocate cache | |
1913 | stfd f12,savefp12(r3) | |
1914 | stfd f13,savefp13(r3) | |
1915 | stfd f14,savefp14(r3) | |
1916 | la r11,savefp20(r3) ; Point to the 6th line | |
1917 | stfd f15,savefp15(r3) | |
1918 | dcbz 0,r11 ; Allocate cache | |
1919 | stfd f16,savefp16(r3) | |
1920 | stfd f17,savefp17(r3) | |
1921 | stfd f18,savefp18(r3) | |
1922 | la r11,savefp24(r3) ; Point to the 7th line | |
1923 | stfd f19,savefp19(r3) | |
1924 | dcbz 0,r11 ; Allocate cache | |
1925 | stfd f20,savefp20(r3) | |
1926 | ||
1927 | stfd f21,savefp21(r3) | |
1928 | stfd f22,savefp22(r3) | |
1929 | la r11,savefp28(r3) ; Point to the 8th line | |
1930 | stfd f23,savefp23(r3) | |
1931 | dcbz 0,r11 ; allocate it | |
1932 | stfd f24,savefp24(r3) | |
1933 | stfd f25,savefp25(r3) | |
1934 | stfd f26,savefp26(r3) | |
1935 | stfd f27,savefp27(r3) | |
1936 | ||
1937 | stfd f28,savefp28(r3) | |
1938 | stfd f29,savefp29(r3) | |
1939 | stfd f30,savefp30(r3) | |
1940 | stfd f31,savefp31(r3) | |
1941 | blr | |
1942 | ||
1943 | ||
1944 | // ******************* | |
1945 | // * v r _ s t o r e * | |
1946 | // ******************* | |
1947 | // | |
1948 | // Store VRs into savearea, according to bits set in passed vrsave bitfield. This routine is used | |
1949 | // both by vec_save and vec_switch. In order to minimize conditional branches and touching in | |
1950 | // unnecessary cache blocks, we either save all or none of the VRs in a block. We have separate paths | |
1951 | // for each cache block size. | |
1952 | // | |
1953 | // When called: | |
1954 | // interrupts are off, vectors are enabled | |
1955 | // r3 = ptr to save area | |
1956 | // r10 = vrsave (not 0) | |
1957 | // | |
1958 | // We destroy: | |
1959 | // r4 - r11, all CRs. | |
1960 | ||
1961 | vr_store: | |
1962 | mfsprg r9,2 ; get feature flags | |
1963 | stw r10,savevrvalid(r3) ; Save the validity information in savearea | |
1964 | slwi r8,r10,1 ; Shift over 1 | |
1965 | mtcrf 0x02,r9 ; put cache line size bits in cr6 where we can test | |
1966 | or r8,r10,r8 ; r8 <- even bits show which pairs are in use | |
1967 | bt-- pf32Byteb,vr_st32 ; skip if 32-byte cacheline processor | |
1968 | ||
1969 | ||
1970 | ; Save vectors on a 128-byte linesize processor. We save all or none of the 8 registers in each of | |
1971 | ; the four cache lines. This minimizes mispredicted branches yet handles cache lines optimally. | |
1972 | ||
1973 | slwi r7,r8,2 ; shift groups-of-2 over by 2 | |
1974 | li r4,16 ; load offsets for X-form stores | |
1975 | or r8,r7,r8 ; show if any in group of 4 are in use | |
1976 | li r5,32 | |
1977 | slwi r7,r8,4 ; shift groups-of-4 over by 4 | |
1978 | li r6,48 | |
1979 | or r11,r7,r8 ; show if any in group of 8 are in use | |
1980 | li r7,64 | |
1981 | mtcrf 0x80,r11 ; set CRs one at a time (faster) | |
1982 | li r8,80 | |
1983 | mtcrf 0x20,r11 | |
1984 | li r9,96 | |
1985 | mtcrf 0x08,r11 | |
1986 | li r10,112 | |
1987 | mtcrf 0x02,r11 | |
1988 | ||
1989 | bf 0,vr_st64b ; skip if none of vr0-vr7 are in use | |
1990 | la r11,savevr0(r3) ; get address of this group of registers in save area | |
1991 | dcbz128 0,r11 ; zero the line | |
1992 | stvxl v0,0,r11 ; save 8 VRs in the line | |
1993 | stvxl v1,r4,r11 | |
1994 | stvxl v2,r5,r11 | |
1995 | stvxl v3,r6,r11 | |
1996 | stvxl v4,r7,r11 | |
1997 | stvxl v5,r8,r11 | |
1998 | stvxl v6,r9,r11 | |
1999 | stvxl v7,r10,r11 | |
2000 | ||
2001 | vr_st64b: | |
2002 | bf 8,vr_st64c ; skip if none of vr8-vr15 are in use | |
2003 | la r11,savevr8(r3) ; get address of this group of registers in save area | |
2004 | dcbz128 0,r11 ; zero the line | |
2005 | stvxl v8,0,r11 ; save 8 VRs in the line | |
2006 | stvxl v9,r4,r11 | |
2007 | stvxl v10,r5,r11 | |
2008 | stvxl v11,r6,r11 | |
2009 | stvxl v12,r7,r11 | |
2010 | stvxl v13,r8,r11 | |
2011 | stvxl v14,r9,r11 | |
2012 | stvxl v15,r10,r11 | |
2013 | ||
2014 | vr_st64c: | |
2015 | bf 16,vr_st64d ; skip if none of vr16-vr23 are in use | |
2016 | la r11,savevr16(r3) ; get address of this group of registers in save area | |
2017 | dcbz128 0,r11 ; zero the line | |
2018 | stvxl v16,0,r11 ; save 8 VRs in the line | |
2019 | stvxl v17,r4,r11 | |
2020 | stvxl v18,r5,r11 | |
2021 | stvxl v19,r6,r11 | |
2022 | stvxl v20,r7,r11 | |
2023 | stvxl v21,r8,r11 | |
2024 | stvxl v22,r9,r11 | |
2025 | stvxl v23,r10,r11 | |
2026 | ||
2027 | vr_st64d: | |
2028 | bflr 24 ; done if none of vr24-vr31 are in use | |
2029 | la r11,savevr24(r3) ; get address of this group of registers in save area | |
2030 | dcbz128 0,r11 ; zero the line | |
2031 | stvxl v24,0,r11 ; save 8 VRs in the line | |
2032 | stvxl v25,r4,r11 | |
2033 | stvxl v26,r5,r11 | |
2034 | stvxl v27,r6,r11 | |
2035 | stvxl v28,r7,r11 | |
2036 | stvxl v29,r8,r11 | |
2037 | stvxl v30,r9,r11 | |
2038 | stvxl v31,r10,r11 | |
2039 | blr | |
2040 | ||
2041 | ; Save vectors on a 32-byte linesize processor. We save in 16 groups of 2: we either save both | |
2042 | ; or neither in each group. This cuts down on conditional branches. | |
2043 | ; r8 = bitmask with bit n set (for even n) if either of that pair of VRs is in use | |
2044 | ; r3 = savearea | |
2045 | ||
2046 | vr_st32: | |
2047 | mtcrf 0xFF,r8 ; set CR bits so we can branch on them | |
2048 | li r4,16 ; load offset for X-form stores | |
2049 | ||
2050 | bf 0,vr_st32b ; skip if neither VR in this pair is in use | |
2051 | la r11,savevr0(r3) ; get address of this group of registers in save area | |
2052 | dcba 0,r11 ; establish the line wo reading it | |
2053 | stvxl v0,0,r11 ; save the two VRs in the line | |
2054 | stvxl v1,r4,r11 | |
2055 | ||
2056 | vr_st32b: | |
2057 | bf 2,vr_st32c ; skip if neither VR in this pair is in use | |
2058 | la r11,savevr2(r3) ; get address of this group of registers in save area | |
2059 | dcba 0,r11 ; establish the line wo reading it | |
2060 | stvxl v2,0,r11 ; save the two VRs in the line | |
2061 | stvxl v3,r4,r11 | |
2062 | ||
2063 | vr_st32c: | |
2064 | bf 4,vr_st32d ; skip if neither VR in this pair is in use | |
2065 | la r11,savevr4(r3) ; get address of this group of registers in save area | |
2066 | dcba 0,r11 ; establish the line wo reading it | |
2067 | stvxl v4,0,r11 ; save the two VRs in the line | |
2068 | stvxl v5,r4,r11 | |
2069 | ||
2070 | vr_st32d: | |
2071 | bf 6,vr_st32e ; skip if neither VR in this pair is in use | |
2072 | la r11,savevr6(r3) ; get address of this group of registers in save area | |
2073 | dcba 0,r11 ; establish the line wo reading it | |
2074 | stvxl v6,0,r11 ; save the two VRs in the line | |
2075 | stvxl v7,r4,r11 | |
2076 | ||
2077 | vr_st32e: | |
2078 | bf 8,vr_st32f ; skip if neither VR in this pair is in use | |
2079 | la r11,savevr8(r3) ; get address of this group of registers in save area | |
2080 | dcba 0,r11 ; establish the line wo reading it | |
2081 | stvxl v8,0,r11 ; save the two VRs in the line | |
2082 | stvxl v9,r4,r11 | |
2083 | ||
2084 | vr_st32f: | |
2085 | bf 10,vr_st32g ; skip if neither VR in this pair is in use | |
2086 | la r11,savevr10(r3) ; get address of this group of registers in save area | |
2087 | dcba 0,r11 ; establish the line wo reading it | |
2088 | stvxl v10,0,r11 ; save the two VRs in the line | |
2089 | stvxl v11,r4,r11 | |
2090 | ||
2091 | vr_st32g: | |
2092 | bf 12,vr_st32h ; skip if neither VR in this pair is in use | |
2093 | la r11,savevr12(r3) ; get address of this group of registers in save area | |
2094 | dcba 0,r11 ; establish the line wo reading it | |
2095 | stvxl v12,0,r11 ; save the two VRs in the line | |
2096 | stvxl v13,r4,r11 | |
2097 | ||
2098 | vr_st32h: | |
2099 | bf 14,vr_st32i ; skip if neither VR in this pair is in use | |
2100 | la r11,savevr14(r3) ; get address of this group of registers in save area | |
2101 | dcba 0,r11 ; establish the line wo reading it | |
2102 | stvxl v14,0,r11 ; save the two VRs in the line | |
2103 | stvxl v15,r4,r11 | |
2104 | ||
2105 | vr_st32i: | |
2106 | bf 16,vr_st32j ; skip if neither VR in this pair is in use | |
2107 | la r11,savevr16(r3) ; get address of this group of registers in save area | |
2108 | dcba 0,r11 ; establish the line wo reading it | |
2109 | stvxl v16,0,r11 ; save the two VRs in the line | |
2110 | stvxl v17,r4,r11 | |
2111 | ||
2112 | vr_st32j: | |
2113 | bf 18,vr_st32k ; skip if neither VR in this pair is in use | |
2114 | la r11,savevr18(r3) ; get address of this group of registers in save area | |
2115 | dcba 0,r11 ; establish the line wo reading it | |
2116 | stvxl v18,0,r11 ; save the two VRs in the line | |
2117 | stvxl v19,r4,r11 | |
2118 | ||
2119 | vr_st32k: | |
2120 | bf 20,vr_st32l ; skip if neither VR in this pair is in use | |
2121 | la r11,savevr20(r3) ; get address of this group of registers in save area | |
2122 | dcba 0,r11 ; establish the line wo reading it | |
2123 | stvxl v20,0,r11 ; save the two VRs in the line | |
2124 | stvxl v21,r4,r11 | |
2125 | ||
2126 | vr_st32l: | |
2127 | bf 22,vr_st32m ; skip if neither VR in this pair is in use | |
2128 | la r11,savevr22(r3) ; get address of this group of registers in save area | |
2129 | dcba 0,r11 ; establish the line wo reading it | |
2130 | stvxl v22,0,r11 ; save the two VRs in the line | |
2131 | stvxl v23,r4,r11 | |
2132 | ||
2133 | vr_st32m: | |
2134 | bf 24,vr_st32n ; skip if neither VR in this pair is in use | |
2135 | la r11,savevr24(r3) ; get address of this group of registers in save area | |
2136 | dcba 0,r11 ; establish the line wo reading it | |
2137 | stvxl v24,0,r11 ; save the two VRs in the line | |
2138 | stvxl v25,r4,r11 | |
2139 | ||
2140 | vr_st32n: | |
2141 | bf 26,vr_st32o ; skip if neither VR in this pair is in use | |
2142 | la r11,savevr26(r3) ; get address of this group of registers in save area | |
2143 | dcba 0,r11 ; establish the line wo reading it | |
2144 | stvxl v26,0,r11 ; save the two VRs in the line | |
2145 | stvxl v27,r4,r11 | |
2146 | ||
2147 | vr_st32o: | |
2148 | bf 28,vr_st32p ; skip if neither VR in this pair is in use | |
2149 | la r11,savevr28(r3) ; get address of this group of registers in save area | |
2150 | dcba 0,r11 ; establish the line wo reading it | |
2151 | stvxl v28,0,r11 ; save the two VRs in the line | |
2152 | stvxl v29,r4,r11 | |
2153 | ||
2154 | vr_st32p: | |
2155 | bflr 30 ; done if neither VR in this pair is in use | |
2156 | la r11,savevr30(r3) ; get address of this group of registers in save area | |
2157 | dcba 0,r11 ; establish the line wo reading it | |
2158 | stvxl v30,0,r11 ; save the two VRs in the line | |
2159 | stvxl v31,r4,r11 | |
2160 | blr | |
2161 | ||
2162 | ||
2163 | // ***************** | |
2164 | // * v r _ l o a d * | |
2165 | // ***************** | |
2166 | // | |
2167 | // Load live VRs from a savearea, according to bits set in a passed vector. This is the reverse | |
2168 | // of "vr_store". Like it, we avoid touching unnecessary cache blocks and minimize conditional | |
2169 | // branches by loading all VRs from a cache line, if we have to load any. If we don't load the VRs | |
2170 | // in a cache line, we bug them. Note that this behavior is slightly different from earlier kernels, | |
2171 | // which would bug all VRs that aren't live. | |
2172 | // | |
2173 | // When called: | |
2174 | // interrupts are off, vectors are enabled | |
2175 | // r3 = ptr to save area | |
2176 | // r10 = vector of live regs to load (ie, savevrsave & savevrvalid, may be 0) | |
2177 | // v31 = bugbug constant (0x7FFFDEAD7FFFDEAD7FFFDEAD7FFFDEAD) | |
2178 | // | |
2179 | // We destroy: | |
2180 | // r4 - r11, all CRs. | |
2181 | ||
2182 | vr_load: | |
2183 | mfsprg r9,2 ; get feature flags | |
2184 | li r6,1 ; assuming 32-byte, get (#VRs)-1 in a cacheline | |
2185 | mtcrf 0x02,r9 ; set cache line size bits in cr6 | |
2186 | lis r7,0xC000 ; assuming 32-byte, set bits 0-1 | |
2187 | bt-- pf32Byteb,vr_ld0 ; skip if 32-bit processor | |
2188 | li r6,7 ; 128-byte machines have 8 VRs in a cacheline | |
2189 | lis r7,0xFF00 ; so set bits 0-7 | |
2190 | ||
2191 | // Loop touching in cache blocks we will load from. | |
2192 | // r3 = savearea ptr | |
2193 | // r5 = we light bits for the VRs we will be loading | |
2194 | // r6 = 1 if 32-byte, 7 if 128-byte | |
2195 | // r7 = 0xC0000000 if 32-byte, 0xFF000000 if 128-byte | |
2196 | // r10 = live VR bits | |
2197 | // v31 = bugbug constant | |
2198 | ||
2199 | vr_ld0: | |
2200 | li r5,0 ; initialize set of VRs to load | |
2201 | la r11,savevr0(r3) ; get address of register file | |
2202 | b vr_ld2 ; enter loop in middle | |
2203 | ||
2204 | .align 5 | |
2205 | vr_ld1: ; loop over each cache line we will load | |
2206 | dcbt r4,r11 ; start prefetch of the line | |
2207 | andc r10,r10,r9 ; turn off the bits in this line | |
2208 | or r5,r5,r9 ; we will load all these | |
2209 | vr_ld2: ; initial entry pt | |
2210 | cntlzw r4,r10 ; get offset to next live VR | |
2211 | andc r4,r4,r6 ; cacheline align it | |
2212 | srw. r9,r7,r4 ; position bits for VRs in that cache line | |
2213 | slwi r4,r4,4 ; get byte offset within register file to that line | |
2214 | bne vr_ld1 ; loop if more bits in r10 | |
2215 | ||
2216 | bf-- pf128Byteb,vr_ld32 ; skip if not 128-byte lines | |
2217 | ||
2218 | // Handle a processor with 128-byte cache lines. Four groups of 8 VRs. | |
2219 | // r3 = savearea ptr | |
2220 | // r5 = 1st bit in each cacheline is 1 iff any reg in that line must be loaded | |
2221 | // r11 = addr(savevr0) | |
2222 | // v31 = bugbug constant | |
2223 | ||
2224 | mtcrf 0x80,r5 ; set up bits for conditional branches | |
2225 | li r4,16 ; load offsets for X-form stores | |
2226 | li r6,48 | |
2227 | mtcrf 0x20,r5 ; load CRs ona at a time, which is faster | |
2228 | li r7,64 | |
2229 | li r8,80 | |
2230 | mtcrf 0x08,r5 | |
2231 | li r9,96 | |
2232 | li r10,112 | |
2233 | mtcrf 0x02,r5 | |
2234 | li r5,32 | |
2235 | ||
2236 | bt 0,vr_ld128a ; skip if this line must be loaded | |
2237 | vor v0,v31,v31 ; no VR must be loaded, so bug them all | |
2238 | vor v1,v31,v31 | |
2239 | vor v2,v31,v31 | |
2240 | vor v3,v31,v31 | |
2241 | vor v4,v31,v31 | |
2242 | vor v5,v31,v31 | |
2243 | vor v6,v31,v31 | |
2244 | vor v7,v31,v31 | |
2245 | b vr_ld128b | |
2246 | vr_ld128a: ; must load from this line | |
2247 | lvxl v0,0,r11 | |
2248 | lvxl v1,r4,r11 | |
2249 | lvxl v2,r5,r11 | |
2250 | lvxl v3,r6,r11 | |
2251 | lvxl v4,r7,r11 | |
2252 | lvxl v5,r8,r11 | |
2253 | lvxl v6,r9,r11 | |
2254 | lvxl v7,r10,r11 | |
2255 | ||
2256 | vr_ld128b: ; here to handle next cache line | |
2257 | la r11,savevr8(r3) ; load offset to it | |
2258 | bt 8,vr_ld128c ; skip if this line must be loaded | |
2259 | vor v8,v31,v31 ; no VR must be loaded, so bug them all | |
2260 | vor v9,v31,v31 | |
2261 | vor v10,v31,v31 | |
2262 | vor v11,v31,v31 | |
2263 | vor v12,v31,v31 | |
2264 | vor v13,v31,v31 | |
2265 | vor v14,v31,v31 | |
2266 | vor v15,v31,v31 | |
2267 | b vr_ld128d | |
2268 | vr_ld128c: ; must load from this line | |
2269 | lvxl v8,0,r11 | |
2270 | lvxl v9,r4,r11 | |
2271 | lvxl v10,r5,r11 | |
2272 | lvxl v11,r6,r11 | |
2273 | lvxl v12,r7,r11 | |
2274 | lvxl v13,r8,r11 | |
2275 | lvxl v14,r9,r11 | |
2276 | lvxl v15,r10,r11 | |
2277 | ||
2278 | vr_ld128d: ; here to handle next cache line | |
2279 | la r11,savevr16(r3) ; load offset to it | |
2280 | bt 16,vr_ld128e ; skip if this line must be loaded | |
2281 | vor v16,v31,v31 ; no VR must be loaded, so bug them all | |
2282 | vor v17,v31,v31 | |
2283 | vor v18,v31,v31 | |
2284 | vor v19,v31,v31 | |
2285 | vor v20,v31,v31 | |
2286 | vor v21,v31,v31 | |
2287 | vor v22,v31,v31 | |
2288 | vor v23,v31,v31 | |
2289 | b vr_ld128f | |
2290 | vr_ld128e: ; must load from this line | |
2291 | lvxl v16,0,r11 | |
2292 | lvxl v17,r4,r11 | |
2293 | lvxl v18,r5,r11 | |
2294 | lvxl v19,r6,r11 | |
2295 | lvxl v20,r7,r11 | |
2296 | lvxl v21,r8,r11 | |
2297 | lvxl v22,r9,r11 | |
2298 | lvxl v23,r10,r11 | |
2299 | ||
2300 | vr_ld128f: ; here to handle next cache line | |
2301 | la r11,savevr24(r3) ; load offset to it | |
2302 | bt 24,vr_ld128g ; skip if this line must be loaded | |
2303 | vor v24,v31,v31 ; no VR must be loaded, so bug them all | |
2304 | vor v25,v31,v31 | |
2305 | vor v26,v31,v31 | |
2306 | vor v27,v31,v31 | |
2307 | vor v28,v31,v31 | |
2308 | vor v29,v31,v31 | |
2309 | vor v30,v31,v31 | |
2310 | blr | |
2311 | vr_ld128g: ; must load from this line | |
2312 | lvxl v24,0,r11 | |
2313 | lvxl v25,r4,r11 | |
2314 | lvxl v26,r5,r11 | |
2315 | lvxl v27,r6,r11 | |
2316 | lvxl v28,r7,r11 | |
2317 | lvxl v29,r8,r11 | |
2318 | lvxl v30,r9,r11 | |
2319 | lvxl v31,r10,r11 | |
2320 | blr | |
2321 | ||
2322 | // Handle a processor with 32-byte cache lines. Sixteen groups of two VRs. | |
2323 | // r5 = 1st bit in each cacheline is 1 iff any reg in that line must be loaded | |
2324 | // r11 = addr(savevr0) | |
2325 | ||
2326 | vr_ld32: | |
2327 | mtcrf 0xFF,r5 ; set up bits for conditional branches | |
2328 | li r4,16 ; load offset for X-form stores | |
2329 | ||
2330 | bt 0,vr_ld32load0 ; skip if we must load this line | |
2331 | vor v0,v31,v31 ; neither VR is live, so bug them both | |
2332 | vor v1,v31,v31 | |
2333 | b vr_ld32test2 | |
2334 | vr_ld32load0: ; must load VRs in this line | |
2335 | lvxl v0,0,r11 | |
2336 | lvxl v1,r4,r11 | |
2337 | ||
2338 | vr_ld32test2: ; here to handle next cache line | |
2339 | la r11,savevr2(r3) ; get offset to next cache line | |
2340 | bt 2,vr_ld32load2 ; skip if we must load this line | |
2341 | vor v2,v31,v31 ; neither VR is live, so bug them both | |
2342 | vor v3,v31,v31 | |
2343 | b vr_ld32test4 | |
2344 | vr_ld32load2: ; must load VRs in this line | |
2345 | lvxl v2,0,r11 | |
2346 | lvxl v3,r4,r11 | |
2347 | ||
2348 | vr_ld32test4: ; here to handle next cache line | |
2349 | la r11,savevr4(r3) ; get offset to next cache line | |
2350 | bt 4,vr_ld32load4 ; skip if we must load this line | |
2351 | vor v4,v31,v31 ; neither VR is live, so bug them both | |
2352 | vor v5,v31,v31 | |
2353 | b vr_ld32test6 | |
2354 | vr_ld32load4: ; must load VRs in this line | |
2355 | lvxl v4,0,r11 | |
2356 | lvxl v5,r4,r11 | |
2357 | ||
2358 | vr_ld32test6: ; here to handle next cache line | |
2359 | la r11,savevr6(r3) ; get offset to next cache line | |
2360 | bt 6,vr_ld32load6 ; skip if we must load this line | |
2361 | vor v6,v31,v31 ; neither VR is live, so bug them both | |
2362 | vor v7,v31,v31 | |
2363 | b vr_ld32test8 | |
2364 | vr_ld32load6: ; must load VRs in this line | |
2365 | lvxl v6,0,r11 | |
2366 | lvxl v7,r4,r11 | |
2367 | ||
2368 | vr_ld32test8: ; here to handle next cache line | |
2369 | la r11,savevr8(r3) ; get offset to next cache line | |
2370 | bt 8,vr_ld32load8 ; skip if we must load this line | |
2371 | vor v8,v31,v31 ; neither VR is live, so bug them both | |
2372 | vor v9,v31,v31 | |
2373 | b vr_ld32test10 | |
2374 | vr_ld32load8: ; must load VRs in this line | |
2375 | lvxl v8,0,r11 | |
2376 | lvxl v9,r4,r11 | |
2377 | ||
2378 | vr_ld32test10: ; here to handle next cache line | |
2379 | la r11,savevr10(r3) ; get offset to next cache line | |
2380 | bt 10,vr_ld32load10 ; skip if we must load this line | |
2381 | vor v10,v31,v31 ; neither VR is live, so bug them both | |
2382 | vor v11,v31,v31 | |
2383 | b vr_ld32test12 | |
2384 | vr_ld32load10: ; must load VRs in this line | |
2385 | lvxl v10,0,r11 | |
2386 | lvxl v11,r4,r11 | |
2387 | ||
2388 | vr_ld32test12: ; here to handle next cache line | |
2389 | la r11,savevr12(r3) ; get offset to next cache line | |
2390 | bt 12,vr_ld32load12 ; skip if we must load this line | |
2391 | vor v12,v31,v31 ; neither VR is live, so bug them both | |
2392 | vor v13,v31,v31 | |
2393 | b vr_ld32test14 | |
2394 | vr_ld32load12: ; must load VRs in this line | |
2395 | lvxl v12,0,r11 | |
2396 | lvxl v13,r4,r11 | |
2397 | ||
2398 | vr_ld32test14: ; here to handle next cache line | |
2399 | la r11,savevr14(r3) ; get offset to next cache line | |
2400 | bt 14,vr_ld32load14 ; skip if we must load this line | |
2401 | vor v14,v31,v31 ; neither VR is live, so bug them both | |
2402 | vor v15,v31,v31 | |
2403 | b vr_ld32test16 | |
2404 | vr_ld32load14: ; must load VRs in this line | |
2405 | lvxl v14,0,r11 | |
2406 | lvxl v15,r4,r11 | |
2407 | ||
2408 | vr_ld32test16: ; here to handle next cache line | |
2409 | la r11,savevr16(r3) ; get offset to next cache line | |
2410 | bt 16,vr_ld32load16 ; skip if we must load this line | |
2411 | vor v16,v31,v31 ; neither VR is live, so bug them both | |
2412 | vor v17,v31,v31 | |
2413 | b vr_ld32test18 | |
2414 | vr_ld32load16: ; must load VRs in this line | |
2415 | lvxl v16,0,r11 | |
2416 | lvxl v17,r4,r11 | |
2417 | ||
2418 | vr_ld32test18: ; here to handle next cache line | |
2419 | la r11,savevr18(r3) ; get offset to next cache line | |
2420 | bt 18,vr_ld32load18 ; skip if we must load this line | |
2421 | vor v18,v31,v31 ; neither VR is live, so bug them both | |
2422 | vor v19,v31,v31 | |
2423 | b vr_ld32test20 | |
2424 | vr_ld32load18: ; must load VRs in this line | |
2425 | lvxl v18,0,r11 | |
2426 | lvxl v19,r4,r11 | |
2427 | ||
2428 | vr_ld32test20: ; here to handle next cache line | |
2429 | la r11,savevr20(r3) ; get offset to next cache line | |
2430 | bt 20,vr_ld32load20 ; skip if we must load this line | |
2431 | vor v20,v31,v31 ; neither VR is live, so bug them both | |
2432 | vor v21,v31,v31 | |
2433 | b vr_ld32test22 | |
2434 | vr_ld32load20: ; must load VRs in this line | |
2435 | lvxl v20,0,r11 | |
2436 | lvxl v21,r4,r11 | |
2437 | ||
2438 | vr_ld32test22: ; here to handle next cache line | |
2439 | la r11,savevr22(r3) ; get offset to next cache line | |
2440 | bt 22,vr_ld32load22 ; skip if we must load this line | |
2441 | vor v22,v31,v31 ; neither VR is live, so bug them both | |
2442 | vor v23,v31,v31 | |
2443 | b vr_ld32test24 | |
2444 | vr_ld32load22: ; must load VRs in this line | |
2445 | lvxl v22,0,r11 | |
2446 | lvxl v23,r4,r11 | |
2447 | ||
2448 | vr_ld32test24: ; here to handle next cache line | |
2449 | la r11,savevr24(r3) ; get offset to next cache line | |
2450 | bt 24,vr_ld32load24 ; skip if we must load this line | |
2451 | vor v24,v31,v31 ; neither VR is live, so bug them both | |
2452 | vor v25,v31,v31 | |
2453 | b vr_ld32test26 | |
2454 | vr_ld32load24: ; must load VRs in this line | |
2455 | lvxl v24,0,r11 | |
2456 | lvxl v25,r4,r11 | |
2457 | ||
2458 | vr_ld32test26: ; here to handle next cache line | |
2459 | la r11,savevr26(r3) ; get offset to next cache line | |
2460 | bt 26,vr_ld32load26 ; skip if we must load this line | |
2461 | vor v26,v31,v31 ; neither VR is live, so bug them both | |
2462 | vor v27,v31,v31 | |
2463 | b vr_ld32test28 | |
2464 | vr_ld32load26: ; must load VRs in this line | |
2465 | lvxl v26,0,r11 | |
2466 | lvxl v27,r4,r11 | |
2467 | ||
2468 | vr_ld32test28: ; here to handle next cache line | |
2469 | la r11,savevr28(r3) ; get offset to next cache line | |
2470 | bt 28,vr_ld32load28 ; skip if we must load this line | |
2471 | vor v28,v31,v31 ; neither VR is live, so bug them both | |
2472 | vor v29,v31,v31 | |
2473 | b vr_ld32test30 | |
2474 | vr_ld32load28: ; must load VRs in this line | |
2475 | lvxl v28,0,r11 | |
2476 | lvxl v29,r4,r11 | |
2477 | ||
2478 | vr_ld32test30: ; here to handle next cache line | |
2479 | la r11,savevr30(r3) ; get offset to next cache line | |
2480 | bt 30,vr_ld32load30 ; skip if we must load this line | |
2481 | vor v30,v31,v31 ; neither VR is live, so bug them both | |
2482 | blr | |
2483 | vr_ld32load30: ; must load VRs in this line | |
2484 | lvxl v30,0,r11 | |
2485 | lvxl v31,r4,r11 | |
2486 | blr |