]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * @OSF_COPYRIGHT@ | |
24 | */ | |
25 | ||
26 | #include <ppc/asm.h> | |
27 | #include <ppc/proc_reg.h> | |
28 | #include <cpus.h> | |
29 | #include <assym.s> | |
30 | #include <debug.h> | |
31 | #include <mach/ppc/vm_param.h> | |
32 | #include <ppc/exception.h> | |
33 | ||
34 | #define FPVECDBG 0 | |
35 | #define GDDBG 0 | |
36 | ||
37 | .text | |
38 | ||
39 | /* | |
40 | * void load_context(thread_t thread) | |
41 | * | |
42 | * Load the context for the first kernel thread, and go. | |
43 | * | |
44 | * NOTE - if DEBUG is set, the former routine is a piece | |
45 | * of C capable of printing out debug info before calling the latter, | |
46 | * otherwise both entry points are identical. | |
47 | */ | |
48 | ||
49 | ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) | |
50 | ||
51 | /* | |
52 | * Since this is the first thread, we came in on the interrupt | |
53 | * stack. The first thread never returns, so there is no need to | |
54 | * worry about saving its frame, hence we can reset the istackptr | |
55 | * back to the saved_state structure at it's top | |
56 | */ | |
57 | ||
58 | ||
59 | /* | |
60 | * get new thread pointer and set it into the active_threads pointer | |
61 | * | |
62 | */ | |
63 | ||
64 | mfsprg r6,0 | |
65 | lwz r0,PP_INTSTACK_TOP_SS(r6) | |
66 | lwz r11,PP_CPU_DATA(r6) | |
67 | stw r0,PP_ISTACKPTR(r6) | |
68 | stw r3,CPU_ACTIVE_THREAD(r11) | |
69 | ||
70 | /* Find the new stack and store it in active_stacks */ | |
71 | ||
72 | lwz r12,PP_ACTIVE_STACKS(r6) | |
73 | lwz r1,THREAD_KERNEL_STACK(r3) | |
74 | lwz r9,THREAD_TOP_ACT(r3) /* Point to the active activation */ | |
75 | stw r1,0(r12) | |
76 | li r0,0 /* Clear a register */ | |
77 | lwz r8,ACT_MACT_PCB(r9) /* Get the savearea used */ | |
78 | lwz r10,SAVflags(r8) /* Get the savearea flags */ | |
79 | rlwinm r7,r8,0,0,19 /* Switch to savearea base */ | |
80 | lwz r11,SAVprev(r8) /* Get the previous savearea */ | |
81 | mfmsr r5 /* Since we are passing control, get our MSR values */ | |
82 | lwz r1,saver1(r8) /* Load new stack pointer */ | |
83 | rlwinm r10,r10,0,1,31 /* Remove the attached flag */ | |
84 | stw r0,saver3(r8) /* Make sure we pass in a 0 for the continuation */ | |
85 | lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ | |
86 | stw r0,FM_BACKPTR(r1) /* zero backptr */ | |
87 | stw r5,savesrr1(r8) /* Pass our MSR to the new guy */ | |
88 | stw r10,SAVflags(r8) /* Pass back the flags */ | |
89 | xor r3,r7,r8 /* Get the physical address of the new context save area */ | |
90 | stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */ | |
91 | b EXT(exception_exit) /* Go end it all... */ | |
92 | ||
93 | /* struct thread_shuttle *Switch_context(struct thread_shuttle *old, | |
94 | * void (*cont)(void), | |
95 | * struct thread_shuttle *new) | |
96 | * | |
97 | * Switch from one thread to another. If a continuation is supplied, then | |
98 | * we do not need to save callee save registers. | |
99 | * | |
100 | */ | |
101 | ||
102 | /* void Call_continuation( void (*continuation)(void), vm_offset_t stack_ptr) | |
103 | */ | |
104 | ||
105 | ENTRY(Call_continuation, TAG_NO_FRAME_USED) | |
106 | mtlr r3 | |
107 | mr r1, r4 /* Load new stack pointer */ | |
108 | blr /* Jump to the continuation */ | |
109 | ||
110 | /* | |
111 | * Get the old kernel stack, and store into the thread structure. | |
112 | * See if a continuation is supplied, and skip state save if so. | |
113 | * NB. Continuations are no longer used, so this test is omitted, | |
114 | * as should the second argument, but it is in generic code. | |
115 | * We always save state. This does not hurt even if continuations | |
116 | * are put back in. | |
117 | */ | |
118 | ||
119 | /* Context switches are double jumps. We pass the following to the | |
120 | * context switch firmware call: | |
121 | * | |
122 | * R3 = switchee's savearea | |
123 | * R4 = old thread | |
124 | * R5 = new SRR0 | |
125 | * R6 = new SRR1 | |
126 | * | |
127 | * savesrr0 is set to go to switch_in | |
128 | * savesrr1 is set to uninterruptible with translation on | |
129 | */ | |
130 | ||
131 | ||
132 | ENTRY(Switch_context, TAG_NO_FRAME_USED) | |
133 | ||
134 | mfsprg r6,0 /* Get the per_proc block */ | |
135 | lwz r12,PP_ACTIVE_STACKS(r6) | |
136 | #if DEBUG | |
137 | lwz r11,PP_ISTACKPTR(r6) ; (DEBUG/TRACE) make sure we are not | |
138 | mr. r11,r11 ; (DEBUG/TRACE) on the interrupt | |
139 | bne+ notonintstack ; (DEBUG/TRACE) stack | |
140 | BREAKPOINT_TRAP | |
141 | notonintstack: | |
142 | #endif | |
143 | stw r4,THREAD_CONTINUATION(r3) | |
144 | cmpwi cr1,r4,0 /* used waaaay down below */ | |
0b4e3aa0 | 145 | lwz r7,0(r12) |
1c79356b A |
146 | /* |
147 | * Make the new thread the current thread. | |
148 | */ | |
149 | ||
150 | lwz r11,PP_CPU_DATA(r6) | |
0b4e3aa0 | 151 | stw r7,THREAD_KERNEL_STACK(r3) |
1c79356b A |
152 | stw r5, CPU_ACTIVE_THREAD(r11) |
153 | ||
154 | lwz r11,THREAD_KERNEL_STACK(r5) | |
155 | ||
156 | lwz r5,THREAD_TOP_ACT(r5) | |
157 | lwz r10,PP_ACTIVE_STACKS(r6) | |
158 | lwz r7,CTHREAD_SELF(r5) ; Pick up the user assist word | |
0b4e3aa0 | 159 | lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy |
1c79356b A |
160 | |
161 | stw r11,0(r10) ; Save the kernel stack address | |
162 | stw r7,UAW(r6) ; Save the assist word for the "ultra fast path" | |
0b4e3aa0 A |
163 | |
164 | lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment | |
1c79356b A |
165 | |
166 | lwz r7,ACT_MACT_SPF(r5) ; Get the special flags | |
167 | ||
168 | lwz r10,ACT_KLOADED(r5) | |
0b4e3aa0 | 169 | stw r11,ppbbTaskEnv(r6) ; Save the bb task env |
1c79356b A |
170 | li r0,0 |
171 | cmpwi cr0,r10,0 | |
172 | lwz r10,PP_ACTIVE_KLOADED(r6) | |
173 | stw r7,spcFlags(r6) ; Set per_proc copy of the special flags | |
174 | beq cr0,.L_sw_ctx_not_kld | |
175 | ||
176 | stw r5,0(r10) | |
177 | b .L_sw_ctx_cont | |
178 | ||
179 | .L_sw_ctx_not_kld: | |
180 | stw r0,0(r10) /* act_kloaded = 0 */ | |
181 | ||
182 | .L_sw_ctx_cont: | |
183 | lis r10,hi16(EXT(trcWork)) ; Get top of trace mask | |
184 | rlwinm r7,r8,0,0,19 /* Switch to savearea base */ | |
185 | ori r10,r10,lo16(EXT(trcWork)) ; Get bottom of mask | |
186 | lwz r11,SAVprev(r8) /* Get the previous of the switchee's savearea */ | |
187 | lwz r10,traceMask(r10) ; Get the enabled traces | |
188 | lis r0,hi16(CutTrace) ; Trace FW call | |
189 | mr. r10,r10 ; Any tracing going on? | |
190 | ori r0,r0,lo16(CutTrace) ; Trace FW call | |
191 | beq+ cswNoTrc ; No trace today, dude... | |
192 | mr r10,r3 ; Save across trace | |
193 | lwz r2,THREAD_TOP_ACT(r3) ; Trace old activation | |
194 | mr r3,r11 ; Trace prev savearea | |
195 | sc ; Cut trace entry of context switch | |
196 | mr r3,r10 ; Restore | |
197 | ||
198 | cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should inherit it */ | |
199 | lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ | |
200 | lis r0,hi16(SwitchContextCall) /* Top part of switch context */ | |
201 | lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */ | |
202 | stw r11,ACT_MACT_PCB(r5) /* Dequeue the savearea we're switching to */ | |
203 | ||
204 | rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 /* Turn off the FP */ | |
205 | ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */ | |
206 | lwz r5,savesrr0(r8) /* Set up the new SRR0 */ | |
207 | rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 /* Turn off the vector */ | |
208 | mr r4,r3 /* Save our old thread to pass back */ | |
209 | stw r9,savesrr0(r8) /* Make us jump to the switch in routine */ | |
210 | li r10,MSR_SUPERVISOR_INT_OFF /* Get the switcher's MSR */ | |
211 | lwz r9,SAVflags(r8) /* Get the flags */ | |
212 | stw r10,savesrr1(r8) /* Set up for switch in */ | |
213 | rlwinm r9,r9,0,15,13 /* Reset the syscall flag */ | |
214 | ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */ | |
215 | rlwinm r9,r9,0,1,31 /* Clear the attached flag */ | |
216 | xor r3,r7,r8 /* Get the physical address of the new context save area */ | |
217 | stw r9,SAVflags(r8) /* Set the flags */ | |
218 | /* if blocking on continuation avoid saving state */ | |
219 | bne cr1,1f | |
220 | sc /* Switch to the new context */ | |
221 | ||
222 | /* We come back here in the new thread context | |
223 | * R4 was set to hold the old thread pointer, but switch_in will put it into | |
224 | * R3 where it belongs. | |
225 | */ | |
226 | blr /* Jump into the new thread */ | |
227 | ||
228 | 1: stw r5,savesrr0(r8) /* go to real pc */ | |
229 | stw r4,saver3(r8) /* must pass back old thread */ | |
230 | b EXT(exception_exit) /* blocking on continuation, avoid state save */ | |
231 | ||
232 | ||
233 | ||
234 | /* | |
235 | * All switched to threads come here first to clean up the old thread. | |
236 | * We need to do the following contortions because we need to keep | |
237 | * the LR clean. And because we need to manipulate the savearea chain | |
238 | * with translation on. If we could, this should be done in lowmem_vectors | |
239 | * before translation is turned on. But we can't, dang it! | |
240 | * | |
241 | * R3 = switcher's savearea | |
242 | * saver4 = old thread in switcher's save | |
243 | * saver5 = new SRR0 in switcher's save | |
244 | * saver6 = new SRR1 in switcher's save | |
245 | ||
246 | ||
247 | */ | |
248 | ||
249 | ENTRY(switch_in, TAG_NO_FRAME_USED) | |
250 | ||
251 | lwz r4,saver4(r3) /* Get the old thread */ | |
252 | li r8,MSR_VM_OFF /* Set to everything off */ | |
253 | lwz r9,THREAD_TOP_ACT(r4) /* Get the switched from ACT */ | |
254 | lwz r5,saver5(r3) /* Get the srr0 value */ | |
255 | lwz r10,ACT_MACT_PCB(r9) /* Get the top PCB on the old thread */ | |
256 | lwz r6,saver6(r3) /* Get the srr1 value */ | |
257 | ||
258 | stw r3,ACT_MACT_PCB(r9) /* Put the new one on top */ | |
259 | stw r10,SAVprev(r3) /* Chain on the old one */ | |
260 | ||
261 | mr r3,r4 /* Pass back the old thread */ | |
262 | ||
263 | mtsrr0 r5 /* Set return point */ | |
264 | mtsrr1 r6 /* Set return MSR */ | |
265 | rfi /* Jam... */ | |
266 | .long 0 | |
267 | .long 0 | |
268 | .long 0 | |
269 | .long 0 | |
270 | .long 0 | |
271 | .long 0 | |
272 | .long 0 | |
273 | .long 0 | |
274 | ||
275 | ||
276 | ||
277 | /* | |
0b4e3aa0 | 278 | * void fpu_save(thread_act_t act) |
1c79356b A |
279 | * |
280 | * To do the floating point and VMX, we keep three thread pointers: one | |
281 | * to the current thread, one to the thread that has the floating point context | |
282 | * loaded into the FPU registers, and one for the VMX owner. | |
283 | * | |
284 | * Each of these threads has three PCB pointers. The normal PCB, the FPU pcb, | |
285 | * and the VMX pcb. There is also a bit for each in the savearea flags. | |
286 | * When we take an exception, or need to use the FPU/VMX in the kernel, we call | |
287 | * this routine. It checks to see if there is an owner thread for the facility. | |
288 | * If so, it saves the facility's state information in the normal PCB. Then, it | |
289 | * turns on the appropriate flag in the savearea to indicate that the state is | |
290 | * in that particular savearea. Also, the thread pointer for the owner in | |
291 | * the per_processor block is cleared. Note that we don't have to worry about the | |
292 | * PCB pointers in the thread because whenever the state is loaded, the associated | |
293 | * savearea is released and the pointer cleared. This is done so that the facility | |
294 | * context always migrates to the normal savearea/PCB. This always insures that | |
295 | * no more than 2 saveareas are used for a thread. | |
296 | * | |
297 | * When the context is loaded into the facility, the associated PCB is released if | |
298 | * its usage flags indicate that it is empty. (Note that return from exception and | |
299 | * context switch honor these flags and won't release a savearea if there is unrestored | |
300 | * facility context.) The per_processor is set to point to the facility owner's | |
301 | * thread and the associated PCB pointer within the thread is cleared because | |
302 | * the PCB has been released. | |
303 | * | |
304 | * Part of loading a context is to release the savearea. If the savearea contains | |
305 | * other context, the savearea cannot be released. So, what we're left with is | |
306 | * that there will be no normal context savearea, but one for the as-not-yet | |
307 | * restored facility savearea. Again, when that context is reloaded, the PCB | |
308 | * is released, and when it is again stored, it goes into the "normal" savearea. | |
309 | * | |
310 | * So, what do we do when there is no general context, and we have some FPU/VMX | |
311 | * state to save? Heck if I know, but it happens when we switch threads when | |
312 | * we shortcut system calls. The question is: does the target thread carry the | |
313 | * FPU/VMX context with it or not? Actually, it don't matter, not one little bit. | |
314 | * If we are asked to save it, we gotta. It's a really lousy way to do it, but | |
315 | * short of starting over with FPUs, it's what's what. Therefore, we'll | |
316 | * allocate an FPU context save and attach it. | |
317 | * | |
318 | * Actually, it's not quite that simple: since we aren't in | |
319 | * in interrupt handler context (that's only in fpu_switch) we can't use | |
320 | * quickfret to merge FPU into general context. So, if there is an FPU | |
321 | * savearea, we need to use that. So what we do is: if there is FPU context | |
322 | * use that. If there is a general context, then use that. If neither, | |
323 | * allocate a savearea and make that the FPU context. | |
324 | * | |
325 | * The next thing we have to do is to allow the kernel to use both the | |
326 | * floating point and Altivec. It is not recommended, but there may be a | |
327 | * good reason to do so. So, what we need to do is to treat each of the | |
328 | * three types of context the same, by keeping a LIFO chain of states. | |
329 | * We do have a problem with that in that there can be multiple levels of | |
330 | * kernel context. For example, we are using floating point and we take a | |
331 | * page fault, and somehow start using the FPU, and take another page fault, | |
332 | * etc. | |
333 | * | |
334 | * Anyway, we will hope that we only reasonably use floating point and vectors in | |
335 | * the kernel. And try to pack the context in as few saveareas as possible. | |
336 | * | |
337 | * The way we keep these "levels" of floating point or vector context straight is | |
338 | * to remember the top of the normal savearea chain when we activate the | |
339 | * facility when it is first used. Then, when we save that context, this value | |
340 | * is saved in its level field. | |
341 | * | |
342 | * What the level concept gives us is a way to distinguish between multiple | |
343 | * independent contexts under the same thread activation. Any time we take | |
344 | * any kind of interruption (trap, system call, I/O interruption), we are, | |
345 | * in effect, running with a different context even though we are in the | |
346 | * same thread. The top savearea address is used only as a marker. It does not | |
347 | * point to any context associated with the float or vector context. For example, | |
348 | * the top savearea pointer will always be 0 for the user context, because there | |
349 | * it it always last on the list. | |
350 | * | |
351 | * As normal context is unstacked, the first facility context is checked and | |
352 | * if there is a match, the facility savearea is released. This is because we | |
353 | * are returning to a level before the facility saved there was used. In effect, | |
354 | * this allows us to unwind the facility context saveareas at different rates. | |
355 | * | |
356 | * In conjunction with the current activation, these markers are also used to | |
357 | * determine the state of the facility enablement. Whenever the facility context is | |
358 | * "live," i.e., loaded in the hardware registers and belonging to the currently | |
359 | * running context, the facility is enabled before dispatch. | |
360 | * | |
361 | * There is nothing special about using floating point or vector facilities, | |
362 | * no preliminary saving, enabling, or disabling. You just use them. The only exception | |
363 | * is during context switching on an SMP system. In this case, the context must | |
364 | * be saved as there is no guarantee that the thread will resume on the same | |
365 | * processor. This is not a good thing, not at all. | |
366 | * | |
367 | * Whenever we switch out a thread with a dirty context, we always need to save it | |
368 | * because it can wake up on a different processor. However, once the context has | |
369 | * been saved, we don't need to save it again until it gets dirty, nor do we need | |
370 | * to reload it unless someone else's context has been loaded. To handle this | |
371 | * optimization, we need 3 things. We need to know what processor the saved context | |
372 | * was last loaded on, whether the loaded context could be dirty, and if we've already | |
373 | * saved it. | |
374 | * | |
375 | * Whenever the facility is enabled, the processor ID is saved in the activation. This | |
376 | * will show which processor has dirty data. When a context switch occurs, the facility | |
377 | * contexts are saved, but are still remembered as live. The next time we need to | |
378 | * context switch, we first check if the state is live, and if not, do no state | |
379 | * saving. Then we check if the state has already been save and if not, save it. | |
380 | * The facility is always disabled on a context switch. On a UP, this save function | |
381 | * does not occur. | |
382 | * | |
383 | * Whenever a facility unavailable interruption occurs, the current state is saved | |
384 | * if it is live and unsaved. However, if the live state is the same as the new | |
385 | * one to be loaded, the processor ID is checked and if it is the current processor | |
386 | * the state does not need to be loaded or saved. The facility is simply enabled. | |
387 | * | |
388 | * Once allocated, facility saveareas are not released until a return is made to a | |
389 | * previous level. Once a facility has been enabled, there is no way to tell if | |
390 | * it will ever be used again, but it is likely. Therefore, discarding a savearea | |
391 | * when its context is made live is extra overhead. So, we don't do it, but we | |
392 | * do mark the savearea contents as invalid. | |
393 | * | |
394 | */ | |
395 | ||
396 | /* | |
397 | ; The following is the actual way it is implemented. It doesn't quite match | |
398 | ; the above text. I need to go and fix that. | |
399 | ; | |
400 | ; Context download (operates on owner's data): | |
401 | ; | |
402 | ; 0) enable facility | |
403 | ; 1) if no owner exit to context restore | |
404 | ; 2) if context processor != current processor exit to context restore | |
405 | ; 3) if current activation == owner activation: | |
406 | ; 1) if curr level == active level: | |
407 | ; 1) if top facility savearea exists: | |
408 | ; invalidate savearea by setting level to 1 | |
409 | ; 2) enable facility for user | |
410 | ; 3) exit | |
411 | ; | |
412 | ; 2) else go to 5 | |
413 | ; | |
414 | ; 4) if curr level == active level: | |
415 | ; 1) if top facility savearea exists: | |
416 | ; 1) if top save level == active level exit to context restore | |
417 | ; | |
418 | ; 5) allocate savearea | |
419 | ; 1) if there is a facility save and it is invalid, select it, and break | |
420 | ; 2) scan normal list for free facility area, select if found, and break | |
421 | ; 3) scan other facility for free save: select, if found, and break | |
422 | ; 4) allocate a new save area | |
423 | ; | |
424 | ; 6) save context | |
425 | ; 7) mark facility save with curr level | |
426 | ; 8) if reusing cached savearea (case #1) exit to context restore | |
427 | ; 9) set facility save backchain to facility top savearea | |
428 | ; 10) set facility top to savearea | |
429 | ; 11) exit to context restore | |
430 | ; | |
431 | ; | |
432 | ; Context restore/upload (operates on current activation's data): | |
433 | ; | |
434 | ; 1) set current to activation | |
435 | ; 2) set active level to current level | |
436 | ; 3) set context processor to current processor | |
437 | ; 4) if no facility savearea or top save level != curr level | |
438 | ; initialize facility registers to empty value | |
439 | ; 5) else | |
440 | ; 1) load registers from savearea | |
441 | ; 2) invalidate save area by setting level to 1 | |
442 | ; | |
443 | ; 6) enable facility for user | |
444 | ; 7) exit to interrupt return | |
445 | ; | |
446 | ; | |
0b4e3aa0 A |
447 | ; Context save (operates on specified activation's data): |
448 | ||
1c79356b | 449 | ; 1) if no owner exit |
0b4e3aa0 | 450 | ; 2) if owner != specified activation exit |
1c79356b A |
451 | ; 3) if context processor != current processor |
452 | ; 1) clear owner | |
453 | ; 2) exit | |
454 | ; | |
455 | ; 4) if facility top savearea level exists and == active level exit | |
456 | ; 5) if curr level != active level exit | |
457 | ; 6) allocate savearea | |
458 | ; 1) if there is a facility save and it is invalid, select it, and break | |
459 | ; 2) scan normal list for free facility area, select if found, and break | |
460 | ; 3) scan other facility for free save: select, if found, and break | |
461 | ; 4) allocate a new save area | |
462 | ; 7) save context | |
463 | ; 8) mark facility savearea with curr level | |
464 | ; 9) if reusing cached savearea (case #1) exit | |
465 | ; 10) set facility save backchain to facility top savearea | |
466 | ; 11) set facility top to savearea | |
467 | ; 12) exit | |
468 | ; | |
469 | ; | |
470 | ; Exception exit (hw_exceptions): | |
471 | ; | |
472 | ; 1) disable return facility | |
473 | ; 2) if returning savearea != active level | |
474 | ; 1) if owner != current activation exit | |
475 | ; 2) if context processor != current processor: | |
476 | ; 1) clear owner | |
477 | ; 2) exit | |
478 | ; | |
479 | ; 3) if new level != active level exit | |
480 | ; 4) enable return facility | |
481 | ; 5) exit | |
482 | ; | |
483 | ; 3) if no facility savearea exit | |
484 | ; 4) if top save level == active or top is invalid | |
485 | ; 1) dequeue top facility savearea | |
486 | ; 2) set active level to new top savearea's level | |
487 | ; 3) release savearea | |
488 | ; 4) if owner == current activation clear owner | |
489 | ; 5) exit | |
490 | ; | |
491 | ; | |
492 | ; | |
493 | ; | |
494 | ; if (owner == activation) && (curr level == active level) | |
495 | ; && (activation processor == current processor) ::= context live | |
496 | */ | |
497 | ||
498 | ENTRY(fpu_save, TAG_NO_FRAME_USED) | |
499 | ||
500 | mfmsr r0 ; Get the MSR | |
501 | rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point forever | |
502 | rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now | |
503 | ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also | |
504 | mtmsr r2 ; Set the MSR | |
505 | isync | |
506 | ||
507 | mfsprg r6,0 ; Get the per_processor block | |
508 | lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU | |
509 | #if FPVECDBG | |
510 | mr r7,r0 ; (TEST/DEBUG) | |
511 | li r4,0 ; (TEST/DEBUG) | |
0b4e3aa0 | 512 | mr r10,r3 ; (TEST/DEBUG) |
1c79356b A |
513 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) |
514 | mr. r3,r12 ; (TEST/DEBUG) | |
515 | li r2,0x6F00 ; (TEST/DEBUG) | |
516 | li r5,0 ; (TEST/DEBUG) | |
517 | beq- noowneryet ; (TEST/DEBUG) | |
518 | lwz r4,ACT_MACT_FPUlvl(r12) ; (TEST/DEBUG) | |
519 | lwz r5,ACT_MACT_FPU(r12) ; (TEST/DEBUG) | |
520 | ||
521 | noowneryet: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
522 | sc ; (TEST/DEBUG) | |
523 | mr r0,r7 ; (TEST/DEBUG) | |
0b4e3aa0 | 524 | mr r3,r10 ; (TEST/DEBUG) |
1c79356b A |
525 | #endif |
526 | mflr r2 ; Save the return address | |
1c79356b A |
527 | lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number |
528 | ||
529 | mr. r12,r12 ; Anyone own the FPU? | |
0b4e3aa0 | 530 | cmplw cr1,r3,r12 ; Is the specified thread the owner? |
1c79356b | 531 | |
0b4e3aa0 | 532 | beq- fsretnr ; Nobody owns the FPU, no save required... |
1c79356b | 533 | |
0b4e3aa0 A |
534 | li r4,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word |
535 | bne- cr1,fsretnr ; Facility belongs to some other activation... | |
1c79356b | 536 | |
0b4e3aa0 A |
537 | fsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU |
538 | mr. r9,r9 ; Is it changing now? | |
539 | oris r3,r9,hi16(fvChk) ; Set the "changing" flag | |
540 | blt- fsvSpin2 ; Spin if changing | |
541 | stwcx. r3,r4,r12 ; Lock it up | |
542 | bne- fsvSpin2 ; Someone is messing right now | |
543 | ||
544 | isync ; Make sure we see everything | |
1c79356b | 545 | |
1c79356b | 546 | cmplw cr1,r9,r11 ; Was the context for this processor? |
1c79356b A |
547 | li r3,0 ; Assume we need a fix-me-up |
548 | beq- cr1,fsgoodcpu ; Facility last used on this processor... | |
549 | stw r3,PP_FPU_THREAD(r6) ; Clear owner because it was really on the other processor | |
550 | b fsret ; Bail now with no save... | |
551 | ||
552 | fsgoodcpu: lwz r3,ACT_MACT_FPU(r12) ; Get the current FPU savearea for the thread | |
553 | lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator | |
554 | ||
555 | cmplwi cr1,r3,0 ; Have we ever saved this facility context? | |
556 | beq- cr1,fsneedone ; Never saved it, so we need an area... | |
557 | ||
558 | lwz r8,SAVlvlfp(r3) ; Get the level this savearea is for | |
559 | cmplwi r8,1 ; See if it is a spare | |
560 | cmplw cr1,r9,r8 ; Correct level? | |
561 | beq+ fsusespare ; We have a spare to use... | |
562 | beq- cr1,fsret ; The current level is already saved, bail out... | |
563 | ||
564 | fsneedone: li r3,0 ; Tell the routine to allocate an area if none found | |
565 | bl fpsrchsave ; Find a free savearea | |
566 | ||
567 | mfsprg r6,0 ; Get back per_processor block | |
568 | oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit | |
569 | lwz r12,PP_FPU_THREAD(r6) ; Get back our thread | |
570 | mtlr r2 ; Restore return | |
571 | lwz r8,ACT_MACT_FPU(r12) ; Get the current top floating point savearea | |
572 | lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator again | |
573 | stw r3,ACT_MACT_FPU(r12) ; Set this as the latest FPU savearea for the thread | |
574 | stw r8,SAVprefp(r3) ; And then chain this in front | |
575 | stw r7,SAVflags(r3) ; Set the validity flags | |
576 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
577 | ||
578 | fsusespare: stw r9,SAVlvlfp(r3) ; And set the level this savearea is for | |
579 | ||
580 | ; | |
581 | ; Save the current FPU state into the PCB of the thread that owns it. | |
582 | ; | |
583 | ||
584 | la r11,savefp0(r3) ; Point to the 1st line | |
585 | dcbz 0,r11 ; Allocate the first savearea line | |
586 | ||
587 | la r11,savefp4(r3) /* Point to the 2nd line */ | |
588 | stfd f0,savefp0(r3) | |
589 | dcbz 0,r11 /* allocate it */ | |
590 | stfd f1,savefp1(r3) | |
591 | stfd f2,savefp2(r3) | |
592 | la r11,savefp8(r3) /* Point to the 3rd line */ | |
593 | stfd f3,savefp3(r3) | |
594 | dcbz 0,r11 /* allocate it */ | |
595 | stfd f4,savefp4(r3) | |
596 | stfd f5,savefp5(r3) | |
597 | stfd f6,savefp6(r3) | |
598 | la r11,savefp12(r3) /* Point to the 4th line */ | |
599 | stfd f7,savefp7(r3) | |
600 | dcbz 0,r11 /* allocate it */ | |
601 | stfd f8,savefp8(r3) | |
602 | stfd f9,savefp9(r3) | |
603 | stfd f10,savefp10(r3) | |
604 | la r11,savefp16(r3) /* Point to the 5th line */ | |
605 | stfd f11,savefp11(r3) | |
606 | dcbz 0,r11 /* allocate it */ | |
607 | stfd f12,savefp12(r3) | |
608 | stfd f13,savefp13(r3) | |
609 | stfd f14,savefp14(r3) | |
610 | la r11,savefp20(r3) /* Point to the 6th line */ | |
611 | stfd f15,savefp15(r3) | |
612 | stfd f16,savefp16(r3) | |
613 | stfd f17,savefp17(r3) | |
614 | stfd f18,savefp18(r3) | |
615 | la r11,savefp24(r3) /* Point to the 7th line */ | |
616 | stfd f19,savefp19(r3) | |
617 | dcbz 0,r11 /* allocate it */ | |
618 | stfd f20,savefp20(r3) | |
619 | lwz r10,liveFPSCR(r6) ; Get the previously saved FPSCR | |
620 | stfd f21,savefp21(r3) | |
621 | stfd f22,savefp22(r3) | |
622 | li r9,0 ; Just clear this out | |
623 | la r11,savefp28(r3) /* Point to the 8th line */ | |
624 | stfd f23,savefp23(r3) | |
625 | dcbz 0,r11 /* allocate it */ | |
626 | stfd f24,savefp24(r3) | |
627 | stfd f25,savefp25(r3) | |
628 | stfd f26,savefp26(r3) | |
629 | stfd f27,savefp27(r3) | |
630 | stfd f28,savefp28(r3) | |
631 | ||
632 | ; Note that we just save the FPSCR here for ease. It is really already saved | |
633 | ; in the "normal" context area of the savearea. | |
634 | ||
635 | stw r9,savefpscrpad(r3) ; Save the FPSCR pad | |
636 | stw r10,savefpscr(r3) ; Save the FPSCR | |
637 | ||
638 | stfd f29,savefp29(r3) | |
639 | stfd f30,savefp30(r3) | |
640 | stfd f31,savefp31(r3) | |
641 | lfd f0,savefp0(r3) ; We need to restore F0 because we used it | |
642 | ; to get the FPSCR | |
643 | ||
644 | #if 0 | |
645 | la r9,savefp0(r3) ; (TEST/DEBUG) | |
646 | la r10,savefp31(r3) ; (TEST/DEBUG) | |
647 | ||
648 | chkkillmedead: | |
649 | lha r8,0(r9) ; (TEST/DEBUG) | |
650 | addi r9,r9,8 ; (TEST/DEBUG) | |
651 | cmpwi r8,-8 ; (TEST/DEBUG) | |
652 | cmplw cr1,r9,r10 ; (TEST/DEBUG) | |
653 | bne+ dontkillmedead ; (TEST/DEBUG) | |
654 | BREAKPOINT_TRAP ; (TEST/DEBUG) | |
655 | ||
656 | dontkillmedead: ; (TEST/DEBUG) | |
657 | ble+ cr1,chkkillmedead ; (TEST/DEBUG) | |
658 | #endif | |
659 | ||
0b4e3aa0 A |
660 | fsret: lwz r4,ACT_MACT_FPUcpu(r12) ; Get back the owner CPU |
661 | rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock | |
662 | sync | |
663 | stw r4,ACT_MACT_FPUcpu(r12) ; Unlock the context | |
664 | ||
665 | fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off | |
1c79356b A |
666 | isync |
667 | ||
668 | blr | |
669 | ||
670 | /* | |
671 | * fpu_switch() | |
672 | * | |
673 | * Entered to handle the floating-point unavailable exception and | |
674 | * switch fpu context | |
675 | * | |
676 | * This code is run in virtual address mode on with interrupts off. | |
677 | * | |
678 | * Upon exit, the code returns to the users context with the floating | |
679 | * point facility turned on. | |
680 | * | |
681 | * ENTRY: VM switched ON | |
682 | * Interrupts OFF | |
683 | * State is saved in savearea pointed to by R4. | |
684 | * All other registers are free. | |
685 | * | |
686 | */ | |
687 | ||
688 | ENTRY(fpu_switch, TAG_NO_FRAME_USED) | |
689 | #if DEBUG | |
690 | #if GDDBG | |
691 | mr r7,r4 ; Save input parameter | |
692 | lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter | |
693 | ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter | |
694 | lwz r1,0(r3) | |
695 | lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display | |
696 | ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
697 | addi r1,r1,1 | |
698 | mtlr r5 ; Set link register | |
699 | stw r1,0(r3) | |
700 | mr r4,r1 | |
701 | li r3,0 | |
702 | blrl ; Display count | |
703 | mr r4,r7 ; Restore the parameter | |
704 | #else | |
705 | lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter | |
706 | ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter | |
707 | lwz r1,0(r3) | |
708 | addi r1,r1,1 | |
709 | stw r1,0(r3) | |
710 | #endif | |
711 | #endif /* DEBUG */ | |
712 | ||
713 | mfsprg r6,0 ; Get the per_processor block | |
714 | mfmsr r19 ; Get the current MSR | |
715 | ||
716 | lwz r10,PP_CPU_DATA(r6) ; Get the CPU data pointer | |
717 | lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU | |
718 | lwz r10,CPU_ACTIVE_THREAD(r10) ; Get the pointer to the active thread | |
719 | ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature | |
720 | lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running | |
721 | ||
722 | ; R12 has the "old" activation | |
723 | ; R17 has the "new" activation | |
724 | ||
725 | #if FPVECDBG | |
726 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
727 | li r2,0x7F01 ; (TEST/DEBUG) | |
728 | mr r3,r12 ; (TEST/DEBUG) | |
729 | mr r5,r17 ; (TEST/DEBUG) | |
730 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
731 | sc ; (TEST/DEBUG) | |
732 | #endif | |
733 | mr. r12,r12 ; See if there is any live FP status | |
734 | ||
735 | lhz r18,PP_CPU_NUMBER(r6) ; Get the current CPU, we will need it later | |
736 | ||
737 | mtmsr r19 ; Enable floating point instructions | |
738 | isync | |
739 | ||
740 | beq- fsnosave ; No live context, so nothing to save... | |
741 | ||
0b4e3aa0 A |
742 | li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word |
743 | ||
744 | fsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU | |
745 | mr. r19,r19 ; Is it changing now? | |
746 | oris r21,r19,hi16(fvChk) ; Set the "changing" flag | |
747 | blt- fsSpin1 ; Spin if changing | |
748 | stwcx. r21,r20,r12 ; Lock it up | |
749 | bne- fsSpin1 ; Someone is messing right now | |
750 | ||
751 | isync ; Make sure we see everything | |
752 | ||
1c79356b A |
753 | lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one |
754 | cmplw r18,r19 ; Check the CPU that the old context is live on | |
755 | lwz r14,ACT_MACT_FPU(r12) ; Point to the top of the old context stack | |
0b4e3aa0 | 756 | bne- fsnosaverel ; Context is not live if used on a different CPU... |
1c79356b A |
757 | lwz r13,ACT_MACT_FPUlvl(r12) ; Get the "old" active level |
758 | ||
759 | ; | |
760 | ; First, check to see if all we are doing is enabling because the | |
761 | ; "new" context is live. | |
762 | ; | |
763 | #if FPVECDBG | |
764 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
765 | li r2,0x7F02 ; (TEST/DEBUG) | |
766 | mr r1,r15 ; (TEST/DEBUG) | |
767 | mr r3,r13 ; (TEST/DEBUG) | |
768 | mr r5,r14 ; (TEST/DEBUG) | |
769 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
770 | sc ; (TEST/DEBUG) | |
771 | #endif | |
772 | ||
773 | cmplw cr1,r12,r17 ; Are the "old" activation and the "new" the same? | |
774 | cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? | |
775 | bne+ cr1,fsmstsave ; The activations are different so "old" context must be saved... | |
776 | ||
777 | ; | |
778 | ; Here we know that both the "old" and "new" activations are the same. We will | |
779 | ; check the current level and active levels. If they are the same, the context is | |
780 | ; already live, so all we do is turn on the facility and invalidate the top | |
781 | ; savearea. | |
782 | ; | |
783 | ; If the current level, the active level, and the top savearea level are the | |
784 | ; same, then the context was saved as part of a thread context switch and neither | |
785 | ; needs saving or restoration. | |
786 | ; | |
787 | ; In all other cases, the context must be saved unless we are just re-enabling | |
788 | ; floating point. | |
789 | ; | |
790 | ||
791 | cmplw r13,r15 ; Are the levels the same? | |
792 | cmplwi cr2,r14,0 ; Is there any saved context? | |
793 | bne- fsmstsave ; Levels are different, we need to save... | |
794 | ||
0b4e3aa0 | 795 | beq- cr2,fsenableret ; No saved context at all, enable and go... |
1c79356b A |
796 | |
797 | lwz r20,SAVlvlfp(r14) ; Get the level of the top savearea | |
798 | ||
799 | #if FPVECDBG | |
800 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
801 | li r2,0x7F03 ; (TEST/DEBUG) | |
802 | mr r3,r15 ; (TEST/DEBUG) | |
803 | mr r5,r20 ; (TEST/DEBUG) | |
804 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
805 | sc ; (TEST/DEBUG) | |
806 | #endif | |
807 | cmplw r15,r20 ; Is the top level the same as the current? | |
808 | li r0,1 ; Get the invalid flag | |
0b4e3aa0 | 809 | bne- fsenableret ; Not the same, just enable and go... |
1c79356b A |
810 | |
811 | stw r0,SAVlvlfp(r14) ; Invalidate that top savearea | |
0b4e3aa0 A |
812 | fsenableret: |
813 | sync ; Make sure everything is saved | |
814 | stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore | |
1c79356b A |
815 | |
816 | b fsenable ; Then enable and go... | |
817 | ||
818 | ; | |
819 | ; We need to save the "old" context here. The LIFO queueing scheme works | |
820 | ; out for all cases because if both the "new" and "old" activations are the | |
821 | ; same, there can not be any saved state to load. the "new" level is | |
822 | ; truely new. | |
823 | ; | |
824 | ; When we save the context, we either use a new savearea, or the free | |
825 | ; one that is cached at the head of the list. | |
826 | ||
827 | fsmstsave: beq- cr2,fsgetsave ; There is no possible cached save area | |
828 | ||
829 | lwz r5,SAVlvlfp(r14) ; Get the level of first facility savearea | |
830 | #if FPVECDBG | |
831 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
832 | li r2,0x7F04 ; (TEST/DEBUG) | |
833 | mr r3,r15 ; (TEST/DEBUG) | |
834 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
835 | sc ; (TEST/DEBUG) | |
836 | #endif | |
837 | mr r3,r14 ; Assume we are invalid | |
838 | cmplwi r5,1 ; Is it invalid? | |
839 | cmplw cr1,r5,r13 ; Is the SA level the active one? | |
840 | beq+ fsusecache ; Invalid, just use it... | |
0b4e3aa0 | 841 | beq- cr1,fsnosaverel ; The SA level is active, it is already saved... |
1c79356b A |
842 | |
843 | fsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached | |
844 | #if FPVECDBG | |
845 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
846 | li r2,0x7F05 ; (TEST/DEBUG) | |
847 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
848 | sc ; (TEST/DEBUG) | |
849 | #endif | |
850 | ||
851 | bl fpsrchsave ; Find a free savearea | |
852 | ||
853 | stw r3,ACT_MACT_FPU(r12) ; Set this as the latest context savearea for the thread | |
854 | mfsprg r6,0 ; Get back per_processor block | |
855 | stw r14,SAVprefp(r3) ; And then chain this in front | |
856 | oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit | |
857 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
858 | stw r7,SAVflags(r3) ; Set the allocation flags | |
859 | ||
860 | fsusecache: la r11,savefp0(r3) ; Point to the 1st line in area | |
861 | stw r13,SAVlvlfp(r3) ; Set this context level | |
862 | #if FPVECDBG | |
863 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
864 | li r2,0x7F06 ; (TEST/DEBUG) | |
865 | mr r5,r13 ; (TEST/DEBUG) | |
866 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
867 | sc ; (TEST/DEBUG) | |
868 | #endif | |
869 | ||
870 | ; | |
871 | ; Now we will actually save the old context | |
872 | ; | |
873 | ||
874 | dcbz 0,r11 ; Allocate the output area | |
875 | ||
876 | la r11,savefp4(r3) ; Point to the 2nd line | |
877 | stfd f0,savefp0(r3) | |
878 | dcbz 0,r11 ; Allocate cache | |
879 | stfd f1,savefp1(r3) | |
880 | stfd f2,savefp2(r3) | |
881 | la r11,savefp8(r3) ; Point to the 3rd line | |
882 | stfd f3,savefp3(r3) | |
883 | dcbz 0,r11 ; Allocate cache | |
884 | stfd f4,savefp4(r3) | |
885 | stfd f5,savefp5(r3) | |
886 | stfd f6,savefp6(r3) | |
887 | la r11,savefp12(r3) ; Point to the 4th line | |
888 | stfd f7,savefp7(r3) | |
889 | dcbz 0,r11 ; Allocate cache | |
890 | stfd f8,savefp8(r3) | |
891 | stfd f9,savefp9(r3) | |
892 | stfd f10,savefp10(r3) | |
893 | la r11,savefp16(r3) ; Point to the 5th line | |
894 | stfd f11,savefp11(r3) | |
895 | dcbz 0,r11 ; Allocate cache | |
896 | stfd f12,savefp12(r3) | |
897 | stfd f13,savefp13(r3) | |
898 | stfd f14,savefp14(r3) | |
899 | la r11,savefp20(r3) ; Point to the 6th line | |
900 | stfd f15,savefp15(r3) | |
901 | dcbz 0,r11 ; Allocate cache | |
902 | stfd f16,savefp16(r3) | |
903 | stfd f17,savefp17(r3) | |
904 | stfd f18,savefp18(r3) | |
905 | la r11,savefp24(r3) ; Point to the 7th line | |
906 | stfd f19,savefp19(r3) | |
907 | dcbz 0,r11 ; Allocate cache | |
908 | stfd f20,savefp20(r3) | |
909 | ||
910 | li r14,0 ; Clear this for now | |
911 | lwz r15,liveFPSCR(r6) ; Get the previously saved FPSCR | |
912 | ||
913 | stfd f21,savefp21(r3) | |
914 | stfd f22,savefp22(r3) | |
915 | la r11,savefp28(r3) ; Point to the 8th line | |
916 | stfd f23,savefp23(r3) | |
917 | dcbz 0,r11 ; allocate it | |
918 | stfd f24,savefp24(r3) | |
919 | stfd f25,savefp25(r3) | |
920 | stfd f26,savefp26(r3) | |
921 | la r11,savefpscrpad(r3) ; Point to the 9th line | |
922 | stfd f27,savefp27(r3) | |
923 | dcbz 0,r11 ; allocate it | |
924 | stfd f28,savefp28(r3) | |
925 | stfd f29,savefp29(r3) | |
926 | stfd f30,savefp30(r3) | |
927 | stfd f31,savefp31(r3) | |
928 | ||
929 | ; Note that we just save the FPSCR here for ease. It is really already saved | |
930 | ; in the "normal" context area of the savearea. | |
931 | ||
932 | stw r14,savefpscrpad(r3) ; Save the FPSCR pad | |
933 | stw r15,savefpscr(r3) ; Save the FPSCR | |
934 | ||
935 | ; | |
936 | ; The context is all saved now and the facility is free. | |
937 | ; | |
938 | ; Now check out the "new" and see if we need to load up his context. | |
939 | ; If we do (and this should be the normal case), do it and then invalidate the | |
940 | ; savearea. (This will keep it cached for quick access next time around.) | |
941 | ; | |
942 | ; If we do not (remember, we already took care of the case where we just enable | |
943 | ; the FPU), we need to fill the registers with junk, because this level has | |
944 | ; never used them before and some thieving bastard could hack the old values | |
945 | ; of some thread! Just imagine what would happen if they could! Why, nothing | |
946 | ; would be safe! My God! It is terrifying! | |
947 | ; | |
948 | ||
0b4e3aa0 A |
949 | |
950 | fsnosaverel: | |
951 | sync ; Make sure everything is saved | |
952 | stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore | |
1c79356b | 953 | |
0b4e3aa0 A |
954 | fsnosave: |
955 | li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word | |
956 | ||
957 | fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU | |
958 | mr. r19,r19 ; Is it changing now? | |
959 | oris r21,r19,hi16(fvChk) ; Set the "changing" flag | |
960 | blt- fsSpin2 ; Spin if changing | |
961 | stwcx. r21,r20,r17 ; Lock it up | |
962 | bne- fsSpin2 ; Someone is messing right now | |
963 | ||
964 | isync ; Make sure we see everything | |
965 | ||
966 | lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one | |
1c79356b A |
967 | lwz r14,ACT_MACT_FPU(r17) ; Point to the top of the "new" context stack |
968 | lwz r13,ACT_MACT_FPUlvl(r17) ; Get the "new" active level | |
969 | #if FPVECDBG | |
970 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
971 | li r2,0x7F07 ; (TEST/DEBUG) | |
972 | mr r1,r15 ; (TEST/DEBUG) | |
973 | mr r3,r14 ; (TEST/DEBUG) | |
974 | mr r5,r13 ; (TEST/DEBUG) | |
975 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
976 | sc ; (TEST/DEBUG) | |
977 | #endif | |
978 | ||
979 | cmplwi cr1,r14,0 ; Do we possibly have some context to load? | |
980 | stw r15,ACT_MACT_FPUlvl(r17) ; Set the "new" active level | |
1c79356b A |
981 | la r11,savefp0(r14) ; Point to first line to bring in |
982 | stw r17,PP_FPU_THREAD(r6) ; Store current thread address in fpu_thread to claim fpu for thread | |
983 | ||
984 | beq+ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load... | |
985 | lwz r0,SAVlvlfp(r14) ; Get the level of first facility savearea | |
986 | cmplw r0,r15 ; Top level correct to load? | |
987 | bne- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize... | |
988 | ||
989 | #if FPVECDBG | |
990 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
991 | li r2,0x7F08 ; (TEST/DEBUG) | |
992 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
993 | sc ; (TEST/DEBUG) | |
994 | #endif | |
995 | ||
996 | dcbt 0,r11 ; Touch line in | |
997 | li r0,1 ; Get the level invalid indication | |
998 | ||
999 | la r11,savefp4(r14) ; Point to next line | |
1000 | dcbt 0,r11 ; Touch line in | |
1001 | lfd f0, savefp0(r14) | |
1002 | lfd f1,savefp1(r14) | |
1003 | stw r0,SAVlvlfp(r14) ; Mark the savearea invalid because we are activating again | |
1004 | lfd f2,savefp2(r14) | |
1005 | la r11,savefp8(r14) ; Point to next line | |
1006 | lfd f3,savefp3(r14) | |
1007 | dcbt 0,r11 ; Touch line in | |
1008 | lfd f4,savefp4(r14) | |
1009 | lfd f5,savefp5(r14) | |
1010 | lfd f6,savefp6(r14) | |
1011 | la r11,savefp12(r14) ; Point to next line | |
1012 | lfd f7,savefp7(r14) | |
1013 | dcbt 0,r11 ; Touch line in | |
1014 | lfd f8,savefp8(r14) | |
1015 | lfd f9,savefp9(r14) | |
1016 | lfd f10,savefp10(r14) | |
1017 | la r11,savefp16(r14) ; Point to next line | |
1018 | lfd f11,savefp11(r14) | |
1019 | dcbt 0,r11 ; Touch line in | |
1020 | lfd f12,savefp12(r14) | |
1021 | lfd f13,savefp13(r14) | |
1022 | lfd f14,savefp14(r14) | |
1023 | la r11,savefp20(r14) ; Point to next line | |
1024 | lfd f15,savefp15(r14) | |
1025 | dcbt 0,r11 ; Touch line in | |
1026 | lfd f16,savefp16(r14) | |
1027 | lfd f17,savefp17(r14) | |
1028 | lfd f18,savefp18(r14) | |
1029 | la r11,savefp24(r14) ; Point to next line | |
1030 | lfd f19,savefp19(r14) | |
1031 | dcbt 0,r11 ; Touch line in | |
1032 | lfd f20,savefp20(r14) | |
1033 | lfd f21,savefp21(r14) | |
1034 | la r11,savefp28(r14) ; Point to next line | |
1035 | lfd f22,savefp22(r14) | |
1036 | lfd f23,savefp23(r14) | |
1037 | dcbt 0,r11 ; Touch line in | |
1038 | lfd f24,savefp24(r14) | |
1039 | lfd f25,savefp25(r14) | |
1040 | lfd f26,savefp26(r14) | |
1041 | lfd f27,savefp27(r14) | |
1042 | lfd f28,savefp28(r14) | |
1043 | lfd f29,savefp29(r14) | |
1044 | lfd f30,savefp30(r14) | |
1045 | lfd f31,savefp31(r14) | |
1046 | ||
0b4e3aa0 A |
1047 | fsenablexx: sync ; Make sure all is saved |
1048 | stw r18,ACT_MACT_FPUcpu(r17) ; Set the active CPU and release | |
1049 | ||
1c79356b A |
1050 | fsenable: lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ |
1051 | lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy | |
1052 | rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ | |
1053 | ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature | |
1054 | lwz r10,ACT_MACT_SPF(r17) ; Get the special flags | |
1055 | lis r7,hi16(SAVattach) /* Get the attached flag */ | |
1056 | lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ | |
1057 | oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point | |
1058 | mr. r15,r15 ; See if we are doing this for user state | |
1059 | stw r8,savesrr1(r4) ; Set the msr of the interrupted guy | |
1060 | andc r9,r9,r7 /* Clear the attached bit */ | |
1061 | xor r3,r4,r5 /* Get the real address of the savearea */ | |
1062 | bne- fsnuser ; We are not user state... | |
1063 | stw r10,ACT_MACT_SPF(r17) ; Set the activation copy | |
1064 | stw r10,spcFlags(r6) ; Set per_proc copy | |
1065 | ||
1066 | fsnuser: | |
1067 | #if FPVECDBG | |
1068 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1069 | li r2,0x7F0A ; (TEST/DEBUG) | |
1070 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1071 | sc ; (TEST/DEBUG) | |
1072 | #endif | |
1073 | stw r9,SAVflags(r4) /* Set the flags of the current savearea */ | |
1074 | ||
1075 | b EXT(exception_exit) /* Exit from the fray... */ | |
1076 | ||
1077 | /* | |
1078 | * Initialize the registers to some bogus value | |
1079 | */ | |
1080 | ||
1081 | MakeSureThatNoTerroristsCanHurtUsByGod: | |
0b4e3aa0 A |
1082 | |
1083 | #if 0 | |
1084 | lwz r10,savesrr1(r4) ; (TEST/DEBUG) | |
1085 | rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) | |
1086 | beq- nxxxxxx ; (TEST/DEBUG) | |
1087 | lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) | |
1088 | rlwinm. r10,r10,0,1,1 ; (TEST/DEBUG) | |
1089 | beq+ nxxxxxx | |
1090 | BREAKPOINT_TRAP ; (TEST/DEBUG) | |
1091 | nxxxxxx: | |
1092 | #endif | |
1093 | ||
1c79356b A |
1094 | #if FPVECDBG |
1095 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1096 | li r2,0x7F09 ; (TEST/DEBUG) | |
1097 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1098 | sc ; (TEST/DEBUG) | |
1099 | #endif | |
1100 | lis r5,hi16(EXT(FloatInit)) /* Get top secret floating point init value address */ | |
1101 | ori r5,r5,lo16(EXT(FloatInit)) /* Slam bottom */ | |
1102 | lfd f0,0(r5) /* Initialize FP0 */ | |
1103 | fmr f1,f0 ; Do them all | |
1104 | fmr f2,f0 | |
1105 | fmr f3,f0 | |
1106 | fmr f4,f0 | |
1107 | fmr f5,f0 | |
1108 | fmr f6,f0 | |
1109 | fmr f7,f0 | |
1110 | fmr f8,f0 | |
1111 | fmr f9,f0 | |
1112 | fmr f10,f0 | |
1113 | fmr f11,f0 | |
1114 | fmr f12,f0 | |
1115 | fmr f13,f0 | |
1116 | fmr f14,f0 | |
1117 | fmr f15,f0 | |
1118 | fmr f16,f0 | |
1119 | fmr f17,f0 | |
1120 | fsub f31,f31,f31 ; Get set to initialize the FPSCR | |
1121 | fmr f18,f0 | |
1122 | fmr f19,f0 | |
1123 | fmr f20,f0 | |
1124 | mtfsf 0xff,f31 ; Clear all FPSCR exception eanbles | |
1125 | fmr f21,f0 | |
1126 | fmr f22,f0 | |
1127 | fmr f23,f0 | |
1128 | fmr f24,f0 | |
1129 | fmr f25,f0 | |
1130 | fmr f26,f0 | |
1131 | fmr f27,f0 | |
1132 | fmr f28,f0 | |
1133 | fmr f29,f0 | |
1134 | fmr f30,f0 | |
1135 | fmr f31,f0 | |
0b4e3aa0 | 1136 | b fsenablexx ; Finish setting it all up... |
1c79356b A |
1137 | |
1138 | ; | |
1139 | ; Finds an unused floating point area in the activation pointed | |
1140 | ; to by R12s saved contexts. If none are found (unlikely but possible) | |
1141 | ; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains | |
1142 | ; a pointer to an floating point savearea that is free. | |
1143 | ; | |
1144 | fpsrchsave: | |
1145 | lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea | |
1146 | ||
1147 | fpsrnorm: mr. r5,r6 ; Is there another? | |
1148 | beq- fpsrvect ; No, search the vector saveareas... | |
1149 | lwz r7,SAVflags(r5) ; Get the flags for this guy | |
1150 | lwz r6,SAVprev(r5) ; Get the previous savearea, just in case | |
1151 | andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in normal? | |
1152 | beq+ fpsrgot ; We found one... | |
1153 | b fpsrnorm ; Search again... | |
1154 | ||
1155 | fpsrvect: lwz r6,ACT_MACT_VMX(r12) ; Get the first "vector" savearea | |
1156 | ||
1157 | fpsrvectx: mr. r5,r6 ; Is there another? | |
1158 | beq- fpsrget ; No, try to allocate one... | |
1159 | lwz r7,SAVflags(r5) ; Get the flags for this guy | |
1160 | lwz r6,SAVprevec(r5) ; Get the previous savearea, just in case | |
1161 | andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in vector? | |
1162 | bne- fpsrvectx ; Search again... | |
1163 | ||
1164 | fpsrgot: mr r3,r5 ; Get the savearea into the right register | |
1165 | blr ; Return... | |
1166 | ||
1167 | fpsrget: mr. r5,r3 ; Do we allocate or use existing? | |
1168 | beq+ fpsrallo ; Allocate one... | |
1169 | ||
1170 | lwz r7,SAVflags(r3) ; Get the passed in area flags | |
1171 | blr ; Return... | |
1172 | ; | |
1173 | ; NOTE: save_get will return directly and set R7 to 0... | |
1174 | ; | |
1175 | fpsrallo: b EXT(save_get) ; Get a fresh savearea | |
1176 | ||
1177 | /* | |
1178 | * Altivec stuff is here. The techniques used are pretty identical to | |
1179 | * the floating point. Except that we will honor the VRSAVE register | |
1180 | * settings when loading and restoring registers. | |
1181 | * | |
1182 | * There are two indications of saved VRs: the VRSAVE register and the vrvalid | |
1183 | * mask. VRSAVE is set by the vector user and represents the VRs that they | |
1184 | * say that they are using. The vrvalid mask indicates which vector registers | |
1185 | * are saved in the savearea. Whenever context is saved, it is saved according | |
1186 | * to the VRSAVE register. It is loaded based on VRSAVE anded with | |
1187 | * vrvalid (all other registers are splatted with 0s). This is done because we | |
1188 | * don't want to load any registers we don't have a copy of, we want to set them | |
1189 | * to zero instead. | |
1190 | * | |
1191 | */ | |
1192 | ||
1193 | ENTRY(vec_save, TAG_NO_FRAME_USED) | |
1194 | ||
1195 | mfmsr r0 ; Get the MSR | |
1196 | rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector forever | |
1197 | rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now | |
1198 | oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also | |
1199 | mtmsr r2 ; Set the MSR | |
1200 | isync | |
1201 | ||
1202 | mfsprg r6,0 ; Get the per_processor block | |
1203 | lwz r12,PP_VMX_THREAD(r6) ; Get the thread that owns the vector | |
1204 | #if FPVECDBG | |
1205 | mr r7,r0 ; (TEST/DEBUG) | |
1206 | li r4,0 ; (TEST/DEBUG) | |
0b4e3aa0 | 1207 | mr r10,r3 ; (TEST/DEBUG) |
1c79356b A |
1208 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) |
1209 | mr. r3,r12 ; (TEST/DEBUG) | |
1210 | li r2,0x5F00 ; (TEST/DEBUG) | |
1211 | li r5,0 ; (TEST/DEBUG) | |
1212 | beq- noowneryeu ; (TEST/DEBUG) | |
1213 | lwz r4,ACT_MACT_VMXlvl(r12) ; (TEST/DEBUG) | |
1214 | lwz r5,ACT_MACT_VMX(r12) ; (TEST/DEBUG) | |
1215 | ||
1216 | noowneryeu: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1217 | sc ; (TEST/DEBUG) | |
1218 | mr r0,r7 ; (TEST/DEBUG) | |
0b4e3aa0 | 1219 | mr r3,r10 ; (TEST/DEBUG) |
1c79356b A |
1220 | #endif |
1221 | mflr r2 ; Save the return address | |
1c79356b A |
1222 | lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number |
1223 | ||
1224 | mr. r12,r12 ; Anyone own the vector? | |
0b4e3aa0 A |
1225 | cmplw cr1,r3,r12 ; Is the specified thread the owner? |
1226 | ||
1227 | beq- vsretnr ; Nobody owns the vector, no save required... | |
1c79356b | 1228 | |
0b4e3aa0 A |
1229 | li r4,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word |
1230 | bne- cr1,vsretnr ; Facility belongs to some other activation... | |
1c79356b | 1231 | |
0b4e3aa0 A |
1232 | vsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU |
1233 | mr. r9,r9 ; Is it changing now? | |
1234 | oris r3,r9,hi16(fvChk) ; Set the "changing" flag | |
1235 | blt- vsvSpin2 ; Spin if changing | |
1236 | stwcx. r3,r4,r12 ; Lock it up | |
1237 | bne- vsvSpin2 ; Someone is messing right now | |
1238 | ||
1239 | isync ; Make sure we see everything | |
1c79356b | 1240 | |
1c79356b | 1241 | cmplw cr1,r9,r11 ; Was the context for this processor? |
1c79356b A |
1242 | li r3,0 ; Assume we need a fix-me-up |
1243 | beq- cr1,vsgoodcpu ; Facility last used on this processor... | |
1244 | stw r3,PP_VMX_THREAD(r6) ; Clear owner because it was really on the other processor | |
1245 | b vsret ; Bail now with no save... | |
1246 | ||
1247 | vsgoodcpu: lwz r3,ACT_MACT_VMX(r12) ; Get the current vector savearea for the thread | |
1248 | lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator | |
1249 | ||
1250 | cmplwi cr1,r3,0 ; Have we ever saved this facility context? | |
1251 | beq- cr1,vsneedone ; Never saved it, so we need an area... | |
1252 | ||
1253 | lwz r8,SAVlvlvec(r3) ; Get the level this savearea is for | |
1254 | cmplwi r8,1 ; See if this is a spare | |
1255 | cmplw cr1,r9,r8 ; Correct level? | |
1256 | beq+ vsusespare ; It is still live... | |
1257 | beq- cr1,vsret ; The current level is already saved, bail out... | |
1258 | ||
1259 | vsneedone: li r3,0 ; Tell the routine to allocate an area if none found | |
1260 | bl vsrchsave ; Find a free savearea | |
1261 | ||
1262 | mfsprg r6,0 ; Get back per_processor block | |
1263 | oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit | |
1264 | lwz r12,PP_VMX_THREAD(r6) ; Get back our thread | |
1265 | mtlr r2 ; Restore return | |
1266 | lwz r8,ACT_MACT_VMX(r12) ; Get the current top vector savearea | |
1267 | lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator again | |
1268 | stw r3,ACT_MACT_VMX(r12) ; Set this as the latest vector savearea for the thread | |
1269 | stw r8,SAVprevec(r3) ; And then chain this in front | |
1270 | stw r7,SAVflags(r3) ; Set the allocation flags | |
1271 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
1272 | ||
1273 | vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for | |
1274 | mfcr r2 ; Save non-volatile CRs | |
1275 | lwz r10,liveVRS(r6) ; Get the right VRSave register | |
1276 | lis r9,0x5555 ; Mask with odd bits set | |
1277 | rlwinm r11,r10,1,0,31 ; Shift over 1 | |
1278 | ori r9,r9,0x5555 ; Finish mask | |
0b4e3aa0 | 1279 | or r4,r10,r11 ; After this, even bits show which lines to zap |
1c79356b | 1280 | |
0b4e3aa0 | 1281 | andc r11,r4,r9 ; Clear out odd bits |
1c79356b A |
1282 | |
1283 | la r6,savevr0(r3) ; Point to line 0 | |
1284 | rlwinm r4,r11,15,0,15 ; Move line 8-15 flags to high order odd bits | |
1285 | la r9,savevrvalid(r3) ; Point to the saved register mask field | |
1286 | or r4,r11,r4 ; Set the odd bits | |
1287 | ; (bit 0 is line 0, bit 1 is line 8, | |
1288 | ; bit 2 is line 1, bit 3 is line 9, etc. | |
1289 | dcba br0,r9 ; Allocate the cache for it | |
1290 | rlwimi r4,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 | |
1291 | la r7,savevr2(r3) ; Point to line 1 | |
1292 | mtcrf 255,r4 ; Load up the CRs | |
1293 | stw r10,savevrvalid(r3) ; Save the validity information | |
1294 | mr r8,r6 ; Start registers off | |
1295 | ; | |
1296 | ; Save the current vector state | |
1297 | ; | |
1298 | ||
1299 | bf 0,snol0 ; No line 0 to do... | |
1300 | dcba br0,r6 ; Allocate cache line 0 | |
1301 | ||
1302 | snol0: | |
1303 | la r6,savevr4(r3) ; Point to line 2 | |
1304 | bf 2,snol1 ; No line 1 to do... | |
1305 | dcba br0,r7 ; Allocate cache line 1 | |
1306 | ||
1307 | snol1: | |
1308 | la r7,savevr6(r3) ; Point to line 3 | |
1309 | bf 4,snol2 ; No line 2 to do... | |
1310 | dcba br0,r6 ; Allocate cache line 2 | |
1311 | ||
1312 | snol2: | |
1313 | li r11,16 ; Get offset for odd registers | |
1314 | bf 16,snovr0 ; Do not save VR0... | |
1315 | stvxl v0,br0,r8 ; Save VR0 | |
1316 | ||
1317 | snovr0: | |
1318 | la r9,savevr2(r3) ; Point to V2/V3 pair | |
1319 | bf 17,snovr1 ; Do not save VR1... | |
1320 | stvxl v1,r11,r8 ; Save VR1 | |
1321 | ||
1322 | snovr1: | |
1323 | la r6,savevr8(r3) ; Point to line 4 | |
1324 | bf 6,snol3 ; No line 3 to do... | |
1325 | dcba br0,r7 ; Allocate cache line 3 | |
1326 | ||
1327 | snol3: | |
1328 | la r8,savevr4(r3) ; Point to V4/V5 pair | |
1329 | bf 18,snovr2 ; Do not save VR2... | |
1330 | stvxl v2,br0,r9 ; Save VR2 | |
1331 | ||
1332 | snovr2: | |
1333 | bf 19,snovr3 ; Do not save VR3... | |
1334 | stvxl v3,r11,r9 ; Save VR3 | |
1335 | ||
1336 | snovr3: | |
1337 | ; | |
1338 | ; Note: CR4 is now free | |
1339 | ; | |
1340 | la r7,savevr10(r3) ; Point to line 5 | |
1341 | bf 8,snol4 ; No line 4 to do... | |
1342 | dcba br0,r6 ; Allocate cache line 4 | |
1343 | ||
1344 | snol4: | |
1345 | la r9,savevr6(r3) ; Point to R6/R7 pair | |
1346 | bf 20,snovr4 ; Do not save VR4... | |
1347 | stvxl v4,br0,r8 ; Save VR4 | |
1348 | ||
1349 | snovr4: | |
1350 | bf 21,snovr5 ; Do not save VR5... | |
1351 | stvxl v5,r11,r8 ; Save VR5 | |
1352 | ||
1353 | snovr5: | |
1354 | mtcrf 0x08,r10 ; Set CRs for registers 16-19 | |
1355 | la r6,savevr12(r3) ; Point to line 6 | |
1356 | bf 10,snol5 ; No line 5 to do... | |
1357 | dcba br0,r7 ; Allocate cache line 5 | |
1358 | ||
1359 | snol5: | |
1360 | la r8,savevr8(r3) ; Point to V8/V9 pair | |
1361 | bf 22,snovr6 ; Do not save VR6... | |
1362 | stvxl v6,br0,r9 ; Save VR6 | |
1363 | ||
1364 | snovr6: | |
1365 | bf 23,snovr7 ; Do not save VR7... | |
1366 | stvxl v7,r11,r9 ; Save VR7 | |
1367 | ||
1368 | snovr7: | |
1369 | ; | |
1370 | ; Note: CR5 is now free | |
1371 | ; | |
1372 | la r7,savevr14(r3) ; Point to line 7 | |
1373 | bf 12,snol6 ; No line 6 to do... | |
1374 | dcba br0,r6 ; Allocate cache line 6 | |
1375 | ||
1376 | snol6: | |
1377 | la r9,savevr10(r3) ; Point to V10/V11 pair | |
1378 | bf 24,snovr8 ; Do not save VR8... | |
1379 | stvxl v8,br0,r8 ; Save VR8 | |
1380 | ||
1381 | snovr8: | |
1382 | bf 25,snovr9 ; Do not save VR9... | |
1383 | stvxl v9,r11,r8 ; Save VR9 | |
1384 | ||
1385 | snovr9: | |
1386 | mtcrf 0x04,r10 ; Set CRs for registers 20-23 | |
1387 | la r6,savevr16(r3) ; Point to line 8 | |
1388 | bf 14,snol7 ; No line 7 to do... | |
1389 | dcba br0,r7 ; Allocate cache line 7 | |
1390 | ||
1391 | snol7: | |
1392 | la r8,savevr12(r3) ; Point to V12/V13 pair | |
1393 | bf 26,snovr10 ; Do not save VR10... | |
1394 | stvxl v10,br0,r9 ; Save VR10 | |
1395 | ||
1396 | snovr10: | |
1397 | bf 27,snovr11 ; Do not save VR11... | |
1398 | stvxl v11,r11,r9 ; Save VR11 | |
1399 | ||
1400 | snovr11: | |
1401 | ||
1402 | ; | |
1403 | ; Note: CR6 is now free | |
1404 | ; | |
1405 | la r7,savevr18(r3) ; Point to line 9 | |
1406 | bf 1,snol8 ; No line 8 to do... | |
1407 | dcba br0,r6 ; Allocate cache line 8 | |
1408 | ||
1409 | snol8: | |
1410 | la r9,savevr14(r3) ; Point to V14/V15 pair | |
1411 | bf 28,snovr12 ; Do not save VR12... | |
1412 | stvxl v12,br0,r8 ; Save VR12 | |
1413 | ||
1414 | snovr12: | |
1415 | bf 29,snovr13 ; Do not save VR13... | |
1416 | stvxl v13,r11,r8 ; Save VR13 | |
1417 | ||
1418 | snovr13: | |
1419 | mtcrf 0x02,r10 ; Set CRs for registers 24-27 | |
1420 | la r6,savevr20(r3) ; Point to line 10 | |
1421 | bf 3,snol9 ; No line 9 to do... | |
1422 | dcba br0,r7 ; Allocate cache line 9 | |
1423 | ||
1424 | snol9: | |
1425 | la r8,savevr16(r3) ; Point to V16/V17 pair | |
1426 | bf 30,snovr14 ; Do not save VR14... | |
1427 | stvxl v14,br0,r9 ; Save VR14 | |
1428 | ||
1429 | snovr14: | |
1430 | bf 31,snovr15 ; Do not save VR15... | |
1431 | stvxl v15,r11,r9 ; Save VR15 | |
1432 | ||
1433 | snovr15: | |
1434 | ; | |
1435 | ; Note: CR7 is now free | |
1436 | ; | |
1437 | la r7,savevr22(r3) ; Point to line 11 | |
1438 | bf 5,snol10 ; No line 10 to do... | |
1439 | dcba br0,r6 ; Allocate cache line 10 | |
1440 | ||
1441 | snol10: | |
1442 | la r9,savevr18(r3) ; Point to V18/V19 pair | |
1443 | bf 16,snovr16 ; Do not save VR16... | |
1444 | stvxl v16,br0,r8 ; Save VR16 | |
1445 | ||
1446 | snovr16: | |
1447 | bf 17,snovr17 ; Do not save VR17... | |
1448 | stvxl v17,r11,r8 ; Save VR17 | |
1449 | ||
1450 | snovr17: | |
1451 | mtcrf 0x01,r10 ; Set CRs for registers 28-31 | |
1452 | ; | |
1453 | ; Note: All registers have been or are accounted for in CRs | |
1454 | ; | |
1455 | la r6,savevr24(r3) ; Point to line 12 | |
1456 | bf 7,snol11 ; No line 11 to do... | |
1457 | dcba br0,r7 ; Allocate cache line 11 | |
1458 | ||
1459 | snol11: | |
1460 | la r8,savevr20(r3) ; Point to V20/V21 pair | |
1461 | bf 18,snovr18 ; Do not save VR18... | |
1462 | stvxl v18,br0,r9 ; Save VR18 | |
1463 | ||
1464 | snovr18: | |
1465 | bf 19,snovr19 ; Do not save VR19... | |
1466 | stvxl v19,r11,r9 ; Save VR19 | |
1467 | ||
1468 | snovr19: | |
1469 | la r7,savevr26(r3) ; Point to line 13 | |
1470 | bf 9,snol12 ; No line 12 to do... | |
1471 | dcba br0,r6 ; Allocate cache line 12 | |
1472 | ||
1473 | snol12: | |
1474 | la r9,savevr22(r3) ; Point to V22/V23 pair | |
1475 | bf 20,snovr20 ; Do not save VR20... | |
1476 | stvxl v20,br0,r8 ; Save VR20 | |
1477 | ||
1478 | snovr20: | |
1479 | bf 21,snovr21 ; Do not save VR21... | |
1480 | stvxl v21,r11,r8 ; Save VR21 | |
1481 | ||
1482 | snovr21: | |
1483 | la r6,savevr28(r3) ; Point to line 14 | |
1484 | bf 11,snol13 ; No line 13 to do... | |
1485 | dcba br0,r7 ; Allocate cache line 13 | |
1486 | ||
1487 | snol13: | |
1488 | la r8,savevr24(r3) ; Point to V24/V25 pair | |
1489 | bf 22,snovr22 ; Do not save VR22... | |
1490 | stvxl v22,br0,r9 ; Save VR22 | |
1491 | ||
1492 | snovr22: | |
1493 | bf 23,snovr23 ; Do not save VR23... | |
1494 | stvxl v23,r11,r9 ; Save VR23 | |
1495 | ||
1496 | snovr23: | |
1497 | la r7,savevr30(r3) ; Point to line 15 | |
1498 | bf 13,snol14 ; No line 14 to do... | |
1499 | dcba br0,r6 ; Allocate cache line 14 | |
1500 | ||
1501 | snol14: | |
1502 | la r9,savevr26(r3) ; Point to V26/V27 pair | |
1503 | bf 24,snovr24 ; Do not save VR24... | |
1504 | stvxl v24,br0,r8 ; Save VR24 | |
1505 | ||
1506 | snovr24: | |
1507 | bf 25,snovr25 ; Do not save VR25... | |
1508 | stvxl v25,r11,r8 ; Save VR25 | |
1509 | ||
1510 | snovr25: | |
1511 | bf 15,snol15 ; No line 15 to do... | |
1512 | dcba br0,r7 ; Allocate cache line 15 | |
1513 | ||
1514 | snol15: | |
1515 | ; | |
1516 | ; Note: All cache lines allocated now | |
1517 | ; | |
1518 | la r8,savevr28(r3) ; Point to V28/V29 pair | |
1519 | bf 26,snovr26 ; Do not save VR26... | |
1520 | stvxl v26,br0,r9 ; Save VR26 | |
1521 | ||
1522 | snovr26: | |
1523 | bf 27,snovr27 ; Do not save VR27... | |
1524 | stvxl v27,r11,r9 ; Save VR27 | |
1525 | ||
1526 | snovr27: | |
1527 | la r7,savevr30(r3) ; Point to V30/V31 pair | |
1528 | bf 28,snovr28 ; Do not save VR28... | |
1529 | stvxl v28,br0,r8 ; Save VR28 | |
1530 | ||
1531 | snovr28: | |
1532 | bf 29,snovr29 ; Do not save VR29... | |
1533 | stvxl v29,r11,r8 ; Save VR29 | |
1534 | ||
1535 | snovr29: | |
1536 | mfvscr v27 ; Get the VSCR | |
1537 | la r8,savevscr(r3) ; Point to the VSCR save area | |
1538 | bf 30,snovr30 ; Do not save VR30... | |
1539 | stvxl v30,br0,r7 ; Save VR30 | |
1540 | ||
1541 | snovr30: | |
1542 | dcba br0,r8 ; Allocate VSCR savearea | |
1543 | bf 31,snovr31 ; Do not save VR31... | |
1544 | stvxl v31,r11,r7 ; Save VR31 | |
1545 | ||
1546 | snovr31: | |
1547 | add r11,r11,r9 ; Point to V27s saved value | |
1548 | stvxl v27,br0,r8 ; Save the VSCR | |
1549 | bt 27,v27ok ; V27 has been saved and is marked as wanted | |
1550 | ||
1551 | lis r11,hi16(EXT(QNaNbarbarian)) ; V27 is not wanted, so get empty value | |
1552 | ori r11,r11,lo16(EXT(QNaNbarbarian)) | |
1553 | ||
1554 | v27ok: mtcrf 255,r2 ; Restore all non-volatile CRs | |
1555 | lvxl v27,br0,r11 ; Restore or load empty value into V27 because we used it | |
1556 | ||
1557 | ; | |
1558 | ; Save the current vector state into the savearea of the thread that owns it. | |
1559 | ; | |
1560 | ||
0b4e3aa0 A |
1561 | vsret: lwz r4,ACT_MACT_VMXcpu(r12) ; Get back the owner CPU |
1562 | rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock | |
1563 | sync | |
1564 | stw r4,ACT_MACT_VMXcpu(r12) ; Unlock the context | |
1565 | ||
1566 | vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off | |
1c79356b A |
1567 | isync |
1568 | ||
1569 | blr | |
1570 | ||
1571 | /* | |
1572 | * vec_switch() | |
1573 | * | |
1574 | * Entered to handle the vector unavailable exception and | |
1575 | * switch vector context | |
1576 | * | |
1577 | * This code is run with virtual address mode on and interrupts off. | |
1578 | * | |
1579 | * Upon exit, the code returns to the users context with the vector | |
1580 | * facility turned on. | |
1581 | * | |
1582 | * ENTRY: VM switched ON | |
1583 | * Interrupts OFF | |
1584 | * State is saved in savearea pointed to by R4. | |
1585 | * All other registers are free. | |
1586 | * | |
1587 | */ | |
1588 | ||
1589 | ENTRY(vec_switch, TAG_NO_FRAME_USED) | |
1590 | ||
1591 | #if DEBUG | |
1592 | #if GDDBG | |
1593 | mr r7,r4 ; Save input parameter | |
1594 | lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter | |
1595 | ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter | |
1596 | lwz r1,0(r3) | |
1597 | lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1598 | ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1599 | addi r1,r1,1 | |
1600 | mtlr r5 ; Set link register | |
1601 | stw r1,0(r3) | |
1602 | mr r4,r1 | |
1603 | lis r3,1 | |
1604 | blrl ; Display count | |
1605 | mr r4,r7 ; Restore the parameter | |
1606 | #else | |
1607 | lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter | |
1608 | ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter | |
1609 | lwz r1,0(r3) | |
1610 | addi r1,r1,1 | |
1611 | stw r1,0(r3) | |
1612 | #endif | |
1613 | #endif /* DEBUG */ | |
1614 | ||
1615 | mfsprg r6,0 /* Get the per_processor block */ | |
1616 | mfmsr r19 /* Get the current MSR */ | |
1617 | ||
1618 | lwz r10,PP_CPU_DATA(r6) /* Get the CPU data pointer */ | |
1619 | lwz r12,PP_VMX_THREAD(r6) /* Get the thread that owns the vector */ | |
1620 | lwz r10,CPU_ACTIVE_THREAD(r10) /* Get the pointer to the active thread */ | |
1621 | oris r19,r19,hi16(MASK(MSR_VEC)) /* Enable the vector feature */ | |
1622 | lwz r17,THREAD_TOP_ACT(r10) /* Now get the activation that is running */ | |
1623 | ||
1624 | ; R12 has the "old" activation | |
1625 | ; R17 has the "new" activation | |
1626 | ||
1627 | #if FPVECDBG | |
1628 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1629 | li r2,0x5F01 ; (TEST/DEBUG) | |
1630 | mr r3,r12 ; (TEST/DEBUG) | |
1631 | mr r5,r17 ; (TEST/DEBUG) | |
1632 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1633 | sc ; (TEST/DEBUG) | |
1634 | #if GDDBG | |
1635 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1636 | mr r18,r4 ; Save this | |
1637 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1638 | mr r4,r2 ; Set value | |
1639 | mtlr r3 ; Set link register | |
1640 | li r3,1 ; Display address | |
1641 | blrl ; Display it | |
1642 | mr r4,r18 ; Restore it | |
1643 | mfsprg r6,0 ; Get the per_processor block back | |
1644 | #endif | |
1645 | #endif | |
1646 | mr. r12,r12 ; See if there is any live vector status | |
1647 | ||
1648 | lhz r18,PP_CPU_NUMBER(r6) ; Get our CPU number | |
1649 | ||
1650 | mtmsr r19 /* Set vector available */ | |
1651 | isync | |
1652 | ||
1c79356b | 1653 | beq- vsnosave ; No live context, so nothing to save... |
0b4e3aa0 A |
1654 | |
1655 | li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word | |
1656 | ||
1657 | vsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU | |
1658 | mr. r19,r19 ; Is it changing now? | |
1659 | oris r21,r19,hi16(fvChk) ; Set the "changing" flag | |
1660 | blt- vsSpin1 ; Spin if changing | |
1661 | stwcx. r21,r20,r12 ; Lock it up | |
1662 | bne- vsSpin1 ; Someone is messing right now | |
1663 | ||
1664 | isync ; Make sure we see everything | |
1665 | ||
1c79356b A |
1666 | lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one |
1667 | cmplw r18,r19 ; Check the CPU that the old context is live on | |
1668 | lwz r14,ACT_MACT_VMX(r12) ; Point to the top of the old context stack | |
0b4e3aa0 | 1669 | bne- vsnosaverel ; Context is not live if used on a different CPU... |
1c79356b A |
1670 | lwz r13,ACT_MACT_VMXlvl(r12) ; Get the "old" active level |
1671 | ||
1672 | ; | |
1673 | ; First, check to see if all we are doing is enabling because the | |
1674 | ; "new" context is live. | |
1675 | ; | |
1676 | #if FPVECDBG | |
1677 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1678 | li r2,0x5F02 ; (TEST/DEBUG) | |
1679 | mr r1,r15 ; (TEST/DEBUG) | |
1680 | mr r3,r13 ; (TEST/DEBUG) | |
1681 | mr r5,r14 ; (TEST/DEBUG) | |
1682 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1683 | sc ; (TEST/DEBUG) | |
1684 | #if GDDBG | |
1685 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1686 | mr r8,r4 ; Save this | |
1687 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1688 | mr r4,r2 ; Set value | |
1689 | mtlr r3 ; Set link register | |
1690 | li r3,1 ; Display address | |
1691 | blrl ; Display it | |
1692 | mr r4,r8 ; Restore it | |
1693 | #endif | |
1694 | #endif | |
1695 | ||
1696 | cmplw cr1,r12,r17 ; Is the "old" activation and the "new" the same? | |
1697 | cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? | |
1698 | bne+ cr1,vsmstsave ; The activations are different so "old" context must be saved... | |
1699 | ||
1700 | ; | |
1701 | ; Here we know that both the "old" and "new" activations are the same. We will | |
1702 | ; check the current level and active levels. If they are the same, the context is | |
1703 | ; already live, so all we do is turn on the facility and invalidate the top | |
1704 | ; savearea. | |
1705 | ; | |
1706 | ; If the current level, the active level, and the top savearea level are the | |
1707 | ; same, then the context was saved as part of a thread context switch and neither | |
1708 | ; needs saving or restoration. | |
1709 | ; | |
1710 | ; In all other cases, the context must be saved unless we are just re-enabling | |
1711 | ; vector. | |
1712 | ; | |
1713 | ||
1714 | cmplw r13,r15 ; Are the levels the same? | |
1715 | cmplwi cr2,r14,0 ; Is there any saved context? | |
1716 | bne- vsmstsave ; Levels are different, we need to save... | |
1717 | ||
0b4e3aa0 | 1718 | beq- cr2,vrenableret ; No saved context at all, enable and go... |
1c79356b A |
1719 | |
1720 | lwz r20,SAVlvlvec(r14) ; Get the level of the top savearea | |
1721 | ||
1722 | #if FPVECDBG | |
1723 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1724 | li r2,0x5F03 ; (TEST/DEBUG) | |
1725 | mr r3,r15 ; (TEST/DEBUG) | |
1726 | mr r5,r20 ; (TEST/DEBUG) | |
1727 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1728 | sc ; (TEST/DEBUG) | |
1729 | #if GDDBG | |
1730 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1731 | mr r8,r4 ; Save this | |
1732 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1733 | mr r4,r2 ; Set value | |
1734 | mtlr r3 ; Set link register | |
1735 | li r3,1 ; Display address | |
1736 | blrl ; Display it | |
1737 | mr r4,r8 ; Restore it | |
1738 | #endif | |
1739 | #endif | |
1740 | cmplw r15,r20 ; Is the top level the same as the current? | |
1741 | li r0,1 ; Get the invalid flag | |
0b4e3aa0 | 1742 | bne- vrenableret ; Not the same, just enable and go... |
1c79356b A |
1743 | |
1744 | stw r0,SAVlvlvec(r14) ; Invalidate that top savearea | |
1745 | ||
0b4e3aa0 A |
1746 | vrenableret: |
1747 | sync ; Make sure everything is saved | |
1748 | stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore | |
1c79356b A |
1749 | b vrenable ; Then enable and go... |
1750 | ||
1751 | ; | |
1752 | ; We need to save the "old" context here. The LIFO queueing scheme works | |
1753 | ; out for all cases because if both the "new" and "old" activations are the | |
1754 | ; same, there can not be any saved state to load. the "new" level is | |
1755 | ; truely new. | |
1756 | ; | |
1757 | ; When we save the context, we either use a new savearea, or the free | |
1758 | ; one that is cached at the head of the list. | |
1759 | ||
1760 | vsmstsave: beq- cr2,vsgetsave ; There is no possible cached save area | |
1761 | ||
1762 | lwz r5,SAVlvlvec(r14) ; Get the level of first facility savearea | |
1763 | #if FPVECDBG | |
1764 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1765 | li r2,0x5F04 ; (TEST/DEBUG) | |
1766 | mr r3,r15 ; (TEST/DEBUG) | |
1767 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1768 | sc ; (TEST/DEBUG) | |
1769 | #if GDDBG | |
1770 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1771 | mr r8,r4 ; Save this | |
1772 | mr r7,r5 ; Save this | |
1773 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1774 | mr r4,r2 ; Set value | |
1775 | mtlr r3 ; Set link register | |
1776 | li r3,1 ; Display address | |
1777 | blrl ; Display it | |
1778 | mr r4,r8 ; Restore it | |
1779 | mr r5,r7 ; Restore it | |
1780 | #endif | |
1781 | #endif | |
1782 | mr r3,r14 ; Assume we are invalid | |
1783 | cmplwi r5,1 ; Is it invalid? | |
1784 | cmplw cr1,r5,r13 ; Is the SA level the active one? | |
1785 | beq+ vsusecache ; Invalid, just use it... | |
0b4e3aa0 | 1786 | beq- cr1,vsnosaverel ; The SA level is active, it is already saved... |
1c79356b A |
1787 | |
1788 | vsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached | |
1789 | #if FPVECDBG | |
1790 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1791 | li r2,0x5F05 ; (TEST/DEBUG) | |
1792 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1793 | sc ; (TEST/DEBUG) | |
1794 | #if GDDBG | |
1795 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1796 | mr r8,r4 ; Save this | |
1797 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1798 | mr r4,r2 ; Set value | |
1799 | mtlr r3 ; Set link register | |
1800 | li r3,1 ; Display address | |
1801 | blrl ; Display it | |
1802 | mr r4,r8 ; Restore it | |
1803 | mr r3,r8 ; This too | |
1804 | #endif | |
1805 | #endif | |
1806 | ||
1807 | bl vsrchsave ; Find a free savearea | |
1808 | ||
1809 | stw r3,ACT_MACT_VMX(r12) ; Set this as the latest context savearea for the thread | |
1810 | mfsprg r6,0 ; Get back per_processor block | |
1811 | stw r14,SAVprevec(r3) ; And then chain this in front | |
1812 | oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit | |
1813 | stw r12,SAVact(r3) ; Make sure we point to the right guy | |
1814 | stw r7,SAVflags(r3) ; Set the allocation flags | |
1815 | ||
1816 | vsusecache: la r11,savevr0(r3) ; Point to the 1st line in area | |
1817 | stw r13,SAVlvlvec(r3) ; Set this context level | |
1818 | #if FPVECDBG | |
1819 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
1820 | li r2,0x5F06 ; (TEST/DEBUG) | |
1821 | mr r5,r13 ; (TEST/DEBUG) | |
1822 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
1823 | sc ; (TEST/DEBUG) | |
1824 | #if GDDBG | |
1825 | mr r10,r3 | |
1826 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
1827 | mr r8,r4 ; Save this | |
1828 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
1829 | mr r4,r2 ; Set value | |
1830 | mtlr r3 ; Set link register | |
1831 | li r3,1 ; Display address | |
1832 | blrl ; Display it | |
1833 | mr r4,r8 ; Restore it | |
1834 | mr r3,r10 | |
1835 | mfsprg r6,0 ; Get back per_processor block | |
1836 | #endif | |
1837 | #endif | |
1838 | ||
1839 | vsgotsave: | |
1840 | lwz r10,liveVRS(r6) ; Get the right VRSave register | |
1841 | lis r9,0x5555 ; Mask with odd bits set | |
1842 | rlwinm r11,r10,1,0,31 ; Shift over 1 | |
1843 | ori r9,r9,0x5555 ; Finish mask | |
0b4e3aa0 | 1844 | or r21,r10,r11 ; After this, even bits show which lines to zap |
1c79356b A |
1845 | |
1846 | stw r13,SAVlvlvec(r3) ; Set the savearea level | |
0b4e3aa0 | 1847 | andc r13,r21,r9 ; Clear out odd bits |
1c79356b A |
1848 | |
1849 | la r20,savevr0(r3) ; Point to line 0 | |
1850 | rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits | |
1851 | la r23,savevrvalid(r3) ; Point to the saved register mask field | |
1852 | or r24,r13,r24 ; Set the odd bits | |
1853 | ; (bit 0 is line 0, bit 1 is line 8, | |
1854 | ; bit 2 is line 1, bit 3 is line 9, etc. | |
1855 | dcba br0,r23 ; Allocate the cache for it | |
1856 | rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 | |
1857 | la r21,savevr2(r3) ; Point to line 1 | |
1858 | mtcrf 255,r24 ; Load up the CRs | |
1859 | stw r10,savevrvalid(r3) ; Save the validity information | |
1860 | mr r22,r20 ; Start registers off | |
1861 | ; | |
1862 | ; Save the current vector state | |
1863 | ; | |
1864 | ||
1865 | bf 0,nol0 ; No line 0 to do... | |
1866 | dcba br0,r20 ; Allocate cache line 0 | |
1867 | ||
1868 | nol0: | |
1869 | la r20,savevr4(r3) ; Point to line 2 | |
1870 | bf 2,nol1 ; No line 1 to do... | |
1871 | dcba br0,r21 ; Allocate cache line 1 | |
1872 | ||
1873 | nol1: | |
1874 | la r21,savevr6(r3) ; Point to line 3 | |
1875 | bf 4,nol2 ; No line 2 to do... | |
1876 | dcba br0,r20 ; Allocate cache line 2 | |
1877 | ||
1878 | nol2: | |
1879 | li r30,16 ; Get offset for odd registers | |
1880 | bf 16,novr0 ; Do not save VR0... | |
1881 | stvxl v0,br0,r22 ; Save VR0 | |
1882 | ||
1883 | novr0: | |
1884 | la r23,savevr2(r3) ; Point to V2/V3 pair | |
1885 | bf 17,novr1 ; Do not save VR1... | |
1886 | stvxl v1,r30,r22 ; Save VR1 | |
1887 | ||
1888 | novr1: | |
1889 | la r20,savevr8(r3) ; Point to line 4 | |
1890 | bf 6,nol3 ; No line 3 to do... | |
1891 | dcba br0,r21 ; Allocate cache line 3 | |
1892 | ||
1893 | nol3: | |
1894 | la r22,savevr4(r3) ; Point to V4/V5 pair | |
1895 | bf 18,novr2 ; Do not save VR2... | |
1896 | stvxl v2,br0,r23 ; Save VR2 | |
1897 | ||
1898 | novr2: | |
1899 | bf 19,novr3 ; Do not save VR3... | |
1900 | stvxl v3,r30,r23 ; Save VR3 | |
1901 | ||
1902 | novr3: | |
1903 | ; | |
1904 | ; Note: CR4 is now free | |
1905 | ; | |
1906 | la r21,savevr10(r3) ; Point to line 5 | |
1907 | bf 8,nol4 ; No line 4 to do... | |
1908 | dcba br0,r20 ; Allocate cache line 4 | |
1909 | ||
1910 | nol4: | |
1911 | la r23,savevr6(r3) ; Point to R6/R7 pair | |
1912 | bf 20,novr4 ; Do not save VR4... | |
1913 | stvxl v4,br0,r22 ; Save VR4 | |
1914 | ||
1915 | novr4: | |
1916 | bf 21,novr5 ; Do not save VR5... | |
1917 | stvxl v5,r30,r22 ; Save VR5 | |
1918 | ||
1919 | novr5: | |
1920 | mtcrf 0x08,r10 ; Set CRs for registers 16-19 | |
1921 | la r20,savevr12(r3) ; Point to line 6 | |
1922 | bf 10,nol5 ; No line 5 to do... | |
1923 | dcba br0,r21 ; Allocate cache line 5 | |
1924 | ||
1925 | nol5: | |
1926 | la r22,savevr8(r3) ; Point to V8/V9 pair | |
1927 | bf 22,novr6 ; Do not save VR6... | |
1928 | stvxl v6,br0,r23 ; Save VR6 | |
1929 | ||
1930 | novr6: | |
1931 | bf 23,novr7 ; Do not save VR7... | |
1932 | stvxl v7,r30,r23 ; Save VR7 | |
1933 | ||
1934 | novr7: | |
1935 | ; | |
1936 | ; Note: CR5 is now free | |
1937 | ; | |
1938 | la r21,savevr14(r3) ; Point to line 7 | |
1939 | bf 12,nol6 ; No line 6 to do... | |
1940 | dcba br0,r20 ; Allocate cache line 6 | |
1941 | ||
1942 | nol6: | |
1943 | la r23,savevr10(r3) ; Point to V10/V11 pair | |
1944 | bf 24,novr8 ; Do not save VR8... | |
1945 | stvxl v8,br0,r22 ; Save VR8 | |
1946 | ||
1947 | novr8: | |
1948 | bf 25,novr9 ; Do not save VR9... | |
1949 | stvxl v9,r30,r22 ; Save VR9 | |
1950 | ||
1951 | novr9: | |
1952 | mtcrf 0x04,r10 ; Set CRs for registers 20-23 | |
1953 | la r20,savevr16(r3) ; Point to line 8 | |
1954 | bf 14,nol7 ; No line 7 to do... | |
1955 | dcba br0,r21 ; Allocate cache line 7 | |
1956 | ||
1957 | nol7: | |
1958 | la r22,savevr12(r3) ; Point to V12/V13 pair | |
1959 | bf 26,novr10 ; Do not save VR10... | |
1960 | stvxl v10,br0,r23 ; Save VR10 | |
1961 | ||
1962 | novr10: | |
1963 | bf 27,novr11 ; Do not save VR11... | |
1964 | stvxl v11,r30,r23 ; Save VR11 | |
1965 | ||
1966 | novr11: | |
1967 | ||
1968 | ; | |
1969 | ; Note: CR6 is now free | |
1970 | ; | |
1971 | la r21,savevr18(r3) ; Point to line 9 | |
1972 | bf 1,nol8 ; No line 8 to do... | |
1973 | dcba br0,r20 ; Allocate cache line 8 | |
1974 | ||
1975 | nol8: | |
1976 | la r23,savevr14(r3) ; Point to V14/V15 pair | |
1977 | bf 28,novr12 ; Do not save VR12... | |
1978 | stvxl v12,br0,r22 ; Save VR12 | |
1979 | ||
1980 | novr12: | |
1981 | bf 29,novr13 ; Do not save VR13... | |
1982 | stvxl v13,r30,r22 ; Save VR13 | |
1983 | ||
1984 | novr13: | |
1985 | mtcrf 0x02,r10 ; Set CRs for registers 24-27 | |
1986 | la r20,savevr20(r3) ; Point to line 10 | |
1987 | bf 3,nol9 ; No line 9 to do... | |
1988 | dcba br0,r21 ; Allocate cache line 9 | |
1989 | ||
1990 | nol9: | |
1991 | la r22,savevr16(r3) ; Point to V16/V17 pair | |
1992 | bf 30,novr14 ; Do not save VR14... | |
1993 | stvxl v14,br0,r23 ; Save VR14 | |
1994 | ||
1995 | novr14: | |
1996 | bf 31,novr15 ; Do not save VR15... | |
1997 | stvxl v15,r30,r23 ; Save VR15 | |
1998 | ||
1999 | novr15: | |
2000 | ; | |
2001 | ; Note: CR7 is now free | |
2002 | ; | |
2003 | la r21,savevr22(r3) ; Point to line 11 | |
2004 | bf 5,nol10 ; No line 10 to do... | |
2005 | dcba br0,r20 ; Allocate cache line 10 | |
2006 | ||
2007 | nol10: | |
2008 | la r23,savevr18(r3) ; Point to V18/V19 pair | |
2009 | bf 16,novr16 ; Do not save VR16... | |
2010 | stvxl v16,br0,r22 ; Save VR16 | |
2011 | ||
2012 | novr16: | |
2013 | bf 17,novr17 ; Do not save VR17... | |
2014 | stvxl v17,r30,r22 ; Save VR17 | |
2015 | ||
2016 | novr17: | |
2017 | mtcrf 0x01,r10 ; Set CRs for registers 28-31 | |
2018 | ; | |
2019 | ; Note: All registers have been or are accounted for in CRs | |
2020 | ; | |
2021 | la r20,savevr24(r3) ; Point to line 12 | |
2022 | bf 7,nol11 ; No line 11 to do... | |
2023 | dcba br0,r21 ; Allocate cache line 11 | |
2024 | ||
2025 | nol11: | |
2026 | la r22,savevr20(r3) ; Point to V20/V21 pair | |
2027 | bf 18,novr18 ; Do not save VR18... | |
2028 | stvxl v18,br0,r23 ; Save VR18 | |
2029 | ||
2030 | novr18: | |
2031 | bf 19,novr19 ; Do not save VR19... | |
2032 | stvxl v19,r30,r23 ; Save VR19 | |
2033 | ||
2034 | novr19: | |
2035 | la r21,savevr26(r3) ; Point to line 13 | |
2036 | bf 9,nol12 ; No line 12 to do... | |
2037 | dcba br0,r20 ; Allocate cache line 12 | |
2038 | ||
2039 | nol12: | |
2040 | la r23,savevr22(r3) ; Point to V22/V23 pair | |
2041 | bf 20,novr20 ; Do not save VR20... | |
2042 | stvxl v20,br0,r22 ; Save VR20 | |
2043 | ||
2044 | novr20: | |
2045 | bf 21,novr21 ; Do not save VR21... | |
2046 | stvxl v21,r30,r22 ; Save VR21 | |
2047 | ||
2048 | novr21: | |
2049 | la r20,savevr28(r3) ; Point to line 14 | |
2050 | bf 11,nol13 ; No line 13 to do... | |
2051 | dcba br0,r21 ; Allocate cache line 13 | |
2052 | ||
2053 | nol13: | |
2054 | la r22,savevr24(r3) ; Point to V24/V25 pair | |
2055 | bf 22,novr22 ; Do not save VR22... | |
2056 | stvxl v22,br0,r23 ; Save VR22 | |
2057 | ||
2058 | novr22: | |
2059 | bf 23,novr23 ; Do not save VR23... | |
2060 | stvxl v23,r30,r23 ; Save VR23 | |
2061 | ||
2062 | novr23: | |
2063 | la r21,savevr30(r3) ; Point to line 15 | |
2064 | bf 13,nol14 ; No line 14 to do... | |
2065 | dcba br0,r20 ; Allocate cache line 14 | |
2066 | ||
2067 | nol14: | |
2068 | la r23,savevr26(r3) ; Point to V26/V27 pair | |
2069 | bf 24,novr24 ; Do not save VR24... | |
2070 | stvxl v24,br0,r22 ; Save VR24 | |
2071 | ||
2072 | novr24: | |
2073 | bf 25,novr25 ; Do not save VR25... | |
2074 | stvxl v25,r30,r22 ; Save VR25 | |
2075 | ||
2076 | novr25: | |
2077 | bf 15,nol15 ; No line 15 to do... | |
2078 | dcba br0,r21 ; Allocate cache line 15 | |
2079 | ||
2080 | nol15: | |
2081 | ; | |
2082 | ; Note: All cache lines allocated now | |
2083 | ; | |
2084 | la r22,savevr28(r3) ; Point to V28/V29 pair | |
2085 | bf 26,novr26 ; Do not save VR26... | |
2086 | stvxl v26,br0,r23 ; Save VR26 | |
2087 | ||
2088 | novr26: | |
2089 | bf 27,novr27 ; Do not save VR27... | |
2090 | stvxl v27,r30,r23 ; Save VR27 | |
2091 | ||
2092 | novr27: | |
2093 | la r23,savevr30(r3) ; Point to V30/V31 pair | |
2094 | bf 28,novr28 ; Do not save VR28... | |
2095 | stvxl v28,br0,r22 ; Save VR28 | |
2096 | ||
2097 | novr28: | |
2098 | mfvscr v27 ; Get the VSCR | |
2099 | bf 29,novr29 ; Do not save VR29... | |
2100 | stvxl v29,r30,r22 ; Save VR29 | |
2101 | ||
2102 | novr29: | |
2103 | la r22,savevscr(r3) ; Point to the VSCR save area | |
2104 | bf 30,novr30 ; Do not save VR30... | |
2105 | stvxl v30,br0,r23 ; Save VR30 | |
2106 | ||
2107 | novr30: | |
2108 | dcba br0,r22 ; Allocate VSCR savearea | |
2109 | bf 31,novr31 ; Do not save VR31... | |
2110 | stvxl v31,r30,r23 ; Save VR31 | |
2111 | ||
2112 | novr31: | |
2113 | stvxl v27,br0,r22 ; Save the VSCR | |
2114 | ||
2115 | ||
2116 | ||
2117 | /* | |
2118 | * Now check out the current thread and see if we need to load up his context. | |
2119 | * If we do (and this should be the normal case), do it and then release the | |
2120 | * savearea. | |
2121 | * | |
2122 | * If we don't (remember, we already took care of the case where we just enable | |
2123 | * the vector), we need to fill the registers with garbage, because this thread has | |
2124 | * never used them before and some thieving bastard could hack the old values | |
2125 | * of some thread! Just imagine what would happen if they could! Why, nothing | |
2126 | * would be safe! My Gosh! It's terrifying! | |
2127 | */ | |
2128 | ||
0b4e3aa0 A |
2129 | vsnosaverel: |
2130 | sync ; Make sure everything is saved | |
2131 | stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore | |
2132 | ||
2133 | ||
2134 | vsnosave: | |
2135 | li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word | |
2136 | ||
2137 | vsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU | |
2138 | mr. r19,r19 ; Is it changing now? | |
2139 | oris r21,r19,hi16(fvChk) ; Set the "changing" flag | |
2140 | blt- vsSpin2 ; Spin if changing | |
2141 | stwcx. r21,r20,r17 ; Lock it up | |
2142 | bne- vsSpin2 ; Someone is messing right now | |
2143 | ||
2144 | isync ; Make sure we see everything | |
2145 | ||
2146 | lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one | |
1c79356b A |
2147 | lwz r14,ACT_MACT_VMX(r17) ; Point to the top of the "new" context stack |
2148 | lwz r13,ACT_MACT_VMXlvl(r17) ; Get the "new" active level | |
2149 | ||
2150 | #if FPVECDBG | |
2151 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
2152 | li r2,0x5F07 ; (TEST/DEBUG) | |
2153 | mr r1,r15 ; (TEST/DEBUG) | |
2154 | mr r3,r14 ; (TEST/DEBUG) | |
2155 | mr r5,r13 ; (TEST/DEBUG) | |
2156 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
2157 | sc ; (TEST/DEBUG) | |
2158 | #endif | |
2159 | ||
2160 | cmplwi cr1,r14,0 ; Do we possibly have some context to load? | |
2161 | stw r15,ACT_MACT_VMXlvl(r17) ; Set the "new" active level | |
2162 | la r23,savevscr(r14) ; Point to the VSCR | |
1c79356b A |
2163 | la r20,savevr0(r14) ; Point to first line to bring in |
2164 | stw r17,PP_VMX_THREAD(r6) ; Store current thread address in vmx_thread to claim vector for thread | |
2165 | beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... | |
2166 | lwz r0,SAVlvlvec(r14) ; Get the level of first facility savearea | |
2167 | cmplw r0,r15 ; Top level correct to load? | |
2168 | bne- ProtectTheAmericanWay ; No, go initialize... | |
2169 | ||
2170 | #if FPVECDBG | |
2171 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
2172 | li r2,0x5F08 ; (TEST/DEBUG) | |
2173 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
2174 | sc ; (TEST/DEBUG) | |
2175 | #if GDDBG | |
2176 | mr r8,r3 | |
2177 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
2178 | mr r22,r4 ; Save this | |
2179 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
2180 | mr r4,r2 ; Set value | |
2181 | mtlr r3 ; Set link register | |
2182 | li r3,1 ; Display address | |
2183 | blrl ; Display it | |
2184 | mr r4,r22 ; Restore it | |
2185 | mr r3,r8 | |
2186 | #endif | |
2187 | #endif | |
2188 | ||
2189 | li r0,1 ; Get the level invalid indication | |
2190 | lwz r22,savevrsave(r4) ; Get the most current VRSAVE | |
2191 | lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea | |
2192 | lis r9,0x5555 ; Mask with odd bits set | |
2193 | and r10,r10,r22 ; Figure out just what registers need to be loaded | |
2194 | ori r9,r9,0x5555 ; Finish mask | |
2195 | rlwinm r11,r10,1,0,31 ; Shift over 1 | |
2196 | stw r0,SAVlvlvec(r14) ; Mark the savearea invalid because we are activating again | |
2197 | or r12,r10,r11 ; After this, even bits show which lines to touch | |
2198 | dcbt br0,r23 ; Touch in the VSCR | |
2199 | andc r13,r12,r9 ; Clear out odd bits | |
2200 | ||
2201 | la r20,savevr0(r14) ; Point to line 0 | |
2202 | rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits | |
2203 | la r21,savevr2(r3) ; Point to line 1 | |
2204 | or r3,r13,r3 ; Set the odd bits | |
2205 | ; (bit 0 is line 0, bit 1 is line 8, | |
2206 | ; bit 2 is line 1, bit 3 is line 9, etc. | |
2207 | lvxl v31,br0,r23 ; Get the VSCR | |
2208 | rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 | |
2209 | mtvscr v31 ; Slam the VSCR value | |
2210 | mtcrf 255,r3 ; Load up the CRs | |
2211 | mr r22,r20 ; Start registers off | |
2212 | ; | |
2213 | ; Load the new vector state | |
2214 | ; | |
2215 | ||
2216 | bf 0,lnol0 ; No line 0 to do... | |
2217 | dcbt br0,r20 ; Touch cache line 0 | |
2218 | ||
2219 | lnol0: | |
2220 | la r20,savevr4(r14) ; Point to line 2 | |
2221 | bf 2,lnol1 ; No line 1 to do... | |
2222 | dcbt br0,r21 ; Touch cache line 1 | |
2223 | ||
2224 | lnol1: | |
2225 | la r21,savevr6(r14) ; Point to line 3 | |
2226 | bf 4,lnol2 ; No line 2 to do... | |
2227 | dcbt br0,r20 ; Touch cache line 2 | |
2228 | ||
2229 | lnol2: | |
2230 | li r30,16 ; Get offset for odd registers | |
2231 | bf 16,lnovr0 ; Do not restore VR0... | |
2232 | lvxl v0,br0,r22 ; Restore VR0 | |
2233 | ||
2234 | lnovr0: | |
2235 | la r23,savevr2(r14) ; Point to V2/V3 pair | |
2236 | bf 17,lnovr1 ; Do not restore VR1... | |
2237 | lvxl v1,r30,r22 ; Restore VR1 | |
2238 | ||
2239 | lnovr1: | |
2240 | la r20,savevr8(r14) ; Point to line 4 | |
2241 | bf 6,lnol3 ; No line 3 to do... | |
2242 | dcbt br0,r21 ; Touch cache line 3 | |
2243 | ||
2244 | lnol3: | |
2245 | la r22,savevr4(r14) ; Point to V4/V5 pair | |
2246 | bf 18,lnovr2 ; Do not restore VR2... | |
2247 | lvxl v2,br0,r23 ; Restore VR2 | |
2248 | ||
2249 | lnovr2: | |
2250 | bf 19,lnovr3 ; Do not restore VR3... | |
2251 | lvxl v3,r30,r23 ; Restore VR3 | |
2252 | ||
2253 | lnovr3: | |
2254 | ; | |
2255 | ; Note: CR4 is now free | |
2256 | ; | |
2257 | la r21,savevr10(r14) ; Point to line 5 | |
2258 | bf 8,lnol4 ; No line 4 to do... | |
2259 | dcbt br0,r20 ; Touch cache line 4 | |
2260 | ||
2261 | lnol4: | |
2262 | la r23,savevr6(r14) ; Point to R6/R7 pair | |
2263 | bf 20,lnovr4 ; Do not restore VR4... | |
2264 | lvxl v4,br0,r22 ; Restore VR4 | |
2265 | ||
2266 | lnovr4: | |
2267 | bf 21,lnovr5 ; Do not restore VR5... | |
2268 | lvxl v5,r30,r22 ; Restore VR5 | |
2269 | ||
2270 | lnovr5: | |
2271 | mtcrf 0x08,r10 ; Set CRs for registers 16-19 | |
2272 | la r20,savevr12(r14) ; Point to line 6 | |
2273 | bf 10,lnol5 ; No line 5 to do... | |
2274 | dcbt br0,r21 ; Touch cache line 5 | |
2275 | ||
2276 | lnol5: | |
2277 | la r22,savevr8(r14) ; Point to V8/V9 pair | |
2278 | bf 22,lnovr6 ; Do not restore VR6... | |
2279 | lvxl v6,br0,r23 ; Restore VR6 | |
2280 | ||
2281 | lnovr6: | |
2282 | bf 23,lnovr7 ; Do not restore VR7... | |
2283 | lvxl v7,r30,r23 ; Restore VR7 | |
2284 | ||
2285 | lnovr7: | |
2286 | ; | |
2287 | ; Note: CR5 is now free | |
2288 | ; | |
2289 | la r21,savevr14(r14) ; Point to line 7 | |
2290 | bf 12,lnol6 ; No line 6 to do... | |
2291 | dcbt br0,r20 ; Touch cache line 6 | |
2292 | ||
2293 | lnol6: | |
2294 | la r23,savevr10(r14) ; Point to V10/V11 pair | |
2295 | bf 24,lnovr8 ; Do not restore VR8... | |
2296 | lvxl v8,br0,r22 ; Restore VR8 | |
2297 | ||
2298 | lnovr8: | |
2299 | bf 25,lnovr9 ; Do not save VR9... | |
2300 | lvxl v9,r30,r22 ; Restore VR9 | |
2301 | ||
2302 | lnovr9: | |
2303 | mtcrf 0x04,r10 ; Set CRs for registers 20-23 | |
2304 | la r20,savevr16(r14) ; Point to line 8 | |
2305 | bf 14,lnol7 ; No line 7 to do... | |
2306 | dcbt br0,r21 ; Touch cache line 7 | |
2307 | ||
2308 | lnol7: | |
2309 | la r22,savevr12(r14) ; Point to V12/V13 pair | |
2310 | bf 26,lnovr10 ; Do not restore VR10... | |
2311 | lvxl v10,br0,r23 ; Restore VR10 | |
2312 | ||
2313 | lnovr10: | |
2314 | bf 27,lnovr11 ; Do not restore VR11... | |
2315 | lvxl v11,r30,r23 ; Restore VR11 | |
2316 | ||
2317 | lnovr11: | |
2318 | ||
2319 | ; | |
2320 | ; Note: CR6 is now free | |
2321 | ; | |
2322 | la r21,savevr18(r14) ; Point to line 9 | |
2323 | bf 1,lnol8 ; No line 8 to do... | |
2324 | dcbt br0,r20 ; Touch cache line 8 | |
2325 | ||
2326 | lnol8: | |
2327 | la r23,savevr14(r14) ; Point to V14/V15 pair | |
2328 | bf 28,lnovr12 ; Do not restore VR12... | |
2329 | lvxl v12,br0,r22 ; Restore VR12 | |
2330 | ||
2331 | lnovr12: | |
2332 | bf 29,lnovr13 ; Do not restore VR13... | |
2333 | lvxl v13,r30,r22 ; Restore VR13 | |
2334 | ||
2335 | lnovr13: | |
2336 | mtcrf 0x02,r10 ; Set CRs for registers 24-27 | |
2337 | la r20,savevr20(r14) ; Point to line 10 | |
2338 | bf 3,lnol9 ; No line 9 to do... | |
2339 | dcbt br0,r21 ; Touch cache line 9 | |
2340 | ||
2341 | lnol9: | |
2342 | la r22,savevr16(r14) ; Point to V16/V17 pair | |
2343 | bf 30,lnovr14 ; Do not restore VR14... | |
2344 | lvxl v14,br0,r23 ; Restore VR14 | |
2345 | ||
2346 | lnovr14: | |
2347 | bf 31,lnovr15 ; Do not restore VR15... | |
2348 | lvxl v15,r30,r23 ; Restore VR15 | |
2349 | ||
2350 | lnovr15: | |
2351 | ; | |
2352 | ; Note: CR7 is now free | |
2353 | ; | |
2354 | la r21,savevr22(r14) ; Point to line 11 | |
2355 | bf 5,lnol10 ; No line 10 to do... | |
2356 | dcbt br0,r20 ; Touch cache line 10 | |
2357 | ||
2358 | lnol10: | |
2359 | la r23,savevr18(r14) ; Point to V18/V19 pair | |
2360 | bf 16,lnovr16 ; Do not restore VR16... | |
2361 | lvxl v16,br0,r22 ; Restore VR16 | |
2362 | ||
2363 | lnovr16: | |
2364 | bf 17,lnovr17 ; Do not restore VR17... | |
2365 | lvxl v17,r30,r22 ; Restore VR17 | |
2366 | ||
2367 | lnovr17: | |
2368 | mtcrf 0x01,r10 ; Set CRs for registers 28-31 | |
2369 | ; | |
2370 | ; Note: All registers have been or are accounted for in CRs | |
2371 | ; | |
2372 | la r20,savevr24(r14) ; Point to line 12 | |
2373 | bf 7,lnol11 ; No line 11 to do... | |
2374 | dcbt br0,r21 ; Touch cache line 11 | |
2375 | ||
2376 | lnol11: | |
2377 | la r22,savevr20(r14) ; Point to V20/V21 pair | |
2378 | bf 18,lnovr18 ; Do not restore VR18... | |
2379 | lvxl v18,br0,r23 ; Restore VR18 | |
2380 | ||
2381 | lnovr18: | |
2382 | bf 19,lnovr19 ; Do not restore VR19... | |
2383 | lvxl v19,r30,r23 ; Restore VR19 | |
2384 | ||
2385 | lnovr19: | |
2386 | la r21,savevr26(r14) ; Point to line 13 | |
2387 | bf 9,lnol12 ; No line 12 to do... | |
2388 | dcbt br0,r20 ; Touch cache line 12 | |
2389 | ||
2390 | lnol12: | |
2391 | la r23,savevr22(r14) ; Point to V22/V23 pair | |
2392 | bf 20,lnovr20 ; Do not restore VR20... | |
2393 | lvxl v20,br0,r22 ; Restore VR20 | |
2394 | ||
2395 | lnovr20: | |
2396 | bf 21,lnovr21 ; Do not restore VR21... | |
2397 | lvxl v21,r30,r22 ; Restore VR21 | |
2398 | ||
2399 | lnovr21: | |
2400 | la r20,savevr28(r14) ; Point to line 14 | |
2401 | bf 11,lnol13 ; No line 13 to do... | |
2402 | dcbt br0,r21 ; Touch cache line 13 | |
2403 | ||
2404 | lnol13: | |
2405 | la r22,savevr24(r14) ; Point to V24/V25 pair | |
2406 | bf 22,lnovr22 ; Do not restore VR22... | |
2407 | lvxl v22,br0,r23 ; Restore VR22 | |
2408 | ||
2409 | lnovr22: | |
2410 | bf 23,lnovr23 ; Do not restore VR23... | |
2411 | lvxl v23,r30,r23 ; Restore VR23 | |
2412 | ||
2413 | lnovr23: | |
2414 | la r21,savevr30(r14) ; Point to line 15 | |
2415 | bf 13,lnol14 ; No line 14 to do... | |
2416 | dcbt br0,r20 ; Touch cache line 14 | |
2417 | ||
2418 | lnol14: | |
2419 | la r23,savevr26(r14) ; Point to V26/V27 pair | |
2420 | bf 24,lnovr24 ; Do not restore VR24... | |
2421 | lvxl v24,br0,r22 ; Restore VR24 | |
2422 | ||
2423 | lnovr24: | |
2424 | bf 25,lnovr25 ; Do not restore VR25... | |
2425 | lvxl v25,r30,r22 ; Restore VR25 | |
2426 | ||
2427 | lnovr25: | |
2428 | bf 15,lnol15 ; No line 15 to do... | |
2429 | dcbt br0,r21 ; Touch cache line 15 | |
2430 | ||
2431 | lnol15: | |
2432 | ; | |
2433 | ; Note: All needed cache lines have been touched now | |
2434 | ; | |
2435 | la r22,savevr28(r14) ; Point to V28/V29 pair | |
2436 | bf 26,lnovr26 ; Do not restore VR26... | |
2437 | lvxl v26,br0,r23 ; Restore VR26 | |
2438 | ||
2439 | lnovr26: | |
2440 | bf 27,lnovr27 ; Do not restore VR27... | |
2441 | lvxl v27,r30,r23 ; Restore VR27 | |
2442 | ||
2443 | lnovr27: | |
2444 | la r23,savevr30(r14) ; Point to V30/V31 pair | |
2445 | bf 28,lnovr28 ; Do not restore VR28... | |
2446 | lvxl v28,br0,r22 ; Restore VR28 | |
2447 | ||
2448 | lnovr28: | |
2449 | bf 29,lnovr29 ; Do not restore VR29... | |
2450 | lvxl v29,r30,r22 ; Restore VR29 | |
2451 | ||
2452 | lnovr29: | |
2453 | bf 30,lnovr30 ; Do not restore VR30... | |
2454 | lvxl v30,br0,r23 ; Restore VR30 | |
2455 | ||
2456 | lnovr30: | |
2457 | ; | |
2458 | ; Everything is restored now except for VR31. We need it to get | |
2459 | ; the QNaNBarbarian value to put into idle vector registers | |
2460 | ; | |
2461 | ||
2462 | lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value | |
2463 | cmpwi r10,-1 ; Handle the quick case of all registers in use | |
2464 | ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value | |
2465 | beq- mstlvr31 ; Not likely, but all are in use... | |
2466 | mtcrf 255,r10 ; Get mask of valid registers | |
2467 | lvxl v31,br0,r5 ; Initialize VR31 to the empty value | |
2468 | ||
2469 | bt 0,ni0 ; Register is ok already... | |
2470 | vor v0,v31,v31 ; Copy into the next register | |
2471 | ni0: | |
2472 | bt 1,ni1 ; Register is ok already... | |
2473 | vor v1,v31,v31 ; Copy into the next register | |
2474 | ni1: | |
2475 | bt 2,ni2 ; Register is ok already... | |
2476 | vor v2,v31,v31 ; Copy into the next register | |
2477 | ni2: | |
2478 | bt 3,ni3 ; Register is ok already... | |
2479 | vor v3,v31,v31 ; Copy into the next register | |
2480 | ni3: | |
2481 | bt 4,ni4 ; Register is ok already... | |
2482 | vor v4,v31,v31 ; Copy into the next register | |
2483 | ni4: | |
2484 | bt 5,ni5 ; Register is ok already... | |
2485 | vor v5,v31,v31 ; Copy into the next register | |
2486 | ni5: | |
2487 | bt 6,ni6 ; Register is ok already... | |
2488 | vor v6,v31,v31 ; Copy into the next register | |
2489 | ni6: | |
2490 | bt 7,ni7 ; Register is ok already... | |
2491 | vor v7,v31,v31 ; Copy into the next register | |
2492 | ni7: | |
2493 | bt 8,ni8 ; Register is ok already... | |
2494 | vor v8,v31,v31 ; Copy into the next register | |
2495 | ni8: | |
2496 | bt 9,ni9 ; Register is ok already... | |
2497 | vor v9,v31,v31 ; Copy into the next register | |
2498 | ni9: | |
2499 | bt 10,ni10 ; Register is ok already... | |
2500 | vor v10,v31,v31 ; Copy into the next register | |
2501 | ni10: | |
2502 | bt 11,ni11 ; Register is ok already... | |
2503 | vor v11,v31,v31 ; Copy into the next register | |
2504 | ni11: | |
2505 | bt 12,ni12 ; Register is ok already... | |
2506 | vor v12,v31,v31 ; Copy into the next register | |
2507 | ni12: | |
2508 | bt 13,ni13 ; Register is ok already... | |
2509 | vor v13,v31,v31 ; Copy into the next register | |
2510 | ni13: | |
2511 | bt 14,ni14 ; Register is ok already... | |
2512 | vor v14,v31,v31 ; Copy into the next register | |
2513 | ni14: | |
2514 | bt 15,ni15 ; Register is ok already... | |
2515 | vor v15,v31,v31 ; Copy into the next register | |
2516 | ni15: | |
2517 | bt 16,ni16 ; Register is ok already... | |
2518 | vor v16,v31,v31 ; Copy into the next register | |
2519 | ni16: | |
2520 | bt 17,ni17 ; Register is ok already... | |
2521 | vor v17,v31,v31 ; Copy into the next register | |
2522 | ni17: | |
2523 | bt 18,ni18 ; Register is ok already... | |
2524 | vor v18,v31,v31 ; Copy into the next register | |
2525 | ni18: | |
2526 | bt 19,ni19 ; Register is ok already... | |
2527 | vor v19,v31,v31 ; Copy into the next register | |
2528 | ni19: | |
2529 | bt 20,ni20 ; Register is ok already... | |
2530 | vor v20,v31,v31 ; Copy into the next register | |
2531 | ni20: | |
2532 | bt 21,ni21 ; Register is ok already... | |
2533 | vor v21,v31,v31 ; Copy into the next register | |
2534 | ni21: | |
2535 | bt 22,ni22 ; Register is ok already... | |
2536 | vor v22,v31,v31 ; Copy into the next register | |
2537 | ni22: | |
2538 | bt 23,ni23 ; Register is ok already... | |
2539 | vor v23,v31,v31 ; Copy into the next register | |
2540 | ni23: | |
2541 | bt 24,ni24 ; Register is ok already... | |
2542 | vor v24,v31,v31 ; Copy into the next register | |
2543 | ni24: | |
2544 | bt 25,ni25 ; Register is ok already... | |
2545 | vor v25,v31,v31 ; Copy into the next register | |
2546 | ni25: | |
2547 | bt 26,ni26 ; Register is ok already... | |
2548 | vor v26,v31,v31 ; Copy into the next register | |
2549 | ni26: | |
2550 | bt 27,ni27 ; Register is ok already... | |
2551 | vor v27,v31,v31 ; Copy into the next register | |
2552 | ni27: | |
2553 | bt 28,ni28 ; Register is ok already... | |
2554 | vor v28,v31,v31 ; Copy into the next register | |
2555 | ni28: | |
2556 | bt 29,ni29 ; Register is ok already... | |
2557 | vor v29,v31,v31 ; Copy into the next register | |
2558 | ni29: | |
2559 | bt 30,ni30 ; Register is ok already... | |
2560 | vor v30,v31,v31 ; Copy into the next register | |
2561 | ni30: | |
2562 | bf 31,lnovr31 ; R31 is empty, no need to restore... | |
2563 | ||
2564 | mstlvr31: lvxl v31,r30,r23 ; Restore VR31 | |
2565 | ||
2566 | lnovr31: | |
0b4e3aa0 A |
2567 | |
2568 | vrenablexx: sync ; Make sure all is saved | |
2569 | stw r18,ACT_MACT_VMXcpu(r17) ; Set the active CPU and release | |
1c79356b A |
2570 | |
2571 | vrenable: | |
2572 | lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ | |
2573 | lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy | |
2574 | rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ | |
2575 | oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility | |
2576 | lwz r10,ACT_MACT_SPF(r17) ; Get the special flags | |
2577 | lis r7,hi16(SAVattach) /* Get the attached flag */ | |
2578 | lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ | |
2579 | oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors | |
2580 | mr. r15,r15 ; See if we are doing this for user state | |
2581 | stw r8,savesrr1(r4) ; Set the msr of the interrupted guy | |
2582 | andc r9,r9,r7 /* Clear the attached bit */ | |
2583 | xor r3,r4,r5 /* Get the real address of the savearea */ | |
2584 | stw r9,SAVflags(r4) /* Set the flags of the current savearea */ | |
2585 | bne- vrnuser ; We are not user state... | |
2586 | stw r10,ACT_MACT_SPF(r17) ; Set the activation copy | |
2587 | stw r10,spcFlags(r6) ; Set per_proc copy | |
2588 | ||
2589 | vrnuser: | |
2590 | #if FPVECDBG | |
2591 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
2592 | li r2,0x5F0A ; (TEST/DEBUG) | |
2593 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
2594 | sc ; (TEST/DEBUG) | |
2595 | #if GDDBG | |
2596 | mr r8,r3 ; Save this | |
2597 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
2598 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
2599 | mr r4,r2 ; Set value | |
2600 | mtlr r3 ; Set link register | |
2601 | li r3,1 ; Display address | |
2602 | blrl ; Display it | |
2603 | mr r3,r8 ; Restore it | |
2604 | #endif | |
2605 | #endif | |
2606 | b EXT(exception_exit) /* Exit from the fray... */ | |
2607 | ||
2608 | /* | |
2609 | * Initialize the registers to some bogus value | |
2610 | * We make sure that non-Java mode is the default here | |
2611 | */ | |
2612 | ||
2613 | ProtectTheAmericanWay: | |
2614 | ||
0b4e3aa0 A |
2615 | #if 0 |
2616 | lwz r10,savesrr1(r4) ; (TEST/DEBUG) | |
2617 | rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) | |
2618 | beq- nxxxxxx2 ; (TEST/DEBUG) | |
2619 | lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) | |
2620 | rlwinm. r10,r10,0,2,2 ; (TEST/DEBUG) | |
2621 | beq+ nxxxxxx2 | |
2622 | BREAKPOINT_TRAP ; (TEST/DEBUG) | |
2623 | nxxxxxx2: | |
2624 | #endif | |
1c79356b A |
2625 | #if FPVECDBG |
2626 | lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) | |
2627 | li r2,0x5F09 ; (TEST/DEBUG) | |
2628 | oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) | |
2629 | sc ; (TEST/DEBUG) | |
2630 | #if GDDBG | |
2631 | lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display | |
2632 | mr r8,r4 ; Save this | |
2633 | ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part | |
2634 | mr r4,r2 ; Set value | |
2635 | mtlr r3 ; Set link register | |
2636 | li r3,1 ; Display address | |
2637 | blrl ; Display it | |
2638 | mr r4,r8 ; Restore it | |
2639 | #endif | |
2640 | #endif | |
2641 | lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value | |
2642 | vspltish v1,1 ; Turn on the non-Java bit and saturate | |
2643 | ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value | |
2644 | vspltisw v2,1 ; Turn on the saturate bit | |
2645 | lvxl v0,br0,r5 ; Initialize VR0 | |
2646 | vxor v1,v1,v2 ; Turn off saturate | |
2647 | ||
2648 | vor v2,v0,v0 ; Copy into the next register | |
2649 | mtvscr v1 ; Clear the vector status register | |
2650 | vor v3,v0,v0 ; Copy into the next register | |
2651 | vor v1,v0,v0 ; Copy into the next register | |
2652 | vor v4,v0,v0 ; Copy into the next register | |
2653 | vor v5,v0,v0 ; Copy into the next register | |
2654 | vor v6,v0,v0 ; Copy into the next register | |
2655 | vor v7,v0,v0 ; Copy into the next register | |
2656 | vor v8,v0,v0 ; Copy into the next register | |
2657 | vor v9,v0,v0 ; Copy into the next register | |
2658 | vor v10,v0,v0 ; Copy into the next register | |
2659 | vor v11,v0,v0 ; Copy into the next register | |
2660 | vor v12,v0,v0 ; Copy into the next register | |
2661 | vor v13,v0,v0 ; Copy into the next register | |
2662 | vor v14,v0,v0 ; Copy into the next register | |
2663 | vor v15,v0,v0 ; Copy into the next register | |
2664 | vor v16,v0,v0 ; Copy into the next register | |
2665 | vor v17,v0,v0 ; Copy into the next register | |
2666 | vor v18,v0,v0 ; Copy into the next register | |
2667 | vor v19,v0,v0 ; Copy into the next register | |
2668 | vor v20,v0,v0 ; Copy into the next register | |
2669 | vor v21,v0,v0 ; Copy into the next register | |
2670 | vor v22,v0,v0 ; Copy into the next register | |
2671 | vor v23,v0,v0 ; Copy into the next register | |
2672 | vor v24,v0,v0 ; Copy into the next register | |
2673 | vor v25,v0,v0 ; Copy into the next register | |
2674 | vor v26,v0,v0 ; Copy into the next register | |
2675 | vor v27,v0,v0 ; Copy into the next register | |
2676 | vor v28,v0,v0 ; Copy into the next register | |
2677 | vor v29,v0,v0 ; Copy into the next register | |
2678 | vor v30,v0,v0 ; Copy into the next register | |
2679 | vor v31,v0,v0 ; Copy into the next register | |
0b4e3aa0 | 2680 | b vrenablexx ; Finish setting it all up... |
1c79356b A |
2681 | |
2682 | ; | |
2683 | ; Finds a unused vector area in the activation pointed | |
2684 | ; to by R12s saved contexts. If none are found (unlikely but possible) | |
2685 | ; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains | |
2686 | ; a pointer to a vector savearea that is free. | |
2687 | ; | |
2688 | ||
2689 | vsrchsave: lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea | |
2690 | ||
2691 | vsrnorm: mr. r5,r6 ; Is there another? | |
2692 | beq- vsrvect ; No, search the floating point saveareas... | |
2693 | lwz r7,SAVflags(r5) ; Get the flags for this guy | |
2694 | lwz r6,SAVprev(r5) ; Get the previous savearea, just in case | |
2695 | andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in normal? | |
2696 | beq+ vsrgot ; We found one... | |
2697 | b vsrnorm ; Search again... | |
2698 | ||
2699 | vsrvect: lwz r6,ACT_MACT_FPU(r12) ; Get the first "floating point" savearea | |
2700 | ||
2701 | vsrvectx: mr. r5,r6 ; Is there another? | |
2702 | beq- vsrget ; No, try to allocate one... | |
2703 | lwz r7,SAVflags(r5) ; Get the flags for this guy | |
2704 | lwz r6,SAVprefp(r5) ; Get the previous savearea, just in case | |
2705 | andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in float? | |
2706 | bne- vsrvectx ; Search again... | |
2707 | ||
2708 | vsrgot: mr r3,r5 ; Get the savearea into the right register | |
2709 | blr ; Return... | |
2710 | ||
2711 | vsrget: mr. r5,r3 ; Do we allocate or use existing? | |
2712 | beq+ vsrallo ; Allocate one... | |
2713 | ||
2714 | lwz r7,SAVflags(r3) ; Get the passed in area flags | |
2715 | blr ; Return... | |
2716 | ; | |
2717 | ; NOTE: save_get will return directly and set R7 to 0... | |
2718 | ; | |
2719 | vsrallo: b EXT(save_get) ; Get a fresh savearea | |
2720 | ||
2721 | ||
2722 | /* | |
2723 | * void lfs(fpsp,fpdp) | |
2724 | * | |
2725 | * load the single precision float to the double | |
2726 | * | |
2727 | * This routine is used by the alignment handler. | |
2728 | * | |
2729 | */ | |
2730 | ENTRY(lfs, TAG_NO_FRAME_USED) | |
2731 | lfs f1, 0(r3) | |
2732 | stfd f1, 0(r4) | |
2733 | blr | |
2734 | ||
2735 | /* | |
2736 | * fpsp stfs(fpdp,fpsp) | |
2737 | * | |
2738 | * store the double precision float to the single | |
2739 | * | |
2740 | * This routine is used by the alignment handler. | |
2741 | * | |
2742 | */ | |
2743 | ENTRY(stfs, TAG_NO_FRAME_USED) | |
2744 | lfd f1, 0(r3) | |
2745 | stfs f1, 0(r4) | |
2746 | blr | |
2747 |