]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - arch/powerpc/kvm/44x_emulate.c
Merge tag 'kvm-3.8-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[can-eth-gw-linux.git] / arch / powerpc / kvm / 44x_emulate.c
index c8c61578fdfc6e8420497854971d8da7b6d74598..35ec0a8547dabb86977f0e24657f8ba710cd4f69 100644 (file)
 #include "booke.h"
 #include "44x_tlb.h"
 
+#define XOP_MFDCRX  259
 #define XOP_MFDCR   323
+#define XOP_MTDCRX  387
 #define XOP_MTDCR   451
 #define XOP_TLBSX   914
 #define XOP_ICCCI   966
 #define XOP_TLBWE   978
 
+static int emulate_mtdcr(struct kvm_vcpu *vcpu, int rs, int dcrn)
+{
+       /* emulate some access in kernel */
+       switch (dcrn) {
+       case DCRN_CPR0_CONFIG_ADDR:
+               vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
+               return EMULATE_DONE;
+       default:
+               vcpu->run->dcr.dcrn = dcrn;
+               vcpu->run->dcr.data = kvmppc_get_gpr(vcpu, rs);
+               vcpu->run->dcr.is_write = 1;
+               vcpu->arch.dcr_is_write = 1;
+               vcpu->arch.dcr_needed = 1;
+               kvmppc_account_exit(vcpu, DCR_EXITS);
+               return EMULATE_DO_DCR;
+       }
+}
+
+static int emulate_mfdcr(struct kvm_vcpu *vcpu, int rt, int dcrn)
+{
+       /* The guest may access CPR0 registers to determine the timebase
+        * frequency, and it must know the real host frequency because it
+        * can directly access the timebase registers.
+        *
+        * It would be possible to emulate those accesses in userspace,
+        * but userspace can really only figure out the end frequency.
+        * We could decompose that into the factors that compute it, but
+        * that's tricky math, and it's easier to just report the real
+        * CPR0 values.
+        */
+       switch (dcrn) {
+       case DCRN_CPR0_CONFIG_ADDR:
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
+               break;
+       case DCRN_CPR0_CONFIG_DATA:
+               local_irq_disable();
+               mtdcr(DCRN_CPR0_CONFIG_ADDR,
+                         vcpu->arch.cpr0_cfgaddr);
+               kvmppc_set_gpr(vcpu, rt,
+                              mfdcr(DCRN_CPR0_CONFIG_DATA));
+               local_irq_enable();
+               break;
+       default:
+               vcpu->run->dcr.dcrn = dcrn;
+               vcpu->run->dcr.data =  0;
+               vcpu->run->dcr.is_write = 0;
+               vcpu->arch.dcr_is_write = 0;
+               vcpu->arch.io_gpr = rt;
+               vcpu->arch.dcr_needed = 1;
+               kvmppc_account_exit(vcpu, DCR_EXITS);
+               return EMULATE_DO_DCR;
+       }
+
+       return EMULATE_DONE;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -50,55 +108,21 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                switch (get_xop(inst)) {
 
                case XOP_MFDCR:
-                       /* The guest may access CPR0 registers to determine the timebase
-                        * frequency, and it must know the real host frequency because it
-                        * can directly access the timebase registers.
-                        *
-                        * It would be possible to emulate those accesses in userspace,
-                        * but userspace can really only figure out the end frequency.
-                        * We could decompose that into the factors that compute it, but
-                        * that's tricky math, and it's easier to just report the real
-                        * CPR0 values.
-                        */
-                       switch (dcrn) {
-                       case DCRN_CPR0_CONFIG_ADDR:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
-                               break;
-                       case DCRN_CPR0_CONFIG_DATA:
-                               local_irq_disable();
-                               mtdcr(DCRN_CPR0_CONFIG_ADDR,
-                                         vcpu->arch.cpr0_cfgaddr);
-                               kvmppc_set_gpr(vcpu, rt,
-                                              mfdcr(DCRN_CPR0_CONFIG_DATA));
-                               local_irq_enable();
-                               break;
-                       default:
-                               run->dcr.dcrn = dcrn;
-                               run->dcr.data =  0;
-                               run->dcr.is_write = 0;
-                               vcpu->arch.io_gpr = rt;
-                               vcpu->arch.dcr_needed = 1;
-                               kvmppc_account_exit(vcpu, DCR_EXITS);
-                               emulated = EMULATE_DO_DCR;
-                       }
+                       emulated = emulate_mfdcr(vcpu, rt, dcrn);
+                       break;
 
+               case XOP_MFDCRX:
+                       emulated = emulate_mfdcr(vcpu, rt,
+                                       kvmppc_get_gpr(vcpu, ra));
                        break;
 
                case XOP_MTDCR:
-                       /* emulate some access in kernel */
-                       switch (dcrn) {
-                       case DCRN_CPR0_CONFIG_ADDR:
-                               vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
-                               break;
-                       default:
-                               run->dcr.dcrn = dcrn;
-                               run->dcr.data = kvmppc_get_gpr(vcpu, rs);
-                               run->dcr.is_write = 1;
-                               vcpu->arch.dcr_needed = 1;
-                               kvmppc_account_exit(vcpu, DCR_EXITS);
-                               emulated = EMULATE_DO_DCR;
-                       }
+                       emulated = emulate_mtdcr(vcpu, rs, dcrn);
+                       break;
 
+               case XOP_MTDCRX:
+                       emulated = emulate_mtdcr(vcpu, rs,
+                                       kvmppc_get_gpr(vcpu, ra));
                        break;
 
                case XOP_TLBWE: