X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=f5b8745196c5c3427dfddfb6d6f8493ed852c4c9;hp=e778377fb58ef71285dc47ef74cfc641e7db48df;hb=8a4f765fabfbee269818c56e517b8a37fc394d7e;hpb=7a9bc0ba0fd215bd5b9a2e370937d81870aadba5 diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index e778377..f5b8745 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -1,11 +1,12 @@ package org.ibex.nestedvm; import org.ibex.nestedvm.util.*; -// FEATURE: This is ugly, this stuff needs to be in org.ibex.util or something +// HACK: This is ugly, this stuff needs to be in org.ibex.util or something import org.ibex.classgen.util.Sort; import java.io.*; import java.util.*; import java.net.*; +import java.lang.reflect.*; // For lazily linked RuntimeCompiler // FEATURE: vfork @@ -19,6 +20,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private GlobalState gs; public void setGlobalState(GlobalState gs) { if(state != STOPPED) throw new IllegalStateException("can't change GlobalState when running"); + if(gs == null) throw new NullPointerException("gs is null"); this.gs = gs; } @@ -158,6 +160,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case SYS_accept: return sys_accept(a,b,c); case SYS_shutdown: return sys_shutdown(a,b); case SYS_sysctl: return sys_sysctl(a,b,c,d,e,f); + case SYS_sendto: return sys_sendto(a,b,c,d,e,f); + case SYS_recvfrom: return sys_recvfrom(a,b,c,d,e,f); + case SYS_select: return sys_select(a,b,c,d,e); default: return super._syscall(syscall,a,b,c,d,e,f); } @@ -223,6 +228,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { exitedChildren.removeElementAt(exitedChildren.size() - 1); } } else if(pid > 0) { + if(pid >= gs.tasks.length) return -ECHILD; UnixRuntime t = gs.tasks[pid]; if(t.parent != this) return -ECHILD; if(t.state == EXITED) { @@ -288,9 +294,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } private int sys_fork() { - CPUState state = new CPUState(); - getCPUState(state); - int sp = state.r[SP]; final UnixRuntime r; try { @@ -316,6 +319,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } activeChildren.addElement(r); + CPUState state = new CPUState(); + getCPUState(state); state.r[V0] = 0; // return 0 to child state.pc += 4; // skip over syscall instruction r.setCPUState(state); @@ -357,43 +362,148 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_exec(int cpath, int cargv, int cenvp) throws ErrnoException, FaultException { return exec(normalizePath(cstring(cpath)),readStringArray(cargv),readStringArray(cenvp)); } + + private final static Method runtimeCompilerCompile; + static { + Method m; + try { + m = Class.forName("org.ibex.nestedvm.RuntimeCompiler").getMethod("compile",new Class[]{Seekable.class,String.class}); + } catch(NoSuchMethodException e) { + m = null; + } catch(ClassNotFoundException e) { + m = null; + } + runtimeCompilerCompile = m; + } + + public Class runtimeCompile(Seekable s) throws IOException { + if(runtimeCompilerCompile == null) { + if(STDERR_DIAG) System.err.println("WARNING: Exec attempted but RuntimeCompiler not found!"); + return null; + } + + try { + return (Class) runtimeCompilerCompile.invoke(null,new Object[]{s,"unixruntime"}); + } catch(IllegalAccessException e) { + e.printStackTrace(); + return null; + } catch(InvocationTargetException e) { + Throwable t = e.getTargetException(); + if(t instanceof IOException) throw (IOException) t; + if(t instanceof RuntimeException) throw (RuntimeException) t; + if(t instanceof Error) throw (Error) t; + if(STDERR_DIAG) t.printStackTrace(); + return null; + } + } - private int exec(String normalizedPath, String[] argv, String[] envp) throws ErrnoException { + private int exec(String path, String[] argv, String[] envp) throws ErrnoException { if(argv.length == 0) argv = new String[]{""}; - + // HACK: Hideous hack to make a standalone busybox possible + if(path.equals("bin/busybox") && getClass().getName().endsWith("BusyBox")) + return execClass(getClass(),argv,envp); + // NOTE: For this little hack to work nestedvm.root MUST be "." /*try { System.err.println("Execing normalized path: " + normalizedPath); if(true) return exec(new Interpreter(normalizedPath),argv,envp); } catch(IOException e) { throw new Error(e); }*/ - Object o = gs.exec(this,normalizedPath); - if(o == null) return -ENOENT; - - if(o instanceof Class) { - Class c = (Class) o; - try { - UnixRuntime r = (UnixRuntime) c.getDeclaredConstructor(new Class[]{Boolean.TYPE}).newInstance(new Object[]{Boolean.TRUE}); - return exec(r,argv,envp); - } catch(Exception e) { - e.printStackTrace(); - return -ENOEXEC; + FStat fstat = gs.stat(this,path); + if(fstat == null) return -ENOENT; + GlobalState.CacheEnt ent = (GlobalState.CacheEnt) gs.execCache.get(path); + long mtime = fstat.mtime(); + long size = fstat.size(); + if(ent != null) { + //System.err.println("Found cached entry for " + path); + if(ent.time ==mtime && ent.size == size) { + if(ent.o instanceof Class) + return execClass((Class) ent.o,argv,envp); + if(ent.o instanceof String[]) + return execScript(path,(String[]) ent.o,argv,envp); + throw new Error("should never happen"); } - } else { - String[] command = (String[]) o; - String[] newArgv = new String[argv.length + command[1] != null ? 2 : 1]; - int p = command[0].lastIndexOf('/'); - newArgv[0] = p == -1 ? command[0] : command[0].substring(p+1); - p = 1; - if(command[1] != null) newArgv[p++] = command[1]; - newArgv[p++] = "/" + normalizedPath; - for(int i=1;i>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -683,22 +822,21 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return -EADDRNOTAVAIL; } + fd.connectAddr = inetAddr; + fd.connectPort = port; + try { switch(fd.type()) { case SocketFD.TYPE_STREAM: { Socket s = new Socket(inetAddr,port); - fd.o = s; + fd.s = s; fd.setOptions(); fd.is = s.getInputStream(); fd.os = s.getOutputStream(); break; } - case SocketFD.TYPE_DGRAM: { - if(fd.dp == null) fd.dp = new DatagramPacket(null,0); - fd.dp.setAddress(inetAddr); - fd.dp.setPort(port); + case SocketFD.TYPE_DGRAM: break; - } default: throw new Error("should never happen"); } @@ -778,7 +916,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_bind(int fdn, int addr, int namelen) throws FaultException, ErrnoException { SocketFD fd = getSocketFD(fdn); - if(fd.type() == SocketFD.TYPE_STREAM && fd.o != null) return -EISCONN; + if(fd.type() == SocketFD.TYPE_STREAM && (fd.s != null || fd.ss != null)) return -EISCONN; int word1 = memRead(addr); if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -801,10 +939,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } case SocketFD.TYPE_DGRAM: { - DatagramSocket s = (DatagramSocket) fd.o; - if(s != null) s.close(); + if(fd.ds != null) fd.ds.close(); try { - fd.o = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); + fd.ds = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); } catch(IOException e) { return -EADDRINUSE; } @@ -818,11 +955,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_listen(int fdn, int backlog) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP; - if(fd.o != null) return -EISCONN; + if(fd.ss != null || fd.s != null) return -EISCONN; if(fd.bindPort < 0) return -EOPNOTSUPP; try { - fd.o = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); + fd.ss = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); fd.flags |= SocketFD.LISTEN; return 0; } catch(IOException e) { @@ -838,7 +975,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { int size = memRead(lenaddr); - ServerSocket s = (ServerSocket) fd.o; + ServerSocket s = fd.ss; Socket client; try { client = s.accept(); @@ -854,7 +991,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } SocketFD clientFD = new SocketFD(SocketFD.TYPE_STREAM); - clientFD.o = client; + clientFD.s = client; try { clientFD.is = client.getInputStream(); clientFD.os = client.getOutputStream(); @@ -869,9 +1006,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_shutdown(int fdn, int how) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM || fd.listen()) return -EOPNOTSUPP; - if(fd.o == null) return -ENOTCONN; + if(fd.s == null) return -ENOTCONN; - Socket s = (Socket) fd.o; + Socket s = fd.s; try { if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false); @@ -883,6 +1020,58 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } + private int sys_sendto(int fdn, int addr, int count, int flags, int destAddr, int socklen) throws ErrnoException,ReadFaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + int word1 = memRead(destAddr); + if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; + int port = word1 & 0xffff; + InetAddress inetAddr; + byte[] ip = new byte[4]; + copyin(destAddr+4,ip,4); + try { + inetAddr = Platform.inetAddressFromBytes(ip); + } catch(UnknownHostException e) { + return -EADDRNOTAVAIL; + } + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + copyin(addr,buf,count); + try { + return fd.sendto(buf,0,count,inetAddr,port); + } catch(ErrnoException e) { + if(e.errno == EPIPE) exit(128+13,true); + throw e; + } + } + + private int sys_recvfrom(int fdn, int addr, int count, int flags, int sourceAddr, int socklenAddr) throws ErrnoException, FaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + InetAddress[] inetAddr = sourceAddr == 0 ? null : new InetAddress[1]; + int[] port = sourceAddr == 0 ? null : new int[1]; + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + int n = fd.recvfrom(buf,0,count,inetAddr,port); + copyout(buf,addr,n); + + if(sourceAddr != 0) { + memWrite(sourceAddr,(AF_INET << 16) | port[0]); + byte[] ip = inetAddr[0].getAddress(); + copyout(ip,sourceAddr+4,4); + } + + return n; + } + + private int sys_select(int n, int readFDs, int writeFDs, int exceptFDs, int timevalAddr) throws ReadFaultException, ErrnoException { + return -ENOSYS; + } + private static String hostName() { try { return InetAddress.getLocalHost().getHostName(); @@ -931,13 +1120,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } - // FEATURE: Run through the fork/wait stuff one more time - public static class GlobalState { - protected static final int OPEN = 1; - protected static final int STAT = 2; - protected static final int LSTAT = 3; - protected static final int MKDIR = 4; - protected static final int UNLINK = 5; + public static final class GlobalState { + Hashtable execCache = new Hashtable(); final UnixRuntime[] tasks; int nextPID = 1; @@ -955,7 +1139,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } } - private static class MP implements Sort.Comparable { + static class MP implements Sort.Comparable { public MP(String path, FS fs) { this.path = path; this.fs = fs; } public String path; public FS fs; @@ -1020,7 +1204,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { mps = newMPS; } - // FEATURE: We shouldn't need to special case the root dir, it should work in the MP array private Object fsop(int op, UnixRuntime r, String normalizedPath, int arg1, int arg2) throws ErrnoException { int pl = normalizedPath.length(); if(pl != 0) { @@ -1030,136 +1213,47 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { MP mp = list[i]; int mpl = mp.path.length(); if(normalizedPath.startsWith(mp.path) && (pl == mpl || normalizedPath.charAt(mpl) == '/')) - return dispatch(mp.fs,op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); + return mp.fs.dispatch(op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); } } - return dispatch(root,op,r,normalizedPath,arg1,arg2); + return root.dispatch(op,r,normalizedPath,arg1,arg2); } - // FEATURE: move this into FS so some filesystem can override it directly (devfs) - private static Object dispatch(FS fs, int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException { - switch(op) { - case OPEN: return fs.open(r,path,arg1,arg2); - case STAT: return fs.stat(r,path); - case LSTAT: return fs.lstat(r,path); - case MKDIR: fs.mkdir(r,path,arg1); return null; - case UNLINK: fs.unlink(r,path); return null; - default: throw new Error("should never happen"); - } - } + public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(FS.OPEN,r,path,flags,mode); } + public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.STAT,r,path,0,0); } + public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.LSTAT,r,path,0,0); } + public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(FS.MKDIR,r,path,mode,0); } + public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(FS.UNLINK,r,path,0,0); } - public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(OPEN,r,path,flags,mode); } - public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(STAT,r,path,0,0); } - public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(LSTAT,r,path,0,0); } - public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(MKDIR,r,path,mode,0); } - public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(UNLINK,r,path,0,0); } - - private Hashtable execCache = new Hashtable(); private static class CacheEnt { public final long time; public final long size; public final Object o; public CacheEnt(long time, long size, Object o) { this.time = time; this.size = size; this.o = o; } } - - public synchronized Object exec(UnixRuntime r, String path) throws ErrnoException { - // HACK: Hideous hack to make a standalone busybox possible - if(path.equals("bin/busybox") && r.getClass().getName().endsWith("BusyBox")) return r.getClass(); - - FStat fstat = stat(r,path); - if(fstat == null) return null; - long mtime = fstat.mtime(); - long size = fstat.size(); - CacheEnt ent = (CacheEnt) execCache.get(path); - if(ent != null) { - //System.err.println("Found cached entry for " + path); - if(ent.time == mtime && ent.size == size) return ent.o; - //System.err.println("Cache was out of date"); - execCache.remove(path); - } - FD fd = open(r,path,RD_ONLY,0); - if(fd == null) return null; - Seekable s = fd.seekable(); - - String[] command = null; - - if(s == null) throw new ErrnoException(EACCES); - byte[] buf = new byte[4096]; - - try { - int n = s.read(buf,0,buf.length); - if(n == -1) throw new ErrnoException(ENOEXEC); - - switch(buf[0]) { - case '\177': // possible ELF - if(n < 4 && s.tryReadFully(buf,n,4-n) != 4-n) throw new ErrnoException(ENOEXEC); - if(buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') throw new ErrnoException(ENOEXEC); - break; - case '#': - if(n == 1) { - int n2 = s.read(buf,1,buf.length-1); - if(n2 == -1) throw new ErrnoException(ENOEXEC); - n += n2; - } - if(buf[1] != '!') throw new ErrnoException(ENOEXEC); - int p = 2; - n -= 2; - OUTER: for(;;) { - for(int i=p;i