From: <mic...@us...> - 2007-04-25 19:15:39
|
Revision: 92 http://svn.sourceforge.net/pearcolator/?rev=92&view=rev Author: michael_baer Date: 2007-04-25 12:15:36 -0700 (Wed, 25 Apr 2007) Log Message: ----------- - Added AutoMappingMemory as a decorator, which makes sure that no memory accesses fail due to non-mapped pages. - Partially enabled functions that use the ARM shadow registers. - Cosmetic fixes to the ARM disassembler. - First version of ARM Angel Semihosting ABI that can run a libc program. Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.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/generic/memory/MemoryMapException.java Added Paths: ----------- src/org/binarytranslator/generic/memory/AutoMappingMemory.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-04-25 19:15:36 UTC (rev 92) @@ -185,13 +185,17 @@ } public void visit(DataProcessing instr) { - String mnemonic = instr.getOpcode().name(); + + DataProcessing.Opcode opcode = instr.getOpcode(); + String mnemonic = opcode.name(); mnemonic += cond(instr); String parameters; - - if (instr.getOpcode() == DataProcessing.Opcode.CMN || - instr.getOpcode() == DataProcessing.Opcode.CMP) { + + if (opcode == DataProcessing.Opcode.CMN || + opcode == DataProcessing.Opcode.CMP || + opcode == DataProcessing.Opcode.TST || + opcode == DataProcessing.Opcode.TEQ) { //these functions don't use the destination register and always set the condition codes setResult(String.format("%s r%s, %s", mnemonic, instr.getRn(), operand(instr.getOperand2()))); return; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-25 19:15:36 UTC (rev 92) @@ -197,7 +197,7 @@ } shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >>> shiftAmount; + return value >> shiftAmount; case LSL: @@ -237,7 +237,7 @@ } shifterCarryOut = Utils.getBit(value, shiftAmount - 1); - return value >> shiftAmount; + return value >>> shiftAmount; case ROR: @@ -1014,7 +1014,7 @@ switch (offset.getShiftType()) { case ASR: - addrOffset = addrOffset >>> offset.getShiftAmount(); + addrOffset = addrOffset >> offset.getShiftAmount(); break; case LSL: @@ -1022,7 +1022,7 @@ break; case LSR: - addrOffset = addrOffset >> offset.getShiftAmount(); + addrOffset = addrOffset >>> offset.getShiftAmount(); break; case ROR: Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-04-25 19:15:36 UTC (rev 92) @@ -1,14 +1,17 @@ package org.binarytranslator.arch.arm.os.abi.semihosting; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintStream; import java.io.RandomAccessFile; import java.util.HashMap; import java.util.Map; +import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; @@ -39,20 +42,21 @@ private final ARM_ProcessSpace ps; /** A mapping from file handles to open files. */ - private final Map<Integer, RandomAccessFile> files = new HashMap<Integer, RandomAccessFile>(); + private final Map<Integer, AngelFileStream> files = new HashMap<Integer, AngelFileStream>(); /** The directory in which temporary files are created. Note that the path is expected to end with a path delimiter.*/ private final static String TEMP_FILE_DIR = "/tmp/"; - /** The file handle that is distributed with the next call to {@link #addFile(RandomAccessFile)}*/ - private int nextFileHandle = 0; + /** The file handle that is distributed with the next call to {@link #addFile(RandomAccessFile)}. + * Valid Angle handles are non-zero values (i.e. >= 1).*/ + private int nextFileHandle = 1; /** */ private AngelSystemCall[] sysCalls; public AngelSystemCalls(ARM_ProcessSpace ps) { this.ps = ps; - sysCalls = new AngelSystemCall[0x31]; + sysCalls = new AngelSystemCall[0x32]; sysCalls[0x1] = new Sys_Open(); sysCalls[0x2] = new Sys_Close(); @@ -76,6 +80,7 @@ sysCalls[0x14] = null; //Another undefined call sysCalls[0x15] = new Sys_Get_CmdLine(); sysCalls[0x16] = new Sys_HeapInfo(); + sysCalls[0x18] = new Sys_Exit(); sysCalls[0x30] = new Sys_Elapsed(); sysCalls[0x31] = new Sys_TickFreq(); } @@ -93,20 +98,20 @@ } /** Add a file to the open file table and return its handle. */ - private int addFile(RandomAccessFile file) { + private int addFile(AngelFileStream file) { int handle = nextFileHandle++; files.put(handle, file); return handle; } /** Returns the file associated with an open file handle or null, if that file handle does not exist. */ - private RandomAccessFile getFile(int handle) { + private AngelFileStream getFile(int handle) { return files.get(handle); } private boolean closeFile(int handle) { try { - RandomAccessFile file = files.get(handle); + AngelFileStream file = files.get(handle); file.close(); return true; } @@ -118,6 +123,133 @@ } } + private interface AngelFileStream { + + boolean isTty(); + int getLength(); + void close(); + + int read() throws IOException; + int read(byte[] buffer) throws IOException; + + void write(int b) throws IOException; + void write(byte[] buffer) throws IOException; + + void seek(long pos) throws IOException; + } + + private class ConsoleStream implements AngelFileStream { + + private String previousInputLine = null; + + public void close() { + throw new RuntimeException("The stdin and stdout are not closeable."); + } + + public int getLength() { + return 0; + } + + public boolean isTty() { + return false; + } + + public int read() throws IOException { + return System.in.read(); + } + + public int read(byte[] buffer) throws IOException { + + //do we already have unhandled input? + if (previousInputLine == null) { + //if not, query a line from the prompt + + 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"; + } + + if (DBT.VerifyAssertions) DBT._assert(previousInputLine != null); + + int bytesToRead = Math.min(previousInputLine.length(), buffer.length); + + for (int i = 0; i < bytesToRead; i++) { + buffer[i] = (byte)previousInputLine.charAt(i); + } + + //if we put the complete line into the buffer, then read a new line the next time + if (bytesToRead == previousInputLine.length()) + previousInputLine = null; + + return bytesToRead; + } + + public void seek(long pos) throws IOException { + throw new IOException("The stdin and stdout are not seekable."); + } + + public void write(int b) throws IOException { + System.out.write(b); + } + + public void write(byte[] buffer) throws IOException { + System.out.write(buffer); + } + } + + private class FileStream implements AngelFileStream { + + private final RandomAccessFile file; + + public FileStream(RandomAccessFile file) { + this.file = file; + } + + public void close() { + try { + file.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + public int getLength() { + try { + return (int)file.length(); + } + catch (IOException e) { + e.printStackTrace(); + return 0; + } + } + + public boolean isTty() { + return false; + } + + public int read() throws IOException { + return file.read(); + } + + public int read(byte[] buffer) throws IOException { + return file.read(buffer); + } + + public void seek(long pos) throws IOException { + file.seek(pos); + } + + public void write(int b) throws IOException { + file.write(b); + } + + public void write(byte[] buffer) throws IOException { + file.write(buffer); + } + } + abstract class AngelSystemCall { public abstract void execute(); @@ -149,18 +281,29 @@ @Override public void execute() { int ptrParamBlock = ps.registers.get(1); - int ptrBuffer = ps.memory.loadUnsigned8(ptrParamBlock); - int fileMode = ps.memory.loadUnsigned8(ptrParamBlock + 4); - int length = ps.memory.loadUnsigned8(ptrParamBlock + 8); + int ptrBuffer = ps.memory.load32(ptrParamBlock); + int fileMode = ps.memory.load32(ptrParamBlock + 4); + int length = ps.memory.load32(ptrParamBlock + 8); String fileName = readString(ptrBuffer, length); try { - String openMode = (fileMode >= 4) ? "rw" : "w"; - RandomAccessFile file = new RandomAccessFile(fileName, openMode); + AngelFileStream stream; + //Angel uses a special file called ":tt" to denote stdin / stdout + if (fileName.equals(":tt")) { + //we're supposed to open the console + stream = new ConsoleStream(); + } + else { + //we're supposed to open a file + String openMode = (fileMode >= 4) ? "rw" : "w"; + RandomAccessFile file = new RandomAccessFile(fileName, openMode); + stream = new FileStream(file); + } + //return the file's index within this table as a file handle - setReturn(addFile(file)); + setReturn(addFile(stream)); } catch (FileNotFoundException e) { @@ -187,7 +330,9 @@ public void execute() { int ptrCharToOutput = ps.registers.get(1); char output = (char)ps.memory.loadUnsigned8(ptrCharToOutput); - consoleOutput.print(output); + + if (output != 0) + consoleOutput.print(output); } } @@ -196,7 +341,6 @@ @Override public void execute() { int ptrOutput = ps.registers.get(1); - char output = (char)ps.memory.loadUnsigned8(ptrOutput++); while (output != 0) { @@ -216,12 +360,16 @@ int length = ps.memory.load32(ptrParamBlock + 8); try { - RandomAccessFile file = getFile(fileHandle); + AngelFileStream file = getFile(fileHandle); - while (length != 0) { - file.writeByte(ps.memory.loadUnsigned8(ptrBuffer++)); - length--; - } + //first try to read the whole buffer from memory + byte[] buf = new byte[length]; + + for (int i = 0; i < length; i++) + buf[i] = (byte)ps.memory.loadUnsigned8(ptrBuffer++); + + file.write(buf); + length = 0; } catch (Exception e) {} @@ -239,7 +387,7 @@ int ptrBuffer = ps.memory.load32(ptrParamBlock + 4); int length = ps.memory.load32(ptrParamBlock + 8); - RandomAccessFile file = getFile(fileHandle); + AngelFileStream file = getFile(fileHandle); //fail with EOF if the handle is invalid. Angel does not provide any facilities to //notify about an invalid handle @@ -248,21 +396,28 @@ return; } - int leftToRead = length; - while (leftToRead-- != 0) { - try { - ps.memory.store8(ptrBuffer++, file.readByte()); + byte buf[] = new byte[length]; + try { + int bytesRead = file.read(buf); + + //store the retrieved info into the buffer + for (int i = 0; i < bytesRead; i++) + ps.memory.store8(ptrBuffer++, buf[i]); + + if (bytesRead == length) { + setReturn(0); } - catch (Exception e) { - //did we read any values at all? - if (leftToRead == length) { - setReturn(length); //no, then fail with eof - return; - } + else { + setReturn(bytesRead + 2*length); } + + } catch (IOException e1) { + e1.printStackTrace(); + + //due to us not having a better return code, just return EOF. + setReturn(length); + return; } - - setReturn(length + leftToRead); //otherwise return that we partially filled the buffer } } @@ -303,11 +458,10 @@ int ptrParamBlock = ps.registers.get(1); int fileHandle = ps.memory.load32(ptrParamBlock); - RandomAccessFile file = getFile(fileHandle); + AngelFileStream file = getFile(fileHandle); if (file != null) { - //TODO: Check if the file is an interactive device and return 1 in that case. - setReturn(0); + setReturn( file.isTty() ? 1 : 0 ); } else { setReturn(-1); @@ -323,11 +477,12 @@ int fileHandle = ps.memory.load32(ptrParamBlock); int absolutePosition = ps.memory.load32(ptrParamBlock + 4); - RandomAccessFile file = getFile(fileHandle); + AngelFileStream file = getFile(fileHandle); + try { file.seek(absolutePosition); setReturn(0); - } catch (Exception e) { + } catch (Exception e) { //this path also catches null-pointer exceptions, in case an invalid handle is given setReturn(-1); } } @@ -340,12 +495,12 @@ int ptrParamBlock = ps.registers.get(1); int fileHandle = ps.memory.load32(ptrParamBlock); - RandomAccessFile file = getFile(fileHandle); + AngelFileStream file = getFile(fileHandle); try { - setReturn((int)file.length()); + setReturn(file.getLength()); } - catch (Exception e) { + catch (Exception e) { //this path also catches null-pointer exceptions, in case an invalid handle is given setReturn(-1); } } @@ -516,4 +671,13 @@ setReturn(1000000000); //Return that ticks are measured in nanoseconds } } + + class Sys_Exit extends AngelSystemCall { + + @Override + public void execute() { + ps.finished = true; + } + + } } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-04-25 19:15:36 UTC (rev 92) @@ -61,7 +61,7 @@ public static ProcessSpace createProcessSpaceFromBinary(Loader loader) throws IOException { Loader.ABI abi = loader.getABI(); - if (abi == Loader.ABI.ARM || abi == Loader.ABI.SystemV) { + if (abi == Loader.ABI.ARM) { report("Creating ARM Linux ABI Process space"); return new ARM_LinuxProcessSpace(); } else { Modified: src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-25 19:15:36 UTC (rev 92) @@ -1,13 +1,16 @@ package org.binarytranslator.arch.arm.os.process; +import org.binarytranslator.DBT; import org.jikesrvm.VM; public final class ARM_Registers { - public final static int FP = 11; - public final static int SP = 13; - public final static int LR = 14; - public final static int PC = 15; + /** Symbolic constants for the registers in ARM that have a special function. + * Note that (except for the PC), those registers can also be used as general purpose registers*/ + public final static int FP = 11; //frame pointer + public final static int SP = 13; //stack pointer + public final static int LR = 14; //link register + public final static int PC = 15; //program counter /** * The currently visible ARM general purpose registers. Register 15 also @@ -17,14 +20,19 @@ /** * The ARM features a number of shadow registers, that are mapped into the - * register map depending on the operating mode. It contains 8 registers for - * fast IRQ handlers 3 registers for SWI handlers 3 registers for abort - * handlers 3 registers for irq handlers 3 registers for undefined instruction - * handlers 8 registers for temporarely storing the user mode registers during - * non-user modes + * register map depending on the operating mode. It contains 3 registers for SWI handlers, + * 3 registers for abort handlers, 3 registers for irq handlers, 3 registers for undefined instruction + * handlers, 8 registers for fast IRQ handlers and 7 registers to store the user/system mode registers r8-r14. + * + * The registers are contained in the said order. All modes (except for the user mode) have their SPSR + * stored as the third element (from the beginning of their registers) in this table. */ @SuppressWarnings("unused") - private int shadowRegisters[] = new int[28]; + private int shadowRegisters[] = new int[27]; + + /** As mentioned above, each mode has its SPSR stored as the third element within the {@link #shadowRegisters} + * table. This constant is a "human-redable" representation of this offset. */ + private final int SPSR_OFFSET = 2; /** * The negative flag from the CPSR. @@ -62,29 +70,39 @@ * The operating mode from the CPSR register. Note that only the bottom five * bits of this register may ever be set. */ - private byte operatingMode = OPERATING_MODE_SVC; + private OperatingMode operatingMode = OperatingMode.SVC; /** - * Definition of symbolic constants for all valid operating modes - */ - public final static byte OPERATING_MODE_USR = 0x10; - - public final static byte OPERATING_MODE_FIQ = 0x11; - - public final static byte OPERATING_MODE_IRQ = 0x12; - - public final static byte OPERATING_MODE_SVC = 0x13; - - public final static byte OPERATING_MODE_ABT = 0x17; - - public final static byte OPERATING_MODE_UND = 0x1A; + * Definition of symbolic constants for all valid operating modes. */ + public enum OperatingMode { + USR ((byte) 0x10, (byte) 20), + SYS ((byte) 0x1F, (byte) 25), //System mode is being treated as a mode with two special registers (r13, r14), that it shares with user mode + FIQ ((byte) 0x11, (byte) 12), + IRQ ((byte) 0x12, (byte) 6), + SVC ((byte) 0x13, (byte) 0), + ABT ((byte) 0x17, (byte) 3), + UND ((byte) 0x1A, (byte) 9); + + /** + * Each operating system is identified by 5 bits within the PSR. This values stores the byte + * which identifies this mode within the Program Status Registers (PSR). */ + public final byte PSR_IDENTIFIER; + + /** + * Most operating modes have banked registers, that are stored in the <code>shadowRegisters</code> array. + * This value determines the offset at which the shadowed registers for the said mode are stored. + * */ + private final byte SHADOW_OFFSET; + + private OperatingMode(byte psrIdentifier, byte shadowOffset) { + this.PSR_IDENTIFIER = psrIdentifier; + this.SHADOW_OFFSET = shadowOffset; + } + } /** Is the processor currently in thumb mode? */ private boolean thumbMode = false; - public ARM_Registers() { - } - /** Returns the value of the specified register. */ public int get(int reg) { if (VM.VerifyAssertions) @@ -101,12 +119,106 @@ regs[reg] = value; } + public void switchOperatingMode(OperatingMode newMode) { + + int previous_cpsr = getCPSR(); + + //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); + return; + } + + //in the first step, we're saving all registers of the current operating mode. + //Furthermore, we are restoring all user registers except for r13 and r14. This way of approaching + //the problem has the benefit, that we're only exchanging the registers that we really need to exchange. + //However, we need to remember that user mode r8-r12 have not been saved after performing the first step. + int shadowOffset = operatingMode.SHADOW_OFFSET; + + if (operatingMode == OperatingMode.FIQ) { + //store the extra fiq registers + shadowRegisters[shadowOffset++] = regs[8]; + shadowRegisters[shadowOffset++] = regs[9]; + + //skip the FIQ mode SPSR + if (DBT.VerifyAssertions) DBT._assert(OperatingMode.FIQ.SHADOW_OFFSET - shadowOffset == SPSR_OFFSET); + shadowOffset++; + + shadowRegisters[shadowOffset++] = regs[10]; + shadowRegisters[shadowOffset++] = regs[11]; + shadowRegisters[shadowOffset++] = regs[12]; + + //and restore their corresponding user mode registers + regs[8] = shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 0]; + regs[9] = shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 1]; + regs[10] = shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 2]; + regs[11] = shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 3]; + regs[12] = shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 4]; + } + else if (operatingMode == OperatingMode.USR) { + //skip user mode r8-r12 + shadowOffset += 5; + } + + //store the current mode's r13 and r14 + shadowRegisters[shadowOffset++] = regs[13]; + shadowRegisters[shadowOffset] = regs[14]; + + //Up to there, we have saved the current mode's registers and restored user mode r8-r12. + //Now, load the new mode's registers. However, remember that though r8-r12 are currently in the register map, + //they have not been saved to the shadowMap. So, if the new mode needs r8-r12, then it + //has to save them first. + shadowOffset = newMode.SHADOW_OFFSET; + + if (newMode == OperatingMode.FIQ) { + //if we're switching to FIQ mode, then remember that we also have to save the (previously unsaved) + //r8-r12 registers + shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 0] = regs[8]; + shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 1] = regs[9]; + shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 2] = regs[10]; + shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 3] = regs[11]; + shadowRegisters[OperatingMode.USR.SHADOW_OFFSET + 4] = regs[12]; + + //then load in the FIQ mode's r8-r12 + regs[8] = shadowRegisters[shadowOffset++]; + regs[9] = shadowRegisters[shadowOffset++]; + + //skip the shadow mode SPSR + if (DBT.VerifyAssertions) DBT._assert(OperatingMode.FIQ.SHADOW_OFFSET - shadowOffset == SPSR_OFFSET); + shadowOffset++; + + regs[10] = shadowRegisters[shadowOffset++]; + regs[11] = shadowRegisters[shadowOffset++]; + regs[12] = shadowRegisters[shadowOffset++]; + } + else if (operatingMode == OperatingMode.USR) { + //skip these shadow registers for now + shadowOffset += 5; + } + + //now load the remaining r13 and r14 registers + regs[13] = shadowRegisters[shadowOffset++]; + regs[14] = shadowRegisters[shadowOffset]; + + //perform the actual mode switch + operatingMode = newMode; + + //save the previous CPSR as the current SPSR + setSPSR(previous_cpsr); + } + + /** * Restores the saved program status register of the current operating mode to the CPSR, * thereby effectively switching to a different operating mode. */ public void restoreSPSR2CPSR() { - if (VM.VerifyAssertions) VM._assert(operatingMode != OPERATING_MODE_USR && operatingMode != OPERATING_MODE_SVC); + if (VM.VerifyAssertions) VM._assert(operatingMode != OperatingMode.USR); setFlagsFromCPSR(getSPSR()); } @@ -115,18 +227,39 @@ * Returns the content of ARM's Current Program Status Register. * * @return + * A integer, containing a bit representation that is equal to what the current processor state + * would look like on the ARM processor. */ public int getCPSR() { return (flagNegative ? 1 << 31 : 0) | (flagZero ? 1 << 30 : 0) | (flagCarry ? 1 << 29 : 0) | (flagOverflow ? 1 << 28 : 0) | (flagIRQsDisabled ? 1 << 7 : 0) | (flagFIQsDisabled ? 1 << 6 : 0) - | (thumbMode ? 1 << 5 : 0) | operatingMode; + | (thumbMode ? 1 << 5 : 0) | operatingMode.PSR_IDENTIFIER; } /** Returns the content of the current mode's Saved Program Status register.*/ public int getSPSR() { - throw new RuntimeException("Accessing the SPSR is not yet implemented"); + if (operatingMode == OperatingMode.USR || operatingMode == OperatingMode.SYS) { + //these modes don't have a SPSR, so throw an exception + throw new RuntimeException("Cannot read a SPSR in operating mode: " + operatingMode); + } + + 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. @@ -135,7 +268,26 @@ * ARM CPSR register content */ public void setFlagsFromCPSR(int cpsr) { - throw new RuntimeException("Interpreting a previous SPSR is not yet implemented."); + + //extract teh differnet flags from the PSR + flagNegative = (cpsr & 0x80000000) != 0; //bit 31 + flagZero = (cpsr & 0x40000000) != 0; //bit 30 + flagCarry = (cpsr & 0x20000000) != 0; //bit 29 + flagOverflow = (cpsr & 0x10000000) != 0; //bit 28 + flagIRQsDisabled = (cpsr & 0x80) != 0; //bit 7 + flagFIQsDisabled = (cpsr & 0x40) != 0; //bit 6 + thumbMode = (cpsr & 0x20) != 0; //bit 5 + + //extract the new operating mode + byte mode = (byte)(cpsr & 0x1F); + + //then perform a regular mode switch to update the register map + for (OperatingMode opMode : OperatingMode.values()) + if (opMode.PSR_IDENTIFIER == mode) { + switchOperatingMode(opMode); + } + + if (DBT.VerifyAssertions) DBT._assert(operatingMode.PSR_IDENTIFIER == mode); } /** @@ -214,5 +366,4 @@ public boolean isNegativeSet() { return flagNegative; } - } 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-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-04-25 19:15:36 UTC (rev 92) @@ -1,27 +1,62 @@ package org.binarytranslator.arch.arm.os.process.image; -import org.binarytranslator.arch.arm.decoder.ARM2IR; +import org.binarytranslator.DBT; +import org.binarytranslator.arch.arm.decoder.ARM_InstructionDecoder; +import org.binarytranslator.arch.arm.decoder.ARM_Instructions; +import org.binarytranslator.arch.arm.os.abi.semihosting.AngelSystemCalls; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.generic.execution.GdbController.GdbTarget; +import org.binarytranslator.generic.memory.AutoMappingMemory; import org.binarytranslator.generic.os.loader.Loader; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { + + private AngelSystemCalls sysCalls = new AngelSystemCalls(this); + + public ARM_ImageProcessSpace() { + super(); + + //make sure that pages of memory are automatically mapped in as they are requested. + memory = new AutoMappingMemory(memory); + } @Override public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { throw new UnsupportedOperationException("Not yet implemented."); - //return new ARM2IR(context); } @Override public void doSysCall() { - throw new UnsupportedOperationException("Syscalls not supported."); + + //check the SWI instrution to make sure, that we're actually doing an Angel call here + int instruction = memory.loadInstruction32(getCurrentInstructionAddress()); + ARM_Instructions.Instruction instr = ARM_InstructionDecoder.decode(instruction); + + if (DBT.VerifyAssertions) { + if (!(instr instanceof ARM_Instructions.SoftwareInterrupt)) { + throw new Error("The current instruction is not a valid system call."); + } + } + + //Thumb system calls start from 0, while ARM calls start from 0x900000. + //Use a mask to let both calls start from the same address + int sysCallNr = ((ARM_Instructions.SoftwareInterrupt)instr).getInterruptNumber(); + + if (sysCallNr == 0x123456) { + sysCalls.doSysCall(registers.get(0)); + + //simulate a proper return from syscalls + setCurrentInstructionAddress(getCurrentInstructionAddress() + 4); + } + else { + throw new RuntimeException("Non-Angel system calls are not yet supported."); + } } - + @Override public GdbTarget getGdbTarget() { throw new UnsupportedOperationException("GDB not implemented."); Added: src/org/binarytranslator/generic/memory/AutoMappingMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/AutoMappingMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/AutoMappingMemory.java 2007-04-25 19:15:36 UTC (rev 92) @@ -0,0 +1,221 @@ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.vmInterface.TranslationHelper; +import org.jikesrvm.classloader.VM_MethodReference; +import org.jikesrvm.compilers.opt.ir.OPT_Operand; +import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; + +/** + * A memory implementation that will automatically map pages into memory, as soon + * as they are requested. Therefore, this memory never fails with an exception + * due to a non-mapped memory page. + * + * The class is implemented as a decorator, therefore it can work with any underlying + * memory that implements the {@link Memory} interface. However, automatic mapping + * of pages is (at the moment) only supported during interpretation. + * + * @author Michael Baer + * + */ +public class AutoMappingMemory extends Memory { + + private Memory mem; + + public AutoMappingMemory(Memory memoryImplementation) { + this.mem = memoryImplementation; + } + + public boolean equals(Object arg0) { + return mem.equals(arg0); + } + + public VM_MethodReference getMethodRef(int callAddress) { + return mem.getMethodRef(callAddress); + } + + public int getPageSize() { + return mem.getPageSize(); + } + + public int hashCode() { + return mem.hashCode(); + } + + public void initTranslate(TranslationHelper helper) { + mem.initTranslate(helper); + } + + public boolean isMapped(int addr) { + return mem.isMapped(addr); + } + + public boolean isPageAligned(int addr) { + return mem.isPageAligned(addr); + } + + public int load32(int addr) { + try { + return mem.load32(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 4); + return load32(addr); + } + } + + public int loadInstruction32(int addr) { + try { + return mem.loadInstruction32(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 4); + return loadInstruction32(addr); + } + } + + public int loadInstruction8(int addr) { + try { + return mem.loadInstruction8(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 1); + return mem.loadInstruction8(addr); + } + } + + public int loadSigned16(int addr) { + try { + return mem.loadSigned16(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 2); + return mem.loadSigned16(addr); + } + } + + public int loadSigned8(int addr) { + try { + return mem.loadSigned8(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 1); + return mem.loadSigned8(addr); + } + } + + public int loadUnsigned16(int addr) { + try { + return mem.loadUnsigned16(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 2); + return mem.loadUnsigned16(addr); + } + } + + public int loadUnsigned8(int addr) { + try { + return mem.loadUnsigned8(addr); + } + catch (Exception e) { + ensureMapped(addr, addr + 1); + return mem.loadUnsigned8(addr); + } + } + + public int map(int addr, int len, boolean read, boolean write, boolean exec) throws MemoryMapException { + return mem.map(addr, len, read, write, exec); + } + + public int map(RandomAccessFile file, long offset, int addr, int len, boolean read, boolean write, boolean exec) throws MemoryMapException { + return mem.map(file, offset, addr, len, read, write, exec); + } + + public void store16(int addr, int value) { + try { + mem.store16(addr, value); + } + catch (Exception e) { + ensureMapped(addr, addr + 2); + mem.store16(addr, value); + } + } + + public void store32(int addr, int value) { + try { + mem.store32(addr, value); + } + catch (Exception e) { + ensureMapped(addr, addr + 4); + mem.store32(addr, value); + } + } + + public void store8(int addr, int value) { + try { + mem.store8(addr, value); + } + catch (Exception e) { + ensureMapped(addr, addr + 1); + mem.store8(addr, value); + } + } + + public String toString() { + return mem.toString(); + } + + public void translateLoad32(OPT_Operand addr, OPT_RegisterOperand dest) { + //mem.translateLoad32(addr, dest); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateLoadSigned16(OPT_Operand addr, OPT_RegisterOperand dest) { + //mem.translateLoadSigned16(addr, dest); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateLoadSigned8(OPT_Operand addr, OPT_RegisterOperand dest) { + //mem.translateLoadSigned8(addr, dest); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateLoadUnsigned16(OPT_Operand addr, OPT_RegisterOperand dest) { + //mem.translateLoadUnsigned16(addr, dest); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateLoadUnsigned8(OPT_Operand addr, OPT_RegisterOperand dest) { + //mem.translateLoadUnsigned8(addr, dest); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateStore16(OPT_Operand addr, OPT_RegisterOperand src) { + //mem.translateStore16(addr, src); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateStore32(OPT_Operand addr, OPT_RegisterOperand src) { + //mem.translateStore32(addr, src); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public void translateStore8(OPT_Operand addr, OPT_RegisterOperand src) { + //mem.translateStore8(addr, src); + throw new RuntimeException("Automatic mapping of pages during binary translation is currently not provided."); + } + + public int truncateToNextPage(int addr) { + return mem.truncateToNextPage(addr); + } + + public int truncateToPage(int addr) { + return mem.truncateToPage(addr); + } + + public void unmap(int addr, int len) { + mem.unmap(addr, len); + } +} Modified: src/org/binarytranslator/generic/memory/MemoryMapException.java =================================================================== --- src/org/binarytranslator/generic/memory/MemoryMapException.java 2007-04-24 23:01:32 UTC (rev 91) +++ src/org/binarytranslator/generic/memory/MemoryMapException.java 2007-04-25 19:15:36 UTC (rev 92) @@ -13,7 +13,7 @@ /** * Captures exceptions that can occur during memory mangement */ -final public class MemoryMapException extends Exception { +final public class MemoryMapException extends RuntimeException { /** * Attempt to allocate on a non-page boundary */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |