X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FRuntime.java;h=e72ef9426f5209e05ab5536dc667cd4a7e94a56b;hp=ee022147a0b00821cd43b65de4193b27446330cd;hb=4a26f91aad32c62d7407e0a2dc04c5cb44c74043;hpb=19e0f90cbc9c66e274bac04f819a78e387c8f1fc
diff --git a/src/org/ibex/nestedvm/Runtime.java b/src/org/ibex/nestedvm/Runtime.java
index ee02214..e72ef94 100644
--- a/src/org/ibex/nestedvm/Runtime.java
+++ b/src/org/ibex/nestedvm/Runtime.java
@@ -1,3 +1,7 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
// Copyright 2003 Brian Alliet
// Based on org.xwt.imp.MIPS by Adam Megacz
// Portions Copyright 2003 Adam Megacz
@@ -46,10 +50,10 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** When the process started */
private long startTime;
- /** Text/Data loaded in memory */
- public final static int STOPPED = 0;
/** Program is executing instructions */
- public final static int RUNNING = 1;
+ public final static int RUNNING = 0; // Horrible things will happen if this isn't 0
+ /** Text/Data loaded in memory */
+ public final static int STOPPED = 1;
/** Prgram has been started but is paused */
public final static int PAUSED = 2;
/** Program is executing a callJava() method */
@@ -70,8 +74,12 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
public ExecutionException exitException;
/** Table containing all open file descriptors. (Entries are null if the fd is not in use */
- FD[] fds = new FD[OPEN_MAX]; // package-private for UnixRuntime
- boolean closeOnExec[] = new boolean[OPEN_MAX];
+ FD[] fds; // package-private for UnixRuntime
+ boolean closeOnExec[];
+
+ /** Table of all current file locks held by this process. */
+ Seekable.Lock[] locks;
+ public static final int LOCK_MAX = 8;
/** Pointer to a SecurityManager for this process */
SecurityManager sm;
@@ -94,7 +102,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** Subclasses should return the address of the symbol symbol or -1 it it doesn't exits in this method
This method is only required if the call() function is used */
- protected int lookupSymbol(String symbol) { return -1; }
+ public int lookupSymbol(String symbol) { return -1; }
/** Subclasses should populate a CPUState object representing the cpu state */
protected abstract void getCPUState(CPUState state);
@@ -102,12 +110,23 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** Subclasses should set the CPUState to the state held in state */
protected abstract void setCPUState(CPUState state);
+ /** True to enabled a few hacks to better support the win32 console */
+ final static boolean win32Hacks;
+
+ static {
+ String os = Platform.getProperty("os.name");
+ String prop = Platform.getProperty("nestedvm.win32hacks");
+ if(prop != null) { win32Hacks = Boolean.valueOf(prop).booleanValue(); }
+ else { win32Hacks = os != null && os.toLowerCase().indexOf("windows") != -1; }
+ }
+
protected Object clone() throws CloneNotSupportedException {
Runtime r = (Runtime) super.clone();
r._byteBuf = null;
r.startTime = 0;
r.fds = new FD[OPEN_MAX];
for(int i=0;i>2];
}
}
-
- InputStream stdin = Boolean.valueOf(getSystemProperty("nestedvm.textstdin")).booleanValue() ? new TextInputStream(System.in) : System.in;
- addFD(new TerminalFD(stdin));
- addFD(new TerminalFD(System.out));
- addFD(new TerminalFD(System.err));
+
+ if(!exec) {
+ fds = new FD[OPEN_MAX];
+ closeOnExec = new boolean[OPEN_MAX];
+ locks = new Seekable.Lock[LOCK_MAX];
+
+ InputStream stdin = win32Hacks ? new Win32ConsoleIS(System.in) : System.in;
+ addFD(new TerminalFD(stdin));
+ addFD(new TerminalFD(System.out));
+ addFD(new TerminalFD(System.err));
+ }
}
/** Copy everything from src to addr initializing uninitialized pages if required.
@@ -481,17 +507,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) {
if(STDERR_DIAG) e.printStackTrace();
- sys_exit(128+11); // SIGSEGV
+ exit(128+11,true); // SIGSEGV
exitException = e;
} catch(ExecutionException e) {
if(STDERR_DIAG) e.printStackTrace();
- sys_exit(128+4); // SIGILL
+ exit(128+4,true); // SIGILL
exitException = e;
}
}
@@ -537,7 +562,6 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
public final void start(String[] args, String[] environ) {
int top, sp, argsAddr, envAddr;
if(state != STOPPED) throw new IllegalStateException("start() called in inappropriate state");
-
if(args == null) args = new String[]{getClass().getName()};
sp = top = writePages.length*(1<= OPEN_MAX) return false;
if(fds[fdn] == null) return false;
+
+ // release all fcntl locks on this file
+ Seekable s = fds[fdn].seekable();
+ if (s != null) {
+ try {
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] != null && s.equals(locks[i].seekable())) {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ } catch (IOException e) { throw new RuntimeException(e); }
+ }
+
fds[fdn].close();
fds[fdn] = null;
return true;
@@ -712,7 +750,6 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
if((flags & ~(3|O_CREAT|O_EXCL|O_APPEND|O_TRUNC)) != 0) {
if(STDERR_DIAG)
System.err.println("WARNING: Unsupported flags passed to open(\"" + f + "\"): " + toHex(flags & ~(3|O_CREAT|O_EXCL|O_APPEND|O_TRUNC)));
-
throw new ErrnoException(ENOTSUP);
}
boolean write = (flags&3) != RD_ONLY;
@@ -721,7 +758,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
if((flags & (O_EXCL|O_CREAT)) == (O_EXCL|O_CREAT)) {
try {
- if(Platform.atomicCreateFile(f)) throw new ErrnoException(EEXIST);
+ if(!Platform.atomicCreateFile(f)) throw new ErrnoException(EEXIST);
} catch(IOException e) {
throw new ErrnoException(EIO);
}
@@ -791,6 +828,17 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
copyout(buf,addr,n);
return n;
}
+
+ /** The ftruncate syscall */
+ private int sys_ftruncate(int fdn, long length) {
+ if (fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if (fds[fdn] == null) return -EBADFD;
+
+ Seekable seekable = fds[fdn].seekable();
+ if (length < 0 || seekable == null) return -EINVAL;
+ try { seekable.resize(length); } catch (IOException e) { return -EIO; }
+ return 0;
+ }
/** The close syscall */
private int sys_close(int fdn) {
@@ -960,15 +1008,25 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** Hook for subclasses to do something when the process exits */
void _exited() { }
- private int sys_exit(int status) {
+ void exit(int status, boolean fromSignal) {
+ if(fromSignal && fds[2] != null) {
+ try {
+ byte[] msg = getBytes("Process exited on signal " + (status - 128) + "\n");
+ fds[2].write(msg,0,msg.length);
+ } catch(ErrnoException e) { }
+ }
exitStatus = status;
for(int i=0;i= OPEN_MAX) return -EBADFD;
@@ -989,12 +1047,125 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
return 0;
case F_GETFD:
return closeOnExec[fdn] ? 1 : 0;
+ case F_GETLK:
+ case F_SETLK:
+ try {
+ return sys_fcntl_lock(fd, cmd, arg);
+ } catch (IOException e) { throw new RuntimeException(e);}
default:
if(STDERR_DIAG) System.err.println("WARNING: Unknown fcntl command: " + cmd);
return -ENOSYS;
}
}
-
+
+ /** Implements the F_GETLK and F_SETLK cases of fcntl syscall.
+ * If l_start = 0 and l_len = 0 the lock refers to the entire file.
+ struct flock {
+ short l_type; // lock type: F_UNLCK, F_RDLCK, F_WRLCK
+ short l_whence; // type of l_start: SEEK_SET, SEEK_CUR, SEEK_END
+ long l_start; // starting offset, bytes
+ long l_len; // len = 0 means until EOF
+ short l_pid; // lock owner
+ short l_xxx; // padding
+ };
+ */
+ private int sys_fcntl_lock(FD fd, int cmd, int arg)
+ throws FaultException, IOException {
+ if (arg == 0) { System.out.println("BAD ARG"); return -EINVAL; }
+ int word = memRead(arg);
+ int l_start = memRead(arg+4);
+ int l_len = memRead(arg+8);
+ int l_type = word>>16;
+ int l_whence = word&0x00ff;
+
+ Seekable s = fd.seekable();
+ if (s == null) return -EINVAL;
+
+ switch (l_whence) {
+ case SEEK_SET: break;
+ case SEEK_CUR: l_start += s.pos(); break;
+ case SEEK_END: l_start += s.length(); break;
+ default: return -1;
+ }
+
+ if (cmd != F_GETLK && cmd != F_SETLK) return -EINVAL;
+
+ if (cmd == F_GETLK) {
+ // Check if an l_type lock can be aquired. The only way to
+ // do this within the Java API is to try and create a lock.
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+
+ if (lock != null) {
+ // no lock exists
+ memWrite(arg, SEEK_SET|(F_UNLCK<<16));
+ lock.release();
+ }
+
+ return 0;
+ }
+
+ // now processing F_SETLK
+ if (cmd != F_SETLK) return -EINVAL;
+
+ if (l_type == F_UNLCK) {
+ // release all locks that fall within the boundaries given
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+
+ int pos = (int)locks[i].position();
+ if (pos < l_start) continue;
+ if (l_start != 0 && l_len != 0) // start/len 0 means unlock all
+ if (pos + locks[i].size() > l_start + l_len)
+ continue;
+
+ locks[i].release();
+ locks[i] = null;
+ }
+ return 0;
+
+ } else if (l_type == F_RDLCK || l_type == F_WRLCK) {
+ // first see if a lock already exists
+ for (int i=0; i < LOCK_MAX; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ int pos = (int)locks[i].position();
+ int size = (int)locks[i].size();
+ if (l_start < pos && pos + size < l_start + l_len) {
+ // found a lock contained in the new requested lock
+ locks[i].release();
+ locks[i] = null;
+
+ } else if (l_start >= pos && pos + size >= l_start + l_len) {
+ // found a lock that contains the requested lock
+ if (locks[i].isShared() == (l_type == F_RDLCK)) {
+ memWrite(arg+4, pos);
+ memWrite(arg+8, size);
+ return 0;
+ } else {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ }
+
+ // create the lock
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+ if (lock == null) return -EAGAIN;
+
+ int i;
+ for (i=0; i < LOCK_MAX; i++)
+ if (locks[i] == null) break;
+ if (i == LOCK_MAX) return -ENOLCK;
+ locks[i] = lock;
+ return 0;
+
+ } else {
+ return -EINVAL;
+ }
+ }
+
+
/** The syscall dispatcher.
The should be called by subclasses when the syscall instruction is invoked.
syscall should be the contents of V0 and a, b, c, and d should be
@@ -1003,9 +1174,11 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
protected final int syscall(int syscall, int a, int b, int c, int d, int e, int f) {
try {
int n = _syscall(syscall,a,b,c,d,e,f);
- //if(n < 0) System.err.println("syscall: " + syscall + " returned " + n);
+ //if(n<0) throw new ErrnoException(-n);
return n;
} catch(ErrnoException ex) {
+ //System.err.println("While executing syscall: " + syscall + ":");
+ //if(syscall == SYS_open) try { System.err.println("Failed to open " + cstring(a) + " errno " + ex.errno); } catch(Exception e2) { }
//ex.printStackTrace();
return -ex.errno;
} catch(FaultException ex) {
@@ -1028,6 +1201,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
case SYS_close: return sys_close(a);
case SYS_read: return sys_read(a,b,c);
case SYS_lseek: return sys_lseek(a,b,c);
+ case SYS_ftruncate: return sys_ftruncate(a,b);
case SYS_getpid: return sys_getpid();
case SYS_calljava: return sys_calljava(a,b,c,d);
case SYS_gettimeofday: return sys_gettimeofday(a,b);
@@ -1036,6 +1210,10 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
case SYS_getpagesize: return sys_getpagesize();
case SYS_fcntl: return sys_fcntl(a,b,c);
case SYS_sysconf: return sys_sysconf(a);
+ case SYS_getuid: return sys_getuid();
+ case SYS_geteuid: return sys_geteuid();
+ case SYS_getgid: return sys_getgid();
+ case SYS_getegid: return sys_getegid();
case SYS_memcpy: memcpy(a,b,c); return a;
case SYS_memset: memset(a,b,c); return a;
@@ -1057,6 +1235,11 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
}
}
+ private int sys_getuid() { return 0; }
+ private int sys_geteuid() { return 0; }
+ private int sys_getgid() { return 0; }
+ private int sys_getegid() { return 0; }
+
public int xmalloc(int size) { int p=malloc(size); if(p==0) throw new RuntimeException("malloc() failed"); return p; }
public int xrealloc(int addr,int newsize) { int p=realloc(addr,newsize); if(p==0) throw new RuntimeException("realloc() failed"); return p; }
public int realloc(int addr, int newsize) { try { return call("realloc",addr,newsize); } catch(CallException e) { return 0; } }
@@ -1083,6 +1266,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
/** Helper function to read a cstring from main memory */
public final String cstring(int addr) throws ReadFaultException {
+ if (addr == 0) return null;
StringBuffer sb = new StringBuffer();
for(;;) {
int word = memRead(addr&~3);
@@ -1109,8 +1293,6 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
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; }
@@ -1122,6 +1304,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
}
protected abstract FStat _fstat();
+ public abstract int flags();
/** Closes the fd */
public final void close() { if(--refCount==0) _close(); }
@@ -1225,7 +1408,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
}
}
- public FStat _fstat() { return new FStat(); }
+ public FStat _fstat() { return new SocketFStat(); }
}
static class TerminalFD extends InputOutputStreamFD {
@@ -1233,14 +1416,14 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
public TerminalFD(OutputStream os) { this(null,os); }
public TerminalFD(InputStream is, OutputStream os) { super(is,os); }
public void _close() { /* noop */ }
- public FStat _fstat() { return new FStat() { public int type() { return S_IFCHR; } public int mode() { return 0600; } }; }
+ public FStat _fstat() { return new SocketFStat() { public int type() { return S_IFCHR; } public int mode() { return 0600; } }; }
}
- // FEATURE: TextInputStream: This is pretty inefficient but it is only used for reading from the console on win32
- static class TextInputStream extends InputStream {
+ // This is pretty inefficient but it is only used for reading from the console on win32
+ static class Win32ConsoleIS extends InputStream {
private int pushedBack = -1;
private final InputStream parent;
- public TextInputStream(InputStream parent) { this.parent = parent; }
+ public Win32ConsoleIS(InputStream parent) { this.parent = parent; }
public int read() throws IOException {
if(pushedBack != -1) { int c = pushedBack; pushedBack = -1; return c; }
int c = parent.read();
@@ -1255,7 +1438,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
pos++; len--; pb = true;
}
int n = parent.read(buf,pos,len);
- if(n == -1) return -1;
+ if(n == -1) return pb ? 1 : -1;
for(int i=0;i