From: <mic...@us...> - 2007-04-26 20:27:45
|
Revision: 94 http://svn.sourceforge.net/pearcolator/?rev=94&view=rev Author: michael_baer Date: 2007-04-26 13:27:47 -0700 (Thu, 26 Apr 2007) Log Message: ----------- - Introduced processor mode handling to the ARM interpreter - Fixed decoder bug related to BLX - Several minor ARM fixes - First interpreter version that can run an ARM monitor Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/memory/AutoMappingMemory.java src/org/binarytranslator/generic/memory/DebugMemory.java src/org/binarytranslator/generic/memory/MemoryMapException.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-26 20:27:47 UTC (rev 94) @@ -357,7 +357,7 @@ public void visit(BranchExchange instr) { String mnemonic = instr.link ? "BLX" : "BX"; - setResult(String.format("%s%s #%d", mnemonic, cond(instr), operand(instr + setResult(String.format("%s%s #%s", mnemonic, cond(instr), operand(instr .target()))); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-04-26 20:27:47 UTC (rev 94) @@ -69,7 +69,8 @@ return factory.createMoveFromStatusRegister(instr); } - if (bits_7_4 == 1 && ((instr & 0x01F00000) == 0x01200000)) { + if (((bits_7_4 & 0xD) == 1) && ((instr & 0x01F00000) == 0x01200000)) { + //bits 7-4 == 1 || bits 7-4 == 3 //Utils.getBit(instr, 24) == true && Utils.getBit(instr, 23) == false && Utils.getBit(instr, 22) == false && Utils.getBit(instr, 21) == true && Utils.getBit(instr, 20) == false return factory.createBranchExchange(instr); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-04-26 20:27:47 UTC (rev 94) @@ -1157,7 +1157,7 @@ sourceOperand = OperandWrapper.decodeDataProcessingOperand(instr); } - /** Identifies the PSR that is to be transferred: true for the SPSR, false for the CPSR. */ + /** Identifies the PSR that is to be overwritten: true for the SPSR, false for the CPSR. */ public final boolean transferSavedPSR() { return transferSavedPSR; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-26 20:27:47 UTC (rev 94) @@ -7,6 +7,7 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Instruction.Condition; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; +import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; import org.binarytranslator.generic.decoder.Interpreter; import com.sun.org.apache.bcel.internal.generic.InstructionFactory; @@ -48,6 +49,288 @@ return instruction; } + + private abstract static class ResolvedOperand { + + protected int value; + + public static ResolvedOperand resolveWithShifterCarryOut(ARM_Registers regs, OperandWrapper operand) { + ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(regs, operand); + return result; + } + + public static int resolve(ARM_Registers regs, OperandWrapper operand) { + ResolvedOperand result = new ResolvedOperand_WithoutShifterCarryOut(regs, operand); + return result.getValue(); + } + + public final int getValue() { + return value; + } + + public abstract boolean getShifterCarryOut(); + + private static class ResolvedOperand_WithoutShifterCarryOut + extends ResolvedOperand{ + + private ResolvedOperand_WithoutShifterCarryOut(ARM_Registers regs, OperandWrapper operand) { + _resolve(regs, operand); + } + + public boolean getShifterCarryOut() { + throw new RuntimeException("This class does not provide a shifter carry out value."); + } + + private void _resolve(ARM_Registers regs, OperandWrapper operand) { + + switch (operand.getType()) { + case Immediate: + value = operand.getImmediate(); + return; + + case Register: + int reg = operand.getRegister(); + + //mind the arm pc offset + value = regs.get(reg); + + if (reg == 15) + value += 8; + + return; + + case RegisterShiftedRegister: + case ImmediateShiftedRegister: + value = resolveShift(regs, operand); + return; + + case PcRelative: + value = regs.get(ARM_Registers.PC) + 8 + operand.getOffset(); + break; + + default: + throw new RuntimeException("Unexpected wrapped operand type: " + + operand.getType()); + } + } + + /** If the given OperandWrapper involves shifting a register, then this function will decoder the shift + * and set the result of the barrel shifter accordingly. */ + private final int resolveShift(ARM_Registers regs, OperandWrapper operand) { + if (DBT.VerifyAssertions) + DBT._assert(operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister || + operand.getType() == OperandWrapper.Type.RegisterShiftedRegister); + + int value = regs.get(operand.getRegister()); + + //consider the "usual" ARM program counter offset + if (operand.getRegister() == ARM_Registers.PC) + value += 8; + + byte shiftAmount; + + if (operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister) + shiftAmount = operand.getShiftAmount(); + else { + shiftAmount = (byte) (regs.get(operand.getShiftingRegister()) & 0xF); + } + + switch (operand.getShiftType()) { + case ASR: + + if (shiftAmount >= 32) { + return Utils.getBit(value, 31) ? 0xFFFFFFFF : 0; + } + return value >> shiftAmount; + + case LSL: + + if (shiftAmount >= 32) { + return 0; + } + + return value << shiftAmount; + + case LSR: + + if (shiftAmount >= 32) { + return 0; + } + + return value >>> shiftAmount; + + case ROR: + return Integer.rotateRight(value, shiftAmount); + + case RRE: + if (regs.isCarrySet()) + return (value >> 1) | 0x80000000; + else + return value >> 1; + + default: + throw new RuntimeException("Unexpected shift type: " + + operand.getShiftType()); + } + } + } + + private static class ResolvedOperand_WithShifterCarryOut + extends ResolvedOperand{ + + private boolean shifterCarryOut; + + private ResolvedOperand_WithShifterCarryOut(ARM_Registers regs, OperandWrapper operand) { + _resolve(regs, operand); + } + + public boolean getShifterCarryOut() { + return shifterCarryOut; + } + + private void _resolve(ARM_Registers regs, OperandWrapper operand) { + + switch (operand.getType()) { + case Immediate: + value = operand.getImmediate(); + + if (operand.getShiftAmount() == 0) + shifterCarryOut = regs.isCarrySet(); + else + shifterCarryOut = (value & 0x80000000) != 0; + + return; + + case Register: + shifterCarryOut = regs.isCarrySet(); + int reg = operand.getRegister(); + + //mind the arm pc offset + value = regs.get(reg); + + if (reg == 15) + value += 8; + + return; + + case RegisterShiftedRegister: + case ImmediateShiftedRegister: + value = resolveShift(regs, operand); + return; + + case PcRelative: + throw new RuntimeException("This operand type does not produce a shifter carry out."); + + default: + throw new RuntimeException("Unexpected wrapped operand type: " + + operand.getType()); + } + } + + /** If the given OperandWrapper involves shifting a register, then this function will decoder the shift + * and set the result of the barrel shifter accordingly. */ + private final int resolveShift(ARM_Registers regs, OperandWrapper operand) { + if (DBT.VerifyAssertions) + DBT._assert(operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister || + operand.getType() == OperandWrapper.Type.RegisterShiftedRegister); + + int value = regs.get(operand.getRegister()); + + //consider the "usual" ARM program counter offset + if (operand.getRegister() == ARM_Registers.PC) + value += 8; + + byte shiftAmount; + + if (operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister) + shiftAmount = operand.getShiftAmount(); + else { + shiftAmount = (byte) (regs.get(operand.getShiftingRegister()) & 0xF); + } + + switch (operand.getShiftType()) { + case ASR: + + if (shiftAmount >= 32) { + shifterCarryOut = Utils.getBit(value, 31); + return shifterCarryOut ? 0xFFFFFFFF : 0; + } + + if (shiftAmount == 0) { + shifterCarryOut = regs.isCarrySet(); + return value; + } + + shifterCarryOut = Utils.getBit(value, shiftAmount - 1); + return value >> shiftAmount; + + case LSL: + + if (shiftAmount > 32) { + shifterCarryOut = false; + return 0; + } + + if (shiftAmount == 32) { + shifterCarryOut = Utils.getBit(value, 31); + return 0; + } + + if (shiftAmount == 0) { + shifterCarryOut = regs.isCarrySet(); + return value; + } + + shifterCarryOut = Utils.getBit(value, 32 - shiftAmount); + return value << shiftAmount; + + case LSR: + + if (shiftAmount > 32) { + shifterCarryOut = false; + return 0; + } + + if (shiftAmount == 32) { + shifterCarryOut = Utils.getBit(value, 31); + return 0; + } + + if (shiftAmount == 0) { + shifterCarryOut = regs.isCarrySet(); + return value; + } + + shifterCarryOut = Utils.getBit(value, shiftAmount - 1); + return value >>> shiftAmount; + + case ROR: + + if (shiftAmount == 0) { + shifterCarryOut = regs.isCarrySet(); + return value; + } + else { + shifterCarryOut = Utils.getBit(value, shiftAmount & 0x1F); + return Integer.rotateRight(value, shiftAmount); + } + + case RRE: + shifterCarryOut = (value & 0x1) != 0; + + if (regs.isCarrySet()) + return (value >> 1) | 0x80000000; + else + return value >> 1; + + default: + throw new RuntimeException("Unexpected shift type: " + + operand.getShiftType()); + } + } + } + } + /** All ARM interpreter instructions implement this interface. */ private interface ARM_Instruction extends Interpreter.Instruction { /** Returns the condition, under which the given instruction will be executed. */ @@ -164,105 +447,8 @@ /** If the given OperandWrapper involves shifting a register, then this function will decoder the shift * and set the result of the barrel shifter accordingly. */ - private final int resolveShift(OperandWrapper operand) { - if (DBT.VerifyAssertions) - DBT._assert(operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister || - operand.getType() == OperandWrapper.Type.RegisterShiftedRegister); - int value = regs.get(operand.getRegister()); - - //consider the "usual" ARM program counter offset - if (operand.getRegister() == ARM_Registers.PC) - value += 8; - - byte shiftAmount; - if (operand.getType() == OperandWrapper.Type.ImmediateShiftedRegister) - shiftAmount = operand.getShiftAmount(); - else { - shiftAmount = (byte) (regs.get(operand.getShiftingRegister()) & 0xF); - } - - switch (operand.getShiftType()) { - case ASR: - - if (shiftAmount >= 32) { - shifterCarryOut = Utils.getBit(value, 31); - return shifterCarryOut ? 0xFFFFFFFF : 0; - } - - if (shiftAmount == 0) { - shifterCarryOut = regs.isCarrySet(); - return value; - } - - shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >> shiftAmount; - - case LSL: - - if (shiftAmount > 32) { - shifterCarryOut = false; - return 0; - } - - if (shiftAmount == 32) { - shifterCarryOut = Utils.getBit(value, 31); - return 0; - } - - if (shiftAmount == 0) { - shifterCarryOut = regs.isCarrySet(); - return value; - } - - shifterCarryOut = Utils.getBit(value, 32 - shiftAmount); - return value << shiftAmount; - - case LSR: - - if (shiftAmount > 32) { - shifterCarryOut = false; - return 0; - } - - if (shiftAmount == 32) { - shifterCarryOut = Utils.getBit(value, 31); - return 0; - } - - if (shiftAmount == 0) { - shifterCarryOut = regs.isCarrySet(); - return value; - } - - shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >>> shiftAmount; - - case ROR: - - if (shiftAmount == 0) { - shifterCarryOut = regs.isCarrySet(); - return value; - } else { - shifterCarryOut = Utils.getBit(value, shiftAmount & 0x1F); - return Integer.rotateRight(value, shiftAmount); - } - - case RRE: - shifterCarryOut = (value & 0x1) != 0; - - if (regs.isCarrySet()) - return (value >> 1) | 0x80000000; - else - return value >> 1; - - default: - throw new RuntimeException("Unexpected shift type: " - + operand.getShiftType()); - } - } - /** Returns the value of operand 1 of the data processing instruction. This is always a register value. * However, deriving classes may alter this behavior, for example to return a negative register * value for a RSB instruction. */ @@ -277,38 +463,9 @@ /** Returns the value of the rhs-operand of the data processing instruction. */ protected int resolveOperand2() { - int value; - - switch (operand2.getType()) { - case Immediate: - value = operand2.getImmediate(); - - if (operand2.getShiftAmount() == 0) - shifterCarryOut = regs.isCarrySet(); - else - shifterCarryOut = (value & 0x80000000) != 0; - - return value; - - case Register: - shifterCarryOut = regs.isCarrySet(); - int reg = operand2.getRegister(); - - //mind the arm pc offset - if (reg == 15) - return regs.get(reg) + 8; - else - return regs.get(operand2.getRegister()); - - case RegisterShiftedRegister: - case ImmediateShiftedRegister: - return resolveShift(operand2); - - case PcRelative: - default: - throw new RuntimeException("Unexpected wrapped operand type: " - + operand2.getType()); - } + ResolvedOperand resolvedOperand2 = ResolvedOperand.resolveWithShifterCarryOut(regs, operand2); + shifterCarryOut = resolvedOperand2.getShifterCarryOut(); + return resolvedOperand2.getValue(); } public abstract void execute(); @@ -675,17 +832,26 @@ public void execute() { int memAddr = regs.get(Rn); - + //swap exchanges the value of a memory address with the value in a register - int tmp = ps.memory.load32(memAddr); - ps.memory.store16(memAddr, regs.get(Rm)); - - //according to the ARM architecture reference, the value loaded from a memory address is rotated - //according to the number of ones in the first two bits of the address - regs.set(Rd, Integer.rotateRight(tmp, (memAddr & 0x3) * 8)); + if (swapByte) { + int tmp = ps.memory.load32(memAddr); + ps.memory.store32(memAddr, regs.get(Rm)); + + //according to the ARM architecture reference, the value loaded from a memory address is rotated + //by the number of ones in the first two bits of the address + regs.set(Rd, Integer.rotateRight(tmp, (memAddr & 0x3) * 8)); + } + else { + int tmp = ps.memory.loadUnsigned8(memAddr); + ps.memory.store8(memAddr, regs.get(Rm) & 0xFF); + regs.set(Rm, tmp); + } } public int getSuccessor(int pc) { + //according to the ARM Architecture reference, using the pc as Rd yields an undefined + //result. Therefore, we can safely assume that this instruction never equals a branch return pc + 4; } } @@ -740,10 +906,18 @@ } else { //pre-indexing, forward reading //no need to adjust the start address - } } int nextAddress = startAddress; + + OperatingMode previousMode = ps.registers.getOperatingMode(); + + //if we should transfer the user mode registers... + if (forceUser) { + //... then change the current register map, but do NOT change the current processor mode + ps.registers.switchOperatingMode(OperatingMode.USR); + ps.registers.setOperatingModeWithoutRegisterLayout(previousMode); + } //are we supposed to load or store multiple registers? if (isLoad) { @@ -761,8 +935,22 @@ int newpc = ps.memory.load32(nextAddress); regs.set(ARM_Registers.PC, newpc & 0xFFFFFFFE); - //shall we switch to thumb mode - regs.setThumbMode((newpc & 0x1) != 0); + if (forceUser) { + //when we are transferring the PC with a forced-user transfer, then we also want to + //restore the CPSR from the SPSR. + //However, at the moment our register layout is different from our operating mode. + //Therefore, sync both first by switching the operating mode to user (which is what our register layout + //is anyway). + regs.setOperatingModeWithoutRegisterLayout(OperatingMode.USR); + regs.restoreSPSR2CPSR(); + + //there is no write-back for this instruction. + return; + } + else { + //shall we switch to thumb mode + regs.setThumbMode((newpc & 0x1) != 0); + } } } else { int nextReg = 0; @@ -780,6 +968,12 @@ } } + //restore the register layout, if we were transferring the user mode registers + if (forceUser) { + ps.registers.setOperatingModeWithoutRegisterLayout(OperatingMode.USR); + ps.registers.switchOperatingMode(previousMode); + } + if (writeBack) { //write the last address we read from back to a register if (!incrementBase) { @@ -961,7 +1155,69 @@ return pc + 4; } } + + private final class MoveToStatusRegister extends + ARM_Instructions.MoveToStatusRegister implements + ARM_Instruction { + public MoveToStatusRegister(int instr) { + super(instr); + } + + public void execute() { + //this variable is going to receive the new psr, which we will set + int new_psr = ResolvedOperand.resolve(regs, sourceOperand); + + //are we currently in a privileged mode? + boolean inPrivilegedMode = (regs.getOperatingMode() != ARM_Registers.OperatingMode.USR); + + //this variable receives the psr that we're replacing + int old_psr; + + //get the currect value for old_psr + if (transferSavedPSR) { + //if the current mode does not have a SPSR, then do nothing + if (inPrivilegedMode && regs.getOperatingMode() != ARM_Registers.OperatingMode.SYS) + return; + + old_psr = regs.getSPSR(); + } + else { + old_psr = regs.getCPSR(); + } + + //create a new CPSR value according to what pieces of the CPSR we are actually required to set + if (!transferControl || !inPrivilegedMode) { + new_psr &= 0xFFFFFF00; + new_psr |= (old_psr & 0xFF); + } + + if (!transferExtension || !inPrivilegedMode) { + new_psr &= 0xFFFF00FF; + new_psr |= (old_psr & 0xFF00); + } + + if (!transferStatus || !inPrivilegedMode) { + new_psr &= 0xFF00FFFF; + new_psr |= (old_psr & 0xFF0000); + } + + if (!transferFlags) { + new_psr &= 0x00FFFFFF; + new_psr |= (old_psr & 0xFF000000); + } + + if (transferSavedPSR) + regs.setSPSR(new_psr); + else + regs.setCPSR(new_psr); + } + + public int getSuccessor(int pc) { + return pc+4; + } + } + /** Invoke a software interrupt. */ private final class SoftwareInterrupt extends ARM_Instructions.SoftwareInterrupt implements ARM_Instruction { @@ -992,63 +1248,8 @@ /** Resolves the offset, which is (when post-indexing is not used) to be added to the * base address to create the final address. */ private int resolveOffset() { - int addrOffset; + int addrOffset = ResolvedOperand.resolve(regs, offset); - switch (offset.getType()) { - case Immediate: - addrOffset = offset.getImmediate(); - break; - - case Register: - addrOffset = regs.get(offset.getRegister()); - if (offset.getRegister() == ARM_Registers.PC) { - addrOffset += 8; - } - break; - - case ImmediateShiftedRegister: - addrOffset = regs.get(offset.getRegister()); - - if (offset.getRegister() == 15) - addrOffset += 8; - - switch (offset.getShiftType()) { - case ASR: - addrOffset = addrOffset >> offset.getShiftAmount(); - break; - - case LSL: - addrOffset = addrOffset << offset.getShiftAmount(); - break; - - case LSR: - addrOffset = addrOffset >>> offset.getShiftAmount(); - break; - - case ROR: - addrOffset = Integer.rotateRight(addrOffset, offset.getShiftAmount()); - break; - - case RRE: - if (regs.isCarrySet()) - addrOffset = (addrOffset >> 1) | 0x80000000; - else - addrOffset = addrOffset >> 1; - break; - - default: - throw new RuntimeException("Unexpected shift type: " - + offset.getShiftType()); - } - break; - - case PcRelative: - case RegisterShiftedRegister: - default: - throw new RuntimeException("Unexpected operand type: " - + offset.getType()); - } - if (positiveOffset) return addrOffset; else @@ -1073,11 +1274,12 @@ } public void execute() { - //should we simulate a user-mode memory access? + //should we simulate a user-mode memory access? If yes, store the current mode and fake a switch + //to user mode. + OperatingMode previousMode = null; if (forceUserMode) { - //TODO: Implement user mode memory access - throw new RuntimeException( - "Forced user mode memory access is not yet supported."); + previousMode = ps.registers.getOperatingMode(); + ps.registers.setOperatingModeWithoutRegisterLayout(ARM_Registers.OperatingMode.USR); } //get the address of the memory, that we're supposed access @@ -1088,11 +1290,12 @@ int value; switch (size) { - case Byte: - if (signExtend) - value = ps.memory.loadSigned8(address); - else - value = ps.memory.loadUnsigned8(address); + + case Word: + value = ps.memory.load32(address); + + //according to the ARM reference, the last two bits cause the value to be right-rotated + value = Integer.rotateRight(value, (address & 0x3) * 8); break; case HalfWord: @@ -1102,8 +1305,11 @@ value = ps.memory.loadUnsigned16(address); break; - case Word: - value = ps.memory.load32(address); + case Byte: + if (signExtend) + value = ps.memory.loadSigned8(address); + else + value = ps.memory.loadUnsigned8(address); break; default: @@ -1112,27 +1318,33 @@ //finally, write the variable into a register regs.set(Rd, value); - } else { + } + else { //we are store a value from a register to memory. int value = regs.get(Rd); switch (size) { - case Byte: - ps.memory.store8(address, value); + case Word: + ps.memory.store32(address & 0xFFFFFFFE, value); break; - + case HalfWord: - ps.memory.store16(address, value); + ps.memory.store16(address, value & 0xFFFF); break; - - case Word: - ps.memory.store32(address, value); + + case Byte: + ps.memory.store8(address, value & 0xFF); break; default: throw new RuntimeException("Unexpected memory size: " + size); } } + + //if we were writing in user mode, then switch back to our previous operating mode + if (forceUserMode) { + ps.registers.setOperatingModeWithoutRegisterLayout(previousMode); + } //should the memory address, which we accessed, be written back into a register? //This is used for continuous memory accesses @@ -1160,14 +1372,11 @@ * is executed. */ private final class UndefinedInstruction implements ARM_Instruction { - private final int instruction; - public UndefinedInstruction(int instr) { - this.instruction = instr; } public void execute() { - throw new RuntimeException("Undefined instruction: " + instruction); + ps.doUndefinedInstruction(); } public int getSuccessor(int pc) { @@ -1235,7 +1444,6 @@ return new DataProcessing_Teq(instr); case TST: return new DataProcessing_Tst(instr); - case CLZ: return new DataProcessing_Clz(instr); @@ -1283,6 +1491,7 @@ } public ARM_Instruction createLongMultiply(int instr) { + //TODO: Implement multiplications with longs throw new RuntimeException("Long Multiplications are not yet supported."); } @@ -1291,9 +1500,7 @@ } public ARM_Instruction createMoveToStatusRegister(int instr) { - //TODO: Implement Register -> CPSR transfers - throw new RuntimeException( - "Modifying the status register using MSR is not yet supported."); + return new MoveToStatusRegister(instr); } public ARM_Instruction createSingleDataTransfer(int instr) { Modified: src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java 2007-04-26 20:27:47 UTC (rev 94) @@ -6,8 +6,7 @@ public class ARM_LinuxSystemCalls extends LinuxSystemCalls { - private final ARM_LinuxProcessSpace ps; - + public ARM_LinuxSystemCalls(ARM_LinuxProcessSpace ps, LinuxSystemCallGenerator src) { super(src); @@ -25,6 +24,7 @@ systemCallTable[91] = new LinuxSystemCalls.SysMunmap(); systemCallTable[122] = new LinuxSystemCalls.SysUname(); systemCallTable[146] = new LinuxSystemCalls.SysWriteV(); + systemCallTable[195] = new LinuxSystemCalls.SysStat64(); systemCallTable[197] = new LinuxSystemCalls.SysFstat64(); systemCallTable[199] = new LinuxSystemCalls.SysGetEUID(); systemCallTable[200] = new LinuxSystemCalls.SysGetEGID(); @@ -32,8 +32,7 @@ systemCallTable[202] = new LinuxSystemCalls.SysGetEGID(); systemCallTable[221] = new LinuxSystemCalls.SysFcntl64(); systemCallTable[252] = new LinuxSystemCalls.SysExitGroup(); - - this.ps = ps; + } @Override Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-04-26 20:27:47 UTC (rev 94) @@ -167,7 +167,7 @@ previousInputLine = new BufferedReader(new InputStreamReader(System.in)).readLine(); //don't forget the Angel expects us to submit a carriage return etc. too - previousInputLine += "\n\r"; + previousInputLine += "\n"; } if (DBT.VerifyAssertions) DBT._assert(previousInputLine != null); @@ -344,7 +344,10 @@ char output = (char)ps.memory.loadUnsigned8(ptrOutput++); while (output != 0) { - consoleOutput.print(output); + + if (output != 13) + consoleOutput.print(output); + output = (char)ps.memory.loadUnsigned8(ptrOutput++); } } @@ -428,6 +431,10 @@ try { int value = consoleInput.read(); + //skip #13, because that's what Angel seems to do. + while (value == 13) + value = consoleInput.read(); + if (value == -1) throw new RuntimeException("Unable to read further characters from console"); Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-26 20:27:47 UTC (rev 94) @@ -111,4 +111,15 @@ public String toString() { return registers.toString(); } + + /** + * ARM undefined instruction handler. This method is called when the ARM processor + * is asked to execute an undefined instruction. By default, this throws a runtime exception. + * + * However, derived classes may re-implement this behaviour to achieve full system emulation. + * + */ + public void doUndefinedInstruction() { + throw new RuntimeException("Undefined instruction at 0x" + Integer.toHexString(getCurrentInstructionAddress())); + } } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-26 20:27:47 UTC (rev 94) @@ -58,13 +58,13 @@ * This flag from the CPSR denotes whether IRQs are currently accepted by the * processor. */ - private boolean flagIRQsDisabled = false; + private boolean flagIRQsDisabled = true; /** * This flag from the CPSR denotes whether FIQs are currently accepted by the * processor. */ - private boolean flagFIQsDisabled = false; + private boolean flagFIQsDisabled = true; /** * The operating mode from the CPSR register. Note that only the bottom five @@ -119,18 +119,63 @@ regs[reg] = value; } - public void switchOperatingMode(OperatingMode newMode) { + /** + * Switches the current processor operating mode to <code>newMode</code>, by loading the appropriate + * register layout for the mode and changing the processor's OperatingMode flag. + * During this process, the SPSR of the newMode is replaced with the CPSR of the current mode. + * + * @param newMode + * The operating mode that shall switch to. + */ + public void switchOperatingModeAndStoreSPSR(OperatingMode newMode) { + //get the previous SPSR int previous_cpsr = getCPSR(); + //change the current operating mode + switchOperatingMode(newMode); + + setSPSR(previous_cpsr); + } + + /** + * Sets the current operating mode and loads the register layout for that mode. + * However, the CPSR is not pushed into the new mode's SPSR. + * + * @param newMode + * The operating mode to switch to. + */ + public void switchOperatingMode(OperatingMode newMode) { + //perform the actual mode switch + setRegisterLayout(newMode); + operatingMode = newMode; + } + + /** + * Sets the processor's operating mode without changing the register layout. + * This is useful in certain situations, where a command just "fakes" to be in another mode + * so that the memory is fooled. + * + * @param newMode + */ + public void setOperatingModeWithoutRegisterLayout(OperatingMode newMode) { + operatingMode = newMode; + } + + /** + * Sets the layout of the ARM registers to the layout expected in <code>newMode</code>. + * + * @param newMode + * The mode for which the register layout shall be constructed. + */ + private void setRegisterLayout(OperatingMode newMode) { + //if we're either not switching to a new mode or if we're switching between SYS and USR mode, then //take a special fast-path if (newMode == operatingMode || ((operatingMode == OperatingMode.USR || newMode == OperatingMode.SYS) && (operatingMode == OperatingMode.SYS || newMode == OperatingMode.USR))) { - //we don't need to do anything in this case, except for copying the CPSR to the SPSR - operatingMode = newMode; - setSPSR(previous_cpsr); + //we don't need to do anything in this case return; } @@ -196,7 +241,7 @@ regs[11] = shadowRegisters[shadowOffset++]; regs[12] = shadowRegisters[shadowOffset++]; } - else if (operatingMode == OperatingMode.USR) { + else if (newMode == OperatingMode.USR) { //skip these shadow registers for now shadowOffset += 5; } @@ -204,14 +249,30 @@ //now load the remaining r13 and r14 registers regs[13] = shadowRegisters[shadowOffset++]; regs[14] = shadowRegisters[shadowOffset]; + } + + /** + * Overwrites the SPSR of the current mode with the supplied value. + * + * @param newSPSR + * The new value, which will replace the current SPSR. + */ + public void setSPSR(int newSPSR) { + //save the previous CPSR as the current SPSR + if (operatingMode == OperatingMode.USR || operatingMode == OperatingMode.SYS) { + //these modes don't have a SPSR, so ignore them + return; + } - //perform the actual mode switch - operatingMode = newMode; - - //save the previous CPSR as the current SPSR - setSPSR(previous_cpsr); + shadowRegisters[operatingMode.SHADOW_OFFSET + SPSR_OFFSET] = newSPSR; } + /** + * Returns the current operating mode. + */ + public OperatingMode getOperatingMode() { + return operatingMode; + } /** * Restores the saved program status register of the current operating mode to the CPSR, @@ -220,8 +281,18 @@ public void restoreSPSR2CPSR() { if (VM.VerifyAssertions) VM._assert(operatingMode != OperatingMode.USR); - setFlagsFromCPSR(getSPSR()); + setCPSR(getSPSR()); } + + /** + * Used to control the processor flag which says if the the processor is accepting interrupt requests. + * + * @param enabled + * Set to true to enable interrupts or false otherwise. + */ + public void setInterruptsEnabled(boolean enabled) { + flagIRQsDisabled = !enabled; + } /** * Returns the content of ARM's Current Program Status Register. @@ -246,20 +317,6 @@ return shadowRegisters[operatingMode.SHADOW_OFFSET + SPSR_OFFSET]; } - - /** - * Set's the current mode's Saved Program status register. - * @param newSPSR - */ - public void setSPSR(int newSPSR) { - - if (operatingMode == OperatingMode.USR || operatingMode == OperatingMode.SYS) { - //these modes don't have a SPSR, so ignore them - return; - } - - shadowRegisters[operatingMode.SHADOW_OFFSET + SPSR_OFFSET] = newSPSR; - } /** * Restores the processor state to the state saved within the given CPSR. @@ -267,9 +324,9 @@ * @param cpsr * ARM CPSR register content */ - public void setFlagsFromCPSR(int cpsr) { + public void setCPSR(int cpsr) { - //extract teh differnet flags from the PSR + //extract the different flags from the PSR flagNegative = (cpsr & 0x80000000) != 0; //bit 31 flagZero = (cpsr & 0x40000000) != 0; //bit 30 flagCarry = (cpsr & 0x20000000) != 0; //bit 29 @@ -285,6 +342,7 @@ for (OperatingMode opMode : OperatingMode.values()) if (opMode.PSR_IDENTIFIER == mode) { switchOperatingMode(opMode); + break; } if (DBT.VerifyAssertions) DBT._assert(operatingMode.PSR_IDENTIFIER == mode); Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-04-26 20:27:47 UTC (rev 94) @@ -53,11 +53,37 @@ setCurrentInstructionAddress(getCurrentInstructionAddress() + 4); } else { - throw new RuntimeException("Non-Angel system calls are not yet supported."); + //switch the operating mode to Supervisor + registers.switchOperatingModeAndStoreSPSR(ARM_Registers.OperatingMode.SVC); + registers.setInterruptsEnabled(false); + + //put the return address into the link register + registers.set(ARM_Registers.LR, getCurrentInstructionAddress() + 4); + + //jump to the respective SWI handler + setCurrentInstructionAddress(0x8); } } + /** + * This implementation of the undefined instruction handler behaves as + * the ARM processor would: It switches the operating mode, + * jumps to the undefined instruction handler and tries to execute the instruction + * stored there. + */ @Override + public void doUndefinedInstruction() { + registers.switchOperatingModeAndStoreSPSR(ARM_Registers.OperatingMode.SVC); + registers.setInterruptsEnabled(false); + + //put the return address into the link register + registers.set(ARM_Registers.LR, getCurrentInstructionAddress() + 4); + + //jump to the respective SWI handler + setCurrentInstructionAddress(0x4); + } + + @Override public GdbTarget getGdbTarget() { throw new UnsupportedOperationException("GDB not implemented."); } Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-04-26 20:27:47 UTC (rev 94) @@ -71,6 +71,24 @@ registers.set(ARM_Registers.SP, LinuxStackInitializer.stackInit(memory, STACK_TOP, getEnvironmentVariables(), auxVector)); } + @Override + protected String[] getEnvironmentVariables() { + return new String[] { "PWD=/root", + "PS1=\\h:\\w\\$", + "USER=root", + "MAIL=/var/mail/root", + "LANG=C", + "SSH_CLIENT=130.88.199.8 54342 22", + "LOGNAME=root", + "SHLVL=1", + "SHELL=/bin/bash", + "HOME=/root", + "TERM=xterm", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11", + "SSH_TTY=/dev/pts/1", + "_=/usr/bin/env" }; + } + public void dumpStack() { //grab the current frame pointer int fp = registers.get(ARM_Registers.FP); Modified: src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java 2007-04-26 20:27:47 UTC (rev 94) @@ -68,13 +68,11 @@ } public void setSysCallError(int r) { - // TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + ps.registers.set(0, -r); } public void setSysCallReturn(int r) { - // TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + ps.registers.set(0, r); } /** An argument iterator that hides the layout of syscall arguments on the ARM architecture */ Modified: src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java 2007-04-26 20:27:47 UTC (rev 94) @@ -84,8 +84,7 @@ } public void setSysCallError(int r) { -// TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + ps.registers.set(0, -r); } public void setSysCallReturn(int value) { Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-04-26 20:27:47 UTC (rev 94) @@ -18,10 +18,10 @@ while (!ps.finished) { Interpreter.Instruction instruction = interpreter.decode(pc); - System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); - pc = instruction.getSuccessor(pc); + //System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); instruction.execute(); + pc = instruction.getSuccessor(pc); if (pc == -1) pc = ps.getCurrentInstructionAddress(); Modified: src/org/binarytranslator/generic/memory/AutoMappingMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/AutoMappingMemory.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/generic/memory/AutoMappingMemory.java 2007-04-26 20:27:47 UTC (rev 94) @@ -60,8 +60,8 @@ return mem.load32(addr); } catch (Exception e) { - ensureMapped(addr, addr + 4); - return load32(addr); + mem.ensureMapped(addr, addr + 4); + return mem.load32(addr); } } @@ -70,8 +70,8 @@ return mem.loadInstruction32(addr); } catch (Exception e) { - ensureMapped(addr, addr + 4); - return loadInstruction32(addr); + mem.ensureMapped(addr, addr + 4); + return mem.loadInstruction32(addr); } } @@ -80,7 +80,7 @@ return mem.loadInstruction8(addr); } catch (Exception e) { - ensureMapped(addr, addr + 1); + mem.ensureMapped(addr, addr + 1); return mem.loadInstruction8(addr); } } @@ -90,7 +90,7 @@ return mem.loadSigned16(addr); } catch (Exception e) { - ensureMapped(addr, addr + 2); + mem.ensureMapped(addr, addr + 2); return mem.loadSigned16(addr); } } @@ -100,7 +100,7 @@ return mem.loadSigned8(addr); } catch (Exception e) { - ensureMapped(addr, addr + 1); + mem.ensureMapped(addr, addr + 1); return mem.loadSigned8(addr); } } @@ -110,7 +110,7 @@ return mem.loadUnsigned16(addr); } catch (Exception e) { - ensureMapped(addr, addr + 2); + mem.ensureMapped(addr, addr + 2); return mem.loadUnsigned16(addr); } } @@ -120,7 +120,7 @@ return mem.loadUnsigned8(addr); } catch (Exception e) { - ensureMapped(addr, addr + 1); + mem.ensureMapped(addr, addr + 1); return mem.loadUnsigned8(addr); } } @@ -138,7 +138,7 @@ mem.store16(addr, value); } catch (Exception e) { - ensureMapped(addr, addr + 2); + mem.ensureMapped(addr, addr + 2); mem.store16(addr, value); } } @@ -148,7 +148,7 @@ mem.store32(addr, value); } catch (Exception e) { - ensureMapped(addr, addr + 4); + mem.ensureMapped(addr, addr + 4); mem.store32(addr, value); } } @@ -158,7 +158,7 @@ mem.store8(addr, value); } catch (Exception e) { - ensureMapped(addr, addr + 1); + mem.ensureMapped(addr, addr + 1); mem.store8(addr, value); } } Modified: src/org/binarytranslator/generic/memory/DebugMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/DebugMemory.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/generic/memory/DebugMemory.java 2007-04-26 20:27:47 UTC (rev 94) @@ -11,7 +11,6 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; -import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.vmInterface.TranslationHelper; import org.jikesrvm.compilers.opt.ir.OPT_Operand; @@ -79,6 +78,22 @@ private static final int getPTE(int address) { return address >>> OFFSET_BITS; } + + /** + * Ensure memory between start and end is mapped + * @param startAddr starting address for mapped memory + * @param endAddr ending address for mapped memory + */ + @Override + public void ensureMapped(int startAddr, int endAddr) throws MemoryMapException { + startAddr = truncateToPage(startAddr); + endAddr = truncateToNextPage(endAddr); + for (;startAddr < endAddr; startAddr += getPageSize()) { + if (!isMapped(startAddr)) { + map(startAddr, getPageSize(), true, true, true); + } + } + } /** * Find free consecutive pages @@ -120,11 +135,16 @@ * is the page writable * @param exec * is the page executable + * @return + * The start address of the mapped memory. */ public int map(int addr, int len, boolean read, boolean write, boolean exec) throws MemoryMapException { // Check that the address is page aligned if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + + /* // if it is not, truncate the address down to the next page boundary and // start mapping from there int validPageCount = addr / PAGE_SIZE; @@ -135,7 +155,7 @@ DBT._assert(oldStartAddress > addr); // we have to map more more memory now to reach the same end address - len += (oldStartAddress - addr); + len += (oldStartAddress - addr);*/ } // Create memory @@ -196,12 +216,6 @@ if ((addr % PAGE_SIZE) != 0) { MemoryMapException.unalignedAddress(addr); } - // Check file offset is page aligned - /* - if ((offset % PAGE_SIZE) != 0) { - MemoryMapException.unalignedFileOffset(offset); - } - */ // Calculate number of pages int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; @@ -257,31 +271,25 @@ throw new Error("Memory map of already mapped location addr=0x" + Integer.toHexString(addr) + " len=" + len); } - // Allocate page - if (read && write) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - writableMemory[pte + i] = readableMemory[pte + i]; - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (read) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (exec) { - executableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - } else { - throw new Error("Unable to map address 0x" - + Integer.toHexString(addr) + " with permissions " - + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + + byte[] page; + + if (write) + page = file.getChannel().map(FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), PAGE_SIZE).array(); + else + page = file.getChannel().map(FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), PAGE_SIZE).array(); + + if (write) { + writableMemory[pte + i] = page; } + + if (read) { + readableMemory[pte + 1] = page; + } + + if (exec) { + executableMemory[pte + i] = page; + } } } return addr; Modified: src/org/binarytranslator/generic/memory/MemoryMapException.java =================================================================== --- src/org/binarytranslator/generic/memory/MemoryMapException.java 2007-04-26 20:26:01 UTC (rev 93) +++ src/org/binarytranslator/generic/memory/MemoryMapException.java 2007-04-26 20:27:47 UTC (rev 94) @@ -13,21 +13,20 @@ /** * Captures exceptions that can occur during memory mangement */ -final public class MemoryMapException extends RuntimeException { - /** - * Attempt to allocate on a non-page boundary - */ - private static final int UNALIGNED_ADDRESS = 1; +final public class MemoryMapException + extends RuntimeException { + + public enum Reason { + /** Attempt to allocate on a non-page boundary */ + UNALIGNED_ADDRESS, + /** Attempt to allocate from a file on an unaligned file offset */ + UNALIGNED_FILE_OFFSET + } /** - * Attempt to allocate from a file on an unaligned file offset - */ - private static final int UNALIGNED_FILE_OFFSET = 2; - - /** * The type of this memory map exception */ - private int type; + private Reason reason; /** * The file offset or address that was unaligned @@ -38,36 +37,37 @@ * Throw an unaligned address memory map exception */ static void unalignedAddress(int addr) throws MemoryMapException { - throw new MemoryMapException((long) addr, UNALIGNED_ADDRESS); + throw new MemoryMapException((long) addr, Reason.UNALIGNED_ADDRESS); } /** * Throw an unaligned file offset memory map exception */ static void unalignedFileOffset(long offset) throws MemoryMapException { - throw new MemoryMapException(offset, UNALIGNED_FILE_OFFSET); + throw new MemoryMapException(offset, Reason.UNALIGNED_FILE_OFFSET); } /** * Constructor */ - private MemoryMapException(long addr, int type) { + private MemoryMapException(long addr, Reason reason) { offsetOrAddress = addr; - this.type = type; + this.reason = reason; } /** * String representation of exception */ public String toString() { - switch (type) { + switch (reason) { case UNALIGNED_ADDRESS: - return "Unaligned memory map address: 0x" - + Integer.toHexString((int) offsetOrAddress); + return String.format("Unaligned memory map address: 0x%x", offsetOrAddress); + case UNALIGNED_FILE_OFFSET: - return "Unaligned file offset: " + offsetOrAddress; + return String.format("Unaligned file offset: 0x%x", offsetOrAddress); + + default: + throw new RuntimeException("Unexpected MemoryMapException Reason: " + reason); } - DBT_OptimizingCompilerException.UNREACHABLE(); - return null; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |