From 5d81a2fd48cdd3138698beb1da56fa7064f6c5c5 Mon Sep 17 00:00:00 2001
From: aroulin <andy.roulin@epfl.ch>
Date: Wed, 5 Aug 2015 12:12:24 +0200
Subject: [PATCH 1/2] Disassembler: ARMv6K hint instructions

---
 src/core/arm/disassembler/arm_disasm.cpp | 49 ++++++++++++++++++++++++
 src/core/arm/disassembler/arm_disasm.h   |  7 ++++
 2 files changed, 56 insertions(+)

diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index f6d44d85a..bb87043a4 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -4,6 +4,7 @@
 
 #include "common/string_util.h"
 #include "core/arm/disassembler/arm_disasm.h"
+#include "core/arm/skyeye_common/armsupp.h"
 
 static const char *cond_names[] = {
     "eq",
@@ -58,11 +59,13 @@ static const char *opcode_names[] = {
     "msr",
     "mul",
     "mvn",
+    "nop",
     "orr",
     "pld",
     "rsb",
     "rsc",
     "sbc",
+    "sev",
     "smlal",
     "smull",
     "stc",
@@ -80,6 +83,9 @@ static const char *opcode_names[] = {
     "tst",
     "umlal",
     "umull",
+    "wfe",
+    "wfi",
+    "yield",
 
     "undefined",
     "adc",
@@ -204,6 +210,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
             return DisassembleMSR(insn);
         case OP_MUL:
             return DisassembleMUL(opcode, insn);
+        case OP_NOP:
+        case OP_SEV:
+        case OP_WFE:
+        case OP_WFI:
+        case OP_YIELD:
+            return DisassembleNoOperands(opcode, insn);
         case OP_PLD:
             return DisassemblePLD(insn);
         case OP_STC:
@@ -646,6 +658,12 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
             cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
 }
 
+std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn)
+{
+    uint32_t cond = BITS(insn, 28, 31);
+    return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond));
+}
+
 std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
 {
     uint8_t is_reg = (insn >> 25) & 0x1;
@@ -739,6 +757,12 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
         }
     }
 
+    uint32_t op1 = BITS(insn, 20, 24);
+    if (bit25 && (op1 == 0x12 || op1 == 0x16)) {
+        // One of the MSR (immediate) and hints instructions
+        return DecodeMSRImmAndHints(insn);
+    }
+
     // One of the data processing instructions
     return DecodeALU(insn);
 }
@@ -878,6 +902,31 @@ Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
     return OP_SMLAL;
 }
 
+Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
+    uint32_t op = BIT(insn, 22);
+    uint32_t op1 = BITS(insn, 16, 19);
+    uint32_t op2 = BITS(insn, 0, 7);
+
+    if (op == 0 && op1 == 0) {
+        switch (op2) {
+            case 0x0:
+                return OP_NOP;
+            case 0x1:
+                return OP_YIELD;
+            case 0x2:
+                return OP_WFE;
+            case 0x3:
+                return OP_WFI;
+            case 0x4:
+                return OP_SEV;
+            default:
+                return OP_UNDEFINED;
+        }
+    }
+
+    return OP_MSR;
+}
+
 Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) {
     uint8_t is_load = (insn >> 20) & 0x1;
     uint8_t bits_65 = (insn >> 5) & 0x3;
diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h
index f94bd4669..a4e4adf2f 100644
--- a/src/core/arm/disassembler/arm_disasm.h
+++ b/src/core/arm/disassembler/arm_disasm.h
@@ -41,11 +41,13 @@ enum Opcode {
     OP_MSR,
     OP_MUL,
     OP_MVN,
+    OP_NOP,
     OP_ORR,
     OP_PLD,
     OP_RSB,
     OP_RSC,
     OP_SBC,
+    OP_SEV,
     OP_SMLAL,
     OP_SMULL,
     OP_STC,
@@ -63,6 +65,9 @@ enum Opcode {
     OP_TST,
     OP_UMLAL,
     OP_UMULL,
+    OP_WFE,
+    OP_WFI,
+    OP_YIELD,
 
     // Define thumb opcodes
     OP_THUMB_UNDEFINED,
@@ -118,6 +123,7 @@ class ARM_Disasm {
   static Opcode Decode10(uint32_t insn);
   static Opcode Decode11(uint32_t insn);
   static Opcode DecodeMUL(uint32_t insn);
+  static Opcode DecodeMSRImmAndHints(uint32_t insn);
   static Opcode DecodeLDRH(uint32_t insn);
   static Opcode DecodeALU(uint32_t insn);
 
@@ -135,6 +141,7 @@ class ARM_Disasm {
   static std::string DisassembleMUL(Opcode opcode, uint32_t insn);
   static std::string DisassembleMRS(uint32_t insn);
   static std::string DisassembleMSR(uint32_t insn);
+  static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn);
   static std::string DisassemblePLD(uint32_t insn);
   static std::string DisassembleSWI(uint32_t insn);
   static std::string DisassembleSWP(Opcode opcode, uint32_t insn);

From 3425cfe54a46512a2ef35e5254c2d32e14ace69a Mon Sep 17 00:00:00 2001
From: aroulin <andy.roulin@epfl.ch>
Date: Thu, 6 Aug 2015 13:55:56 +0200
Subject: [PATCH 2/2] Disassembler: ARMv6K REX instructions

---
 src/core/arm/disassembler/arm_disasm.cpp | 92 ++++++++++++++++++++++--
 src/core/arm/disassembler/arm_disasm.h   | 11 +++
 2 files changed, 97 insertions(+), 6 deletions(-)

diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index bb87043a4..8eec64d48 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -38,6 +38,7 @@ static const char *opcode_names[] = {
     "blx",
     "bx",
     "cdp",
+    "clrex",
     "clz",
     "cmn",
     "cmp",
@@ -47,6 +48,10 @@ static const char *opcode_names[] = {
     "ldr",
     "ldrb",
     "ldrbt",
+    "ldrex",
+    "ldrexb",
+    "ldrexd",
+    "ldrexh",
     "ldrh",
     "ldrsb",
     "ldrsh",
@@ -73,6 +78,10 @@ static const char *opcode_names[] = {
     "str",
     "strb",
     "strbt",
+    "strex",
+    "strexb",
+    "strexd",
+    "strexh",
     "strh",
     "strt",
     "sub",
@@ -178,6 +187,8 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
             return DisassembleBX(insn);
         case OP_CDP:
             return "cdp";
+        case OP_CLREX:
+            return "clrex";
         case OP_CLZ:
             return DisassembleCLZ(insn);
         case OP_LDC:
@@ -194,6 +205,15 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn)
         case OP_STRBT:
         case OP_STRT:
             return DisassembleMem(insn);
+        case OP_LDREX:
+        case OP_LDREXB:
+        case OP_LDREXD:
+        case OP_LDREXH:
+        case OP_STREX:
+        case OP_STREXB:
+        case OP_STREXD:
+        case OP_STREXH:
+            return DisassembleREX(opcode, insn);
         case OP_LDRH:
         case OP_LDRSB:
         case OP_LDRSH:
@@ -687,6 +707,36 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
     }
 }
 
+std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) {
+    uint32_t rn = BITS(insn, 16, 19);
+    uint32_t rd = BITS(insn, 12, 15);
+    uint32_t rt = BITS(insn, 0, 3);
+    uint32_t cond = BITS(insn, 28, 31);
+
+    switch (opcode) {
+        case OP_STREX:
+        case OP_STREXB:
+        case OP_STREXH:
+            return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
+                                            cond_to_str(cond), rd, rt, rn);
+        case OP_STREXD:
+            return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode],
+                                            cond_to_str(cond), rd, rt, rt + 1, rn);
+
+        // for LDREX instructions, rd corresponds to Rt from reference manual
+        case OP_LDREX:
+        case OP_LDREXB:
+        case OP_LDREXH:
+            return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode],
+                                            cond_to_str(cond), rd, rn);
+        case OP_LDREXD:
+            return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode],
+                                            cond_to_str(cond), rd, rd + 1, rn);
+        default:
+            return opcode_names[OP_UNDEFINED];
+    }
+}
+
 std::string ARM_Disasm::DisassembleSWI(uint32_t insn)
 {
     uint8_t cond = (insn >> 28) & 0xf;
@@ -739,12 +789,9 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) {
         }
         uint32_t bits7_4 = (insn >> 4) & 0xf;
         if (bits7_4 == 0x9) {
-            if ((insn & 0x0ff00ff0) == 0x01000090) {
-                // Swp instruction
-                uint8_t bit22 = (insn >> 22) & 0x1;
-                if (bit22)
-                    return OP_SWPB;
-                return OP_SWP;
+            uint32_t bit24 = BIT(insn, 24);
+            if (bit24) {
+                return DecodeSyncPrimitive(insn);
             }
             // One of the multiply instructions
             return DecodeMUL(insn);
@@ -778,6 +825,10 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) {
         // Pre-load
         return OP_PLD;
     }
+    if (insn == 0xf57ff01f) {
+        // Clear-Exclusive
+        return OP_CLREX;
+    }
     if (is_load) {
         if (is_byte) {
             // Load byte
@@ -868,6 +919,35 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
     return OP_MCR;
 }
 
+Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) {
+    uint32_t op = BITS(insn, 20, 23);
+    uint32_t bit22 = BIT(insn, 22);
+    switch (op) {
+        case 0x0:
+            if (bit22)
+                return OP_SWPB;
+            return OP_SWP;
+        case 0x8:
+            return OP_STREX;
+        case 0x9:
+            return OP_LDREX;
+        case 0xA:
+            return OP_STREXD;
+        case 0xB:
+            return OP_LDREXD;
+        case 0xC:
+            return OP_STREXB;
+        case 0xD:
+            return OP_LDREXB;
+        case 0xE:
+            return OP_STREXH;
+        case 0xF:
+            return OP_LDREXH;
+        default:
+            return OP_UNDEFINED;
+    }
+}
+
 Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
     uint8_t bit24 = (insn >> 24) & 0x1;
     if (bit24 != 0) {
diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h
index a4e4adf2f..d04fd21eb 100644
--- a/src/core/arm/disassembler/arm_disasm.h
+++ b/src/core/arm/disassembler/arm_disasm.h
@@ -20,6 +20,7 @@ enum Opcode {
     OP_BLX,
     OP_BX,
     OP_CDP,
+    OP_CLREX,
     OP_CLZ,
     OP_CMN,
     OP_CMP,
@@ -29,6 +30,10 @@ enum Opcode {
     OP_LDR,
     OP_LDRB,
     OP_LDRBT,
+    OP_LDREX,
+    OP_LDREXB,
+    OP_LDREXD,
+    OP_LDREXH,
     OP_LDRH,
     OP_LDRSB,
     OP_LDRSH,
@@ -55,6 +60,10 @@ enum Opcode {
     OP_STR,
     OP_STRB,
     OP_STRBT,
+    OP_STREX,
+    OP_STREXB,
+    OP_STREXD,
+    OP_STREXH,
     OP_STRH,
     OP_STRT,
     OP_SUB,
@@ -122,6 +131,7 @@ class ARM_Disasm {
   static Opcode Decode01(uint32_t insn);
   static Opcode Decode10(uint32_t insn);
   static Opcode Decode11(uint32_t insn);
+  static Opcode DecodeSyncPrimitive(uint32_t insn);
   static Opcode DecodeMUL(uint32_t insn);
   static Opcode DecodeMSRImmAndHints(uint32_t insn);
   static Opcode DecodeLDRH(uint32_t insn);
@@ -143,6 +153,7 @@ class ARM_Disasm {
   static std::string DisassembleMSR(uint32_t insn);
   static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn);
   static std::string DisassemblePLD(uint32_t insn);
+  static std::string DisassembleREX(Opcode opcode, uint32_t insn);
   static std::string DisassembleSWI(uint32_t insn);
   static std::string DisassembleSWP(Opcode opcode, uint32_t insn);
 };