X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FRuntime.java;h=55851c39cfea3626a172e7ae8834d1704ae9c294;hp=f6a00df4c6c73cb177550f091a8a0a0525e6b880;hb=d1a9c17fc77be2e8f200b7be68c4f70c10e73f89;hpb=49cb14fa5b1e479ed41c38fd60372d9cd3086cd3 diff --git a/src/org/ibex/nestedvm/Runtime.java b/src/org/ibex/nestedvm/Runtime.java index f6a00df..55851c3 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 @@ -72,6 +76,10 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { /** Table containing all open file descriptors. (Entries are null if the fd is not in use */ 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); @@ -118,6 +126,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { r.startTime = 0; r.fds = new FD[OPEN_MAX]; for(int i=0;i= 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; @@ -727,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; @@ -736,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); } @@ -806,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) { @@ -993,7 +1026,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { return 0; } - private int sys_fcntl(int fdn, int cmd, int arg) { + private int sys_fcntl(int fdn, int cmd, int arg) throws FaultException { int i; if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; @@ -1014,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 @@ -1028,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) { @@ -1053,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); @@ -1061,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; @@ -1082,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; } } @@ -1105,9 +1263,38 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { } return addr; } - + + // TODO: less memory copying (custom utf-8 reader) + // or at least roll strlen() into copyin() + public final String utfstring(int addr) throws ReadFaultException { + if (addr == 0) return null; + + // determine length + int i=addr; + for(int word = 1; word != 0; i++) { + word = memRead(i&~3); + switch(i&3) { + case 0: word = (word>>>24)&0xff; break; + case 1: word = (word>>>16)&0xff; break; + case 2: word = (word>>> 8)&0xff; break; + case 3: word = (word>>> 0)&0xff; break; + } + } + if (i > addr) i--; // do not count null + + byte[] bytes = new byte[i-addr]; + copyin(addr, bytes, bytes.length); + + try { + return new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // should never happen with UTF-8 + } + } + /** 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); @@ -1279,7 +1466,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