This patch adds emulation support for conditional branches.

Signed-off-by: Alexander Graf <ag...@suse.de>
---
 arch/powerpc/include/asm/ppc-opcode.h |  1 +
 arch/powerpc/kvm/emulate.c            | 51 +++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/arch/powerpc/include/asm/ppc-opcode.h 
b/arch/powerpc/include/asm/ppc-opcode.h
index 5160af9..e130156 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -116,6 +116,7 @@
 
 #define OP_CMPI 11
 #define OP_ADDIS 15
+#define OP_BC   16
 #define OP_ORI  24
 #define OP_ANDI 28
 #define OP_LWZ  32
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 7b8acb0..aeadc30 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -473,6 +473,54 @@ static int kvmppc_emulate_cmp(struct kvm_vcpu *vcpu, u64 
value0, u64 value1,
        return EMULATE_DONE;
 }
 
+int kvmppc_emulate_bc(struct kvm_vcpu *vcpu, u32 inst, bool is_32bit)
+{
+       u64 addr = (s64)(s16)get_d(inst);
+       int bo = get_rt(inst);
+       int bi = get_ra(inst);
+
+       /* If not absolute, PC gets added */
+       if (!(inst & 0x2))
+               addr += kvmppc_get_pc(vcpu);
+       if (is_32bit)
+               addr = (u32)addr;
+
+       /* LR gets set with LK=1 */
+       if (inst & 0x1)
+               kvmppc_set_lr(vcpu, kvmppc_get_pc(vcpu) + 4);
+
+       /* CTR handling */
+       if (!(bo & 0x4)) {
+               ulong ctr = kvmppc_get_ctr(vcpu);
+               ctr--;
+               if (is_32bit)
+                       ctr = (u32)ctr;
+               kvmppc_set_ctr(vcpu, ctr);
+               if (((bo & 0x2) && (ctr != 0)) ||
+                  (!(bo & 0x2) && (ctr == 0))) {
+                       /* Condition not fulfilled, go to next inst */
+                       return EMULATE_DONE;
+               }
+       }
+
+       /* CR handling */
+       if (!(bo & 0x10)) {
+               uint32_t mask = 1 << (3 - (bi & 0x3));
+               u32 cr_part = kvmppc_get_cr(vcpu) >> (28 - (bi & ~0x3));
+               if (((bo & 0x8) && (cr_part != mask)) ||
+                  (!(bo & 0x8) && (cr_part == mask))) {
+                       /* Condition not fulfilled, go to next inst */
+                       return EMULATE_DONE;
+               }
+       }
+
+       /* Off we branch ... */
+       kvmppc_set_pc(vcpu, addr);
+
+       /* Indicate that we don't want to advance the PC */
+       return EMULATE_AGAIN;
+}
+
 /* Emulates privileged and non-privileged instructions */
 int kvmppc_emulate_any_instruction(struct kvm_vcpu *vcpu)
 {
@@ -536,6 +584,9 @@ int kvmppc_emulate_any_instruction(struct kvm_vcpu *vcpu)
                kvmppc_emulate_cmp(vcpu, value, (s16)get_d(inst), true,
                                   get_rt(inst) >> 2, !(get_rt(inst) & 1));
                break;
+       case OP_BC:
+               emulated = kvmppc_emulate_bc(vcpu, inst, is_32bit);
+               break;
        case 31:
                switch (get_xop(inst)) {
                case OP_31_XOP_MFCR:
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to