]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/Emulate64.s
xnu-792.17.14.tar.gz
[apple/xnu.git] / osfmk / ppc / Emulate64.s
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* Emulate64.s
30 *
31 * Software emulation of instructions not handled in hw, on 64-bit machines.
32 */
33
34 #include <sys/appleapiopts.h>
35 #include <ppc/asm.h>
36 #include <ppc/proc_reg.h>
37 #include <ppc/exception.h>
38 #include <mach/machine/vm_param.h>
39 #include <ppc/cpu_capabilities.h>
40 #include <assym.s>
41
42 // CR bit set if the instruction is an "update" form (LFDU, STWU, etc):
43 #define kUpdate 25
44
45 // CR bit set if interrupt occured in trace mode (ie, MSR_SE_BIT):
46 #define kTrace 8
47
48 // CR bit set if notification on alignment interrupts is requested (notifyUnalignbit in spcFlags):
49 #define kNotify 9
50
51 // CR bit distinguishes between alignment and program exceptions:
52 #define kAlignment 10
53
54
55
56 // *************************************
57 // * P R O G R A M I N T E R R U P T *
58 // *************************************
59 //
60 // These are floating pt exceptions, illegal instructions, privileged mode violations,
61 // and traps. All we're interested in at this low level is illegal instructions.
62 // The ones we "emulate" are:
63 // DCBA, which is not implemented in the IBM 970. The emulation is to ignore it,
64 // as it is just a hint.
65 // MCRXR, which is not implemented on the IBM 970, but is in the PPC ISA.
66 //
67 // Additionally, to facilitate debugging the alignment handler, we recognize a special
68 // diagnostic mode that is used to simulate alignment exceptions. When in this mode,
69 // if the instruction has opcode==0 and the extended opcode is one of the X-form
70 // instructions that can take an alignment interrupt, then we change the opcode to
71 // 31 and pretend it got an alignment interrupt. This exercises paths that
72 // are hard to drive or perhaps never driven on this particular CPU.
73
74 .text
75 .globl EXT(Emulate64)
76 .align 5
77 LEXT(Emulate64)
78 crclr kAlignment // not an alignment exception
79 b a64AlignAssistJoin // join alignment handler
80
81
82 // Return from alignment handler with all the regs loaded for opcode emulation.
83
84 a64HandleProgramInt:
85 rlwinm. r0,r29,0,SRR1_PRG_ILL_INS_BIT,SRR1_PRG_ILL_INS_BIT // illegal opcode?
86 beq a64PassAlong // No, must have been trap or priv violation etc
87 rlwinm r3,r20,6,26,31 // right justify opcode field (bits 0-5)
88 rlwinm r4,r20,31,22,31 // right justify extended opcode field (bits 21-30)
89 cmpwi cr0,r3,31 // X-form?
90 cmpwi cr1,r4,758 // DCBA?
91 cmpwi cr4,r4,512 // MCRXR?
92 crand cr1_eq,cr0_eq,cr1_eq // merge the two tests for DCBA
93 crand cr4_eq,cr0_eq,cr4_eq // and for MCRXR
94 beq++ cr1_eq,a64ExitEm // was DCBA, so ignore
95 bne-- cr4_eq,a64NotEmulated // skip if not MCRXR
96
97 // Was MCRXR, so emulate.
98
99 ld r3,savexer(r13) // get the XER
100 lwz r4,savecr(r13) // and the CR
101 rlwinm r5,r20,11,27,29 // get (CR# * 4) from instruction
102 rlwinm r6,r3,0,4,31 // zero XER[32-35] (also XER[0-31])
103 sld r4,r4,r5 // move target CR field to bits 32-35
104 rlwimi r4,r3,0,0,3 // move XER[32-35] into CR field
105 stw r6,savexer+4(r13) // update XER
106 srd r4,r4,r5 // re-position CR
107 stw r4,savecr(r13) // update CR
108 b a64ExitEm // done
109
110 // Not an opcode we normally emulate. If in special diagnostic mode and opcode=0,
111 // emulate as an alignment exception. This special case is for test software.
112
113 a64NotEmulated:
114 lwz r30,dgFlags(0) // Get the flags
115 rlwinm. r0,r30,0,enaDiagEMb,enaDiagEMb // Do we want to try to emulate something?
116 beq++ a64PassAlong // No emulation allowed
117 cmpwi r3,0 // opcode==0 ?
118 bne a64PassAlong // not the special case
119 oris r20,r20,0x7C00 // change opcode to 31
120 crset kAlignment // say we took alignment exception
121 rlwinm r5,r4,0,26+1,26-1 // mask Update bit (32) out of extended opcode
122 rlwinm r5,r5,0,0,31 // Clean out leftover junk from rlwinm
123
124 cmpwi r4,1014 // dcbz/dcbz128 ?
125 crmove cr1_eq,cr0_eq
126 cmpwi r5,21 // ldx/ldux ?
127 cror cr1_eq,cr0_eq,cr1_eq
128 cmpwi r5,599 // lfdx/lfdux ?
129 cror cr1_eq,cr0_eq,cr1_eq
130 cmpwi r5,535 // lfsx/lfsux ?
131 cror cr1_eq,cr0_eq,cr1_eq
132 cmpwi r5,343 // lhax/lhaux ?
133 cror cr1_eq,cr0_eq,cr1_eq
134 cmpwi r4,790 // lhbrx ?
135 cror cr1_eq,cr0_eq,cr1_eq
136 cmpwi r5,279 // lhzx/lhzux ?
137 cror cr1_eq,cr0_eq,cr1_eq
138 cmpwi r4,597 // lswi ?
139 cror cr1_eq,cr0_eq,cr1_eq
140 cmpwi r4,533 // lswx ?
141 cror cr1_eq,cr0_eq,cr1_eq
142 cmpwi r5,341 // lwax/lwaux ?
143 cror cr1_eq,cr0_eq,cr1_eq
144 cmpwi r4,534 // lwbrx ?
145 cror cr1_eq,cr0_eq,cr1_eq
146 cmpwi r5,23 // lwz/lwzx ?
147 cror cr1_eq,cr0_eq,cr1_eq
148 cmpwi r5,149 // stdx/stdux ?
149 cror cr1_eq,cr0_eq,cr1_eq
150 cmpwi r5,727 // stfdx/stfdux ?
151 cror cr1_eq,cr0_eq,cr1_eq
152 cmpwi r4,983 // stfiwx ?
153 cror cr1_eq,cr0_eq,cr1_eq
154 cmpwi r5,663 // stfsx/stfsux ?
155 cror cr1_eq,cr0_eq,cr1_eq
156 cmpwi r4,918 // sthbrx ?
157 cror cr1_eq,cr0_eq,cr1_eq
158 cmpwi r5,407 // sthx/sthux ?
159 cror cr1_eq,cr0_eq,cr1_eq
160 cmpwi r4,725 // stswi ?
161 cror cr1_eq,cr0_eq,cr1_eq
162 cmpwi r4,661 // stswx ?
163 cror cr1_eq,cr0_eq,cr1_eq
164 cmpwi r4,662 // stwbrx ?
165 cror cr1_eq,cr0_eq,cr1_eq
166 cmpwi r5,151 // stwx/stwux ?
167 cror cr1_eq,cr0_eq,cr1_eq
168
169 beq++ cr1,a64GotInstruction // it was one of the X-forms we handle
170 crclr kAlignment // revert to program interrupt
171 b a64PassAlong // not recognized extended opcode
172
173
174 // *****************************************
175 // * A L I G N M E N T I N T E R R U P T *
176 // *****************************************
177 //
178 // We get here in exception context, ie with interrupts disabled, translation off, and
179 // in 64-bit mode, with:
180 // r13 = save-area pointer, with general context already saved in it
181 // cr6 = feature flags
182 // We preserve r13 and cr6. Other GPRs and CRs, the LR and CTR are used.
183 //
184 // Current 64-bit processors (GPUL) handle almost all misaligned operations in hardware,
185 // so this routine usually isn't called very often. Only floating pt ops that cross a page
186 // boundary and are not word aligned, and LMW/STMW can take exceptions to cacheable memory.
187 // However, in contrast to G3 and G4, any misaligned load/store will get an alignment
188 // interrupt on uncached memory.
189 //
190 // We always emulate scalar ops with a series of byte load/stores. Doing so is no slower
191 // than LWZ/STW in cases where a scalar op gets an alignment exception.
192 //
193 // This routine supports all legal permutations of alignment interrupts occuring in user or
194 // supervisor mode, 32 or 64-bit addressing, and translation on or off. We do not emulate
195 // instructions that go past the end of an address space, such as "LHZ -1(0)"; we just pass
196 // along the alignment exception rather than wrap around to byte 0.
197 //
198 // First, check for a few special cases such as virtual machines, etc.
199
200 .globl EXT(AlignAssist64)
201 .align 5
202 LEXT(AlignAssist64)
203 crset kAlignment // mark as alignment interrupt
204
205 a64AlignAssistJoin: // join here from program interrupt handler
206 li r0,0 // Get a 0
207 mfsprg r31,0 // get the per_proc data ptr
208 mcrf cr3,cr6 // save feature flags here...
209 lwz r21,spcFlags(r31) // grab the special flags
210 ld r29,savesrr1(r13) // get the MSR etc at the fault
211 ld r28,savesrr0(r13) // get the EA of faulting instruction
212 stw r0,savemisc3(r13) // Assume we will handle this ok
213 mfmsr r26 // save MSR at entry
214 rlwinm. r0,r21,0,runningVMbit,runningVMbit // Are we running a VM?
215 lwz r19,dgFlags(0) // Get the diagnostics flags
216 bne-- a64PassAlong // yes, let the virtual machine monitor handle
217
218
219 // Set up the MSR shadow regs. We turn on FP in this routine, and usually set DR and RI
220 // when accessing user space (the SLB is still set up with all the user space translations.)
221 // However, if the interrupt occured in the kernel with DR off, we keep it off while
222 // accessing the "target" address space. If we set DR to access the target space, we also
223 // set RI. The RI bit tells the exception handlers to clear cr0 beq and return if we get an
224 // exception accessing the user address space. We are careful to test cr0 beq after every such
225 // access. We keep the following "shadows" of the MSR in global regs across this code:
226 // r25 = MSR at entry, plus FP and probably DR and RI (used to access target space)
227 // r26 = MSR at entry
228 // r27 = free
229 // r29 = SRR1 (ie, MSR at interrupt)
230 // Note that EE and IR are always off, and SF is always on in this code.
231
232 rlwinm r3,r29,0,MSR_DR_BIT,MSR_DR_BIT // was translation on at fault?
233 rlwimi r3,r3,32-MSR_RI_BIT+MSR_DR_BIT,MSR_RI_BIT,MSR_RI_BIT // if DR was set, set RI too
234 or r25,r26,r3 // assemble MSR to use accessing target space
235
236
237 // Because the DSISR and DAR are either not set or are not to be trusted on some 64-bit
238 // processors on an alignment interrupt, we must fetch the faulting instruction ourselves,
239 // then decode/hash the opcode and reconstruct the EA manually.
240
241 mtmsr r25 // turn on FP and (if it was on at fault) DR and RI
242 isync // wait for it to happen
243 cmpw r0,r0 // turn on beq so we can check for DSIs
244 lwz r20,0(r28) // fetch faulting instruction, probably with DR on
245 bne-- a64RedriveAsISI // got a DSI trying to fetch it, pretend it was an ISI
246 mtmsr r26 // turn DR back off
247 isync // wait for it to happen
248
249
250 // Set a few flags while we wait for the faulting instruction to arrive from cache.
251
252 rlwinm. r0,r29,0,MSR_SE_BIT,MSR_SE_BIT // Were we single stepping?
253 stw r20,savemisc2(r13) // Save the instruction image in case we notify
254 crnot kTrace,cr0_eq
255 rlwinm. r0,r19,0,enaNotifyEMb,enaNotifyEMb // Should we notify?
256 crnot kNotify,cr0_eq
257
258
259 // Hash the intruction into a 5-bit value "AAAAB" used to index the branch table, and a
260 // 1-bit kUpdate flag, as follows:
261 // ¥ for X-form instructions (with primary opcode 31):
262 // the "AAAA" bits are bits 21-24 of the instruction
263 // the "B" bit is the XOR of bits 29 and 30
264 // the update bit is instruction bit 25
265 // ¥ for D and DS-form instructions (actually, any primary opcode except 31):
266 // the "AAAA" bits are bits 1-4 of the instruction
267 // the "B" bit is 0
268 // the update bit is instruction bit 5
269 //
270 // Just for fun (and perhaps a little speed on deep-pipe machines), we compute the hash,
271 // update flag, and EA without branches and with ipc >= 2.
272 //
273 // When we "bctr" to the opcode-specific reoutine, the following are all set up:
274 // MSR = EE and IR off, SF and FP on
275 // r12 = full 64-bit EA (r17 is clamped EA)
276 // r13 = save-area pointer (physical)
277 // r14 = ptr to saver0 in save-area (ie, to base of GPRs)
278 // r15 = 0x00000000FFFFFFFF if 32-bit mode fault, 0xFFFFFFFFFFFFFFFF if 64
279 // r16 = RA * 8 (ie, reg# not reg value)
280 // r17 = EA, clamped to 32 bits if 32-bit mode fault (see also r12)
281 // r18 = (RA|0) (reg value)
282 // r19 = -1 if X-form, 0 if D-form
283 // r20 = faulting instruction
284 // r21 = RT * 8 (ie, reg# not reg value)
285 // r22 = addr(aaFPopTable)+(RT*32), ie ptr to floating pt table for target register
286 // r25 = MSR at entrance, probably with DR and RI set (for access to target space)
287 // r26 = MSR at entrance
288 // r27 = free
289 // r28 = SRR0 (ie, EA of faulting instruction)
290 // r29 = SRR1 (ie, MSR at fault)
291 // r30 = scratch, usually user data
292 // r31 = per-proc pointer
293 // cr2 = kTrace, kNotify, and kAlignment flags
294 // cr3 = saved copy of feature flags used in lowmem vector code
295 // cr6 = bits 24-27 of CR are bits 24-27 of opcode if X-form, or bits 4-5 and 00 if D-form
296 // bit 25 is the kUpdate flag, set for update form instructions
297 // cr7 = bits 28-31 of CR are bits 28-31 of opcode if X-form, or 0 if D-form
298
299 a64GotInstruction: // here from program interrupt with instruction in r20
300 rlwinm r21,r20,6+6,20,25 // move the primary opcode (bits 0-6) to bits 20-25
301 la r14,saver0(r13) // r14 <- base address of GPR registers
302 xori r19,r21,0x07C0 // iff primary opcode is 31, set r19 to 0
303 rlwinm r16,r20,16+3,24,28 // r16 <- RA*8
304 subi r19,r19,1 // set bit 0 iff X-form (ie, if primary opcode is 31)
305 rlwinm r17,r20,21+3,24,28 // r17 <- RB*8 (if X-form)
306 sradi r19,r19,63 // r19 <- -1 if X-form, 0 if D-form
307 extsh r22,r20 // r22 <- displacement (if D-form)
308
309 ldx r23,r14,r17 // get (RB), if any
310 and r15,r20,r19 // instruction if X, 0 if D
311 andc r17,r21,r19 // primary opcode in bits 20-25 if D, 0 if X
312 ldx r18,r14,r16 // get (RA)
313 subi r24,r16,1 // set bit 0 iff RA==0
314 or r21,r15,r17 // r21 <- instruction if X, or bits 0-5 in bits 20-25 if D
315 sradi r24,r24,63 // r24 <- -1 if RA==0, 0 otherwise
316 rlwinm r17,r21,32-4,25,28 // shift opcode bits 21-24 to 25-28 (hash "AAAA" bits)
317 lis r10,ha16(a64BranchTable) // start to build up branch table address
318 rlwimi r17,r21,0,29,29 // move opcode bit 29 into hash as start of "B" bit
319 rlwinm r30,r21,1,29,29 // position opcode bit 30 in position 29
320 and r12,r23,r19 // RB if X-form, 0 if D-form
321 andc r11,r22,r19 // 0 if X-form, sign extended displacement if D-form
322 xor r17,r17,r30 // bit 29 ("B") of hash is xor(bit29,bit30)
323 addi r10,r10,lo16(a64BranchTable)
324 or r12,r12,r11 // r12 <- (RB) or displacement, as appropriate
325 lwzx r30,r10,r17 // get address from branch table
326 mtcrf 0x01,r21 // move opcode bits 28-31 to CR7
327 sradi r15,r29,32 // propogate SF bit from SRR1 (MSR_SF, which is bit 0)
328 andc r18,r18,r24 // r18 <- (RA|0)
329 mtcrf 0x02,r21 // move opcode bits 24-27 to CR6 (kUpdate is bit 25)
330 add r12,r18,r12 // r12 <- 64-bit EA
331 mtctr r30 // set up branch address
332
333 oris r15,r15,0xFFFF // start to fill low word of r15 with 1s
334 rlwinm r21,r20,11+3,24,28 // r21 <- RT * 8
335 lis r22,ha16(EXT(aaFPopTable)) // start to compute address of floating pt table
336 ori r15,r15,0xFFFF // now bits 32-63 of r15 are 1s
337 addi r22,r22,lo16(EXT(aaFPopTable))
338 and r17,r12,r15 // clamp EA to 32 bits if fault occured in 32-bit mode
339 rlwimi r22,r21,2,22,26 // move RT into aaFPopTable address (which is 1KB aligned)
340
341 bf-- kAlignment,a64HandleProgramInt // return to Program Interrupt handler
342 bctr // if alignment interrupt, jump to opcode-specific routine
343
344
345 // Floating-pt load single (lfs[u], lfsx[u])
346
347 a64LfsLfsx:
348 bl a64Load4Bytes // get data in r30
349 mtctr r22 // set up address of "lfs fRT,emfp0(r31)"
350 stw r30,emfp0(r31) // put word here for aaFPopTable routine
351 bctrl // do the lfs
352 b a64UpdateCheck // update RA if necessary and exit
353
354
355 // Floating-pt store single (stfs[u], stfsx[u])
356
357 a64StfsStfsx:
358 ori r22,r22,8 // set dir==1 (ie, single store) in aaFPopTable
359 mtctr r22 // set up address of "stfs fRT,emfp0(r31)"
360 bctrl // execute the store into emfp0
361 lwz r30,emfp0(r31) // get the word
362 bl a64Store4Bytes // store r30 into user space
363 b a64UpdateCheck // update RA if necessary and exit
364
365
366 // Floating-pt store as integer word (stfiwx)
367
368 a64Stfiwx:
369 ori r22,r22,16+8 // set size=1, dir==1 (ie, double store) in aaFPopTable
370 mtctr r22 // set up FP register table address
371 bctrl // double precision store into emfp0
372 lwz r30,emfp0+4(r31) // get the low-order word
373 bl a64Store4Bytes // store r30 into user space
374 b a64Exit // successfully emulated
375
376
377 // Floating-pt load double (lfd[u], lfdx[u])
378
379 a64LfdLfdx:
380 ori r22,r22,16 // set Double bit in aaFPopTable address
381 bl a64Load8Bytes // get data in r30
382 mtctr r22 // set up address of "lfd fRT,emfp0(r31)"
383 std r30,emfp0(r31) // put doubleword here for aaFPopTable routine
384 bctrl // execute the load
385 b a64UpdateCheck // update RA if necessary and exit
386
387
388 // Floating-pt store double (stfd[u], stfdx[u])
389
390 a64StfdStfdx:
391 ori r22,r22,16+8 // set size=1, dir==1 (ie, double store) in aaFPopTable address
392 mtctr r22 // address of routine to stfd RT
393 bctrl // store into emfp0
394 ld r30,emfp0(r31) // get the doubleword
395 bl a64Store8Bytes // store r30 into user space
396 b a64UpdateCheck // update RA if necessary and exit
397
398
399 // Load halfword w 0-fill (lhz[u], lhzx[u])
400
401 a64LhzLhzx:
402 bl a64Load2Bytes // load into r30 from user space (w 0-fill)
403 stdx r30,r14,r21 // store into RT slot in register file
404 b a64UpdateCheck // update RA if necessary and exit
405
406
407 // Load halfword w sign fill (lha[u], lhax[u])
408
409 a64LhaLhax:
410 bl a64Load2Bytes // load into r30 from user space (w 0-fill)
411 extsh r30,r30 // sign-extend
412 stdx r30,r14,r21 // store into RT slot in register file
413 b a64UpdateCheck // update RA if necessary and exit
414
415
416 // Load halfword byte reversed (lhbrx)
417
418 a64Lhbrx:
419 bl a64Load2Bytes // load into r30 from user space (w 0-fill)
420 rlwinm r3,r30,8,16,23 // reverse bytes into r3
421 rlwimi r3,r30,24,24,31
422 stdx r3,r14,r21 // store into RT slot in register file
423 b a64Exit // successfully emulated
424
425
426 // Store halfword (sth[u], sthx[u])
427
428 a64SthSthx:
429 ldx r30,r14,r21 // get RT
430 bl a64Store2Bytes // store r30 into user space
431 b a64UpdateCheck // update RA if necessary and exit
432
433
434 // Store halfword byte reversed (sthbrx)
435
436 a64Sthbrx:
437 addi r21,r21,6 // point to low two bytes of RT
438 lhbrx r30,r14,r21 // load and reverse
439 bl a64Store2Bytes // store r30 into user space
440 b a64Exit // successfully emulated
441
442
443 // Load word w 0-fill (lwz[u], lwzx[u]), also lwarx.
444
445 a64LwzLwzxLwarx:
446 andc r3,r19,r20 // light bit 30 of r3 iff lwarx
447 andi. r0,r3,2 // is it lwarx?
448 bne-- a64PassAlong // yes, never try to emulate a lwarx
449 bl a64Load4Bytes // load 4 bytes from user space into r30 (0-filled)
450 stdx r30,r14,r21 // update register file
451 b a64UpdateCheck // update RA if necessary and exit
452
453
454 // Load word w sign fill (lwa, lwax[u])
455
456 a64Lwa:
457 crclr kUpdate // no update form of lwa (its a reserved encoding)
458 a64Lwax:
459 bl a64Load4Bytes // load 4 bytes from user space into r30 (0-filled)
460 extsw r30,r30 // sign extend
461 stdx r30,r14,r21 // update register file
462 b a64UpdateCheck // update RA if necessary and exit
463
464
465 // Load word byte reversed (lwbrx)
466
467 a64Lwbrx:
468 bl a64Load4Bytes // load 4 bytes from user space into r30 (0-filled)
469 rlwinm r3,r30,24,0,31 // flip bytes 1234 to 4123
470 rlwimi r3,r30,8,8,15 // r3 is now 4323
471 rlwimi r3,r30,8,24,31 // r3 is now 4321
472 stdx r3,r14,r21 // update register file
473 b a64Exit // successfully emulated
474
475
476 // Store word (stw[u], stwx[u])
477
478 a64StwStwx:
479 ldx r30,r14,r21 // get RT
480 bl a64Store4Bytes // store r30 into user space
481 b a64UpdateCheck // update RA if necessary and exit
482
483
484 // Store word byte reversed (stwbrx)
485
486 a64Stwbrx:
487 addi r21,r21,4 // point to low word of RT
488 lwbrx r30,r14,r21 // load and reverse
489 bl a64Store4Bytes // store r30 into user space
490 b a64Exit // successfully emulated
491
492
493 // Load doubleword (ld[u], ldx[u]), also lwa.
494
495 a64LdLwa: // these are DS form: ld=0, ldu=1, and lwa=2
496 mtcrf 0x01,r20 // move DS field to cr7
497 rlwinm r3,r20,0,30,31 // must adjust EA by subtracting DS field
498 sub r12,r12,r3 // subtract from full 64-bit EA
499 and r17,r12,r15 // then re-clamp to 32 bits if necessary
500 bt 30,a64Lwa // handle lwa
501 crmove kUpdate,31 // if opcode bit 31 is set, it is ldu so set update flag
502 a64Ldx:
503 bl a64Load8Bytes // load 8 bytes from user space into r30
504 stdx r30,r14,r21 // update register file
505 b a64UpdateCheck // update RA if necessary and exit
506
507
508 // Store doubleword (stdx[u], std[u], stwcx)
509
510 a64StdxStwcx:
511 bf-- 30,a64PassAlong // stwcx, so pass along alignment exception
512 b a64Stdx // was stdx
513 a64StdStfiwx: // if DS form: 0=std, 1=stdu, 2-3=undefined
514 bt 30,a64Stfiwx // handle stfiwx
515 rlwinm r3,r20,0,30,31 // must adjust EA by subtracting DS field
516 mtcrf 0x01,r20 // move DS field to cr7
517 sub r12,r12,r3 // subtract from full 64-bit EA
518 and r17,r12,r15 // then re-clamp to 32 bits if necessary
519 crmove kUpdate,31 // if DS==1, then it is update form
520 a64Stdx:
521 ldx r30,r14,r21 // get RT
522 bl a64Store8Bytes // store RT into user space
523 b a64UpdateCheck // update RA if necessary and exit
524
525
526 // Dcbz and Dcbz128 (bit 10 distinguishes the two forms)
527
528 a64DcbzDcbz128:
529 andis. r0,r20,0x0020 // bit 10 set?
530 li r3,0 // get a 0 to store
531 li r0,4 // assume 32-bit version, store 8 bytes 4x
532 rldicr r17,r17,0,63-5 // 32-byte align EA
533 li r4,_COMM_PAGE_BASE_ADDRESS
534 beq a64DcbzSetup // it was the 32-byte version
535 rldicr r17,r17,0,63-7 // zero low 7 bits of EA
536 li r0,16 // store 8 bytes 16x
537 a64DcbzSetup:
538 sub r4,r28,r4 // get instruction offset from start of commpage
539 and r4,r4,r15 // mask off high-order bits if 32-bit mode
540 cmpldi r4,_COMM_PAGE_AREA_USED // did fault occur in commpage area?
541 bge a64NotCommpage // not in commpage
542 rlwinm. r4,r29,0,MSR_PR_BIT,MSR_PR_BIT // did fault occur in user mode?
543 beq-- a64NotCommpage // do not zero cr7 if kernel got alignment exception
544 lwz r4,savecr(r13) // if we take a dcbz{128} in the commpage...
545 rlwinm r4,r4,0,0,27 // ...clear user's cr7...
546 stw r4,savecr(r13) // ...as a flag for commpage code
547 a64NotCommpage:
548 mtctr r0
549 cmpw r0,r0 // turn cr0 beq on so we can check for DSIs
550 mtmsr r25 // turn on DR and RI so we can address user space
551 isync // wait for it to happen
552 a64DcbzLoop:
553 std r3,0(r17) // store into user space
554 bne-- a64RedriveAsDSI
555 addi r17,r17,8
556 bdnz a64DcbzLoop
557
558 mtmsr r26 // restore MSR
559 isync // wait for it to happen
560 b a64Exit
561
562
563 // Load and store multiple (lmw, stmw), distinguished by bit 25
564
565 a64LmwStmw:
566 subfic r22,r21,32*8 // how many regs to load or store?
567 srwi r22,r22,1 // get bytes to load/store
568 bf 25,a64LoadMultiple // handle lmw
569 b a64StoreMultiple // it was stmw
570
571
572 // Load string word immediate (lswi)
573
574 a64Lswi:
575 rlwinm r22,r20,21,27,31 // get #bytes in r22
576 and r17,r18,r15 // recompute EA as (RA|0), and clamp
577 subi r3,r22,1 // r22==0?
578 rlwimi r22,r3,6,26,26 // map count of 0 to 32
579 b a64LoadMultiple
580
581
582 // Store string word immediate (stswi)
583
584 a64Stswi:
585 rlwinm r22,r20,21,27,31 // get #bytes in r22
586 and r17,r18,r15 // recompute EA as (RA|0), and clamp
587 subi r3,r22,1 // r22==0?
588 rlwimi r22,r3,6,26,26 // map count of 0 to 32
589 b a64StoreMultiple
590
591
592 // Load string word indexed (lswx), also lwbrx
593
594 a64LswxLwbrx:
595 bf 30,a64Lwbrx // was lwbrx
596 ld r22,savexer(r13) // get the xer
597 rlwinm r22,r22,0,25,31 // isolate the byte count
598 b a64LoadMultiple // join common code
599
600
601 // Store string word indexed (stswx), also stwbrx
602
603 a64StswxStwbrx:
604 bf 30,a64Stwbrx // was stwbrx
605 ld r22,savexer(r13) // get the xer
606 rlwinm r22,r22,0,25,31 // isolate the byte count
607 b a64StoreMultiple // join common code
608
609
610 // Load multiple words. This handles lmw, lswi, and lswx.
611
612 a64LoadMultiple: // r22 = byte count, may be 0
613 subic. r3,r22,1 // get (#bytes-1)
614 blt a64Exit // done if 0
615 add r4,r17,r3 // get EA of last operand byte
616 and r4,r4,r15 // clamp
617 cmpld r4,r17 // address space wrap?
618 blt-- a64PassAlong // pass along exception if so
619 srwi. r4,r22,2 // get # full words to load
620 rlwinm r22,r22,0,30,31 // r22 <- leftover byte count
621 cmpwi cr1,r22,0 // leftover bytes?
622 beq a64Lm3 // no words
623 mtctr r4 // set up word count
624 cmpw r0,r0 // set beq for DSI test
625 a64Lm2:
626 mtmsr r25 // turn on DR and RI
627 isync // wait for it to happen
628 lbz r3,0(r17)
629 bne-- a64RedriveAsDSI // got a DSI
630 lbz r4,1(r17)
631 bne-- a64RedriveAsDSI // got a DSI
632 lbz r5,2(r17)
633 bne-- a64RedriveAsDSI // got a DSI
634 lbz r6,3(r17)
635 bne-- a64RedriveAsDSI // got a DSI
636 rlwinm r30,r3,24,0,7 // pack bytes into r30
637 rldimi r30,r4,16,40
638 rldimi r30,r5,8,48
639 rldimi r30,r6,0,56
640 mtmsr r26 // turn DR back off so we can store into register file
641 isync
642 addi r17,r17,4 // bump EA
643 stdx r30,r14,r21 // pack into register file
644 addi r21,r21,8 // bump register file offset
645 rlwinm r21,r21,0,24,28 // wrap around to 0
646 bdnz a64Lm2
647 a64Lm3: // cr1/r22 = leftover bytes (0-3), cr0 beq set
648 beq cr1,a64Exit // no leftover bytes
649 mtctr r22
650 mtmsr r25 // turn on DR so we can access user space
651 isync
652 lbz r3,0(r17) // get 1st leftover byte
653 bne-- a64RedriveAsDSI // got a DSI
654 rlwinm r30,r3,24,0,7 // position in byte 4 of r30 (and clear rest of r30)
655 bdz a64Lm4 // only 1 byte leftover
656 lbz r3,1(r17) // get 2nd byte
657 bne-- a64RedriveAsDSI // got a DSI
658 rldimi r30,r3,16,40 // insert into byte 5 of r30
659 bdz a64Lm4 // only 2 bytes leftover
660 lbz r3,2(r17) // get 3rd byte
661 bne-- a64RedriveAsDSI // got a DSI
662 rldimi r30,r3,8,48 // insert into byte 6
663 a64Lm4:
664 mtmsr r26 // turn DR back off so we can store into register file
665 isync
666 stdx r30,r14,r21 // pack partially-filled word into register file
667 b a64Exit
668
669
670 // Store multiple words. This handles stmw, stswi, and stswx.
671
672 a64StoreMultiple: // r22 = byte count, may be 0
673 subic. r3,r22,1 // get (#bytes-1)
674 blt a64Exit // done if 0
675 add r4,r17,r3 // get EA of last operand byte
676 and r4,r4,r15 // clamp
677 cmpld r4,r17 // address space wrap?
678 blt-- a64PassAlong // pass along exception if so
679 srwi. r4,r22,2 // get # full words to load
680 rlwinm r22,r22,0,30,31 // r22 <- leftover byte count
681 cmpwi cr1,r22,0 // leftover bytes?
682 beq a64Sm3 // no words
683 mtctr r4 // set up word count
684 cmpw r0,r0 // turn on beq so we can check for DSIs
685 a64Sm2:
686 ldx r30,r14,r21 // get next register
687 addi r21,r21,8 // bump register file offset
688 rlwinm r21,r21,0,24,28 // wrap around to 0
689 srwi r3,r30,24 // shift the four bytes into position
690 srwi r4,r30,16
691 srwi r5,r30,8
692 mtmsr r25 // turn on DR so we can access user space
693 isync // wait for it to happen
694 stb r3,0(r17)
695 bne-- a64RedriveAsDSI // got a DSI
696 stb r4,1(r17)
697 bne-- a64RedriveAsDSI // got a DSI
698 stb r5,2(r17)
699 bne-- a64RedriveAsDSI // got a DSI
700 stb r30,3(r17)
701 bne-- a64RedriveAsDSI // got a DSI
702 mtmsr r26 // turn DR back off
703 isync
704 addi r17,r17,4 // bump EA
705 bdnz a64Sm2
706 a64Sm3: // r22 = 0-3, cr1 set on r22, cr0 beq set
707 beq cr1,a64Exit // no leftover bytes
708 ldx r30,r14,r21 // get last register
709 mtctr r22
710 mtmsr r25 // turn on DR so we can access user space
711 isync // wait for it to happen
712 a64Sm4:
713 rlwinm r30,r30,8,0,31 // position next byte
714 stb r30,0(r17) // pack into user space
715 addi r17,r17,1 // bump user space ptr
716 bne-- a64RedriveAsDSI // got a DSI
717 bdnz a64Sm4
718 mtmsr r26 // turn DR back off
719 isync
720 b a64Exit
721
722
723 // Subroutines to load bytes from user space.
724
725 a64Load2Bytes: // load 2 bytes right-justified into r30
726 addi r7,r17,1 // get EA of last byte
727 and r7,r7,r15 // clamp
728 cmpld r7,r17 // address wrap?
729 blt-- a64PassAlong // yes
730 mtmsr r25 // turn on DR so we can access user space
731 isync // wait for it to happen
732 sub. r30,r30,r30 // 0-fill dest and set beq
733 b a64Load2 // jump into routine
734 a64Load4Bytes: // load 4 bytes right-justified into r30 (ie, low order word)
735 addi r7,r17,3 // get EA of last byte
736 and r7,r7,r15 // clamp
737 cmpld r7,r17 // address wrap?
738 blt-- a64PassAlong // yes
739 mtmsr r25 // turn on DR so we can access user space
740 isync // wait for it to happen
741 sub. r30,r30,r30 // 0-fill dest and set beq
742 b a64Load4 // jump into routine
743 a64Load8Bytes: // load 8 bytes into r30
744 addi r7,r17,7 // get EA of last byte
745 and r7,r7,r15 // clamp
746 cmpld r7,r17 // address wrap?
747 blt-- a64PassAlong // yes
748 mtmsr r25 // turn on DR so we can access user space
749 isync // wait for it to happen
750 sub. r30,r30,r30 // 0-fill dest and set beq
751 lbz r3,-7(r7) // get byte 0
752 bne-- a64RedriveAsDSI // got a DSI
753 lbz r4,-6(r7) // and byte 1, etc
754 bne-- a64RedriveAsDSI // got a DSI
755 lbz r5,-5(r7)
756 bne-- a64RedriveAsDSI // got a DSI
757 lbz r6,-4(r7)
758 bne-- a64RedriveAsDSI // got a DSI
759 rldimi r30,r3,56,0 // position bytes in upper word
760 rldimi r30,r4,48,8
761 rldimi r30,r5,40,16
762 rldimi r30,r6,32,24
763 a64Load4:
764 lbz r3,-3(r7)
765 bne-- a64RedriveAsDSI // got a DSI
766 lbz r4,-2(r7)
767 bne-- a64RedriveAsDSI // got a DSI
768 rldimi r30,r3,24,32 // insert bytes 4 and 5 into r30
769 rldimi r30,r4,16,40
770 a64Load2:
771 lbz r3,-1(r7)
772 bne-- a64RedriveAsDSI // got a DSI
773 lbz r4,0(r7)
774 bne-- a64RedriveAsDSI // got a DSI
775 mtmsr r26 // turn DR back off
776 isync
777 rldimi r30,r3,8,48 // insert bytes 6 and 7 into r30
778 rldimi r30,r4,0,56
779 blr
780
781
782 // Subroutines to store bytes into user space.
783
784 a64Store2Bytes: // store bytes 6 and 7 of r30
785 addi r7,r17,1 // get EA of last byte
786 and r7,r7,r15 // clamp
787 cmpld r7,r17 // address wrap?
788 blt-- a64PassAlong // yes
789 mtmsr r25 // turn on DR so we can access user space
790 isync // wait for it to happen
791 cmpw r0,r0 // set beq so we can check for DSI
792 b a64Store2 // jump into routine
793 a64Store4Bytes: // store bytes 4-7 of r30 (ie, low order word)
794 addi r7,r17,3 // get EA of last byte
795 and r7,r7,r15 // clamp
796 cmpld r7,r17 // address wrap?
797 blt-- a64PassAlong // yes
798 mtmsr r25 // turn on DR so we can access user space
799 isync // wait for it to happen
800 cmpw r0,r0 // set beq so we can check for DSI
801 b a64Store4 // jump into routine
802 a64Store8Bytes: // r30 = bytes
803 addi r7,r17,7 // get EA of last byte
804 and r7,r7,r15 // clamp
805 cmpld r7,r17 // address wrap?
806 blt-- a64PassAlong // yes
807 mtmsr r25 // turn on DR so we can access user space
808 isync // wait for it to happen
809 cmpw r0,r0 // set beq so we can check for DSI
810 rotldi r3,r30,8 // shift byte 0 into position
811 rotldi r4,r30,16 // and byte 1
812 rotldi r5,r30,24 // and byte 2
813 rotldi r6,r30,32 // and byte 3
814 stb r3,-7(r7) // store byte 0
815 bne-- a64RedriveAsDSI // got a DSI
816 stb r4,-6(r7) // and byte 1 etc...
817 bne-- a64RedriveAsDSI // got a DSI
818 stb r5,-5(r7)
819 bne-- a64RedriveAsDSI // got a DSI
820 stb r6,-4(r7)
821 bne-- a64RedriveAsDSI // got a DSI
822 a64Store4:
823 rotldi r3,r30,40 // shift byte 4 into position
824 rotldi r4,r30,48 // and byte 5
825 stb r3,-3(r7)
826 bne-- a64RedriveAsDSI // got a DSI
827 stb r4,-2(r7)
828 bne-- a64RedriveAsDSI // got a DSI
829 a64Store2:
830 rotldi r3,r30,56 // shift byte 6 into position
831 stb r3,-1(r7) // store byte 6
832 bne-- a64RedriveAsDSI // got a DSI
833 stb r30,0(r7) // store byte 7, which is already positioned
834 bne-- a64RedriveAsDSI // got a DSI
835 mtmsr r26 // turn off DR
836 isync
837 blr
838
839
840 // Exit routines.
841
842 a64ExitEm:
843 li r30,T_EMULATE // Change exception code to emulate
844 stw r30,saveexception(r13) // Save it
845 b a64Exit // Join standard exit routine...
846
847 a64PassAlong: // unhandled exception, just pass it along
848 li r0,1 // Set that the alignment/program exception was not emulated
849 crset kNotify // return T_ALIGNMENT or T_PROGRAM
850 stw r0,savemisc3(r13) // Set that emulation was not done
851 crclr kTrace // not a trace interrupt
852 b a64Exit1
853 a64UpdateCheck: // successfully emulated, may be update form
854 bf kUpdate,a64Exit // update?
855 stdx r12,r14,r16 // yes, store 64-bit EA into RA
856 a64Exit: // instruction successfully emulated
857 addi r28,r28,4 // bump SRR0 past the emulated instruction
858 li r30,T_IN_VAIN // eat the interrupt since we emulated it
859 and r28,r28,r15 // clamp to address space size (32 vs 64)
860 std r28,savesrr0(r13) // save, so we return to next instruction
861 a64Exit1:
862 bt-- kTrace,a64Trace // were we in single-step at fault?
863 bt-- kNotify,a64Notify // should we say T_ALIGNMENT anyway?
864 a64Exit2:
865 mcrf cr6,cr3 // restore feature flags
866 mr r11,r30 // pass back exception code (T_IN_VAIN etc) in r11
867 b EXT(EmulExit) // return to exception processing
868
869
870 // Notification requested: pass exception upstairs even though it might have been emulated.
871
872 a64Notify:
873 li r30,T_ALIGNMENT // somebody wants to know about it (but don't redrive)
874 bt kAlignment,a64Exit2 // was an alignment exception
875 li r30,T_PROGRAM // was an emulated instruction
876 b a64Exit2
877
878
879 // Emulate a trace interrupt after handling alignment interrupt.
880
881 a64Trace:
882 lwz r9,SAVflags(r13) // get the save-area flags
883 li r30,T_TRACE
884 oris r9,r9,hi16(SAVredrive) // Set the redrive bit
885 stw r30,saveexception(r13) // Set the exception code
886 stw r9,SAVflags(r13) // Set the flags
887 b a64Exit2 // Exit and do trace interrupt...
888
889
890 // Got a DSI accessing user space. Redrive. One way this can happen is if another
891 // processor removes a mapping while we are emulating.
892
893 a64RedriveAsISI: // this DSI happened fetching the opcode (r1==DSISR r4==DAR)
894 mtmsr r26 // turn DR back off
895 isync // wait for it to happen
896 li r30,T_INSTRUCTION_ACCESS
897 rlwimi r29,r1,0,0,4 // insert the fault type from DSI's DSISR
898 std r29,savesrr1(r13) // update SRR1 to look like an ISI
899 b a64Redrive
900
901 a64RedriveAsDSI: // r0==DAR r1==DSISR
902 mtmsr r26 // turn DR back off
903 isync // wait for it to happen
904 stw r1,savedsisr(r13) // Set the DSISR of failed access
905 std r0,savedar(r13) // Set the address of the failed access
906 li r30,T_DATA_ACCESS // Set failing data access code
907 a64Redrive:
908 lwz r9,SAVflags(r13) // Pick up the flags
909 stw r30,saveexception(r13) // Set the replacement code
910 oris r9,r9,hi16(SAVredrive) // Set the redrive bit
911 stw r9,SAVflags(r13) // Set redrive request
912 crclr kTrace // don't take a trace interrupt
913 crclr kNotify // don't pass alignment exception
914 b a64Exit2 // done
915
916
917 // This is the branch table, indexed by the "AAAAB" opcode hash.
918
919 a64BranchTable:
920 .long a64LwzLwzxLwarx // 00000 lwz[u], lwzx[u], lwarx
921 .long a64Ldx // 00001 ldx[u]
922 .long a64PassAlong // 00010 ldarx (never emulate these)
923 .long a64PassAlong // 00011
924 .long a64StwStwx // 00100 stw[u], stwx[u]
925 .long a64StdxStwcx // 00101 stdx[u], stwcx
926 .long a64PassAlong // 00110
927 .long a64PassAlong // 00111 stdcx (never emulate these)
928 .long a64LhzLhzx // 01000 lhz[u], lhzx[u]
929 .long a64PassAlong // 01001
930 .long a64LhaLhax // 01010 lha[u], lhax[u]
931 .long a64Lwax // 01011 lwax[u]
932 .long a64SthSthx // 01100 sth[u], sthx[u]
933 .long a64PassAlong // 01101
934 .long a64LmwStmw // 01110 lmw, stmw
935 .long a64PassAlong // 01111
936 .long a64LfsLfsx // 10000 lfs[u], lfsx[u]
937 .long a64LswxLwbrx // 10001 lswx, lwbrx
938 .long a64LfdLfdx // 10010 lfd[u], lfdx[u]
939 .long a64Lswi // 10011 lswi
940 .long a64StfsStfsx // 10100 stfs[u], stfsx[u]
941 .long a64StswxStwbrx // 10101 stswx, stwbrx
942 .long a64StfdStfdx // 10110 stfd[u], stfdx[u]
943 .long a64Stswi // 10111 stswi
944 .long a64PassAlong // 11000
945 .long a64Lhbrx // 11001 lhbrx
946 .long a64LdLwa // 11010 ld[u], lwa
947 .long a64PassAlong // 11011
948 .long a64PassAlong // 11100
949 .long a64Sthbrx // 11101 sthbrx
950 .long a64StdStfiwx // 11110 std[u], stfiwx
951 .long a64DcbzDcbz128 // 11111 dcbz, dcbz128
952
953