aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2010-03-24 16:48:28 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:17:07 -0400
commitca7f4203b9b66e12d0d9968ff7dfe781f3a9695a (patch)
treeddec3225d7f7a2ab2d0cdaf4ff55725e547206d1 /arch/powerpc
parent1c85e73303fa70cd6bc2bf138484acb4ffe30efd (diff)
KVM: PPC: Implement alignment interrupt
Mac OS X has some applications - namely the Finder - that require alignment interrupts to work properly. So we need to implement them. But the spec for 970 and 750 also looks different. While 750 requires the DSISR and DAR fields to reflect some instruction bits (DSISR) and the fault address (DAR), the 970 declares this as an optional feature. So we need to reconstruct DSISR and DAR manually. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h2
-rw-r--r--arch/powerpc/kvm/book3s.c10
-rw-r--r--arch/powerpc/kvm/book3s_64_emulate.c75
3 files changed, 87 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index b47b2f516eff..bea76371dbe1 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -131,6 +131,8 @@ extern void kvmppc_rmcall(ulong srr0, ulong srr1);
131extern void kvmppc_load_up_fpu(void); 131extern void kvmppc_load_up_fpu(void);
132extern void kvmppc_load_up_altivec(void); 132extern void kvmppc_load_up_altivec(void);
133extern void kvmppc_load_up_vsx(void); 133extern void kvmppc_load_up_vsx(void);
134extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst);
135extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst);
134 136
135static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) 137static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
136{ 138{
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index c058f1a5c095..de12202fe1c6 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -906,6 +906,16 @@ program_interrupt:
906 } 906 }
907 break; 907 break;
908 } 908 }
909 case BOOK3S_INTERRUPT_ALIGNMENT:
910 if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
911 to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu,
912 vcpu->arch.last_inst);
913 vcpu->arch.dear = kvmppc_alignment_dar(vcpu,
914 vcpu->arch.last_inst);
915 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
916 }
917 r = RESUME_GUEST;
918 break;
909 case BOOK3S_INTERRUPT_MACHINE_CHECK: 919 case BOOK3S_INTERRUPT_MACHINE_CHECK:
910 case BOOK3S_INTERRUPT_TRACE: 920 case BOOK3S_INTERRUPT_TRACE:
911 kvmppc_book3s_queue_irqprio(vcpu, exit_nr); 921 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
diff --git a/arch/powerpc/kvm/book3s_64_emulate.c b/arch/powerpc/kvm/book3s_64_emulate.c
index 39d5003e01f0..1e5cf8d594ea 100644
--- a/arch/powerpc/kvm/book3s_64_emulate.c
+++ b/arch/powerpc/kvm/book3s_64_emulate.c
@@ -44,6 +44,11 @@
44/* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */ 44/* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */
45#define OP_31_XOP_DCBZ 1010 45#define OP_31_XOP_DCBZ 1010
46 46
47#define OP_LFS 48
48#define OP_LFD 50
49#define OP_STFS 52
50#define OP_STFD 54
51
47#define SPRN_GQR0 912 52#define SPRN_GQR0 912
48#define SPRN_GQR1 913 53#define SPRN_GQR1 913
49#define SPRN_GQR2 914 54#define SPRN_GQR2 914
@@ -474,3 +479,73 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
474 return emulated; 479 return emulated;
475} 480}
476 481
482u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst)
483{
484 u32 dsisr = 0;
485
486 /*
487 * This is what the spec says about DSISR bits (not mentioned = 0):
488 *
489 * 12:13 [DS] Set to bits 30:31
490 * 15:16 [X] Set to bits 29:30
491 * 17 [X] Set to bit 25
492 * [D/DS] Set to bit 5
493 * 18:21 [X] Set to bits 21:24
494 * [D/DS] Set to bits 1:4
495 * 22:26 Set to bits 6:10 (RT/RS/FRT/FRS)
496 * 27:31 Set to bits 11:15 (RA)
497 */
498
499 switch (get_op(inst)) {
500 /* D-form */
501 case OP_LFS:
502 case OP_LFD:
503 case OP_STFD:
504 case OP_STFS:
505 dsisr |= (inst >> 12) & 0x4000; /* bit 17 */
506 dsisr |= (inst >> 17) & 0x3c00; /* bits 18:21 */
507 break;
508 /* X-form */
509 case 31:
510 dsisr |= (inst << 14) & 0x18000; /* bits 15:16 */
511 dsisr |= (inst << 8) & 0x04000; /* bit 17 */
512 dsisr |= (inst << 3) & 0x03c00; /* bits 18:21 */
513 break;
514 default:
515 printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
516 break;
517 }
518
519 dsisr |= (inst >> 16) & 0x03ff; /* bits 22:31 */
520
521 return dsisr;
522}
523
524ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst)
525{
526 ulong dar = 0;
527 ulong ra;
528
529 switch (get_op(inst)) {
530 case OP_LFS:
531 case OP_LFD:
532 case OP_STFD:
533 case OP_STFS:
534 ra = get_ra(inst);
535 if (ra)
536 dar = kvmppc_get_gpr(vcpu, ra);
537 dar += (s32)((s16)inst);
538 break;
539 case 31:
540 ra = get_ra(inst);
541 if (ra)
542 dar = kvmppc_get_gpr(vcpu, ra);
543 dar += kvmppc_get_gpr(vcpu, get_rb(inst));
544 break;
545 default:
546 printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst);
547 break;
548 }
549
550 return dar;
551}