X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FRuntime.java;h=63e8835977270b484256e170aaa2714cac52d610;hp=a745084176b0c32375ca143ec6263686f2b57894;hb=7e1e0dc49707b777e71e69c23c0a48e0a2665a4b;hpb=c59b7cfc7a6b67574d38c5c8eb7732bad37236b0 diff --git a/src/org/ibex/nestedvm/Runtime.java b/src/org/ibex/nestedvm/Runtime.java index a745084..63e8835 100644 --- a/src/org/ibex/nestedvm/Runtime.java +++ b/src/org/ibex/nestedvm/Runtime.java @@ -8,14 +8,14 @@ import org.ibex.nestedvm.util.*; 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 { + /** True to write useful diagnostic information to stderr when things go wrong */ + final static boolean STDERR_DIAG = true; + /** Number of bits to shift to get the page number (1<<>> pageShift; - heapStart = (heapStart + pageSize) & ~(pageSize-1); + heapStart = (heapStart + pageSize - 1) & ~(pageSize-1); if(stackPages + STACK_GUARD_PAGES + (heapStart >>> pageShift) >= totalPages) throw new IllegalArgumentException("total pages too small"); } else { @@ -152,8 +152,8 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { if(totalPages == 1) { readPages[0] = writePages[0] = new int[pageSize>>2]; } else { - for(int i=(stackBottom >>> pageShift);i>2]; + for(int i=(stackBottom >>> pageShift);i>2]; } } @@ -295,7 +295,6 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { public final void memcpy(int dst, int src, int count) throws FaultException { int pageWords = (1<>>2; int pageWordMask = pageWords - 1; - if((dst&3) == 0 && (src&3)==0) { if((count&~3) != 0) { int c = count>>2; @@ -450,13 +449,12 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { addr += 4; } } catch(FaultException e) { - // should never happen - throw new Error(e.toString()); + throw new RuntimeException(e.toString()); } 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 index in the _user_info table to word * The user_info table is a chunk of memory in the program's memory defined by the @@ -480,16 +478,16 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } /** Calls _execute() (subclass's execute()) and catches exceptions */ + // FEATURE: Have these call kill() so we get a pretty message to stdout private void __execute() { try { _execute(); } catch(FaultException e) { - e.printStackTrace(); + if(STDERR_DIAG) e.printStackTrace(); sys_exit(128+11); // SIGSEGV exitException = e; } catch(ExecutionException e) { - e.printStackTrace(); - System.err.println(e); + if(STDERR_DIAG) e.printStackTrace(); sys_exit(128+4); // SIGILL exitException = e; } @@ -506,9 +504,9 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { return state != PAUSED; } - protected static String[] concatArgv(String argv0, String[] rest) { - String[] argv = new String[rest.length+1]; - System.arraycopy(rest,0,argv,1,rest.length); + 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; return argv; } @@ -523,9 +521,9 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { start(args,env); for(;;) { if(execute()) break; - System.err.println("WARNING: Pause requested while executing run()"); + if(STDERR_DIAG) System.err.println("WARNING: Pause requested while executing run()"); } - if(state == EXECED) System.err.println("WARNING: Process exec()ed while being run under run()"); + if(state == EXECED && STDERR_DIAG) System.err.println("WARNING: Process exec()ed while being run under run()"); return state == EXITED ? exitStatus() : 0; } @@ -541,14 +539,23 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { sp = top = writePages.length*(1< ARG_MAX) throw new IllegalArgumentException("args/environ too big"); + // HACK: heapStart() isn't always available when the constructor + // is run and this sometimes doesn't get initialized + if(heapEnd == 0) { + heapEnd = heapStart(); + if(heapEnd == 0) throw new Error("heapEnd == 0"); + int pageSize = writePages.length == 1 ? 4096 : (1<fileName. 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 fd 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;ifdn 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; @@ -683,11 +683,11 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } /** Duplicates the file descriptor fdn and returns the new fs */ - public int dupFD(int fdn) { - int i; - if(fdn < 0 || fdn >= OPEN_MAX) return -1; - if(fds[fdn] == null) return -1; - for(i=0;i= OPEN_MAX) return -1; + if(fds[fdn] == null) return -1; + for(i=0;i= OPEN_MAX) return -EBADFD; - if(fds[fdn] == null || !fds[fdn].writable()) return -EBADFD; + if(fds[fdn] == null) return -EBADFD; + byte[] buf = byteBuf(count); + copyin(addr,buf,count); try { - byte[] buf = byteBuf(count); - copyin(addr,buf,count); return fds[fdn].write(buf,0,count); - } catch(IOException e) { - // NOTE: This should really send a SIGPIPE - if(e.getMessage().equals("Pipe closed")) return sys_exit(128+13); - return -EIO; + } catch(ErrnoException e) { + if(e.errno == EPIPE) sys_exit(128+13); + throw e; } } /** The read syscall */ - private int sys_read(int fdn, int addr, int count) throws FaultException { + private int sys_read(int fdn, int addr, int count) throws FaultException, ErrnoException { count = Math.min(count,MAX_CHUNK); if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; - if(fds[fdn] == null || !fds[fdn].readable()) return -EBADFD; - try { - byte[] buf = byteBuf(count); - int n = fds[fdn].read(buf,0,count); - copyout(buf,addr,n); - return n; - } catch(IOException e) { - return -EIO; - } + if(fds[fdn] == null) return -EBADFD; + byte[] buf = byteBuf(count); + int n = fds[fdn].read(buf,0,count); + copyout(buf,addr,n); + return n; } /** The close syscall */ @@ -790,16 +792,12 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { /** The seek syscall */ - private int sys_lseek(int fdn, int offset, int whence) { + private int sys_lseek(int fdn, int offset, int whence) throws ErrnoException { if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; if(fds[fdn] == null) return -EBADFD; if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) return -EINVAL; - try { - int n = fds[fdn].seek(offset,whence); - return n < 0 ? -ESPIPE : n; - } catch(IOException e) { - return -ESPIPE; - } + int n = fds[fdn].seek(offset,whence); + return n < 0 ? -ESPIPE : n; } /** The stat/fstat syscall helper */ @@ -885,15 +883,17 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { private int sys_sysconf(int n) { switch(n) { case _SC_CLK_TCK: return 1000; + case _SC_PAGESIZE: return writePages.length == 1 ? 4096 : (1<incr 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; @@ -909,7 +909,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { try { for(int i=start;i= OPEN_MAX) return -EBADFD; - if(fds[fdn] == null) return -EBADFD; - return fds[fdn].isatty() ? 1 : 0; - } - - /** Hook for subclasses to do something when the process exits */ - protected void _exited() { } + void _exited() { } private int sys_exit(int status) { exitStatus = status; @@ -983,17 +976,14 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { fds[i] = fd.dup(); return 0; case F_GETFL: - int flags = 0; - if(fd.writable() && fd.readable()) flags = 2; - else if(fd.writable()) flags = 1; - return flags; + return fd.flags(); case F_SETFD: - closeOnExec[fdn] = arg != 0; + closeOnExec[fdn] = arg != 0; return 0; case F_GETFD: return closeOnExec[fdn] ? 1 : 0; default: - System.err.println("WARNING: Unknown fcntl command: " + cmd); + if(STDERR_DIAG) System.err.println("WARNING: Unknown fcntl command: " + cmd); return -ENOSYS; } } @@ -1005,15 +995,14 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { @see Runtime#state state */ protected final int syscall(int syscall, int a, int b, int c, int d) { try { - return _syscall(syscall,a,b,c,d); + return _syscall(syscall,a,b,c,d); } catch(ErrnoException e) { - e.printStackTrace(); - return -e.errno; + return -e.errno; } catch(FaultException e) { - return -EFAULT; + return -EFAULT; } catch(RuntimeException e) { e.printStackTrace(); - throw new Error("Internal Error in _syscall()"); + throw new Error("Internal Error in _syscall()"); } } @@ -1035,9 +1024,11 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { case SYS_sleep: return sys_sleep(a); case SYS_times: return sys_times(a); case SYS_getpagesize: return sys_getpagesize(); - case SYS_isatty: return sys_isatty(a); case SYS_fcntl: return sys_fcntl(a,b,c); case SYS_sysconf: return sys_sysconf(a); + + case SYS_memcpy: memcpy(a,b,c); return a; + case SYS_memset: memset(a,b,c); return a; case SYS_kill: case SYS_fork: @@ -1048,10 +1039,10 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { case SYS_mkdir: case SYS_getcwd: case SYS_chdir: - System.err.println("Attempted to use a UnixRuntime syscall in Runtime (" + syscall + ")"); + if(STDERR_DIAG) System.err.println("Attempted to use a UnixRuntime syscall in Runtime (" + syscall + ")"); return -ENOSYS; default: - System.err.println("Attempted to use unknown syscall: " + syscall); + if(STDERR_DIAG) System.err.println("Attempted to use unknown syscall: " + syscall); return -ENOSYS; } } @@ -1081,7 +1072,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } /** 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); @@ -1097,28 +1088,23 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { /** File Descriptor class */ public static abstract class FD { private int refCount = 1; - - /** returns true if the fd is readable */ - public boolean readable() { return false; } - /** returns true if the fd is writable */ - public boolean writable() { return false; } /** Read some bytes. Should return the number of bytes read, 0 on EOF, or throw an IOException on error */ - public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } + public int read(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); } /** Write. Should return the number of bytes written or throw an IOException on error */ - public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } + public int write(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); } /** Seek in the filedescriptor. Whence is SEEK_SET, SEEK_CUR, or SEEK_END. Should return -1 on error or the new position. */ - public int seek(int n, int whence) throws IOException { return -1; } + public int seek(int n, int whence) throws ErrnoException { return -1; } + + public int getdents(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); } + + public int flags() { return O_RDONLY; } /** Return a Seekable object representing this file descriptor (can be read only) This is required for exec() */ 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 - public boolean isatty() { return false; } - private FStat cachedFStat = null; public final FStat fstat() { if(cachedFStat == null) cachedFStat = _fstat(); @@ -1138,35 +1124,48 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { public abstract static class SeekableFD extends FD { private final int flags; private final Seekable data; - public boolean readable() { return (flags&3) != WR_ONLY; } - public boolean writable() { return (flags&3) != RD_ONLY; } SeekableFD(Seekable data, int flags) { this.data = data; this.flags = flags; } protected abstract FStat _fstat(); + public int flags() { return flags; } Seekable seekable() { return data; } - public int seek(int n, int whence) throws IOException { - switch(whence) { - case SEEK_SET: break; - case SEEK_CUR: n += data.pos(); break; - case SEEK_END: n += data.length(); break; - default: return -1; + public int seek(int n, int whence) throws ErrnoException { + try { + switch(whence) { + case SEEK_SET: break; + case SEEK_CUR: n += data.pos(); break; + case SEEK_END: n += data.length(); break; + default: return -1; + } + data.seek(n); + return n; + } catch(IOException e) { + throw new ErrnoException(ESPIPE); } - data.seek(n); - return n; } - public int write(byte[] a, int off, int length) throws IOException { + public int write(byte[] a, int off, int length) throws ErrnoException { + if((flags&3) == RD_ONLY) throw new ErrnoException(EBADFD); // NOTE: There is race condition here but we can't fix it in pure java if((flags&O_APPEND) != 0) seek(0,SEEK_END); - return data.write(a,off,length); + try { + return data.write(a,off,length); + } catch(IOException e) { + throw new ErrnoException(EIO); + } } - public int read(byte[] a, int off, int length) throws IOException { - int n = data.read(a,off,length); - return n < 0 ? 0 : n; + public int read(byte[] a, int off, int length) throws ErrnoException { + if((flags&3) == WR_ONLY) throw new ErrnoException(EBADFD); + try { + int n = data.read(a,off,length); + return n < 0 ? 0 : n; + } catch(IOException e) { + throw new ErrnoException(EIO); + } } protected void _close() { try { data.close(); } catch(IOException e) { /*ignore*/ } } @@ -1174,33 +1173,46 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { public static class OutputStreamFD extends FD { private OutputStream os; - public boolean writable() { return true; } + public int flags() { return O_WRONLY; } 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 int write(byte[] a, int off, int length) throws ErrnoException { + try { + os.write(a,off,length); + return length; + } catch(IOException e) { + throw new ErrnoException(EIO); + } + } public void _close() { try { os.close(); } catch(IOException e) { /*ignore*/ } } public FStat _fstat() { return new FStat(); } } public static class InputStreamFD extends FD { private InputStream is; - public boolean readable() { return true; } + public int flags() { return O_RDONLY; } 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; } + public int read(byte[] a, int off, int length) throws ErrnoException { + try { + int n = is.read(a,off,length); + return n < 0 ? 0 : n; + } catch(IOException e) { + throw new ErrnoException(EIO); + } + } public void _close() { try { is.close(); } catch(IOException e) { /*ignore*/ } } 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 boolean isatty() { return true; } } public static class FStat { @@ -1209,9 +1221,8 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { public static final int S_IFDIR = 0040000; public static final int S_IFREG = 0100000; - public int dev() { return -1; } - // FEATURE: inode numbers are calculated inconsistently throught the runtime - public int inode() { return hashCode() & 0xfffff; } + public int dev() { return 1; } + public int inode() { return hashCode() & 0x7fff; } public int mode() { return 0; } public int type() { return S_IFIFO; } public int nlink() { return 0; } @@ -1225,12 +1236,13 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { 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; } @@ -1245,21 +1257,21 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { 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)"; @@ -1290,13 +1302,13 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { public int pc; public CPUState dup() { - CPUState c = new CPUState(); + CPUState c = new CPUState(); c.hi = hi; c.lo = lo; c.fcsr = fcsr; c.pc = pc; for(int i=0;i<32;i++) { - c.r[i] = r[i]; + c.r[i] = r[i]; c.f[i] = f[i]; } return c; @@ -1304,7 +1316,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } public static class SecurityManager { - public boolean allowRead(File f) { return true; } + public boolean allowRead(File f) { return true; } public boolean allowWrite(File f) { return true; } public boolean allowStat(File f) { return true; } } @@ -1316,14 +1328,14 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } // Utility functions - private byte[] byteBuf(int size) { + 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)]; return _byteBuf; } - protected static String getSystemProperty(String key) { + static String getSystemProperty(String key) { try { return System.getProperty(key); } catch(SecurityException e) { @@ -1348,7 +1360,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { return buf; } - protected static byte[] getBytes(String s) { + static byte[] getBytes(String s) { try { return s.getBytes("ISO-8859-1"); } catch(UnsupportedEncodingException e) { @@ -1356,7 +1368,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } } - 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; } }