From: megacz Date: Fri, 30 Jan 2004 07:35:49 +0000 (+0000) Subject: 2003/09/19 05:01:37 X-Git-Tag: RC3~603 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=4923e8529bbd51d0d03387d2f08ae08b38d5ef4a;p=org.ibex.core.git 2003/09/19 05:01:37 darcs-hash:20040130073549-2ba56-f15adecf41228362e120f8a6362d3a2b86b955b6.gz --- diff --git a/src/org/xwt/ByteStream.java b/src/org/xwt/ByteStream.java index ced9378..69acc89 100644 --- a/src/org/xwt/ByteStream.java +++ b/src/org/xwt/ByteStream.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; diff --git a/src/org/xwt/DoubleBuffer.java b/src/org/xwt/DoubleBuffer.java index f420875..6529870 100644 --- a/src/org/xwt/DoubleBuffer.java +++ b/src/org/xwt/DoubleBuffer.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; /** diff --git a/src/org/xwt/Glyph.java b/src/org/xwt/Glyph.java new file mode 100644 index 0000000..0a75b0b --- /dev/null +++ b/src/org/xwt/Glyph.java @@ -0,0 +1,29 @@ +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] +package org.xwt; +import org.xwt.translators.*; + +public class Glyph { + char c; + int line_height; // same value for every glyph in font; the max height of all chars + int baseline; // within the picture, this is the y-coordinate of the baseline + int advance; // amount to increment the x-coordinate + Picture p; + + // k1=font.res k2=(c << 16 | pointsize) + private static Cache glyphCache = new Cache(); + + public static Glyph getGlyph(Res res, int pointsize, char c) { + Glyph ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize)); + if (ret != null) return ret; + + // FEATURE: be smarter here + if (c < 256) + org.xwt.translators.Font.renderGlyphs(res, pointsize, 0, 255, glyphCache); + else + org.xwt.translators.Font.renderGlyphs(res, pointsize, (int)c, (int)c, glyphCache); + + ret = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize)); + if (ret != null) return ret; + throw new RuntimeException("renderGlyphs didn't create the glyph we wanted"); + } +} diff --git a/src/org/xwt/HTML.java b/src/org/xwt/HTML.java index 022e7a0..f065f3a 100644 --- a/src/org/xwt/HTML.java +++ b/src/org/xwt/HTML.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.util.*; diff --git a/src/org/xwt/HTTP.java b/src/org/xwt/HTTP.java index b7a3eb8..45c777d 100644 --- a/src/org/xwt/HTTP.java +++ b/src/org/xwt/HTTP.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.net.*; diff --git a/src/org/xwt/ImageDecoder.java b/src/org/xwt/ImageDecoder.java index bfcbc7e..3a4fb6e 100644 --- a/src/org/xwt/ImageDecoder.java +++ b/src/org/xwt/ImageDecoder.java @@ -1,8 +1,9 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; import org.xwt.js.*; import org.xwt.util.*; +import org.xwt.translators.*; /** Interface implemented by classes capable of decoding an image file into an int[] */ public abstract class ImageDecoder { diff --git a/src/org/xwt/Main.java b/src/org/xwt/Main.java index 92d0b77..4f7ec28 100644 --- a/src/org/xwt/Main.java +++ b/src/org/xwt/Main.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.net.*; @@ -8,6 +8,7 @@ import java.awt.*; import org.bouncycastle.util.encoders.Base64; import org.xwt.js.*; import org.xwt.util.*; +import org.xwt.translators.*; /** Entry point for the XWT Engine; handles splash screen, initial xwar loading, and argument processing */ public class Main { diff --git a/src/org/xwt/Message.java b/src/org/xwt/Message.java index 53e26cc..30eec80 100644 --- a/src/org/xwt/Message.java +++ b/src/org/xwt/Message.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; /** A simple interface that must be supported by any object inserted into the MessageQueue. */ diff --git a/src/org/xwt/MessageQueue.java b/src/org/xwt/MessageQueue.java index ffbe064..2f444c8 100644 --- a/src/org/xwt/MessageQueue.java +++ b/src/org/xwt/MessageQueue.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.util.*; diff --git a/src/org/xwt/Picture.java b/src/org/xwt/Picture.java index 89db921..1013cc4 100644 --- a/src/org/xwt/Picture.java +++ b/src/org/xwt/Picture.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; /** diff --git a/src/org/xwt/Platform.java b/src/org/xwt/Platform.java index 93d92f7..4426ca9 100644 --- a/src/org/xwt/Platform.java +++ b/src/org/xwt/Platform.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.lang.reflect.*; @@ -211,12 +211,24 @@ public class Platform { /** returns an InputStream to the builtin xwar */ protected InputStream _getBuiltinInputStream() { - return this.getClass().getClassLoader().getResourceAsStream("org/xwt/builtin.xwar"); + try { + return new FileInputStream("builtin.xwar"); + } catch (Exception e) { + Log.log(this, e); + return null; + } + //return this.getClass().getClassLoader().getResourceAsStream("org/xwt/builtin.xwar"); } /** returns an InputStream to the builtin xwar */ protected InputStream _getFreetypeInputStream() { - return this.getClass().getClassLoader().getResourceAsStream("org/xwt/freetype.mips"); + try { + return new FileInputStream("freetype.mips"); + } catch (Exception e) { + Log.log(this, e); + return null; + } + //return this.getClass().getClassLoader().getResourceAsStream("org/xwt/freetype.mips"); } /** returns the value of the environment variable key, or null if no such key exists */ diff --git a/src/org/xwt/Proxy.java b/src/org/xwt/Proxy.java index def26ca..8409fa5 100644 --- a/src/org/xwt/Proxy.java +++ b/src/org/xwt/Proxy.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.net.*; diff --git a/src/org/xwt/Res.java b/src/org/xwt/Res.java new file mode 100644 index 0000000..bf7b6f8 --- /dev/null +++ b/src/org/xwt/Res.java @@ -0,0 +1,58 @@ +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] +package org.xwt; + +import java.io.*; + +/** base class for XWT resources */ +public abstract class Res { + + public abstract InputStream getInputStream(); + public Res getSubResource(String key) { return Null.singleton; } + + public static Res stringToRes(String url) { + if (url.indexOf('!') == -1) + return new Zip(stringToRes(url.substring(0, url.lastIndexOf('!'))), + url.substring(url.lastIndexOf('!') + 1)); + if (url.startsWith("http://")) return new HTTP(url); + if (url.startsWith("https://")) return new HTTP(url); + throw new JS.Exn("invalid resource specifier"); + } + + /** the invalid resource; only causes an error if you actually try to use it */ + public static class Null extends Res { + Null() { } + private static singleton = new Null(); + public InputStream getInputStream() throws JS.Exn { throw new JS.Exn("invalid resource"); } + } + + /** HTTP or HTTPS resource */ + public static class HTTP extends Res { + private String url; + HTTP(String url) { this.url = url; } + public InputStream getInputStream() { return new HTTP(url).GET(); } + public Res getSubResource(String key) { return new HTTP(url + "/" + key); } + } + + /** wrap a Res around a preexisting InputStream */ + public static class IS extends Res { + InputStream parent; + IS(InputStream parent) { this.parent = parent; } + public InputStream getInputStream() { return parent; } + } + + /** "unwrap" a Zip archive */ + public static class Zip extends Res { + private Res parent; + private String path = ""; + Zip(Res parent, String path) { this.parent = parent; this.path = path; } + public InputStream getInputStream() { + ZipInputStream zis = new ZipInputStream(parent.getInputStream()); + ZipEntry ze = zis.getNextEntry(); + while(ze != null && !ze.getName().equals(path)) ze = zis.getNextEntry(); + if (ze == null) throw new JS.Exn("zip file not found in archive"); + return zis; + } + public Res getSubResource(String key) { return new Zip(parent, path + '/' + key); } + } + +} diff --git a/src/org/xwt/Resources.java b/src/org/xwt/Resources.java index 9149790..230f2fd 100644 --- a/src/org/xwt/Resources.java +++ b/src/org/xwt/Resources.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; diff --git a/src/org/xwt/SOAP.java b/src/org/xwt/SOAP.java index 7de30d3..1678068 100644 --- a/src/org/xwt/SOAP.java +++ b/src/org/xwt/SOAP.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; diff --git a/src/org/xwt/SVG.java b/src/org/xwt/SVG.java index 3af7462..9b94609 100644 --- a/src/org/xwt/SVG.java +++ b/src/org/xwt/SVG.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.util.*; diff --git a/src/org/xwt/Static.java b/src/org/xwt/Static.java index 4d6fe81..f762df3 100644 --- a/src/org/xwt/Static.java +++ b/src/org/xwt/Static.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import org.xwt.js.*; diff --git a/src/org/xwt/Surface.java b/src/org/xwt/Surface.java index 0f47dfb..182558c 100644 --- a/src/org/xwt/Surface.java +++ b/src/org/xwt/Surface.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import org.bouncycastle.util.encoders.Base64; diff --git a/src/org/xwt/Template.java b/src/org/xwt/Template.java index 1bf8b2b..ee0bea5 100644 --- a/src/org/xwt/Template.java +++ b/src/org/xwt/Template.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; diff --git a/src/org/xwt/ThreadMessage.java b/src/org/xwt/ThreadMessage.java index 51a4d7a..61e8964 100644 --- a/src/org/xwt/ThreadMessage.java +++ b/src/org/xwt/ThreadMessage.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.util.*; diff --git a/src/org/xwt/Trap.java b/src/org/xwt/Trap.java index a9023e7..5f803cb 100644 --- a/src/org/xwt/Trap.java +++ b/src/org/xwt/Trap.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.util.*; diff --git a/src/org/xwt/Weak.java b/src/org/xwt/Weak.java index 1963061..dc82fed 100644 --- a/src/org/xwt/Weak.java +++ b/src/org/xwt/Weak.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; /** Encapsulates a weak reference; MSJVM and NSJVM don't use the standard Java2 java.lang.ref.WeakReference class */ diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index c4f5fc6..7cef4c2 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; diff --git a/src/org/xwt/XWT.java b/src/org/xwt/XWT.java index 33950f1..8efbc2c 100644 --- a/src/org/xwt/XWT.java +++ b/src/org/xwt/XWT.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; @@ -70,6 +70,10 @@ public final class XWT extends JS.Obj { return null; }}); + super.put("load", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { + return Res.stringToResource(args.elementAt(0).toString()); + }}); + super.put("theme", new JS.Callable() { public Object call(JS.Array args) throws JS.Exn { if (args.length() != 2) return null; if (args.elementAt(0) == null || args.elementAt(1) == null) return null; diff --git a/src/org/xwt/mips/Compiler.java b/src/org/xwt/mips/Compiler.java index bcfc662..f47d160 100644 --- a/src/org/xwt/mips/Compiler.java +++ b/src/org/xwt/mips/Compiler.java @@ -1,5 +1,5 @@ // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] -package org.xwt.imp; +package org.xwt.mips; import java.util.*; import java.io.*; @@ -19,7 +19,7 @@ import java.io.*; // FEATURE: emit bytecode rather than .java code (for on-the-fly classloading without javac present in "real" JVMs) /** reads a fully linked MIPS ELF binary image on stdin; writes a .java file on stdout */ -public class MIPS { +public class Compiler { static String runs = ""; static int last_emit = -1; @@ -27,7 +27,7 @@ public class MIPS { public static void main(String[] s) throws IOException { if (s.length != 2) { - System.err.println("usage: java " + MIPS.class.getName() + " "); + System.err.println("usage: java " + Compiler.class.getName() + " "); System.exit(-1); } diff --git a/src/org/xwt/mips/ELF.java b/src/org/xwt/mips/ELF.java new file mode 100644 index 0000000..50f7ab3 --- /dev/null +++ b/src/org/xwt/mips/ELF.java @@ -0,0 +1,215 @@ +package org.xwt.mips; +import java.io.*; + +class ELF { + private MyRandomAccessFile fd; + + public ELFHeader header; + public PHeader[] pheaders; + public SHeader[] sheaders; + + private boolean sectionReaderActive; + + public class ELFHeader { + byte klass; + byte data; + byte osabi; + byte abiversion; + + public static final short ET_EXEC = 2; + public short type; + public static final short EM_MIPS = 8; + public short machine; + public int version; + public int entry; + public int phoff; + public int shoff; + public int flags; + public short ehsize; + public short phentsize; + public short phnum; + public short shentsize; + public short shnum; + public short shstrndx; + + private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F' + ELFHeader() throws IOException { + if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " ); + klass = fd.readByte(); + data = fd.readByte(); + fd.skipFully(1); // version + osabi = fd.readByte(); + abiversion = fd.readByte(); + fd.skipFully(7); + type = fd.readShort(); + machine = fd.readShort(); + version = fd.readInt(); + entry = fd.readInt(); + phoff = fd.readInt(); + shoff = fd.readInt(); + flags = fd.readInt(); + ehsize = fd.readShort(); + phentsize = fd.readShort(); + phnum = fd.readShort(); + shentsize = fd.readShort(); + shnum = fd.readShort(); + shstrndx = fd.readShort(); + } + } + + public class PHeader { + public int type; + public int offset; + public int vaddr; + public int paddr; + public int filesz; + public int memsz; + public int flags; + public int align; + + public static final int PF_X = 0x1; + public static final int PF_W = 0x2; + public static final int PF_R = 0x4; + + public static final int PT_LOAD = 1; + + PHeader() throws IOException { + type = fd.readInt(); + offset = fd.readInt(); + vaddr = fd.readInt(); + paddr = fd.readInt(); + filesz = fd.readInt(); + memsz = fd.readInt(); + flags = fd.readInt(); + align = fd.readInt(); + if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz"); + } + + public boolean writable() { return (flags & PF_W) != 0; } + + public InputStream getInputStream() throws IOException { + return new BufferedInputStream(new SectionInputStream( + offset,offset+filesz)); + } + } + + public class SHeader { + int nameidx; + public String name; + public int type; + public int flags; + public int addr; + public int offset; + public int size; + public int link; + public int info; + public int addralign; + public int entsize; + + public static final int T_NOBITS = 8; + + SHeader() throws IOException { + nameidx = fd.readInt(); + type = fd.readInt(); + flags = fd.readInt(); + addr = fd.readInt(); + offset = fd.readInt(); + size = fd.readInt(); + link = fd.readInt(); + info = fd.readInt(); + addralign = fd.readInt(); + entsize = fd.readInt(); + } + + public InputStream getInputStream() throws IOException { + return new BufferedInputStream(new SectionInputStream( + offset, type == T_NOBITS ? 0 : offset+size)); + } + } + + public ELF(String file) throws IOException, ELFException { + fd = new MyRandomAccessFile(file,"r"); + header = new ELFHeader(); + pheaders = new PHeader[header.phnum]; + for(int i=0;i= header.shnum) throw new ELFException("Bad shstrndx"); + fd.seek(sheaders[header.shstrndx].offset); + byte[] a = new byte[sheaders[header.shstrndx].size]; + fd.readFully(a); + for(int i=0;i0) n-= skipBytes(n); + } + } + + private class SectionInputStream extends InputStream { + private int pos; + private int maxpos; + SectionInputStream(int start, int end) throws IOException { + if(sectionReaderActive) + throw new IOException("Section reader already active"); + sectionReaderActive = true; + pos = start; + fd.seek(pos); + maxpos = end; + } + + private int bytesLeft() { return maxpos - pos; } + public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; } + public int read(byte[] b, int off, int len) throws IOException { + int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n; + } + public void close() { sectionReaderActive = false; } + } + + private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } + + public static void main(String[] args) throws IOException { + ELF elf = new ELF(args[0]); + System.out.println("Type: " + toHex(elf.header.type)); + System.out.println("Machine: " + toHex(elf.header.machine)); + for(int i=0;i 1.1, however, it is only used for debugging @@ -691,7 +690,7 @@ public class MIPSInterpreter extends MIPSEmu { public static void main(String[] argv) throws Exception { String image = argv[0]; - MIPSInterpreter emu = new MIPSInterpreter(); + Interpreter emu = new Interpreter(); emu.loadImage(image); Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook())); // User data @@ -710,985 +709,4 @@ public class MIPSInterpreter extends MIPSEmu { } } -abstract class MIPSEmu implements Syscalls, Errno { - // Register Names - protected final static int ZERO = 0; // Immutable, hardwired to 0 - protected final static int AT = 1; // Reserved for assembler - protected final static int K0 = 26; // Reserved for kernel - protected final static int K1 = 27; // Reserved for kernel - protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss) - protected final static int SP = 29; // Stack pointer - protected final static int FP = 30; // Frame Pointer - protected final static int RA = 31; // Return Address - - // Return values (caller saved) - protected final static int V0 = 2; - protected final static int V1 = 3; - // Argument Registers (caller saved) - protected final static int A0 = 4; - protected final static int A1 = 5; - protected final static int A2 = 6; - protected final static int A3 = 7; - // Temporaries (caller saved) - protected final static int T0 = 8; - protected final static int T1 = 9; - protected final static int T2 = 10; - protected final static int T3 = 11; - protected final static int T4 = 12; - protected final static int T5 = 13; - protected final static int T6 = 14; - protected final static int T7 = 15; - protected final static int T8 = 24; - protected final static int T9 = 25; - // Saved (callee saved) - protected final static int S0 = 16; - protected final static int S1 = 17; - protected final static int S2 = 18; - protected final static int S3 = 19; - protected final static int S4 = 20; - protected final static int S5 = 21; - protected final static int S6 = 22; - protected final static int S7 = 23; - - // Page Constants - // Page Size: 4k - // Total Pages: 64k - // Maxiumum Addressable memory 256mb - // 1mb of stack space - protected final static int PAGE_SIZE = 4096; - protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2); - protected final static int PAGE_SHIFT = 12; - protected final static int STACK_PAGES = 256; - // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the - // new location of INITIAL_SP - protected final static int TOTAL_PAGES = 65536; - protected final static int BRK_LIMIT = 32768; - // Top page is always empty - // next page down contains command line arguments - protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE; - // next page down contains _user_info data - protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE; - // next page down is the start of the stack - protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE; - // magic page that signified an allocated but empty (untouched) page - private final static int[] emptyPage = new int[0]; - - // Main memory - protected final int[][] readPages; - protected final int[][] writePages; - - // Brk - protected int brk; // PAGE not address - - // Entry point - what start() sets pc to - protected int entryPoint; - - // State constants - public final static int UNINITIALIZED = 0; - public final static int INITIALIZED = 1; - public final static int RUNNING = 2; - public final static int PAUSED = 3; - public final static int DONE = 4; - - // State - protected int state = UNINITIALIZED; - public final int getState() { return state; } - protected int exitStatus; - - // File descriptors - private final static int OPEN_MAX = 256; - private FileDescriptor[] fds; - - // Temporary buffer for read/write operations - private byte[] _byteBuf = null; - private final static int MAX_CHUNK = 4*1024*1024-8; - - // Abstract methods - // This should start executing at pc - public abstract void execute() throws EmulationException; - // This should initialize the cpu registers to point to the entry point - protected abstract void _start(int pc); - - public static final int PID = 1; - - public MIPSEmu() { - readPages = new int[TOTAL_PAGES][]; - writePages = new int[TOTAL_PAGES][]; - for(int i=0;i>>16)&0xff); if(length-n==0) break; - case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break; - case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break; - } - addr = (addr&~3)+4; - } - while(length-n > 3) { - int start = (addr&(PAGE_SIZE-1))>>2; - int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); - int[] page = readPages[addr >>> PAGE_SHIFT]; - if(page == null) throw new ReadFaultException(addr); - if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; } - for(int i=start;i>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff); - a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff); - } - } - if(length-n > 0) { - int word = memRead(addr); - if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff); - if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff); - if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff); - } - } - - public void copyout(byte[] a, int addr, int length) throws FaultException { - int n=0; - if((addr&3)!=0) { - int word = memRead(addr&~3); - switch(addr&3) { - case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break; - case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break; - case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break; - } - memWrite(addr&~3,word); - addr = (addr&~3)+4; - } - - while(length-n > 3) { - int start = (addr&(PAGE_SIZE-1))>>2; - int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); - int[] page = writePages[addr >>> PAGE_SHIFT]; - if(page == null) throw new WriteFaultException(addr); - if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; } - for(int i=start;i 0) { - int word = memRead(addr); - word = (word&0x00ffffff)|((a[n]&0xff)<<24); - if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); } - if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); } - memWrite(addr,word); - } - } - - protected final int memRead(int addr) throws ReadFaultException { - if((addr & 3) != 0) throw new ReadFaultException(addr); - int page = addr >>> PAGE_SHIFT; - int entry = (addr >>> 2) & (PAGE_WORDS-1); - try { - return readPages[page][entry]; - } catch(ArrayIndexOutOfBoundsException e) { - if(page < 0) throw e; // should never happen - if(page > readPages.length) throw new ReadFaultException(addr); - if(readPages[page] != emptyPage) throw e; // should never happen - initPage(page); - return 0; - } catch(NullPointerException e) { - throw new ReadFaultException(addr); - } - } - - protected final void memWrite(int addr, int value) throws WriteFaultException { - if((addr & 3) != 0) throw new WriteFaultException(addr); - int page = addr >>> PAGE_SHIFT; - int entry = (addr>>>2)&(PAGE_WORDS-1); - try { - writePages[page][entry] = value; - } catch(ArrayIndexOutOfBoundsException e) { - if(page < 0) throw e;// should never happen - if(page > writePages.length) throw new WriteFaultException(addr); - if(readPages[page] != emptyPage) throw e; // should never happen - initPage(page); - writePages[page][entry] = value; - } catch(NullPointerException e) { - throw new WriteFaultException(addr); - } - } - - protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; } - - public final int exitStatus() { - if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state"); - return exitStatus; - } - - public final int run(String[] args) throws EmulationException { - start(args); - for(;;) { - execute(); - if(state != PAUSED) break; - System.err.println("WARNING: Pause requested while executing run()"); - try { Thread.sleep(500); } catch(InterruptedException e) { } - } - if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state"); - return exitStatus(); - } - - private void addArgs(String[] args) throws EmulationException { - if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state"); - int count = args.length; - byte[] nullTerminator = new byte[1]; - int total = 4; /* null last table entry */ - for(int i=0;i PAGE_SIZE) throw new EmulationException("Arguments too large"); - int start = ARGS_ADDR; - int addr = start + (count+1)*4; - int[] table = new int[count+1]; - for(int i=0;i= 1024) throw new EmulationException("setUserInfo called with index >= 1024"); - memWrite(USER_INFO_ADDR+index*4,word); - } - - public int getUserInfo(int index) throws EmulationException { - if(index < 0 || index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024"); - return memRead(USER_INFO_ADDR+index*4); - } - - public final void start(String[] args) throws EmulationException { - if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state"); - _start(entryPoint); - addArgs(args); - fds = new FileDescriptor[OPEN_MAX]; - fds[0] = new InputStreamFD(System.in) { public boolean isatty() { return true; } }; - fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } }; - fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } }; - state = PAUSED; - } - - - // Syscalls - private int write(int fdn, int addr, int count) { - int n = 0; - int r; - FileDescriptor fd; - count = Math.min(count,MAX_CHUNK); - try { - fd = fds[fdn]; - if(fd == null || !fd.writable()) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - try { - byte[] buf = byteBuf(count); - copyin(addr,buf,count); - return fd.write(buf,0,count); - } catch(FaultException e) { - System.err.println(e); - return -EFAULT; - } catch(IOException e) { - System.err.println(e); - return -EIO; - } - } - - private int read(int fdn, int addr, int count) { - FileDescriptor fd; - count = Math.min(count,MAX_CHUNK); - try { - fd = fds[fdn]; - if(fd == null || !fd.readable()) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - try { - byte[] buf = byteBuf(count); - int n = fd.read(buf,0,count); - copyout(buf,addr,n); - return n; - } catch(FaultException e) { - System.err.println(e); - return -EFAULT; - } catch(IOException e) { - System.err.println(e); - return -EIO; - } - } - - private int close(int fdn) { - FileDescriptor fd; - try { - fd = fds[fdn]; - if(fd == null) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - fds[fdn] = null; - fd.close(); - return 0; - } - - private int stat(FileInfo fi, int addr) { - int size = fi.size(); - try { - memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16) - memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode - memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16) - memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16) - memWrite(addr+16,size); // st_size - memWrite(addr+20,0); // st_atime - // memWrite(addr+24,0) // st_spare1 - memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime - // memWrite(addr+32,0) // st_spare2 - memWrite(addr+36,0); // st_atime - // memWrite(addr+40,0) // st_spare3 - memWrite(addr+44,512); // st_bklsize; - memWrite(addr+48,(size+511)&(~511)); // st_blocks - // memWrite(addr+52,0) // st_spare4[0] - // memWrite(addr+56,0) // st_spare4[1] - } catch(FaultException e) { - System.err.println(e); - return -EFAULT; - } - return 0; - } - - private int fstat(int fdn, int addr) { - FileDescriptor fd; - try { - fd = fds[fdn]; - if(fd == null) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - return stat(fd.fileInfo(),addr); - } - - public int sbrk(int incr) { - if(incr==0) return brk<>PAGE_SHIFT); - if(newBrk >= BRK_LIMIT) { - System.err.println("Hit BRK_LIMIT"); - return -ENOMEM; - } - for(int i=oldBrk;i= Integer.MAX_VALUE) return -EOPNOTSUPP; - } else { - if((flags & O_CREAT) == 0) return -ENOENT; - } - for(int i=0;i= 0) return -EACCES; - return -ENOENT; - } catch(IOException e) { - return -EIO; - } - } - - private int seek(int fdn, int offset, int whence) { - FileDescriptor fd; - try { - fd = fds[fdn]; - if(fd == null || !fd.readable()) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - try { - return fd.seek(offset,whence); - } catch(IOException e) { - System.err.println(e); - return -EPIPE; - } - } - - // This will only be called by raise() to invoke the default handler - // We don't have to worry about actually delivering the signal - private int kill(int pid, int signal) { - if(pid != PID) return -ESRCH; - if(signal < 0 || signal >= 32) return -EINVAL; - switch(signal) { - case 0: return 0; - case 17: // SIGSTOP - case 18: // SIGTSTP - case 21: // SIGTTIN - case 22: // SIGTTOU - state = PAUSED; - break; - case 19: // SIGCONT - case 20: // SIGCHLD - case 23: // SIGIO - case 28: // SIGWINCH - break; - default: { - String msg = "Terminating on signal: " + signal + "\n"; - exitStatus = 1; - state = DONE; - if(fds[2]==null) { - System.out.print(msg); - } else { - byte[] b = msg.getBytes(); - try { - fds[2].write(b,0,b.length); - } catch(IOException e) { } - } - } - } - return 0; - } - - private int getpid() { return PID; } - - protected int syscall(int syscall, int a, int b, int c, int d) { - switch(syscall) { - case SYS_null: return 0; - case SYS_exit: exitStatus = a; state = DONE; return 0; - case SYS_pause: state = PAUSED; return 0; - case SYS_write: return write(a,b,c); - case SYS_fstat: return fstat(a,b); - case SYS_sbrk: return sbrk(a); - case SYS_open: return open(a,b,c); - case SYS_close: return close(a); - case SYS_read: return read(a,b,c); - case SYS_seek: return seek(a,b,c); - case SYS_kill: return kill(a,b); - case SYS_getpid: return getpid(); - default: - System.err.println("Attempted to use unknown syscall: " + syscall); - return -ENOSYS; - } - } - - // Helper function to read a cstring from main memory - private String cstring(int addr) throws ReadFaultException { - StringBuffer sb = new StringBuffer(); - for(;;) { - int word = memRead(addr&~3); - switch(addr&3) { - case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++; - case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++; - case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++; - case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++; - } - } - } - - // Exceptions - public static class ReadFaultException extends FaultException { - public ReadFaultException(int addr) { super(addr); } - } - public static class WriteFaultException extends FaultException { - public WriteFaultException(int addr) { super(addr); } - } - public static abstract class FaultException extends EmulationException { - private int addr; - public FaultException(int addr) { this.addr = addr; } - public String getMessage() { return "fault at: " + toHex(addr); } - } - public static class EmulationException extends Exception { - public EmulationException() { } - public EmulationException(String s) { super(s); } - } - - // FileInfo classes - used by stat(2) - static class FileInfo { - public static final int S_IFIFO = 0010000; - public static final int S_FCHR = 0020000; - public static final int S_IFDIR = 0040000; - public static final int S_IFREG = 0100000; - - public int size() { return 0; } - public int type() { return S_IFIFO; } - public long modTime() { return 0; } - } - - public static class FileFileInfo extends FileInfo { - public File f; - public FileFileInfo(File f) { this.f = f; } - public int size() { return (int)f.length(); } - public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; } - public long modTime() { return f.lastModified(); } - } - - // File descriptor classes - public static abstract class FileDescriptor { - public boolean readable() { return false; } - public boolean writable() { return false; } - - private static final FileInfo nullFi = new FileInfo(); - private FileInfo fi; - public FileInfo fileInfo() { return fi; } - - FileDescriptor() { this(null); } - FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; } - - public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } - public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } - - public int seek(int n, int whence) throws IOException { return -ESPIPE; } - public boolean isatty() { return false; } - - void close() { } - } - - public static class RegularFileDescriptor extends FileDescriptor { - private int mode; - private RandomAccessFile raf; - public boolean readable() { return mode != 1; } - public boolean writable() { return mode != 0; } - - RegularFileDescriptor(File f,int m) throws IOException { - super(new FileFileInfo(f)); - String mode = m == 0 ? "r" : "rw"; - this.mode = m; - raf = new RandomAccessFile(f,mode); - if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large"); - } - - public int seek(int n, int whence) throws IOException { - final int SEEK_SET = 0; - final int SEEK_CUR = 1; - final int SEEK_END = 2; - - switch(whence) { - case SEEK_SET: break; - case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break; - case SEEK_END: n = (int)(raf.length()+n); break; - default: return -EINVAL; - } - raf.seek(n); - return n; - } - - public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; } - public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; } - - void close() { try { raf.close(); } catch(Exception e) { } } - } - - public class OutputStreamFD extends FileDescriptor { - private OutputStream os; - public boolean writable() { return true; } - public OutputStreamFD(OutputStream os) { this.os = os; } - public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; } - } - - public class InputStreamFD extends FileDescriptor { - private InputStream is; - public boolean readable() { return true; } - public InputStreamFD(InputStream is) { this.is = is; } - public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; } - } - - // Utility functions - private byte[] byteBuf(int size) { - if(_byteBuf==null) _byteBuf = new byte[size]; - else if(_byteBuf.length < size) - _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)]; - return _byteBuf; - } - protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } - protected final static int min(int a, int b) { return a < b ? a : b; } - protected final static int max(int a, int b) { return a > b ? a : b; } -} - -class ELF { - private MyRandomAccessFile fd; - - public ELFHeader header; - public PHeader[] pheaders; - public SHeader[] sheaders; - - private boolean sectionReaderActive; - - public class ELFHeader { - byte klass; - byte data; - byte osabi; - byte abiversion; - - public static final short ET_EXEC = 2; - public short type; - public static final short EM_MIPS = 8; - public short machine; - public int version; - public int entry; - public int phoff; - public int shoff; - public int flags; - public short ehsize; - public short phentsize; - public short phnum; - public short shentsize; - public short shnum; - public short shstrndx; - private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F' - ELFHeader() throws IOException { - if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " ); - klass = fd.readByte(); - data = fd.readByte(); - fd.skipFully(1); // version - osabi = fd.readByte(); - abiversion = fd.readByte(); - fd.skipFully(7); - type = fd.readShort(); - machine = fd.readShort(); - version = fd.readInt(); - entry = fd.readInt(); - phoff = fd.readInt(); - shoff = fd.readInt(); - flags = fd.readInt(); - ehsize = fd.readShort(); - phentsize = fd.readShort(); - phnum = fd.readShort(); - shentsize = fd.readShort(); - shnum = fd.readShort(); - shstrndx = fd.readShort(); - } - } - - public class PHeader { - public int type; - public int offset; - public int vaddr; - public int paddr; - public int filesz; - public int memsz; - public int flags; - public int align; - - public static final int PF_X = 0x1; - public static final int PF_W = 0x2; - public static final int PF_R = 0x4; - - public static final int PT_LOAD = 1; - - PHeader() throws IOException { - type = fd.readInt(); - offset = fd.readInt(); - vaddr = fd.readInt(); - paddr = fd.readInt(); - filesz = fd.readInt(); - memsz = fd.readInt(); - flags = fd.readInt(); - align = fd.readInt(); - if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz"); - } - - public boolean writable() { return (flags & PF_W) != 0; } - - public InputStream getInputStream() throws IOException { - return new BufferedInputStream(new SectionInputStream( - offset,offset+filesz)); - } - } - - public class SHeader { - int nameidx; - public String name; - public int type; - public int flags; - public int addr; - public int offset; - public int size; - public int link; - public int info; - public int addralign; - public int entsize; - - public static final int T_NOBITS = 8; - - SHeader() throws IOException { - nameidx = fd.readInt(); - type = fd.readInt(); - flags = fd.readInt(); - addr = fd.readInt(); - offset = fd.readInt(); - size = fd.readInt(); - link = fd.readInt(); - info = fd.readInt(); - addralign = fd.readInt(); - entsize = fd.readInt(); - } - - public InputStream getInputStream() throws IOException { - return new BufferedInputStream(new SectionInputStream( - offset, type == T_NOBITS ? 0 : offset+size)); - } - } - - public ELF(String file) throws IOException, ELFException { - fd = new MyRandomAccessFile(file,"r"); - header = new ELFHeader(); - pheaders = new PHeader[header.phnum]; - for(int i=0;i= header.shnum) throw new ELFException("Bad shstrndx"); - fd.seek(sheaders[header.shstrndx].offset); - byte[] a = new byte[sheaders[header.shstrndx].size]; - fd.readFully(a); - for(int i=0;i0) n-= skipBytes(n); - } - } - - private class SectionInputStream extends InputStream { - private int pos; - private int maxpos; - SectionInputStream(int start, int end) throws IOException { - if(sectionReaderActive) - throw new IOException("Section reader already active"); - sectionReaderActive = true; - pos = start; - fd.seek(pos); - maxpos = end; - } - - private int bytesLeft() { return maxpos - pos; } - public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.read(); if(b >= 0) pos++; return b; } - public int read(byte[] b, int off, int len) throws IOException { - int n = fd.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n; - } - public void close() { sectionReaderActive = false; } - } - - private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } - - public static void main(String[] args) throws IOException { - ELF elf = new ELF(args[0]); - System.out.println("Type: " + toHex(elf.header.type)); - System.out.println("Machine: " + toHex(elf.header.machine)); - for(int i=0;i>> 2); + protected final static int PAGE_SHIFT = 12; + protected final static int STACK_PAGES = 256; + // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the + // new location of INITIAL_SP + protected final static int TOTAL_PAGES = 65536; + protected final static int BRK_LIMIT = 32768; + // Top page is always empty + // next page down contains command line arguments + protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE; + // next page down contains _user_info data + protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE; + // next page down is the start of the stack + protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE; + // magic page that signified an allocated but empty (untouched) page + private final static int[] emptyPage = new int[0]; + + // Main memory + protected final int[][] readPages; + protected final int[][] writePages; + + // Brk + protected int brk; // PAGE not address + + // Entry point - what start() sets pc to + protected int entryPoint; + + // State constants + public final static int UNINITIALIZED = 0; + public final static int INITIALIZED = 1; + public final static int RUNNING = 2; + public final static int PAUSED = 3; + public final static int DONE = 4; + + // State + protected int state = UNINITIALIZED; + public final int getState() { return state; } + protected int exitStatus; + + // File descriptors + private final static int OPEN_MAX = 256; + private FileDescriptor[] fds; + + // Temporary buffer for read/write operations + private byte[] _byteBuf = null; + private final static int MAX_CHUNK = 4*1024*1024-8; + + // Abstract methods + // This should start executing at pc + public abstract void execute() throws EmulationException; + // This should initialize the cpu registers to point to the entry point + protected abstract void _start(int pc); + + public static final int PID = 1; + + public VM() { + readPages = new int[TOTAL_PAGES][]; + writePages = new int[TOTAL_PAGES][]; + for(int i=0;i>>16)&0xff); if(length-n==0) break; + case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break; + case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break; + } + addr = (addr&~3)+4; + } + while(length-n > 3) { + int start = (addr&(PAGE_SIZE-1))>>2; + int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); + int[] page = readPages[addr >>> PAGE_SHIFT]; + if(page == null) throw new ReadFaultException(addr); + if(page == emptyPage) { addr+=(end-start); n+=(end-start); continue; } + for(int i=start;i>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff); + a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff); + } + } + if(length-n > 0) { + int word = memRead(addr); + if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff); + if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff); + if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff); + } + } + + public void copyout(byte[] a, int addr, int length) throws FaultException { + int n=0; + if((addr&3)!=0) { + int word = memRead(addr&~3); + switch(addr&3) { + case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break; + case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break; + case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break; + } + memWrite(addr&~3,word); + addr = (addr&~3)+4; + } + + while(length-n > 3) { + int start = (addr&(PAGE_SIZE-1))>>2; + int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); + int[] page = writePages[addr >>> PAGE_SHIFT]; + if(page == null) throw new WriteFaultException(addr); + if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; } + for(int i=start;i 0) { + int word = memRead(addr); + word = (word&0x00ffffff)|((a[n]&0xff)<<24); + if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); } + if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); } + memWrite(addr,word); + } + } + + public final int memRead(int addr) throws ReadFaultException { + if((addr & 3) != 0) throw new ReadFaultException(addr); + int page = addr >>> PAGE_SHIFT; + int entry = (addr >>> 2) & (PAGE_WORDS-1); + try { + return readPages[page][entry]; + } catch(ArrayIndexOutOfBoundsException e) { + if(page < 0) throw e; // should never happen + if(page > readPages.length) throw new ReadFaultException(addr); + if(readPages[page] != emptyPage) throw e; // should never happen + initPage(page); + return 0; + } catch(NullPointerException e) { + throw new ReadFaultException(addr); + } + } + + protected final void memWrite(int addr, int value) throws WriteFaultException { + if((addr & 3) != 0) throw new WriteFaultException(addr); + int page = addr >>> PAGE_SHIFT; + int entry = (addr>>>2)&(PAGE_WORDS-1); + try { + writePages[page][entry] = value; + } catch(ArrayIndexOutOfBoundsException e) { + if(page < 0) throw e;// should never happen + if(page > writePages.length) throw new WriteFaultException(addr); + if(readPages[page] != emptyPage) throw e; // should never happen + initPage(page); + writePages[page][entry] = value; + } catch(NullPointerException e) { + throw new WriteFaultException(addr); + } + } + + protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; } + + public final int exitStatus() { + if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state"); + return exitStatus; + } + + public final int run(String[] args) throws EmulationException { + start(args); + for(;;) { + execute(); + if(state != PAUSED) break; + System.err.println("WARNING: Pause requested while executing run()"); + try { Thread.sleep(500); } catch(InterruptedException e) { } + } + if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state"); + return exitStatus(); + } + + private void addArgs(String[] args) throws EmulationException { + if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state"); + int count = args.length; + byte[] nullTerminator = new byte[1]; + int total = 4; /* null last table entry */ + for(int i=0;i PAGE_SIZE) throw new EmulationException("Arguments too large"); + int start = ARGS_ADDR; + int addr = start + (count+1)*4; + int[] table = new int[count+1]; + for(int i=0;i= 1024) throw new EmulationException("setUserInfo called with index >= 1024"); + memWrite(USER_INFO_ADDR+index*4,word); + } + + public int getUserInfo(int index) throws EmulationException { + if(index < 0 || index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024"); + return memRead(USER_INFO_ADDR+index*4); + } + + public final void start(String[] args) throws EmulationException { + if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state"); + _start(entryPoint); + addArgs(args); + fds = new FileDescriptor[OPEN_MAX]; + fds[0] = new InputStreamFD(System.in) { public boolean isatty() { return true; } }; + fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } }; + fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } }; + state = PAUSED; + } + + + // Syscalls + private int write(int fdn, int addr, int count) { + int n = 0; + int r; + FileDescriptor fd; + count = Math.min(count,MAX_CHUNK); + try { + fd = fds[fdn]; + if(fd == null || !fd.writable()) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + try { + byte[] buf = byteBuf(count); + copyin(addr,buf,count); + return fd.write(buf,0,count); + } catch(FaultException e) { + System.err.println(e); + return -EFAULT; + } catch(IOException e) { + System.err.println(e); + return -EIO; + } + } + + private int read(int fdn, int addr, int count) { + FileDescriptor fd; + count = Math.min(count,MAX_CHUNK); + try { + fd = fds[fdn]; + if(fd == null || !fd.readable()) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + try { + byte[] buf = byteBuf(count); + int n = fd.read(buf,0,count); + copyout(buf,addr,n); + return n; + } catch(FaultException e) { + System.err.println(e); + return -EFAULT; + } catch(IOException e) { + System.err.println(e); + return -EIO; + } + } + + private int close(int fdn) { + FileDescriptor fd; + try { + fd = fds[fdn]; + if(fd == null) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + fds[fdn] = null; + fd.close(); + return 0; + } + + private int stat(FileInfo fi, int addr) { + int size = fi.size(); + try { + memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16) + memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode + memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16) + memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16) + memWrite(addr+16,size); // st_size + memWrite(addr+20,0); // st_atime + // memWrite(addr+24,0) // st_spare1 + memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime + // memWrite(addr+32,0) // st_spare2 + memWrite(addr+36,0); // st_atime + // memWrite(addr+40,0) // st_spare3 + memWrite(addr+44,512); // st_bklsize; + memWrite(addr+48,(size+511)&(~511)); // st_blocks + // memWrite(addr+52,0) // st_spare4[0] + // memWrite(addr+56,0) // st_spare4[1] + } catch(FaultException e) { + System.err.println(e); + return -EFAULT; + } + return 0; + } + + private int fstat(int fdn, int addr) { + FileDescriptor fd; + try { + fd = fds[fdn]; + if(fd == null) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + return stat(fd.fileInfo(),addr); + } + + public int sbrk(int incr) { + if(incr==0) return brk<>PAGE_SHIFT); + if(newBrk >= BRK_LIMIT) { + System.err.println("Hit BRK_LIMIT"); + return -ENOMEM; + } + for(int i=oldBrk;i= Integer.MAX_VALUE) return -EOPNOTSUPP; + } else { + if((flags & O_CREAT) == 0) return -ENOENT; + } + for(int i=0;i= 0) return -EACCES; + return -ENOENT; + } catch(IOException e) { + return -EIO; + } + } + + private int seek(int fdn, int offset, int whence) { + FileDescriptor fd; + try { + fd = fds[fdn]; + if(fd == null || !fd.readable()) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + try { + return fd.seek(offset,whence); + } catch(IOException e) { + System.err.println(e); + return -EPIPE; + } + } + + // This will only be called by raise() to invoke the default handler + // We don't have to worry about actually delivering the signal + private int kill(int pid, int signal) { + if(pid != PID) return -ESRCH; + if(signal < 0 || signal >= 32) return -EINVAL; + switch(signal) { + case 0: return 0; + case 17: // SIGSTOP + case 18: // SIGTSTP + case 21: // SIGTTIN + case 22: // SIGTTOU + state = PAUSED; + break; + case 19: // SIGCONT + case 20: // SIGCHLD + case 23: // SIGIO + case 28: // SIGWINCH + break; + default: { + String msg = "Terminating on signal: " + signal + "\n"; + exitStatus = 1; + state = DONE; + if(fds[2]==null) { + System.out.print(msg); + } else { + byte[] b = msg.getBytes(); + try { + fds[2].write(b,0,b.length); + } catch(IOException e) { } + } + } + } + return 0; + } + + private int getpid() { return PID; } + + protected int syscall(int syscall, int a, int b, int c, int d) { + switch(syscall) { + case SYS_null: return 0; + case SYS_exit: exitStatus = a; state = DONE; return 0; + case SYS_pause: state = PAUSED; return 0; + case SYS_write: return write(a,b,c); + case SYS_fstat: return fstat(a,b); + case SYS_sbrk: return sbrk(a); + case SYS_open: return open(a,b,c); + case SYS_close: return close(a); + case SYS_read: return read(a,b,c); + case SYS_seek: return seek(a,b,c); + case SYS_kill: return kill(a,b); + case SYS_getpid: return getpid(); + default: + System.err.println("Attempted to use unknown syscall: " + syscall); + return -ENOSYS; + } + } + + // Helper function to read a cstring from main memory + private String cstring(int addr) throws ReadFaultException { + StringBuffer sb = new StringBuffer(); + for(;;) { + int word = memRead(addr&~3); + switch(addr&3) { + case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++; + case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++; + case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++; + case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++; + } + } + } + + // Exceptions + public static class ReadFaultException extends FaultException { + public ReadFaultException(int addr) { super(addr); } + } + public static class WriteFaultException extends FaultException { + public WriteFaultException(int addr) { super(addr); } + } + public static abstract class FaultException extends EmulationException { + private int addr; + public FaultException(int addr) { this.addr = addr; } + public String getMessage() { return "fault at: " + toHex(addr); } + } + public static class EmulationException extends Exception { + public EmulationException() { } + public EmulationException(String s) { super(s); } + } + + // FileInfo classes - used by stat(2) + static class FileInfo { + public static final int S_IFIFO = 0010000; + public static final int S_FCHR = 0020000; + public static final int S_IFDIR = 0040000; + public static final int S_IFREG = 0100000; + + public int size() { return 0; } + public int type() { return S_IFIFO; } + public long modTime() { return 0; } + } + + public static class FileFileInfo extends FileInfo { + public File f; + public FileFileInfo(File f) { this.f = f; } + public int size() { return (int)f.length(); } + public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; } + public long modTime() { return f.lastModified(); } + } + + // File descriptor classes + public static abstract class FileDescriptor { + public boolean readable() { return false; } + public boolean writable() { return false; } + + private static final FileInfo nullFi = new FileInfo(); + private FileInfo fi; + public FileInfo fileInfo() { return fi; } + + FileDescriptor() { this(null); } + FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; } + + public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } + public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } + + public int seek(int n, int whence) throws IOException { return -ESPIPE; } + public boolean isatty() { return false; } + + void close() { } + } + + public static class RegularFileDescriptor extends FileDescriptor { + private int mode; + private RandomAccessFile raf; + public boolean readable() { return mode != 1; } + public boolean writable() { return mode != 0; } + + RegularFileDescriptor(File f,int m) throws IOException { + super(new FileFileInfo(f)); + String mode = m == 0 ? "r" : "rw"; + this.mode = m; + raf = new RandomAccessFile(f,mode); + if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large"); + } + + public int seek(int n, int whence) throws IOException { + final int SEEK_SET = 0; + final int SEEK_CUR = 1; + final int SEEK_END = 2; + + switch(whence) { + case SEEK_SET: break; + case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break; + case SEEK_END: n = (int)(raf.length()+n); break; + default: return -EINVAL; + } + raf.seek(n); + return n; + } + + public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; } + public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; } + + void close() { try { raf.close(); } catch(Exception e) { } } + } + + public class OutputStreamFD extends FileDescriptor { + private OutputStream os; + public boolean writable() { return true; } + public OutputStreamFD(OutputStream os) { this.os = os; } + public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; } + } + + public class InputStreamFD extends FileDescriptor { + private InputStream is; + public boolean readable() { return true; } + public InputStreamFD(InputStream is) { this.is = is; } + public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; } + } + + // Utility functions + private byte[] byteBuf(int size) { + if(_byteBuf==null) _byteBuf = new byte[size]; + else if(_byteBuf.length < size) + _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)]; + return _byteBuf; + } + protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } + protected final static int min(int a, int b) { return a < b ? a : b; } + protected final static int max(int a, int b) { return a > b ? a : b; } +} + + + +interface Errno { + public static final int EPERM = 1; + public static final int ENOENT = 2; + public static final int ESRCH = 3; + public static final int EINTR = 4; + public static final int EIO = 5; + public static final int ENXIO = 6; + public static final int ENOEXEC = 8; + public static final int EBADF = 9; + public static final int ECHILD = 10; + public static final int EAGAIN = 11; + public static final int ENOMEM = 12; + public static final int EACCES = 13; + public static final int EFAULT = 14; + public static final int ENOTBLK = 15; + public static final int EBUSY = 16; + public static final int EEXIST = 17; + public static final int EXDEV = 18; + public static final int ENODEV = 19; + public static final int ENOTDIR = 20; + public static final int EISDIR = 21; + public static final int EINVAL = 22; + public static final int ENFILE = 23; + public static final int EMFILE = 24; + public static final int ENOTTY = 25; + public static final int ETXTBSY = 26; + public static final int EFBIG = 27; + public static final int ENOSPC = 28; + public static final int ESPIPE = 29; + public static final int EROFS = 30; + public static final int EMLINK = 31; + public static final int EPIPE = 32; + public static final int EDOM = 33; + public static final int ERANGE = 34; + public static final int ENOMSG = 35; + public static final int EIDRM = 36; + public static final int ECHRNG = 37; + public static final int ELNRNG = 41; + public static final int EUNATCH = 42; + public static final int ENOCSI = 43; + public static final int EDEADLK = 45; + public static final int ENOLCK = 46; + public static final int EBADE = 50; + public static final int EBADR = 51; + public static final int EXFULL = 52; + public static final int ENOANO = 53; + public static final int EBADRQC = 54; + public static final int EBADSLT = 55; + public static final int EDEADLOCK = 56; + public static final int EBFONT = 57; + public static final int ENOSTR = 60; + public static final int ENODATA = 61; + public static final int ETIME = 62; + public static final int ENOSR = 63; + public static final int ENONET = 64; + public static final int ENOPKG = 65; + public static final int EREMOTE = 66; + public static final int ENOLINK = 67; + public static final int EADV = 68; + public static final int ESRMNT = 69; + public static final int ECOMM = 70; + public static final int EPROTO = 71; + public static final int EMULTIHOP = 74; + public static final int ELBIN = 75; + public static final int EDOTDOT = 76; + public static final int EBADMSG = 77; + public static final int EFTYPE = 79; + public static final int ENOTUNIQ = 80; + public static final int EBADFD = 81; + public static final int EREMCHG = 82; + public static final int ELIBACC = 83; + public static final int ELIBBAD = 84; + public static final int ELIBSCN = 85; + public static final int ELIBMAX = 86; + public static final int ELIBEXEC = 87; + public static final int ENOSYS = 88; + public static final int ENMFILE = 89; + public static final int ENOTEMPTY = 90; + public static final int ENAMETOOLONG = 91; + public static final int ELOOP = 92; + public static final int EOPNOTSUPP = 95; + public static final int EPFNOSUPPORT = 96; + public static final int ECONNRESET = 104; + public static final int ENOBUFS = 105; + public static final int EAFNOSUPPORT = 106; + public static final int EPROTOTYPE = 107; + public static final int ENOTSOCK = 108; + public static final int ENOPROTOOPT = 109; + public static final int ESHUTDOWN = 110; + public static final int ECONNREFUSED = 111; + public static final int EADDRINUSE = 112; + public static final int ECONNABORTED = 113; + public static final int ENETUNREACH = 114; + public static final int ENETDOWN = 115; + public static final int ETIMEDOUT = 116; + public static final int EHOSTDOWN = 117; + public static final int EHOSTUNREACH = 118; + public static final int EINPROGRESS = 119; + public static final int EALREADY = 120; + public static final int EDESTADDRREQ = 121; + public static final int EMSGSIZE = 122; + public static final int EPROTONOSUPPORT = 123; + public static final int ESOCKTNOSUPPORT = 124; + public static final int EADDRNOTAVAIL = 125; + public static final int ENETRESET = 126; + public static final int EISCONN = 127; + public static final int ENOTCONN = 128; + public static final int ETOOMANYREFS = 129; + public static final int EPROCLIM = 130; + public static final int EUSERS = 131; + public static final int EDQUOT = 132; + public static final int ESTALE = 133; + public static final int ENOTSUP = 134; + public static final int ENOMEDIUM = 135; + public static final int ENOSHARE = 136; + public static final int ECASECLASH = 137; + public static final int EILSEQ = 138; + public static final int EOVERFLOW = 139; + public static final int __ELASTERROR = 2000; +} + +interface Syscalls { + public static final int SYS_null = 0; + public static final int SYS_exit = 1; + public static final int SYS_pause = 2; + public static final int SYS_open = 3; + public static final int SYS_close = 4; + public static final int SYS_read = 5; + public static final int SYS_write = 6; + public static final int SYS_sbrk = 7; + public static final int SYS_fstat = 8; + public static final int SYS_isatty = 9; + public static final int SYS_seek = 10; + public static final int SYS_kill = 11; + public static final int SYS_getpid = 12; +} diff --git a/src/org/xwt/mips/linker.ld b/src/org/xwt/mips/linker.ld index cc6b351..374cf25 100644 --- a/src/org/xwt/mips/linker.ld +++ b/src/org/xwt/mips/linker.ld @@ -1,7 +1,7 @@ SEARCH_DIR(build) ENTRY(_start) -STARTUP(org/xwt/imp/crt0.c.o) -INPUT(org/xwt/imp/syscalls.c.o) +STARTUP(org/xwt/mips/crt0.c.o) +INPUT(org/xwt/mips/syscalls.c.o) GROUP(-lc -lgcc) __DYNAMIC = 0; diff --git a/src/org/xwt/plat/AWT.java b/src/org/xwt/plat/AWT.java index 676378c..760c474 100644 --- a/src/org/xwt/plat/AWT.java +++ b/src/org/xwt/plat/AWT.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt.plat; import org.xwt.*;