1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 *
4 * Copyright Novell Inc 2010
5 *
6 * Authors: Alexander Graf <agraf@suse.de>
7 */
8
9#include <asm/kvm.h>
10#include <asm/kvm_ppc.h>
11#include <asm/disassemble.h>
12#include <asm/kvm_book3s.h>
13#include <asm/kvm_fpu.h>
14#include <asm/reg.h>
15#include <asm/cacheflush.h>
16#include <asm/switch_to.h>
17#include <linux/vmalloc.h>
18
19/* #define DEBUG */
20
21#ifdef DEBUG
22#define dprintk printk
23#else
24#define dprintk(...) do { } while(0);
25#endif
26
27#define OP_LFS 48
28#define OP_LFSU 49
29#define OP_LFD 50
30#define OP_LFDU 51
31#define OP_STFS 52
32#define OP_STFSU 53
33#define OP_STFD 54
34#define OP_STFDU 55
35#define OP_PSQ_L 56
36#define OP_PSQ_LU 57
37#define OP_PSQ_ST 60
38#define OP_PSQ_STU 61
39
40#define OP_31_LFSX 535
41#define OP_31_LFSUX 567
42#define OP_31_LFDX 599
43#define OP_31_LFDUX 631
44#define OP_31_STFSX 663
45#define OP_31_STFSUX 695
46#define OP_31_STFX 727
47#define OP_31_STFUX 759
48#define OP_31_LWIZX 887
49#define OP_31_STFIWX 983
50
51#define OP_59_FADDS 21
52#define OP_59_FSUBS 20
53#define OP_59_FSQRTS 22
54#define OP_59_FDIVS 18
55#define OP_59_FRES 24
56#define OP_59_FMULS 25
57#define OP_59_FRSQRTES 26
58#define OP_59_FMSUBS 28
59#define OP_59_FMADDS 29
60#define OP_59_FNMSUBS 30
61#define OP_59_FNMADDS 31
62
63#define OP_63_FCMPU 0
64#define OP_63_FCPSGN 8
65#define OP_63_FRSP 12
66#define OP_63_FCTIW 14
67#define OP_63_FCTIWZ 15
68#define OP_63_FDIV 18
69#define OP_63_FADD 21
70#define OP_63_FSQRT 22
71#define OP_63_FSEL 23
72#define OP_63_FRE 24
73#define OP_63_FMUL 25
74#define OP_63_FRSQRTE 26
75#define OP_63_FMSUB 28
76#define OP_63_FMADD 29
77#define OP_63_FNMSUB 30
78#define OP_63_FNMADD 31
79#define OP_63_FCMPO 32
80#define OP_63_MTFSB1 38 // XXX
81#define OP_63_FSUB 20
82#define OP_63_FNEG 40
83#define OP_63_MCRFS 64
84#define OP_63_MTFSB0 70
85#define OP_63_FMR 72
86#define OP_63_MTFSFI 134
87#define OP_63_FABS 264
88#define OP_63_MFFS 583
89#define OP_63_MTFSF 711
90
91#define OP_4X_PS_CMPU0 0
92#define OP_4X_PSQ_LX 6
93#define OP_4XW_PSQ_STX 7
94#define OP_4A_PS_SUM0 10
95#define OP_4A_PS_SUM1 11
96#define OP_4A_PS_MULS0 12
97#define OP_4A_PS_MULS1 13
98#define OP_4A_PS_MADDS0 14
99#define OP_4A_PS_MADDS1 15
100#define OP_4A_PS_DIV 18
101#define OP_4A_PS_SUB 20
102#define OP_4A_PS_ADD 21
103#define OP_4A_PS_SEL 23
104#define OP_4A_PS_RES 24
105#define OP_4A_PS_MUL 25
106#define OP_4A_PS_RSQRTE 26
107#define OP_4A_PS_MSUB 28
108#define OP_4A_PS_MADD 29
109#define OP_4A_PS_NMSUB 30
110#define OP_4A_PS_NMADD 31
111#define OP_4X_PS_CMPO0 32
112#define OP_4X_PSQ_LUX 38
113#define OP_4XW_PSQ_STUX 39
114#define OP_4X_PS_NEG 40
115#define OP_4X_PS_CMPU1 64
116#define OP_4X_PS_MR 72
117#define OP_4X_PS_CMPO1 96
118#define OP_4X_PS_NABS 136
119#define OP_4X_PS_ABS 264
120#define OP_4X_PS_MERGE00 528
121#define OP_4X_PS_MERGE01 560
122#define OP_4X_PS_MERGE10 592
123#define OP_4X_PS_MERGE11 624
124
125#define SCALAR_NONE 0
126#define SCALAR_HIGH (1 << 0)
127#define SCALAR_LOW (1 << 1)
128#define SCALAR_NO_PS0 (1 << 2)
129#define SCALAR_NO_PS1 (1 << 3)
130
131#define GQR_ST_TYPE_MASK 0x00000007
132#define GQR_ST_TYPE_SHIFT 0
133#define GQR_ST_SCALE_MASK 0x00003f00
134#define GQR_ST_SCALE_SHIFT 8
135#define GQR_LD_TYPE_MASK 0x00070000
136#define GQR_LD_TYPE_SHIFT 16
137#define GQR_LD_SCALE_MASK 0x3f000000
138#define GQR_LD_SCALE_SHIFT 24
139
140#define GQR_QUANTIZE_FLOAT 0
141#define GQR_QUANTIZE_U8 4
142#define GQR_QUANTIZE_U16 5
143#define GQR_QUANTIZE_S8 6
144#define GQR_QUANTIZE_S16 7
145
146#define FPU_LS_SINGLE 0
147#define FPU_LS_DOUBLE 1
148#define FPU_LS_SINGLE_LOW 2
149
150static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
151{
152 kvm_cvt_df(&VCPU_FPR(vcpu, rt), &vcpu->arch.qpr[rt]);
153}
154
155static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
156{
157 u32 dsisr;
158 u64 msr = kvmppc_get_msr(vcpu);
159
160 msr = kvmppc_set_field(msr, 33, 36, 0);
161 msr = kvmppc_set_field(msr, 42, 47, 0);
162 kvmppc_set_msr(vcpu, msr);
163 kvmppc_set_dar(vcpu, eaddr);
164 /* Page Fault */
165 dsisr = kvmppc_set_field(0, 33, 33, 1);
166 if (is_store)
167 dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
168 kvmppc_set_dsisr(vcpu, dsisr);
169 kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
170}
171
172static int kvmppc_emulate_fpr_load(struct kvm_vcpu *vcpu,
173 int rs, ulong addr, int ls_type)
174{
175 int emulated = EMULATE_FAIL;
176 int r;
177 char tmp[8];
178 int len = sizeof(u32);
179
180 if (ls_type == FPU_LS_DOUBLE)
181 len = sizeof(u64);
182
183 /* read from memory */
184 r = kvmppc_ld(vcpu, &addr, len, tmp, true);
185 vcpu->arch.paddr_accessed = addr;
186
187 if (r < 0) {
188 kvmppc_inject_pf(vcpu, eaddr: addr, is_store: false);
189 goto done_load;
190 } else if (r == EMULATE_DO_MMIO) {
191 emulated = kvmppc_handle_load(vcpu, KVM_MMIO_REG_FPR | rs,
192 len, 1);
193 goto done_load;
194 }
195
196 emulated = EMULATE_DONE;
197
198 /* put in registers */
199 switch (ls_type) {
200 case FPU_LS_SINGLE:
201 kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs));
202 vcpu->arch.qpr[rs] = *((u32*)tmp);
203 break;
204 case FPU_LS_DOUBLE:
205 VCPU_FPR(vcpu, rs) = *((u64*)tmp);
206 break;
207 }
208
209 dprintk(KERN_INFO "KVM: FPR_LD [0x%llx] at 0x%lx (%d)\n", *(u64*)tmp,
210 addr, len);
211
212done_load:
213 return emulated;
214}
215
216static int kvmppc_emulate_fpr_store(struct kvm_vcpu *vcpu,
217 int rs, ulong addr, int ls_type)
218{
219 int emulated = EMULATE_FAIL;
220 int r;
221 char tmp[8];
222 u64 val;
223 int len;
224
225 switch (ls_type) {
226 case FPU_LS_SINGLE:
227 kvm_cvt_df(&VCPU_FPR(vcpu, rs), (u32*)tmp);
228 val = *((u32*)tmp);
229 len = sizeof(u32);
230 break;
231 case FPU_LS_SINGLE_LOW:
232 *((u32*)tmp) = VCPU_FPR(vcpu, rs);
233 val = VCPU_FPR(vcpu, rs) & 0xffffffff;
234 len = sizeof(u32);
235 break;
236 case FPU_LS_DOUBLE:
237 *((u64*)tmp) = VCPU_FPR(vcpu, rs);
238 val = VCPU_FPR(vcpu, rs);
239 len = sizeof(u64);
240 break;
241 default:
242 val = 0;
243 len = 0;
244 }
245
246 r = kvmppc_st(vcpu, &addr, len, tmp, true);
247 vcpu->arch.paddr_accessed = addr;
248 if (r < 0) {
249 kvmppc_inject_pf(vcpu, eaddr: addr, is_store: true);
250 } else if (r == EMULATE_DO_MMIO) {
251 emulated = kvmppc_handle_store(vcpu, val, len, 1);
252 } else {
253 emulated = EMULATE_DONE;
254 }
255
256 dprintk(KERN_INFO "KVM: FPR_ST [0x%llx] at 0x%lx (%d)\n",
257 val, addr, len);
258
259 return emulated;
260}
261
262static int kvmppc_emulate_psq_load(struct kvm_vcpu *vcpu,
263 int rs, ulong addr, bool w, int i)
264{
265 int emulated = EMULATE_FAIL;
266 int r;
267 float one = 1.0;
268 u32 tmp[2];
269
270 /* read from memory */
271 if (w) {
272 r = kvmppc_ld(vcpu, &addr, sizeof(u32), tmp, true);
273 memcpy(&tmp[1], &one, sizeof(u32));
274 } else {
275 r = kvmppc_ld(vcpu, &addr, sizeof(u32) * 2, tmp, true);
276 }
277 vcpu->arch.paddr_accessed = addr;
278 if (r < 0) {
279 kvmppc_inject_pf(vcpu, eaddr: addr, is_store: false);
280 goto done_load;
281 } else if ((r == EMULATE_DO_MMIO) && w) {
282 emulated = kvmppc_handle_load(vcpu, KVM_MMIO_REG_FPR | rs,
283 4, 1);
284 vcpu->arch.qpr[rs] = tmp[1];
285 goto done_load;
286 } else if (r == EMULATE_DO_MMIO) {
287 emulated = kvmppc_handle_load(vcpu, KVM_MMIO_REG_FQPR | rs,
288 8, 1);
289 goto done_load;
290 }
291
292 emulated = EMULATE_DONE;
293
294 /* put in registers */
295 kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs));
296 vcpu->arch.qpr[rs] = tmp[1];
297
298 dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
299 tmp[1], addr, w ? 4 : 8);
300
301done_load:
302 return emulated;
303}
304
305static int kvmppc_emulate_psq_store(struct kvm_vcpu *vcpu,
306 int rs, ulong addr, bool w, int i)
307{
308 int emulated = EMULATE_FAIL;
309 int r;
310 u32 tmp[2];
311 int len = w ? sizeof(u32) : sizeof(u64);
312
313 kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp[0]);
314 tmp[1] = vcpu->arch.qpr[rs];
315
316 r = kvmppc_st(vcpu, &addr, len, tmp, true);
317 vcpu->arch.paddr_accessed = addr;
318 if (r < 0) {
319 kvmppc_inject_pf(vcpu, eaddr: addr, is_store: true);
320 } else if ((r == EMULATE_DO_MMIO) && w) {
321 emulated = kvmppc_handle_store(vcpu, tmp[0], 4, 1);
322 } else if (r == EMULATE_DO_MMIO) {
323 u64 val = ((u64)tmp[0] << 32) | tmp[1];
324 emulated = kvmppc_handle_store(vcpu, val, 8, 1);
325 } else {
326 emulated = EMULATE_DONE;
327 }
328
329 dprintk(KERN_INFO "KVM: PSQ_ST [0x%x, 0x%x] at 0x%lx (%d)\n",
330 tmp[0], tmp[1], addr, len);
331
332 return emulated;
333}
334
335/*
336 * Cuts out inst bits with ordering according to spec.
337 * That means the leftmost bit is zero. All given bits are included.
338 */
339static inline u32 inst_get_field(u32 inst, int msb, int lsb)
340{
341 return kvmppc_get_field(inst, msb + 32, lsb + 32);
342}
343
344static bool kvmppc_inst_is_paired_single(struct kvm_vcpu *vcpu, u32 inst)
345{
346 if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
347 return false;
348
349 switch (get_op(inst)) {
350 case OP_PSQ_L:
351 case OP_PSQ_LU:
352 case OP_PSQ_ST:
353 case OP_PSQ_STU:
354 case OP_LFS:
355 case OP_LFSU:
356 case OP_LFD:
357 case OP_LFDU:
358 case OP_STFS:
359 case OP_STFSU:
360 case OP_STFD:
361 case OP_STFDU:
362 return true;
363 case 4:
364 /* X form */
365 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
366 case OP_4X_PS_CMPU0:
367 case OP_4X_PSQ_LX:
368 case OP_4X_PS_CMPO0:
369 case OP_4X_PSQ_LUX:
370 case OP_4X_PS_NEG:
371 case OP_4X_PS_CMPU1:
372 case OP_4X_PS_MR:
373 case OP_4X_PS_CMPO1:
374 case OP_4X_PS_NABS:
375 case OP_4X_PS_ABS:
376 case OP_4X_PS_MERGE00:
377 case OP_4X_PS_MERGE01:
378 case OP_4X_PS_MERGE10:
379 case OP_4X_PS_MERGE11:
380 return true;
381 }
382 /* XW form */
383 switch (inst_get_field(inst, msb: 25, lsb: 30)) {
384 case OP_4XW_PSQ_STX:
385 case OP_4XW_PSQ_STUX:
386 return true;
387 }
388 /* A form */
389 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
390 case OP_4A_PS_SUM1:
391 case OP_4A_PS_SUM0:
392 case OP_4A_PS_MULS0:
393 case OP_4A_PS_MULS1:
394 case OP_4A_PS_MADDS0:
395 case OP_4A_PS_MADDS1:
396 case OP_4A_PS_DIV:
397 case OP_4A_PS_SUB:
398 case OP_4A_PS_ADD:
399 case OP_4A_PS_SEL:
400 case OP_4A_PS_RES:
401 case OP_4A_PS_MUL:
402 case OP_4A_PS_RSQRTE:
403 case OP_4A_PS_MSUB:
404 case OP_4A_PS_MADD:
405 case OP_4A_PS_NMSUB:
406 case OP_4A_PS_NMADD:
407 return true;
408 }
409 break;
410 case 59:
411 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
412 case OP_59_FADDS:
413 case OP_59_FSUBS:
414 case OP_59_FDIVS:
415 case OP_59_FRES:
416 case OP_59_FRSQRTES:
417 return true;
418 }
419 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
420 case OP_59_FMULS:
421 case OP_59_FMSUBS:
422 case OP_59_FMADDS:
423 case OP_59_FNMSUBS:
424 case OP_59_FNMADDS:
425 return true;
426 }
427 break;
428 case 63:
429 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
430 case OP_63_MTFSB0:
431 case OP_63_MTFSB1:
432 case OP_63_MTFSF:
433 case OP_63_MTFSFI:
434 case OP_63_MCRFS:
435 case OP_63_MFFS:
436 case OP_63_FCMPU:
437 case OP_63_FCMPO:
438 case OP_63_FNEG:
439 case OP_63_FMR:
440 case OP_63_FABS:
441 case OP_63_FRSP:
442 case OP_63_FDIV:
443 case OP_63_FADD:
444 case OP_63_FSUB:
445 case OP_63_FCTIW:
446 case OP_63_FCTIWZ:
447 case OP_63_FRSQRTE:
448 case OP_63_FCPSGN:
449 return true;
450 }
451 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
452 case OP_63_FMUL:
453 case OP_63_FSEL:
454 case OP_63_FMSUB:
455 case OP_63_FMADD:
456 case OP_63_FNMSUB:
457 case OP_63_FNMADD:
458 return true;
459 }
460 break;
461 case 31:
462 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
463 case OP_31_LFSX:
464 case OP_31_LFSUX:
465 case OP_31_LFDX:
466 case OP_31_LFDUX:
467 case OP_31_STFSX:
468 case OP_31_STFSUX:
469 case OP_31_STFX:
470 case OP_31_STFUX:
471 case OP_31_STFIWX:
472 return true;
473 }
474 break;
475 }
476
477 return false;
478}
479
480static int get_d_signext(u32 inst)
481{
482 int d = inst & 0x8ff;
483
484 if (d & 0x800)
485 return -(d & 0x7ff);
486
487 return (d & 0x7ff);
488}
489
490static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
491 int reg_out, int reg_in1, int reg_in2,
492 int reg_in3, int scalar,
493 void (*func)(u64 *fpscr,
494 u32 *dst, u32 *src1,
495 u32 *src2, u32 *src3))
496{
497 u32 *qpr = vcpu->arch.qpr;
498 u32 ps0_out;
499 u32 ps0_in1, ps0_in2, ps0_in3;
500 u32 ps1_in1, ps1_in2, ps1_in3;
501
502 /* RC */
503 WARN_ON(rc);
504
505 /* PS0 */
506 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1);
507 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2);
508 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in3), &ps0_in3);
509
510 if (scalar & SCALAR_LOW)
511 ps0_in2 = qpr[reg_in2];
512
513 func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
514
515 dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
516 ps0_in1, ps0_in2, ps0_in3, ps0_out);
517
518 if (!(scalar & SCALAR_NO_PS0))
519 kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
520
521 /* PS1 */
522 ps1_in1 = qpr[reg_in1];
523 ps1_in2 = qpr[reg_in2];
524 ps1_in3 = qpr[reg_in3];
525
526 if (scalar & SCALAR_HIGH)
527 ps1_in2 = ps0_in2;
528
529 if (!(scalar & SCALAR_NO_PS1))
530 func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
531
532 dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
533 ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]);
534
535 return EMULATE_DONE;
536}
537
538static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
539 int reg_out, int reg_in1, int reg_in2,
540 int scalar,
541 void (*func)(u64 *fpscr,
542 u32 *dst, u32 *src1,
543 u32 *src2))
544{
545 u32 *qpr = vcpu->arch.qpr;
546 u32 ps0_out;
547 u32 ps0_in1, ps0_in2;
548 u32 ps1_out;
549 u32 ps1_in1, ps1_in2;
550
551 /* RC */
552 WARN_ON(rc);
553
554 /* PS0 */
555 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1);
556
557 if (scalar & SCALAR_LOW)
558 ps0_in2 = qpr[reg_in2];
559 else
560 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2);
561
562 func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
563
564 if (!(scalar & SCALAR_NO_PS0)) {
565 dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
566 ps0_in1, ps0_in2, ps0_out);
567
568 kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
569 }
570
571 /* PS1 */
572 ps1_in1 = qpr[reg_in1];
573 ps1_in2 = qpr[reg_in2];
574
575 if (scalar & SCALAR_HIGH)
576 ps1_in2 = ps0_in2;
577
578 func(&vcpu->arch.fp.fpscr, &ps1_out, &ps1_in1, &ps1_in2);
579
580 if (!(scalar & SCALAR_NO_PS1)) {
581 qpr[reg_out] = ps1_out;
582
583 dprintk(KERN_INFO "PS2 ps1 -> f(0x%x, 0x%x) = 0x%x\n",
584 ps1_in1, ps1_in2, qpr[reg_out]);
585 }
586
587 return EMULATE_DONE;
588}
589
590static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
591 int reg_out, int reg_in,
592 void (*func)(u64 *t,
593 u32 *dst, u32 *src1))
594{
595 u32 *qpr = vcpu->arch.qpr;
596 u32 ps0_out, ps0_in;
597 u32 ps1_in;
598
599 /* RC */
600 WARN_ON(rc);
601
602 /* PS0 */
603 kvm_cvt_df(&VCPU_FPR(vcpu, reg_in), &ps0_in);
604 func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in);
605
606 dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
607 ps0_in, ps0_out);
608
609 kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
610
611 /* PS1 */
612 ps1_in = qpr[reg_in];
613 func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in);
614
615 dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n",
616 ps1_in, qpr[reg_out]);
617
618 return EMULATE_DONE;
619}
620
621int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu)
622{
623 u32 inst;
624 ppc_inst_t pinst;
625 enum emulation_result emulated = EMULATE_DONE;
626 int ax_rd, ax_ra, ax_rb, ax_rc;
627 short full_d;
628 u64 *fpr_d, *fpr_a, *fpr_b, *fpr_c;
629
630 bool rcomp;
631 u32 cr;
632#ifdef DEBUG
633 int i;
634#endif
635
636 emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst);
637 inst = ppc_inst_val(pinst);
638 if (emulated != EMULATE_DONE)
639 return emulated;
640
641 ax_rd = inst_get_field(inst, msb: 6, lsb: 10);
642 ax_ra = inst_get_field(inst, msb: 11, lsb: 15);
643 ax_rb = inst_get_field(inst, msb: 16, lsb: 20);
644 ax_rc = inst_get_field(inst, msb: 21, lsb: 25);
645 full_d = inst_get_field(inst, msb: 16, lsb: 31);
646
647 fpr_d = &VCPU_FPR(vcpu, ax_rd);
648 fpr_a = &VCPU_FPR(vcpu, ax_ra);
649 fpr_b = &VCPU_FPR(vcpu, ax_rb);
650 fpr_c = &VCPU_FPR(vcpu, ax_rc);
651
652 rcomp = (inst & 1) ? true : false;
653 cr = kvmppc_get_cr(vcpu);
654
655 if (!kvmppc_inst_is_paired_single(vcpu, inst))
656 return EMULATE_FAIL;
657
658 if (!(kvmppc_get_msr(vcpu) & MSR_FP)) {
659 kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL);
660 return EMULATE_AGAIN;
661 }
662
663 kvmppc_giveup_ext(vcpu, MSR_FP);
664 preempt_disable();
665 enable_kernel_fp();
666 /* Do we need to clear FE0 / FE1 here? Don't think so. */
667
668#ifdef DEBUG
669 for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) {
670 u32 f;
671 kvm_cvt_df(&VCPU_FPR(vcpu, i), &f);
672 dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx QPR[%d] = 0x%x\n",
673 i, f, VCPU_FPR(vcpu, i), i, vcpu->arch.qpr[i]);
674 }
675#endif
676
677 switch (get_op(inst)) {
678 case OP_PSQ_L:
679 {
680 ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
681 bool w = inst_get_field(inst, msb: 16, lsb: 16) ? true : false;
682 int i = inst_get_field(inst, msb: 17, lsb: 19);
683
684 addr += get_d_signext(inst);
685 emulated = kvmppc_emulate_psq_load(vcpu, rs: ax_rd, addr, w, i);
686 break;
687 }
688 case OP_PSQ_LU:
689 {
690 ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
691 bool w = inst_get_field(inst, msb: 16, lsb: 16) ? true : false;
692 int i = inst_get_field(inst, msb: 17, lsb: 19);
693
694 addr += get_d_signext(inst);
695 emulated = kvmppc_emulate_psq_load(vcpu, rs: ax_rd, addr, w, i);
696
697 if (emulated == EMULATE_DONE)
698 kvmppc_set_gpr(vcpu, ax_ra, addr);
699 break;
700 }
701 case OP_PSQ_ST:
702 {
703 ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
704 bool w = inst_get_field(inst, msb: 16, lsb: 16) ? true : false;
705 int i = inst_get_field(inst, msb: 17, lsb: 19);
706
707 addr += get_d_signext(inst);
708 emulated = kvmppc_emulate_psq_store(vcpu, rs: ax_rd, addr, w, i);
709 break;
710 }
711 case OP_PSQ_STU:
712 {
713 ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
714 bool w = inst_get_field(inst, msb: 16, lsb: 16) ? true : false;
715 int i = inst_get_field(inst, msb: 17, lsb: 19);
716
717 addr += get_d_signext(inst);
718 emulated = kvmppc_emulate_psq_store(vcpu, rs: ax_rd, addr, w, i);
719
720 if (emulated == EMULATE_DONE)
721 kvmppc_set_gpr(vcpu, ax_ra, addr);
722 break;
723 }
724 case 4:
725 /* X form */
726 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
727 case OP_4X_PS_CMPU0:
728 /* XXX */
729 emulated = EMULATE_FAIL;
730 break;
731 case OP_4X_PSQ_LX:
732 {
733 ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
734 bool w = inst_get_field(inst, msb: 21, lsb: 21) ? true : false;
735 int i = inst_get_field(inst, msb: 22, lsb: 24);
736
737 addr += kvmppc_get_gpr(vcpu, ax_rb);
738 emulated = kvmppc_emulate_psq_load(vcpu, rs: ax_rd, addr, w, i);
739 break;
740 }
741 case OP_4X_PS_CMPO0:
742 /* XXX */
743 emulated = EMULATE_FAIL;
744 break;
745 case OP_4X_PSQ_LUX:
746 {
747 ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
748 bool w = inst_get_field(inst, msb: 21, lsb: 21) ? true : false;
749 int i = inst_get_field(inst, msb: 22, lsb: 24);
750
751 addr += kvmppc_get_gpr(vcpu, ax_rb);
752 emulated = kvmppc_emulate_psq_load(vcpu, rs: ax_rd, addr, w, i);
753
754 if (emulated == EMULATE_DONE)
755 kvmppc_set_gpr(vcpu, ax_ra, addr);
756 break;
757 }
758 case OP_4X_PS_NEG:
759 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
760 VCPU_FPR(vcpu, ax_rd) ^= 0x8000000000000000ULL;
761 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
762 vcpu->arch.qpr[ax_rd] ^= 0x80000000;
763 break;
764 case OP_4X_PS_CMPU1:
765 /* XXX */
766 emulated = EMULATE_FAIL;
767 break;
768 case OP_4X_PS_MR:
769 WARN_ON(rcomp);
770 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
771 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
772 break;
773 case OP_4X_PS_CMPO1:
774 /* XXX */
775 emulated = EMULATE_FAIL;
776 break;
777 case OP_4X_PS_NABS:
778 WARN_ON(rcomp);
779 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
780 VCPU_FPR(vcpu, ax_rd) |= 0x8000000000000000ULL;
781 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
782 vcpu->arch.qpr[ax_rd] |= 0x80000000;
783 break;
784 case OP_4X_PS_ABS:
785 WARN_ON(rcomp);
786 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
787 VCPU_FPR(vcpu, ax_rd) &= ~0x8000000000000000ULL;
788 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
789 vcpu->arch.qpr[ax_rd] &= ~0x80000000;
790 break;
791 case OP_4X_PS_MERGE00:
792 WARN_ON(rcomp);
793 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra);
794 /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */
795 kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb),
796 &vcpu->arch.qpr[ax_rd]);
797 break;
798 case OP_4X_PS_MERGE01:
799 WARN_ON(rcomp);
800 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra);
801 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
802 break;
803 case OP_4X_PS_MERGE10:
804 WARN_ON(rcomp);
805 /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */
806 kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
807 &VCPU_FPR(vcpu, ax_rd));
808 /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */
809 kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb),
810 &vcpu->arch.qpr[ax_rd]);
811 break;
812 case OP_4X_PS_MERGE11:
813 WARN_ON(rcomp);
814 /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */
815 kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
816 &VCPU_FPR(vcpu, ax_rd));
817 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
818 break;
819 }
820 /* XW form */
821 switch (inst_get_field(inst, msb: 25, lsb: 30)) {
822 case OP_4XW_PSQ_STX:
823 {
824 ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
825 bool w = inst_get_field(inst, msb: 21, lsb: 21) ? true : false;
826 int i = inst_get_field(inst, msb: 22, lsb: 24);
827
828 addr += kvmppc_get_gpr(vcpu, ax_rb);
829 emulated = kvmppc_emulate_psq_store(vcpu, rs: ax_rd, addr, w, i);
830 break;
831 }
832 case OP_4XW_PSQ_STUX:
833 {
834 ulong addr = kvmppc_get_gpr(vcpu, ax_ra);
835 bool w = inst_get_field(inst, msb: 21, lsb: 21) ? true : false;
836 int i = inst_get_field(inst, msb: 22, lsb: 24);
837
838 addr += kvmppc_get_gpr(vcpu, ax_rb);
839 emulated = kvmppc_emulate_psq_store(vcpu, rs: ax_rd, addr, w, i);
840
841 if (emulated == EMULATE_DONE)
842 kvmppc_set_gpr(vcpu, ax_ra, addr);
843 break;
844 }
845 }
846 /* A form */
847 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
848 case OP_4A_PS_SUM1:
849 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
850 ax_rb, ax_ra, SCALAR_NO_PS0 | SCALAR_HIGH, fps_fadds);
851 VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rc);
852 break;
853 case OP_4A_PS_SUM0:
854 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
855 ax_ra, ax_rb, SCALAR_NO_PS1 | SCALAR_LOW, fps_fadds);
856 vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rc];
857 break;
858 case OP_4A_PS_MULS0:
859 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
860 ax_ra, ax_rc, SCALAR_HIGH, fps_fmuls);
861 break;
862 case OP_4A_PS_MULS1:
863 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
864 ax_ra, ax_rc, SCALAR_LOW, fps_fmuls);
865 break;
866 case OP_4A_PS_MADDS0:
867 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
868 ax_ra, ax_rc, ax_rb, SCALAR_HIGH, fps_fmadds);
869 break;
870 case OP_4A_PS_MADDS1:
871 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
872 ax_ra, ax_rc, ax_rb, SCALAR_LOW, fps_fmadds);
873 break;
874 case OP_4A_PS_DIV:
875 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
876 ax_ra, ax_rb, SCALAR_NONE, fps_fdivs);
877 break;
878 case OP_4A_PS_SUB:
879 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
880 ax_ra, ax_rb, SCALAR_NONE, fps_fsubs);
881 break;
882 case OP_4A_PS_ADD:
883 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
884 ax_ra, ax_rb, SCALAR_NONE, fps_fadds);
885 break;
886 case OP_4A_PS_SEL:
887 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
888 ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fsel);
889 break;
890 case OP_4A_PS_RES:
891 emulated = kvmppc_ps_one_in(vcpu, rcomp, ax_rd,
892 ax_rb, fps_fres);
893 break;
894 case OP_4A_PS_MUL:
895 emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
896 ax_ra, ax_rc, SCALAR_NONE, fps_fmuls);
897 break;
898 case OP_4A_PS_RSQRTE:
899 emulated = kvmppc_ps_one_in(vcpu, rcomp, ax_rd,
900 ax_rb, fps_frsqrte);
901 break;
902 case OP_4A_PS_MSUB:
903 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
904 ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fmsubs);
905 break;
906 case OP_4A_PS_MADD:
907 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
908 ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fmadds);
909 break;
910 case OP_4A_PS_NMSUB:
911 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
912 ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fnmsubs);
913 break;
914 case OP_4A_PS_NMADD:
915 emulated = kvmppc_ps_three_in(vcpu, rcomp, ax_rd,
916 ax_ra, ax_rc, ax_rb, SCALAR_NONE, fps_fnmadds);
917 break;
918 }
919 break;
920
921 /* Real FPU operations */
922
923 case OP_LFS:
924 {
925 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
926
927 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd, addr,
928 FPU_LS_SINGLE);
929 break;
930 }
931 case OP_LFSU:
932 {
933 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
934
935 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd, addr,
936 FPU_LS_SINGLE);
937
938 if (emulated == EMULATE_DONE)
939 kvmppc_set_gpr(vcpu, ax_ra, addr);
940 break;
941 }
942 case OP_LFD:
943 {
944 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
945
946 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd, addr,
947 FPU_LS_DOUBLE);
948 break;
949 }
950 case OP_LFDU:
951 {
952 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
953
954 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd, addr,
955 FPU_LS_DOUBLE);
956
957 if (emulated == EMULATE_DONE)
958 kvmppc_set_gpr(vcpu, ax_ra, addr);
959 break;
960 }
961 case OP_STFS:
962 {
963 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
964
965 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd, addr,
966 FPU_LS_SINGLE);
967 break;
968 }
969 case OP_STFSU:
970 {
971 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
972
973 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd, addr,
974 FPU_LS_SINGLE);
975
976 if (emulated == EMULATE_DONE)
977 kvmppc_set_gpr(vcpu, ax_ra, addr);
978 break;
979 }
980 case OP_STFD:
981 {
982 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) + full_d;
983
984 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd, addr,
985 FPU_LS_DOUBLE);
986 break;
987 }
988 case OP_STFDU:
989 {
990 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) + full_d;
991
992 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd, addr,
993 FPU_LS_DOUBLE);
994
995 if (emulated == EMULATE_DONE)
996 kvmppc_set_gpr(vcpu, ax_ra, addr);
997 break;
998 }
999 case 31:
1000 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
1001 case OP_31_LFSX:
1002 {
1003 ulong addr = ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0;
1004
1005 addr += kvmppc_get_gpr(vcpu, ax_rb);
1006 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd,
1007 addr, FPU_LS_SINGLE);
1008 break;
1009 }
1010 case OP_31_LFSUX:
1011 {
1012 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
1013 kvmppc_get_gpr(vcpu, ax_rb);
1014
1015 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd,
1016 addr, FPU_LS_SINGLE);
1017
1018 if (emulated == EMULATE_DONE)
1019 kvmppc_set_gpr(vcpu, ax_ra, addr);
1020 break;
1021 }
1022 case OP_31_LFDX:
1023 {
1024 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
1025 kvmppc_get_gpr(vcpu, ax_rb);
1026
1027 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd,
1028 addr, FPU_LS_DOUBLE);
1029 break;
1030 }
1031 case OP_31_LFDUX:
1032 {
1033 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
1034 kvmppc_get_gpr(vcpu, ax_rb);
1035
1036 emulated = kvmppc_emulate_fpr_load(vcpu, rs: ax_rd,
1037 addr, FPU_LS_DOUBLE);
1038
1039 if (emulated == EMULATE_DONE)
1040 kvmppc_set_gpr(vcpu, ax_ra, addr);
1041 break;
1042 }
1043 case OP_31_STFSX:
1044 {
1045 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
1046 kvmppc_get_gpr(vcpu, ax_rb);
1047
1048 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd,
1049 addr, FPU_LS_SINGLE);
1050 break;
1051 }
1052 case OP_31_STFSUX:
1053 {
1054 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
1055 kvmppc_get_gpr(vcpu, ax_rb);
1056
1057 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd,
1058 addr, FPU_LS_SINGLE);
1059
1060 if (emulated == EMULATE_DONE)
1061 kvmppc_set_gpr(vcpu, ax_ra, addr);
1062 break;
1063 }
1064 case OP_31_STFX:
1065 {
1066 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
1067 kvmppc_get_gpr(vcpu, ax_rb);
1068
1069 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd,
1070 addr, FPU_LS_DOUBLE);
1071 break;
1072 }
1073 case OP_31_STFUX:
1074 {
1075 ulong addr = kvmppc_get_gpr(vcpu, ax_ra) +
1076 kvmppc_get_gpr(vcpu, ax_rb);
1077
1078 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd,
1079 addr, FPU_LS_DOUBLE);
1080
1081 if (emulated == EMULATE_DONE)
1082 kvmppc_set_gpr(vcpu, ax_ra, addr);
1083 break;
1084 }
1085 case OP_31_STFIWX:
1086 {
1087 ulong addr = (ax_ra ? kvmppc_get_gpr(vcpu, ax_ra) : 0) +
1088 kvmppc_get_gpr(vcpu, ax_rb);
1089
1090 emulated = kvmppc_emulate_fpr_store(vcpu, rs: ax_rd,
1091 addr,
1092 FPU_LS_SINGLE_LOW);
1093 break;
1094 }
1095 break;
1096 }
1097 break;
1098 case 59:
1099 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
1100 case OP_59_FADDS:
1101 fpd_fadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1102 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1103 break;
1104 case OP_59_FSUBS:
1105 fpd_fsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1106 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1107 break;
1108 case OP_59_FDIVS:
1109 fpd_fdivs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1110 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1111 break;
1112 case OP_59_FRES:
1113 fpd_fres(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1114 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1115 break;
1116 case OP_59_FRSQRTES:
1117 fpd_frsqrtes(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1118 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1119 break;
1120 }
1121 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
1122 case OP_59_FMULS:
1123 fpd_fmuls(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c);
1124 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1125 break;
1126 case OP_59_FMSUBS:
1127 fpd_fmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1128 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1129 break;
1130 case OP_59_FMADDS:
1131 fpd_fmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1132 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1133 break;
1134 case OP_59_FNMSUBS:
1135 fpd_fnmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1136 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1137 break;
1138 case OP_59_FNMADDS:
1139 fpd_fnmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1140 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1141 break;
1142 }
1143 break;
1144 case 63:
1145 switch (inst_get_field(inst, msb: 21, lsb: 30)) {
1146 case OP_63_MTFSB0:
1147 case OP_63_MTFSB1:
1148 case OP_63_MCRFS:
1149 case OP_63_MTFSFI:
1150 /* XXX need to implement */
1151 break;
1152 case OP_63_MFFS:
1153 /* XXX missing CR */
1154 *fpr_d = vcpu->arch.fp.fpscr;
1155 break;
1156 case OP_63_MTFSF:
1157 /* XXX missing fm bits */
1158 /* XXX missing CR */
1159 vcpu->arch.fp.fpscr = *fpr_b;
1160 break;
1161 case OP_63_FCMPU:
1162 {
1163 u32 tmp_cr;
1164 u32 cr0_mask = 0xf0000000;
1165 u32 cr_shift = inst_get_field(inst, msb: 6, lsb: 8) * 4;
1166
1167 fpd_fcmpu(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b);
1168 cr &= ~(cr0_mask >> cr_shift);
1169 cr |= (cr & cr0_mask) >> cr_shift;
1170 break;
1171 }
1172 case OP_63_FCMPO:
1173 {
1174 u32 tmp_cr;
1175 u32 cr0_mask = 0xf0000000;
1176 u32 cr_shift = inst_get_field(inst, msb: 6, lsb: 8) * 4;
1177
1178 fpd_fcmpo(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b);
1179 cr &= ~(cr0_mask >> cr_shift);
1180 cr |= (cr & cr0_mask) >> cr_shift;
1181 break;
1182 }
1183 case OP_63_FNEG:
1184 fpd_fneg(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1185 break;
1186 case OP_63_FMR:
1187 *fpr_d = *fpr_b;
1188 break;
1189 case OP_63_FABS:
1190 fpd_fabs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1191 break;
1192 case OP_63_FCPSGN:
1193 fpd_fcpsgn(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1194 break;
1195 case OP_63_FDIV:
1196 fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1197 break;
1198 case OP_63_FADD:
1199 fpd_fadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1200 break;
1201 case OP_63_FSUB:
1202 fpd_fsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
1203 break;
1204 case OP_63_FCTIW:
1205 fpd_fctiw(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1206 break;
1207 case OP_63_FCTIWZ:
1208 fpd_fctiwz(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1209 break;
1210 case OP_63_FRSP:
1211 fpd_frsp(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1212 kvmppc_sync_qpr(vcpu, rt: ax_rd);
1213 break;
1214 case OP_63_FRSQRTE:
1215 {
1216 double one = 1.0f;
1217
1218 /* fD = sqrt(fB) */
1219 fpd_fsqrt(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
1220 /* fD = 1.0f / fD */
1221 fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, (u64*)&one, fpr_d);
1222 break;
1223 }
1224 }
1225 switch (inst_get_field(inst, msb: 26, lsb: 30)) {
1226 case OP_63_FMUL:
1227 fpd_fmul(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c);
1228 break;
1229 case OP_63_FSEL:
1230 fpd_fsel(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1231 break;
1232 case OP_63_FMSUB:
1233 fpd_fmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1234 break;
1235 case OP_63_FMADD:
1236 fpd_fmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1237 break;
1238 case OP_63_FNMSUB:
1239 fpd_fnmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1240 break;
1241 case OP_63_FNMADD:
1242 fpd_fnmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
1243 break;
1244 }
1245 break;
1246 }
1247
1248#ifdef DEBUG
1249 for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) {
1250 u32 f;
1251 kvm_cvt_df(&VCPU_FPR(vcpu, i), &f);
1252 dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
1253 }
1254#endif
1255
1256 if (rcomp)
1257 kvmppc_set_cr(vcpu, cr);
1258
1259 disable_kernel_fp();
1260 preempt_enable();
1261
1262 return emulated;
1263}
1264

source code of linux/arch/powerpc/kvm/book3s_paired_singles.c