Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-3.10.git] / arch / powerpc / kvm / emulate.c
index b5872f6..ee04aba 100644 (file)
 #define OP_31_XOP_STHBRX    918
 
 #define OP_LWZ  32
+#define OP_LD   58
 #define OP_LWZU 33
 #define OP_LBZ  34
 #define OP_LBZU 35
 #define OP_STW  36
 #define OP_STWU 37
+#define OP_STD  62
 #define OP_STB  38
 #define OP_STBU 39
 #define OP_LHZ  40
@@ -148,13 +150,13 @@ u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
 int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
        u32 inst = kvmppc_get_last_inst(vcpu);
-       int ra;
-       int rb;
-       int rs;
-       int rt;
-       int sprn;
+       int ra = get_ra(inst);
+       int rs = get_rs(inst);
+       int rt = get_rt(inst);
+       int sprn = get_sprn(inst);
        enum emulation_result emulated = EMULATE_DONE;
        int advance = 1;
+       ulong spr_val = 0;
 
        /* this default type might be overwritten by subcategories */
        kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
@@ -189,141 +191,116 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        advance = 0;
                        break;
                case OP_31_XOP_LWZX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
                        break;
 
                case OP_31_XOP_LBZX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
                        break;
 
                case OP_31_XOP_LBZUX:
-                       rt = get_rt(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
                        kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                        break;
 
                case OP_31_XOP_STWX:
-                       rs = get_rs(inst);
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       4, 1);
                        break;
 
                case OP_31_XOP_STBX:
-                       rs = get_rs(inst);
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       1, 1);
                        break;
 
                case OP_31_XOP_STBUX:
-                       rs = get_rs(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       1, 1);
-                       kvmppc_set_gpr(vcpu, rs, vcpu->arch.vaddr_accessed);
+                       kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                        break;
 
                case OP_31_XOP_LHAX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
                        break;
 
                case OP_31_XOP_LHZX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
                        break;
 
                case OP_31_XOP_LHZUX:
-                       rt = get_rt(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
                        kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                        break;
 
                case OP_31_XOP_MFSPR:
-                       sprn = get_sprn(inst);
-                       rt = get_rt(inst);
-
                        switch (sprn) {
                        case SPRN_SRR0:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr0);
+                               spr_val = vcpu->arch.shared->srr0;
                                break;
                        case SPRN_SRR1:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr1);
+                               spr_val = vcpu->arch.shared->srr1;
                                break;
                        case SPRN_PVR:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.pvr); break;
+                               spr_val = vcpu->arch.pvr;
+                               break;
                        case SPRN_PIR:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->vcpu_id); break;
+                               spr_val = vcpu->vcpu_id;
+                               break;
                        case SPRN_MSSSR0:
-                               kvmppc_set_gpr(vcpu, rt, 0); break;
+                               spr_val = 0;
+                               break;
 
                        /* Note: mftb and TBRL/TBWL are user-accessible, so
                         * the guest can always access the real TB anyways.
                         * In fact, we probably will never see these traps. */
                        case SPRN_TBWL:
-                               kvmppc_set_gpr(vcpu, rt, get_tb() >> 32); break;
+                               spr_val = get_tb() >> 32;
+                               break;
                        case SPRN_TBWU:
-                               kvmppc_set_gpr(vcpu, rt, get_tb()); break;
+                               spr_val = get_tb();
+                               break;
 
                        case SPRN_SPRG0:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg0);
+                               spr_val = vcpu->arch.shared->sprg0;
                                break;
                        case SPRN_SPRG1:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg1);
+                               spr_val = vcpu->arch.shared->sprg1;
                                break;
                        case SPRN_SPRG2:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg2);
+                               spr_val = vcpu->arch.shared->sprg2;
                                break;
                        case SPRN_SPRG3:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg3);
+                               spr_val = vcpu->arch.shared->sprg3;
                                break;
                        /* Note: SPRG4-7 are user-readable, so we don't get
                         * a trap. */
 
                        case SPRN_DEC:
-                       {
-                               kvmppc_set_gpr(vcpu, rt,
-                                              kvmppc_get_dec(vcpu, get_tb()));
+                               spr_val = kvmppc_get_dec(vcpu, get_tb());
                                break;
-                       }
                        default:
-                               emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, rt);
-                               if (emulated == EMULATE_FAIL) {
-                                       printk("mfspr: unknown spr %x\n", sprn);
-                                       kvmppc_set_gpr(vcpu, rt, 0);
+                               emulated = kvmppc_core_emulate_mfspr(vcpu, sprn,
+                                                                    &spr_val);
+                               if (unlikely(emulated == EMULATE_FAIL)) {
+                                       printk(KERN_INFO "mfspr: unknown spr "
+                                               "0x%x\n", sprn);
                                }
                                break;
                        }
+                       kvmppc_set_gpr(vcpu, rt, spr_val);
                        kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS);
                        break;
 
                case OP_31_XOP_STHX:
-                       rs = get_rs(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       2, 1);
                        break;
 
                case OP_31_XOP_STHUX:
-                       rs = get_rs(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       2, 1);
@@ -331,14 +308,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
 
                case OP_31_XOP_MTSPR:
-                       sprn = get_sprn(inst);
-                       rs = get_rs(inst);
+                       spr_val = kvmppc_get_gpr(vcpu, rs);
                        switch (sprn) {
                        case SPRN_SRR0:
-                               vcpu->arch.shared->srr0 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->srr0 = spr_val;
                                break;
                        case SPRN_SRR1:
-                               vcpu->arch.shared->srr1 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->srr1 = spr_val;
                                break;
 
                        /* XXX We need to context-switch the timebase for
@@ -349,27 +325,29 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        case SPRN_MSSSR0: break;
 
                        case SPRN_DEC:
-                               vcpu->arch.dec = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.dec = spr_val;
                                kvmppc_emulate_dec(vcpu);
                                break;
 
                        case SPRN_SPRG0:
-                               vcpu->arch.shared->sprg0 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->sprg0 = spr_val;
                                break;
                        case SPRN_SPRG1:
-                               vcpu->arch.shared->sprg1 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->sprg1 = spr_val;
                                break;
                        case SPRN_SPRG2:
-                               vcpu->arch.shared->sprg2 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->sprg2 = spr_val;
                                break;
                        case SPRN_SPRG3:
-                               vcpu->arch.shared->sprg3 = kvmppc_get_gpr(vcpu, rs);
+                               vcpu->arch.shared->sprg3 = spr_val;
                                break;
 
                        default:
-                               emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, rs);
+                               emulated = kvmppc_core_emulate_mtspr(vcpu, sprn,
+                                                                    spr_val);
                                if (emulated == EMULATE_FAIL)
-                                       printk("mtspr: unknown spr %x\n", sprn);
+                                       printk(KERN_INFO "mtspr: unknown spr "
+                                               "0x%x\n", sprn);
                                break;
                        }
                        kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS);
@@ -384,7 +362,6 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
 
                case OP_31_XOP_LWBRX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 4, 0);
                        break;
 
@@ -392,25 +369,16 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
 
                case OP_31_XOP_STWBRX:
-                       rs = get_rs(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       4, 0);
                        break;
 
                case OP_31_XOP_LHBRX:
-                       rt = get_rt(inst);
                        emulated = kvmppc_handle_load(run, vcpu, rt, 2, 0);
                        break;
 
                case OP_31_XOP_STHBRX:
-                       rs = get_rs(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-
                        emulated = kvmppc_handle_store(run, vcpu,
                                                       kvmppc_get_gpr(vcpu, rs),
                                                       2, 0);
@@ -423,55 +391,57 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                break;
 
        case OP_LWZ:
-               rt = get_rt(inst);
                emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
                break;
 
-       case OP_LWZU:
-               ra = get_ra(inst);
+       /* TBD: Add support for other 64 bit load variants like ldu, ldux, ldx etc. */
+       case OP_LD:
                rt = get_rt(inst);
+               emulated = kvmppc_handle_load(run, vcpu, rt, 8, 1);
+               break;
+
+       case OP_LWZU:
                emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1);
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                break;
 
        case OP_LBZ:
-               rt = get_rt(inst);
                emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
                break;
 
        case OP_LBZU:
-               ra = get_ra(inst);
-               rt = get_rt(inst);
                emulated = kvmppc_handle_load(run, vcpu, rt, 1, 1);
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                break;
 
        case OP_STW:
-               rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
                                               4, 1);
                break;
 
-       case OP_STWU:
-               ra = get_ra(inst);
+       /* TBD: Add support for other 64 bit store variants like stdu, stdux, stdx etc. */
+       case OP_STD:
                rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
+                                              8, 1);
+               break;
+
+       case OP_STWU:
+               emulated = kvmppc_handle_store(run, vcpu,
+                                              kvmppc_get_gpr(vcpu, rs),
                                               4, 1);
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                break;
 
        case OP_STB:
-               rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
                                               1, 1);
                break;
 
        case OP_STBU:
-               ra = get_ra(inst);
-               rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
                                               1, 1);
@@ -479,39 +449,30 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                break;
 
        case OP_LHZ:
-               rt = get_rt(inst);
                emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
                break;
 
        case OP_LHZU:
-               ra = get_ra(inst);
-               rt = get_rt(inst);
                emulated = kvmppc_handle_load(run, vcpu, rt, 2, 1);
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                break;
 
        case OP_LHA:
-               rt = get_rt(inst);
                emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
                break;
 
        case OP_LHAU:
-               ra = get_ra(inst);
-               rt = get_rt(inst);
                emulated = kvmppc_handle_loads(run, vcpu, rt, 2, 1);
                kvmppc_set_gpr(vcpu, ra, vcpu->arch.vaddr_accessed);
                break;
 
        case OP_STH:
-               rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
                                               2, 1);
                break;
 
        case OP_STHU:
-               ra = get_ra(inst);
-               rs = get_rs(inst);
                emulated = kvmppc_handle_store(run, vcpu,
                                               kvmppc_get_gpr(vcpu, rs),
                                               2, 1);