diff options
| author | noone <you@example.com> | 2024-06-11 04:44:24 -0500 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-07-08 16:02:37 -0400 |
| commit | eed70ad4d270ca1d134d325362f23c831fe98b0b (patch) | |
| tree | 991fa3ba7f62bc57f42b3164529e6317b84f17ad /arch/mips | |
| parent | c3040ecfc43983af6f05da13cf2242d085b1e230 (diff) | |
Add Cavium Octeon MIPS Instructions and more general MIPS fixes
Diffstat (limited to 'arch/mips')
| -rw-r--r-- | arch/mips/arch_mips.cpp | 1024 | ||||
| -rw-r--r-- | arch/mips/il.cpp | 1305 | ||||
| -rw-r--r-- | arch/mips/il.h | 58 | ||||
| -rw-r--r-- | arch/mips/mips/mips.c | 704 | ||||
| -rw-r--r-- | arch/mips/mips/mips.h | 249 |
5 files changed, 2982 insertions, 358 deletions
diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 7f4501ba..25ce265d 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -181,12 +181,12 @@ class MipsArchitecture: public Architecture protected: size_t m_bits; BNEndianness m_endian; - uint32_t m_enablePseudoOps; + uint32_t m_decomposeFlags; virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result) { memset(&result, 0, sizeof(result)); - if (mips_decompose((uint32_t*)data, maxLen, &result, m_bits == 64 ? MIPS_64 : MIPS_32, addr, m_endian, m_enablePseudoOps) != 0) + if (mips_decompose((uint32_t*)data, maxLen, &result, m_bits == 64 ? MIPS_64 : MIPS_32, addr, m_endian, m_decomposeFlags) != 0) return false; return true; } @@ -219,6 +219,7 @@ protected: case MIPS_BLTZL: case MIPS_BNE: case MIPS_BNEL: + case MIPS_BNEZ: case MIPS_JR: case MIPS_JR_HB: case MIPS_J: @@ -233,6 +234,10 @@ protected: case MIPS_BC2TL: case MIPS_BC2F: case MIPS_BC2T: + case CNMIPS_BBIT0: + case CNMIPS_BBIT032: + case CNMIPS_BBIT1: + case CNMIPS_BBIT132: return 1; default: return 0; @@ -244,8 +249,12 @@ protected: { switch (instr.operation) { + case MIPS_LDL: + case MIPS_LDR: case MIPS_LWL: case MIPS_LWR: + case MIPS_SDL: + case MIPS_SDR: case MIPS_SWL: case MIPS_SWR: return true; @@ -270,6 +279,7 @@ protected: case MIPS_BLTZL: case MIPS_BEQ: case MIPS_BNE: + case MIPS_BNEZ: case MIPS_BEQL: case MIPS_BNEL: case MIPS_BC1F: @@ -280,6 +290,10 @@ protected: case MIPS_BC2TL: case MIPS_BC2F: case MIPS_BC2T: + case CNMIPS_BBIT0: + case CNMIPS_BBIT032: + case CNMIPS_BBIT1: + case CNMIPS_BBIT132: return true; default: return false; @@ -333,6 +347,7 @@ protected: case MIPS_BGTZ: case MIPS_BLEZ: case MIPS_BLTZ: + case MIPS_BNEZ: case MIPS_BGEZL: case MIPS_BGTZL: case MIPS_BLEZL: @@ -346,6 +361,10 @@ protected: case MIPS_BNE: case MIPS_BEQL: case MIPS_BNEL: + case CNMIPS_BBIT0: + case CNMIPS_BBIT032: + case CNMIPS_BBIT1: + case CNMIPS_BBIT132: result.AddBranch(TrueBranch, instr.operands[2].immediate, nullptr, hasBranchDelay); //need to jump over the branch delay slot and current instruction result.AddBranch(FalseBranch, addr + 8, nullptr, hasBranchDelay); @@ -383,10 +402,13 @@ protected: } public: - MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits): Architecture(name), m_bits(bits), m_endian(endian) + MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits, uint32_t decomposeFlags = 0) + : Architecture(name), m_bits(bits), m_endian(endian), m_decomposeFlags(decomposeFlags) { Ref<Settings> settings = Settings::Instance(); - m_enablePseudoOps = settings->Get<bool>("arch.mips.disassembly.pseudoOps") ? 1 : 0; + uint32_t flag_pseudo_ops = settings->Get<bool>("arch.mips.disassembly.pseudoOps") ? DECOMPOSE_FLAGS_PSEUDO_OP : 0; + + m_decomposeFlags |= flag_pseudo_ops; } virtual BNEndianness GetEndianness() const override @@ -501,7 +523,7 @@ public: il.AddInstruction(il.If(GetConditionForInstruction(il, instr, GetAddressSize()), trueCode, falseCode)); il.MarkLabel(trueCode); il.SetCurrentAddress(this, addr + instr.size); - GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize()); + GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags); for (size_t i = 0; i < instrInfo.branchCount; i++) { if (instrInfo.branchType[i] == TrueBranch) @@ -527,7 +549,7 @@ public: nop = il.Nop(); il.AddInstruction(nop); - GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize()); + GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags); LowLevelILInstruction delayed; uint32_t clobbered = BN_INVALID_REGISTER; @@ -554,7 +576,7 @@ public: } else { - status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize()); + status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags); } if (clobbered != BN_INVALID_REGISTER) @@ -603,45 +625,110 @@ public: Instruction* base; uint32_t addrToUse; bool store = false; - bool proceed = true; + bool proceed = false; + bool is32bit = false; switch (instr.operation) { - case MIPS_SWL: - store = true; - // fall through - case MIPS_LWL: - proceed = (secondInstr.operation == (store ? MIPS_SWR : MIPS_LWR)); - left = &instr; - right = &secondInstr; - break; + case MIPS_LDL: proceed = secondInstr.operation == MIPS_LDR; break; + case MIPS_LDR: proceed = secondInstr.operation == MIPS_LDL; break; + case MIPS_LWL: proceed = secondInstr.operation == MIPS_LWR; break; + case MIPS_LWR: proceed = secondInstr.operation == MIPS_LWL; break; - case MIPS_SWR: - store = true; - // fall through - case MIPS_LWR: - proceed = (secondInstr.operation == (store ? MIPS_SWL : MIPS_LWL)); - left = &secondInstr; - right = &instr; - break; + case MIPS_SDL: proceed = secondInstr.operation == MIPS_SDR; break; + case MIPS_SDR: proceed = secondInstr.operation == MIPS_SDL; break; + case MIPS_SWL: proceed = secondInstr.operation == MIPS_SWR; break; + case MIPS_SWR: proceed = secondInstr.operation == MIPS_SWL; break; - default: - proceed = false; - break; + default: proceed = false; + } + + switch (instr.operation) + { + case MIPS_SDL: + case MIPS_SDR: + case MIPS_SWL: + case MIPS_SWR: + store = true; + break; + case MIPS_LDL: + case MIPS_LDR: + case MIPS_LWL: + case MIPS_LWR: + store = false; + break; + + default: proceed = false; + } + + switch (instr.operation) + { + case MIPS_LDL: + case MIPS_LWL: + case MIPS_SDL: + case MIPS_SWL: + left = &instr; + right = &secondInstr; + break; + + case MIPS_LDR: + case MIPS_LWR: + case MIPS_SDR: + case MIPS_SWR: + left = &secondInstr; + right = &instr; + break; + + default: proceed = false; + } + + switch (instr.operation) + { + case MIPS_LWL: + case MIPS_LWR: + case MIPS_SWL: + case MIPS_SWR: + is32bit = true; + break; + + case MIPS_LDL: + case MIPS_LDR: + case MIPS_SDL: + case MIPS_SDR: + is32bit = false; + break; + + default: proceed = false; } proceed = proceed && (instr.operands[0].reg == secondInstr.operands[0].reg); if (m_endian == BigEndian) { - proceed = proceed && ((left->operands[1].immediate + 3) == right->operands[1].immediate); - addrToUse = (uint32_t)addr + ((&instr == left) ? 0 : 4); + if (is32bit) + { + proceed = proceed && ((left->operands[1].immediate + 3) == right->operands[1].immediate); + addrToUse = (uint32_t)addr + ((&instr == left) ? 0 : 4); + } + else + { + proceed = proceed && ((left->operands[1].immediate + 7) == right->operands[1].immediate); + addrToUse = (uint32_t)addr + ((&instr == left) ? 0 : 8); + } base = left; } else { - proceed = proceed && (left->operands[1].immediate == (right->operands[1].immediate + 3)); - addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 4); + if (is32bit) + { + proceed = proceed && (left->operands[1].immediate == (right->operands[1].immediate + 3)); + addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 4); + } + else + { + proceed = proceed && (left->operands[1].immediate == (right->operands[1].immediate + 7)); + addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 8); + } base = right; } @@ -649,13 +736,17 @@ public: { len = 8; il.SetCurrentAddress(this, addrToUse); - base->operation = store ? MIPS_SW : MIPS_LW; - return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize()); + if (store) + base->operation = is32bit ? MIPS_SW : MIPS_SD; + else + base->operation = is32bit ? MIPS_LW : MIPS_LD; + + return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags); } } len = instr.size; - return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize()); + return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags); } virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override @@ -702,6 +793,8 @@ public: return true; int32_t imm = instr.operands[i].immediate; + uint64_t label_imm = instr.operands[i].immediate; + if (i != 0) result.emplace_back(OperandSeparatorToken, ", "); @@ -720,7 +813,7 @@ public: result.emplace_back(IntegerToken, operand, imm); break; case LABEL: - snprintf(operand, sizeof(operand), "%#x", imm); + snprintf(operand, sizeof(operand), "%#" PRIx64, label_imm); result.emplace_back(PossibleAddressToken, operand, imm); break; case REG: @@ -800,22 +893,97 @@ public: { case MIPS_INTRIN_WSBH: return "__wsbh"; + case MIPS_INTRIN_DSBH: + return "_dsbh"; + case MIPS_INTRIN_DSHD: + return "_dshd"; case MIPS_INTRIN_MFC0: - return "moveFromCoprocessor"; + return "moveFromCoprocessor0"; + case MIPS_INTRIN_MFC2: + return "moveFromCoprocessor2"; case MIPS_INTRIN_MFC_UNIMPLEMENTED: return "moveFromCoprocessorUnimplemented"; case MIPS_INTRIN_MTC0: - return "moveToCoprocessor"; + return "moveToCoprocessor0"; + case MIPS_INTRIN_MTC2: + return "moveToCoprocessor2"; case MIPS_INTRIN_MTC_UNIMPLEMENTED: return "moveToCoprocessorUnimplemented"; case MIPS_INTRIN_DMFC0: - return "moveDwordFromCoprocessor"; + return "moveDwordFromCoprocessor0"; + case MIPS_INTRIN_DMFC2: + return "moveDwordFromCoprocessor2"; case MIPS_INTRIN_DMFC_UNIMPLEMENTED: return "moveDwordFromCoprocessorUnimplemented"; case MIPS_INTRIN_DMTC0: - return "moveDwordToCoprocessor"; + return "moveDwordToCoprocessor0"; + case MIPS_INTRIN_DMTC2: + return "moveDwordToCoprocessor2"; case MIPS_INTRIN_DMTC_UNIMPLEMENTED: return "moveDwordToCoprocessorUnimplemented"; + case MIPS_INTRIN_SYNC: + return "_sync"; + case MIPS_INTRIN_EI: + return "_enableInterrupts"; + case MIPS_INTRIN_DI: + return "_disableInterrupts"; + case MIPS_INTRIN_EHB: + return "_clearExecutionHazards"; + case MIPS_INTRIN_WAIT: + return "_enterLowPowerMode"; + case MIPS_INTRIN_HWR0: + return "_cpuNum"; + case MIPS_INTRIN_HWR1: + return "_synciStep"; + case MIPS_INTRIN_HWR2: + return "_cycleCounter"; + case MIPS_INTRIN_HWR3: + return "_cycleCounterResolution"; + case MIPS_INTRIN_HWR29: + return "_userLocalRegister"; + case MIPS_INTRIN_HWR_UNKNOWN: + return "_hardwareRegister"; + case MIPS_INTRIN_LLBIT_SET: + return "_setLLBit"; + case MIPS_INTRIN_LLBIT_CHECK: + return "_checkLLBit"; + case MIPS_INTRIN_PREFETCH: + return "_prefetch"; + case MIPS_INTRIN_CACHE: + return "_cache"; + case MIPS_INTRIN_GET_LEFT_PART32: + return "_getLeftPart32"; + case MIPS_INTRIN_GET_RIGHT_PART32: + return "_getRightPart32"; + case MIPS_INTRIN_SET_LEFT_PART32: + return "_setLeftPart32"; + case MIPS_INTRIN_SET_RIGHT_PART32: + return "_setRightPart32"; + case MIPS_INTRIN_GET_LEFT_PART64: + return "_getLeftPart64"; + case MIPS_INTRIN_GET_RIGHT_PART64: + return "_getRightPart64"; + case MIPS_INTRIN_SET_LEFT_PART64: + return "_setLeftPart64"; + case MIPS_INTRIN_SET_RIGHT_PART64: + return "_setRightPart64"; + + case CNMIPS_INTRIN_SYNCIOBDMA: + return "_synciobdma"; + case CNMIPS_INTRIN_SYNCS: + return "_syncs"; + case CNMIPS_INTRIN_SYNCW: + return "_syncw"; + case CNMIPS_INTRIN_SYNCWS: + return "_syncws"; + case CNMIPS_INTRIN_HWR30: + return "_chOrd"; + case CNMIPS_INTRIN_HWR31: + return "_cvmCount"; + case CNMIPS_INTRIN_POP: + return "_countOnes32"; + case CNMIPS_INTRIN_DPOP: + return "_countOnes64"; default: return ""; } @@ -825,6 +993,8 @@ public: { return vector<uint32_t>{ MIPS_INTRIN_WSBH, + MIPS_INTRIN_DSBH, + MIPS_INTRIN_DSHD, MIPS_INTRIN_MFC0, MIPS_INTRIN_MFC_UNIMPLEMENTED, MIPS_INTRIN_MTC0, @@ -833,6 +1003,38 @@ public: MIPS_INTRIN_DMFC_UNIMPLEMENTED, MIPS_INTRIN_DMTC0, MIPS_INTRIN_DMTC_UNIMPLEMENTED, + MIPS_INTRIN_SYNC, + MIPS_INTRIN_DI, + MIPS_INTRIN_EHB, + MIPS_INTRIN_EI, + MIPS_INTRIN_WAIT, + MIPS_INTRIN_HWR0, + MIPS_INTRIN_HWR1, + MIPS_INTRIN_HWR2, + MIPS_INTRIN_HWR3, + MIPS_INTRIN_HWR29, + MIPS_INTRIN_HWR_UNKNOWN, + MIPS_INTRIN_LLBIT_SET, + MIPS_INTRIN_LLBIT_CHECK, + MIPS_INTRIN_PREFETCH, + MIPS_INTRIN_CACHE, + MIPS_INTRIN_GET_LEFT_PART32, + MIPS_INTRIN_GET_RIGHT_PART32, + MIPS_INTRIN_SET_LEFT_PART32, + MIPS_INTRIN_SET_RIGHT_PART32, + MIPS_INTRIN_GET_LEFT_PART64, + MIPS_INTRIN_GET_RIGHT_PART64, + MIPS_INTRIN_SET_LEFT_PART64, + MIPS_INTRIN_SET_RIGHT_PART64, + + CNMIPS_INTRIN_SYNCIOBDMA, + CNMIPS_INTRIN_SYNCS, + CNMIPS_INTRIN_SYNCW, + CNMIPS_INTRIN_SYNCWS, + CNMIPS_INTRIN_HWR30, + CNMIPS_INTRIN_HWR31, + CNMIPS_INTRIN_POP, + CNMIPS_INTRIN_DPOP, }; } @@ -842,6 +1044,9 @@ public: { case MIPS_INTRIN_WSBH: return {NameAndType(Type::IntegerType(4, false))}; + case MIPS_INTRIN_DSBH: + case MIPS_INTRIN_DSHD: + return {NameAndType(Type::IntegerType(8, false))}; case MIPS_INTRIN_MFC0: return { NameAndType("register", Type::IntegerType(4, false)), @@ -886,6 +1091,71 @@ public: NameAndType("selector", Type::IntegerType(4, false)), NameAndType("value", Type::IntegerType(8, false)), }; + case MIPS_INTRIN_SYNC: + return { + NameAndType("stype", Type::IntegerType(4, false)), + }; + case MIPS_INTRIN_HWR_UNKNOWN: + return { + NameAndType("hwreg", Type::IntegerType(4, false)), + }; + case MIPS_INTRIN_LLBIT_SET: + return { + NameAndType("value", Type::IntegerType(4, false)), + }; + case MIPS_INTRIN_PREFETCH: + case MIPS_INTRIN_CACHE: + return { + NameAndType("op", Type::IntegerType(1, false)), + NameAndType("address", Type::IntegerType(m_bits == 64 ? 8 : 4, false)), + }; + + // NOTE: SET_x_PARTx could potentially benefit from + // including the old value as an input (since each + // only sets part of the register and keeps the + // other the same), but this can lead to registers + // unnecessarily treated as function arguments + // + // NOTE: PARTx intrinsics could benefit from some kind + // of "size" input indicating how many bytes to + // get/set, but that value would be taking the + // low bits of a pointer with unknown value, which + // isn't exactly useful + // + // PLUS, the majority of the SWL/SWR/etc. + // instructions that get lifted by themselves + // actually *are* members of a pair that just + // aren't immediately next to each other, so they + // go through the code checking for those pairs... + // so for each "rX = setLeftXX([address])" we also + // expect to see a "rY = setRightXX([address])", + // which is a little more follow-able + case MIPS_INTRIN_GET_LEFT_PART32: + case MIPS_INTRIN_GET_RIGHT_PART32: + return { + NameAndType("value", Type::IntegerType(4, false)), + }; + case MIPS_INTRIN_SET_LEFT_PART32: + return { + NameAndType("leftpart", Type::IntegerType(4, false)) + }; + case MIPS_INTRIN_SET_RIGHT_PART32: + return { + NameAndType("rightpart", Type::IntegerType(4, false)) + }; + case MIPS_INTRIN_GET_LEFT_PART64: + case MIPS_INTRIN_GET_RIGHT_PART64: + return { + NameAndType("value", Type::IntegerType(8, false)), + }; + case MIPS_INTRIN_SET_LEFT_PART64: + return { + NameAndType("leftpart", Type::IntegerType(8, false)) + }; + case MIPS_INTRIN_SET_RIGHT_PART64: + return { + NameAndType("rightpart", Type::IntegerType(8, false)) + }; default: return vector<NameAndType>(); } @@ -896,13 +1166,39 @@ public: switch (intrinsic) { case MIPS_INTRIN_WSBH: + case CNMIPS_INTRIN_POP: return {Type::IntegerType(4, false)}; + case MIPS_INTRIN_DSBH: + case MIPS_INTRIN_DSHD: + case CNMIPS_INTRIN_DPOP: + return {Type::IntegerType(8, false)}; case MIPS_INTRIN_MFC0: case MIPS_INTRIN_MFC_UNIMPLEMENTED: return {Type::IntegerType(4, false)}; case MIPS_INTRIN_DMFC0: case MIPS_INTRIN_DMFC_UNIMPLEMENTED: return {Type::IntegerType(8, false)}; + case MIPS_INTRIN_HWR0: + case MIPS_INTRIN_HWR1: + case MIPS_INTRIN_HWR2: + case MIPS_INTRIN_HWR3: + case MIPS_INTRIN_HWR29: + case MIPS_INTRIN_HWR_UNKNOWN: + case CNMIPS_INTRIN_HWR30: + case CNMIPS_INTRIN_HWR31: + return {Type::IntegerType(4, false)}; + case MIPS_INTRIN_LLBIT_CHECK: + return {Type::IntegerType(0, false)}; + case MIPS_INTRIN_GET_LEFT_PART32: + case MIPS_INTRIN_GET_RIGHT_PART32: + case MIPS_INTRIN_SET_LEFT_PART32: + case MIPS_INTRIN_SET_RIGHT_PART32: + return {Type::IntegerType(4, false)}; + case MIPS_INTRIN_GET_LEFT_PART64: + case MIPS_INTRIN_GET_RIGHT_PART64: + case MIPS_INTRIN_SET_LEFT_PART64: + case MIPS_INTRIN_SET_RIGHT_PART64: + return {Type::IntegerType(8, false)}; default: return vector<Confidence<Ref<Type>>>(); } @@ -995,7 +1291,7 @@ public: if (GetEndianness() == LittleEndian) instValue = bswap32(instValue); - uint32_t op = instValue >> 25; + uint32_t op = instValue >> 26; switch (op) { case 1: //REGIMM @@ -1074,7 +1370,7 @@ public: virtual vector<uint32_t> GetFullWidthRegisters() override { - return vector<uint32_t>{ + vector<uint32_t> registers = vector<uint32_t>{ REG_ZERO, REG_AT, REG_V0, REG_V1, REG_A0, REG_A1, REG_A2, REG_A3, REG_T0, REG_T1, REG_T2, REG_T3, REG_T4, REG_T5, REG_T6, REG_T7, REG_S0, REG_S1, REG_S2, REG_S3, REG_S4, REG_S5, REG_S6, REG_S7, @@ -1190,11 +1486,210 @@ public: // Coprocessor 0 register 31 REG_DESAVE, }; + + if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + uint32_t cavium_registers[] = + { + CNREG_MPL0, + CNREG_MPL1, + CNREG_MPL2, + CNREG_P0, + CNREG_P1, + CNREG_P2, + + CNREG0_CVM_COUNT, + CNREG0_CVM_CTL, + CNREG0_POWTHROTTLE, + CNREG0_CVM_MEM_CTL, + CNREG0_MULTICORE_DBG, + + CNREG2_0040_HSH_DAT0, + CNREG2_0041_HSH_DAT1, + CNREG2_0042_HSH_DAT2, + CNREG2_0043_HSH_DAT3, + CNREG2_0044_HSH_DAT4, + CNREG2_0045_HSH_DAT5, + CNREG2_0046_HSH_DAT6, + + CNREG2_0048_HSH_IV0, + CNREG2_0049_HSH_IV1, + CNREG2_004A_HSH_IV2, + CNREG2_004B_HSH_IV3, + + CNREG2_0050_SHA3_DAT24, + CNREG2_0051_SHA3_DAT15_RD, + + CNREG2_0058_GFM_MUL_REFLECT0, + CNREG2_0059_GFM_MUL_REFLECT1, + CNREG2_005A_GFM_RESINP_REFLECT0, + CNREG2_005B_GFM_RESINP_REFLECT1, + CNREG2_005C_GFM_XOR0_REFLECT, + + // also KASUMI + CNREG2_0080_3DES_KEY0, + CNREG2_0081_3DES_KEY1, + CNREG2_0082_3DES_KEY2, + + CNREG2_0084_3DES_IV, + CNREG2_0088_3DES_RESULT_RD, + CNREG2_0098_3DES_RESULT_WR, + + // also SMS4 RESINP + CNREG2_0100_AES_RESULT0, + CNREG2_0101_AES_RESULT1, + + // also SMS4 IV + CNREG2_0102_AES_IV0, + CNREG2_0103_AES_IV1, + + // also SMS4 KEY + CNREG2_0104_AES_KEY0, + CNREG2_0105_AES_KEY1, + CNREG2_0106_AES_KEY2, + CNREG2_0107_AES_KEY3, + + // also SMS4_x + CNREG2_0108_AES_ENC_CBC0, + CNREG2_010A_AES_ENC0, + CNREG2_010C_AES_DEC_CBC0, + CNREG2_010E_AES_DEC0, + + CNREG2_0110_AES_KEYLENGTH, + CNREG2_0111_AES_DAT0, + + CNREG2_0115_CAMELLIA_FL, + CNREG2_0116_CAMELLIA_FLINV, + + CNREG2_0200_CRC_POLYNOMIAL, + CNREG2_0201_CRC_IV, + CNREG2_0202_CRC_LEN, + CNREG2_0203_CRC_IV_REFLECT_RD, + CNREG2_0204_CRC_BYTE, + CNREG2_0205_CRC_HALF, + CNREG2_0206_CRC_WORD, + CNREG2_0211_CRC_IV_REFLECT_WR, + CNREG2_0214_CRC_BYTE_REFLECT, + CNREG2_0215_CRC_HALF_REFLECT, + CNREG2_0216_CRC_WORD_REFLECT, + + // also SNOW3G_LFSR, SHA3DAT0..=14 + CNREG2_0240_HSH_DATW0, + CNREG2_0241_HSH_DATW1, + CNREG2_0242_HSH_DATW2, + CNREG2_0243_HSH_DATW3, + CNREG2_0244_HSH_DATW4, + CNREG2_0245_HSH_DATW5, + CNREG2_0246_HSH_DATW6, + CNREG2_0247_HSH_DATW7, + CNREG2_0248_HSH_DATW8, + CNREG2_0249_HSH_DATW9, + CNREG2_024A_HSH_DATW10, + CNREG2_024B_HSH_DATW11, + CNREG2_024C_HSH_DATW12, + CNREG2_024D_HSH_DATW13, + CNREG2_024E_HSH_DATW14, + + CNREG2_024F_SHA3_DAT15_RD, + + // also SNOW3G_RESULT (0x250), SNOW3G_SFM (0x251, 0x252, 0x253) + CNREG2_0250_HSH_IVW0, + CNREG2_0251_HSH_IVW1, + CNREG2_0252_HSH_IVW2, + CNREG2_0253_HSH_IVW3, + CNREG2_0254_HSH_IVW4, + CNREG2_0255_HSH_IVW5, + CNREG2_0256_HSH_IVW6, + CNREG2_0257_HSH_IVW7, + + CNREG2_0258_GFM_MUL0, + CNREG2_0259_GFM_MUL1, + CNREG2_025A_GFM_RESINP0, + CNREG2_025B_GFM_RESINP1, + CNREG2_025C_GFM_XOR0, + CNREG2_025E_GFM_POLY, + + CNREG2_02C0_SHA3_XORDAT0, + CNREG2_02C1_SHA3_XORDAT1, + CNREG2_02C2_SHA3_XORDAT2, + CNREG2_02C3_SHA3_XORDAT3, + CNREG2_02C4_SHA3_XORDAT4, + CNREG2_02C5_SHA3_XORDAT5, + CNREG2_02C6_SHA3_XORDAT6, + CNREG2_02C7_SHA3_XORDAT7, + CNREG2_02C8_SHA3_XORDAT8, + CNREG2_02C9_SHA3_XORDAT9, + CNREG2_02CA_SHA3_XORDAT10, + CNREG2_02CB_SHA3_XORDAT11, + CNREG2_02CC_SHA3_XORDAT12, + CNREG2_02CD_SHA3_XORDAT13, + CNREG2_02CE_SHA3_XORDAT14, + CNREG2_02CF_SHA3_XORDAT15, + CNREG2_02D0_SHA3_XORDAT16, + CNREG2_02D1_SHA3_XORDAT17, + + CNREG2_0400_LLM_READ_ADDR0, + CNREG2_0401_LLM_WRITE_ADDR_INTERNAL0, + CNREG2_0402_LLM_DATA0, + CNREG2_0404_LLM_READ64_ADDR0, + CNREG2_0405_LLM_WRITE64_ADDR_INTERNAL0, + CNREG2_0408_LLM_READ_ADDR1, + CNREG2_0409_LLM_WRITE_ADDR_INTERNAL1, + CNREG2_040a_LLM_DATA1, + CNREG2_040c_LLM_READ64_ADDR1, + CNREG2_040d_LLM_WRITE64_ADDR_INTERNAL1, + + CNREG2_1202_CRC_LEN, + CNREG2_1207_CRC_DWORD, + CNREG2_1208_CRC_VAR, + CNREG2_1217_CRC_DWORD_REFLECT, + CNREG2_1218_CRC_VAR_REFLECT, + + CNREG2_3109_AES_ENC_CBC1, + CNREG2_310B_AES_ENC1, + CNREG2_310D_AES_DEC_CBC1, + CNREG2_310F_AES_DEC1, + + CNREG2_3114_CAMELLIA_ROUND, + + CNREG2_3119_SMS4_ENC_CBC1, + CNREG2_311B_SMS4_ENC1, + CNREG2_311D_SMS4_DEC_CBC1, + CNREG2_311F_SMS4_DEC1, + + CNREG2_4052_SHA3_STARTOP, + CNREG2_4047_HSH_STARTMD5, + CNREG2_404D_SNOW3G_START, + CNREG2_4055_ZUC_START, + CNREG2_4056_ZUC_MORE, + CNREG2_405D_GFM_XORMUL1_REFLECT, + CNREG2_404E_SNOW3G_MORE, + CNREG2_404F_HSH_STARTSHA256, + CNREG2_4057_HSH_STARTSHA, + CNREG2_4088_3DES_ENC_CBC, + CNREG2_4089_KAS_ENC_CBC, + CNREG2_408A_3DES_ENC, + CNREG2_408B_KAS_ENC, + CNREG2_408C_3DES_DEC_CBC, + CNREG2_408E_3DES_DEC, + + CNREG2_4200_CRC_POLYNOMIAL_WR, + CNREG2_4210_CRC_POLYNOMIAL_REFLECT, + + CNREG2_424F_HSH_STARTSHA512, + CNREG2_425D_GFM_XORMUL1, + + }; + + registers.insert(registers.end(), std::begin(cavium_registers), std::end(cavium_registers)); + } + + return registers; } virtual vector<uint32_t> GetAllRegisters() override { - return vector<uint32_t>{ + vector<uint32_t> registers = vector<uint32_t>{ REG_ZERO, REG_AT, REG_V0, REG_V1, REG_A0, REG_A1, REG_A2, REG_A3, REG_T0, REG_T1, REG_T2, REG_T3, REG_T4, REG_T5, REG_T6, REG_T7, REG_S0, REG_S1, REG_S2, REG_S3, REG_S4, REG_S5, REG_S6, REG_S7, @@ -1309,6 +1804,205 @@ public: // Coprocessor 0 register 31 REG_DESAVE, }; + + if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + uint32_t cavium_registers[] = + { + CNREG_MPL0, + CNREG_MPL1, + CNREG_MPL2, + CNREG_P0, + CNREG_P1, + CNREG_P2, + + CNREG0_CVM_COUNT, + CNREG0_CVM_CTL, + CNREG0_POWTHROTTLE, + CNREG0_CVM_MEM_CTL, + CNREG0_MULTICORE_DBG, + + CNREG2_0040_HSH_DAT0, + CNREG2_0041_HSH_DAT1, + CNREG2_0042_HSH_DAT2, + CNREG2_0043_HSH_DAT3, + CNREG2_0044_HSH_DAT4, + CNREG2_0045_HSH_DAT5, + CNREG2_0046_HSH_DAT6, + + CNREG2_0048_HSH_IV0, + CNREG2_0049_HSH_IV1, + CNREG2_004A_HSH_IV2, + CNREG2_004B_HSH_IV3, + + CNREG2_0050_SHA3_DAT24, + CNREG2_0051_SHA3_DAT15_RD, + + CNREG2_0058_GFM_MUL_REFLECT0, + CNREG2_0059_GFM_MUL_REFLECT1, + CNREG2_005A_GFM_RESINP_REFLECT0, + CNREG2_005B_GFM_RESINP_REFLECT1, + CNREG2_005C_GFM_XOR0_REFLECT, + + // also KASUMI + CNREG2_0080_3DES_KEY0, + CNREG2_0081_3DES_KEY1, + CNREG2_0082_3DES_KEY2, + + CNREG2_0084_3DES_IV, + CNREG2_0088_3DES_RESULT_RD, + CNREG2_0098_3DES_RESULT_WR, + + // also SMS4 RESINP + CNREG2_0100_AES_RESULT0, + CNREG2_0101_AES_RESULT1, + + // also SMS4 IV + CNREG2_0102_AES_IV0, + CNREG2_0103_AES_IV1, + + // also SMS4 KEY + CNREG2_0104_AES_KEY0, + CNREG2_0105_AES_KEY1, + CNREG2_0106_AES_KEY2, + CNREG2_0107_AES_KEY3, + + // also SMS4_x + CNREG2_0108_AES_ENC_CBC0, + CNREG2_010A_AES_ENC0, + CNREG2_010C_AES_DEC_CBC0, + CNREG2_010E_AES_DEC0, + + CNREG2_0110_AES_KEYLENGTH, + CNREG2_0111_AES_DAT0, + + CNREG2_0115_CAMELLIA_FL, + CNREG2_0116_CAMELLIA_FLINV, + + CNREG2_0200_CRC_POLYNOMIAL, + CNREG2_0201_CRC_IV, + CNREG2_0202_CRC_LEN, + CNREG2_0203_CRC_IV_REFLECT_RD, + CNREG2_0204_CRC_BYTE, + CNREG2_0205_CRC_HALF, + CNREG2_0206_CRC_WORD, + CNREG2_0211_CRC_IV_REFLECT_WR, + CNREG2_0214_CRC_BYTE_REFLECT, + CNREG2_0215_CRC_HALF_REFLECT, + CNREG2_0216_CRC_WORD_REFLECT, + + // also SNOW3G_LFSR, SHA3DAT0..=14 + CNREG2_0240_HSH_DATW0, + CNREG2_0241_HSH_DATW1, + CNREG2_0242_HSH_DATW2, + CNREG2_0243_HSH_DATW3, + CNREG2_0244_HSH_DATW4, + CNREG2_0245_HSH_DATW5, + CNREG2_0246_HSH_DATW6, + CNREG2_0247_HSH_DATW7, + CNREG2_0248_HSH_DATW8, + CNREG2_0249_HSH_DATW9, + CNREG2_024A_HSH_DATW10, + CNREG2_024B_HSH_DATW11, + CNREG2_024C_HSH_DATW12, + CNREG2_024D_HSH_DATW13, + CNREG2_024E_HSH_DATW14, + + CNREG2_024F_SHA3_DAT15_RD, + + // also SNOW3G_RESULT (0x250), SNOW3G_SFM (0x251, 0x252, 0x253) + CNREG2_0250_HSH_IVW0, + CNREG2_0251_HSH_IVW1, + CNREG2_0252_HSH_IVW2, + CNREG2_0253_HSH_IVW3, + CNREG2_0254_HSH_IVW4, + CNREG2_0255_HSH_IVW5, + CNREG2_0256_HSH_IVW6, + CNREG2_0257_HSH_IVW7, + + CNREG2_0258_GFM_MUL0, + CNREG2_0259_GFM_MUL1, + CNREG2_025A_GFM_RESINP0, + CNREG2_025B_GFM_RESINP1, + CNREG2_025C_GFM_XOR0, + CNREG2_025E_GFM_POLY, + + CNREG2_02C0_SHA3_XORDAT0, + CNREG2_02C1_SHA3_XORDAT1, + CNREG2_02C2_SHA3_XORDAT2, + CNREG2_02C3_SHA3_XORDAT3, + CNREG2_02C4_SHA3_XORDAT4, + CNREG2_02C5_SHA3_XORDAT5, + CNREG2_02C6_SHA3_XORDAT6, + CNREG2_02C7_SHA3_XORDAT7, + CNREG2_02C8_SHA3_XORDAT8, + CNREG2_02C9_SHA3_XORDAT9, + CNREG2_02CA_SHA3_XORDAT10, + CNREG2_02CB_SHA3_XORDAT11, + CNREG2_02CC_SHA3_XORDAT12, + CNREG2_02CD_SHA3_XORDAT13, + CNREG2_02CE_SHA3_XORDAT14, + CNREG2_02CF_SHA3_XORDAT15, + CNREG2_02D0_SHA3_XORDAT16, + CNREG2_02D1_SHA3_XORDAT17, + + CNREG2_0400_LLM_READ_ADDR0, + CNREG2_0401_LLM_WRITE_ADDR_INTERNAL0, + CNREG2_0402_LLM_DATA0, + CNREG2_0404_LLM_READ64_ADDR0, + CNREG2_0405_LLM_WRITE64_ADDR_INTERNAL0, + CNREG2_0408_LLM_READ_ADDR1, + CNREG2_0409_LLM_WRITE_ADDR_INTERNAL1, + CNREG2_040a_LLM_DATA1, + CNREG2_040c_LLM_READ64_ADDR1, + CNREG2_040d_LLM_WRITE64_ADDR_INTERNAL1, + + CNREG2_1202_CRC_LEN, + CNREG2_1207_CRC_DWORD, + CNREG2_1208_CRC_VAR, + CNREG2_1217_CRC_DWORD_REFLECT, + CNREG2_1218_CRC_VAR_REFLECT, + + CNREG2_3109_AES_ENC_CBC1, + CNREG2_310B_AES_ENC1, + CNREG2_310D_AES_DEC_CBC1, + CNREG2_310F_AES_DEC1, + + CNREG2_3114_CAMELLIA_ROUND, + + CNREG2_3119_SMS4_ENC_CBC1, + CNREG2_311B_SMS4_ENC1, + CNREG2_311D_SMS4_DEC_CBC1, + CNREG2_311F_SMS4_DEC1, + + CNREG2_4052_SHA3_STARTOP, + CNREG2_4047_HSH_STARTMD5, + CNREG2_404D_SNOW3G_START, + CNREG2_4055_ZUC_START, + CNREG2_4056_ZUC_MORE, + CNREG2_405D_GFM_XORMUL1_REFLECT, + CNREG2_404E_SNOW3G_MORE, + CNREG2_404F_HSH_STARTSHA256, + CNREG2_4057_HSH_STARTSHA, + CNREG2_4088_3DES_ENC_CBC, + CNREG2_4089_KAS_ENC_CBC, + CNREG2_408A_3DES_ENC, + CNREG2_408B_KAS_ENC, + CNREG2_408C_3DES_DEC_CBC, + CNREG2_408E_3DES_DEC, + + CNREG2_4200_CRC_POLYNOMIAL_WR, + CNREG2_4210_CRC_POLYNOMIAL_REFLECT, + + CNREG2_424F_HSH_STARTSHA512, + CNREG2_425D_GFM_XORMUL1, + + }; + + registers.insert(registers.end(), std::begin(cavium_registers), std::end(cavium_registers)); + } + + return registers; } virtual vector<uint32_t> GetAllFlags() override @@ -1336,7 +2030,7 @@ public: virtual vector<uint32_t> GetSystemRegisters() override { - return vector< uint32_t> { + vector<uint32_t> registers = vector<uint32_t>{ // Coprocessor 0 register 0 REG_INDEX, REG_MVP_CONTROL, @@ -1437,7 +2131,207 @@ public: REG_ERROR_EPC, // Coprocessor 0 register 31 REG_DESAVE, + }; + + if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + uint32_t cavium_registers[] = + { + CNREG_MPL0, + CNREG_MPL1, + CNREG_MPL2, + CNREG_P0, + CNREG_P1, + CNREG_P2, + + CNREG0_CVM_COUNT, + CNREG0_CVM_CTL, + CNREG0_POWTHROTTLE, + CNREG0_CVM_MEM_CTL, + CNREG0_MULTICORE_DBG, + + CNREG2_0040_HSH_DAT0, + CNREG2_0041_HSH_DAT1, + CNREG2_0042_HSH_DAT2, + CNREG2_0043_HSH_DAT3, + CNREG2_0044_HSH_DAT4, + CNREG2_0045_HSH_DAT5, + CNREG2_0046_HSH_DAT6, + + CNREG2_0048_HSH_IV0, + CNREG2_0049_HSH_IV1, + CNREG2_004A_HSH_IV2, + CNREG2_004B_HSH_IV3, + + CNREG2_0050_SHA3_DAT24, + CNREG2_0051_SHA3_DAT15_RD, + + CNREG2_0058_GFM_MUL_REFLECT0, + CNREG2_0059_GFM_MUL_REFLECT1, + CNREG2_005A_GFM_RESINP_REFLECT0, + CNREG2_005B_GFM_RESINP_REFLECT1, + CNREG2_005C_GFM_XOR0_REFLECT, + + // also KASUMI + CNREG2_0080_3DES_KEY0, + CNREG2_0081_3DES_KEY1, + CNREG2_0082_3DES_KEY2, + + CNREG2_0084_3DES_IV, + CNREG2_0088_3DES_RESULT_RD, + CNREG2_0098_3DES_RESULT_WR, + + // also SMS4 RESINP + CNREG2_0100_AES_RESULT0, + CNREG2_0101_AES_RESULT1, + + // also SMS4 IV + CNREG2_0102_AES_IV0, + CNREG2_0103_AES_IV1, + + // also SMS4 KEY + CNREG2_0104_AES_KEY0, + CNREG2_0105_AES_KEY1, + CNREG2_0106_AES_KEY2, + CNREG2_0107_AES_KEY3, + + // also SMS4_x + CNREG2_0108_AES_ENC_CBC0, + CNREG2_010A_AES_ENC0, + CNREG2_010C_AES_DEC_CBC0, + CNREG2_010E_AES_DEC0, + + CNREG2_0110_AES_KEYLENGTH, + CNREG2_0111_AES_DAT0, + + CNREG2_0115_CAMELLIA_FL, + CNREG2_0116_CAMELLIA_FLINV, + + CNREG2_0200_CRC_POLYNOMIAL, + CNREG2_0201_CRC_IV, + CNREG2_0202_CRC_LEN, + CNREG2_0203_CRC_IV_REFLECT_RD, + CNREG2_0204_CRC_BYTE, + CNREG2_0205_CRC_HALF, + CNREG2_0206_CRC_WORD, + CNREG2_0211_CRC_IV_REFLECT_WR, + CNREG2_0214_CRC_BYTE_REFLECT, + CNREG2_0215_CRC_HALF_REFLECT, + CNREG2_0216_CRC_WORD_REFLECT, + + // also SNOW3G_LFSR, SHA3DAT0..=14 + CNREG2_0240_HSH_DATW0, + CNREG2_0241_HSH_DATW1, + CNREG2_0242_HSH_DATW2, + CNREG2_0243_HSH_DATW3, + CNREG2_0244_HSH_DATW4, + CNREG2_0245_HSH_DATW5, + CNREG2_0246_HSH_DATW6, + CNREG2_0247_HSH_DATW7, + CNREG2_0248_HSH_DATW8, + CNREG2_0249_HSH_DATW9, + CNREG2_024A_HSH_DATW10, + CNREG2_024B_HSH_DATW11, + CNREG2_024C_HSH_DATW12, + CNREG2_024D_HSH_DATW13, + CNREG2_024E_HSH_DATW14, + + CNREG2_024F_SHA3_DAT15_RD, + + // also SNOW3G_RESULT (0x250), SNOW3G_SFM (0x251, 0x252, 0x253) + CNREG2_0250_HSH_IVW0, + CNREG2_0251_HSH_IVW1, + CNREG2_0252_HSH_IVW2, + CNREG2_0253_HSH_IVW3, + CNREG2_0254_HSH_IVW4, + CNREG2_0255_HSH_IVW5, + CNREG2_0256_HSH_IVW6, + CNREG2_0257_HSH_IVW7, + + CNREG2_0258_GFM_MUL0, + CNREG2_0259_GFM_MUL1, + CNREG2_025A_GFM_RESINP0, + CNREG2_025B_GFM_RESINP1, + CNREG2_025C_GFM_XOR0, + CNREG2_025E_GFM_POLY, + + CNREG2_02C0_SHA3_XORDAT0, + CNREG2_02C1_SHA3_XORDAT1, + CNREG2_02C2_SHA3_XORDAT2, + CNREG2_02C3_SHA3_XORDAT3, + CNREG2_02C4_SHA3_XORDAT4, + CNREG2_02C5_SHA3_XORDAT5, + CNREG2_02C6_SHA3_XORDAT6, + CNREG2_02C7_SHA3_XORDAT7, + CNREG2_02C8_SHA3_XORDAT8, + CNREG2_02C9_SHA3_XORDAT9, + CNREG2_02CA_SHA3_XORDAT10, + CNREG2_02CB_SHA3_XORDAT11, + CNREG2_02CC_SHA3_XORDAT12, + CNREG2_02CD_SHA3_XORDAT13, + CNREG2_02CE_SHA3_XORDAT14, + CNREG2_02CF_SHA3_XORDAT15, + CNREG2_02D0_SHA3_XORDAT16, + CNREG2_02D1_SHA3_XORDAT17, + + CNREG2_0400_LLM_READ_ADDR0, + CNREG2_0401_LLM_WRITE_ADDR_INTERNAL0, + CNREG2_0402_LLM_DATA0, + CNREG2_0404_LLM_READ64_ADDR0, + CNREG2_0405_LLM_WRITE64_ADDR_INTERNAL0, + CNREG2_0408_LLM_READ_ADDR1, + CNREG2_0409_LLM_WRITE_ADDR_INTERNAL1, + CNREG2_040a_LLM_DATA1, + CNREG2_040c_LLM_READ64_ADDR1, + CNREG2_040d_LLM_WRITE64_ADDR_INTERNAL1, + + CNREG2_1202_CRC_LEN, + CNREG2_1207_CRC_DWORD, + CNREG2_1208_CRC_VAR, + CNREG2_1217_CRC_DWORD_REFLECT, + CNREG2_1218_CRC_VAR_REFLECT, + + CNREG2_3109_AES_ENC_CBC1, + CNREG2_310B_AES_ENC1, + CNREG2_310D_AES_DEC_CBC1, + CNREG2_310F_AES_DEC1, + + CNREG2_3114_CAMELLIA_ROUND, + + CNREG2_3119_SMS4_ENC_CBC1, + CNREG2_311B_SMS4_ENC1, + CNREG2_311D_SMS4_DEC_CBC1, + CNREG2_311F_SMS4_DEC1, + + CNREG2_4052_SHA3_STARTOP, + CNREG2_4047_HSH_STARTMD5, + CNREG2_404D_SNOW3G_START, + CNREG2_4055_ZUC_START, + CNREG2_4056_ZUC_MORE, + CNREG2_405D_GFM_XORMUL1_REFLECT, + CNREG2_404E_SNOW3G_MORE, + CNREG2_404F_HSH_STARTSHA256, + CNREG2_4057_HSH_STARTSHA, + CNREG2_4088_3DES_ENC_CBC, + CNREG2_4089_KAS_ENC_CBC, + CNREG2_408A_3DES_ENC, + CNREG2_408B_KAS_ENC, + CNREG2_408C_3DES_DEC_CBC, + CNREG2_408E_3DES_DEC, + + CNREG2_4200_CRC_POLYNOMIAL_WR, + CNREG2_4210_CRC_POLYNOMIAL_REFLECT, + + CNREG2_424F_HSH_STARTSHA512, + CNREG2_425D_GFM_XORMUL1, + + }; + + registers.insert(registers.end(), std::begin(cavium_registers), std::end(cavium_registers)); + } + + return registers; } }; @@ -2035,7 +2929,7 @@ public: uint32_t inst2 = *(uint32_t*)(cur->relocationDataCache); Instruction instruction; memset(&instruction, 0, sizeof(instruction)); - if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, MIPS_32, cur->address, arch->GetEndianness(), 1)) + if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, MIPS_32, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) break; int32_t immediate = swap(inst2) & 0xffff; @@ -2226,6 +3120,36 @@ static void InitMipsSettings() })"); } + +static Ref<Platform> ElfFlagsRecognize(BinaryView* view, Metadata* metadata) +{ + Ref<Metadata> abiMetadata = metadata->Get("EI_OSABI"); + if (!abiMetadata || !abiMetadata->IsUnsignedInteger()) + return nullptr; + + uint64_t abi = abiMetadata->GetUnsignedInteger(); + if (abi != 0 && abi != 3) + return nullptr; + + Ref<Metadata> flagsMetadata = metadata->Get("e_flags"); + if (!flagsMetadata || !flagsMetadata->IsUnsignedInteger()) + return nullptr; + + uint64_t flagsValue = flagsMetadata->GetUnsignedInteger(); + uint8_t machineVariant = (flagsValue >> 16) & 0xff; + + switch (machineVariant) + { + case 0x8b: // EF_MIPS_MACH_OCTEON + case 0x8d: // EF_MIPS_MACH_OCTEON2 + case 0x8e: // EF_MIPS_MACH_OCTEON3 + LogInfo("ELF flags 0x%08" PRIx64 " machine variant 0x%02x: using cavium architecture", flagsValue, machineVariant); + return Platform::GetByName("linux-cnmips64"); + default: + return nullptr; + } +} + extern "C" { BN_DECLARE_CORE_ABI_VERSION @@ -2245,15 +3169,18 @@ extern "C" Architecture* mipsel = new MipsArchitecture("mipsel32", LittleEndian, 32); Architecture* mipseb = new MipsArchitecture("mips32", BigEndian, 32); Architecture* mips64eb = new MipsArchitecture("mips64", BigEndian, 64); + Architecture* cnmips64eb = new MipsArchitecture("cavium-mips64", BigEndian, 64, DECOMPOSE_FLAGS_CAVIUM); Architecture::Register(mipsel); Architecture::Register(mipseb); Architecture::Register(mips64eb); + Architecture::Register(cnmips64eb); /* calling conventions */ MipsO32CallingConvention* o32LE = new MipsO32CallingConvention(mipsel); MipsO32CallingConvention* o32BE = new MipsO32CallingConvention(mipseb); MipsN64CallingConvention* n64BE = new MipsN64CallingConvention(mips64eb); + MipsN64CallingConvention* n64BEc = new MipsN64CallingConvention(cnmips64eb); mipsel->RegisterCallingConvention(o32LE); mipseb->RegisterCallingConvention(o32BE); @@ -2261,6 +3188,8 @@ extern "C" mipseb->SetDefaultCallingConvention(o32BE); mips64eb->RegisterCallingConvention(n64BE); mips64eb->SetDefaultCallingConvention(n64BE); + cnmips64eb->RegisterCallingConvention(n64BEc); + cnmips64eb->SetDefaultCallingConvention(n64BEc); MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel); MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb); @@ -2270,6 +3199,7 @@ extern "C" mipsel->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipsel)); mipseb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipseb)); mips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips64eb)); + cnmips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(cnmips64eb)); /* function recognizers */ mipsel->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); @@ -2278,6 +3208,7 @@ extern "C" mipsel->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mipseb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); + cnmips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); // Register the architectures with the binary format parsers so that they know when to use // these architectures for disassembling an executable file @@ -2292,6 +3223,11 @@ extern "C" BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS64, BigEndian, mips64eb); BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS32, LittleEndian, mipsel); BinaryViewType::RegisterArchitecture("ELF", ARCH_ID_MIPS32, BigEndian, mipseb); + + Ref<BinaryViewType> elf = BinaryViewType::GetByName("ELF"); + if (elf) + elf->RegisterPlatformRecognizer(ARCH_ID_MIPS64, BigEndian, ElfFlagsRecognize); + BinaryViewType::RegisterArchitecture("PE", 0x166, LittleEndian, mipsel); return true; } diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 76a62274..37785db2 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -62,33 +62,33 @@ static void ConditionExecute(LowLevelILFunction& il, ExprId cond, ExprId trueCas } -static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t addrSize) +static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t addrSize, int32_t delta=0) { size_t offset = 0; if (operand.reg == REG_ZERO) - return il.ConstPointer(addrSize, operand.immediate); + return il.ConstPointer(addrSize, operand.immediate + (int64_t)delta); if (operand.operandClass == MEM_IMM) { - if (operand.immediate >= 0x80000000) + if (operand.immediate + (uint64_t)((int64_t)delta) >= 0x80000000) offset = il.Sub(addrSize, il.Register(addrSize, operand.reg), - il.Const(addrSize, -(int32_t)operand.immediate)); + il.Const(addrSize, -((int32_t)operand.immediate + delta))); else offset = il.Add(addrSize, il.Register(addrSize, operand.reg), - il.Const(addrSize, operand.immediate)); + il.Const(addrSize, operand.immediate + delta)); } else if (operand.operandClass == MEM_REG) { - if (operand.immediate >= 0x80000000) + if (operand.immediate + (uint64_t)((int64_t)delta) >= 0x80000000) offset = il.Sub(addrSize, il.Register(addrSize, operand.reg), - il.Register(addrSize, -(int32_t)operand.immediate)); + il.Register(addrSize, -((int32_t)operand.immediate + delta))); else offset = il.Add(addrSize, il.Register(addrSize, operand.reg), - il.Register(addrSize, operand.immediate)); + il.Register(addrSize, operand.immediate + delta)); } return offset; } @@ -101,7 +101,8 @@ static size_t ReadILOperand(LowLevelILFunction& il, size_t opSize = SIZE_MAX, bool isAddress = false) { - if (opSize == SIZE_MAX) { + if (opSize == SIZE_MAX) + { opSize = registerSize; } InstructionOperand operand = instr.operands[i - 1]; @@ -199,6 +200,8 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, si return il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)); case MIPS_BEQZ: return il.CompareEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + case MIPS_BNEZ: + return il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); case MIPS_BGEZ: case MIPS_BGEZL: case MIPS_BGEZAL: @@ -223,19 +226,87 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, si if (instr.operands[0].operandClass == FLAG) return il.Flag(instr.operands[0].reg); return il.Flag(FPCCREG_FCC0); + case CNMIPS_BBIT0: + return il.CompareEqual(registerSize, + il.And(registerSize, + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, 1 << instr.operands[1].immediate) + ), + il.Const(registerSize, 0) + ); + case CNMIPS_BBIT032: + return il.CompareEqual(registerSize, + il.And(registerSize, + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32)) + ), + il.Const(registerSize, 0) + ); + case CNMIPS_BBIT1: + return il.CompareNotEqual(registerSize, + il.And(registerSize, + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, 1 << instr.operands[1].immediate) + ), + il.Const(registerSize, 0) + ); + case CNMIPS_BBIT132: + return il.CompareNotEqual(registerSize, + il.And(registerSize, + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32)) + ), + il.Const(registerSize, 0) + ); + default: LogError("Missing conditional: %d", instr.operation); return il.Unimplemented(); } } +static bool IsCop0ImplementationDefined(uint32_t reg, uint64_t sel) +{ + switch (reg) + { + case 9: + switch (sel) + { + case 6: + case 7: return true; + default: return false; + } + break; + case 11: + switch (sel) + { + case 6: + case 7: return true; + default: return false; + } + break; + case 16: + switch (sel) + { + case 6: + case 7: return true; + default: return false; + } + break; + case 22: return true; + default: return false; + } +} + // Get the IL Register for a given cop0 register/selector pair. // Returns REG_ZERO for unsupported/unimplemented values. static Reg GetCop0Register(uint32_t reg, uint64_t sel) { - switch (reg) { + switch (reg) + { case 0: - switch (sel) { + switch (sel) + { case 0: return REG_INDEX; case 1: return REG_MVP_CONTROL; case 2: return REG_MVP_CONF0; @@ -243,7 +314,8 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 1: - switch (sel) { + switch (sel) + { case 0: return REG_RANDOM; case 1: return REG_VPE_CONTROL; case 2: return REG_VPE_CONF0; @@ -255,7 +327,8 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 2: - switch (sel) { + switch (sel) + { case 0: return REG_ENTRY_LO0; case 1: return REG_TC_STATUS; case 2: return REG_TC_BIND; @@ -267,24 +340,28 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 3: - switch (sel) { + switch (sel) + { case 0: return REG_ENTRY_LO1; } break; case 4: - switch (sel) { + switch (sel) + { case 0: return REG_CONTEXT; case 1: return REG_CONTEXT_CONFIG; } break; case 5: - switch (sel) { + switch (sel) + { case 0: return REG_PAGE_MASK; case 1: return REG_PAGE_GRAIN; } break; case 6: - switch (sel) { + switch (sel) + { case 0: return REG_WIRED; case 1: return REG_SRS_CONF0; case 2: return REG_SRS_CONF1; @@ -294,32 +371,38 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 7: - switch (sel) { + switch (sel) + { case 0: return REG_HWR_ENA; } break; case 8: - switch (sel) { + switch (sel) + { case 0: return REG_BAD_VADDR; } break; case 9: - switch (sel) { + switch (sel) + { case 0: return REG_COUNT; } break; case 10: - switch (sel) { + switch (sel) + { case 0: return REG_ENTRY_HI; } break; case 11: - switch (sel) { + switch (sel) + { case 0: return REG_COMPARE; } break; case 12: - switch (sel) { + switch (sel) + { case 0: return REG_STATUS; case 1: return REG_INT_CTL; case 2: return REG_SRS_CTL; @@ -327,23 +410,27 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 13: - switch (sel) { + switch (sel) + { case 0: return REG_CAUSE; } break; case 14: - switch (sel) { + switch (sel) + { case 0: return REG_EPC; } break; case 15: - switch (sel) { + switch (sel) + { case 0: return REG_PR_ID; case 1: return REG_EBASE; } break; case 16: - switch (sel) { + switch (sel) + { case 0: return REG_CONFIG; case 1: return REG_CONFIG1; case 2: return REG_CONFIG2; @@ -351,17 +438,20 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 17: - switch (sel) { + switch (sel) + { case 0: return REG_LLADDR; } break; case 20: - switch (sel) { + switch (sel) + { case 0: return REG_XCONTEXT; } break; case 23: - switch (sel) { + switch (sel) + { case 0: return REG_DEBUG; case 1: return REG_TRACE_CONTROL; case 2: return REG_TRACE_CONTROL2; @@ -370,17 +460,20 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 24: - switch (sel) { + switch (sel) + { case 0: return REG_DEPC; } break; case 26: - switch (sel) { + switch (sel) + { case 0: return REG_ERR_CTL; } break; case 27: - switch (sel) { + switch (sel) + { case 0: return REG_CACHE_ERR0; case 1: return REG_CACHE_ERR1; case 2: return REG_CACHE_ERR2; @@ -388,12 +481,14 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) } break; case 30: - switch (sel) { + switch (sel) + { case 0: return REG_ERROR_EPC; } break; case 31: - switch (sel) { + switch (sel) + { case 0: return REG_DESAVE; } break; @@ -401,18 +496,224 @@ static Reg GetCop0Register(uint32_t reg, uint64_t sel) return REG_ZERO; } -static ExprId MoveFromCoprocessor(unsigned cop, LowLevelILFunction& il, size_t loadSize, uint32_t outReg, uint32_t reg, uint64_t sel) +static Reg GetCaviumCop0Register(uint32_t reg, uint64_t sel) { - if (cop == 0) { + switch (reg) + { + case 9: + switch (sel) + { + case 6: return CNREG0_CVM_COUNT; + case 7: return CNREG0_CVM_CTL; + default: return REG_ZERO; + } + break; + + case 11: + switch (sel) + { + case 6: return CNREG0_POWTHROTTLE; + case 7: return CNREG0_CVM_MEM_CTL; + default: return REG_ZERO; + } + break; + case 22: + switch (sel) + { + case 0: return CNREG0_MULTICORE_DBG; + default: return REG_ZERO; + } + break; + + default: return REG_ZERO; + } +} + +static Reg GetCaviumCop2Register(uint32_t reg) +{ + switch (reg) + { + case 0x0040: return CNREG2_0040_HSH_DAT0; + case 0x0041: return CNREG2_0041_HSH_DAT1; + case 0x0042: return CNREG2_0042_HSH_DAT2; + case 0x0043: return CNREG2_0043_HSH_DAT3; + case 0x0044: return CNREG2_0044_HSH_DAT4; + case 0x0045: return CNREG2_0045_HSH_DAT5; + case 0x0046: return CNREG2_0046_HSH_DAT6; + case 0x0048: return CNREG2_0048_HSH_IV0; + case 0x0049: return CNREG2_0049_HSH_IV1; + case 0x004a: return CNREG2_004A_HSH_IV2; + case 0x004b: return CNREG2_004B_HSH_IV3; + case 0x0050: return CNREG2_0050_SHA3_DAT24; + case 0x0051: return CNREG2_0051_SHA3_DAT15_RD; + case 0x0058: return CNREG2_0058_GFM_MUL_REFLECT0; + case 0x0059: return CNREG2_0059_GFM_MUL_REFLECT1; + case 0x005a: return CNREG2_005A_GFM_RESINP_REFLECT0; + case 0x005b: return CNREG2_005B_GFM_RESINP_REFLECT1; + case 0x005c: return CNREG2_005C_GFM_XOR0_REFLECT; + case 0x0080: return CNREG2_0080_3DES_KEY0; + case 0x0081: return CNREG2_0081_3DES_KEY1; + case 0x0082: return CNREG2_0082_3DES_KEY2; + case 0x0084: return CNREG2_0084_3DES_IV; + case 0x0088: return CNREG2_0088_3DES_RESULT_RD; + case 0x0098: return CNREG2_0098_3DES_RESULT_WR; + case 0x0100: return CNREG2_0100_AES_RESULT0; + case 0x0101: return CNREG2_0101_AES_RESULT1; + case 0x0102: return CNREG2_0102_AES_IV0; + case 0x0103: return CNREG2_0103_AES_IV1; + case 0x0104: return CNREG2_0104_AES_KEY0; + case 0x0105: return CNREG2_0105_AES_KEY1; + case 0x0106: return CNREG2_0106_AES_KEY2; + case 0x0107: return CNREG2_0107_AES_KEY3; + case 0x0108: return CNREG2_0108_AES_ENC_CBC0; + case 0x010a: return CNREG2_010A_AES_ENC0; + case 0x010c: return CNREG2_010C_AES_DEC_CBC0; + case 0x010e: return CNREG2_010E_AES_DEC0; + case 0x0110: return CNREG2_0110_AES_KEYLENGTH; + case 0x0111: return CNREG2_0111_AES_DAT0; + case 0x0115: return CNREG2_0115_CAMELLIA_FL; + case 0x0116: return CNREG2_0116_CAMELLIA_FLINV; + case 0x0200: return CNREG2_0200_CRC_POLYNOMIAL; + case 0x0201: return CNREG2_0201_CRC_IV; + case 0x0202: return CNREG2_0202_CRC_LEN; + case 0x0203: return CNREG2_0203_CRC_IV_REFLECT_RD; + case 0x0204: return CNREG2_0204_CRC_BYTE; + case 0x0205: return CNREG2_0205_CRC_HALF; + case 0x0206: return CNREG2_0206_CRC_WORD; + case 0x0211: return CNREG2_0211_CRC_IV_REFLECT_WR; + case 0x0214: return CNREG2_0214_CRC_BYTE_REFLECT; + case 0x0215: return CNREG2_0215_CRC_HALF_REFLECT; + case 0x0216: return CNREG2_0216_CRC_WORD_REFLECT; + case 0x0240: return CNREG2_0240_HSH_DATW0; + case 0x0241: return CNREG2_0241_HSH_DATW1; + case 0x0242: return CNREG2_0242_HSH_DATW2; + case 0x0243: return CNREG2_0243_HSH_DATW3; + case 0x0244: return CNREG2_0244_HSH_DATW4; + case 0x0245: return CNREG2_0245_HSH_DATW5; + case 0x0246: return CNREG2_0246_HSH_DATW6; + case 0x0247: return CNREG2_0247_HSH_DATW7; + case 0x0248: return CNREG2_0248_HSH_DATW8; + case 0x0249: return CNREG2_0249_HSH_DATW9; + case 0x024a: return CNREG2_024A_HSH_DATW10; + case 0x024b: return CNREG2_024B_HSH_DATW11; + case 0x024c: return CNREG2_024C_HSH_DATW12; + case 0x024d: return CNREG2_024D_HSH_DATW13; + case 0x024e: return CNREG2_024E_HSH_DATW14; + case 0x024f: return CNREG2_024F_SHA3_DAT15_RD; + case 0x0250: return CNREG2_0250_HSH_IVW0; + case 0x0251: return CNREG2_0251_HSH_IVW1; + case 0x0252: return CNREG2_0252_HSH_IVW2; + case 0x0253: return CNREG2_0253_HSH_IVW3; + case 0x0254: return CNREG2_0254_HSH_IVW4; + case 0x0255: return CNREG2_0255_HSH_IVW5; + case 0x0256: return CNREG2_0256_HSH_IVW6; + case 0x0257: return CNREG2_0257_HSH_IVW7; + case 0x0258: return CNREG2_0258_GFM_MUL0; + case 0x0259: return CNREG2_0259_GFM_MUL1; + case 0x025a: return CNREG2_025A_GFM_RESINP0; + case 0x025b: return CNREG2_025B_GFM_RESINP1; + case 0x025c: return CNREG2_025C_GFM_XOR0; + case 0x025e: return CNREG2_025E_GFM_POLY; + case 0x02c0: return CNREG2_02C0_SHA3_XORDAT0; + case 0x02c1: return CNREG2_02C1_SHA3_XORDAT1; + case 0x02c2: return CNREG2_02C2_SHA3_XORDAT2; + case 0x02c3: return CNREG2_02C3_SHA3_XORDAT3; + case 0x02c4: return CNREG2_02C4_SHA3_XORDAT4; + case 0x02c5: return CNREG2_02C5_SHA3_XORDAT5; + case 0x02c6: return CNREG2_02C6_SHA3_XORDAT6; + case 0x02c7: return CNREG2_02C7_SHA3_XORDAT7; + case 0x02c8: return CNREG2_02C8_SHA3_XORDAT8; + case 0x02c9: return CNREG2_02C9_SHA3_XORDAT9; + case 0x02ca: return CNREG2_02CA_SHA3_XORDAT10; + case 0x02cb: return CNREG2_02CB_SHA3_XORDAT11; + case 0x02cc: return CNREG2_02CC_SHA3_XORDAT12; + case 0x02cd: return CNREG2_02CD_SHA3_XORDAT13; + case 0x02ce: return CNREG2_02CE_SHA3_XORDAT14; + case 0x02cf: return CNREG2_02CF_SHA3_XORDAT15; + case 0x02d0: return CNREG2_02D0_SHA3_XORDAT16; + case 0x02d1: return CNREG2_02D1_SHA3_XORDAT17; + case 0x0400: return CNREG2_0400_LLM_READ_ADDR0; + case 0x0401: return CNREG2_0401_LLM_WRITE_ADDR_INTERNAL0; + case 0x0402: return CNREG2_0402_LLM_DATA0; + case 0x0404: return CNREG2_0404_LLM_READ64_ADDR0; + case 0x0405: return CNREG2_0405_LLM_WRITE64_ADDR_INTERNAL0; + case 0x0408: return CNREG2_0408_LLM_READ_ADDR1; + case 0x0409: return CNREG2_0409_LLM_WRITE_ADDR_INTERNAL1; + case 0x040a: return CNREG2_040a_LLM_DATA1; + case 0x040c: return CNREG2_040c_LLM_READ64_ADDR1; + case 0x040d: return CNREG2_040d_LLM_WRITE64_ADDR_INTERNAL1; + case 0x1202: return CNREG2_1202_CRC_LEN; + case 0x1207: return CNREG2_1207_CRC_DWORD; + case 0x1208: return CNREG2_1208_CRC_VAR; + case 0x1217: return CNREG2_1217_CRC_DWORD_REFLECT; + case 0x1218: return CNREG2_1218_CRC_VAR_REFLECT; + case 0x3109: return CNREG2_3109_AES_ENC_CBC1; + case 0x310b: return CNREG2_310B_AES_ENC1; + case 0x310d: return CNREG2_310D_AES_DEC_CBC1; + case 0x310f: return CNREG2_310F_AES_DEC1; + case 0x3114: return CNREG2_3114_CAMELLIA_ROUND; + case 0x3119: return CNREG2_3119_SMS4_ENC_CBC1; + case 0x311b: return CNREG2_311B_SMS4_ENC1; + case 0x311d: return CNREG2_311D_SMS4_DEC_CBC1; + case 0x311f: return CNREG2_311F_SMS4_DEC1; + case 0x4052: return CNREG2_4052_SHA3_STARTOP; + case 0x4047: return CNREG2_4047_HSH_STARTMD5; + case 0x404d: return CNREG2_404D_SNOW3G_START; + case 0x4055: return CNREG2_4055_ZUC_START; + case 0x4056: return CNREG2_4056_ZUC_MORE; + case 0x405d: return CNREG2_405D_GFM_XORMUL1_REFLECT; + case 0x404e: return CNREG2_404E_SNOW3G_MORE; + case 0x404f: return CNREG2_404F_HSH_STARTSHA256; + case 0x4057: return CNREG2_4057_HSH_STARTSHA; + case 0x4088: return CNREG2_4088_3DES_ENC_CBC; + case 0x4089: return CNREG2_4089_KAS_ENC_CBC; + case 0x408a: return CNREG2_408A_3DES_ENC; + case 0x408b: return CNREG2_408B_KAS_ENC; + case 0x408c: return CNREG2_408C_3DES_DEC_CBC; + case 0x408e: return CNREG2_408E_3DES_DEC; + case 0x4200: return CNREG2_4200_CRC_POLYNOMIAL_WR; + case 0x4210: return CNREG2_4210_CRC_POLYNOMIAL_REFLECT; + case 0x424f: return CNREG2_424F_HSH_STARTSHA512; + case 0x425d: return CNREG2_425D_GFM_XORMUL1; + + default: return REG_ZERO; + } +} + +static ExprId MoveFromCoprocessor(unsigned cop, LowLevelILFunction& il, size_t loadSize, uint32_t outReg, uint32_t reg, uint64_t sel, uint32_t decomposeFlags) +{ + if (cop == 0) + { Reg copReg = GetCop0Register(reg, sel); - switch (copReg) { - case REG_ZERO: /* Unimplemented coprocessor register */ - break; - default: + if (copReg == REG_ZERO && IsCop0ImplementationDefined(reg, sel)) + { + if ((decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + copReg = GetCaviumCop0Register(reg, sel); + } + } + + if (copReg != REG_ZERO) + { + return il.Intrinsic( + {RegisterOrFlag::Register(outReg)}, + loadSize == 4 ? MIPS_INTRIN_MFC0 : MIPS_INTRIN_DMFC0, + {il.Register(loadSize, copReg)}); + + } + } + else if (cop == 2) + { + if ((decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + Reg cop2Reg = GetCaviumCop2Register(reg); + if (cop2Reg != REG_ZERO) + { return il.Intrinsic( - {RegisterOrFlag::Register(outReg)}, - loadSize == 4 ? MIPS_INTRIN_MFC0 : MIPS_INTRIN_DMFC0, - {il.Register(loadSize, copReg)}); + {RegisterOrFlag::Register(outReg)}, + loadSize == 4 ? MIPS_INTRIN_MFC2 : MIPS_INTRIN_DMFC2, + {il.Register(loadSize, cop2Reg)}); + } } } @@ -422,18 +723,39 @@ static ExprId MoveFromCoprocessor(unsigned cop, LowLevelILFunction& il, size_t l {il.Const(4, cop), il.Const(4, reg), il.Const(4, sel)}); } -static ExprId MoveToCoprocessor(unsigned cop, LowLevelILFunction& il, size_t storeSize, uint32_t reg, uint64_t sel, ExprId srcExpr) +static ExprId MoveToCoprocessor(unsigned cop, LowLevelILFunction& il, size_t storeSize, uint32_t reg, uint64_t sel, ExprId srcExpr, uint32_t decomposeFlags) { - if (cop == 0) { + if (cop == 0) + { Reg copReg = GetCop0Register(reg, sel); - switch (copReg) { - case REG_ZERO: /* Unimplemented coprocessor register */ - break; - default: + if (copReg == REG_ZERO && IsCop0ImplementationDefined(reg, sel)) + { + if ((decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + copReg = GetCaviumCop0Register(reg, sel); + } + } + + if (copReg != REG_ZERO) + { + return il.Intrinsic( + {}, + storeSize == 4 ? MIPS_INTRIN_MTC0 : MIPS_INTRIN_DMTC0, + {il.Register(storeSize, copReg), srcExpr}); + } + } + else if (cop == 2) + { + if ((decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + Reg cop2Reg = GetCaviumCop2Register(reg); + if (cop2Reg != REG_ZERO) + { return il.Intrinsic( {}, - storeSize == 4 ? MIPS_INTRIN_MTC0 : MIPS_INTRIN_DMTC0, - {il.Register(storeSize, copReg), srcExpr}); + storeSize == 4 ? MIPS_INTRIN_MTC2 : MIPS_INTRIN_DMTC2, + {il.Register(storeSize, cop2Reg), srcExpr}); + } } } @@ -443,7 +765,24 @@ static ExprId MoveToCoprocessor(unsigned cop, LowLevelILFunction& il, size_t sto {il.Const(4, cop), il.Const(4, reg), il.Const(4, sel), srcExpr}); } -bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize) +static ExprId SimpleIntrinsic(LowLevelILFunction& il, MipsIntrinsic intrinsic) +{ + return il.Intrinsic({}, intrinsic, {}); +} + +// returns 256-bit value of [0:64] || [regHi] || [regMid] || [regLo] +static ExprId Concat3to256(LowLevelILFunction& il, uint32_t regHi, uint32_t regMid, uint32_t regLo) +{ + return il.Or(0x20, + il.ShiftLeft(0x20, il.ZeroExtend(0x20, il.Register(8, regHi)), il.Const(4, 0x80)), + il.Or(0x20, + il.ShiftLeft(0x20, il.ZeroExtend(0x20, il.Register(8, regMid)), il.Const(4, 0x40)), + il.ZeroExtend(0x20, il.Register(8, regLo)) + ) + ); +} + +bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags) { LowLevelILLabel trueLabel, falseLabel, doneLabel, dirFlagSet, dirFlagClear, dirFlagDone; InstructionOperand& op1 = instr.operands[0]; @@ -452,6 +791,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu InstructionOperand& op4 = instr.operands[3]; LowLevelILLabel trueCode, falseCode, again; size_t registerSize = addrSize; + BNEndianness endian = arch->GetEndianness(); switch (instr.operation) { case MIPS_ADD: @@ -487,15 +827,22 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ReadILOperand(il, instr, 2, registerSize, 4), ReadILOperand(il, instr, 3, registerSize, 4)))); break; + case MIPS_DSUB: + case MIPS_DSUBU: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.Sub(8, + ReadILOperand(il, instr, 2, registerSize, 8), + ReadILOperand(il, instr, 3, registerSize, 8)))); + break; case MIPS_AND: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(4, + il.And(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; case MIPS_ANDI: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(4, + il.And(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))))); break; @@ -519,6 +866,26 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ReadILOperand(il, instr, 1, registerSize, 4), ReadILOperand(il, instr, 2, registerSize, 4)))); break; + case MIPS_DDIV: + il.AddInstruction(il.SetRegister(8, REG_LO, + il.DivSigned(8, + ReadILOperand(il, instr, 1, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize, 8)))); + il.AddInstruction(il.SetRegister(8, REG_HI, + il.ModSigned(8, + ReadILOperand(il, instr, 1, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize, 8)))); + break; + case MIPS_DDIVU: + il.AddInstruction(il.SetRegister(8, REG_LO, + il.DivUnsigned(8, + ReadILOperand(il, instr, 1, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize, 8)))); + il.AddInstruction(il.SetRegister(8, REG_HI, + il.ModUnsigned(8, + ReadILOperand(il, instr, 1, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize, 8)))); + break; case MIPS_MUL: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.Mult(4, @@ -526,15 +893,15 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ReadILOperand(il, instr, 3, registerSize, 4)))); break; case MIPS_XOR: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Xor(4, + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Xor(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; case MIPS_XORI: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Xor(4, - ReadILOperand(il, instr, 2, registerSize, 4), + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Xor(registerSize, + ReadILOperand(il, instr, 2, registerSize), il.Operand(1,il.Const(4, 0x0000ffff & op3.immediate))))); break; case MIPS_B: @@ -546,7 +913,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu if (op1.immediate == (addr + 8)) // Get PC construct il.AddInstruction(il.SetRegister(addrSize, REG_RA, il.ConstPointer(addrSize ,addr + 8))); else - il.AddInstruction(il.Call(il.ConstPointer(4, op1.immediate))); + il.AddInstruction(il.Call(il.ConstPointer(addrSize, op1.immediate))); break; case MIPS_BEQ: @@ -561,6 +928,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_BGTZ: case MIPS_BLEZ: case MIPS_BLTZ: + case MIPS_BNEZ: case MIPS_BGEZL: //Branch likely case MIPS_BGTZL: case MIPS_BLEZL: @@ -617,13 +985,35 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.Goto(again)); il.MarkLabel(falseCode); break; - case MIPS_CLZ: + case MIPS_DCLO: //count leading ones //algorithm is as follows // //tmp0 = 0; //again: - //if (((op2 << tmp) & 0x80000000) != 0) + //if (((op2 << tmp) & 0x80000000_00000000) != 0) + //{ + // tmp0 += 1; + // goto again; + //} + // + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); + il.MarkLabel(again); + il.AddInstruction(il.If(il.CompareNotEqual(8, + il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize, 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), + il.Const(8,0)), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); + il.AddInstruction(il.Goto(again)); + il.MarkLabel(falseCode); + break; + case MIPS_CLZ: + //count leading zeroes + //algorithm is as follows + // + //tmp0 = 0; + //again: + //if (((op2 << tmp) & 0x80000000) == 0) //{ // tmp0 += 1; // goto again; @@ -639,6 +1029,28 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.Goto(again)); il.MarkLabel(falseCode); break; + case MIPS_DCLZ: + //count leading zeroes + //algorithm is as follows + // + //tmp0 = 0; + //again: + //if (((op2 << tmp) & 0x80000000_00000000) == 0) + //{ + // tmp0 += 1; + // goto again; + //} + // + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); + il.MarkLabel(again); + il.AddInstruction(il.If(il.CompareEqual(8, + il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize, 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), + il.Const(8,0)), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); + il.AddInstruction(il.Goto(again)); + il.MarkLabel(falseCode); + break; case MIPS_JALR: case MIPS_JALR_HB: { @@ -680,28 +1092,34 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(registerSize, REG_LO, ReadILOperand(il, instr, 1, registerSize))); break; case MIPS_DMFC0: - il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate)); + il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); break; case MIPS_MFC0: - il.AddInstruction(MoveFromCoprocessor(0, il, 4, op1.reg, op2.immediate, op3.immediate)); + il.AddInstruction(MoveFromCoprocessor(0, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); break; case MIPS_MFC1: - il.AddInstruction(MoveFromCoprocessor(1, il, 4, op1.reg, op2.immediate, op3.immediate)); + il.AddInstruction(MoveFromCoprocessor(1, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); + break; + case MIPS_DMFC2: + il.AddInstruction(MoveFromCoprocessor(2, il, 8, op1.reg, op2.immediate, 0, decomposeFlags)); break; case MIPS_MFC2: - il.AddInstruction(MoveFromCoprocessor(2, il, 4, op1.reg, op2.immediate, op3.immediate)); + il.AddInstruction(MoveFromCoprocessor(2, il, 4, op1.reg, op2.immediate, 0, decomposeFlags)); break; case MIPS_DMTC0: - il.AddInstruction(MoveToCoprocessor(0, il, 8, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(MoveToCoprocessor(0, il, 8, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); break; case MIPS_MTC0: - il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); break; case MIPS_MTC1: - il.AddInstruction(MoveToCoprocessor(1, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(MoveToCoprocessor(1, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + break; + case MIPS_DMTC2: + il.AddInstruction(MoveToCoprocessor(2, il, 8, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); break; case MIPS_MTC2: - il.AddInstruction(MoveToCoprocessor(2, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(MoveToCoprocessor(2, il, 4, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); break; case MIPS_MOVE: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); @@ -746,63 +1164,165 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_MULTU: il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecUnsigned(8, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); break; + case MIPS_DMULT: + il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecSigned(16, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); + break; + case MIPS_DMULTU: + il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecUnsigned(16, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); + break; case MIPS_NEG: case MIPS_NEGU: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.Neg(4, ReadILOperand(il, instr, 2, registerSize)))); break; case MIPS_NOT: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Not(4, ReadILOperand(il, instr, 2, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Not(registerSize, ReadILOperand(il, instr, 2, registerSize)))); break; case MIPS_NOR: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Not(4, il.Or(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Not(registerSize, il.Or(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); break; case MIPS_OR: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Or(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Or(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; case MIPS_ORI: if (op2.reg == REG_ZERO) - il.AddInstruction(il.SetRegister(4, op1.reg, il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))); + il.AddInstruction(il.SetRegister(registerSize, op1.reg, il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))); else - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Or(4, + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, + il.Or(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))))); break; case MIPS_RDHWR: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.Unimplemented())); + { + MipsIntrinsic intrinsic; + switch (op2.immediate) + { + case 0: intrinsic = MIPS_INTRIN_HWR0; break; + case 1: intrinsic = MIPS_INTRIN_HWR1; break; + case 2: intrinsic = MIPS_INTRIN_HWR2; break; + case 3: intrinsic = MIPS_INTRIN_HWR3; break; + default: intrinsic = MIPS_INTRIN_HWR_UNKNOWN; + } + + if (intrinsic != MIPS_INTRIN_HWR_UNKNOWN) + { + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, intrinsic, {}) + ); + } + else + { + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_HWR_UNKNOWN, {il.Const(1, op2.immediate)}) + ); + } break; + } case MIPS_SW: il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); break; + case MIPS_SWL: + { + int32_t delta = endian == LittleEndian ? -3 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART32, { ReadILOperand(il, instr, 1, registerSize, 4) })); + il.AddInstruction(il.Store(4, + GetILOperandMemoryAddress(il, op2, addrSize, delta), + il.Register(4, LLIL_TEMP(0)) + )); + + break; + } + + case MIPS_SDL: + { + int32_t delta = endian == LittleEndian ? -7 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART64, { ReadILOperand(il, instr, 1, registerSize, 8) })); + il.AddInstruction(il.Store(8, + GetILOperandMemoryAddress(il, op2, addrSize, delta), + il.Register(8, LLIL_TEMP(0)) + )); + + break; + } + case MIPS_SWR: + { + int32_t delta = endian == BigEndian ? -3 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART32, { ReadILOperand(il, instr, 1, registerSize, 4) })); + il.AddInstruction(il.Store(4, + GetILOperandMemoryAddress(il, op2, addrSize, delta), + il.Register(4, LLIL_TEMP(0)) + )); + + break; + } + + case MIPS_SDR: + { + int32_t delta = endian == BigEndian ? -7 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART64, { ReadILOperand(il, instr, 1, registerSize, 8) })); + il.AddInstruction(il.Store(8, + GetILOperandMemoryAddress(il, op2, addrSize, delta), + il.Register(8, LLIL_TEMP(0)) + )); + + break; + } + + case MIPS_SC: + { + LowLevelILLabel trueCode, falseCode, doneCode; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {})); + il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)), + trueCode, falseCode)); + il.MarkLabel(trueCode); + + il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 1))); + il.AddInstruction(il.Goto(doneCode)); + + il.MarkLabel(falseCode); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0))); + + il.MarkLabel(doneCode); + break; + } case MIPS_SD: il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize))); break; + case MIPS_SCD: + { + LowLevelILLabel trueCode, falseCode, doneCode; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {})); + il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)), + trueCode, falseCode)); + il.MarkLabel(trueCode); + + il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 1))); + il.AddInstruction(il.Goto(doneCode)); + + il.MarkLabel(falseCode); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0))); + + il.MarkLabel(doneCode); + break; + } case MIPS_SWC1: - il.AddInstruction(MoveFromCoprocessor(1, il, 4, LLIL_TEMP(0), op1.immediate, 0)); + il.AddInstruction(MoveFromCoprocessor(1, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(4, LLIL_TEMP(0)))); break; case MIPS_SWC2: - il.AddInstruction(MoveFromCoprocessor(2, il, 4, LLIL_TEMP(0), op1.immediate, 0)); + il.AddInstruction(MoveFromCoprocessor(2, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(4, LLIL_TEMP(0)))); break; case MIPS_SWC3: - il.AddInstruction(MoveFromCoprocessor(3, il, 4, LLIL_TEMP(0), op1.immediate, 0)); + il.AddInstruction(MoveFromCoprocessor(3, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(4, LLIL_TEMP(0)))); break; - case MIPS_SWL: - il.AddInstruction(il.Store(2, - GetILOperandMemoryAddress(il, op2, addrSize), - il.LogicalShiftRight(4, ReadILOperand(il, instr, 1, registerSize, 4), il.Const(1, 16)))); - break; - case MIPS_SWR: - il.AddInstruction(il.Store(2, - il.Sub(4, GetILOperandMemoryAddress(il, op2, addrSize), il.Const(4, 1)), - il.And(4, ReadILOperand(il, instr, 1, registerSize, 4), il.Const(4, 0xffff)))); - break; case MIPS_SYSCALL: il.AddInstruction(il.SystemCall()); break; @@ -810,19 +1330,61 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu //op1 = op4.imm bits in op2.reg at bit offset op3.imm il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.And(registerSize, - il.Const(registerSize, (1<<op4.immediate)-1), - il.ShiftLeft(registerSize, ReadILOperand(il, instr, 2, registerSize), - il.Const(1, op3.immediate))))); + il.LogicalShiftRight(registerSize, + ReadILOperand(il, instr, 2, registerSize), + il.Const(1, op3.immediate) + ), + il.Const(registerSize, (1<<op4.immediate)-1) + ))); + break; + case MIPS_DEXT: + case MIPS_DEXTM: + case MIPS_DEXTU: + //op1 = op4.imm bits in op2.reg at bit offset op3.imm + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.And(8, + il.LogicalShiftRight(8, + ReadILOperand(il, instr, 2, registerSize), + il.Const(1, op3.immediate) + ), + il.Const(8, (((uint64_t)1)<<op4.immediate)-1) + ))); break; case MIPS_INS: + // recall: pos = op3, size = op4 il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Or(registerSize, il.And(registerSize, - il.Const(registerSize, ((1<<op4.immediate)-1)<<op3.immediate), - ReadILOperand(il, instr, 1, registerSize)), - il.And(registerSize, - il.Const(registerSize, (1<<op4.immediate)-1), - ReadILOperand(il, instr, 2, registerSize))))); + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, ~(((1<<op4.immediate)-1)<<op3.immediate)) + ), + il.ShiftLeft(registerSize, + il.And(registerSize, + ReadILOperand(il, instr, 2, registerSize), + il.Const(registerSize, (1<<op4.immediate)-1) + ), + il.Const(registerSize, op3.immediate) + ) + ))); + break; + case MIPS_DINS: + case MIPS_DINSM: + case MIPS_DINSU: + // recall: pos = op3, size = op4 + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.Or(8, + il.And(8, + ReadILOperand(il, instr, 1, registerSize), + il.Const(registerSize, ~(((((uint64_t)1)<<op4.immediate)-1)<<op3.immediate)) + ), + il.ShiftLeft(8, + il.And(8, + ReadILOperand(il, instr, 2, registerSize), + il.Const(8, (((uint64_t)1)<<op4.immediate)-1) + ), + il.Const(8, op3.immediate) + ) + ))); break; case MIPS_LUI: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.Const(4, op2.immediate << 16))); @@ -830,16 +1392,72 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_LI: case MIPS_LW: case MIPS_LWX: - case MIPS_LL: // TODO: Atomic access primitives il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize, 4))); break; + case MIPS_LWU: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ZeroExtend(8, ReadILOperand(il, instr, 2, registerSize, 4)))); + break; case MIPS_LD: il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); break; + case MIPS_LWL: + { + int32_t delta = endian == LittleEndian ? -3 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART32, + { + il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta)) + } + )); + + break; + } + case MIPS_LDL: + { + int32_t delta = endian == LittleEndian ? -7 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART64, + { + il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta)) + } + )); + + break; + } + case MIPS_LWR: + { + int32_t delta = endian == BigEndian ? -3 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART32, + { + il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta)) + } + )); + + break; + } + case MIPS_LDR: + { + int32_t delta = endian == BigEndian ? -7 : 0; + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART64, + { + il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta)) + } + )); + + break; + } + case MIPS_LL: + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize, 4))); + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)})); + break; + case MIPS_LLD: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)})); + break; case MIPS_SRA: - case MIPS_SRAV: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; + case MIPS_SRAV: + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f))))); + break; case MIPS_SLT: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, il.CompareSignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); @@ -857,25 +1475,73 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.CompareUnsignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); break; case MIPS_SLL: + // SLL is unique in that the input doesn't have to be sign extended, and the + // preferred way to sign extend the lower 32 bits of an register is to shift + // it left by 0 + if (registerSize == 8 && op2.reg != 0 && op3.immediate == 0) + { + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, 8))))); + + } + else + { + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); + } + break; case MIPS_SLLV: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f))))); break; case MIPS_DSLL: case MIPS_DSLL32: - if (registerSize != 8) { + if (registerSize != 8) + { il.AddInstruction(il.Unimplemented()); break; } il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; + case MIPS_DSLLV: + if (registerSize != 8) + { + il.AddInstruction(il.Undefined()); + break; + } + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f))))); + break; case MIPS_DSRL: case MIPS_DSRL32: - if (registerSize != 8) { + if (registerSize != 8) + { il.AddInstruction(il.Unimplemented()); break; } il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; + case MIPS_DSRLV: + if (registerSize != 8) + { + il.AddInstruction(il.Undefined()); + break; + } + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f))))); + break; + case MIPS_DSRA: + case MIPS_DSRA32: + if (registerSize != 8) + { + il.AddInstruction(il.Unimplemented()); + break; + } + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); + break; + case MIPS_DSRAV: + if (registerSize != 8) + { + il.AddInstruction(il.Undefined()); + break; + } + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f))))); + break; case MIPS_SB: il.AddInstruction(il.Store(1, GetILOperandMemoryAddress(il, op2, addrSize), il.LowPart(1, ReadILOperand(il, instr, 1, registerSize)))); break; @@ -912,85 +1578,74 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(4, ReadILOperand(il, instr, 2, registerSize, 2)))); break; case MIPS_LHU: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ZeroExtend(4, ReadILOperand(il, instr, 2, registerSize, 2)))); - break; - case MIPS_LWR: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.And(4, - il.Const(4, 0xffff0000), - il.Register(4, op1.reg)))); - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Or(4, - ReadILOperand(il, instr, 2, registerSize, 2), - il.Register(4, op1.reg)))); - break; - case MIPS_LWL: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.And(4, - il.Const(4, 0xffff), - il.Register(4, op1.reg)))); - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Or(4, - il.ShiftLeft(4, - ReadILOperand(il, instr, 2, registerSize, 2), - il.Const(1, 16)), - il.Register(4, op1.reg)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.ZeroExtend(4, ReadILOperand(il, instr, 2, registerSize, 2)))); break; case MIPS_MADD: - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), - il.MultDoublePrecSigned(8, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - il.AddInstruction(il.SetRegister(4, REG_LO, - il.Add(4, - il.Register(4, REG_LO), - il.LowPart(4, il.Register(8, LLIL_TEMP(0)))))); - il.AddInstruction(il.SetRegister(4, REG_HI, - il.Add(4, - il.Register(4, REG_HI), - il.LogicalShiftRight(4, - il.Register(8, LLIL_TEMP(0)), - il.Const(1, 16))))); + il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + il.Add(8, + il.RegisterSplit(4, REG_HI, REG_LO), + il.MultDoublePrecSigned(4, + ReadILOperand(il, instr, 1, registerSize, 4), + ReadILOperand(il, instr, 2, registerSize, 4) + ) + ) + )); + + if (registerSize == 8) + { + il.AddInstruction(il.SetRegister(8, REG_HI, + il.SignExtend(8, il.LowPart(4, il.Register(registerSize, REG_HI))) + )); + + il.AddInstruction(il.SetRegister(8, REG_LO, + il.SignExtend(8, il.LowPart(4, il.Register(registerSize, REG_LO))) + )); + } break; case MIPS_MADDU: - il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), - il.MultDoublePrecUnsigned(8, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - il.AddInstruction(il.SetRegister(4, REG_LO, - il.Add(4, - il.Register(4, REG_LO), - il.LowPart(4, il.Register(8, LLIL_TEMP(0)))))); - il.AddInstruction(il.SetRegister(4, REG_HI, - il.Add(4, - il.Register(4, REG_HI), - il.LogicalShiftRight(4, - il.Register(8, LLIL_TEMP(0)), - il.Const(1, 16))))); + il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + il.Add(8, + il.RegisterSplit(4, REG_HI, REG_LO), + il.MultDoublePrecUnsigned(4, + ReadILOperand(il, instr, 1, registerSize, 4), + ReadILOperand(il, instr, 2, registerSize, 4) + ) + ) + )); + + if (registerSize == 8) + { + il.AddInstruction(il.SetRegister(8, REG_HI, + il.SignExtend(8, il.LowPart(4, il.Register(registerSize, REG_HI))) + )); + + il.AddInstruction(il.SetRegister(8, REG_LO, + il.SignExtend(8, il.LowPart(4, il.Register(registerSize, REG_LO))) + )); + } break; case MIPS_ROTR: case MIPS_ROTRV: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.RotateRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; - case MIPS_SC: - il.AddInstruction(il.UnimplementedMemoryRef(4, ReadILOperand(il, instr, 2, registerSize))); - break; case MIPS_SDBBP: il.AddInstruction(il.Unimplemented()); break; case MIPS_SEB: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(4, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize))))); break; case MIPS_SEH: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(4, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize))))); break; case MIPS_SH: il.AddInstruction(il.Store(2, GetILOperandMemoryAddress(il, op2, addrSize), il.LowPart(2, ReadILOperand(il, instr, 1, registerSize)))); break; case MIPS_SRL: - case MIPS_SRLV: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); break; + case MIPS_SRLV: + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f))))); + break; case MIPS_SSNOP: case MIPS_NOP: il.AddInstruction(il.Nop()); @@ -998,6 +1653,12 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_WSBH: il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_WSBH, {ReadILOperand(il, instr, 2, registerSize)})); break; + case MIPS_DSBH: + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSBH, {ReadILOperand(il, instr, 2, registerSize)})); + break; + case MIPS_DSHD: + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSHD, {ReadILOperand(il, instr, 2, registerSize)})); + break; case MIPS_BGEZALL: case MIPS_BLTZALL: break; @@ -1166,35 +1827,315 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1))))); } break; + + case MIPS_SYNC: + { + uint64_t stype = 0; + if (op1.operandClass != NONE) + { + stype = op1.immediate; + } + + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_SYNC, {il.Const(1, stype)})); + break; + } + + case MIPS_DI: + il.AddInstruction(SimpleIntrinsic(il, MIPS_INTRIN_DI)); + break; + + case MIPS_EHB: + il.AddInstruction(SimpleIntrinsic(il, MIPS_INTRIN_EHB)); + break; + + case MIPS_EI: + il.AddInstruction(SimpleIntrinsic(il, MIPS_INTRIN_EI)); + break; + + case MIPS_WAIT: + il.AddInstruction(SimpleIntrinsic(il, MIPS_INTRIN_WAIT)); + break; + + case MIPS_PREF: + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_PREFETCH, {il.Const(1, op1.immediate), GetILOperandMemoryAddress(il, op2, addrSize)})); + break; + + case MIPS_CACHE: + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_CACHE, {il.Const(1, op1.immediate), GetILOperandMemoryAddress(il, op2, addrSize)})); + break; + + case CNMIPS_BADDU: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.ZeroExtend(registerSize, + il.Add(1, + il.LowPart(1, ReadILOperand(il, instr, 2, registerSize, 8)), + il.LowPart(1, ReadILOperand(il, instr, 3, registerSize, 8)) + ) + ) + )); + break; + + case CNMIPS_BBIT0: + case CNMIPS_BBIT032: + case CNMIPS_BBIT1: + case CNMIPS_BBIT132: + ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op3.immediate, addr + 8); + break; + + case CNMIPS_CINS: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.ShiftLeft(8, + il.And(8, + ReadILOperand(il, instr, 2, registerSize), + il.Const(8, (((uint64_t)1) << (op4.immediate + 1)) - 1)), + il.Const(8, op3.immediate) + ) + )); + break; + + case CNMIPS_CINS32: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.ShiftLeft(8, + il.And(8, + ReadILOperand(il, instr, 2, registerSize), + il.Const(8, (((uint64_t)1) << (op4.immediate + 1)) - 1)), + il.Const(8, op3.immediate + 32) + ) + )); + break; + + case CNMIPS_DMUL: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.Mult(8, + ReadILOperand(il, instr, 2, registerSize, 8), + ReadILOperand(il, instr, 3, registerSize, 8)))); + break; + + case CNMIPS_EXTS: + // recall: p = op3.immediate, lenm1 = op4.immediate + if (op3.immediate == 0 && op4.immediate == 7) + { + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.SignExtend(8, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize, registerSize))) + )); + } + else if (op3.immediate == 0 && op4.immediate == 0xf) + { + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.SignExtend(8, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize, registerSize))) + )); + } + else if (op3.immediate == 0 && op4.immediate == 0x1f) + { + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, registerSize, registerSize))) + )); + } + else + { + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.ArithShiftRight(8, + il.ShiftLeft(8, + ReadILOperand(il, instr, 2, registerSize, 8), + il.Const(8, 63 - (op3.immediate + op4.immediate)) + ), + il.Const(8, 63 - op4.immediate) + ) + )); + } + break; + + case CNMIPS_EXTS32: + // recall: p = op3.immediate, lenm1 = op4.immediate + if (op3.immediate + op4.immediate + 32 > 63) + { + il.AddInstruction(il.Undefined()); + } + else + { + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.ArithShiftRight(8, + il.ShiftLeft(8, + ReadILOperand(il, instr, 2, registerSize, 8), + il.Const(8, 63 - (32 + op3.immediate + op4.immediate)) + ), + il.Const(8, 63 - op4.immediate) + ) + )); + } + break; + + case CNMIPS_POP: + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_POP, {ReadILOperand(il, instr, 2, registerSize)})); + break; + case CNMIPS_DPOP: + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_DPOP, {ReadILOperand(il, instr, 2, registerSize)})); + break; + case CNMIPS_MTM0: + il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL0, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_MTM1: + il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL1, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_MTM2: + il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL2, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_MTP0: + il.AddInstruction(il.SetRegister(registerSize, CNREG_P0, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_MTP1: + il.AddInstruction(il.SetRegister(registerSize, CNREG_P1, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_MTP2: + il.AddInstruction(il.SetRegister(registerSize, CNREG_P2, ReadILOperand(il, instr, 1, registerSize))); + break; + case CNMIPS_RDHWR: + { + MipsIntrinsic intrinsic; + switch (op2.immediate) + { + case 30: intrinsic = CNMIPS_INTRIN_HWR30; break; + case 31: intrinsic = CNMIPS_INTRIN_HWR31; break; + default: intrinsic = MIPS_INTRIN_HWR_UNKNOWN; + } + + if (intrinsic != MIPS_INTRIN_HWR_UNKNOWN) + { + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, intrinsic, {}) + ); + } + else + { + il.AddInstruction( + il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_HWR_UNKNOWN, {il.Const(1, op2.immediate)}) + ); + } + break; + } + case CNMIPS_SAA: + il.AddInstruction( + il.Store(4, + GetILOperandMemoryAddress(il, op2, addrSize), + il.Add(4, + il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize)), + ReadILOperand(il, instr, 1, registerSize, 4) + ) + ) + ); + break; + + case CNMIPS_SAAD: + il.AddInstruction( + il.Store(8, + GetILOperandMemoryAddress(il, op2, addrSize), + il.Add(8, + il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize)), + ReadILOperand(il, instr, 1, registerSize, 8) + ) + ) + ); + break; + + case CNMIPS_SEQ: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, + il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + break; + + case CNMIPS_SEQI: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, + il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate))))); + break; + + case CNMIPS_SNE: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, + il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + break; + + case CNMIPS_SNEI: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, + il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate))))); + break; + + case CNMIPS_SYNCIOBDMA: + il.AddInstruction(SimpleIntrinsic(il, CNMIPS_INTRIN_SYNCIOBDMA)); + break; + + case CNMIPS_SYNCS: + il.AddInstruction(SimpleIntrinsic(il, CNMIPS_INTRIN_SYNCS)); + break; + + case CNMIPS_SYNCW: + il.AddInstruction(SimpleIntrinsic(il, CNMIPS_INTRIN_SYNCW)); + break; + + case CNMIPS_SYNCWS: + il.AddInstruction(SimpleIntrinsic(il, CNMIPS_INTRIN_SYNCWS)); + break; + + case CNMIPS_V3MULU: + // description of this behemoth of an instruction: + // + // ([0:64] || P2 || P1 || P0) + // + ([0:192] || rt) + // + (rs x (MPL2 || MPL1 || MPL0)) + // ------------------------------ + // (P2 || P1 || P0 || rd) + // + // register splits IL operations work with 2 registers, and + // considering Px registers as subregisters of a massive + // product register would also introduce complications (for example, + // note that P0 is in bits 63..0 in the first summand, but then + // occupies bits 127..64 of the total sum), so the simplest way forward + // seems to be to do shifts... + il.AddInstruction(il.SetRegister(0x20, LLIL_TEMP(0), + il.Add(0x20, + // [0:64] || P2 || P1 || P0 + Concat3to256(il, CNREG_P2, CNREG_P1, CNREG_P0), + il.Add(0x20, + // [0:192] || rt + il.ZeroExtend(0x20, ReadILOperand(il, instr, 3, 8)), + + // rs x (MPL2 || MPL1 || MPL0) + il.Mult(0x20, + il.ZeroExtend(0x20, ReadILOperand(il, instr, 2, 8)), + Concat3to256(il, CNREG_MPL2, CNREG_MPL1, CNREG_MPL0) + ) + ) + ) + )); + + il.AddInstruction(il.SetRegister(8, CNREG_P2, + il.LowPart(8, il.LogicalShiftRight(0x20, il.Register(0x20, LLIL_TEMP(0)), il.Const(4, 0xc0))) + )); + + il.AddInstruction(il.SetRegister(8, CNREG_P1, + il.LowPart(8, il.LogicalShiftRight(0x20, il.Register(0x20, LLIL_TEMP(0)), il.Const(4, 0x80))) + )); + + il.AddInstruction(il.SetRegister(8, CNREG_P0, + il.LowPart(8, il.LogicalShiftRight(0x20, il.Register(0x20, LLIL_TEMP(0)), il.Const(4, 0x40))) + )); + + il.AddInstruction(SetRegisterOrNop(il, 8, 8, op1.reg, il.LowPart(8, il.Register(0x20, LLIL_TEMP(0))))); + + break; + case MIPS_ADDR: - case MIPS_DSLLV: - case MIPS_DSRA32: - case MIPS_DSRA: - case MIPS_DSRAV: - case MIPS_DSLV: - case MIPS_DSUB: - case MIPS_DSUBU: - case MIPS_LDL: - case MIPS_LDR: case MIPS_LDXC1: - case MIPS_LLD: case MIPS_LLO: case MIPS_LUXC1: case MIPS_LWC1: case MIPS_LWC2: case MIPS_LWC3: - case MIPS_LWU: case MIPS_LWXC1: case MIPS_MFHC1: case MIPS_MFHC2: case MIPS_MOVT: case MIPS_MULR: - case MIPS_SCD: case MIPS_SDC1: case MIPS_SDC2: case MIPS_SDC3: - case MIPS_SDL: - case MIPS_SDR: case MIPS_SDXC1: case MIPS_LDC1: case MIPS_LDC2: @@ -1215,25 +2156,17 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_CTC1: case MIPS_CTC2: case MIPS_DERET: - case MIPS_DI: - case MIPS_DMULT: - case MIPS_DMULTU: case MIPS_DRET: - case MIPS_EHB: - case MIPS_EI: case MIPS_JALX: //Special instruction for switching to MIPS32/microMIPS32/MIPS16e case MIPS_MTHC1: case MIPS_MTHC2: case MIPS_PAUSE: - case MIPS_PREF: case MIPS_PREFX: - case MIPS_SYNC: case MIPS_SYNCI: case MIPS_TLBP: case MIPS_TLBR: case MIPS_TLBWI: case MIPS_TLBWR: - case MIPS_WAIT: case MIPS_WRPGPR: case MIPS_RDPGPR: case MIPS_RECIP1: diff --git a/arch/mips/il.h b/arch/mips/il.h index 5c03f82b..abb3d939 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -7,14 +7,69 @@ enum MipsIntrinsic : uint32_t { MIPS_INTRIN_WSBH, + MIPS_INTRIN_DSBH, + MIPS_INTRIN_DSHD, MIPS_INTRIN_MFC0, + MIPS_INTRIN_MFC2, MIPS_INTRIN_MFC_UNIMPLEMENTED, MIPS_INTRIN_MTC0, + MIPS_INTRIN_MTC2, MIPS_INTRIN_MTC_UNIMPLEMENTED, MIPS_INTRIN_DMFC0, + MIPS_INTRIN_DMFC2, MIPS_INTRIN_DMFC_UNIMPLEMENTED, MIPS_INTRIN_DMTC0, + MIPS_INTRIN_DMTC2, MIPS_INTRIN_DMTC_UNIMPLEMENTED, + MIPS_INTRIN_SYNC, + MIPS_INTRIN_DI, + MIPS_INTRIN_EHB, + MIPS_INTRIN_EI, + MIPS_INTRIN_WAIT, + MIPS_INTRIN_HWR0, + MIPS_INTRIN_HWR1, + MIPS_INTRIN_HWR2, + MIPS_INTRIN_HWR3, + MIPS_INTRIN_HWR29, + MIPS_INTRIN_HWR_UNKNOWN, + MIPS_INTRIN_LLBIT_SET, + MIPS_INTRIN_LLBIT_CHECK, + MIPS_INTRIN_PREFETCH, + MIPS_INTRIN_CACHE, + + // there's no clean way to lift LWL/LWR, SWL/SWR, etc when not + // a pair of adjacent instructions, since the number and position + // of the bytes written to/read from depends on the alignment of + // the address + // + // consider writing a register to an unaligned address with + // SWL rX, 0(rY)/SWR rX, 3(rY); this could write either 1, 2, 3, + // or 4 bytes in each instruction, and then later in the function + // to load the value of rX back, the number of bytes read by + // LWL rX, 0(rY)/LWR rX, 3(rY) is again variable...the number of + // bytes, shifts, and bitmasks all depend on (rY & 3) + // + // lifting these instructions faithfully, even when the analysis + // engine is able to follow this, would be a total mess to read, + // so it might as well be an intrinsic-like black box anyways, to + // help data cross-references work + MIPS_INTRIN_GET_LEFT_PART32, + MIPS_INTRIN_GET_RIGHT_PART32, + MIPS_INTRIN_SET_LEFT_PART32, + MIPS_INTRIN_SET_RIGHT_PART32, + MIPS_INTRIN_GET_LEFT_PART64, + MIPS_INTRIN_GET_RIGHT_PART64, + MIPS_INTRIN_SET_LEFT_PART64, + MIPS_INTRIN_SET_RIGHT_PART64, + + CNMIPS_INTRIN_SYNCIOBDMA, + CNMIPS_INTRIN_SYNCS, + CNMIPS_INTRIN_SYNCW, + CNMIPS_INTRIN_SYNCWS, + CNMIPS_INTRIN_HWR30, + CNMIPS_INTRIN_HWR31, + CNMIPS_INTRIN_POP, + CNMIPS_INTRIN_DPOP, MIPS_INTRIN_INVALID=0xFFFFFFFF, }; @@ -23,6 +78,7 @@ bool GetLowLevelILForInstruction( uint64_t addr, BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, - size_t addrSize); + size_t addrSize, + uint32_t decomposeFlags); BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t registerSize); diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index 42bb0311..a108c8f3 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -54,153 +54,171 @@ using namespace mips; } while (0); +static Operation cavium_mips_base_table[8][8] = { + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_JALX, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, + {MIPS_LL, MIPS_LWC1, CNMIPS_BBIT0, MIPS_PREF, MIPS_LLD, MIPS_LDC1, CNMIPS_BBIT032, MIPS_LD}, + {MIPS_SC, MIPS_SWC1, CNMIPS_BBIT1, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, CNMIPS_BBIT132, MIPS_SD} +}; + //Fields are: [Version][opcode_high][opcode_low] static Operation mips_base_table[6][8][8] = { { //MIPS version 1 - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP3}, - {MIPS_LLO, MIPS_LHI, MIPS_TRAP}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_INVALID, MIPS_INVALID, MIPS_SWR}, - {MIPS_INVALID, MIPS_LWC1, MIPS_LWC2, MIPS_LWC3}, - {MIPS_INVALID, MIPS_SWC1, MIPS_SWC2, MIPS_SWC3} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP3, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LLO, MIPS_LHI, MIPS_TRAP, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_INVALID}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_INVALID, MIPS_INVALID, MIPS_SWR, MIPS_INVALID}, + {MIPS_INVALID, MIPS_LWC1, MIPS_LWC2, MIPS_LWC3, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_SWC1, MIPS_SWC2, MIPS_SWC3, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID} },{ //MIPS version 2 - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP3, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, - {MIPS_INVALID}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_INVALID, MIPS_INVALID, MIPS_SWR}, - {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_LWC3, MIPS_INVALID, MIPS_LDC1, MIPS_LDC2, MIPS_LDC3}, - {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_SWC3, MIPS_INVALID, MIPS_SDC1, MIPS_SDC2, MIPS_SDC3} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP3, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_INVALID}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_INVALID, MIPS_INVALID, MIPS_SWR, MIPS_INVALID}, + {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_LWC3, MIPS_INVALID, MIPS_LDC1, MIPS_LDC2, MIPS_LDC3}, + {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_SWC3, MIPS_INVALID, MIPS_SDC1, MIPS_SDC2, MIPS_SDC3} },{ //MIPS version 3 - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_INVALID, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, - {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR}, - {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_INVALID, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, - {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_INVALID, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_INVALID}, + {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_INVALID, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, + {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} },{ //MIPS version 4 - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, - {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR}, - {MIPS_INVALID, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, - {MIPS_INVALID, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_INVALID}, + {MIPS_INVALID, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, + {MIPS_INVALID, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} },{ //MIPS version 5 (MIPS32) - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, - {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_JALX, MIPS_INVALID, MIPS_INVALID}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, - {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, - {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_JALX, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, + {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, + {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} },{ //MIPS version 6 (MIPS64) - {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, - {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, - {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, - {MIPS_DADDI, MIPS_DADDIU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_JALX, MIPS_INVALID, MIPS_INVALID}, - {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, - {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, - {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, - {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_JALX, MIPS_INVALID, MIPS_INVALID}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, + {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, + {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} } }; //Fields are: [Version][function_high][function_low] static Operation mips_special_table[6][8][8] = { { //MIPS version 1 - {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU} + {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID} },{ //MIPS version 2 - {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU}, - {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE} + {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID} },{ //MIPS version 3 - {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSLV, MIPS_DSRAV}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, - {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE}, - {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} + {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} },{ //MIPS version 4 - {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSLV, MIPS_DSRAV}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, - {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE}, - {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} + {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} },{ //MIPS version 5 - {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, - {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE}, - {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} + {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} },{ //MIPS version 6 - {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, - {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, - {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO}, - {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU}, - {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, - {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, - {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE}, - {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} + {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_DMULT, MIPS_DMULTU, MIPS_DDIV, MIPS_DDIVU}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} } }; static Operation mips_regimm_table[6][4][8] = { { //MIPS version 1 - {MIPS_BLTZ, MIPS_BGEZ}, - {MIPS_INVALID}, - {MIPS_BLTZAL, MIPS_BGEZAL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, },{ //MIPS version 2 - {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL}, - {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI}, - {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, },{ //MIPS version 3 - {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL}, - {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI}, - {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, },{ //MIPS version 4 - {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL}, - {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI}, - {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, },{ //MIPS version 5 - {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL}, - {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI}, - {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SYNCI} },{ //MIPS version 6 - {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL}, - {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI}, - {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL}, + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SYNCI} } }; -static Operation mips_special2_table[8][8] = { - {MIPS_MADD, MIPS_MADDU, MIPS_MUL, MIPS_INVALID, MIPS_MSUB, MIPS_MSUBU}, +static Operation mips32_special2_table[8][8] = { + {MIPS_MADD, MIPS_MADDU, MIPS_MUL, MIPS_INVALID, MIPS_MSUB, MIPS_MSUBU, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, @@ -210,7 +228,29 @@ static Operation mips_special2_table[8][8] = { {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SDBBP} }; -static Operation mips_special3_table[8][8] = { +static Operation mips64_special2_table[8][8] = { + {MIPS_MADD, MIPS_MADDU, MIPS_MUL, MIPS_INVALID, MIPS_MSUB, MIPS_MSUBU, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_CLZ, MIPS_CLO, MIPS_INVALID, MIPS_INVALID, MIPS_DCLZ, MIPS_DCLO, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SDBBP} +}; + +static Operation cavium_mips64_special2_table[8][8] = { + {MIPS_MADD, MIPS_MADDU, MIPS_MUL, CNMIPS_DMUL, MIPS_MSUB, MIPS_MSUBU, MIPS_INVALID, MIPS_INVALID}, + {CNMIPS_MTM0, CNMIPS_MTP0, CNMIPS_MTP1, CNMIPS_MTP2, CNMIPS_MTM1, CNMIPS_MTM2, MIPS_INVALID, CNMIPS_VMULU}, + {CNMIPS_VMM0, CNMIPS_V3MULU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {CNMIPS_SAA, CNMIPS_SAAD, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, CNMIPS_CVM}, + {MIPS_CLZ, MIPS_CLO, MIPS_INVALID, MIPS_INVALID, MIPS_DCLZ, MIPS_DCLO, MIPS_INVALID, MIPS_INVALID}, + {CNMIPS_BADDU, MIPS_INVALID, CNMIPS_SEQ, CNMIPS_SNE, CNMIPS_POP, CNMIPS_DPOP, CNMIPS_SEQI, CNMIPS_SNEI}, + {MIPS_INVALID, MIPS_INVALID, CNMIPS_CINS, CNMIPS_CINS32, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, CNMIPS_EXTS, CNMIPS_EXTS32, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SDBBP} +}; + +static Operation mips32_special3_table[8][8] = { {MIPS_EXT, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INS, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_LX, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, @@ -221,6 +261,17 @@ static Operation mips_special3_table[8][8] = { {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_RDHWR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, }; +static Operation mips64_special3_table[8][8] = { + {MIPS_EXT, MIPS_DEXTM, MIPS_DEXTU, MIPS_DEXT, MIPS_INS, MIPS_DINSM, MIPS_DINSU, MIPS_DINS}, + {MIPS_INVALID, MIPS_INVALID, MIPS_LX, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_BSHFL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_DBSHFL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_RDHWR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, +}; + static Operation mips_v5_cop1_S_table[8][8] = { {MIPS_ADD_S, MIPS_SUB_S, MIPS_MUL_S, MIPS_DIV_S, MIPS_SQRT_S, MIPS_ABS_S, MIPS_MOV_S, MIPS_NEG_S}, {MIPS_ROUND_L_S, MIPS_TRUNC_L_S, MIPS_CEIL_L_S, MIPS_FLOOR_L_S, MIPS_ROUND_W_S, MIPS_TRUNC_W_S, MIPS_CEIL_W_S, MIPS_FLOOR_W_S}, @@ -326,6 +377,7 @@ static const char* const OperationStrings[] = { "bltzl", "bne", "bnel", + "bnez", "bnz.b", "bnz.d", "bnz.h", @@ -446,10 +498,19 @@ static const char* const OperationStrings[] = { "daddi", "daddiu", "daddu", + "dbshfl", + "dclo", + "dclz", "ddiv", "ddivu", "deret", + "dext", + "dextm", + "dextu", "di", + "dins", + "dinsm", + "dinsu", "div.d", "div.ps", "div.s", @@ -464,15 +525,20 @@ static const char* const OperationStrings[] = { "dmtc1", "dmtc2", "dret", + "drotr", + "drotr32", + "drotrv", + "dsbh", + "dshd", "dsll", "dsll32", "dsllv", - "dslv", "dsra", "dsra32", "dsrav", "dsrl", "dsrl32", + "dsrlv", "dsub", "dsubu", "ehb", @@ -699,6 +765,44 @@ static const char* const OperationStrings[] = { "wsbh", "xor", "xori", + + // cavium instructions + "baddu", + "bbit0", + "bbit032", + "bbit1", + "bbit132", + "cins", + "cins32", + "cvm", + "dmul", + "dpop", + "exts", + "exts32", + "mtm0", + "mtm1", + "mtm2", + "mtp0", + "mtp1", + "mtp2", + "pop", + "rdhwr", + "saa", + "saad", + "seq", + "seqi", + "sne", + "snei", + "synciobdma", + "syncs", + "syncw", + "syncws", + "v3mulu", + "vmm0", + "vmulu", + "zcb", + "zcbt", + }; static const char * const RegisterStrings[] = { @@ -870,6 +974,183 @@ static const char * const RegisterStrings[] = { "cop0_DataHi", "cop0_ErrorEPC", "cop0_DESAVE", + + // cavium-specific multiplication registers + "cvm_mpl0", + "cvm_mpl1", + "cvm_mpl2", + "cvm_p0", + "cvm_p1", + "cvm_p2", + + // cavium-specific implementation defined + "cop0_CvmCount", + "cop0_CvmCtl", + "cop0_PowerThrottle", + "cop0_CvmMemCtl", + "cop0_MulticoreDbg", + + "CVMX_HSH_DAT0", + "CVMX_HSH_DAT1", + "CVMX_HSH_DAT2", + "CVMX_HSH_DAT3", + "CVMX_HSH_DAT4", + "CVMX_HSH_DAT5", + "CVMX_HSH_DAT6", + "CVMX_HSH_IV0", + "CVMX_HSH_IV1", + "CVMX_HSH_IV2", + "CVMX_HSH_IV3", + "CVMX_SHA3_DAT24", + "CVMX_SHA3_DAT15_RD", + "CVMX_GFM_MUL_REFLECT0", + "CVMX_GFM_MUL_REFLECT1", + "CVMX_GFM_RESINP_REFLECT0", + "CVMX_GFM_RESINP_REFLECT1", + "CVMX_GFM_XOR0_REFLECT", + + "CVMX_3DES/KASUMI_KEY0", + "CVMX_3DES/KASUMI_KEY1", + "CVMX_3DES/KASUMI_KEY2", + "CVMX_3DES_IV", + "CVMX_3DES_RESULT_RD", + "CVMX_3DES_RESULT_WR", + + "CVMX_AES/SMS4_RESULT0", + "CVMX_AES/SMS4_RESULT1", + "CVMX_AES/SMS4_IV0", + "CVMX_AES/SMS4_IV1", + "CVMX_AES/SMS4_KEY0", + "CVMX_AES/SMS4_KEY1", + "CVMX_AES/SMS4_KEY2", + "CVMX_AES/SMS4_KEY3", + + "CVMX_AES/SMS4_ENC_CBC0", + "CVMX_AES/SMS4_ENC0", + "CVMX_AES/SMS4_DEC_CBC0", + "CVMX_AES/SMS4_DEC0", + + "CVMX_AES_KEYLENGTH", + "CVMX_AES_DAT0", + + "CVMX_CAMELLIA_FL", + "CVMX_CAMELLIA_FLINV", + + "CVMX_CRC_POLYNOMIAL", + "CVMX_CRC_IV", + "CVMX_CRC_LEN", + "CVMX_CRC_IV_REFLECT_RD", + "CVMX_CRC_BYTE", + "CVMX_CRC_HALF", + "CVMX_CRC_WORD", + "CVMX_CRC_IV_REFLECT_WR", + "CVMX_CRC_BYTE_REFLECT", + "CVMX_CRC_HALF_REFLECT", + "CVMX_CRC_WORD_REFLECT", + + "CVMX_HSH_DATW0", + "CVMX_HSH_DATW1", + "CVMX_HSH_DATW2", + "CVMX_HSH_DATW3", + "CVMX_HSH_DATW4", + "CVMX_HSH_DATW5", + "CVMX_HSH_DATW6", + "CVMX_HSH_DATW7", + "CVMX_HSH_DATW8", + "CVMX_HSH_DATW9", + "CVMX_HSH_DATW10", + "CVMX_HSH_DATW11", + "CVMX_HSH_DATW12", + "CVMX_HSH_DATW13", + "CVMX_HSH_DATW14", + + "CVMX_SHA3_DAT15_RD", + + "CVMX_HSH_IVW0", + "CVMX_HSH_IVW1", + "CVMX_HSH_IVW2", + "CVMX_HSH_IVW3", + "CVMX_HSH_IVW4", + "CVMX_HSH_IVW5", + "CVMX_HSH_IVW6", + "CVMX_HSH_IVW7", + + "CVMX_GFM_MUL0", + "CVMX_GFM_MUL1", + "CVMX_GFM_RESINP0", + "CVMX_GFM_RESINP1", + "CVMX_GFM_XOR0", + "CVMX_GFM_POLY", + + "CVMX_SHA3_XORDAT0", + "CVMX_SHA3_XORDAT1", + "CVMX_SHA3_XORDAT2", + "CVMX_SHA3_XORDAT3", + "CVMX_SHA3_XORDAT4", + "CVMX_SHA3_XORDAT5", + "CVMX_SHA3_XORDAT6", + "CVMX_SHA3_XORDAT7", + "CVMX_SHA3_XORDAT8", + "CVMX_SHA3_XORDAT9", + "CVMX_SHA3_XORDAT10", + "CVMX_SHA3_XORDAT11", + "CVMX_SHA3_XORDAT12", + "CVMX_SHA3_XORDAT13", + "CVMX_SHA3_XORDAT14", + "CVMX_SHA3_XORDAT15", + "CVMX_SHA3_XORDAT16", + "CVMX_SHA3_XORDAT17", + + "CVMX_LLM_READ_ADDR0", + "CVMX_LLM_WRITE_ADDR_INTERNAL0", + "CVMX_LLM_DATA0", + "CVMX_LLM_READ64_ADDR0", + "CVMX_LLM_WRITE64_ADDR_INTERNAL0", + "CVMX_LLM_READ_ADDR1", + "CVMX_LLM_WRITE_ADDR_INTERNAL1", + "CVMX_LLM_DATA1", + "CVMX_LLM_READ64_ADDR1", + "CVMX_LLM_WRITE64_ADDR_INTERNAL1", + + "CVMX_CRC_LEN", + "CVMX_CRC_DWORD", + "CVMX_CRC_VAR", + "CVMX_CRC_DWORD_REFLECT", + "CVMX_CRC_VAR_REFLECT", + + "CVMX_AES_ENC_CBC1", + "CVMX_AES_ENC1", + "CVMX_AES_DEC_CBC1", + "CVMX_AES_DEC1", + + "CVMX_CAMELLIA_ROUND", + + "CVMX_SMS4_ENC_CBC1", + "CVMX_SMS4_ENC1", + "CVMX_SMS4_DEC_CBC1", + "CVMX_SMS4_DEC1", + + "CVMX_SHA3_STARTOP", + "CVMX_HSH_STARTMD5", + "CVMX_SNOW3G_START", + "CVMX_ZUC_START", + "CVMX_ZUC_MORE", + "CVMX_GFM_XORMUL1_REFLECT", + "CVMX_SNOW3G_MORE", + "CVMX_HSH_STARTSHA256", + "CVMX_HSH_STARTSHA", + "CVMX_3DES_ENC_CBC", + "CVMX_KAS_ENC_CBC", + "CVMX_3DES_ENC", + "CVMX_KAS_ENC", + "CVMX_3DES_DEC_CBC", + "CVMX_3DES_DEC", + + "CVMX_CRC_POLYNOMIAL_WR", + "CVMX_CRC_POLYNOMIAL_REFLECT", + + "CVMX_HSH_STARTSHA512", + "CVMX_GFM_XORMUL1", }; static const char * const FlagStrings[] = { @@ -959,7 +1240,8 @@ uint32_t mips_decompose_instruction( combined ins, Instruction* restrict instruction, uint32_t version, - uint64_t address) + uint64_t address, + uint32_t flags) { uint64_t registerMask; @@ -986,14 +1268,40 @@ uint32_t mips_decompose_instruction( break; case 0x1c: if (version == MIPS_32) - instruction->operation = mips_special2_table[ins.decode.func_hi][ins.decode.func_lo]; + instruction->operation = mips32_special2_table[ins.decode.func_hi][ins.decode.func_lo]; + else if (version == MIPS_64) + { + if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0) + instruction->operation = mips64_special2_table[ins.decode.func_hi][ins.decode.func_lo]; + else + { + instruction->operation = cavium_mips64_special2_table[ins.decode.func_hi][ins.decode.func_lo]; + if (instruction->operation == CNMIPS_CVM) + { + switch (ins.r.sa) + { + // note that CN50xx docs don't include these instructions, but they are + // listed in the SDK (bootloader/u-boot/mips/include/asm/inst.h) + case 0x1c: instruction->operation = CNMIPS_ZCB; break; + case 0x1d: instruction->operation = CNMIPS_ZCBT; break; + default: return 1; + } + } + } + + } break; case 0x1f: if (version == MIPS_32) - instruction->operation = mips_special3_table[ins.decode.func_hi][ins.decode.func_lo]; + instruction->operation = mips32_special3_table[ins.decode.func_hi][ins.decode.func_lo]; + else if (version == MIPS_64) + instruction->operation = mips64_special3_table[ins.decode.func_hi][ins.decode.func_lo]; break; default: - instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo]; + if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0) + instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo]; + else + instruction->operation = cavium_mips_base_table[ins.decode.op_hi][ins.decode.op_lo]; } //Now deal with aliases and stage 2 decoding @@ -1029,14 +1337,35 @@ uint32_t mips_decompose_instruction( return 1; } break; + case MIPS_DBSHFL: + switch (ins.r.sa) + { + case 0x02: instruction->operation = MIPS_DSBH; break; + case 0x05: instruction->operation = MIPS_DSHD; break; + default: + return 1; + } + break; case MIPS_SRL: if (ins.bits.bit21 == 1) instruction->operation = MIPS_ROTR; break; + case MIPS_DSRL: + if (ins.bits.bit21 == 1) + instruction->operation = MIPS_DROTR; + break; + case MIPS_DSRL32: + if (ins.bits.bit21 == 1) + instruction->operation = MIPS_DROTR32; + break; case MIPS_SRLV: if (ins.bits.bit6 == 1) instruction->operation = MIPS_ROTRV; break; + case MIPS_DSRLV: + if (ins.bits.bit6 == 1) + instruction->operation = MIPS_DROTRV; + break; case MIPS_COP0: switch (ins.r.rs) { @@ -1289,9 +1618,36 @@ uint32_t mips_decompose_instruction( instruction->operation = MIPS_BEQZ; } break; + case MIPS_BNE: + if (ins.r.rt == 0) + instruction->operation = MIPS_BNEZ; + + break; case MIPS_BGEZAL: if (ins.r.rs == 0) instruction->operation = MIPS_BAL; + case MIPS_SYNC: + if ((flags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + switch (ins.r.sa) + { + case 2: instruction->operation = CNMIPS_SYNCIOBDMA; break; + case 4: instruction->operation = CNMIPS_SYNCW; break; + case 5: instruction->operation = CNMIPS_SYNCWS; break; + case 6: instruction->operation = CNMIPS_SYNCS; break; + } + } + break; + case MIPS_RDHWR: + if ((flags & DECOMPOSE_FLAGS_CAVIUM) != 0) + { + switch (ins.r.rd) + { + case 30: instruction->operation = CNMIPS_RDHWR; break; + case 31: instruction->operation = CNMIPS_RDHWR; break; + } + } + break; default: break; } @@ -1355,7 +1711,7 @@ uint32_t mips_decompose_instruction( break; case MIPS_J: case MIPS_JAL: - INS_1(LABEL, (address & 0xf0000000) + (((uint32_t)ins.j.immediate)<<2)) + INS_1(LABEL, (address & 0xfffffffff0000000) + (((uint32_t)ins.j.immediate)<<2)) break; case MIPS_JR: INS_1(REG, ins.r.rs) @@ -1406,10 +1762,12 @@ uint32_t mips_decompose_instruction( case MIPS_CLZ: case MIPS_NOT: case MIPS_MOVE: + case MIPS_DCLO: + case MIPS_DCLZ: INS_2(REG, ins.r.rd, REG, ins.r.rs) break; case MIPS_RDHWR: - INS_2(REG, ins.r.rt, REG, (CPREG_0 + ins.r.rd)); + INS_2(REG, ins.r.rt, IMM, ins.r.rd); break; case MIPS_TRUNC_W_S: case MIPS_TRUNC_W_D: @@ -1479,6 +1837,7 @@ uint32_t mips_decompose_instruction( case MIPS_BLTZALL: case MIPS_BLTZL: case MIPS_BEQZ: + case MIPS_BNEZ: INS_2(REG, ins.i.rs, LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask) break; case MIPS_BGTZ: @@ -1543,6 +1902,8 @@ uint32_t mips_decompose_instruction( case MIPS_NEG: case MIPS_NEGU: case MIPS_BITSWAP: + case MIPS_DSBH: + case MIPS_DSHD: INS_2(REG, ins.r.rd, REG, ins.r.rt) break; case MIPS_CFC0: @@ -1827,6 +2188,8 @@ uint32_t mips_decompose_instruction( INS_3(REG, ins.i.rs, REG, ins.i.rt, LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask) break; case MIPS_ROTR: + case MIPS_DROTR: + case MIPS_DROTR32: INS_3(REG, ins.r.rd, REG, ins.r.rt, IMM, ins.r.sa) if (ins.r.rs != 1) return 1; @@ -1849,6 +2212,7 @@ uint32_t mips_decompose_instruction( return 1; break; case MIPS_ROTRV: + case MIPS_DROTRV: INS_3(REG, ins.r.rd, REG, ins.r.rt, REG, ins.r.rs) if (ins.r.sa != 1) return 1; @@ -1856,7 +2220,7 @@ uint32_t mips_decompose_instruction( case MIPS_SRLV: case MIPS_DSLLV: case MIPS_DSRAV: - case MIPS_DSLV: + case MIPS_DSRLV: case MIPS_SLLV: case MIPS_SRAV: INS_3(REG, ins.r.rd, REG, ins.r.rt, REG, ins.r.rs) @@ -1887,14 +2251,101 @@ uint32_t mips_decompose_instruction( REG, ins.f.ft + FPREG_F0); break; case MIPS_INS: + case MIPS_DINS: INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa, IMM, ((int32_t)ins.r.rd + 1) - ins.r.sa); break; + case MIPS_DINSM: + INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa, IMM, ((int32_t)ins.r.rd + 33) - ins.r.sa); + break; + case MIPS_DINSU: + INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa + 32, IMM, ((int32_t)ins.r.rd + 1) - ins.r.sa); + break; case MIPS_EXT: + case MIPS_DEXT: INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa, IMM, ins.r.rd + 1); break; + case MIPS_DEXTM: + INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa, IMM, ins.r.rd + 33); + break; + case MIPS_DEXTU: + INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa + 32, IMM, ins.r.rd + 1); + break; case MIPS_ALIGN: INS_4(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt, IMM, (ins.r.sa & 3)); break; + + case CNMIPS_BADDU: + case CNMIPS_DMUL: + case CNMIPS_SEQ: + case CNMIPS_SNE: + case CNMIPS_V3MULU: + case CNMIPS_VMM0: + case CNMIPS_VMULU: + INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt) + if (ins.r.sa != 0) + return 1; + break; + case CNMIPS_BBIT0: + case CNMIPS_BBIT032: + case CNMIPS_BBIT1: + case CNMIPS_BBIT132: + INS_3(REG, ins.i.rs, IMM, ins.i.rt, LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask) + break; + case CNMIPS_CINS: + case CNMIPS_CINS32: + case CNMIPS_EXTS: + case CNMIPS_EXTS32: + INS_4(REG, ins.r.rt, REG, ins.r.rs, IMM, ins.r.sa, IMM, ins.r.rd) + break; + case CNMIPS_MTM0: + case CNMIPS_MTM1: + case CNMIPS_MTM2: + case CNMIPS_MTP0: + case CNMIPS_MTP1: + case CNMIPS_MTP2: + INS_1(REG, ins.r.rs) + break; + case CNMIPS_SAA: + case CNMIPS_SAAD: + instruction->operands[0].operandClass = REG; + instruction->operands[1].operandClass = MEM_IMM; + instruction->operands[0].reg = ins.i.rt; + instruction->operands[1].reg = ins.i.rs; + instruction->operands[1].immediate = 0; + break; + case CNMIPS_SEQI: + case CNMIPS_SNEI: + { + uint32_t uimm = ins.decode.group1; + + uint32_t mask = 1u << (10 - 1); + int32_t simm = (uimm ^ mask) - mask; + + INS_3(REG, ins.r.rt, REG, ins.r.rs, IMM, simm) + break; + } + case CNMIPS_DPOP: + case CNMIPS_POP: + INS_2(REG, ins.r.rd, REG, ins.r.rs); + break; + + case CNMIPS_RDHWR: + INS_2(REG, ins.r.rt, IMM, ins.r.rd); + break; + + case CNMIPS_SYNCIOBDMA: + case CNMIPS_SYNCS: + case CNMIPS_SYNCW: + case CNMIPS_SYNCWS: + break; + + case CNMIPS_ZCB: + case CNMIPS_ZCBT: + instruction->operands[0].operandClass = MEM_IMM; + instruction->operands[0].reg = ins.i.rs; + instruction->operands[0].immediate = 0; + break; + default: return 1; } @@ -1976,6 +2427,7 @@ uint32_t mips_disassemble( } +// flags: see DECOMPOSE_FLAGS_* uint32_t mips_decompose( const uint32_t* instructionValue, size_t size, @@ -1983,7 +2435,7 @@ uint32_t mips_decompose( uint32_t version, uint64_t address, uint32_t endianBig, - uint32_t enablePseudoOps) + uint32_t flags) { combined ins; if (instructionValue == NULL) @@ -1994,12 +2446,12 @@ uint32_t mips_decompose( else ins.value = instructionValue[0]; - uint32_t result = mips_decompose_instruction(ins, instruction, version, address); + uint32_t result = mips_decompose_instruction(ins, instruction, version, address, flags); if (result != 0) return result; instruction->size = 4; //look for peudoinstructions by disassembling the next instruction too - if (enablePseudoOps != 0 && size >= 8) + if ((flags & DECOMPOSE_FLAGS_PSEUDO_OP != 0) && size >= 8) { if (endianBig == 1) ins.value = bswap32(instructionValue[1]); @@ -2008,7 +2460,7 @@ uint32_t mips_decompose( Instruction instruction2; if (instruction->operation == MIPS_LUI) { - result = mips_decompose_instruction(ins, &instruction2, version, address+4); + result = mips_decompose_instruction(ins, &instruction2, version, address+4, flags); if (result != 0) { return result; diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 14c5f2d8..48b68712 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -30,6 +30,9 @@ namespace mips { #endif + static const uint32_t DECOMPOSE_FLAGS_PSEUDO_OP = 0x1; + static const uint32_t DECOMPOSE_FLAGS_CAVIUM = 0x2; + enum Operation { MIPS_INVALID, MIPS_ABS_D, @@ -82,6 +85,7 @@ namespace mips MIPS_BLTZL, MIPS_BNE, MIPS_BNEL, + MIPS_BNEZ, MIPS_BNZ_B, MIPS_BNZ_D, MIPS_BNZ_H, @@ -202,10 +206,19 @@ namespace mips MIPS_DADDI, MIPS_DADDIU, MIPS_DADDU, + MIPS_DBSHFL, + MIPS_DCLO, + MIPS_DCLZ, MIPS_DDIV, MIPS_DDIVU, MIPS_DERET, + MIPS_DEXT, + MIPS_DEXTM, + MIPS_DEXTU, MIPS_DI, + MIPS_DINS, + MIPS_DINSM, + MIPS_DINSU, MIPS_DIV_D, MIPS_DIV_PS, MIPS_DIV_S, @@ -220,15 +233,20 @@ namespace mips MIPS_DMTC1, MIPS_DMTC2, MIPS_DRET, + MIPS_DROTR, + MIPS_DROTR32, + MIPS_DROTRV, + MIPS_DSBH, + MIPS_DSHD, MIPS_DSLL, MIPS_DSLL32, MIPS_DSLLV, - MIPS_DSLV, MIPS_DSRA, MIPS_DSRA32, MIPS_DSRAV, MIPS_DSRL, MIPS_DSRL32, + MIPS_DSRLV, MIPS_DSUB, MIPS_DSUBU, MIPS_EHB, @@ -455,6 +473,44 @@ namespace mips MIPS_WSBH, MIPS_XOR, MIPS_XORI, + + // cavium instructions + CNMIPS_BADDU, + CNMIPS_BBIT0, + CNMIPS_BBIT032, + CNMIPS_BBIT1, + CNMIPS_BBIT132, + CNMIPS_CINS, + CNMIPS_CINS32, + CNMIPS_CVM, + CNMIPS_DMUL, + CNMIPS_DPOP, + CNMIPS_EXTS, + CNMIPS_EXTS32, + CNMIPS_MTM0, + CNMIPS_MTM1, + CNMIPS_MTM2, + CNMIPS_MTP0, + CNMIPS_MTP1, + CNMIPS_MTP2, + CNMIPS_POP, + CNMIPS_RDHWR, + CNMIPS_SAA, + CNMIPS_SAAD, + CNMIPS_SEQ, + CNMIPS_SEQI, + CNMIPS_SNE, + CNMIPS_SNEI, + CNMIPS_SYNCIOBDMA, + CNMIPS_SYNCS, + CNMIPS_SYNCW, + CNMIPS_SYNCWS, + CNMIPS_V3MULU, + CNMIPS_VMM0, + CNMIPS_VMULU, + CNMIPS_ZCB, + CNMIPS_ZCBT, + MIPS_OPERATION_END }; @@ -667,6 +723,197 @@ namespace mips // Coprocessor 0 register 31 REG_DESAVE, // 0 + // cavium multiplication registers + CNREG_MPL0, + CNREG_MPL1, + CNREG_MPL2, + CNREG_P0, + CNREG_P1, + CNREG_P2, + + // cavium cop0 registers: see `COP0_xx` macros in cvmx-asm.h in SDK + CNREG0_CVM_COUNT, // implementation-defined 9, 6 + CNREG0_CVM_CTL, // implementation-defined 9, 7 + CNREG0_POWTHROTTLE, // implementation-defined 11, 6 + CNREG0_CVM_MEM_CTL, // implementation-defined 11, 7 + CNREG0_MULTICORE_DBG, // implementation-defined 22, 0 + + // cavium cop2 registers + CNREG2_0040_HSH_DAT0, + CNREG2_0041_HSH_DAT1, + CNREG2_0042_HSH_DAT2, + CNREG2_0043_HSH_DAT3, + CNREG2_0044_HSH_DAT4, + CNREG2_0045_HSH_DAT5, + CNREG2_0046_HSH_DAT6, + + CNREG2_0048_HSH_IV0, + CNREG2_0049_HSH_IV1, + CNREG2_004A_HSH_IV2, + CNREG2_004B_HSH_IV3, + + CNREG2_0050_SHA3_DAT24, + CNREG2_0051_SHA3_DAT15_RD, + + CNREG2_0058_GFM_MUL_REFLECT0, + CNREG2_0059_GFM_MUL_REFLECT1, + CNREG2_005A_GFM_RESINP_REFLECT0, + CNREG2_005B_GFM_RESINP_REFLECT1, + CNREG2_005C_GFM_XOR0_REFLECT, + + // also KASUMI + CNREG2_0080_3DES_KEY0, + CNREG2_0081_3DES_KEY1, + CNREG2_0082_3DES_KEY2, + + CNREG2_0084_3DES_IV, + CNREG2_0088_3DES_RESULT_RD, + CNREG2_0098_3DES_RESULT_WR, + + // also SMS4 RESINP + CNREG2_0100_AES_RESULT0, + CNREG2_0101_AES_RESULT1, + + // also SMS4 IV + CNREG2_0102_AES_IV0, + CNREG2_0103_AES_IV1, + + // also SMS4 KEY + CNREG2_0104_AES_KEY0, + CNREG2_0105_AES_KEY1, + CNREG2_0106_AES_KEY2, + CNREG2_0107_AES_KEY3, + + // also SMS4_x + CNREG2_0108_AES_ENC_CBC0, + CNREG2_010A_AES_ENC0, + CNREG2_010C_AES_DEC_CBC0, + CNREG2_010E_AES_DEC0, + + CNREG2_0110_AES_KEYLENGTH, + CNREG2_0111_AES_DAT0, + + CNREG2_0115_CAMELLIA_FL, + CNREG2_0116_CAMELLIA_FLINV, + + CNREG2_0200_CRC_POLYNOMIAL, + CNREG2_0201_CRC_IV, + CNREG2_0202_CRC_LEN, + CNREG2_0203_CRC_IV_REFLECT_RD, + CNREG2_0204_CRC_BYTE, + CNREG2_0205_CRC_HALF, + CNREG2_0206_CRC_WORD, + CNREG2_0211_CRC_IV_REFLECT_WR, + CNREG2_0214_CRC_BYTE_REFLECT, + CNREG2_0215_CRC_HALF_REFLECT, + CNREG2_0216_CRC_WORD_REFLECT, + + // also SNOW3G_LFSR, SHA3DAT0..=14 + CNREG2_0240_HSH_DATW0, + CNREG2_0241_HSH_DATW1, + CNREG2_0242_HSH_DATW2, + CNREG2_0243_HSH_DATW3, + CNREG2_0244_HSH_DATW4, + CNREG2_0245_HSH_DATW5, + CNREG2_0246_HSH_DATW6, + CNREG2_0247_HSH_DATW7, + CNREG2_0248_HSH_DATW8, + CNREG2_0249_HSH_DATW9, + CNREG2_024A_HSH_DATW10, + CNREG2_024B_HSH_DATW11, + CNREG2_024C_HSH_DATW12, + CNREG2_024D_HSH_DATW13, + CNREG2_024E_HSH_DATW14, + + CNREG2_024F_SHA3_DAT15_RD, + + // also SNOW3G_RESULT (0x250), SNOW3G_SFM (0x251, 0x252, 0x253) + CNREG2_0250_HSH_IVW0, + CNREG2_0251_HSH_IVW1, + CNREG2_0252_HSH_IVW2, + CNREG2_0253_HSH_IVW3, + CNREG2_0254_HSH_IVW4, + CNREG2_0255_HSH_IVW5, + CNREG2_0256_HSH_IVW6, + CNREG2_0257_HSH_IVW7, + + CNREG2_0258_GFM_MUL0, + CNREG2_0259_GFM_MUL1, + CNREG2_025A_GFM_RESINP0, + CNREG2_025B_GFM_RESINP1, + CNREG2_025C_GFM_XOR0, + CNREG2_025E_GFM_POLY, + + CNREG2_02C0_SHA3_XORDAT0, + CNREG2_02C1_SHA3_XORDAT1, + CNREG2_02C2_SHA3_XORDAT2, + CNREG2_02C3_SHA3_XORDAT3, + CNREG2_02C4_SHA3_XORDAT4, + CNREG2_02C5_SHA3_XORDAT5, + CNREG2_02C6_SHA3_XORDAT6, + CNREG2_02C7_SHA3_XORDAT7, + CNREG2_02C8_SHA3_XORDAT8, + CNREG2_02C9_SHA3_XORDAT9, + CNREG2_02CA_SHA3_XORDAT10, + CNREG2_02CB_SHA3_XORDAT11, + CNREG2_02CC_SHA3_XORDAT12, + CNREG2_02CD_SHA3_XORDAT13, + CNREG2_02CE_SHA3_XORDAT14, + CNREG2_02CF_SHA3_XORDAT15, + CNREG2_02D0_SHA3_XORDAT16, + CNREG2_02D1_SHA3_XORDAT17, + + CNREG2_0400_LLM_READ_ADDR0, + CNREG2_0401_LLM_WRITE_ADDR_INTERNAL0, + CNREG2_0402_LLM_DATA0, + CNREG2_0404_LLM_READ64_ADDR0, + CNREG2_0405_LLM_WRITE64_ADDR_INTERNAL0, + CNREG2_0408_LLM_READ_ADDR1, + CNREG2_0409_LLM_WRITE_ADDR_INTERNAL1, + CNREG2_040a_LLM_DATA1, + CNREG2_040c_LLM_READ64_ADDR1, + CNREG2_040d_LLM_WRITE64_ADDR_INTERNAL1, + + CNREG2_1202_CRC_LEN, + CNREG2_1207_CRC_DWORD, + CNREG2_1208_CRC_VAR, + CNREG2_1217_CRC_DWORD_REFLECT, + CNREG2_1218_CRC_VAR_REFLECT, + + CNREG2_3109_AES_ENC_CBC1, + CNREG2_310B_AES_ENC1, + CNREG2_310D_AES_DEC_CBC1, + CNREG2_310F_AES_DEC1, + + CNREG2_3114_CAMELLIA_ROUND, + + CNREG2_3119_SMS4_ENC_CBC1, + CNREG2_311B_SMS4_ENC1, + CNREG2_311D_SMS4_DEC_CBC1, + CNREG2_311F_SMS4_DEC1, + + CNREG2_4052_SHA3_STARTOP, + CNREG2_4047_HSH_STARTMD5, + CNREG2_404D_SNOW3G_START, + CNREG2_4055_ZUC_START, + CNREG2_4056_ZUC_MORE, + CNREG2_405D_GFM_XORMUL1_REFLECT, + CNREG2_404E_SNOW3G_MORE, + CNREG2_404F_HSH_STARTSHA256, + CNREG2_4057_HSH_STARTSHA, + CNREG2_4088_3DES_ENC_CBC, + CNREG2_4089_KAS_ENC_CBC, + CNREG2_408A_3DES_ENC, + CNREG2_408B_KAS_ENC, + CNREG2_408C_3DES_DEC_CBC, + CNREG2_408E_3DES_DEC, + + CNREG2_4200_CRC_POLYNOMIAL_WR, + CNREG2_4210_CRC_POLYNOMIAL_REFLECT, + + CNREG2_424F_HSH_STARTSHA512, + CNREG2_425D_GFM_XORMUL1, + // Last valid register END_REG }; |
