cl.addMethod(getCPUState.getMethod());
- // FEATURE: Catch RuntimeException and turn it into a fault exception
MethodGen execute = newMethod(ACC_PROTECTED,Type.VOID,Type.NO_ARGS,"_execute");
selectMethod(execute);
- a(InstructionConstants.ALOAD_0);
- a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
+ InstructionHandle tryStart = a(InstructionConstants.ALOAD_0);
+ InstructionHandle tryEnd = a(fac.createInvoke(fullClassName,"trampoline",Type.VOID,Type.NO_ARGS,INVOKESPECIAL));
a(InstructionConstants.RETURN);
+
+ InstructionHandle catchInsn = a(InstructionConstants.ASTORE_1);
+ a(fac.createNew("org.ibex.nestedvm.Runtime$FaultException"));
+ a(InstructionConstants.DUP);
+ a(InstructionConstants.ALOAD_1);
+ a(fac.createInvoke("org.ibex.nestedvm.Runtime$FaultException","<init>",Type.VOID,new Type[]{new ObjectType("java.lang.RuntimeException")},INVOKESPECIAL));
+ a(InstructionConstants.ATHROW);
+
+ execute.addExceptionHandler(tryStart,tryEnd,catchInsn,new ObjectType("java.lang.RuntimeException"));
execute.setMaxLocals();
execute.setMaxStack();
cl.addMethod(execute.getMethod());
if(pc == -1) throw new Exn("pc modifying insn in delay slot");
int target = (pc&0xf0000000)|(jumpTarget << 2);
emitInstruction(-1,nextInsn,-1);
+ // FIXME: Have a memcpy syscall and just override memcpy in libnestedvm
if(optimizedMemcpy && (target == memcpy || target == memset)) {
a(InstructionConstants.ALOAD_0);
pushRegZ(R+4);
memWrite();
break;
}
- // FEATURE: This need to be atomic if we ever support threads (see SWC0/SC)
+ // This need to be atomic if we ever support threads (see SWC0/SC)
case 48: // LWC0/LL
preSetReg(R+rt);
memRead(R+rs,signedImmediate);
setReg();
break;
- /* FEATURE: This needs to fail (set rt to 0) if the memory location was modified
+ /* This needs to fail (set rt to 0) if the memory location was modified
* between the LL and SC if we every support threads.
*/
case 56: // SWC0/SC
import java.io.*;
import java.util.Arrays;
-// FEATURE: Look over the public API, make sure we're exposing a bare minimum
-// (we might make this an interface in the future)
-
public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** Number of bits to shift to get the page number (1<<<pageShift == pageSize) */
protected final int pageShift;
/** Bottom of region of memory allocated to the stack */
- protected final int stackBottom;
+ private final int stackBottom;
/** Readable main memory pages */
protected int[][] readPages;
boolean closeOnExec[] = new boolean[OPEN_MAX];
/** Pointer to a SecurityManager for this process */
- protected SecurityManager sm;
+ SecurityManager sm;
public void setSecurityManager(SecurityManager sm) { this.sm = sm; }
/** Pointer to a callback for the call_java syscall */
return start;
}
- protected String[] createEnv(String[] extra) { if(extra == null) extra = new String[0]; return extra; }
+ String[] createEnv(String[] extra) { if(extra == null) extra = new String[0]; return extra; }
/** Sets word number <i>index</i> in the _user_info table to <i>word</i>
* The user_info table is a chunk of memory in the program's memory defined by the
return state != PAUSED;
}
- protected static String[] concatArgv(String argv0, String[] rest) {
+ static String[] concatArgv(String argv0, String[] rest) {
String[] argv = new String[rest.length+1];
System.arraycopy(rest,0,argv,1,rest.length);
argv[0] = argv0;
}
/** Hook for subclasses to do their own startup */
- protected void _started() { }
+ void _started() { }
public final int call(String sym, Object[] args) throws CallException, FaultException {
if(state != PAUSED && state != CALLJAVA) throw new IllegalStateException("call() called in inappropriate state");
return cpustate.r[V1];
}
-
- /** Determines if the process can access <i>fileName</i>. The default implementation simply logs
- the request and allows it */
- protected boolean allowFileAccess(String fileName, boolean write) {
- //System.err.println("Allowing " + (write?"write":"read-only") + " access to " + fileName);
- return true;
- }
-
+
/** Allocated an entry in the FileDescriptor table for <i>fd</i> and returns the number.
Returns -1 if the table is full. This can be used by subclasses to use custom file
descriptors */
- public int addFD(FD fd) {
+ public final int addFD(FD fd) {
if(state == EXITED || state == EXECED) throw new IllegalStateException("addFD called in inappropriate state");
int i;
for(i=0;i<OPEN_MAX;i++) if(fds[i] == null) break;
}
/** Closes file descriptor <i>fdn</i> and removes it from the file descriptor table */
- public boolean closeFD(int fdn) {
+ public final boolean closeFD(int fdn) {
if(state == EXITED || state == EXECED) throw new IllegalStateException("closeFD called in inappropriate state");
if(fdn < 0 || fdn >= OPEN_MAX) return false;
if(fds[fdn] == null) return false;
}
/** Duplicates the file descriptor <i>fdn</i> and returns the new fs */
- public int dupFD(int fdn) {
+ public final int dupFD(int fdn) {
int i;
if(fdn < 0 || fdn >= OPEN_MAX) return -1;
if(fds[fdn] == null) return -1;
/** The sbrk syscall. This can also be used by subclasses to allocate memory.
<i>incr</i> is how much to increase the break by */
- public int sbrk(int incr) {
+ public final int sbrk(int incr) {
if(incr < 0) return -ENOMEM;
if(incr==0) return heapEnd;
incr = (incr+3)&~3;
/** The getpid syscall */
private int sys_getpid() { return getPid(); }
- protected int getPid() { return 1; }
+ int getPid() { return 1; }
public static interface CallJavaCB { public int call(int a, int b, int c, int d); }
/** Hook for subclasses to do something when the process exits */
- protected void _exited() { }
+ void _exited() { }
private int sys_exit(int status) {
exitStatus = status;
}
/** Helper function to read a cstring from main memory */
- public String cstring(int addr) throws ReadFaultException {
+ public final String cstring(int addr) throws ReadFaultException {
StringBuffer sb = new StringBuffer();
for(;;) {
int word = memRead(addr&~3);
Seekable seekable() { return null; }
/** Should return true if this is a tty */
- // FEATURE: get rid of the isatty syscall and just do with newlib's dumb isatty.c
+ // FIXME: get rid of the isatty syscall and just do with newlib's dumb isatty.c
public boolean isatty() { return false; }
private FStat cachedFStat = null;
public FStat _fstat() { return new FStat(); }
}
- protected static class StdinFD extends InputStreamFD {
+ static class StdinFD extends InputStreamFD {
public StdinFD(InputStream is) { super(is); }
public void _close() { /* noop */ }
public FStat _fstat() { return new FStat() { public int type() { return S_IFCHR; } }; }
public boolean isatty() { return true; }
}
- protected static class StdoutFD extends OutputStreamFD {
+
+ static class StdoutFD extends OutputStreamFD {
public StdoutFD(OutputStream os) { super(os); }
public void _close() { /* noop */ }
public FStat _fstat() { return new FStat() { public int type() { return S_IFCHR; } }; }
public static final int S_IFREG = 0100000;
public int dev() { return -1; }
- // FEATURE: inode numbers are calculated inconsistently throught the runtime
+ // FIXME: inode numbers are calculated inconsistently throught the runtime
public int inode() { return hashCode() & 0xfffff; }
public int mode() { return 0; }
public int type() { return S_IFIFO; }
public int blocks() { return (size()+blksize()-1)/blksize(); }
}
- protected static class HostFStat extends FStat {
+ static class HostFStat extends FStat {
private final File f;
private final boolean executable;
- public HostFStat(File f) {
+ public HostFStat(File f) { this(f,false); }
+ public HostFStat(File f, boolean executable) {
this.f = f;
- executable = executable();
+ this.executable = executable;
}
public int dev() { return 1; }
public int inode() { return f.getName().hashCode() & 0xffff; }
return mode;
}
public int size() { return (int) f.length(); }
- public int mtime() { return (int)(f.lastModified()/1000); }
-
- boolean executable() { return false; }
+ public int mtime() { return (int)(f.lastModified()/1000); }
}
// Exceptions
- public class ReadFaultException extends FaultException {
+ public static class ReadFaultException extends FaultException {
public ReadFaultException(int addr) { super(addr); }
}
- public class WriteFaultException extends FaultException {
+ public static class WriteFaultException extends FaultException {
public WriteFaultException(int addr) { super(addr); }
}
- public abstract class FaultException extends ExecutionException {
- public int addr;
- public FaultException(int addr) { super("fault at: " + toHex(addr)); this.addr = addr; }
+ public static class FaultException extends ExecutionException {
+ public final int addr;
+ public final RuntimeException cause;
+ public FaultException(int addr) { super("fault at: " + toHex(addr)); this.addr = addr; cause = null; }
+ public FaultException(RuntimeException e) { super(e.toString()); addr = -1; cause = e; }
}
public static class ExecutionException extends Exception {
private String message = "(null)";
return _byteBuf;
}
- protected static String getSystemProperty(String key) {
+ static String getSystemProperty(String key) {
try {
return System.getProperty(key);
} catch(SecurityException e) {
return buf;
}
- protected static byte[] getBytes(String s) {
+ static byte[] getBytes(String s) {
try {
return s.getBytes("ISO-8859-1");
} catch(UnsupportedEncodingException e) {
}
}
- 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; }
+ final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+ final static int min(int a, int b) { return a < b ? a : b; }
+ final static int max(int a, int b) { return a > b ? a : b; }
}
import java.io.*;
import java.util.*;
+// FIXME: Fix readdir in support_aux.c
+// FIXME: Make plain old "mips-unknown-elf-gcc -o foo foo.c" work (modify spec file or whatever)
+
// FEATURE: Remove System.{out,err}.printlns and throw Errors where applicable
-// FEATURE: BusyBox's ASH doesn't like \r\n at the end of lines
+// FIXME: BusyBox's ASH doesn't like \r\n at the end of lines
// is ash just broken or are many apps like this? if so workaround in nestedvm
public abstract class UnixRuntime extends Runtime implements Cloneable {
/** The pid of this "process" */
private int pid;
private UnixRuntime parent;
- protected int getPid() { return pid; }
+ public final int getPid() { return pid; }
private static final GlobalState defaultGD = new GlobalState();
private GlobalState gd = defaultGD;
private Vector activeChildren;
private Vector exitedChildren;
- public UnixRuntime(int pageSize, int totalPages) {
+ protected UnixRuntime(int pageSize, int totalPages) {
super(pageSize,totalPages);
// FEATURE: Do the proper mangling for non-unix hosts
return false;
}
- protected String[] createEnv(String[] extra) {
+ String[] createEnv(String[] extra) {
String[] defaults = new String[5];
int n=0;
if(extra == null) extra = new String[0];
private static class ProcessTableFullExn extends RuntimeException { }
- protected void _started() {
+ void _started() {
UnixRuntime[] tasks = gd.tasks;
synchronized(gd) {
if(pid != 0) {
}
}
- protected FD _open(String path, int flags, int mode) throws ErrnoException {
+ FD _open(String path, int flags, int mode) throws ErrnoException {
return gd.open(this,normalizePath(path),flags,mode);
}
}
- protected void _exited() {
+ void _exited() {
if(children != null) synchronized(children) {
for(Enumeration e = exitedChildren.elements(); e.hasMoreElements(); ) {
UnixRuntime child = (UnixRuntime) e.nextElement();
protected static final int LSTAT = 3;
protected static final int MKDIR = 4;
- // Make this protected (need to fix _exit)
- private final UnixRuntime[] tasks;
- private int nextPID = 1;
+ final UnixRuntime[] tasks;
+ int nextPID = 1;
private final MP[][] mps = new MP[128][];
private FS root;
}
public abstract static class FS {
- // FEATURE: inode stuff
- // FEATURE: Implement whatever is needed to get newlib's opendir and friends to work - that patch is a pain
+ // FIXME: inode stuff
protected static FD directoryFD(String[] files, int hashCode) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
public abstract void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException;
}
+ // FEATURE: chroot support in here
private String normalizePath(String path) {
boolean absolute = path.startsWith("/");
int cwdl = cwd.length();
//System.err.println("normalize: " + path + " -> " + new String(out,0,outp) + " (cwd: " + cwd + ")");
return new String(out,0,outp);
}
-
- // FEATURE: override Runtime.hostFStat to add executable type checking
- // hostFStat
- /* try {
- FileInputStream fis = new FileInputStream(f);
- switch(fis.read()) {
- case '\177': _executable = fis.read() == 'E' && fis.read() == 'L' && fis.read() == 'F'; break;
- case '#': _executable = fis.read() == '!';
- }
- fis.close();
- } catch(IOException e) { }
- */
+
+ FStat hostFStat(final File f) {
+ boolean e = false;
+ try {
+ FileInputStream fis = new FileInputStream(f);
+ switch(fis.read()) {
+ case '\177': e = fis.read() == 'E' && fis.read() == 'L' && fis.read() == 'F'; break;
+ case '#': e = fis.read() == '!';
+ }
+ fis.close();
+ } catch(IOException e2) { }
+ return new HostFStat(f,e);
+ }
- // FEATURE: inode stuff
+ // FIXME: inode stuff
FD hostFSDirFD(File f) { return FS.directoryFD(f.list(),f.hashCode()); }
public static class HostFS extends FS {