]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/vmachmon_asm.s
xnu-344.12.2.tar.gz
[apple/xnu.git] / osfmk / ppc / vmachmon_asm.s
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22#include <assym.s>
23#include <debug.h>
24#include <ppc/asm.h>
25#include <ppc/proc_reg.h>
26#include <ppc/exception.h>
27
28/*
29 * This file contains implementations for the Virtual Machine Monitor
30 * facility.
31 */
32
33
34/*
35 * int vmm_dispatch(savearea, act);
36
37 * vmm_dispatch is a PPC only system call. It is used with a selector (first
38 * parameter) to determine what function to enter. This is treated as an extension
39 * of hw_exceptions.
40 *
41 * Inputs:
42 * R4 = current activation
43 * R16 = current thread
44 * R30 = current savearea
45 */
46
47 .align 5 /* Line up on cache line */
48 .globl EXT(vmm_dispatch_table)
49
50LEXT(vmm_dispatch_table)
51
52 /* Don't change the order of these routines in the table. It's */
53 /* OK to add new routines, but they must be added at the bottom. */
54
55 .long EXT(vmm_get_version_sel) ; Get the version of the VMM interface
56 .long EXT(vmm_get_features_sel) ; Get the features of the VMM interface
57 .long EXT(vmm_init_context_sel) ; Initializes a new VMM context
58 .long EXT(vmm_tear_down_context) ; Tears down a previously-allocated VMM context
59 .long EXT(vmm_tear_down_all) ; Tears down all VMMs
60 .long EXT(vmm_map_page) ; Maps a page from the main address space into the VM space
61 .long EXT(vmm_get_page_mapping) ; Returns client va associated with VM va
62 .long EXT(vmm_unmap_page) ; Unmaps a page from the VM space
63 .long EXT(vmm_unmap_all_pages) ; Unmaps all pages from the VM space
64 .long EXT(vmm_get_page_dirty_flag) ; Gets the change bit for a page and optionally clears it
65 .long EXT(vmm_get_float_state) ; Gets current floating point state
66 .long EXT(vmm_get_vector_state) ; Gets current vector state
67 .long EXT(vmm_set_timer) ; Sets a timer value
68 .long EXT(vmm_get_timer) ; Gets a timer value
69 .long EXT(switchIntoVM) ; Switches to the VM context
0b4e3aa0
A
70 .long EXT(vmm_protect_page) ; Sets protection values for a page
71 .long EXT(vmm_map_execute) ; Maps a page an launches VM
72 .long EXT(vmm_protect_execute) ; Sets protection values for a page and launches VM
9bccf70c
A
73 .long EXT(vmm_map_list) ; Maps a list of pages
74 .long EXT(vmm_unmap_list) ; Unmaps a list of pages
1c79356b
A
75
76 .set vmm_count,(.-EXT(vmm_dispatch_table))/4 ; Get the top number
77
78
79 .align 5
80 .globl EXT(vmm_dispatch)
81
82LEXT(vmm_dispatch)
83
84 lwz r11,saver3(r30) ; Get the selector
85 mr r3,r4 ; All of our functions want the activation as the first parm
86 lis r10,hi16(EXT(vmm_dispatch_table)) ; Get top half of table
87 cmplwi r11,kVmmExecuteVM ; Should we switch to the VM now?
88 cmplwi cr1,r11,vmm_count ; See if we have a valid selector
89 ori r10,r10,lo16(EXT(vmm_dispatch_table)) ; Get low half of table
90 lwz r4,saver4(r30) ; Get 1st parameter after selector
91 beq+ EXT(switchIntoVM) ; Yes, go switch to it....
92 rlwinm r11,r11,2,0,29 ; Index into table
93 bgt- cr1,vmmBogus ; It is a bogus entry
94 lwzx r10,r10,r11 ; Get address of routine
95 lwz r5,saver5(r30) ; Get 2nd parameter after selector
96 lwz r6,saver6(r30) ; Get 3rd parameter after selector
97 mtlr r10 ; Set the routine address
98 lwz r7,saver7(r30) ; Get 4th parameter after selector
99;
100; NOTE: currently the most paramters for any call is 4. We will support at most 8 because we
101; do not want to get into any stack based parms. However, here is where we need to add
102; code for the 5th - 8th parms if we need them.
103;
104
105 blrl ; Call function
106
107 stw r3,saver3(r30) ; Pass back the return code
108 li r3,1 ; Set normal return with check for AST
109 b EXT(ppcscret) ; Go back to handler...
110
0b4e3aa0 111vmmBogus: li r3,0 ; Bogus selector, treat like a bogus system call
1c79356b
A
112 b EXT(ppcscret) ; Go back to handler...
113
114
115 .align 5
116 .globl EXT(vmm_get_version_sel)
117
118LEXT(vmm_get_version_sel) ; Selector based version of get version
119
120 lis r3,hi16(EXT(vmm_get_version))
121 ori r3,r3,lo16(EXT(vmm_get_version))
122 b selcomm
123
124
125 .align 5
126 .globl EXT(vmm_get_features_sel)
127
128LEXT(vmm_get_features_sel) ; Selector based version of get features
129
0b4e3aa0
A
130 lis r3,hi16(EXT(vmm_get_features))
131 ori r3,r3,lo16(EXT(vmm_get_features))
1c79356b
A
132 b selcomm
133
134
135 .align 5
136 .globl EXT(vmm_init_context_sel)
137
138LEXT(vmm_init_context_sel) ; Selector based version of init context
139
0b4e3aa0
A
140 lwz r4,saver4(r30) ; Get the passed in version
141 lwz r5,saver5(r30) ; Get the passed in comm area
142 lis r3,hi16(EXT(vmm_init_context))
143 stw r4,saver3(r30) ; Cheat and move this parameter over
144 ori r3,r3,lo16(EXT(vmm_init_context))
145 stw r5,saver4(r30) ; Cheat and move this parameter over
1c79356b
A
146
147selcomm: mtlr r3 ; Set the real routine address
148 mr r3,r30 ; Pass in the savearea
149 blrl ; Call the function
150 b EXT(ppcscret) ; Go back to handler...
151
152/*
153 * Here is where we transition to the virtual machine.
154 *
155 * We will swap the register context in the savearea with that which is saved in our shared
156 * context area. We will validity check a bit and clear any nasty bits in the MSR and force
157 * the manditory ones on.
158 *
159 * Then we will setup the new address space to run with, and anything else that is normally part
160 * of a context switch.
161 *
0b4e3aa0
A
162 * The vmm_execute_vm entry point is for the fused vmm_map_execute and vmm_protect_execute
163 * calls. This is called, but never returned from. We always go directly back to the
164 * user from here.
165 *
1c79356b
A
166 * Still need to figure out final floats and vectors. For now, we will go brute
167 * force and when we go into the VM, we will force save any normal floats and
168 * vectors. Then we will hide them and swap the VM copy (if any) into the normal
169 * chain. When we exit VM we will do the opposite. This is not as fast as I would
170 * like it to be.
171 *
172 *
173 */
174
0b4e3aa0
A
175
176 .align 5
177 .globl EXT(vmm_execute_vm)
178
179LEXT(vmm_execute_vm)
180
181 lwz r30,ACT_MACT_PCB(r3) ; Restore the savearea pointer because it could be trash here
182 b EXT(switchIntoVM) ; Join common...
183
184
1c79356b
A
185 .align 5
186 .globl EXT(switchIntoVM)
187
188LEXT(switchIntoVM)
0b4e3aa0 189
1c79356b
A
190 lwz r5,vmmControl(r3) ; Pick up the control table address
191 subi r4,r4,1 ; Switch to zero offset
192 rlwinm. r2,r5,0,0,30 ; Is there a context there? (Note: we will ignore bit 31 so that we
193 ; do not try this while we are transitioning off to on
194 cmplwi cr1,r4,kVmmMaxContextsPerThread ; Is the index valid?
195 beq- vmmBogus ; Not started, treat like a bogus system call
196 mulli r2,r4,vmmCEntrySize ; Get displacement from index
197 bgt- cr1,swvmmBogus ; Index is bogus...
198 add r2,r2,r5 ; Point to the entry
199
200 lwz r4,vmmFlags(r2) ; Get the flags for the selected entry
201 lwz r5,vmmContextKern(r2) ; Get the context area address
202 rlwinm. r26,r4,0,vmmInUseb,vmmInUseb ; See if the slot is in use
203 bne+ swvmChkIntcpt ; We are so cool. Go do check for immediate intercepts...
204
205swvmmBogus: li r2,kVmmBogusContext ; Set bogus index return
206 li r3,1 ; Set normal return with check for AST
207 stw r2,saver3(r30) ; Pass back the return code
208 b EXT(ppcscret) ; Go back to handler...
209
210;
211; Here we check for any immediate intercepts. So far, the only
0b4e3aa0
A
212; two of these are a timer pop and and external stop. We will not dispatch if
213; either is true. They need to either reset the timer (i.e. set timer
214; to 0) or to set a future time, or if it is external stop, set the vmmXStopRst flag.
1c79356b
A
215;
216
217swvmChkIntcpt:
0b4e3aa0
A
218 lwz r6,vmmCntrl(r5) ; Get the control field
219 rlwinm. r7,r6,0,vmmXStartb,vmmXStartb ; Clear all but start bit
220 beq+ swvmChkStop ; Do not reset stop
221 andc r6,r6,r7 ; Clear it
222 li r8,vmmFlags ; Point to the flags
223 stw r6,vmmCntrl(r5) ; Set the control field
224
225swvmtryx: lwarx r4,r8,r2 ; Pick up the flags
226 rlwinm r4,r4,0,vmmXStopb+1,vmmXStopb-1 ; Clear the stop bit
227 stwcx. r4,r8,r2 ; Save the updated field
228 bne- swvmtryx ; Try again...
229
230swvmChkStop:
231 rlwinm. r26,r4,0,vmmXStopb,vmmXStopb ; Is this VM stopped?
232 beq+ swvmNoStop ; Nope...
233
234 li r2,kVmmStopped ; Set stopped return
235 li r3,1 ; Set normal return with check for AST
236 stw r2,saver3(r30) ; Pass back the return code
237 stw r2,return_code(r5) ; Save the exit code
238 b EXT(ppcscret) ; Go back to handler...
239
240swvmNoStop:
9bccf70c 241 rlwinm. r26,r4,0,vmmTimerPopb,vmmTimerPopb ; Did the timer go pop?
1c79356b
A
242 beq+ swvmDoSwitch ; No...
243
244 li r2,kVmmReturnNull ; Set null return
245 li r3,1 ; Set normal return with check for AST
246 stw r2,saver3(r30) ; Pass back the return code
247 stw r2,return_code(r5) ; Save the exit code
248 b EXT(ppcscret) ; Go back to handler...
249
250;
251; Here is where we actually swap into the VM (alternate) context.
252; We will bulk do a wholesale swap of the registers in the context area (the VMs)
253; with the ones in the savearea (our main code). During the copy, we will fix up the
254; MSR, forcing on a few bits and turning off a few others. Then we will deal with the
255; PMAP and other per_proc stuff. Finally, we will exit back through the main exception
256; handler to deal with unstacking saveareas and ASTs, etc.
257;
258
259swvmDoSwitch:
260
261;
262; First, we save the volatile registers we care about. Remember, all register
263; handling here is pretty funky anyway, so we just pick the ones that are ok.
264;
265 mr r26,r3 ; Save the activation pointer
1c79356b 266
9bccf70c
A
267 la r11,vmmFacCtx(r2) ; Point to the virtual machine facility context
268 mr r27,r2 ; Save the context entry
269 stw r11,deferctx(r3) ; Start using the virtual machine facility context when we exit
1c79356b
A
270
271 lwz r11,ACT_MACT_SPF(r26) ; Get the special flags
272 lwz r3,vmmPmap(r27) ; Get the pointer to the PMAP
273 oris r15,r11,hi16(runningVM) ; ; Show that we are swapped to the VM right now
274 bl EXT(hw_set_user_space_dis) ; Swap the address spaces
275 lwz r17,vmmFlags(r27) ; Get the status flags
276 mfsprg r10,0 ; Get the per_proc
277 rlwinm. r0,r17,0,vmmMapDoneb,vmmMapDoneb ; Did we just do a map function?
278 stw r27,vmmCEntry(r26) ; Remember what context we are running
279 andc r17,r17,r0 ; Turn off map flag
280 beq+ swvmNoMap ; No mapping done...
281
282;
283; This little bit of hoopala here (triggered by vmmMapDone) is
284; a performance enhancement. This will change the returning savearea
285; to look like we had a DSI rather than a system call. Then, setting
286; the redrive bit, the exception handler will redrive the exception as
287; a DSI, entering the last mapped address into the hash table. This keeps
288; double faults from happening. Note that there is only a gain if the VM
289; takes a fault, then the emulator resolves it only, and then begins
290; the VM execution again. It seems like this should be the normal case.
291;
292
293 lwz r3,SAVflags(r30) ; Pick up the savearea flags
294 lwz r2,vmmLastMap(r27) ; Get the last mapped address
295 li r20,T_DATA_ACCESS ; Change to DSI fault
296 oris r3,r3,hi16(SAVredrive) ; Set exception redrive
297 stw r2,savedar(r30) ; Set the DAR to the last thing we mapped
298 stw r3,SAVflags(r30) ; Turn on the redrive request
299 lis r2,hi16(MASK(DSISR_HASH)) ; Set PTE/DBAT miss
300 stw r20,saveexception(r30) ; Say we need to emulate a DSI
301 stw r2,savedsisr(r30) ; Pretend we have a PTE miss
302
0b4e3aa0
A
303swvmNoMap: lwz r20,vmmContextKern(r27) ; Get the comm area
304 rlwimi r15,r17,32-(floatCngbit-vmmFloatCngdb),floatCngbit,vectorCngbit ; Shift and insert changed bits
305 lwz r20,vmmCntrl(r20) ; Get the control flags
1c79356b 306 rlwimi r17,r11,8,24,31 ; Save the old spf flags
0b4e3aa0 307 rlwimi r15,r20,32+vmmKeyb-userProtKeybit,userProtKeybit,userProtKeybit ; Set the protection key
1c79356b
A
308 stw r15,spcFlags(r10) ; Set per_proc copy of the special flags
309 stw r15,ACT_MACT_SPF(r26) ; Get the special flags
310
311 stw r17,vmmFlags(r27) ; Set the status flags
312
313 bl swapCtxt ; First, swap the general register state
314
0b4e3aa0 315 lwz r17,vmmContextKern(r27) ; Get the comm area back
9bccf70c 316 la r25,vmmFacCtx(r27) ; Point to the facility context
0b4e3aa0 317 lwz r15,vmmCntrl(r17) ; Get the control flags again
9bccf70c 318 mfsprg r29,0 ; Get the per_proc
1c79356b 319
9bccf70c
A
320;
321; Check if there is new floating point context to load
322;
323
1c79356b 324 rlwinm. r0,r15,0,vmmFloatLoadb,vmmFloatLoadb ; Are there new floating point values?
9bccf70c 325 lhz r29,PP_CPU_NUMBER(r29) ; Get our cpu number
1c79356b
A
326 li r14,vmmppcFPRs ; Get displacement to the new values
327 andc r15,r15,r0 ; Clear the bit
328 beq+ swvmNoNewFloats ; Nope, good...
329
9bccf70c
A
330 lwz r19,FPUcpu(r25) ; Get the last CPU we ran on
331
332 stw r29,FPUcpu(r25) ; Claim the context for ourselves
333
334 eieio ; Make sure this stays in order
335
336 lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc
337 mulli r19,r19,ppSize ; Find offset to the owner per_proc
338 ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc
339 li r16,FPUowner ; Displacement to float owner
340 add r19,r18,r19 ; Point to the owner per_proc
341 li r0,0 ; Clear this out
342
343swvminvfpu: lwarx r18,r16,r19 ; Get the owner
344 cmplw r18,r25 ; Does he still have this context?
345 bne swvminvfpv ; Nope...
346 stwcx. r0,r16,r19 ; Try to invalidate it
347 bne- swvminvfpu ; Try again if there was a collision...
348
349swvminvfpv: lwz r3,FPUsave(r25) ; Get the FPU savearea
350 dcbt r14,r17 ; Touch in first line of new stuff
1c79356b
A
351 mr. r3,r3 ; Is there one?
352 bne+ swvmGotFloat ; Yes...
353
354 bl EXT(save_get) ; Get a savearea
355
9bccf70c
A
356 li r7,SAVfloat ; Get floating point flag
357 stw r26,SAVact(r3) ; Save our activation
358 li r0,0 ; Get a zero
359 stb r7,SAVflags+2(r3) ; Set that this is floating point
360 stw r0,SAVprev(r3) ; Clear the back chain
361 stw r0,SAVlevel(r3) ; We are always at level 0 (user state)
362
363 stw r3,FPUsave(r25) ; Chain us to context
1c79356b
A
364
365swvmGotFloat:
1c79356b
A
366 la r4,savefp0(r3) ; Point to the destination
367 mr r21,r3 ; Save the save area
368 la r3,vmmppcFPRs(r17) ; Point to the source
9bccf70c 369 li r5,32*8 ; Get the size (32 FPRs at 8 bytes each)
1c79356b
A
370
371 bl EXT(bcopy) ; Copy the new values
9bccf70c
A
372
373 lwz r14,vmmppcFPSCRshadow(r17) ; Get the fpscr pad
374 lwz r10,vmmppcFPSCRshadow+4(r17) ; Get the fpscr
375 stw r14,savefpscrpad(r30) ; Save the new fpscr pad
376 stw r10,savefpscr(r30) ; Save the new fpscr
1c79356b
A
377
378 lwz r11,ACT_MACT_SPF(r26) ; Get the special flags
379 stw r15,vmmCntrl(r17) ; Save the control flags sans vmmFloatLoad
380 rlwinm r11,r11,0,floatCngbit+1,floatCngbit-1 ; Clear the changed bit here
381 lwz r14,vmmStat(r17) ; Get the status flags
382 mfsprg r10,0 ; Get the per_proc
383 stw r11,ACT_MACT_SPF(r26) ; Get the special flags
384 rlwinm r14,r14,0,vmmFloatCngdb+1,vmmFloatCngdb-1 ; Clear the changed flag
385 stw r11,spcFlags(r10) ; Set per_proc copy of the special flags
386 stw r14,vmmStat(r17) ; Set the status flags sans vmmFloatCngd
1c79356b 387
9bccf70c
A
388;
389; Check if there is new vector context to load
390;
391
1c79356b
A
392swvmNoNewFloats:
393 rlwinm. r0,r15,0,vmmVectLoadb,vmmVectLoadb ; Are there new vector values?
394 li r14,vmmppcVRs ; Get displacement to the new values
395 andc r15,r15,r0 ; Clear the bit
396 beq+ swvmNoNewVects ; Nope, good...
397
9bccf70c
A
398 lwz r19,VMXcpu(r25) ; Get the last CPU we ran on
399
400 stw r29,VMXcpu(r25) ; Claim the context for ourselves
401
402 eieio ; Make sure this stays in order
403
404 lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc
405 mulli r19,r19,ppSize ; Find offset to the owner per_proc
406 ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc
407 li r16,VMXowner ; Displacement to vector owner
408 add r19,r18,r19 ; Point to the owner per_proc
409 li r0,0 ; Clear this out
410
411swvminvvec: lwarx r18,r16,r19 ; Get the owner
412 cmplw r18,r25 ; Does he still have this context?
413 bne swvminvved ; Nope...
414 stwcx. r0,r16,r19 ; Try to invalidate it
415 bne- swvminvvec ; Try again if there was a collision...
416
417swvminvved: lwz r3,VMXsave(r25) ; Get the vector savearea
418 dcbt r14,r17 ; Touch in first line of new stuff
1c79356b
A
419 mr. r3,r3 ; Is there one?
420 bne+ swvmGotVect ; Yes...
421
422 bl EXT(save_get) ; Get a savearea
423
9bccf70c
A
424 li r7,SAVvector ; Get the vector type flag
425 stw r26,SAVact(r3) ; Save our activation
426 li r0,0 ; Get a zero
427 stb r7,SAVflags+2(r3) ; Set that this is vector
428 stw r0,SAVprev(r3) ; Clear the back chain
429 stw r0,SAVlevel(r3) ; We are always at level 0 (user state)
430
431 stw r3,VMXsave(r25) ; Chain us to context
1c79356b
A
432
433swvmGotVect:
1c79356b
A
434 mr r21,r3 ; Save the pointer to the savearea
435 la r4,savevr0(r3) ; Point to the destination
436 la r3,vmmppcVRs(r17) ; Point to the source
9bccf70c 437 li r5,32*16 ; Get the size (32 vectors at 16 bytes each)
1c79356b
A
438
439 bl EXT(bcopy) ; Copy the new values
440
9bccf70c
A
441 lwz r11,vmmppcVSCRshadow+0(r17) ; Get the VSCR
442 lwz r14,vmmppcVSCRshadow+4(r17) ; Get the VSCR
443 lwz r10,vmmppcVSCRshadow+8(r17) ; Get the VSCR
444 lwz r9,vmmppcVSCRshadow+12(r17) ; Get the VSCR
445 lwz r8,savevrsave(r30) ; Get the current VRSave
446
447 stw r11,savevscr+0(r30) ; Set the VSCR
448 stw r14,savevscr+4(r30) ; Set the VSCR
449 stw r10,savevscr+8(r30) ; Set the VSCR
450 stw r9,savevscr+12(r30) ; Set the VSCR
451 stw r8,savevrvalid(r21) ; Set the current VRSave as valid saved
452
1c79356b
A
453 lwz r11,ACT_MACT_SPF(r26) ; Get the special flags
454 stw r15,vmmCntrl(r17) ; Save the control flags sans vmmVectLoad
455 rlwinm r11,r11,0,vectorCngbit+1,vectorCngbit-1 ; Clear the changed bit here
456 lwz r14,vmmStat(r17) ; Get the status flags
457 mfsprg r10,0 ; Get the per_proc
458 stw r11,ACT_MACT_SPF(r26) ; Get the special flags
459 rlwinm r14,r14,0,vmmVectCngdb+1,vmmVectCngdb-1 ; Clear the changed flag
1c79356b
A
460 stw r11,spcFlags(r10) ; Set per_proc copy of the special flags
461 stw r14,vmmStat(r17) ; Set the status flags sans vmmVectCngd
1c79356b
A
462
463swvmNoNewVects:
464 li r3,1 ; Show normal exit with check for AST
9bccf70c 465 lwz r16,ACT_THREAD(r26) ; Restore the thread pointer
1c79356b
A
466 b EXT(ppcscret) ; Go back to handler...
467
468
1c79356b
A
469;
470; Here is where we exit from vmm mode. We do this on any kind of exception.
471; Interruptions (decrementer, external, etc.) are another story though.
472; These we just pass through. We also switch back explicity when requested.
473; This will happen in response to a timer pop and some kinds of ASTs.
474;
475; Inputs:
476; R3 = activation
477; R4 = savearea
478;
479
480 .align 5
481 .globl EXT(vmm_exit)
482
483LEXT(vmm_exit)
484
485 lwz r2,vmmCEntry(r3) ; Get the context that is active
486 lwz r12,ACT_VMMAP(r3) ; Get the VM_MAP for this guy
487 lwz r11,ACT_MACT_SPF(r3) ; Get the special flags
488 lwz r19,vmmFlags(r2) ; Get the status flags
489 mr r16,r3 ; R16 is safe to use for the activation address
490
491 rlwimi r19,r11,floatCngbit-vmmFloatCngdb,vmmFloatCngdb,vmmVectCngdb ; Shift and insert changed bits
492 li r0,0 ; Get a zero
493 rlwimi r11,r19,vmmSpfSaveb,floatCngbit,vectorCngbit ; Restore the saved part of the spf
494 lwz r3,VMMAP_PMAP(r12) ; Get the pmap for the activation
495 rlwinm r11,r11,0,runningVMbit+1,runningVMbit-1 ; Clear the "in VM" flag
496 stw r0,vmmCEntry(r16) ; Clear pointer to active context
497 stw r19,vmmFlags(r2) ; Set the status flags
0b4e3aa0 498 rlwinm r11,r11,0,userProtKeybit+1,userProtKeybit-1 ; Set back to normal protection key
1c79356b
A
499 mfsprg r10,0 ; Get the per_proc block
500 stw r11,ACT_MACT_SPF(r16) ; Get the special flags
501 stw r11,spcFlags(r10) ; Set per_proc copy of the special flags
502
503 mr r26,r16 ; Save the activation pointer
504 mr r27,r2 ; Save the context entry
505
506 bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator
507
9bccf70c 508 la r5,facctx(r16) ; Point to the main facility context
1c79356b 509 mr r2,r27 ; Restore
9bccf70c
A
510 stw r5,deferctx(r16) ; Start using the main facility context on the way out
511 lwz r5,vmmContextKern(r27) ; Get the context area address
1c79356b
A
512 mr r3,r16 ; Restore activation address
513 stw r19,vmmStat(r5) ; Save the changed and popped flags
514 bl swapCtxt ; Exchange the VM context for the emulator one
515 stw r8,saver3(r30) ; Set the return code as the return value also
516 b EXT(retFromVM) ; Go back to handler...
517
518
519;
520; Here is where we force exit from vmm mode. We do this when as
521; part of termination and is used to insure that we are not executing
522; in an alternate context. Because this is called from C we need to save
523; all non-volatile registers.
524;
525; Inputs:
526; R3 = activation
527; R4 = user savearea
528; Interruptions disabled
529;
530
531 .align 5
532 .globl EXT(vmm_force_exit)
533
534LEXT(vmm_force_exit)
535
536 stwu r1,-(FM_ALIGN(20*4)+FM_SIZE)(r1) ; Get enough space for the registers
537 mflr r0 ; Save the return
538 stmw r13,FM_ARG0(r1) ; Save all non-volatile registers
539 stw r0,(FM_ALIGN(20*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Save the return
540
541 lwz r2,vmmCEntry(r3) ; Get the context that is active
542 lwz r11,ACT_MACT_SPF(r3) ; Get the special flags
543 lwz r19,vmmFlags(r2) ; Get the status flags
544 lwz r12,ACT_VMMAP(r3) ; Get the VM_MAP for this guy
545
546 rlwimi r19,r11,floatCngbit-vmmFloatCngdb,vmmFloatCngdb,vmmVectCngdb ; Shift and insert changed bits
547 mr r26,r3 ; Save the activation pointer
548 rlwimi r11,r19,vmmSpfSaveb,floatCngbit,vectorCngbit ; Restore the saved part of the spf
549 li r0,0 ; Get a zero
550 rlwinm r9,r11,0,runningVMbit+1,runningVMbit-1 ; Clear the "in VM" flag
551 cmplw r9,r11 ; Check if we were in a vm
552 lwz r3,VMMAP_PMAP(r12) ; Get the pmap for the activation
553 beq- vfeNotRun ; We were not in a vm....
0b4e3aa0 554 rlwinm r9,r9,0,userProtKeybit+1,userProtKeybit-1 ; Set back to normal protection key
1c79356b
A
555 stw r0,vmmCEntry(r26) ; Clear pointer to active context
556 mfsprg r10,0 ; Get the per_proc block
557 stw r9,ACT_MACT_SPF(r26) ; Get the special flags
558 stw r9,spcFlags(r10) ; Set per_proc copy of the special flags
559
560 mr r27,r2 ; Save the context entry
561 mr r30,r4 ; Save the savearea
562
563 bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator
564
9bccf70c 565 la r7,facctx(r26) ; Point to the main facility context
1c79356b
A
566
567 lwz r5,vmmContextKern(r27) ; Get the context area address
568 stw r19,vmmStat(r5) ; Save the changed and popped flags
9bccf70c
A
569 stw r7,deferctx(r26) ; Tell context launcher to switch facility context
570
1c79356b
A
571 bl swapCtxt ; Exchange the VM context for the emulator one
572
0b4e3aa0 573 lwz r8,saveexception(r30) ; Pick up the exception code
9bccf70c
A
574 lwz r7,SAVflags(r30) ; Pick up the savearea flags
575 lis r9,hi16(SAVredrive) ; Get exception redrive bit
0b4e3aa0 576 rlwinm r8,r8,30,24,31 ; Convert exception to return code
9bccf70c 577 andc r7,r7,r9 ; Make sure redrive is off because we are intercepting
1c79356b 578 stw r8,saver3(r30) ; Set the return code as the return value also
9bccf70c 579 stw r7,SAVflags(r30) ; Set the savearea flags
1c79356b
A
580
581
582vfeNotRun: lmw r13,FM_ARG0(r1) ; Restore all non-volatile registers
583 lwz r1,0(r1) ; Pop the stack
584 lwz r0,FM_LR_SAVE(r1) ; Get the return address
585 mtlr r0 ; Set return
586 blr
587
588;
589; Note: we will not do any DCBTs to the savearea. It was just stored to a few cycles ago and should
9bccf70c 590; still be in the cache.
1c79356b 591;
1c79356b 592; NOTE NOTE: R16 is important to save!!!!
9bccf70c 593;
1c79356b
A
594 .align 5
595
9bccf70c 596swapCtxt: la r6,vmmppcpc(r5) ; Point to the first line
1c79356b
A
597
598 lwz r14,saveexception(r30) ; Get the exception code
9bccf70c
A
599 dcbt 0,r6 ; Touch in the first line of the context area
600 lwz r7,savesrr0(r30) ; Start moving context
601 lwz r8,savesrr1(r30)
602 lwz r9,saver0(r30)
1c79356b 603 cmplwi cr1,r14,T_SYSTEM_CALL ; Are we switching because of a system call?
9bccf70c
A
604 lwz r10,saver1(r30)
605 lwz r11,saver2(r30)
606 lwz r12,saver3(r30)
607 lwz r13,saver4(r30)
608 la r6,vmmppcr6(r5) ; Point to second line
609 lwz r14,saver5(r30)
1c79356b 610
9bccf70c 611 dcbt 0,r6 ; Touch second line of context area
1c79356b 612
9bccf70c 613 lwz r15,vmmppcpc(r5) ; First line of context
1c79356b 614 lis r22,hi16(MSR_IMPORT_BITS) ; Get the MSR bits that are controllable by user
9bccf70c 615 lwz r23,vmmppcmsr(r5)
1c79356b 616 ori r22,r25,lo16(MSR_IMPORT_BITS) ; Get the rest of the MSR bits that are controllable by user
9bccf70c
A
617 lwz r17,vmmppcr0(r5)
618 lwz r18,vmmppcr1(r5)
1c79356b 619 and r23,r23,r22 ; Keep only the controllable bits
9bccf70c 620 lwz r19,vmmppcr2(r5)
1c79356b 621 oris r23,r23,hi16(MSR_EXPORT_MASK_SET) ; Force on the required bits
9bccf70c 622 lwz r20,vmmppcr3(r5)
1c79356b 623 ori r23,r23,lo16(MSR_EXPORT_MASK_SET) ; Force on the other required bits
9bccf70c
A
624 lwz r21,vmmppcr4(r5)
625 lwz r22,vmmppcr5(r5)
1c79356b 626
9bccf70c 627 dcbt 0,r6 ; Touch third line of context area
1c79356b 628
9bccf70c
A
629 stw r7,vmmppcpc(r5) ; Save emulator context into the context area
630 stw r8,vmmppcmsr(r5)
631 stw r9,vmmppcr0(r5)
632 stw r10,vmmppcr1(r5)
633 stw r11,vmmppcr2(r5)
634 stw r12,vmmppcr3(r5)
635 stw r13,vmmppcr4(r5)
636 stw r14,vmmppcr5(r5)
1c79356b
A
637
638;
639; Save the first 3 parameters if we are an SC (we will take care of the last later)
640;
641 bne+ cr1,swapnotsc ; Skip next if not an SC exception...
642 stw r12,return_params+0(r5) ; Save the first return
643 stw r13,return_params+4(r5) ; Save the second return
644 stw r14,return_params+8(r5) ; Save the third return
645
9bccf70c
A
646swapnotsc: stw r15,savesrr0(r30) ; Save vm context into the savearea
647 stw r23,savesrr1(r30)
648 stw r17,saver0(r30)
649 stw r18,saver1(r30)
650 stw r19,saver2(r30)
651 stw r20,saver3(r30)
652 stw r21,saver4(r30)
653 la r6,vmmppcr14(r5) ; Point to fourth line
654 stw r22,saver5(r30)
655
656 dcbt 0,r6 ; Touch fourth line
657
658; Swap 8 registers
659
660 lwz r7,saver6(r30) ; Read savearea
661 lwz r8,saver7(r30)
662 lwz r9,saver8(r30)
663 lwz r10,saver9(r30)
664 lwz r11,saver10(r30)
665 lwz r12,saver11(r30)
666 lwz r13,saver12(r30)
667 lwz r14,saver13(r30)
668
669 lwz r15,vmmppcr6(r5) ; Read vm context
670 lwz r24,vmmppcr7(r5)
671 lwz r17,vmmppcr8(r5)
672 lwz r18,vmmppcr9(r5)
673 lwz r19,vmmppcr10(r5)
674 lwz r20,vmmppcr11(r5)
675 lwz r21,vmmppcr12(r5)
676 lwz r22,vmmppcr13(r5)
677
678 stw r7,vmmppcr6(r5) ; Write context
679 stw r8,vmmppcr7(r5)
680 stw r9,vmmppcr8(r5)
681 stw r10,vmmppcr9(r5)
682 stw r11,vmmppcr10(r5)
683 stw r12,vmmppcr11(r5)
684 stw r13,vmmppcr12(r5)
685 la r6,vmmppcr22(r5) ; Point to fifth line
686 stw r14,vmmppcr13(r5)
687
688 dcbt 0,r6 ; Touch fifth line
689
690 stw r15,saver6(r30) ; Write vm context
691 stw r24,saver7(r30)
692 stw r17,saver8(r30)
693 stw r18,saver9(r30)
694 stw r19,saver10(r30)
695 stw r20,saver11(r30)
696 stw r21,saver12(r30)
697 stw r22,saver13(r30)
698
699; Swap 8 registers
700
701 lwz r7,saver14(r30) ; Read savearea
702 lwz r8,saver15(r30)
703 lwz r9,saver16(r30)
704 lwz r10,saver17(r30)
705 lwz r11,saver18(r30)
706 lwz r12,saver19(r30)
707 lwz r13,saver20(r30)
708 lwz r14,saver21(r30)
709
710 lwz r15,vmmppcr14(r5) ; Read vm context
711 lwz r24,vmmppcr15(r5)
712 lwz r17,vmmppcr16(r5)
713 lwz r18,vmmppcr17(r5)
714 lwz r19,vmmppcr18(r5)
715 lwz r20,vmmppcr19(r5)
716 lwz r21,vmmppcr20(r5)
717 lwz r22,vmmppcr21(r5)
718
719 stw r7,vmmppcr14(r5) ; Write context
720 stw r8,vmmppcr15(r5)
721 stw r9,vmmppcr16(r5)
722 stw r10,vmmppcr17(r5)
723 stw r11,vmmppcr18(r5)
724 stw r12,vmmppcr19(r5)
725 stw r13,vmmppcr20(r5)
726 la r6,vmmppcr30(r5) ; Point to sixth line
727 stw r14,vmmppcr21(r5)
728
729 dcbt 0,r6 ; Touch sixth line
730
731 stw r15,saver14(r30) ; Write vm context
732 stw r24,saver15(r30)
733 stw r17,saver16(r30)
734 stw r18,saver17(r30)
735 stw r19,saver18(r30)
736 stw r20,saver19(r30)
737 stw r21,saver20(r30)
738 stw r22,saver21(r30)
739
740; Swap 8 registers
741
742 lwz r7,saver22(r30) ; Read savearea
743 lwz r8,saver23(r30)
744 lwz r9,saver24(r30)
745 lwz r10,saver25(r30)
746 lwz r11,saver26(r30)
747 lwz r12,saver27(r30)
748 lwz r13,saver28(r30)
749 lwz r14,saver29(r30)
750
751 lwz r15,vmmppcr22(r5) ; Read vm context
752 lwz r24,vmmppcr23(r5)
753 lwz r17,vmmppcr24(r5)
754 lwz r18,vmmppcr25(r5)
755 lwz r19,vmmppcr26(r5)
756 lwz r20,vmmppcr27(r5)
757 lwz r21,vmmppcr28(r5)
758 lwz r22,vmmppcr29(r5)
759
760 stw r7,vmmppcr22(r5) ; Write context
761 stw r8,vmmppcr23(r5)
762 stw r9,vmmppcr24(r5)
763 stw r10,vmmppcr25(r5)
764 stw r11,vmmppcr26(r5)
765 stw r12,vmmppcr27(r5)
766 stw r13,vmmppcr28(r5)
767 la r6,vmmppcvscr(r5) ; Point to seventh line
768 stw r14,vmmppcr29(r5)
769
770 dcbt 0,r6 ; Touch seventh line
771
772 stw r15,saver22(r30) ; Write vm context
773 stw r24,saver23(r30)
774 stw r17,saver24(r30)
775 stw r18,saver25(r30)
776 stw r19,saver26(r30)
777 stw r20,saver27(r30)
778 stw r21,saver28(r30)
779 stw r22,saver29(r30)
780
781; Swap 8 registers
782
783 lwz r7,saver30(r30) ; Read savearea
784 lwz r8,saver31(r30)
785 lwz r9,savecr(r30)
786 lwz r10,savexer(r30)
787 lwz r11,savelr(r30)
788 lwz r12,savectr(r30)
789 lwz r14,savevrsave(r30)
790
791 lwz r15,vmmppcr30(r5) ; Read vm context
792 lwz r24,vmmppcr31(r5)
793 lwz r17,vmmppccr(r5)
794 lwz r18,vmmppcxer(r5)
795 lwz r19,vmmppclr(r5)
796 lwz r20,vmmppcctr(r5)
797 lwz r22,vmmppcvrsave(r5)
798
799 stw r7,vmmppcr30(r5) ; Write context
800 stw r8,vmmppcr31(r5)
801 stw r9,vmmppccr(r5)
802 stw r10,vmmppcxer(r5)
803 stw r11,vmmppclr(r5)
804 stw r12,vmmppcctr(r5)
805 stw r14,vmmppcvrsave(r5)
806
807 stw r15,saver30(r30) ; Write vm context
808 stw r24,saver31(r30)
809 stw r17,savecr(r30)
810 stw r18,savexer(r30)
811 stw r19,savelr(r30)
812 stw r20,savectr(r30)
813 stw r22,savevrsave(r30)
814
815; Swap 8 registers
816
817 lwz r7,savevscr+0(r30) ; Read savearea
818 lwz r8,savevscr+4(r30)
819 lwz r9,savevscr+8(r30)
820 lwz r10,savevscr+12(r30)
821 lwz r11,savefpscrpad(r30)
822 lwz r12,savefpscr(r30)
823
824 lwz r15,vmmppcvscr+0(r5) ; Read vm context
825 lwz r24,vmmppcvscr+4(r5)
826 lwz r17,vmmppcvscr+8(r5)
827 lwz r18,vmmppcvscr+12(r5)
828 lwz r19,vmmppcfpscrpad(r5)
829 lwz r20,vmmppcfpscr(r5)
830
831 stw r7,vmmppcvscr+0(r5) ; Write context
832 stw r8,vmmppcvscr+4(r5)
833 stw r9,vmmppcvscr+8(r5)
834 stw r10,vmmppcvscr+12(r5)
835 stw r11,vmmppcfpscrpad(r5)
836 stw r12,vmmppcfpscr(r5)
837
838 stw r15,savevscr+0(r30) ; Write vm context
839 stw r24,savevscr+4(r30)
840 stw r17,savevscr+8(r30)
841 stw r18,savevscr+12(r30)
842 stw r19,savefpscrpad(r30)
843 stw r20,savefpscr(r30)
844
1c79356b
A
845
846;
847; Cobble up the exception return code and save any specific return values
848;
849
850 lwz r7,saveexception(r30) ; Pick up the exception code
851 rlwinm r8,r7,30,24,31 ; Convert exception to return code
852 cmplwi r7,T_DATA_ACCESS ; Was this a DSI?
853 stw r8,return_code(r5) ; Save the exit code
854 cmplwi cr1,r7,T_INSTRUCTION_ACCESS ; Exiting because of an ISI?
855 beq+ swapDSI ; Yeah...
856 cmplwi r7,T_ALIGNMENT ; Alignment exception?
857 beq+ cr1,swapISI ; We had an ISI...
858 cmplwi cr1,r7,T_SYSTEM_CALL ; Exiting because of an system call?
859 beq+ swapDSI ; An alignment exception looks like a DSI...
860 beq+ cr1,swapSC ; We had a system call...
861
862 blr ; Return...
863
864;
865; Set exit returns for a DSI or alignment exception
866;
867
868swapDSI: lwz r10,savedar(r30) ; Get the DAR
869 lwz r7,savedsisr(r30) ; and the DSISR
870 stw r10,return_params+0(r5) ; Save DAR as first return parm
871 stw r7,return_params+4(r5) ; Save DSISR as second return parm
872 blr ; Return...
873
874;
875; Set exit returns for a ISI
876;
877
9bccf70c
A
878swapISI: lwz r7,vmmppcmsr(r5) ; Get the SRR1 value
879 lwz r10,vmmppcpc(r5) ; Get the PC as failing address
1c79356b
A
880 rlwinm r7,r7,0,1,4 ; Save the bits that match the DSISR
881 stw r10,return_params+0(r5) ; Save PC as first return parm
882 stw r7,return_params+4(r5) ; Save the pseudo-DSISR as second return parm
883 blr ; Return...
884
885;
886; Set exit returns for a system call (note: we did the first 3 earlier)
887; Do we really need to pass parameters back here????
888;
889
9bccf70c 890swapSC: lwz r10,vmmppcr6(r5) ; Get the fourth paramter
1c79356b
A
891 stw r10,return_params+12(r5) ; Save it
892 blr ; Return...
893