Exemplo n.º 1
0
    def execute(self, simulatorContext):
        if not self._checkCondition(simulatorContext.regs):
            # Nothing to do, instruction not executed
            self.countExecConditionFalse += 1
            return
        self.countExec += 1

        if self.modeWrite:
            if self.usespsr and simulatorContext.regs.mode == "User":
                # Check if SPSR exists (we are not in user mode)
                raise ExecutionException(
                    "Erreur : écriture de SPSR en mode 'User' (ce mode ne possede pas de registre SPSR)"
                )
            if self.flagsOnly:
                if self.imm:
                    valToSet = self.val
                    if self.shift[2] != 0:
                        _unused, valToSet = utils.applyShift(
                            valToSet, self.shift, simulatorContext.regs.C)
                else:
                    valToSet = simulatorContext.regs[
                        self.
                        val] & 0xF0000000  # We only keep the condition flag bits
                if self.usespsr:
                    valToSet |= simulatorContext.regs.SPSR & 0x0FFFFFFF
                else:
                    valToSet |= simulatorContext.regs.CPSR & 0x0FFFFFFF
            else:
                valToSet = simulatorContext.regs[self.val]

            if (valToSet & 0x1F) not in simulatorContext.regs.bits2mode:
                raise ExecutionException(
                    "Erreur : les bits ({:05b}) du mode du {} ne correspondent à aucun mode valide!"
                    .format(valToSet & 0x1F,
                            "SPSR" if self.usespsr else "CPSR"))

            if self.usespsr:
                simulatorContext.regs.SPSR = valToSet
            else:
                if not simulatorContext.allowSwitchModeInUserMode and simulatorContext.regs.mode == "User" and simulatorContext.regs.CPSR & 0x1F != valToSet & 0x1F:
                    raise ExecutionException(
                        "Erreur : tentative de changer le mode du processeur à partir d'un mode non privilégié!"
                    )
                simulatorContext.regs.CPSR = valToSet
        else:  # Read
            if self.usespsr and simulatorContext.regs.mode == "User":
                # Check if SPSR exists (we are not in user mode)
                raise ExecutionException(
                    "Erreur : lecture de SPSR en mode 'User' (ce mode ne possede pas de registre SPSR)"
                )
            else:
                simulatorContext.regs[
                    self.
                    rd] = simulatorContext.regs.SPSR if self.usespsr else simulatorContext.regs.CPSR
Exemplo n.º 2
0
    def decode(self):
        instrInt = self.instrInt
        # This one is tricky
        # The signature looks like a data processing operation, BUT
        # it sets the "opcode" to an operation beginning with 10**,
        # and the only operations that match this are TST, TEQ, CMP and CMN
        # It is said that for these ops, the S flag MUST be set to 1
        # With MSR and MRS, the bit representing the S flag is always 0,
        # so we can differentiate these instructions...
        if not (utils.checkMask(instrInt, (19, 24), (27, 26, 23, 20))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()

        self.usespsr = bool(instrInt & (1 << 22))
        self.modeWrite = bool(instrInt & (1 << 21))
        self.flagsOnly = not bool(instrInt & (1 << 16))
        self.imm = bool(instrInt & (1 << 25))
        self.rd = (instrInt >> 12) & 0xF

        if self.imm and self.flagsOnly:  # Immediate mode is allowed only for flags-only mode
            self.val = instrInt & 0xFF
            self.shift = utils.shiftInfo(
                type="ROR", immediate=True, value=((instrInt >> 8) & 0xF) *
                2)  # see 4.5.3 of ARM doc to understand the * 2
        else:
            self.val = instrInt & 0xF
            self.shift = utils.shiftInfo(
                type="ROR", immediate=True, value=0
            )  # No rotate with registers for these particular instructions

        self.opcode = "MSR" if self.modeWrite else "MRS"
Exemplo n.º 3
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(self.instrInt, (26, 25), (4, 27))
                or utils.checkMask(self.instrInt, (26, ), (25, 27))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()

        # For LDR/STR, imm is 0 if offset IS an immediate value (4-26 datasheet)
        self.imm = not bool(instrInt & (1 << 25))
        self.pre = bool(instrInt & (1 << 24))
        self.sign = 1 if instrInt & (1 << 23) else -1
        self.byte = bool(instrInt & (1 << 22))
        # See 4.9.1 (with post, writeback is redundant and always on)
        self.writeback = bool(instrInt & (1 << 21)) or not self.pre
        # See same section, with post-inc, writeback is actually used to indicate an LDRT instruction
        self.nonprivileged = bool(instrInt & (1 << 21)) and not self.pre
        self.mode = "LDR" if instrInt & (1 << 20) else "STR"

        self.basereg = (instrInt >> 16) & 0xF
        self.rd = (instrInt >> 12) & 0xF
        if self.imm:
            self.offsetImm = instrInt & 0xFFF
        else:
            self.offsetReg = instrInt & 0xF
            # Cannot be a register shift
            self.offsetRegShift = utils.shiftInfo(
                type=utils.shiftMappingR[(instrInt >> 5) & 0x3],
                immediate=True,
                value=(instrInt >> 7) & 0x1F)
Exemplo n.º 4
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (27, 25), (26, ))
                or utils.checkMask(instrInt, (24, 21, 4) + tuple(range(8, 20)),
                                   (27, 26, 25, 23, 22, 20, 7, 6, 5))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide (1)",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()
        self.imm = (instrInt >> 25) & 1 != 0

        if self.imm:
            # B or BL
            self.imm = True
            self.link = bool(instrInt & (1 << 24))
            self.offsetImm = instrInt & 0xFFFFFF
            if self.offsetImm & 0x800000:  # Negative offset
                self.offsetImm = -2**24 + self.offsetImm
            # Branch offset is *4 (since an ARM instruction covers 4 bytes)
            self.offsetImm <<= 2

        else:
            # BX
            self.link = False
            self.addrReg = instrInt & 0xF
Exemplo n.º 5
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (24, 25, 26, 27), ())):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()
        self.datauser = instrInt & 0xFFFFFF
Exemplo n.º 6
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (25, 24, 21),
                                (27, 26, 23, 22, 20, 19, 18, 17, 16))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()
Exemplo n.º 7
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (7, 4, 24), (27, 26, 25, 23, 21, 20, 11, 10, 9, 8, 6, 5))):
            raise ExecutionException("Le bytecode à cette adresse ne correspond à aucune instruction valide",
                                        internalError=False)

        # Retrieve the condition field
        self._decodeCondition()
        
        self.byte = bool(instrInt & (1 << 22))
        self.rm = instrInt & 0xF
        self.rd = (instrInt >> 12) & 0xF
        self.rn = (instrInt >> 16) & 0xF
Exemplo n.º 8
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (7, 4),
                                tuple(range(22, 28)) + (5, 6))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()

        self.rd = (instrInt >> 16) & 0xF
        self.rn = (instrInt >> 12) & 0xF
        self.rs = (instrInt >> 8) & 0xF
        self.rm = instrInt & 0xF

        self.modifyFlags = bool(instrInt & (1 << 20))
        self.accumulate = bool(instrInt & (1 << 21))
Exemplo n.º 9
0
    def execute(self, simulatorContext):
        if not self._checkCondition(simulatorContext.regs):
            # Nothing to do, instruction not executed
            self.countExecConditionFalse += 1
            return
        self.countExec += 1

        addr = simulatorContext.regs[self.rn]
        s = 1 if self.byte else 4
        m = simulatorContext.mem.get(addr, size=s)
        if m is None:       # No such address in the mapped memory, we cannot continue
            raise ExecutionException("Tentative de lecture de {} octets à partir de l'adresse {} invalide : mémoire non initialisée".format(s, addr))
        valMem = struct.unpack("<B" if self.byte else "<I", m)[0]

        # We write to the memory before writing the register in case where rd==rm
        valWrite = simulatorContext.regs[self.rm]
        simulatorContext.mem.set(addr, valWrite, size=1 if self.byte else 4)

        simulatorContext.regs[self.rd] = valMem
Exemplo n.º 10
0
    def decode(self):
        instrInt = self.instrInt
        if not utils.checkMask(instrInt, (), (27, 26)):
            raise ExecutionException("Le bytecode à cette adresse ne correspond à aucune instruction valide (2)", 
                                        internalError=False)

        # Retrieve the condition field
        self._decodeCondition()

        # Get the opcode
        self.opcodeNum = (instrInt >> 21) & 0xF
        self.opcode = utils.dataOpcodeMappingR[self.opcodeNum]

        # "Immediate" and "set flags"
        self.imm = bool(instrInt & (1 << 25))
        self.modifyFlags = bool(instrInt & (1 << 20))

        self.rd = (instrInt >> 12) & 0xF    # Destination register
        self.rn = (instrInt >> 16) & 0xF    # First operand register

        if self.imm:
            self.shiftedVal = instrInt & 0xFF
            # see 4.5.3 of ARM doc to understand the * 2
            self.shift = utils.shiftInfo(type="ROR", 
                                            immediate=True, 
                                            value=((instrInt >> 8) & 0xF) * 2)
            self.carryOutImmShift = 0
            if self.shift.value != 0:
                # If it is a constant, we shift as we decode
                self.carryOutImmShift, self.shiftedVal = utils.applyShift(self.shiftedVal, 
                                                                            self.shift, 
                                                                            False)
        else:
            self.op2reg = instrInt & 0xF
            if instrInt & (1 << 4):
                self.shift = utils.shiftInfo(type=utils.shiftMappingR[(instrInt >> 5) & 0x3],
                                                immediate=False,
                                                value=(instrInt >> 8) & 0xF)
            else:
                self.shift = utils.shiftInfo(type=utils.shiftMappingR[(instrInt >> 5) & 0x3],
                                                immediate=True,
                                                value=(instrInt >> 7) & 0x1F)
Exemplo n.º 11
0
    def execute(self, simulatorContext):
        self.pcmodified = False
        if not self._checkCondition(simulatorContext.regs):
            # Nothing to do, instruction not executed
            self.countExecConditionFalse += 1
            return
        self.countExec += 1

        addr = baseval = simulatorContext.regs[self.basereg]
        if self.imm:
            addr += self.sign * self.offsetImm
        else:
            _, sval = utils.applyShift(simulatorContext.regs[self.offsetReg],
                                       self.offsetRegShift,
                                       simulatorContext.regs.C)
            addr += self.sign * sval

        realAddr = addr if self.pre else baseval
        s = 1 if self.byte else 4
        if self.mode == 'LDR':
            m = simulatorContext.mem.get(realAddr, size=s)
            if m is None:  # No such address in the mapped memory, we cannot continue
                raise ExecutionException(
                    "Tentative de lecture de {} octets à partir de l'adresse {} invalide : mémoire non initialisée"
                    .format(s, realAddr))
            res = struct.unpack("<B" if self.byte else "<I", m)[0]

            simulatorContext.regs[self.rd] = res
            if self.rd == simulatorContext.PC:
                self.pcmodified = True
        else:  # STR
            valWrite = simulatorContext.regs[self.rd]
            if self.rd == simulatorContext.PC and simulatorContext.PCSpecialBehavior:
                valWrite += 4  # Special case for PC (see ARM datasheet, 4.9.4)
            simulatorContext.mem.set(realAddr,
                                     valWrite,
                                     size=1 if self.byte else 4)

        if self.writeback:
            simulatorContext.regs[self.basereg] = addr
Exemplo n.º 12
0
    def decode(self):
        instrInt = self.instrInt
        if not (utils.checkMask(instrInt, (27, ), (26, 25))):
            raise ExecutionException(
                "Le bytecode à cette adresse ne correspond à aucune instruction valide",
                internalError=False)

        # Retrieve the condition field
        self._decodeCondition()

        self.pre = bool(instrInt & (1 << 24))
        self.sign = 1 if instrInt & (1 << 23) else -1
        self.sbit = bool(instrInt & (1 << 22))
        self.writeback = bool(instrInt & (1 << 21))
        self.mode = "LDR" if instrInt & (1 << 20) else "STR"

        self.basereg = (instrInt >> 16) & 0xF
        self.regbitmap = instrInt & 0xFFFF
        reglist = []
        for i in range(16):
            if self.regbitmap & (1 << i):
                reglist.append(i)
        self.reglist = tuple(reglist)
Exemplo n.º 13
0
    def explain(self, simulatorContext):
        self.resetAccessStates()
        bank = simulatorContext.regs.mode
        simulatorContext.regs.deactivateBreakpoints()
        modifiedFlags = {'Z', 'N'}

        disassembly = self.opcode
        description = "<ol>\n"
        disCond, descCond = self._explainCondition()
        disassembly += disCond
        description += descCond

        if self.modifyFlags and self.opcode not in ("TST", "TEQ", "CMP", "CMN"):
            disassembly += "S"

        if self.opcode not in ("MOV", "MVN"):
            self._readregs |= utils.registerWithCurrentBank(self.rn, bank)

        op2desc = ""
        op2dis = ""
        # Get second operand value
        if self.imm:
            op2 = self.shiftedVal
            op2desc = "La constante {}".format(op2)
            op2dis = "#{}".format(hex(op2))
        else:
            self._readregs |= utils.registerWithCurrentBank(self.op2reg, bank)
            
            if self.shift.type != "LSL" or self.shift.value > 0 or not self.shift.immediate:
                modifiedFlags.add('C')

            shiftDesc = utils.shiftToDescription(self.shift, bank)
            shiftinstr = utils.shiftToInstruction(self.shift)
            op2desc = "Le registre {} {}".format(utils.regSuffixWithBank(self.op2reg, bank), shiftDesc)
            op2dis = "R{}{}".format(self.op2reg, shiftinstr)
            if not self.shift.immediate:
                self._readregs |= utils.registerWithCurrentBank(self.shift.value, bank)
            op2 = simulatorContext.regs[self.op2reg]

        if self.opcode in ("AND", "TST"):
            # These instructions do not affect the V flag (ARM Instr. set, 4.5.1)
            # However, C flag "is set to the carry out from the barrel shifter [if the shift is not LSL #0]" (4.5.1)
            # this was already done when we called _shiftVal
            description += "<li>Effectue une opération ET entre:\n"
        elif self.opcode in ("EOR", "TEQ"):
            # These instructions do not affect the C and V flags (ARM Instr. set, 4.5.1)
            description += "<li>Effectue une opération OU EXCLUSIF (XOR) entre:\n"
        elif self.opcode in ("SUB", "CMP"):
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une soustraction (A-B) entre:\n"
            if self.opcode == "SUB" and self.rd == simulatorContext.PC:
                # We change PC, we show it in the editor
                self._nextInstrAddr = simulatorContext.regs[self.rn] - op2
        elif self.opcode == "RSB":
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une soustraction inverse (B-A) entre:\n"
        elif self.opcode in ("ADD", "CMN"):
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une addition (A+B) entre:\n"
            if self.opcode == "ADD" and self.rd == simulatorContext.PC:
                # We change PC, we show it in the editor
                self._nextInstrAddr = simulatorContext.regs[self.rn] + op2
        elif self.opcode == "ADC":
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une addition avec retenue (A+B+carry) entre:\n"
        elif self.opcode == "SBC":
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une soustraction avec emprunt (A-B+carry) entre:\n"
        elif self.opcode == "RSC":
            modifiedFlags.update(('C', 'V'))
            description += "<li>Effectue une soustraction inverse avec emprunt (B-A+carry) entre:\n"
        elif self.opcode == "ORR":
            description += "<li>Effectue une opération OU entre:\n"
        elif self.opcode == "MOV":
            description += "<li>Lit la valeur de :\n"
            if self.rd == simulatorContext.PC:
                # We change PC, we show it in the editor
                self._nextInstrAddr = op2
        elif self.opcode == "BIC":
            description += "<li>Effectue une opération ET NON entre:\n"
        elif self.opcode == "MVN":
            description += "<li>Effectue une opération NOT sur :\n"
            if self.rd == simulatorContext.PC:
                # We change PC, we show it in the editor
                self._nextInstrAddr = ~op2
        else:
            raise ExecutionException("Mnémonique invalide : {}".format(self.opcode))

        if self.opcode in ("MOV", "MVN"):
            description += "<ol type=\"A\"><li>{}</li></ol>\n".format(op2desc)
            disassembly += " R{}, ".format(self.rd)
        elif self.opcode in ("TST", "TEQ", "CMP", "CMN"):
            description += "<ol type=\"A\"><li>Le registre {}</li><li>{}</li></ol>\n".format(utils.regSuffixWithBank(self.rn, bank), op2desc)
            disassembly += " R{}, ".format(self.rn)
        else:
            description += "<ol type=\"A\"><li>Le registre {}</li>\n".format(utils.regSuffixWithBank(self.rn, bank))
            description += "<li>{}</li></ol>\n".format(op2desc)
            disassembly += " R{}, R{}, ".format(self.rd, self.rn)
        disassembly += op2dis

        description += "</li>\n"

        if self.modifyFlags:
            if self.rd == simulatorContext.PC:
                description += "<li>Copie le SPSR courant dans CPSR</li>\n"
            else:
                self._writeflags = modifiedFlags
                description += "<li>Met à jour les drapeaux de l'ALU en fonction du résultat de l'opération</li>\n"
        if self.opcode not in ("TST", "TEQ", "CMP", "CMN"):
            description += "<li>Écrit le résultat dans {}</li>".format(utils.regSuffixWithBank(self.rd, bank))
            self._writeregs |= utils.registerWithCurrentBank(self.rd, bank)

        description += "</ol>"

        simulatorContext.regs.reactivateBreakpoints()
        return disassembly, description
Exemplo n.º 14
0
    def execute(self, simulatorContext):
        self.pcmodified = False
        if not self._checkCondition(simulatorContext.regs):
            # Nothing to do, instruction not executed
            self.countExecConditionFalse += 1
            return
        self.countExec += 1
        
        workingFlags = {}
        workingFlags['C'] = 0
        # "On logical operations, if the S bit is set (and Rd is not R15)
        # the V flag in the CPSR will be unaffected"
        # (ARM Reference 4.5.1)
        workingFlags['V'] = simulatorContext.regs.V
        # Get first operand value
        op1 = simulatorContext.regs[self.rn]
        # Get second operand value
        if self.imm:
            op2 = self.shiftedVal
            if self.shift.value != 0:
                # We change the carry flag only if we did a shift
                workingFlags['C'] = self.carryOutImmShift
            else:
                workingFlags['C'] = simulatorContext.regs.C
        else:
            op2 = simulatorContext.regs[self.op2reg]
            if self.op2reg == simulatorContext.PC and not self.shift.immediate and simulatorContext.PCSpecialBehavior:
                op2 += 4    # Special case for PC where we use PC+12 instead of PC+8 (see 4.5.5 of ARM Instr. set)
            carry, op2 = utils.applyShift(op2, self.shift, simulatorContext.regs.C)
            workingFlags['C'] = bool(carry)

        if self.opcode == "MOV":
            res = op2
        elif self.opcode in ("ADD", "CMN"):
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, op2, 0)
        elif self.opcode in ("SUB", "CMP"):
            # For a subtraction, including the comparison instruction CMP, C is set to 0
            # if the subtraction produced a borrow (that is, an unsigned underflow), and to 1 otherwise.
            # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0801a/CIADCDHH.html
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, ~op2, 1)
        elif self.opcode == "MVN":
            res = ~op2
        elif self.opcode in ("AND", "TST"):
            # These instructions do not affect the V flag (ARM Instr. set, 4.5.1)
            # However, C flag "is set to the carry out from the barrel shifter [if the shift is not LSL #0]" (4.5.1)
            # this was already done when we called _shiftVal
            res = op1 & op2
        elif self.opcode == "ORR":
            res = op1 | op2
        elif self.opcode == "BIC":
            res = op1 & ~op2     # Bit clear?
        elif self.opcode in ("EOR", "TEQ"):
            # These instructions do not affect the C and V flags (ARM Instr. set, 4.5.1)
            res = op1 ^ op2
        elif self.opcode == "RSB":
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(~op1, op2, 1)
        elif self.opcode== "ADC":
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, op2, int(simulatorContext.regs.C))
        elif self.opcode == "SBC":
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, ~op2, int(simulatorContext.regs.C))
        elif self.opcode == "RSC":
            res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(~op1, op2, int(simulatorContext.regs.C))
        else:
            raise ExecutionException("Mnémonique invalide : {}".format(self.opcode))

        # Get the result back to 32 bits, if applicable (else it's just a no-op)
        res &= 0xFFFFFFFF           

        workingFlags['Z'] = res == 0
         # "N flag will be set to the value of bit 31 of the result" (4.5.1)
        workingFlags['N'] = res & 0x80000000

        if self.modifyFlags:
            if self.rd == simulatorContext.PC:
                # Combining writing to PC and the S flag is a special case (see ARM Instr. set, 4.5.5)
                # "When Rd is R15 and the S flag is set the result of the operation is placed in R15 and
                # the SPSR corresponding to the current mode is moved to the CPSR. This allows state
                # changes which atomically restore both PC and CPSR. This form of instruction should
                # not be used in User mode."
                if simulatorContext.regs.mode == "User":
                    raise ExecutionException("L'utilisation de PC comme registre de destination en combinaison avec la mise a jour des drapeaux est interdite en mode User!")
                if (simulatorContext.regs.SPSR & 0x1F) not in simulatorContext.regs.bits2mode:
                    # The mode in SPSR is invalid
                    raise ExecutionException("SPSR devrait ici être copié dans CPSR, mais le mode contenu dans SPSR est invalide!")
                simulatorContext.regs.CPSR = simulatorContext.regs.SPSR        # Put back the saved SPSR in CPSR
            else:
                simulatorContext.regs.setAllFlags(workingFlags)

        if self.opcode not in ("TST", "TEQ", "CMP", "CMN"):
            # We actually write the result
            simulatorContext.regs[self.rd] = res
            if self.rd == simulatorContext.PC:
                self.pcmodified = True
            # We consider writing into LR as stepping out of a function
            # This does not change anything for the emulation, but has consequences
            # for the emulation stopping criterion
            if self.rd == 14 and simulatorContext.stepCondition > 0:
                simulatorContext.stepCondition -= 1
                if len(simulatorContext.callStack) > 0:
                    simulatorContext.callStack.pop()