diff options
-rw-r--r-- | arch/powerpc/include/asm/kvm_book3s.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_64_emulate.c | 75 |
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); | |||
131 | extern void kvmppc_load_up_fpu(void); | 131 | extern void kvmppc_load_up_fpu(void); |
132 | extern void kvmppc_load_up_altivec(void); | 132 | extern void kvmppc_load_up_altivec(void); |
133 | extern void kvmppc_load_up_vsx(void); | 133 | extern void kvmppc_load_up_vsx(void); |
134 | extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst); | ||
135 | extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst); | ||
134 | 136 | ||
135 | static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) | 137 | static 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 | ||
482 | u32 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 | |||
524 | ulong 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 | } | ||