-// 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.*;
-// 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;
/**
--- /dev/null
+// 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");
+ }
+}
-// 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.*;
-// 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.*;
-// 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 {
-// 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.*;
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 {
-// 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. */
-// 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.*;
-// 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;
/**
-// 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.*;
/** 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 */
-// 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.*;
--- /dev/null
+// 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); }
+ }
+
+}
-// 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.*;
-// 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.*;
-// 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.*;
-// 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.*;
-// 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;
-// 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.*;
-// 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.*;
-// 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.*;
-// 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 */
-// 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.*;
-// 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.*;
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;
// 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.*;
// 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;
public static void main(String[] s) throws IOException {
if (s.length != 2) {
- System.err.println("usage: java " + MIPS.class.getName() + " <classname> <binary.mips>");
+ System.err.println("usage: java " + Compiler.class.getName() + " <classname> <binary.mips>");
System.exit(-1);
}
--- /dev/null
+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.phnum;i++) {
+ fd.seek(header.phoff+i*header.phentsize);
+ pheaders[i] = new PHeader();
+ }
+ sheaders = new SHeader[header.shnum];
+ for(int i=0;i<header.shnum;i++) {
+ fd.seek(header.shoff+i*header.shentsize);
+ sheaders[i] = new SHeader();
+ }
+ if(header.shstrndx < 0 || header.shstrndx >= 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;i<header.shnum;i++) {
+ SHeader s = sheaders[i];
+ StringBuffer sb = new StringBuffer();
+ for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
+ s.name = sb.toString();
+ }
+ }
+
+ public SHeader sectionWithName(String name) {
+ for(int i=0;i<sheaders.length;i++)
+ if(sheaders[i].name.equals(name))
+ return sheaders[i];
+ return null;
+ }
+
+ public class ELFException extends IOException { ELFException(String s) { super(s); } }
+
+ private class MyRandomAccessFile extends RandomAccessFile {
+ MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
+ public void skipFully(int n) throws IOException {
+ while(n>0) 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<elf.pheaders.length;i++) {
+ ELF.PHeader ph = elf.pheaders[i];
+ System.out.println("PHeader " + toHex(i));
+ System.out.println("\tOffset: " + ph.offset);
+ System.out.println("\tVaddr: " + toHex(ph.vaddr));
+ System.out.println("\tFile Size: " + ph.filesz);
+ System.out.println("\tMem Size: " + ph.memsz);
+ }
+ for(int i=0;i<elf.sheaders.length;i++) {
+ ELF.SHeader sh = elf.sheaders[i];
+ System.out.println("SHeader " + toHex(i));
+ System.out.println("\tName: " + sh.name);
+ System.out.println("\tOffset: " + sh.offset);
+ System.out.println("\tAddr: " + toHex(sh.addr));
+ System.out.println("\tSize: " + sh.size);
+ System.out.println("\tType: " + toHex(sh.type));
+ }
+ }
+}
// Copyright 2003 Adam Megacz
// Author Brian Alliet
-// Based on org.xwt.imp.MIPS by Adam Megacz
-
-package org.xwt.imp;
+// Based on org.xwt.mips.Compiler by Adam Megacz
+package org.xwt.mips;
import java.io.*;
-public class MIPSInterpreter extends MIPSEmu {
+public class Interpreter extends VM {
// Registers
private int[] registers = new int[32];
registers[RA] = 0xdeadbeef;
nextPC = pc;
}
- public MIPSInterpreter() { }
- public MIPSInterpreter(String image) throws IOException { loadImage(image); }
+ public Interpreter() { }
+ public Interpreter(String image) throws IOException { loadImage(image); }
// Debug functions
// NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
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
}
}
-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<STACK_PAGES;i++)
- readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
- }
-
- public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
- int n=0;
- if((addr&3)!=0) {
- int word = memRead(addr&~3);
- switch(addr&3) {
- case 1: a[n++] = (byte)((word>>>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<end;i++,addr+=4) {
- int word = page[i];
- a[n++] = (byte)((word>>>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<end;i++,addr+=4) {
- int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
- page[i] = word;
- }
- }
- if(length-n > 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<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
- if(total > 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<count;i++) {
- byte[] a;
- try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw new Error(e.getMessage()); }
- table[i] = addr;
-
- copyout(a,addr,a.length);
- addr += a.length;
- copyout(nullTerminator,addr,1);
- addr += 1;
-
- }
- addr=start;
- for(int i=0;i<count;i++) {
- memWrite(addr,table[i]);
- addr += 4;
- }
- }
-
- public void setUserInfo(int index, int word) throws EmulationException {
- if(index < 0 || index >= 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;
- int oldBrk = brk;
- int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
- if(newBrk >= BRK_LIMIT) {
- System.err.println("Hit BRK_LIMIT");
- return -ENOMEM;
- }
- for(int i=oldBrk;i<newBrk+256;i++)
- readPages[i] = writePages[i] = emptyPage;
- brk = newBrk;
- return oldBrk<<PAGE_SHIFT;
- }
-
- private int open(int addr, int flags, int mode) {
- final int O_RDONLY = 0;
- final int O_WRONLY = 1;
- final int O_RDWR = 2;
- final int O_APPEND = 0x0008;
- final int O_CREAT = 0x0200;
- final int O_NONBLOCK = 0x4000;
- final int O_EXCL = 0x0800;
-
- if((flags & O_APPEND) != 0) {
- System.err.println("WARNING: O_APPEND not supported");
- return -EOPNOTSUPP;
- }
- if((flags & O_NONBLOCK) != 0) {
- System.err.println("WARNING: O_NONBLOCK not supported");
- return -EOPNOTSUPP;
- }
-
- try {
- int fdn=-1;
- File f = new File(cstring(addr));
- System.err.println("Opening: " + f);
- if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
- if(!f.createNewFile()) return -EEXIST;
- if(f.exists()) {
- if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
- } else {
- if((flags & O_CREAT) == 0) return -ENOENT;
- }
- for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
- if(fdn==-1) return -ENFILE;
- fds[fdn] = new RegularFileDescriptor(f,flags&3);
- return fdn;
- } catch(FaultException e) {
- return -EFAULT;
- } catch(FileNotFoundException e) {
- if(e.getMessage().indexOf("Permission denied") >= 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.phnum;i++) {
- fd.seek(header.phoff+i*header.phentsize);
- pheaders[i] = new PHeader();
- }
- sheaders = new SHeader[header.shnum];
- for(int i=0;i<header.shnum;i++) {
- fd.seek(header.shoff+i*header.shentsize);
- sheaders[i] = new SHeader();
- }
- if(header.shstrndx < 0 || header.shstrndx >= 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;i<header.shnum;i++) {
- SHeader s = sheaders[i];
- StringBuffer sb = new StringBuffer();
- for(int off = s.nameidx;off < a.length && a[off] != 0; off++) sb.append((char)a[off]);
- s.name = sb.toString();
- }
- }
-
- public SHeader sectionWithName(String name) {
- for(int i=0;i<sheaders.length;i++)
- if(sheaders[i].name.equals(name))
- return sheaders[i];
- return null;
- }
-
- public class ELFException extends IOException { ELFException(String s) { super(s); } }
-
- private class MyRandomAccessFile extends RandomAccessFile {
- MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
- public void skipFully(int n) throws IOException {
- while(n>0) 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<elf.pheaders.length;i++) {
- ELF.PHeader ph = elf.pheaders[i];
- System.out.println("PHeader " + toHex(i));
- System.out.println("\tOffset: " + ph.offset);
- System.out.println("\tVaddr: " + toHex(ph.vaddr));
- System.out.println("\tFile Size: " + ph.filesz);
- System.out.println("\tMem Size: " + ph.memsz);
- }
- for(int i=0;i<elf.sheaders.length;i++) {
- ELF.SHeader sh = elf.sheaders[i];
- System.out.println("SHeader " + toHex(i));
- System.out.println("\tName: " + sh.name);
- System.out.println("\tOffset: " + sh.offset);
- System.out.println("\tAddr: " + toHex(sh.addr));
- System.out.println("\tSize: " + sh.size);
- System.out.println("\tType: " + toHex(sh.type));
- }
- }
-}
-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;
-}
--- /dev/null
+package org.xwt.mips;
+import java.io.*;
+
+abstract class VM 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 VM() {
+ readPages = new int[TOTAL_PAGES][];
+ writePages = new int[TOTAL_PAGES][];
+ for(int i=0;i<STACK_PAGES;i++)
+ readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
+ }
+
+ public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
+ int n=0;
+ if((addr&3)!=0) {
+ int word = memRead(addr&~3);
+ switch(addr&3) {
+ case 1: a[n++] = (byte)((word>>>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<end;i++,addr+=4) {
+ int word = page[i];
+ a[n++] = (byte)((word>>>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<end;i++,addr+=4) {
+ int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
+ page[i] = word;
+ }
+ }
+ if(length-n > 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<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
+ if(total > 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<count;i++) {
+ byte[] a;
+ try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw new Error(e.getMessage()); }
+ table[i] = addr;
+
+ copyout(a,addr,a.length);
+ addr += a.length;
+ copyout(nullTerminator,addr,1);
+ addr += 1;
+
+ }
+ addr=start;
+ for(int i=0;i<count;i++) {
+ memWrite(addr,table[i]);
+ addr += 4;
+ }
+ }
+
+ public void setUserInfo(int index, int word) throws EmulationException {
+ if(index < 0 || index >= 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;
+ int oldBrk = brk;
+ int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
+ if(newBrk >= BRK_LIMIT) {
+ System.err.println("Hit BRK_LIMIT");
+ return -ENOMEM;
+ }
+ for(int i=oldBrk;i<newBrk+256;i++)
+ readPages[i] = writePages[i] = emptyPage;
+ brk = newBrk;
+ return oldBrk<<PAGE_SHIFT;
+ }
+
+ private int open(int addr, int flags, int mode) {
+ final int O_RDONLY = 0;
+ final int O_WRONLY = 1;
+ final int O_RDWR = 2;
+ final int O_APPEND = 0x0008;
+ final int O_CREAT = 0x0200;
+ final int O_NONBLOCK = 0x4000;
+ final int O_EXCL = 0x0800;
+
+ if((flags & O_APPEND) != 0) {
+ System.err.println("WARNING: O_APPEND not supported");
+ return -EOPNOTSUPP;
+ }
+ if((flags & O_NONBLOCK) != 0) {
+ System.err.println("WARNING: O_NONBLOCK not supported");
+ return -EOPNOTSUPP;
+ }
+
+ try {
+ int fdn=-1;
+ File f = new File(cstring(addr));
+ System.err.println("Opening: " + f);
+ if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
+ if(!f.createNewFile()) return -EEXIST;
+ if(f.exists()) {
+ if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
+ } else {
+ if((flags & O_CREAT) == 0) return -ENOENT;
+ }
+ for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
+ if(fdn==-1) return -ENFILE;
+ fds[fdn] = new RegularFileDescriptor(f,flags&3);
+ return fdn;
+ } catch(FaultException e) {
+ return -EFAULT;
+ } catch(FileNotFoundException e) {
+ if(e.getMessage().indexOf("Permission denied") >= 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;
+}
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;
-// 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.*;