From: <mic...@us...> - 2007-04-18 17:40:18
|
Revision: 69 http://svn.sourceforge.net/pearcolator/?rev=69&view=rev Author: michael_baer Date: 2007-04-18 10:40:18 -0700 (Wed, 18 Apr 2007) Log Message: ----------- Intermediate commit: First version of an ARM interpreter that is able to run a small loop. Modified Paths: -------------- src/org/binarytranslator/Main.java 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_InstructionVisitor.java src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/Utils.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java src/org/binarytranslator/generic/os/process/ProcessSpace.java Added Paths: ----------- src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/memory/DebugMemory.java Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/Main.java 2007-04-18 17:40:18 UTC (rev 69) @@ -8,9 +8,12 @@ */ package org.binarytranslator; +import java.io.File; + import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; +import org.binarytranslator.generic.execution.InterpreterController; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -60,11 +63,18 @@ return; } + //check if the user actually supplied an executable name if (DBT_Options.executableFile == null) { System.err.println("Missing executable file name"); showUsage(); return; } + + //also make sure that the said executable really exists + if (!new File(DBT_Options.executableFile).exists()) { + System.err.println("The specified executable '" + DBT_Options.executableFile + "' could not be found."); + return; + } ProcessSpace ps; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-18 17:40:18 UTC (rev 69) @@ -7,7 +7,6 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.CoprocessorDataProcessing; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.CoprocessorDataTransfer; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.CoprocessorRegisterTransfer; -import org.binarytranslator.arch.arm.decoder.ARM_Instructions.CountLeadingZeros; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.DataProcessing; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.IntMultiply; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.LongMultiply; @@ -143,7 +142,10 @@ * @return A human readable form of this instructions condition. */ private String cond(Instruction instr) { - return instr.getCondition().name(); + if (instr.getCondition() == Condition.AL) + return ""; + else + return instr.getCondition().name(); } /** @@ -157,7 +159,7 @@ private final String operand(OperandWrapper op) { switch (op.getType()) { case Immediate: - return String.format("#%x", op.getImmediate()); + return String.format("#%d", op.getImmediate()); case ImmediateShiftedRegister: return String.format("r%d %s #%d", op.getRegister(), op.getShiftType(), @@ -165,9 +167,9 @@ case PcRelative: if (address != -1) - return String.format("#%x", op.getOffset() + address + 8); + return String.format("#0x%x", op.getOffset() + address + 8); else - return String.format("#<%x + pc>", op.getOffset()); + return String.format("#<%d + pc>", op.getOffset()); case Register: return "r" + op.getRegister(); @@ -193,14 +195,15 @@ // Filter instructions that only take one parameter if (instr.getOpcode() != DataProcessing.Opcode.MOV - && instr.getOpcode() != DataProcessing.Opcode.MVN) { + && instr.getOpcode() != DataProcessing.Opcode.MVN + && instr.getOpcode() != DataProcessing.Opcode.CLZ) { optionalParam = ", " + operand(instr.getOperand2()); } else optionalParam = ""; - setResult(String.format("%s r%d, r%d %s", mnemonic, instr.getRd(), instr - .getRn(), optionalParam)); + setResult(String.format("%s r%d, r%d%s", mnemonic, instr.getRd(), instr + .getOperandRegister(), optionalParam)); } public void visit(SingleDataTransfer instr) { @@ -308,7 +311,7 @@ public void visit(SoftwareInterrupt instr) { - setResult(String.format("SWI%s #%x", cond(instr), instr + setResult(String.format("SWI%s #0x%x", cond(instr), instr .getInterruptNumber())); } @@ -317,15 +320,15 @@ String mnemonic = instr.link() ? "BL" : "B"; if (address != -1) - setResult(String.format("%s%s #%x", mnemonic, cond(instr), instr.getOffset() + address + 8)); + setResult(String.format("%s%s #%d", mnemonic, cond(instr), instr.getOffset() + address + 8)); else - setResult(String.format("%s%s #<%x + pc>", mnemonic, cond(instr), instr.getOffset())); + setResult(String.format("%s%s #<%d + pc>", mnemonic, cond(instr), instr.getOffset())); } public void visit(BranchExchange instr) { String mnemonic = instr.link ? "BLX" : "BX"; - setResult(String.format("%s%s #%x", mnemonic, cond(instr), operand(instr + setResult(String.format("%s%s #%d", mnemonic, cond(instr), operand(instr .target()))); } @@ -407,11 +410,5 @@ setResult(String.format("MSR%s %s, %s", cond(instr), fields, operand(instr.getSource()))); } - - public void visit(CountLeadingZeros instr) { - - setResult(String.format("CLZ%s r%s r%s ", cond(instr), instr.getRd(), - instr.getRm())); - } } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-04-18 17:40:18 UTC (rev 69) @@ -180,7 +180,7 @@ //bit 6 and 7 are clear if (Utils.getBit(instr, 4)) { if (Utils.getBit(instr, 22)) - return factory.createCountLeadingZeros(instr); + return factory.createDataProcessing(instr); //should be a CLZ instruction else return factory.createBranchExchange(instr); } @@ -249,7 +249,6 @@ T createCoprocessorRegisterTransfer(int instr); T createMoveFromStatusRegister(int instr); T createMoveToStatusRegister(int instr); - T createCountLeadingZeros(int instr); T createUndefinedInstruction(int instr); } @@ -283,10 +282,6 @@ return new CoprocessorRegisterTransfer(instr); } - public Instruction createCountLeadingZeros(int instr) { - return new CountLeadingZeros(instr); - } - public Instruction createDataProcessing(int instr) { return new DataProcessing(instr); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java 2007-04-18 17:40:18 UTC (rev 69) @@ -19,5 +19,4 @@ void visit(CoprocessorRegisterTransfer instr); void visit(MoveFromStatusRegister instr); void visit(MoveToStatusRegister instr); - void visit(CountLeadingZeros instr); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-04-18 17:40:18 UTC (rev 69) @@ -28,7 +28,7 @@ protected final Condition condition; private Instruction(int instr) { - condition = Condition.values()[(byte) Utils.getBits(instr, 28, 31)]; + condition = Condition.values()[(instr & 0xF0000000) >>> 28]; } /** Returns the condition code that specifies, under which circumstances this operation shall be executed. */ @@ -190,6 +190,22 @@ return new PcRelativeOperand(offset); } + public static OperandWrapper decodeDataProcessingOperand(int instr) { + if (Utils.getBit(instr, 25)) { + //this is a right-rotated immediate value + byte shiftAmount = (byte)(Utils.getBits(instr, 8, 11) << 2); + int value = instr & 0xFF; + + if (shiftAmount == 0) + return new ImmediateOperand(value); + else + return new RightRotatedImmediateOperand(value, shiftAmount); + } + else { + return decodeShiftedRegister(instr); + } + } + /** Creates an operand wrapper, that represents a register shifted by an immediate or a register, depending on the instruction. */ public static OperandWrapper decodeShiftedRegister(int instr) { ShiftType shift = ShiftType.values()[Utils.getBits(instr, 5, 6)]; @@ -283,6 +299,39 @@ } } + /** Represents an immediate value operand. */ + protected static class RightRotatedImmediateOperand extends ImmediateOperand { + + /** @see #getShiftAmount() */ + protected final byte shiftAmount; + + protected RightRotatedImmediateOperand(int immediate, byte shiftAmount) { + super(Integer.rotateRight(immediate, shiftAmount)); + this.shiftAmount = shiftAmount; + } + + @Override + public int getImmediate() { + return immediate; + } + + /** The amount of shifting that had to be performed to create this immediate. */ + @Override + public byte getShiftAmount() { + return shiftAmount; + } + + @Override + public ShiftType getShiftType() { + return ShiftType.ROR; + } + + @Override + public Type getType() { + return Type.Immediate; + } + } + protected static class PcRelativeOperand extends OperandWrapper { protected final int offset; @@ -392,14 +441,13 @@ } /** Represents a Data Processing instruction. */ - public static class DataProcessing extends - TwoRegistersTemplate { + public static class DataProcessing extends Instruction { /** A list of possible DataProcessing operations. The list is orded in ascendingly, with the * first opcode corresponding to opcode 0 (zero) in the opcode field of an ARM data processing * instruction. */ public enum Opcode { - AND, EOR, SUB, RSB, ADD, ADC, SBC, RSC, TST, TEQ, CMP, CMN, ORR, MOV, BIC, MVN + AND, EOR, SUB, RSB, ADD, ADC, SBC, RSC, TST, TEQ, CMP, CMN, ORR, MOV, BIC, MVN, CLZ } /** @see #hasSetConditionCodes() */ @@ -411,18 +459,42 @@ /** @see #getOperand2() */ protected final OperandWrapper operand2; + /** @see #getOperandRegister() */ + protected final byte operandRegister; + + /** @see #getRd() */ + protected final byte Rd; + public DataProcessing(int instr) { super(instr); + + Rd = (byte) Utils.getBits(instr, 12, 15); updateConditionCodes = Utils.getBit(instr, 20); - opcode = Opcode.values()[(byte) Utils.getBits(instr, 21, 24)]; - - if (Utils.getBit(instr, 25)) - operand2 = OperandWrapper.createImmediate(Integer.rotateRight(instr & 0xFF, Utils.getBits(instr, 8, 11) << 2)); - else - operand2 = OperandWrapper.decodeShiftedRegister(instr); + + if (Utils.getBits(instr, 20, 27) == 0x16 && Utils.getBits(instr, 4, 7) == 1) { + //this is a CLZ instruction, which we're catching and merging into the data processing instructions + operandRegister = (byte) (instr & 0xF); + opcode = Opcode.CLZ; + operand2 = OperandWrapper.createImmediate(0); + } + else { + operandRegister = (byte) Utils.getBits(instr, 16, 19); + opcode = Opcode.values()[(byte) Utils.getBits(instr, 21, 24)]; + operand2 = OperandWrapper.decodeDataProcessingOperand(instr); + } } + /** Returns the number of the operation's destination register, starting from 0.*/ + public final byte getRd() { + return Rd; + } + + /** Returns the number of the operation's first operand register, starting from 0.*/ + public final byte getOperandRegister() { + return operandRegister; + } + /** Returns the opcode, that specifies the data processing operation, which is to be performed. */ public final Opcode getOpcode() { return opcode; @@ -498,9 +570,9 @@ size = TransferSize.Word; if (Utils.getBit(instr, 25)) - offset = OperandWrapper.createImmediate(instr & 0xFF); + offset = OperandWrapper.decodeShiftedRegister(instr); else - offset = OperandWrapper.decodeShiftedRegister(instr); + offset = OperandWrapper.createImmediate(instr & 0xFFF); } else { //this is a byte or half-word transfer @@ -524,6 +596,9 @@ //The decoder should make sure that we're never being called with this combination if (DBT.VerifyAssertions) DBT._assert(!signExtend || isLoad); } + + //this instruction variant yields an undefined result + if (DBT.VerifyAssertions) DBT._assert(Rd != 15 || !writeBack); } /** Returns true, if this memory access shall be treated as if it had been done in user mode. */ @@ -760,7 +835,7 @@ public Branch(int instr) { super(instr); link = Utils.getBit(instr, 24); - offset = instr & 0xFFF; + offset = Utils.signExtend((instr & 0xFFF) << 2, 14); } /** Should the current PC be put into the lr? */ @@ -1082,13 +1157,9 @@ transferExtension = Utils.getBit(instr, 17); transferStatus = Utils.getBit(instr, 18); transferFlags = Utils.getBit(instr, 19); - transferSavedPSR = Utils.getBit(instr, 22); - if (Utils.getBit(instr, 25)) - sourceOperand = OperandWrapper.createImmediate((instr & 0xFF) << Utils.getBits(instr, 8, 11)); - else - sourceOperand = OperandWrapper.decodeShiftedRegister(instr); + sourceOperand = OperandWrapper.decodeDataProcessingOperand(instr); } /** Identifies the PSR that is to be transferred: true for the SPSR, false for the CPSR. */ @@ -1126,36 +1197,4 @@ visitor.visit(this); } } - - /** Represents a CLZ instruction. */ - public static class CountLeadingZeros extends Instruction { - - /** @see #getRm() */ - protected final byte Rm; - - /** @see #getRd() */ - protected final byte Rd; - - public CountLeadingZeros(int instr) { - super(instr); - - Rm = (byte) (instr & 0xF); - Rd = (byte) Utils.getBits(instr, 12, 15); - } - - /** Returns the source register for this operation. */ - public final byte getRm() { - return Rm; - } - - /** Returns the destination register for this operation. */ - public final byte getRd() { - return Rd; - } - - @Override - public void visit(ARM_InstructionVisitor visitor) { - visitor.visit(this); - } - } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-18 17:40:18 UTC (rev 69) @@ -1,43 +1,116 @@ package org.binarytranslator.arch.arm.decoder; import org.binarytranslator.arch.arm.decoder.ARM_InstructionDecoder.ARM_InstructionFactory; -import org.binarytranslator.arch.arm.decoder.ARM_Instructions.*; +import org.binarytranslator.arch.arm.decoder.ARM_Instructions.OperandWrapper; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.DataProcessing.Opcode; +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.generic.decoder.Interpreter; -import org.binarytranslator.generic.decoder.Interpreter.Instruction; -public class ARM_Interpreter { +public class ARM_Interpreter implements Interpreter { protected final ARM_ProcessSpace ps; - protected final ARM_Registers regs; + protected final InterpreterFactory instructionFactory; public ARM_Interpreter(ARM_ProcessSpace ps) { this.ps = ps; this.regs = ps.registers; + instructionFactory = new InterpreterFactory(); } + public Instruction decode(int pc) { + + int binaryInstruction = ps.memory.loadInstruction32(pc); + ARM_Instruction instruction = ARM_InstructionDecoder.decode(binaryInstruction, instructionFactory); + + if (instruction.getCondition() != Condition.AL) { + return new ConditionalDecorator(instruction); + } + + return instruction; + } + + private interface ARM_Instruction extends Interpreter.Instruction { + Condition getCondition(); + } + private final class ConditionalDecorator implements Interpreter.Instruction { - protected final Interpreter.Instruction conditionalInstruction; + protected final ARM_Instruction conditionalInstruction; - protected ConditionalDecorator(Interpreter.Instruction i) { + protected ConditionalDecorator(ARM_Instruction i) { conditionalInstruction = i; } - + public void execute() { - conditionalInstruction.execute(); + if (isConditionTrue()) + conditionalInstruction.execute(); } public int getSuccessor(int pc) { return -1; } + + private boolean isConditionTrue() { + switch (conditionalInstruction.getCondition()) { + case AL: + return true; + + case CC: + return !regs.isCarrySet(); + + case CS: + return regs.isCarrySet(); + + case EQ: + return regs.isZeroSet(); + + case GE: + return regs.isNegativeSet() == regs.isOverflowSet(); + + case GT: + return (regs.isNegativeSet() == regs.isOverflowSet()) && regs.isZeroSet(); + + case HI: + return regs.isCarrySet() && !regs.isZeroSet(); + + case LE: + return regs.isZeroSet() || (regs.isNegativeSet() == regs.isOverflowSet()); + + case LS: + return !regs.isCarrySet() || regs.isZeroSet(); + + case LT: + return regs.isNegativeSet() != regs.isOverflowSet(); + + case MI: + return regs.isNegativeSet(); + + case NE: + return !regs.isZeroSet(); + + case NV: + return false; + + case PL: + return !regs.isNegativeSet(); + + case VC: + return !regs.isOverflowSet(); + + case VS: + return regs.isOverflowSet(); + + default: + throw new RuntimeException("Unexpected condition code: " + conditionalInstruction.getCondition()); + } + } } private abstract class DataProcessing extends ARM_Instructions.DataProcessing - implements Interpreter.Instruction { + implements ARM_Instruction { protected boolean shifterCarryOut; @@ -59,43 +132,59 @@ switch (operand.getShiftType()) { case ASR: - if (shiftAmount > 32) - shiftAmount = 32; + if (shiftAmount >= 32) { + shifterCarryOut = Utils.getBit(value, 31); + return shifterCarryOut ? 0xFFFFFFFF : 0; + } if (shiftAmount == 0) { shifterCarryOut = regs.isCarrySet(); return value; - } else { - shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >>> shiftAmount; } + + shifterCarryOut = Utils.getBit(value, shiftAmount - 1); + return value >>> shiftAmount; case LSL: - if (shiftAmount > 32) - shiftAmount = 32; + 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; - } else { - shifterCarryOut = Utils.getBit(value, 32 - shiftAmount); - return value << shiftAmount; } + shifterCarryOut = Utils.getBit(value, 32 - shiftAmount); + return value << shiftAmount; + case LSR: - if (shiftAmount > 32) - shiftAmount = 32; + 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; - } else { - shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >> shiftAmount; } + shifterCarryOut = Utils.getBit(value, shiftAmount - 1); + return value >> shiftAmount; + case ROR: if (shiftAmount == 0) { @@ -120,6 +209,15 @@ } } + protected int resolveOperand1() { + + if (operandRegister == ARM_Registers.PC) { + return regs.get(operandRegister) + 8; + } + + return regs.get(operandRegister); + } + protected int resolveOperand2() { int value; @@ -131,6 +229,8 @@ shifterCarryOut = regs.isCarrySet(); else shifterCarryOut = (value & 0x80000000) != 0; + + return value; case Register: shifterCarryOut = regs.isCarrySet(); @@ -147,7 +247,6 @@ } } - public abstract void execute(); protected final void setFlagsForResult(int result) { @@ -160,7 +259,7 @@ } } } - + protected final void setFlagsForAdd(int lhs, int rhs) { if (updateConditionCodes) { @@ -177,7 +276,7 @@ } public int getSuccessor(int pc) { - if (Rd == 15) + if (Rd != 15) return pc + 4; else return -1; @@ -189,11 +288,10 @@ protected DataProcessing_And(int instr) { super(instr); } - @Override public void execute() { - int result = regs.get(Rn) & resolveOperand2(); + int result = resolveOperand1() & resolveOperand2(); regs.set(Rd, result); setFlagsForResult(result); } @@ -207,7 +305,7 @@ @Override public void execute() { - int result = regs.get(Rn) ^ resolveOperand2(); + int result = resolveOperand1() ^ resolveOperand2(); regs.set(Rd, result); setFlagsForResult(result); } @@ -218,16 +316,12 @@ public DataProcessing_Add(int instr) { super(instr); } - - protected int resolveOperand1() { - return regs.get(Rn); - } - + public void execute() { int operand1 = resolveOperand1(); int operand2 = resolveOperand2(); int result = operand1 + operand2; - + regs.set(Rd, result); setFlagsForAdd(operand1, operand2); } @@ -260,6 +354,7 @@ private class DataProcessing_Adc extends DataProcessing_Add { protected int cachedOperand1; + protected int cachedOperand2; protected DataProcessing_Adc(int instr) { @@ -307,7 +402,7 @@ return -cachedOperand2; } } - + private class DataProcessing_Rsc extends DataProcessing_Adc { protected DataProcessing_Rsc(int instr) { @@ -319,7 +414,7 @@ return -cachedOperand1; } } - + private class DataProcessing_Tst extends DataProcessing { protected DataProcessing_Tst(int instr) { @@ -328,10 +423,10 @@ @Override public void execute() { - setFlagsForResult(regs.get(Rn) & resolveOperand2()); + setFlagsForResult(resolveOperand1() & resolveOperand2()); } } - + private class DataProcessing_Teq extends DataProcessing { protected DataProcessing_Teq(int instr) { @@ -340,10 +435,10 @@ @Override public void execute() { - setFlagsForResult(regs.get(Rn) ^ resolveOperand2()); + setFlagsForResult(resolveOperand1() ^ resolveOperand2()); } } - + private class DataProcessing_Cmp extends DataProcessing { protected DataProcessing_Cmp(int instr) { @@ -352,10 +447,10 @@ @Override public void execute() { - setFlagsForAdd(regs.get(Rn), -resolveOperand2()); + setFlagsForAdd(resolveOperand1(), -resolveOperand2()); } } - + private class DataProcessing_Cmn extends DataProcessing { protected DataProcessing_Cmn(int instr) { @@ -364,10 +459,10 @@ @Override public void execute() { - setFlagsForAdd(regs.get(Rn), resolveOperand2()); + setFlagsForAdd(resolveOperand1(), resolveOperand2()); } } - + private class DataProcessing_Orr extends DataProcessing { protected DataProcessing_Orr(int instr) { @@ -376,12 +471,12 @@ @Override public void execute() { - int result = regs.get(Rn) | resolveOperand2(); + int result = resolveOperand1() | resolveOperand2(); regs.set(Rd, result); setFlagsForResult(result); } } - + private class DataProcessing_Mov extends DataProcessing { protected DataProcessing_Mov(int instr) { @@ -395,7 +490,7 @@ setFlagsForResult(result); } } - + private class DataProcessing_Bic extends DataProcessing { protected DataProcessing_Bic(int instr) { @@ -404,12 +499,12 @@ @Override public void execute() { - int result = regs.get(Rn) & (~resolveOperand2()); + int result = resolveOperand1() & (~resolveOperand2()); regs.set(Rd, result); setFlagsForResult(result); } } - + private class DataProcessing_Mvn extends DataProcessing { protected DataProcessing_Mvn(int instr) { @@ -424,125 +519,175 @@ } } - private class Swap extends ARM_Instructions.Swap implements Interpreter.Instruction { + private class DataProcessing_Clz extends DataProcessing { + protected DataProcessing_Clz(int instr) { + super(instr); + } + + @Override + public void execute() { + int result = Integer.numberOfLeadingZeros(resolveOperand1()); + regs.set(Rd, result); + } + } + + private class Swap extends ARM_Instructions.Swap implements + ARM_Instruction { + public Swap(int instr) { super(instr); } 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)); } public int getSuccessor(int pc) { - return pc+4; + return pc + 4; } } - - private class BlockDataTransfer extends ARM_Instructions.BlockDataTransfer implements Interpreter.Instruction { + private class BlockDataTransfer extends ARM_Instructions.BlockDataTransfer + implements ARM_Instruction { + + /** the lowest address that we're reading a register from / writing a register to */ + private final int startAddress; + + /** An array that contains the registers to be transferd in ascending order. + * The list is delimited by setting the entry after the last register index to -1. + * The PC is not included in this list, if it shall be transferred. */ + private final int[] registersToTransfer = new int[16]; + + /** True if the PC should be transferred to, false otherwise. */ + private final boolean transferPC; + public BlockDataTransfer(int instr) { super(instr); - } - public void execute() { - //start address ignores the last two bits - int startAddress = regs.get(baseRegister) & 0xFFFFFFFC; + transferPC = transferRegister(15); + int registerCount = 0; - //build a map of registers that are to be transfered - int registerCount = 0; - boolean transferPC = false; - int[] registersToTransfer = new int[16]; - for (int i = 0; i < 14; i++) if (transferRegister(i)) { registersToTransfer[registerCount++] = i; } - - //also remember if we're supposed to transfer the pc, but don't include it in the register list - transferPC = transferRegister(15); - + + registersToTransfer[registerCount] = -1; + + //build the address, which generally ignores the last two bits if (!incrementBase) { - if (postIndexing) - startAddress -= (registerCount + (transferPC ? -1 : 0)) * 4; //post-indexing, backward reading - else - startAddress -= (registerCount + (transferPC ? 1 : 0)) * 4; //pre-indexing, backward-reading + if (postIndexing) { + //post-indexing, backward reading + startAddress = regs.get(baseRegister) & 0xFFFFFFFC + - (registerCount + (transferPC ? -1 : 0)) * 4; + } else { + //pre-indexing, backward-reading + startAddress = regs.get(baseRegister) & 0xFFFFFFFC + - (registerCount + (transferPC ? 1 : 0)) * 4; + } + } else { + if (postIndexing) { + //post-indexing, forward reading + startAddress = regs.get(baseRegister) & 0xFFFFFFFC - 4; + } else { + //pre-indexing, forward reading + startAddress = regs.get(baseRegister) & 0xFFFFFFFC; + } } - else if (postIndexing) { - //post-indexing, forward reading - startAddress -= 4; - } - + } + + public void execute() { + int nextAddress = startAddress; + //are we supposed to load or store multiple registers? if (isLoad) { - //read the actual registers - for (int i = 0; i < registerCount; i++) { - startAddress += 4; - regs.set(registersToTransfer[i], ps.memory.load32(startAddress)); + int nextReg = 0; + + while (registersToTransfer[nextReg] != -1) { + nextAddress += 4; + regs.set(registersToTransfer[nextReg++], ps.memory + .load32(nextAddress)); } - + //if we also transferred the program counter if (transferPC) { - int newpc = ps.memory.load32(startAddress + 4); + nextAddress += 4; + int newpc = ps.memory.load32(nextAddress); regs.set(ARM_Registers.PC, newpc & 0xFFFFFFFE); - + //shall we switch to thumb mode regs.setThumbMode((newpc & 0x1) != 0); } - } - else { + } else { + int nextReg = 0; + + while (registersToTransfer[nextReg] != -1) { + nextAddress += 4; + ps.memory.store32(nextAddress, regs + .get(registersToTransfer[nextReg++])); + } + //also transfer the program counter, if requested so - if (transferPC) - registersToTransfer[registerCount++] = 15; - - for (int i = 0; i < registerCount; i++) { - startAddress += 4; - ps.memory.store32(startAddress, regs.get(i)); + if (transferPC) { + nextAddress += 4; + ps.memory.store32(nextAddress, regs.get(15)); } } + + if (writeBack) { + //write the last address we read from back to a register + //TODO: Check if we have to consider the different cases? + if (!incrementBase) + nextAddress = startAddress; + + regs.set(baseRegister, nextAddress); + } } public int getSuccessor(int pc) { //if we're loading values into the PC, then we can't tell where this instruction will be going - if (isLoad && transferRegister(ARM_Registers.PC)) + if (isLoad && transferPC) return -1; else - return pc+4; + return pc + 4; } } - - private class Branch extends ARM_Instructions.Branch implements Interpreter.Instruction { + private class Branch extends ARM_Instructions.Branch implements + ARM_Instruction { + public Branch(int instr) { super(instr); } public void execute() { int previousAddress = regs.get(ARM_Registers.PC); - + //jump to the new address regs.set(ARM_Registers.PC, previousAddress + getOffset()); - + //if we're supposed to link, then write the previous address into the link register if (link) regs.set(ARM_Registers.LR, previousAddress + 4); } public int getSuccessor(int pc) { - return pc + getOffset(); + return pc + getOffset() + 8; } } - - private class BranchExchange extends ARM_Instructions.BranchExchange implements Interpreter.Instruction { + private class BranchExchange extends ARM_Instructions.BranchExchange + implements ARM_Instruction { + public BranchExchange(int instr) { super(instr); } @@ -551,13 +696,13 @@ int previousAddress = regs.get(ARM_Registers.PC); boolean thumb; int targetAddress; - + switch (target.getType()) { case PcRelative: targetAddress = previousAddress + target.getOffset(); thumb = true; break; - + case Register: targetAddress = regs.get(target.getRegister()); thumb = (targetAddress & 0x1) != 0; @@ -565,13 +710,14 @@ break; default: - throw new RuntimeException("Unexpected Operand type: " + target.getType()); + throw new RuntimeException("Unexpected Operand type: " + + target.getType()); } - + //jump to the new address regs.set(ARM_Registers.PC, targetAddress); regs.setThumbMode(thumb); - + //if we're supposed to link, then write the previous address into the link register if (link) regs.set(ARM_Registers.LR, previousAddress + 4); @@ -581,55 +727,41 @@ //if we're jumping relative to the PC, then we can predict the next instruction if (target.getType() == OperandWrapper.Type.PcRelative) { return pc + target.getOffset(); - } - else { + } else { //otherwise we can't predict it return -1; } } } - - private class CountLeadingZeros extends ARM_Instructions.CountLeadingZeros implements Interpreter.Instruction { - public CountLeadingZeros(int instr) { - super(instr); - } + private class IntMultiply extends ARM_Instructions.IntMultiply implements + ARM_Instruction { - public void execute() { - int leadingZeros = Integer.numberOfLeadingZeros(regs.get(Rm)); - regs.set(Rd, leadingZeros); - } - - public int getSuccessor(int pc) { - return pc+4; - } - } - - private class IntMultiply extends ARM_Instructions.IntMultiply implements Interpreter.Instruction { - protected IntMultiply(int instr) { super(instr); } public void execute() { int result = regs.get(Rm) * regs.get(Rs); - + if (accumulate) result += regs.get(Rn); - + regs.set(Rd, result); - + if (updateConditionCodes) { regs.setFlags(result < 0, result == 0); } } public int getSuccessor(int pc) { - return pc+4; + return pc + 4; } } - private class MoveFromStatusRegister extends ARM_Instructions.MoveFromStatusRegister implements Interpreter.Instruction { + private class MoveFromStatusRegister extends + ARM_Instructions.MoveFromStatusRegister implements + ARM_Instruction { public MoveFromStatusRegister(int instr) { super(instr); @@ -637,24 +769,24 @@ public void execute() { int statusRegisterValue; - + if (transferSavedPSR) { statusRegisterValue = regs.getSPSR(); - } - else { + } else { statusRegisterValue = regs.getCPSR(); } - + regs.set(Rd, statusRegisterValue); } public int getSuccessor(int pc) { - return pc+4; + return pc + 4; } } - - private class SoftwareInterrupt extends ARM_Instructions.SoftwareInterrupt implements Interpreter.Instruction { + private class SoftwareInterrupt extends ARM_Instructions.SoftwareInterrupt + implements ARM_Instruction { + public SoftwareInterrupt(int instr) { super(instr); } @@ -666,33 +798,172 @@ public int getSuccessor(int pc) { return -1; } - + } - - private class SingleDataTransfer extends ARM_Instructions.SingleDataTransfer implements Interpreter.Instruction { + private class SingleDataTransfer extends ARM_Instructions.SingleDataTransfer + implements ARM_Instruction { + public SingleDataTransfer(int instr) { super(instr); } - public void execute() { + private int resolveAddress() { + + //acquire the base address + int base = regs.get(Rn); + //take ARM's PC offset into account + if (Rn == 15) + base += 8; + + //if we are not pre-indexing, then just use the base register for the memory access + if (!preIndexing) + return base; + + switch (offset.getType()) { + case Immediate: + if (positiveOffset) + return base + offset.getImmediate(); + else + return base - offset.getImmediate(); + + case Register: + int offsetRegister = regs.get(offset.getRegister()); + if (offset.getRegister() == ARM_Registers.PC) { + offsetRegister += 8; + } + + if (positiveOffset) + return base + offsetRegister; + else + return base - offsetRegister; + + case ImmediateShiftedRegister: + if (offset.getRegister() == 15) + throw new RuntimeException( + "PC-relative memory accesses are not yet supported."); + + int addrOffset = regs.get(offset.getRegister()); + + 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()); + } + + case PcRelative: + case RegisterShiftedRegister: + default: + throw new RuntimeException("Unexpected operand type: " + + offset.getType()); + } + } + public void execute() { + if (forceUserMode) { + //TODO: Implement user mode memory access + throw new RuntimeException( + "Forced user mode memory access is not yet supported."); + } + + int address = resolveAddress(); + + if (isLoad) { + int value; + + switch (size) { + case Byte: + if (signExtend) + value = ps.memory.loadSigned8(address); + else + value = ps.memory.loadUnsigned8(address); + break; + + case HalfWord: + if (signExtend) + value = ps.memory.loadSigned16(address); + else + value = ps.memory.loadUnsigned16(address); + break; + + case Word: + value = ps.memory.load32(address); + break; + + default: + throw new RuntimeException("Unexpected memory size: " + size); + } + + regs.set(Rd, value); + } else { + int value = regs.get(Rd); + + switch (size) { + case Byte: + ps.memory.store8(address, value); + break; + + case HalfWord: + ps.memory.store16(address, value); + break; + + case Word: + ps.memory.store32(address, value); + break; + + default: + throw new RuntimeException("Unexpected memory size: " + size); + } + } + + if (writeBack) { + if (preIndexing) + regs.set(Rn, address); + else { + //TODO: calculate the post-indexed address + //and set it to Rn + } + } + } + public int getSuccessor(int pc) { //if we're loading to the PC, then the next instruction is undefined - if (Rd == ARM_Registers.PC) + if (Rd == ARM_Registers.PC && isLoad) return -1; - - return pc+4; + + return pc + 4; } - } - - private class UndefinedInstruction implements Interpreter.Instruction { - + + private class UndefinedInstruction implements ARM_Instruction { + private final int instruction; - + public UndefinedInstruction(int instr) { this.instruction = instr; } @@ -704,12 +975,16 @@ public int getSuccessor(int pc) { return -1; } + + public Condition getCondition() { + return Condition.AL; + } } class InterpreterFactory implements - ARM_InstructionFactory<Interpreter.Instruction> { + ARM_InstructionFactory<ARM_Instruction> { - public Interpreter.Instruction createDataProcessing(int instr) { + public ARM_Instruction createDataProcessing(int instr) { Opcode opcode = Opcode.values()[Utils.getBits(instr, 21, 24)]; switch (opcode) { @@ -745,6 +1020,9 @@ return new DataProcessing_Teq(instr); case TST: return new DataProcessing_Tst(instr); + + case CLZ: + return new DataProcessing_Clz(instr); default: throw new RuntimeException("Unexpected Data Procesing opcode: " @@ -752,70 +1030,68 @@ } } - public Instruction createBlockDataTransfer(int instr) { + public ARM_Instruction createBlockDataTransfer(int instr) { return new BlockDataTransfer(instr); } - public Instruction createBranch(int instr) { + public ARM_Instruction createBranch(int instr) { return new Branch(instr); } - public Instruction createBranchExchange(int instr) { + public ARM_Instruction createBranchExchange(int instr) { return new BranchExchange(instr); } - public Instruction createCoprocessorDataProcessing(int instr) { + public ARM_Instruction createCoprocessorDataProcessing(int instr) { //TODO: Implement coprocessor instructions - throw new RuntimeException("Coprocessor instructions are not yet supported."); + throw new RuntimeException( + "Coprocessor instructions are not yet supported."); } - public Instruction createCoprocessorDataTransfer(int instr) { -// TODO: Implement coprocessor instructions - throw new RuntimeException("Coprocessor instructions are not yet supported."); + public ARM_Instruction createCoprocessorDataTransfer(int instr) { + // TODO: Implement coprocessor instructions + throw new RuntimeException( + "Coprocessor instructions are not yet supported."); } - public Instruction createCoprocessorRegisterTransfer(int instr) { -// TODO: Implement coprocessor instructions - throw new RuntimeException("Coprocessor instructions are not yet supported."); + public ARM_Instruction createCoprocessorRegisterTransfer(int instr) { + // TODO: Implement coprocessor instructions + throw new RuntimeException( + "Coprocessor instructions are not yet supported."); } - public Instruction createCountLeadingZeros(int instr) { - return new CountLeadingZeros(instr); - } - - public Instruction createIntMultiply(int instr) { + public ARM_Instruction createIntMultiply(int instr) { return new IntMultiply(instr); } - public Instruction createLongMultiply(int instr) { + public ARM_Instruction createLongMultiply(int instr) { throw new RuntimeException("Long Multiplications are not yet supported."); } - public Instruction createMoveFromStatusRegister(int instr) { + public ARM_Instruction createMoveFromStatusRegister(int instr) { return new MoveFromStatusRegister(instr); } - public Instruction createMoveToStatusRegister(int instr) { + public ARM_Instruction createMoveToStatusRegister(int instr) { //TODO: Implement Register -> CPSR transfers - throw new RuntimeException("Modifying the status register using MSR is not yet supported."); + throw new RuntimeException( + "Modifying the status register using MSR is not yet supported."); } - public Instruction createSingleDataTransfer(int instr) { - // TODO Auto-generated method stub - return null; + public ARM_Instruction createSingleDataTransfer(int instr) { + return new SingleDataTransfer(instr); } - public Instruction createSoftwareInterrupt(int instr) { + public ARM_Instruction createSoftwareInterrupt(int instr) { return new SoftwareInterrupt(instr); } - public Instruction createSwap(int instr) { + public ARM_Instruction createSwap(int instr) { return new Swap(instr); } - public Instruction createUndefinedInstruction(int instr) { + public ARM_Instruction createUndefinedInstruction(int instr) { return new UndefinedInstruction(instr); } } - } Modified: src/org/binarytranslator/arch/arm/decoder/Utils.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-04-18 17:40:18 UTC (rev 69) @@ -20,7 +20,8 @@ } /** - * Extracts a subsequence of bits from a word. + * Extracts a subsequence of bits from a word and shifts the beginning of that subsequence to + * a zero based-number. * A call to <code>getBits(0xFF, 2, 3)</code> would return 0x3. * @param word * The word that is to be examined. @@ -33,7 +34,8 @@ */ static final int getBits(int word, int from, int to) { if (DBT.VerifyAssertions) - DBT._assert(from < to && from >= 0 && to <= 31); + DBT._assert(from < to && from >= 0 && to < 31); + return (word & ((1 << (to + 1)) - 1)) >> from; } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-18 17:40:18 UTC (rev 69) @@ -2,10 +2,11 @@ import java.io.IOException; import org.binarytranslator.DBT_Options; +import org.binarytranslator.arch.arm.decoder.ARM_Interpreter; import org.binarytranslator.arch.arm.os.process.image.ARM_ImageProcessSpace; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; -import org.binarytranslator.generic.fault.BadInstructionException; -import org.binarytranslator.generic.memory.ByteAddressedMemory; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.DebugMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; @@ -14,18 +15,10 @@ public abstract class ARM_ProcessSpace extends ProcessSpace { - /* - * Instance data - */ - /** - * Registers used by this process - */ + /** Registers used by this process */ public ARM_Registers registers; - /* - * Utility functions - */ /** * Debug information @@ -40,16 +33,9 @@ } } - /* - * Methods - */ - - /** - * Constructor - */ protected ARM_ProcessSpace() { registers = new ARM_Registers(); - memory = new ByteAddressedMemory(); + memory = new DebugMemory(); } /** @@ -82,13 +68,10 @@ return new ARM_ImageProcessSpace(); } } - - /** - * Run a single instruction - */ - public void runOneInstruction() throws BadInstructionException { - // TODO - throw new RuntimeException("Not yet implemented"); + + @Override + public Interpreter createInstructionInterpreter() throws UnsupportedOperationException { + return new ARM_Interpreter(this); } /** Modified: src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-18 14:34:18 UTC (rev 68) +++ src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-18 17:40:18 UTC (rev 69) @@ -198,5 +198,20 @@ public boolean isCarrySet() { return flagCarry; } + + /** Returns true if the zero flag is set, false otherwise. */ + public boolean isZeroSet() { + return flagZero; + } + + /** Returns true if the overflow flag is set, false otherwise. */ + public boolean isOverflowSet() { + return flagOverflow; + } + + /** Returns true if the negative flag is set, false otherwise. */ + public boolean isNegativeSet() { + return flagNegative; + } } Added: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java (rev 0) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-04-18 17:40:18 UTC (rev 69) @@ -0,0 +1,31 @@ +package org.binarytranslator.generic.execution; + +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public class InterpreterController extends ExecutionController { + + public InterpreterController(ProcessSpace ps) { + super(ps); + } + + @Override + public void run() { + Interpreter interpreter = ps.createInstructionInterpreter(); + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + + Interpreter.Instruction instruction = interpreter.decode(pc); + pc = instruction.getSuccessor(pc); + + System.out.println("Interpreting instruction: " + instruction.toString()); + + instruction.execute(); + + if (pc == -1) + pc = ps.getCurrentInstructionAddress(); + } + } + +} Added: src/org/binarytranslator/generic/memory/DebugMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/DebugMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/DebugMemory.java 2007-04-18 17:40:18 UTC (rev 69) @@ -0,0 +1,539 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.vmInterface.TranslationHelper; +import org.jikesrvm.compilers.opt.ir.OPT_Operand; +import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; + +/** + * A copy of byte-addressed memory, that does not allow the translation of accesses to bytecode. + * This is stricly for debugging purposes, as it allows the Pearcolator interpreter to be executed + * in a windows environment. + */ +public class DebugMemory extends Memory { + /** + * The size of pages + */ + private static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + private static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + private static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private byte readableMemory[][]; + + private byte writableMemory[][]; + + private byte executableMemory[][]; + + /** + * Do we have more optimal nio mmap operation? + */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public DebugMemory() { + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if ((readableMemory[i] == null) && (writableMemory[i] == null) + && (executableMemory[i] == null)) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if ((readableMemory[i] != null) || (writableMemory[i] != null) + || (executableMemory[i] != null)) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.err.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if ((readableMemory[pte + i] != null) + || (writableMemory[pte + i] != null) + || (executableMemory[pte + i] != null)) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate pages + if (read) { + readableMemory[pte + i] = pages[i]; + } + if (write) { + writableMemory[pte + i] = pages[i]; + } + if (exec) { + executableMemory[pte + i] = pages[i]; + } + } + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + 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; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.err.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if ((readableMemory[pte + i] != null) + || (writableMemory[pte + i] != null) + || (executableMemory[pte + i] != null)) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + if (read) { + readableMemory[pte + i] = page; + } + if (write) { + writableMemory[pte + i] = page; + } + if (exec) { + executableMemory[pte + i] = page; + } + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if ((readableMemory[pte + i] != null) + || (writableMemory[pte + i] != null) + || (executableMemory[pte + i] != null)) { + 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), + P... [truncated message content] |