From: brian Date: Fri, 23 Apr 2004 07:35:15 +0000 (-0700) Subject: Exec support and cleanup X-Git-Tag: merge~30 X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=commitdiff_plain;h=034a42fa65955289442614ef9914e5474fac62aa Exec support and cleanup tons of cleanup partial exec() support darcs-hash:20040423073515-24bed-0b09a1a4de1ea7b5532260231d549477ae6b34e3.gz --- diff --git a/Makefile b/Makefile index 7f30324..ee8e941 100644 --- a/Makefile +++ b/Makefile @@ -78,12 +78,6 @@ $(tasks)/%: upstream_clean_%: $(MAKE) -C upstream clean_$* usr="$(usr)" -errno_h = $(usr)/mips-unknown-elf/include/sys/errno.h -$(errno_h): $(tasks)/build_newlib - -unistd_h = $(usr)/mips-unknown-elf/include/sys/unistd.h -$(unistd_h): $(tasks)/build_newlib - # # Interpreter/Compiler/Runtime Java Compilation # @@ -190,9 +184,12 @@ unixruntime.jar: $(unixruntime_classes:%=build/org/ibex/nestedvm/%.class) cd build && jar cf ../$@ $(unixruntime_classes:%=org/ibex/nestedvm/%*.class) # This is only for Brian to use... don't mess with it -rebuild-constants: src/org/ibex/nestedvm/syscalls.h $(errno_h) $(unistd_h) +rebuild-constants: $(tasks)/build_newlib @mkdir -p `dirname $@` - cat $^ | ( \ + cat \ + src/org/ibex/nestedvm/syscalls.h \ + $(usr)/mips-unknown-elf/include/sys/{errno.h,unistd.h,syslimits.h} \ + | ( \ echo "// THIS FILE IS AUTOGENERATED! DO NOT EDIT!"; \ echo "// run \"make rebuild-constants\" if it needs to be updated"; \ echo ""; \ diff --git a/src/org/ibex/nestedvm/ClassFileCompiler.java b/src/org/ibex/nestedvm/ClassFileCompiler.java index 0d48aba..0c4dd67 100644 --- a/src/org/ibex/nestedvm/ClassFileCompiler.java +++ b/src/org/ibex/nestedvm/ClassFileCompiler.java @@ -79,7 +79,7 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const if(!pruneCases) throw new Exn("-o prunecases MUST be enabled for ClassFileCompiler"); // Class - cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC,null); + cl = new ClassGen(fullClassName,runtimeClass,source,ACC_SUPER|ACC_PUBLIC|ACC_FINAL,null); cp = cl.getConstantPool(); fac = new InstructionFactory(cl,cp); @@ -193,43 +193,33 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const throw new Exn("Generation of the trampoline method failed. Try increasing maxInsnPerMethod"); } + addConstReturnMethod("gp",gp.addr); + addConstReturnMethod("entryPoint",elf.header.entry); + addConstReturnMethod("heapStart",highestAddr); + + if(userInfo != null) { + addConstReturnMethod("userInfoBase",userInfo.addr); + addConstReturnMethod("userInfoSize",userInfo.size); + } + + // FEATURE: Allow specification of memory size at runtime (numpages) + // Constructor MethodGen init = newMethod(ACC_PUBLIC,Type.VOID, Type.NO_ARGS, ""); selectMethod(init); - // Constructor a(InstructionConstants.ALOAD_0); pushConst(pageSize); pushConst(totalPages); - pushConst(fastMem ? 0 : 1); - a(fac.createInvoke(runtimeClass,"",Type.VOID,new Type[]{Type.INT,Type.INT,Type.BOOLEAN},INVOKESPECIAL)); - a(InstructionConstants.ALOAD_0); - pushConst(gp.addr); - a(fac.createFieldAccess(fullClassName,"gp",Type.INT, PUTFIELD)); + a(fac.createInvoke(runtimeClass,"",Type.VOID,new Type[]{Type.INT,Type.INT},INVOKESPECIAL)); - a(InstructionConstants.ALOAD_0); - pushConst(elf.header.entry); - a(fac.createFieldAccess(fullClassName,"entryPoint",Type.INT, PUTFIELD)); - - a(InstructionConstants.ALOAD_0); - pushConst(onePage ? ((highestAddr+4095)&~4095) : ((highestAddr+pageSize-1)&~(pageSize-1))); - a(fac.createFieldAccess(fullClassName,"brkAddr",Type.INT, PUTFIELD)); - - if(userInfo != null) { - a(InstructionConstants.ALOAD_0); - pushConst(userInfo.addr); - a(fac.createFieldAccess(fullClassName,"userInfoBase",Type.INT, PUTFIELD)); - a(InstructionConstants.ALOAD_0); - pushConst(userInfo.size); - a(fac.createFieldAccess(fullClassName,"userInfoSize",Type.INT, PUTFIELD)); - } a(initExtras); - a(InstructionConstants.ALOAD_0); - pushConst(Runtime.INITIALIZED); - a(fac.createFieldAccess(fullClassName,"state",Type.INT, PUTFIELD)); + a(InstructionConstants.RETURN); + init.setMaxLocals(); init.setMaxStack(); cl.addMethod(init.getMethod()); + MethodGen clinit = newMethod(ACC_PRIVATE|ACC_STATIC,Type.VOID, Type.NO_ARGS, ""); selectMethod(clinit); a(clinitExtras); @@ -318,18 +308,14 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const a(InstructionConstants.ALOAD_1); a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,GETFIELD)); a(fac.createFieldAccess(fullClassName,"pc",Type.INT, PUTFIELD)); + a(InstructionConstants.RETURN); setCPUState.setMaxLocals(); setCPUState.setMaxStack(); cl.addMethod(setCPUState.getMethod()); - MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;"),Type.NO_ARGS,"getCPUState"); + MethodGen getCPUState = newMethod(ACC_PROTECTED,Type.VOID,new Type[]{Type.getType("Lorg/ibex/nestedvm/Runtime$CPUState;")},"getCPUState"); selectMethod(getCPUState); - a(fac.createNew("org.ibex.nestedvm.Runtime$CPUState")); - a(InstructionConstants.DUP); - a(fac.createInvoke("org.ibex.nestedvm.Runtime$CPUState","",Type.VOID,Type.NO_ARGS,INVOKESPECIAL)); - a(InstructionConstants.ASTORE_1); - a(InstructionConstants.ALOAD_1); a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","r",new ArrayType(Type.INT,1),GETFIELD)); a(InstructionConstants.ASTORE_2); @@ -368,13 +354,13 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const a(fac.createFieldAccess(fullClassName,"pc",Type.INT, GETFIELD)); a(fac.createFieldAccess("org.ibex.nestedvm.Runtime$CPUState","pc",Type.INT,PUTFIELD)); - a(InstructionConstants.ALOAD_1); - a(InstructionConstants.ARETURN); + a(InstructionConstants.RETURN); getCPUState.setMaxLocals(); getCPUState.setMaxStack(); 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); @@ -392,7 +378,12 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const a(fac.createInvoke(fullClassName,"",Type.VOID,Type.NO_ARGS,INVOKESPECIAL)); a(new PUSH(cp,fullClassName)); a(InstructionConstants.ALOAD_0); - a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL)); + if(unixRuntime) + a(fac.createInvoke("org.ibex.nestedvm.UnixRuntime","runAndExec",Type.INT, + new Type[]{Type.getType("Lorg/ibex/nestedvm/UnixRuntime;"),Type.STRING,new ArrayType(Type.STRING,1)}, + INVOKESTATIC)); + else + a(fac.createInvoke(fullClassName,"run",Type.INT,new Type[]{Type.STRING,new ArrayType(Type.STRING,1)},INVOKEVIRTUAL)); a(fac.createInvoke("java.lang.System","exit",Type.VOID,new Type[]{Type.INT},INVOKESTATIC)); a(InstructionConstants.RETURN); main.setMaxLocals(); @@ -401,6 +392,16 @@ public class ClassFileCompiler extends Compiler implements org.apache.bcel.Const cl.getJavaClass().dump(os); } + + private void addConstReturnMethod(String name, int val) { + MethodGen method = newMethod(ACC_PROTECTED,Type.INT, Type.NO_ARGS,name); + selectMethod(method); + pushConst(val); + a(InstructionConstants.IRETURN); + method.setMaxLocals(); + method.setMaxStack(); + cl.addMethod(method.getMethod()); + } private static int initDataCount; private void emitData(int addr, DataInputStream dis, int size, boolean readOnly) throws Exn,IOException { diff --git a/src/org/ibex/nestedvm/ClassLoader.java b/src/org/ibex/nestedvm/ClassLoader.java index c1023b0..860e3a7 100644 --- a/src/org/ibex/nestedvm/ClassLoader.java +++ b/src/org/ibex/nestedvm/ClassLoader.java @@ -1,6 +1,11 @@ package org.ibex.nestedvm; import java.io.*; +import java.util.*; + +import org.ibex.nestedvm.util.*; + +// FIXME: This is totally broken now // FEATURE: This is just a quick hack, it is really ugly and broken @@ -10,10 +15,13 @@ import java.io.*; // NOTE: Need to handle binaries spanned accross many classfiles public class ClassLoader extends java.lang.ClassLoader { + private Hashtable cache = new Hashtable(); + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class c; - if(name.startsWith("mips.")) { - String path = name.substring(5).replace('.','/') + ".mips"; + if(name.startsWith("nestedvm.")) { + throw new Error("probably shouldn't be here"); + /*String path = name.substring(5).replace('.','/') + ".mips"; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ClassFileCompiler(path,name,bos).go(); @@ -24,7 +32,7 @@ public class ClassLoader extends java.lang.ClassLoader { throw new ClassNotFoundException(name); } catch(Compiler.Exn e) { throw new ClassNotFoundException(e.getMessage()); - } + }*/ } else { c = findSystemClass(name); } @@ -34,7 +42,45 @@ public class ClassLoader extends java.lang.ClassLoader { return c; } - public Class classFromBinary(String path) throws ClassNotFoundException { + /*public synchronized void clearCache() { + cache.clear(); + } + + public synchronized Class getCachedClass(String key, long timeStamp) { + String name = "nestedvm." + Base64.encode(key); + CacheEnt ent = (CacheEnt) cache.get(name); + if(ent.timeStamp < timeStamp) { + cache.remove(key); + return null; + } + return ent.klass; + } + + public synchronized Class createClass(String key, long timeStamp, Seekable data) { + Class klass = getCachedClass(key,timeStamp); + if(klass != null) return klass; + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + new ClassFileCompiler(data,name,bos).go(); + bos.close(); + byte[] buf = bos.toByteArray(); + klass = defineClass(name,buf,0,buf.length); + resolveClass(klass); + cache.put(key,new CacheEnt(klass,timeStamp)); + return klass; + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + private class CacheEnt { + public CacheEnt(Class klass, long timeStamp) { this.klass = klass; this.timeStamp = timeStamp; } + public Class klass; + public long timeStamp; + }*/ + + /*public Class classFromBinary(String path) throws ClassNotFoundException { if(!path.endsWith(".mips")) throw new IllegalArgumentException("isn't a .mips"); return loadClass("mips." + path.substring(0,path.length()-5).replace('/','.')); } @@ -45,5 +91,5 @@ public class ClassLoader extends java.lang.ClassLoader { public static void main(String[] args) throws Exception { System.exit(new ClassLoader().runtimeFromBinary(args[0]).run(args)); - } + }*/ } diff --git a/src/org/ibex/nestedvm/Compiler.java b/src/org/ibex/nestedvm/Compiler.java index c68e5cf..68d2dee 100644 --- a/src/org/ibex/nestedvm/Compiler.java +++ b/src/org/ibex/nestedvm/Compiler.java @@ -79,11 +79,8 @@ public abstract class Compiler implements Registers { protected boolean onePage; protected void pageSizeInit() throws Exn { - try { - Runtime.checkPageSize(pageSize,totalPages); - } catch(IllegalArgumentException e) { - throw new Exn(e.getMessage()); - } + if((pageSize&(pageSize-1)) != 0) throw new Exn("pageSize not a multiple of two"); + if((totalPages&(totalPages-1)) != 0) throw new Exn("totalPages not a multiple of two"); while(pageSize>>>pageShift != 1) pageShift++; } diff --git a/src/org/ibex/nestedvm/Interpreter.java b/src/org/ibex/nestedvm/Interpreter.java index cd82365..276eea7 100644 --- a/src/org/ibex/nestedvm/Interpreter.java +++ b/src/org/ibex/nestedvm/Interpreter.java @@ -54,6 +54,7 @@ public class Interpreter extends UnixRuntime { // Main interpretor // the return value is meaningless, its just to catch people typing "return" by accident private final int runSome() throws FaultException,ExecutionException { + final int PAGE_WORDS = (1<>2; int[] r = registers; int[] f = fpregs; int pc = this.pc; @@ -62,7 +63,7 @@ public class Interpreter extends UnixRuntime { OUTER: for(;;) { int insn; try { - insn = readPages[pc>>>PAGE_SHIFT][(pc>>>2)&PAGE_WORDS-1]; + insn = readPages[pc>>>pageShift][(pc>>>2)&PAGE_WORDS-1]; } catch (RuntimeException e) { insn = memRead(pc); } @@ -430,7 +431,7 @@ public class Interpreter extends UnixRuntime { case 32: { // LB addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -447,7 +448,7 @@ public class Interpreter extends UnixRuntime { case 33: { // LH addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -462,7 +463,7 @@ public class Interpreter extends UnixRuntime { case 34: { // LWL; addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -477,7 +478,7 @@ public class Interpreter extends UnixRuntime { case 35: // LW addr = r[rs] + signedImmediate; try { - r[rt] = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + r[rt] = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { r[rt] = memRead(addr); } @@ -485,7 +486,7 @@ public class Interpreter extends UnixRuntime { case 36: { // LBU addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr); } @@ -500,7 +501,7 @@ public class Interpreter extends UnixRuntime { case 37: { // LHU addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -513,7 +514,7 @@ public class Interpreter extends UnixRuntime { case 38: { // LWR addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -528,7 +529,7 @@ public class Interpreter extends UnixRuntime { case 40: { // SB addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -539,7 +540,7 @@ public class Interpreter extends UnixRuntime { case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break; } try { - writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp; } catch(RuntimeException e) { memWrite(addr&~3,tmp); } @@ -548,7 +549,7 @@ public class Interpreter extends UnixRuntime { case 41: { // SH addr = r[rs] + signedImmediate; try { - tmp = readPages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)]; + tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)]; } catch(RuntimeException e) { tmp = memRead(addr&~3); } @@ -557,7 +558,7 @@ public class Interpreter extends UnixRuntime { case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break; } try { - writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp; } catch(RuntimeException e) { memWrite(addr&~3,tmp); } @@ -573,7 +574,7 @@ public class Interpreter extends UnixRuntime { case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break; } try { - writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = tmp; + writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp; } catch(RuntimeException e) { memWrite(addr&~3,tmp); } @@ -582,7 +583,7 @@ public class Interpreter extends UnixRuntime { case 43: // SW addr = r[rs] + signedImmediate; try { - writePages[addr>>>PAGE_SHIFT][(addr>>>2)&(PAGE_WORDS-1)] = r[rt]; + writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = r[rt]; } catch(RuntimeException e) { memWrite(addr&~3,r[rt]); } @@ -632,10 +633,21 @@ public class Interpreter extends UnixRuntime { return sym == null ? -1 : sym.addr; } + private int gp; + protected int gp() { return gp; } + + private ELF.Symbol userInfo; + protected int userInfoBae() { return userInfo == null ? 0 : userInfo.addr; } + protected int userInfoSize() { return userInfo == null ? 0 : userInfo.size; } + + private int entryPoint; + protected int entryPoint() { return entryPoint; } + + private int heapStart; + protected int heapStart() { return heapStart; } + // Image loading function private void loadImage(Seekable data) throws IOException { - if(state != UNINITIALIZED) throw new IllegalStateException("loadImage called on initialized runtime"); - ELF elf = new ELF(data); symtab = elf.getSymtab(); @@ -647,19 +659,18 @@ public class Interpreter extends UnixRuntime { ELF.Symtab symtab = elf.getSymtab(); if(symtab == null) throw new IOException("No symtab in binary (did you strip it?)"); - ELF.Symbol userInfo = symtab.getGlobalSymbol("user_info"); + userInfo = symtab.getGlobalSymbol("user_info"); ELF.Symbol gpsym = symtab.getGlobalSymbol("_gp"); if(gpsym == null) throw new IOException("NO _gp symbol!"); gp = gpsym.addr; - if(userInfo != null) { - userInfoBase = userInfo.addr; - userInfoSize = userInfo.size; - } + entryPoint = elf.header.entry; ELF.PHeader[] pheaders = elf.pheaders; int brk = 0; + int pageSize = (1<> 2; for(int i=0;i>> PAGE_SHIFT; + for(int j=0;j>> pageShift; if(readPages[page] == null) - readPages[page] = new int[PAGE_WORDS]; + readPages[page] = new int[pageWords]; if(ph.writable()) writePages[page] = readPages[page]; } if(filesize != 0) { filesize = filesize & ~3; DataInputStream dis = new DataInputStream(ph.getInputStream()); do { - readPages[addr >>> PAGE_SHIFT][(addr >>> 2)&(PAGE_WORDS-1)] = dis.readInt(); + readPages[addr >>> pageShift][(addr >>> 2)&(pageWords-1)] = dis.readInt(); addr+=4; filesize-=4; } while(filesize > 0); dis.close(); } } - brkAddr = (brk+PAGE_SIZE-1)&~(PAGE_SIZE-1); - state = INITIALIZED; + heapStart = (brk+pageSize-1)&~(pageSize-1); } protected void setCPUState(CPUState state) { @@ -699,18 +709,17 @@ public class Interpreter extends UnixRuntime { pc=state.pc; } - protected CPUState getCPUState() { - CPUState state = new CPUState(); + protected void getCPUState(CPUState state) { for(int i=1;i<32;i++) state.r[i] = registers[i]; for(int i=0;i<32;i++) state.f[i] = fpregs[i]; state.hi=hi; state.lo=lo; state.fcsr=fcsr; state.pc=pc; - return state; } - // This is package private for fork() which does all kinds of ugly things behind the scenes - Interpreter() { super(4096,65536,true); } - public Interpreter(Seekable data) throws IOException { this(); loadImage(data); } + public Interpreter(Seekable data) throws IOException { + super(4096,65536); + loadImage(data); + } public Interpreter(String filename) throws IOException { this(new Seekable.File(filename,false)); image = filename; diff --git a/src/org/ibex/nestedvm/JavaSourceCompiler.java b/src/org/ibex/nestedvm/JavaSourceCompiler.java index d71bee8..b581d22 100644 --- a/src/org/ibex/nestedvm/JavaSourceCompiler.java +++ b/src/org/ibex/nestedvm/JavaSourceCompiler.java @@ -47,7 +47,7 @@ public class JavaSourceCompiler extends Compiler { if (packageName != null) p("package " + packageName + ";"); if(runtimeStats) p("import java.util.*;"); p(); - p("public class " + className + " extends " + runtimeClass + " {"); + p("public final class " + className + " extends " + runtimeClass + " {"); indent++; p("/* program counter */"); @@ -116,23 +116,20 @@ public class JavaSourceCompiler extends Compiler { // Constructor p("public " + className + "() {"); indent++; - p("super(" + pageSize + "," + totalPages + "," + (fastMem?"false":"true") + ");"); - p("entryPoint = " + toHex(elf.header.entry) + ";"); - if(userInfo != null) { - p("userInfoBase=" + toHex(userInfo.addr) + ";"); - p("userInfoSize=" + userInfo.size + ";"); - } - p("gp = " + toHex(gp.addr) + ";"); - if(onePage) - p("brkAddr = " + toHex((highestAddr+4095)&~4095) + ";"); - else - p("brkAddr = " + toHex((highestAddr+pageSize-1)&~(pageSize-1)) + ";"); + p("super(" + pageSize + "," + totalPages + ");"); pblock(inits); - p("state = INITIALIZED;"); indent--; p("}"); p(); + p("protected int entryPoint() { return " + toHex(elf.header.entry) + "; }"); + p("protected int heapStart() { return " + toHex(highestAddr) + "; }"); + p("protected int gp() { return " + toHex(gp.addr) + "; }"); + if(userInfo != null) { + p("protected int userInfoBase() { return " + toHex(userInfo.addr) + "; }"); + p("protected int userInfoSize() { return " + toHex(userInfo.size) + "; }"); + } + // main() function p("public static void main(String[] args) throws Exception {"); indent++; @@ -156,14 +153,12 @@ public class JavaSourceCompiler extends Compiler { p("pc=state.pc;"); indent--; p("}"); - p("protected CPUState getCPUState() {"); + p("protected void getCPUState(CPUState state) {"); indent++; - p("CPUState state = new CPUState();"); for(int i=1;i<32;i++) p("state.r[" + i + "]=r" + i+ ";"); for(int i=0;i<32;i++) p("state.f[" + i + "]=f" + i +";"); p("state.hi=hi; state.lo=lo; state.fcsr=fcsr;"); p("state.pc=pc;"); - p("return state;"); indent--; p("}"); p(); diff --git a/src/org/ibex/nestedvm/Runtime.java b/src/org/ibex/nestedvm/Runtime.java index bcbadd4..a04dac2 100644 --- a/src/org/ibex/nestedvm/Runtime.java +++ b/src/org/ibex/nestedvm/Runtime.java @@ -11,81 +11,66 @@ 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 { - /** Pages are 4k in size */ - protected final int PAGE_SIZE; - protected final int PAGE_WORDS; - protected final int PAGE_SHIFT; - protected final int TOTAL_PAGES; - /** This is the upper limit of the pages allocated by the sbrk() syscall. */ - protected final int BRK_LIMIT; - protected final int STACK_BOTTOM; - - /** This is the maximum size of command line arguments */ - public final static int ARGS_MAX = 1024*1024; - - /** True if we allow empty pages (_emptyPage) to exist in memory. - Empty pages are pages which are allocated by the program but do not contain any - data yet (they are all 0s). If empty pages are allowed subclasses must always - access main memory with the memRead and memWrite functions */ - private final boolean allowEmptyPages; - /** the "empty page" */ - private final static int[] _emptyPage = new int[0]; - - protected final static boolean isEmptyPage(int[] page) { return page == _emptyPage; } - - /** Returns a new empty page (_emptyPage is empty pages are enabled or a new zero'd page) */ - private final int[] emptyPage() { return allowEmptyPages ? _emptyPage : new int[PAGE_WORDS]; } +public abstract class Runtime implements UsermodeConstants,Registers,Cloneable { + /** Number of bits to shift to get the page number (1<<state */ protected abstract void setCPUState(CPUState state); - - static void checkPageSize(int pageSize, int totalPages) throws IllegalArgumentException { - if(pageSize < 256) throw new IllegalArgumentException("pageSize too small"); - if((pageSize&(pageSize-1)) != 0) throw new IllegalArgumentException("pageSize must be a power of two"); - if((totalPages&(totalPages-1)) != 0) throw new IllegalArgumentException("totalPages must be a power of two"); - if(totalPages != 1 && totalPages < 256) throw new IllegalArgumentException("totalPages too small"); - if(totalPages * pageSize < 4*1024*1024) throw new IllegalArgumentException("total memory too small (" + totalPages + "*" + pageSize + ")"); + + 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; - int pageShift = 0; - while(pageSize>>>pageShift != 1) pageShift++; - PAGE_SHIFT = pageShift; - - TOTAL_PAGES = totalPages; - - readPages = new int[TOTAL_PAGES][]; - writePages = new int[TOTAL_PAGES][]; + protected Runtime(int pageSize, int totalPages) { + if(pageSize <= 0) throw new IllegalArgumentException("pageSize <= 0"); + if(totalPages <= 0) throw new IllegalArgumentException("totalPages <= 0"); + if((pageSize&(pageSize-1)) != 0) throw new IllegalArgumentException("pageSize not a power of two"); + + int _pageShift = 0; + while(pageSize>>>_pageShift != 1) _pageShift++; + pageShift = _pageShift; - if(TOTAL_PAGES == 1) { - readPages[0] = writePages[0] = new int[PAGE_WORDS]; - BRK_LIMIT = STACK_BOTTOM = 0; + int heapStart = heapStart(); + int totalMemory = totalPages * pageSize; + int stackSize = max(totalMemory/64,ARG_MAX+65536); + int stackPages = 0; + if(totalPages > 1) { + stackSize = max(stackSize,pageSize); + stackSize = (stackSize + pageSize) & ~(pageSize-1); + stackPages = stackSize >>> pageShift; + heapStart = (heapStart + pageSize) & ~(pageSize-1); + if(stackPages + STACK_GUARD_PAGES + (heapStart >>> pageShift) >= totalPages) + throw new IllegalArgumentException("total pages too small"); } else { - int stackPages = max(TOTAL_PAGES>>>8,(1024*1024)>>>PAGE_SHIFT); - STACK_BOTTOM = (TOTAL_PAGES - stackPages) * PAGE_SIZE; - // leave some unmapped pages between the stack and the heap - BRK_LIMIT = STACK_BOTTOM - 4*PAGE_SIZE; - - for(int i=0;i>2]; + else + for(int i=stackBottom >>> pageShift;i>2]; + addFD(new StdinFD(System.in)); addFD(new StdoutFD(System.out)); addFD(new StdoutFD(System.err)); @@ -158,10 +160,13 @@ public abstract class Runtime implements UsermodeConstants,Registers { /** Copy everything from src to addr initializing uninitialized pages if required. Newly initalized pages will be marked read-only if ro is set */ protected final void initPages(int[] src, int addr, boolean ro) { + int pageWords = (1<>>2; + int pageMask = (1<>> PAGE_SHIFT; - int start = (addr&(PAGE_SIZE-1))>>2; - int elements = min(PAGE_WORDS-start,src.length-i); + int page = addr >>> pageShift; + int start = (addr&pageMask)>>2; + int elements = min(pageWords-start,src.length-i); if(readPages[page]==null) { initPage(page,ro); } else if(!ro) { @@ -175,12 +180,15 @@ public abstract class Runtime implements UsermodeConstants,Registers { /** Initialize words of pages starting at addr to 0 */ protected final void clearPages(int addr, int words) { + int pageWords = (1<>>2; + int pageMask = (1<>> PAGE_SHIFT; - int start = (addr&(PAGE_SIZE-1))>>2; - int elements = min(PAGE_WORDS-start,words-i); + int page = addr >>> pageShift; + int start = (addr&pageMask)>>2; + int elements = min(pageWords-start,words-i); if(readPages[page]==null) { - readPages[page] = writePages[page] = emptyPage(); + readPages[page] = writePages[page] = new int[pageWords]; } else { if(writePages[page] == null) writePages[page] = readPages[page]; for(int j=start;jlength bytes from the processes memory space starting at addr INTO a java byte array a */ public final void copyin(int addr, byte[] buf, int count) throws ReadFaultException { + int pageWords = (1<>>2; + int pageMask = pageWords - 1; + int x=0; if(count == 0) return; if((addr&3)!=0) { @@ -208,16 +219,14 @@ public abstract class Runtime implements UsermodeConstants,Registers { int c = count>>>2; int a = addr>>>2; while(c != 0) { - int[] page = readPages[a >>> (PAGE_SHIFT-2)]; + int[] page = readPages[a >>> (pageShift-2)]; if(page == null) throw new ReadFaultException(a<<2); - int index = a&(PAGE_WORDS-1); - int n = min(c,PAGE_WORDS-index); - if(page != _emptyPage) { - for(int i=0;i>>24)&0xff); buf[x+1] = (byte)((word>>>16)&0xff); - buf[x+2] = (byte)((word>>> 8)&0xff); buf[x+3] = (byte)((word>>> 0)&0xff); - } + int index = a&pageMask; + int n = min(c,pageWords-index); + for(int i=0;i>>24)&0xff); buf[x+1] = (byte)((word>>>16)&0xff); + buf[x+2] = (byte)((word>>> 8)&0xff); buf[x+3] = (byte)((word>>> 0)&0xff); } a += n; c -=n; } @@ -236,6 +245,9 @@ public abstract class Runtime implements UsermodeConstants,Registers { /** Copies length bytes OUT OF the java array a into the processes memory space at addr */ public final void copyout(byte[] buf, int addr, int count) throws FaultException { + int pageWords = (1<>>2; + int pageWordMask = pageWords - 1; + int x=0; if(count == 0) return; if((addr&3)!=0) { @@ -248,21 +260,22 @@ public abstract class Runtime implements UsermodeConstants,Registers { memWrite(addr&~3,word); addr += x; } + if((count&~3) != 0) { int c = count>>>2; int a = addr>>>2; while(c != 0) { - int[] page = writePages[a >>> (PAGE_SHIFT-2)]; + int[] page = writePages[a >>> (pageShift-2)]; if(page == null) throw new WriteFaultException(a<<2); - if(page == _emptyPage) page = initPage(a >>> (PAGE_SHIFT-2)); - int index = a&(PAGE_WORDS-1); - int n = min(c,PAGE_WORDS-index); + int index = a&pageWordMask; + int n = min(c,pageWords-index); for(int i=0;i>>2; + int pageWordMask = pageWords - 1; + if((dst&3) == 0 && (src&3)==0) { if((count&~3) != 0) { int c = count>>2; int s = src>>>2; int d = dst>>>2; while(c != 0) { - int[] srcPage = readPages[s>>>(PAGE_SHIFT-2)]; + int[] srcPage = readPages[s>>>(pageShift-2)]; if(srcPage == null) throw new ReadFaultException(s<<2); - int[] dstPage = writePages[d>>>(PAGE_SHIFT-2)]; + int[] dstPage = writePages[d>>>(pageShift-2)]; if(dstPage == null) throw new WriteFaultException(d<<2); - int srcIndex = (s&(PAGE_WORDS-1)); - int dstIndex = (d&(PAGE_WORDS-1)); - int n = min(c,PAGE_WORDS-max(srcIndex,dstIndex)); - if(srcPage != _emptyPage) { - if(dstPage == _emptyPage) dstPage = initPage(d>>>(PAGE_SHIFT-2)); - System.arraycopy(srcPage,srcIndex,dstPage,dstIndex,n); - } else if(srcPage == _emptyPage && dstPage != _emptyPage) { - Arrays.fill(dstPage,dstIndex,dstIndex+n,0); - } + int srcIndex = s&pageWordMask; + int dstIndex = d&pageWordMask; + int n = min(c,pageWords-max(srcIndex,dstIndex)); + System.arraycopy(srcPage,srcIndex,dstPage,dstIndex,n); s += n; d += n; c -= n; } src = s<<2; dst = d<<2; count&=3; @@ -319,6 +330,9 @@ public abstract class Runtime implements UsermodeConstants,Registers { } public final void memset(int addr, int ch, int count) throws FaultException { + int pageWords = (1<>>2; + int pageWordMask = pageWords - 1; + int fourBytes = ((ch&0xff)<<24)|((ch&0xff)<<16)|((ch&0xff)<<8)|((ch&0xff)<<0); if((addr&3)!=0) { int word = memRead(addr&~3); @@ -334,14 +348,11 @@ public abstract class Runtime implements UsermodeConstants,Registers { int c = count>>2; int a = addr>>>2; while(c != 0) { - int[] page = readPages[a>>>(PAGE_SHIFT-2)]; + int[] page = readPages[a>>>(pageShift-2)]; if(page == null) throw new WriteFaultException(a<<2); - int index = (a&(PAGE_WORDS-1)); - int n = min(c,PAGE_WORDS-index); - if(page != _emptyPage || ch != 0) { - if(page == _emptyPage) page = initPage(a>>>(PAGE_SHIFT-2)); - Arrays.fill(page,index,index+n,fourBytes); - } + int index = a&pageWordMask; + int n = min(c,pageWords-index); + Arrays.fill(page,index,index+n,fourBytes); a += n; c -= n; } addr = a<<2; count&=3; @@ -364,16 +375,13 @@ public abstract class Runtime implements UsermodeConstants,Registers { } protected final int unsafeMemRead(int addr) throws ReadFaultException { - int page = addr >>> PAGE_SHIFT; - int entry = (addr >>> 2) & (PAGE_WORDS-1); + int page = addr >>> pageShift; + int entry = (addr&(1<>2; try { return readPages[page][entry]; } catch(ArrayIndexOutOfBoundsException e) { - if(page < 0) throw e; // should never happen - if(page >= readPages.length) throw new ReadFaultException(addr); - if(readPages[page] != _emptyPage) throw e; // should never happen - initPage(page); - return 0; + if(page < 0 || page >= readPages.length) throw new ReadFaultException(addr); + throw e; // should never happen } catch(NullPointerException e) { throw new ReadFaultException(addr); } @@ -386,16 +394,13 @@ public abstract class Runtime implements UsermodeConstants,Registers { } protected final void unsafeMemWrite(int addr, int value) throws WriteFaultException { - int page = addr >>> PAGE_SHIFT; - int entry = (addr>>>2)&(PAGE_WORDS-1); + int page = addr >>> pageShift; + int entry = (addr&(1<>2; try { writePages[page][entry] = value; } catch(ArrayIndexOutOfBoundsException e) { - if(page < 0) throw e;// should never happen - if(page >= writePages.length) throw new WriteFaultException(addr); - if(readPages[page] != _emptyPage) throw e; // should never happen - initPage(page); - writePages[page][entry] = value; + if(page < 0 || page >= writePages.length) throw new WriteFaultException(addr); + throw e; // should never happen } catch(NullPointerException e) { throw new WriteFaultException(addr); } @@ -405,7 +410,7 @@ public abstract class Runtime implements UsermodeConstants,Registers { private final int[] initPage(int page) { return initPage(page,false); } /** Created a new non-empty page at page number page. If ro is set the page will be read-only */ private final int[] initPage(int page, boolean ro) { - int[] buf = new int[PAGE_WORDS]; + int[] buf = new int[(1<>>2]; writePages[page] = ro ? null : buf; readPages[page] = buf; return buf; @@ -414,15 +419,14 @@ public abstract class Runtime implements UsermodeConstants,Registers { /** Returns the exit status of the process. (only valid if state == DONE) @see Runtime#state */ public final int exitStatus() { - if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state"); + if(state != EXITED) throw new IllegalStateException("exitStatus() called in an inappropriate state"); return exitStatus; } - private int addStringArray(String[] strings, int topAddr) { + private int addStringArray(String[] strings, int topAddr) throws FaultException { int count = strings.length; int total = 0; /* null last table entry */ for(int i=0;i= ARGS_MAX) throw new IllegalArgumentException("arguments/environ too big"); total += (count+1)*4; int start = (topAddr - total)&~3; int addr = start + (count+1)*4; @@ -455,19 +459,19 @@ public abstract class Runtime implements UsermodeConstants,Registers { * and location of the user_info table from the ELF symbol table. setUserInfo and * getUserInfo are used to modify the words in the user_info table. */ public void setUserInfo(int index, int word) { - if(index < 0 || index >= userInfoSize/4) throw new IndexOutOfBoundsException("setUserInfo called with index >= " + (userInfoSize/4)); + if(index < 0 || index >= userInfoSize()/4) throw new IndexOutOfBoundsException("setUserInfo called with index >= " + (userInfoSize()/4)); try { - memWrite(userInfoBase+index*4,word); - } catch(FaultException e) { throw new Error("should never happen: " + e); } + memWrite(userInfoBase()+index*4,word); + } catch(FaultException e) { throw new RuntimeException(e.toString()); } } /** Returns the word in the _user_info table entry index @see Runtime#setUserInfo(int,int) setUserInfo */ public int getUserInfo(int index) { - if(index < 0 || index >= userInfoSize/4) throw new IndexOutOfBoundsException("setUserInfo called with index >= " + (userInfoSize/4)); + if(index < 0 || index >= userInfoSize()/4) throw new IndexOutOfBoundsException("setUserInfo called with index >= " + (userInfoSize()/4)); try { - return memRead(userInfoBase+index*4); - } catch(FaultException e) { throw new Error("should never happen: " + e); } + return memRead(userInfoBase()+index*4); + } catch(FaultException e) { throw new RuntimeException(e.toString()); } } /** Calls _execute() (subclass's execute()) and catches exceptions */ @@ -492,17 +496,20 @@ public abstract class Runtime implements UsermodeConstants,Registers { if(startTime == 0) startTime = System.currentTimeMillis(); state = RUNNING; __execute(); - if(state != PAUSED && state != DONE) throw new IllegalStateException("execute() ended up in an inappropriate state (" + state + ")"); - return state == DONE; + if(state != PAUSED && state != EXITED && state != EXECED) + throw new IllegalStateException("execute() ended up in an inappropriate state (" + state + ")"); + return state != PAUSED; } - public final int run() { return run(null); } - public final int run(String argv0, String[] rest) { - String[] args = new String[rest.length+1]; - System.arraycopy(rest,0,args,1,rest.length); - args[0] = argv0; - return run(args); + protected 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; } + + public final int run() { return run(null); } + public final int run(String argv0, String[] rest) { return run(concatArgv(argv0,rest)); } public final int run(String[] args) { return run(args,null); } /** Runs the process until it exits and returns the exit status. @@ -512,9 +519,9 @@ public abstract class Runtime implements UsermodeConstants,Registers { for(;;) { if(execute()) break; System.err.println("WARNING: Pause requested while executing run()"); - try { Thread.sleep(500); } catch(InterruptedException e) { /* noop */ } } - return exitStatus(); + if(state == EXECED) System.err.println("WARNING: Process exec()ed while being run under run()"); + return state == EXITED ? exitStatus() : 0; } public final void start() { start(null); } @@ -522,28 +529,33 @@ public abstract class Runtime implements UsermodeConstants,Registers { /** Initializes the process and prepairs it to be executed with execute() */ public final void start(String[] args, String[] environ) { - int sp, argsAddr, envAddr; - if(state != INITIALIZED) throw new IllegalStateException("start() called in inappropriate state"); + 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 = TOTAL_PAGES*PAGE_SIZE-512; - sp = argsAddr = addStringArray(args,sp); - sp = envAddr = addStringArray(createEnv(environ),sp); + sp = top = writePages.length*(1< ARG_MAX) throw new IllegalArgumentException("args/environ too big"); + CPUState cpuState = new CPUState(); cpuState.r[A0] = argsAddr; cpuState.r[A1] = envAddr; cpuState.r[SP] = sp; cpuState.r[RA] = 0xdeadbeef; - cpuState.r[GP] = gp; - cpuState.pc = entryPoint; + cpuState.r[GP] = gp(); + cpuState.pc = entryPoint(); setCPUState(cpuState); - + state = PAUSED; - _start(); + _start(); } /** Hook for subclasses to do their own startup */ @@ -572,9 +584,11 @@ public abstract class Runtime implements UsermodeConstants,Registers { public final int call(int addr, int a0, int a1, int a2, int a3, int s0, int s1, int s2, int s3) { if(state != PAUSED && state != CALLJAVA) throw new IllegalStateException("call() called in inappropriate state"); int oldState = state; - CPUState saved = getCPUState(); - CPUState cpustate = new CPUState(); - cpustate.r[SP] = saved.r[SP]&~15; + CPUState saved = new CPUState(); + getCPUState(saved); + CPUState cpustate = saved.dup(); + + cpustate.r[SP] = cpustate.r[SP]&~15; cpustate.r[RA] = 0xdeadbeef; cpustate.r[A0] = a0; cpustate.r[A1] = a1; @@ -584,14 +598,13 @@ public abstract class Runtime implements UsermodeConstants,Registers { cpustate.r[S1] = s1; cpustate.r[S2] = s2; cpustate.r[S3] = s3; - cpustate.r[GP] = gp; cpustate.pc = addr; state = RUNNING; setCPUState(cpustate); __execute(); - cpustate = getCPUState(); + getCPUState(cpustate); setCPUState(saved); if(state != PAUSED) @@ -613,15 +626,18 @@ public abstract class Runtime implements UsermodeConstants,Registers { Returns -1 if the table is full. This can be used by subclasses to use custom file descriptors */ public 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) { + 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; fds[fdn].close(); @@ -856,31 +872,26 @@ public abstract class Runtime implements UsermodeConstants,Registers { incr is how much to increase the break by */ public int sbrk(int incr) { if(incr < 0) return -ENOMEM; - if(incr==0) return brkAddr; + if(incr==0) return heapEnd; incr = (incr+3)&~3; - int oldBrk = brkAddr; - int newBrk = oldBrk + incr; - if(TOTAL_PAGES == 1) { - CPUState state = getCPUState(); - if(newBrk >= state.r[SP] - 65536) { - System.err.println("WARNING: brk too close to stack pointer"); - return -ENOMEM; - } - } else if(newBrk >= BRK_LIMIT) { - System.err.println("WARNING: Hit BRK_LIMIT"); - return -ENOMEM; - } - if(TOTAL_PAGES != 1) { + int oldEnd = heapEnd; + int newEnd = oldEnd + incr; + if(newEnd >= stackBottom) return -ENOMEM; + + if(writePages.length > 1) { + int pageMask = (1<>> 2; + int start = (oldEnd + pageMask) >>> pageShift; + int end = (newEnd + pageMask) >>> pageShift; try { - for(int i=(oldBrk+PAGE_SIZE-1)>>>PAGE_SHIFT;i<((newBrk+PAGE_SIZE-1)>>>PAGE_SHIFT);i++) - readPages[i] = writePages[i] = emptyPage(); + for(int i=start;i= OPEN_MAX) return -EBADFD; @@ -916,17 +927,20 @@ public abstract class Runtime implements UsermodeConstants,Registers { } - /** Hook for subclasses to do something when the process exits (MUST set state = DONE) */ - protected void _exit() { state = DONE; } + /** Hook for subclasses to do something when the process exits (MUST set state = EXITED) */ + protected void _exit() { state = EXITED; } private int sys_exit(int status) { exitStatus = status; - for(int i=0;i>>PAGE_SHIFT) < 16) + if(addr < 65536) throw new ExecutionException("Attempted to dereference a null pointer " + toHex(addr)); } diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index 135348f..24a7967 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -7,7 +7,10 @@ import java.util.*; // FEATURE: 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 { +// FEATURE: Throw ErrnoException and catch in syscall whereever possible +// (only in cases where we've already paid the price for a throw) + +public abstract class UnixRuntime extends Runtime implements Cloneable { /** The pid of this "process" */ private int pid; private int ppid; @@ -17,7 +20,7 @@ public abstract class UnixRuntime extends Runtime { private FS fs; public FS getFS() { return fs; } public void setFS(FS fs) { - if(state >= RUNNING) throw new IllegalStateException("Can't change fs while process is running"); + if(state != STOPPED) throw new IllegalStateException("Can't change fs while process is running"); this.fs = fs; } @@ -25,6 +28,9 @@ public abstract class UnixRuntime extends Runtime { "" = root, "bin" = /bin "usr/bin" = /usr/bin */ private String cwd; + /** The runtime that should be run next when in state == EXECED */ + private UnixRuntime execedRuntime; + /* Static stuff */ // FEATURE: Most of this is O(n) or worse - fix it private final Object waitNotification = new Object(); @@ -49,8 +55,8 @@ public abstract class UnixRuntime extends Runtime { } } - public UnixRuntime(int pageSize, int totalPages, boolean allowEmptyPages) { - super(pageSize,totalPages,allowEmptyPages); + public UnixRuntime(int pageSize, int totalPages) { + super(pageSize,totalPages); FS root = new HostFS(); FS dev = new DevFS(); @@ -111,11 +117,11 @@ public abstract class UnixRuntime extends Runtime { if(ppid == 0) removeTask(this); for(int i=0;i= sp-PAGE_SIZE*2) - System.arraycopy(writePages[i],0,r.writePages[i],0,PAGE_WORDS); - } else { - r.readPages[i] = r.readPages[i]; - } - } - state.r[V0] = 0; - state.pc += 4; + + state.r[V0] = 0; // return 0 to child + state.pc += 4; // skip over syscall instruction r.setCPUState(state); r.state = PAUSED; @@ -269,23 +254,108 @@ public abstract class UnixRuntime extends Runtime { } }.start(); - return child_pid; + return childPID; + } + + public static int runAndExec(UnixRuntime r, String argv0, String[] rest) { return runAndExec(r,concatArgv(argv0,rest)); } + public static int runAndExec(UnixRuntime r, String[] argv) { r.start(argv); return executeAndExec(r); } + + public static int executeAndExec(UnixRuntime r) { + for(;;) { + for(;;) { + if(r.execute()) break; + System.err.println("WARNING: Pause requested while executing runAndExec()"); + } + if(r.state != EXECED) return r.exitStatus(); + r = r.execedRuntime; + } + } + + private String[] readStringArray(int addr) throws ReadFaultException { + int count = 0; + for(int p=addr;memRead(p) != 0;p+=4) count++; + String[] a = new String[count]; + for(int i=0,p=addr;i= 0) return -EACCES; + return -ENOENT; + } + catch(IOException e) { return -EIO; } + catch(FaultException e) { return -EFAULT; }*/ + } + + private int exec(Class c, String[] argv, String[] envp) { + UnixRuntime r; - private int sys_execve(int cstring, int argv, int envp) { - /* try { - String path = cstring(cstring); - FStat stat = fs.stat(path); - - + r = (UnixRuntime) c.newInstance(); + } catch(Exception e) { + return -ENOMEM; } - catch(FaultException e) { return -EFAULT; } - catch(FileNotFoundException e) { return -ENOENT; } - catch(IOException e) { return -EIO; }*/ - throw new Error("FIXME - exec() isn't finished"); + + for(int i=0;i= RUNNING) throw new IllegalStateException("Can't chdir while process is running"); + if(state != STOPPED) throw new IllegalStateException("Can't chdir while process is running"); try { dir = normalizePath(dir); if(fs.stat(dir).type() != FStat.S_IFDIR) throw new FileNotFoundException(); @@ -409,8 +479,10 @@ public abstract class UnixRuntime extends Runtime { public final FD open(String path, int flags, int mode) throws IOException { return (FD) op(OPEN,path,flags,mode); } public final FStat stat(String path) throws IOException { return (FStat) op(STAT,path,0,0); } public final void mkdir(String path) throws IOException { op(MKDIR,path,0,0); } + - // FIXME: inode stuff + // FEATURE: inode stuff + // FEATURE: Implement whatever is needed to get newlib's opendir and friends to work - that patch is a pain protected static FD directoryFD(String[] files, int hashCode) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); @@ -466,6 +538,7 @@ public abstract class UnixRuntime extends Runtime { continue; } inp++; + out[outp++] = '/'; out[outp++] = '.'; } if(outp > 0 && out[outp-1] == '/') outp--; @@ -473,58 +546,6 @@ public abstract class UnixRuntime extends Runtime { return new String(out,0,outp); } - // FIXME: This is probably still buggy - // FEATURE: Remove some of the "should never happen checks" - /*protected static String cleanupPath(String p) throws ErrnoException { - if(p.length() == 0) throw new ErrnoException(ENOENT); - if(needsCleanup(p)) { - char[] in = p.toCharArray(); - char[] out; - int outp ; - if(in[0] == '/') { - out = new char[in.length]; - outp = 0; - } else { - out = new char[cwd.length() + in.length + 1]; - outp = cwd.length(); - for(int i=0;i 0 && out[outp] != '/'); - } else if(in[inp+1] == '/') { - inp++; - } else { - out[outp++] = '/'; - } - } else { - out[outp++] = '/'; - out[outp++] = in[inp++]; - } - } else { - out[outp++] = in[inp++]; - } - } - if(outp == 0) out[outp++] = '/'; - return new String(out,0,outp); - } else { - if(p.startsWith("/")) return p; - StringBuffer sb = new StringBuffer(cwd); - if(!cwd.equals("/")) sb.append('/'); - return sb.append(p).toString(); - } - }*/ - public static class MountPointFS extends FS { private static class MP { public MP(String path, FS fs) { this.path = path; this.fs = fs; } @@ -545,7 +566,7 @@ public abstract class UnixRuntime extends Runtime { if(path.length() == 0) throw new IllegalArgumentException("Zero length mount point path"); return path; } - public FS get(String path) { + public synchronized FS get(String path) { path = fixup(path); int f = path.charAt(0) & 0x7f; for(int i=0;mps[f] != null && i < mps[f].length;i++) @@ -553,7 +574,7 @@ public abstract class UnixRuntime extends Runtime { return null; } - public void add(String path, FS fs) { + public synchronized void add(String path, FS fs) { if(get(path) != null) throw new IllegalArgumentException("mount point already exists"); path = fixup(path); int f = path.charAt(0) & 0x7f; @@ -565,7 +586,7 @@ public abstract class UnixRuntime extends Runtime { mps[f] = newList; } - public void remove(String path) { + public synchronized void remove(String path) { path = fixup(path); if(get(path) == null) throw new IllegalArgumentException("mount point doesn't exist"); int f = path.charAt(0) & 0x7f; @@ -593,36 +614,7 @@ public abstract class UnixRuntime extends Runtime { return root.op(op,path,arg1,arg2); } } - - // FEATURE: Probably should make this more general - support mountpoints, etc - /*public class UnixOverlayFS extends FS { - private final FS root; - private final FS dev = new DevFS(); - public UnixOverlayFS(FS root) { - this.root = root; - } - private String devPath(String path) { - if(path.startsWith("/dev")) { - if(path.length() == 4) return "/"; - if(path.charAt(4) == '/') return path.substring(4); - } - return null; - } - public FD open(String path, int flags, int mode) throws IOException{ - String dp = devPath(path); - return dp == null ? root.open(path,flags,mode) : dev.open(dp,flags,mode); - } - public FStat stat(String path) throws IOException { - String dp = devPath(path); - return dp == null ? root.stat(path) : dev.stat(dp); - } - public void mkdir(String path) throws IOException { - String dp = devPath(path); - if(dp == null) root.mkdir(path); - else dev.mkdir(dp); - } - }*/ - + public static class HostFS extends FS { protected File root; public File getRoot() { return root; } @@ -635,8 +627,17 @@ public abstract class UnixRuntime extends Runtime { return f; } - private File hostFile(String path) { - if(File.separatorChar != '/') path = path.replace('/',File.separatorChar); + File hostFile(String path) { + char sep = File.separatorChar; + if(sep != '/') { + char buf[] = path.toCharArray(); + for(int i=0;id_name,dent->d_ino);