diff --git a/lib/nestedvm.jar b/lib/nestedvm.jar
deleted file mode 100644
index 9291417..0000000
Binary files a/lib/nestedvm.jar and /dev/null differ
diff --git a/pom.xml b/pom.xml
index fb9e79f..36a2c2f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -141,13 +141,6 @@
reflections
0.9.9
-
- megacz
- nestedvm
- 2014.12.3
- system
- ${project.basedir}/lib/nestedvm.jar
-
junit
junit
diff --git a/src/main/java/org/ibex/nestedvm/Interpreter.java b/src/main/java/org/ibex/nestedvm/Interpreter.java
new file mode 100644
index 0000000..719aa74
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/Interpreter.java
@@ -0,0 +1,787 @@
+// 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
+
+package org.ibex.nestedvm;
+
+import org.ibex.nestedvm.util.*;
+import java.io.*;
+
+public class Interpreter extends UnixRuntime implements Cloneable {
+ // Registers
+ private int[] registers = new int[32];
+ private int hi,lo;
+
+ // Floating Point Registers
+ private int[] fpregs = new int[32];
+ // 24-31 - unused
+ // 23 - conditional bit
+ // 18-22 - unused
+ // 12-17 - cause bits (unimplemented)
+ // 7-11 - enables bits (unimplemented)
+ // 2-6 - flags (unimplemented)
+ // 0-1 - rounding mode (only implemented for fixed point conversions)
+ private int fcsr;
+
+ private int pc;
+
+ // The filename if the binary we're running
+ public String image;
+ private ELF.Symtab symtab;
+
+ // Register Operations
+ private final void setFC(boolean b) { fcsr = (fcsr&~0x800000) | (b ? 0x800000 : 0x000000); }
+ private final int roundingMode() { return fcsr & 3; /* bits 0-1 */ }
+ private final double getDouble(int r) {
+ return Double.longBitsToDouble(((fpregs[r+1]&0xffffffffL) << 32) | (fpregs[r]&0xffffffffL));
+ }
+ private final void setDouble(int r, double d) {
+ long l = Double.doubleToLongBits(d);
+ fpregs[r+1] = (int)(l >>> 32); fpregs[r] = (int)l;
+ }
+ private final float getFloat(int r) { return Float.intBitsToFloat(fpregs[r]); }
+ private final void setFloat(int r, float f) { fpregs[r] = Float.floatToRawIntBits(f); }
+
+ protected void _execute() throws ExecutionException {
+ try {
+ runSome();
+ } catch(ExecutionException e) {
+ e.setLocation(toHex(pc) + ": " + sourceLine(pc));
+ throw e;
+ }
+ }
+
+ protected Object clone() throws CloneNotSupportedException {
+ Interpreter r = (Interpreter) super.clone();
+ r.registers = (int[]) registers.clone();
+ r.fpregs = (int[]) fpregs.clone();
+ return r;
+ }
+
+ // 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;
+ int nextPC = pc + 4;
+ try {
+ OUTER: for(;;) {
+ int insn;
+ try {
+ insn = readPages[pc>>>pageShift][(pc>>>2)&PAGE_WORDS-1];
+ } catch (RuntimeException e) {
+ if(pc == 0xdeadbeef) throw new Error("fell off cpu: r2: " + r[2]);
+ insn = memRead(pc);
+ }
+
+ int op = (insn >>> 26) & 0xff; // bits 26-31
+ int rs = (insn >>> 21) & 0x1f; // bits 21-25
+ int rt = (insn >>> 16) & 0x1f; // bits 16-20
+ int ft = (insn >>> 16) & 0x1f;
+ int rd = (insn >>> 11) & 0x1f; // bits 11-15
+ int fs = (insn >>> 11) & 0x1f;
+ int shamt = (insn >>> 6) & 0x1f; // bits 6-10
+ int fd = (insn >>> 6) & 0x1f;
+ int subcode = insn & 0x3f; // bits 0-5
+
+ int jumpTarget = (insn & 0x03ffffff); // bits 0-25
+ int unsignedImmediate = insn & 0xffff;
+ int signedImmediate = (insn << 16) >> 16;
+ int branchTarget = signedImmediate;
+
+ int tmp, addr; // temporaries
+
+ r[ZERO] = 0;
+
+ switch(op) {
+ case 0: {
+ switch(subcode) {
+ case 0: // SLL
+ if(insn == 0) break;
+ r[rd] = r[rt] << shamt;
+ break;
+ case 2: // SRL
+ r[rd] = r[rt] >>> shamt;
+ break;
+ case 3: // SRA
+ r[rd] = r[rt] >> shamt;
+ break;
+ case 4: // SLLV
+ r[rd] = r[rt] << (r[rs]&0x1f);
+ break;
+ case 6: // SRLV
+ r[rd] = r[rt] >>> (r[rs]&0x1f);
+ break;
+ case 7: // SRAV
+ r[rd] = r[rt] >> (r[rs]&0x1f);
+ break;
+ case 8: // JR
+ tmp = r[rs]; pc += 4; nextPC = tmp;
+ continue OUTER;
+ case 9: // JALR
+ tmp = r[rs]; pc += 4; r[rd] = pc+4; nextPC = tmp;
+ continue OUTER;
+ case 12: // SYSCALL
+ this.pc = pc;
+ r[V0] = syscall(r[V0],r[A0],r[A1],r[A2],r[A3],r[T0],r[T1]);
+ if(state != RUNNING) { this.pc = nextPC; break OUTER; }
+ break;
+ case 13: // BREAK
+ throw new ExecutionException("Break");
+ case 16: // MFHI
+ r[rd] = hi;
+ break;
+ case 17: // MTHI
+ hi = r[rs];
+ break;
+ case 18: // MFLO
+ r[rd] = lo;
+ break;
+ case 19: // MTLO
+ lo = r[rs];
+ break;
+ case 24: { // MULT
+ long hilo = ((long)r[rs]) * ((long)r[rt]);
+ hi = (int) (hilo >>> 32);
+ lo = (int) hilo;
+ break;
+ }
+ case 25: { // MULTU
+ long hilo = (r[rs] & 0xffffffffL) * (r[rt] & 0xffffffffL);
+ hi = (int) (hilo >>> 32);
+ lo = (int) hilo;
+ break;
+ }
+ case 26: // DIV
+ hi = r[rs]%r[rt];
+ lo = r[rs]/r[rt];
+ break;
+ case 27: // DIVU
+ if(rt != 0) {
+ hi = (int)((r[rs] & 0xffffffffL) % (r[rt] & 0xffffffffL));
+ lo = (int)((r[rs] & 0xffffffffL) / (r[rt] & 0xffffffffL));
+ }
+ break;
+ case 32: // ADD
+ throw new ExecutionException("ADD (add with oveflow trap) not suported");
+ /*This must trap on overflow
+ r[rd] = r[rs] + r[rt];
+ break;*/
+ case 33: // ADDU
+ r[rd] = r[rs] + r[rt];
+ break;
+ case 34: // SUB
+ throw new ExecutionException("SUB (sub with oveflow trap) not suported");
+ /*This must trap on overflow
+ r[rd] = r[rs] - r[rt];
+ break;*/
+ case 35: // SUBU
+ r[rd] = r[rs] - r[rt];
+ break;
+ case 36: // AND
+ r[rd] = r[rs] & r[rt];
+ break;
+ case 37: // OR
+ r[rd] = r[rs] | r[rt];
+ break;
+ case 38: // XOR
+ r[rd] = r[rs] ^ r[rt];
+ break;
+ case 39: // NOR
+ r[rd] = ~(r[rs] | r[rt]);
+ break;
+ case 42: // SLT
+ r[rd] = r[rs] < r[rt] ? 1 : 0;
+ break;
+ case 43: // SLTU
+ r[rd] = ((r[rs] & 0xffffffffL) < (r[rt] & 0xffffffffL)) ? 1 : 0;
+ break;
+ default:
+ throw new ExecutionException("Illegal instruction 0/" + subcode);
+ }
+ break;
+ }
+ case 1: {
+ switch(rt) {
+ case 0: // BLTZ
+ if(r[rs] < 0) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 1: // BGEZ
+ if(r[rs] >= 0) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 16: // BLTZAL
+ if(r[rs] < 0) {
+ pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 17: // BGEZAL
+ if(r[rs] >= 0) {
+ pc += 4; r[RA] = pc+4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ default:
+ throw new ExecutionException("Illegal Instruction");
+ }
+ break;
+ }
+ case 2: { // J
+ tmp = (pc&0xf0000000) | (jumpTarget << 2);
+ pc+=4; nextPC = tmp;
+ continue OUTER;
+ }
+ case 3: { // JAL
+ tmp = (pc&0xf0000000) | (jumpTarget << 2);
+ pc+=4; r[RA] = pc+4; nextPC = tmp;
+ continue OUTER;
+ }
+ case 4: // BEQ
+ if(r[rs] == r[rt]) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 5: // BNE
+ if(r[rs] != r[rt]) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 6: //BLEZ
+ if(r[rs] <= 0) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 7: //BGTZ
+ if(r[rs] > 0) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 8: // ADDI
+ r[rt] = r[rs] + signedImmediate;
+ break;
+ case 9: // ADDIU
+ r[rt] = r[rs] + signedImmediate;
+ break;
+ case 10: // SLTI
+ r[rt] = r[rs] < signedImmediate ? 1 : 0;
+ break;
+ case 11: // SLTIU
+ r[rt] = (r[rs]&0xffffffffL) < (signedImmediate&0xffffffffL) ? 1 : 0;
+ break;
+ case 12: // ANDI
+ r[rt] = r[rs] & unsignedImmediate;
+ break;
+ case 13: // ORI
+ r[rt] = r[rs] | unsignedImmediate;
+ break;
+ case 14: // XORI
+ r[rt] = r[rs] ^ unsignedImmediate;
+ break;
+ case 15: // LUI
+ r[rt] = unsignedImmediate << 16;
+ break;
+ case 16:
+ throw new ExecutionException("TLB/Exception support not implemented");
+ case 17: { // FPU
+ boolean debug = false;
+ String line = debug ? sourceLine(pc) : "";
+ boolean debugon = debug && (line.indexOf("dtoa.c:51") >= 0 || line.indexOf("dtoa.c:52") >= 0 || line.indexOf("test.c") >= 0);
+ if(rs > 8 && debugon)
+ System.out.println(" FP Op: " + op + "/" + rs + "/" + subcode + " " + line);
+ if(roundingMode() != 0 && rs != 6 /*CTC.1*/ && !((rs==16 || rs==17) && subcode == 36 /* CVT.W.Z */))
+ throw new ExecutionException("Non-cvt.w.z operation attempted with roundingMode != round to nearest");
+ switch(rs) {
+ case 0: // MFC.1
+ r[rt] = f[rd];
+ break;
+ case 2: // CFC.1
+ if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
+ r[rt] = fcsr;
+ break;
+ case 4: // MTC.1
+ f[rd] = r[rt];
+ break;
+ case 6: // CTC.1
+ if(fs != 31) throw new ExecutionException("FCR " + fs + " unavailable");
+ fcsr = r[rt];
+ break;
+ case 8: // BC1F, BC1T
+ if(((fcsr&0x800000)!=0) == (((insn>>>16)&1)!=0)) {
+ pc += 4; tmp = pc + branchTarget*4; nextPC = tmp;
+ continue OUTER;
+ }
+ break;
+ case 16: { // Single
+ switch(subcode) {
+ case 0: // ADD.S
+ setFloat(fd,getFloat(fs)+getFloat(ft));
+ break;
+ case 1: // SUB.S
+ setFloat(fd,getFloat(fs)-getFloat(ft));
+ break;
+ case 2: // MUL.S
+ setFloat(fd,getFloat(fs)*getFloat(ft));
+ break;
+ case 3: // DIV.S
+ setFloat(fd,getFloat(fs)/getFloat(ft));
+ break;
+ case 5: // ABS.S
+ setFloat(fd,Math.abs(getFloat(fs)));
+ break;
+ case 6: // MOV.S
+ f[fd] = f[fs];
+ break;
+ case 7: // NEG.S
+ setFloat(fd,-getFloat(fs));
+ break;
+ case 33: // CVT.D.S
+ setDouble(fd,getFloat(fs));
+ break;
+ case 36: // CVT.W.S
+ switch(roundingMode()) {
+ case 0: f[fd] = (int)Math.floor(getFloat(fs)+0.5f); break; // Round to nearest
+ case 1: f[fd] = (int)getFloat(fs); break; // Round towards zero
+ case 2: f[fd] = (int)Math.ceil(getFloat(fs)); break; // Round towards plus infinity
+ case 3: f[fd] = (int)Math.floor(getFloat(fs)); break; // Round towards minus infinity
+ }
+ break;
+ case 50: // C.EQ.S
+ setFC(getFloat(fs) == getFloat(ft));
+ break;
+ case 60: // C.LT.S
+ setFC(getFloat(fs) < getFloat(ft));
+ break;
+ case 62: // C.LE.S
+ setFC(getFloat(fs) <= getFloat(ft));
+ break;
+ default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
+ }
+ break;
+ }
+ case 17: { // Double
+ switch(subcode) {
+ case 0: // ADD.D
+ setDouble(fd,getDouble(fs)+getDouble(ft));
+ break;
+ case 1: // SUB.D
+ if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") - f" + ft + " (" + getDouble(ft) + ")");
+ setDouble(fd,getDouble(fs)-getDouble(ft));
+ break;
+ case 2: // MUL.D
+ if(debugon) System.out.println("f" + fd + " = f" + fs + " (" + getDouble(fs) + ") * f" + ft + " (" + getDouble(ft) + ")");
+ setDouble(fd,getDouble(fs)*getDouble(ft));
+ if(debugon) System.out.println("f" + fd + " = " + getDouble(fd));
+ break;
+ case 3: // DIV.D
+ setDouble(fd,getDouble(fs)/getDouble(ft));
+ break;
+ case 5: // ABS.D
+ setDouble(fd,Math.abs(getDouble(fs)));
+ break;
+ case 6: // MOV.D
+ f[fd] = f[fs];
+ f[fd+1] = f[fs+1];
+ break;
+ case 7: // NEG.D
+ setDouble(fd,-getDouble(fs));
+ break;
+ case 32: // CVT.S.D
+ setFloat(fd,(float)getDouble(fs));
+ break;
+ case 36: // CVT.W.D
+ if(debugon) System.out.println("CVT.W.D rm: " + roundingMode() + " f" + fs + ":" + getDouble(fs));
+ switch(roundingMode()) {
+ case 0: f[fd] = (int)Math.floor(getDouble(fs)+0.5); break; // Round to nearest
+ case 1: f[fd] = (int)getDouble(fs); break; // Round towards zero
+ case 2: f[fd] = (int)Math.ceil(getDouble(fs)); break; // Round towards plus infinity
+ case 3: f[fd] = (int)Math.floor(getDouble(fs)); break; // Round towards minus infinity
+ }
+ if(debugon) System.out.println("CVT.W.D: f" + fd + ":" + f[fd]);
+ break;
+ case 50: // C.EQ.D
+ setFC(getDouble(fs) == getDouble(ft));
+ break;
+ case 60: // C.LT.D
+ setFC(getDouble(fs) < getDouble(ft));
+ break;
+ case 62: // C.LE.D
+ setFC(getDouble(fs) <= getDouble(ft));
+ break;
+ default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
+ }
+ break;
+ }
+ case 20: { // Integer
+ switch(subcode) {
+ case 32: // CVT.S.W
+ setFloat(fd,f[fs]);
+ break;
+ case 33: // CVT.D.W
+ setDouble(fd,f[fs]);
+ break;
+ default: throw new ExecutionException("Invalid Instruction 17/" + rs + "/" + subcode + " at " + sourceLine(pc));
+ }
+ break;
+ }
+ default:
+ throw new ExecutionException("Invalid Instruction 17/" + rs);
+ }
+ break;
+ }
+ case 18: case 19:
+ throw new ExecutionException("No coprocessor installed");
+ case 32: { // LB
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: tmp = (tmp>>>24)&0xff; break;
+ case 1: tmp = (tmp>>>16)&0xff; break;
+ case 2: tmp = (tmp>>> 8)&0xff; break;
+ case 3: tmp = (tmp>>> 0)&0xff; break;
+ }
+ if((tmp&0x80)!=0) tmp |= 0xffffff00; // sign extend
+ r[rt] = tmp;
+ break;
+ }
+ case 33: { // LH
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: tmp = (tmp>>>16)&0xffff; break;
+ case 2: tmp = (tmp>>> 0)&0xffff; break;
+ default: throw new ReadFaultException(addr);
+ }
+ if((tmp&0x8000)!=0) tmp |= 0xffff0000; // sign extend
+ r[rt] = tmp;
+ break;
+ }
+ case 34: { // LWL;
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: r[rt] = (r[rt]&0x00000000)|(tmp<< 0); break;
+ case 1: r[rt] = (r[rt]&0x000000ff)|(tmp<< 8); break;
+ case 2: r[rt] = (r[rt]&0x0000ffff)|(tmp<<16); break;
+ case 3: r[rt] = (r[rt]&0x00ffffff)|(tmp<<24); break;
+ }
+ break;
+ }
+ case 35: // LW
+ addr = r[rs] + signedImmediate;
+ try {
+ r[rt] = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ r[rt] = memRead(addr);
+ }
+ break;
+ case 36: { // LBU
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr);
+ }
+ switch(addr&3) {
+ case 0: r[rt] = (tmp>>>24)&0xff; break;
+ case 1: r[rt] = (tmp>>>16)&0xff; break;
+ case 2: r[rt] = (tmp>>> 8)&0xff; break;
+ case 3: r[rt] = (tmp>>> 0)&0xff; break;
+ }
+ break;
+ }
+ case 37: { // LHU
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: r[rt] = (tmp>>>16)&0xffff; break;
+ case 2: r[rt] = (tmp>>> 0)&0xffff; break;
+ default: throw new ReadFaultException(addr);
+ }
+ break;
+ }
+ case 38: { // LWR
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: r[rt] = (r[rt]&0xffffff00)|(tmp>>>24); break;
+ case 1: r[rt] = (r[rt]&0xffff0000)|(tmp>>>16); break;
+ case 2: r[rt] = (r[rt]&0xff000000)|(tmp>>> 8); break;
+ case 3: r[rt] = (r[rt]&0x00000000)|(tmp>>> 0); break;
+ }
+ break;
+ }
+ case 40: { // SB
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: tmp = (tmp&0x00ffffff) | ((r[rt]&0xff)<<24); break;
+ case 1: tmp = (tmp&0xff00ffff) | ((r[rt]&0xff)<<16); break;
+ case 2: tmp = (tmp&0xffff00ff) | ((r[rt]&0xff)<< 8); break;
+ case 3: tmp = (tmp&0xffffff00) | ((r[rt]&0xff)<< 0); break;
+ }
+ try {
+ writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
+ } catch(RuntimeException e) {
+ memWrite(addr&~3,tmp);
+ }
+ break;
+ }
+ case 41: { // SH
+ addr = r[rs] + signedImmediate;
+ try {
+ tmp = readPages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)];
+ } catch(RuntimeException e) {
+ tmp = memRead(addr&~3);
+ }
+ switch(addr&3) {
+ case 0: tmp = (tmp&0x0000ffff) | ((r[rt]&0xffff)<<16); break;
+ case 2: tmp = (tmp&0xffff0000) | ((r[rt]&0xffff)<< 0); break;
+ default: throw new WriteFaultException(addr);
+ }
+ try {
+ writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
+ } catch(RuntimeException e) {
+ memWrite(addr&~3,tmp);
+ }
+ break;
+ }
+ case 42: { // SWL
+ addr = r[rs] + signedImmediate;
+ tmp = memRead(addr&~3);
+ switch(addr&3) {
+ case 0: tmp=(tmp&0x00000000)|(r[rt]>>> 0); break;
+ case 1: tmp=(tmp&0xff000000)|(r[rt]>>> 8); break;
+ case 2: tmp=(tmp&0xffff0000)|(r[rt]>>>16); break;
+ case 3: tmp=(tmp&0xffffff00)|(r[rt]>>>24); break;
+ }
+ try {
+ writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = tmp;
+ } catch(RuntimeException e) {
+ memWrite(addr&~3,tmp);
+ }
+ break;
+ }
+ case 43: // SW
+ addr = r[rs] + signedImmediate;
+ try {
+ writePages[addr>>>pageShift][(addr>>>2)&(PAGE_WORDS-1)] = r[rt];
+ } catch(RuntimeException e) {
+ memWrite(addr&~3,r[rt]);
+ }
+ break;
+ case 46: { // SWR
+ addr = r[rs] + signedImmediate;
+ tmp = memRead(addr&~3);
+ switch(addr&3) {
+ case 0: tmp=(tmp&0x00ffffff)|(r[rt]<<24); break;
+ case 1: tmp=(tmp&0x0000ffff)|(r[rt]<<16); break;
+ case 2: tmp=(tmp&0x000000ff)|(r[rt]<< 8); break;
+ case 3: tmp=(tmp&0x00000000)|(r[rt]<< 0); break;
+ }
+ memWrite(addr&~3,tmp);
+ break;
+ }
+ // Needs to be atomic w/ threads
+ case 48: // LWC0/LL
+ r[rt] = memRead(r[rs] + signedImmediate);
+ break;
+ case 49: // LWC1
+ f[rt] = memRead(r[rs] + signedImmediate);
+ break;
+ // Needs to be atomic w/ threads
+ case 56:
+ memWrite(r[rs] + signedImmediate,r[rt]);
+ r[rt] = 1;
+ break;
+ case 57: // SWC1
+ memWrite(r[rs] + signedImmediate,f[rt]);
+ break;
+ default:
+ throw new ExecutionException("Invalid Instruction: " + op);
+ }
+ pc = nextPC;
+ nextPC = pc + 4;
+ } // for(;;)
+ } catch(ExecutionException e) {
+ this.pc = pc;
+ throw e;
+ }
+ return 0;
+ }
+
+ public int lookupSymbol(String name) {
+ ELF.Symbol sym = symtab.getSymbol(name);
+ 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 {
+ ELF elf = new ELF(data);
+ symtab = elf.getSymtab();
+
+ if(elf.header.type != ELF.ET_EXEC) throw new IOException("Binary is not an executable");
+ if(elf.header.machine != ELF.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
+ if(elf.ident.data != ELF.ELFDATA2MSB) throw new IOException("Binary is not big endian");
+
+ entryPoint = elf.header.entry;
+
+ ELF.Symtab symtab = elf.getSymtab();
+ if(symtab == null) throw new IOException("No symtab in binary (did you strip it?)");
+ userInfo = symtab.getSymbol("user_info");
+ ELF.Symbol gpsym = symtab.getSymbol("_gp");
+
+ if(gpsym == null) throw new IOException("NO _gp symbol!");
+ gp = gpsym.addr;
+
+ entryPoint = elf.header.entry;
+
+ ELF.PHeader[] pheaders = elf.pheaders;
+ int brk = 0;
+ int pageSize = (1<> 2;
+ for(int i=0;i>> pageShift;
+ if(readPages[page] == null)
+ 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 >>> pageShift][(addr >>> 2)&(pageWords-1)] = dis.readInt();
+ addr+=4;
+ filesize-=4;
+ } while(filesize > 0);
+ dis.close();
+ }
+ }
+ heapStart = (brk+pageSize-1)&~(pageSize-1);
+ }
+
+ protected void setCPUState(CPUState state) {
+ for(int i=1;i<32;i++) registers[i] = state.r[i];
+ for(int i=0;i<32;i++) fpregs[i] = state.f[i];
+ hi=state.hi; lo=state.lo; fcsr=state.fcsr;
+ pc=state.pc;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+ public Interpreter(InputStream is) throws IOException { this(new Seekable.InputStream(is)); }
+
+ // Debug functions
+ // NOTE: This probably requires a jdk > 1.1, however, it is only used for debugging
+ private java.util.HashMap sourceLineCache;
+ public String sourceLine(int pc) {
+ final String addr2line = "mips-unknown-elf-addr2line";
+ String line = (String) (sourceLineCache == null ? null : sourceLineCache.get(new Integer(pc)));
+ if(line != null) return line;
+ if(image==null) return null;
+ try {
+ Process p = java.lang.Runtime.getRuntime().exec(new String[]{addr2line,"-e",image,toHex(pc)});
+ line = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine();
+ if(line == null) return null;
+ while(line.startsWith("../")) line = line.substring(3);
+ if(sourceLineCache == null) sourceLineCache = new java.util.HashMap();
+ sourceLineCache.put(new Integer(pc),line);
+ return line;
+ } catch(IOException e) {
+ return null;
+ }
+ }
+
+ public class DebugShutdownHook implements Runnable {
+ public void run() {
+ int pc = Interpreter.this.pc;
+ if(getState() == RUNNING)
+ System.err.print("\nCPU Executing " + toHex(pc) + ": " + sourceLine(pc) + "\n");
+ }
+ }
+
+ public static void main(String[] argv) throws Exception {
+ String image = argv[0];
+ Interpreter emu = new Interpreter(image);
+ java.lang.Runtime.getRuntime().addShutdownHook(new Thread(emu.new DebugShutdownHook()));
+ int status = emu.run(argv);
+ System.err.println("Exit status: " + status);
+ System.exit(status);
+ }
+}
diff --git a/src/main/java/org/ibex/nestedvm/Registers.java b/src/main/java/org/ibex/nestedvm/Registers.java
new file mode 100644
index 0000000..a441af5
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/Registers.java
@@ -0,0 +1,46 @@
+// 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.
+
+package org.ibex.nestedvm;
+
+interface Registers {
+ // Register Names
+ public final static int ZERO = 0; // Immutable, hardwired to 0
+ public final static int AT = 1; // Reserved for assembler
+ public final static int K0 = 26; // Reserved for kernel
+ public final static int K1 = 27; // Reserved for kernel
+ public final static int GP = 28; // Global pointer (the middle of .sdata/.sbss)
+ public final static int SP = 29; // Stack pointer
+ public final static int FP = 30; // Frame Pointer
+ public final static int RA = 31; // Return Address
+
+ // Return values (caller saved)
+ public final static int V0 = 2;
+ public final static int V1 = 3;
+ // Argument Registers (caller saved)
+ public final static int A0 = 4;
+ public final static int A1 = 5;
+ public final static int A2 = 6;
+ public final static int A3 = 7;
+ // Temporaries (caller saved)
+ public final static int T0 = 8;
+ public final static int T1 = 9;
+ public final static int T2 = 10;
+ public final static int T3 = 11;
+ public final static int T4 = 12;
+ public final static int T5 = 13;
+ public final static int T6 = 14;
+ public final static int T7 = 15;
+ public final static int T8 = 24;
+ public final static int T9 = 25;
+ // Saved (callee saved)
+ public final static int S0 = 16;
+ public final static int S1 = 17;
+ public final static int S2 = 18;
+ public final static int S3 = 19;
+ public final static int S4 = 20;
+ public final static int S5 = 21;
+ public final static int S6 = 22;
+ public final static int S7 = 23;
+}
diff --git a/src/main/java/org/ibex/nestedvm/Runtime.java b/src/main/java/org/ibex/nestedvm/Runtime.java
new file mode 100644
index 0000000..2c599a0
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/Runtime.java
@@ -0,0 +1,1566 @@
+// 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
+
+package org.ibex.nestedvm;
+
+import org.ibex.nestedvm.util.*;
+import java.io.*;
+
+public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
+ public static final String VERSION = "1.0";
+
+ /** True to write useful diagnostic information to stderr when things go wrong */
+ final static boolean STDERR_DIAG = true;
+
+ /** Number of bits to shift to get the page number (1<<symbol or -1 it it doesn't exits in this method
+ This method is only required if the call() function is used */
+ public int lookupSymbol(String symbol) { return -1; }
+
+ /** Subclasses should populate a CPUState object representing the cpu state */
+ protected abstract void getCPUState(CPUState state);
+
+ /** 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>>_pageShift != 1) _pageShift++;
+ pageShift = _pageShift;
+
+ int heapStart = heapStart();
+ int totalMemory = totalPages * pageSize;
+ int stackSize = max(totalMemory/512,ARG_MAX+65536);
+ int stackPages = 0;
+ if(totalPages > 1) {
+ stackSize = max(stackSize,pageSize);
+ stackSize = (stackSize + pageSize - 1) & ~(pageSize-1);
+ stackPages = stackSize >>> pageShift;
+ heapStart = (heapStart + pageSize - 1) & ~(pageSize-1);
+ if(stackPages + STACK_GUARD_PAGES + (heapStart >>> pageShift) >= totalPages)
+ throw new IllegalArgumentException("total pages too small");
+ } else {
+ if(pageSize < heapStart + stackSize) throw new IllegalArgumentException("total memory too small");
+ heapStart = (heapStart + 4095) & ~4096;
+ }
+
+ stackBottom = totalMemory - stackSize;
+ heapEnd = heapStart;
+
+ readPages = new int[totalPages][];
+ writePages = new int[totalPages][];
+
+ if(totalPages == 1) {
+ readPages[0] = writePages[0] = new int[pageSize>>2];
+ } else {
+ for(int i=(stackBottom >>> pageShift);i>2];
+ }
+ }
+
+ if(!exec) {
+ fds = new FD[OPEN_MAX];
+ closeOnExec = new boolean[OPEN_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.
+ 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<>> pageShift;
+ int start = (addr&pageMask)>>2;
+ int elements = min(pageWords-start,src.length-i);
+ if(readPages[page]==null) {
+ initPage(page,ro);
+ } else if(!ro) {
+ if(writePages[page] == null) writePages[page] = readPages[page];
+ }
+ System.arraycopy(src,i,readPages[page],start,elements);
+ i += elements;
+ addr += elements*4;
+ }
+ }
+
+ /** Initialize words of pages starting at addr to 0 */
+ protected final void clearPages(int addr, int words) {
+ int pageWords = (1<>>2;
+ int pageMask = (1<>> pageShift;
+ int start = (addr&pageMask)>>2;
+ int elements = min(pageWords-start,words-i);
+ if(readPages[page]==null) {
+ 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) {
+ int word = memRead(addr&~3);
+ switch(addr&3) {
+ case 1: buf[x++] = (byte)((word>>>16)&0xff); if(--count==0) break;
+ case 2: buf[x++] = (byte)((word>>> 8)&0xff); if(--count==0) break;
+ case 3: buf[x++] = (byte)((word>>> 0)&0xff); if(--count==0) break;
+ }
+ addr = (addr&~3)+4;
+ }
+ if((count&~3) != 0) {
+ int c = count>>>2;
+ int a = addr>>>2;
+ while(c != 0) {
+ int[] page = readPages[a >>> (pageShift-2)];
+ if(page == null) throw new ReadFaultException(a<<2);
+ 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;
+ }
+ addr = a<<2; count &=3;
+ }
+ if(count != 0) {
+ int word = memRead(addr);
+ switch(count) {
+ case 3: buf[x+2] = (byte)((word>>>8)&0xff);
+ case 2: buf[x+1] = (byte)((word>>>16)&0xff);
+ case 1: buf[x+0] = (byte)((word>>>24)&0xff);
+ }
+ }
+ }
+
+ /** 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) {
+ int word = memRead(addr&~3);
+ switch(addr&3) {
+ case 1: word = (word&0xff00ffff)|((buf[x++]&0xff)<<16); if(--count==0) break;
+ case 2: word = (word&0xffff00ff)|((buf[x++]&0xff)<< 8); if(--count==0) break;
+ case 3: word = (word&0xffffff00)|((buf[x++]&0xff)<< 0); if(--count==0) break;
+ }
+ 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 >>> (pageShift-2)];
+ if(page == null) throw new WriteFaultException(a<<2);
+ 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>>>(pageShift-2)];
+ if(srcPage == null) throw new ReadFaultException(s<<2);
+ int[] dstPage = writePages[d>>>(pageShift-2)];
+ if(dstPage == null) throw new WriteFaultException(d<<2);
+ 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;
+ }
+ if(count != 0) {
+ int word1 = memRead(src);
+ int word2 = memRead(dst);
+ switch(count) {
+ case 1: memWrite(dst,(word1&0xff000000)|(word2&0x00ffffff)); break;
+ case 2: memWrite(dst,(word1&0xffff0000)|(word2&0x0000ffff)); break;
+ case 3: memWrite(dst,(word1&0xffffff00)|(word2&0x000000ff)); break;
+ }
+ }
+ } else {
+ while(count > 0) {
+ int n = min(count,MAX_CHUNK);
+ byte[] buf = byteBuf(n);
+ copyin(src,buf,n);
+ copyout(buf,dst,n);
+ count -= n; src += n; dst += n;
+ }
+ }
+ }
+
+ 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);
+ switch(addr&3) {
+ case 1: word = (word&0xff00ffff)|((ch&0xff)<<16); if(--count==0) break;
+ case 2: word = (word&0xffff00ff)|((ch&0xff)<< 8); if(--count==0) break;
+ case 3: word = (word&0xffffff00)|((ch&0xff)<< 0); if(--count==0) break;
+ }
+ memWrite(addr&~3,word);
+ addr = (addr&~3)+4;
+ }
+ if((count&~3) != 0) {
+ int c = count>>2;
+ int a = addr>>>2;
+ while(c != 0) {
+ int[] page = readPages[a>>>(pageShift-2)];
+ if(page == null) throw new WriteFaultException(a<<2);
+ int index = a&pageWordMask;
+ int n = min(c,pageWords-index);
+ /* Arrays.fill(page,index,index+n,fourBytes);*/
+ for(int i=index;iaddr */
+ public final int memRead(int addr) throws ReadFaultException {
+ if((addr & 3) != 0) throw new ReadFaultException(addr);
+ return unsafeMemRead(addr);
+ }
+
+ protected final int unsafeMemRead(int addr) throws ReadFaultException {
+ int page = addr >>> pageShift;
+ int entry = (addr&(1<>2;
+ try {
+ return readPages[page][entry];
+ } catch(ArrayIndexOutOfBoundsException e) {
+ if(page < 0 || page >= readPages.length) throw new ReadFaultException(addr);
+ throw e; // should never happen
+ } catch(NullPointerException e) {
+ throw new ReadFaultException(addr);
+ }
+ }
+
+ /** Writes a word to the processes memory at addr */
+ public final void memWrite(int addr, int value) throws WriteFaultException {
+ if((addr & 3) != 0) throw new WriteFaultException(addr);
+ unsafeMemWrite(addr,value);
+ }
+
+ protected final void unsafeMemWrite(int addr, int value) throws WriteFaultException {
+ int page = addr >>> pageShift;
+ int entry = (addr&(1<>2;
+ try {
+ writePages[page][entry] = value;
+ } catch(ArrayIndexOutOfBoundsException e) {
+ if(page < 0 || page >= writePages.length) throw new WriteFaultException(addr);
+ throw e; // should never happen
+ } catch(NullPointerException e) {
+ throw new WriteFaultException(addr);
+ }
+ }
+
+ /** Created a new non-empty writable page at page number page */
+ 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[(1<>>2];
+ writePages[page] = ro ? null : buf;
+ readPages[page] = buf;
+ return buf;
+ }
+
+ /** Returns the exit status of the process. (only valid if state == DONE)
+ @see Runtime#state */
+ public final int exitStatus() {
+ if(state != EXITED) throw new IllegalStateException("exitStatus() called in an inappropriate state");
+ return exitStatus;
+ }
+
+ private int addStringArray(String[] strings, int topAddr) throws FaultException {
+ int count = strings.length;
+ int total = 0; /* null last table entry */
+ for(int i=0;iindex in the _user_info table to word
+ * The user_info table is a chunk of memory in the program's memory defined by the
+ * symbol "user_info". The compiler/interpreter automatically determine the size
+ * 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));
+ try {
+ 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));
+ try {
+ return memRead(userInfoBase()+index*4);
+ } catch(FaultException e) { throw new RuntimeException(e.toString()); }
+ }
+
+ /** Calls _execute() (subclass's execute()) and catches exceptions */
+ private void __execute() {
+ try {
+ _execute();
+ } catch(FaultException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ exit(128+11,true); // SIGSEGV
+ exitException = e;
+ } catch(ExecutionException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ exit(128+4,true); // SIGILL
+ exitException = e;
+ }
+ }
+
+ /** Executes the process until the PAUSE syscall is invoked or the process exits. Returns true if the process exited. */
+ public final boolean execute() {
+ if(state != PAUSED) throw new IllegalStateException("execute() called in inappropriate state");
+ if(startTime == 0) startTime = System.currentTimeMillis();
+ state = RUNNING;
+ __execute();
+ if(state != PAUSED && state != EXITED && state != EXECED)
+ throw new IllegalStateException("execute() ended up in an inappropriate state (" + state + ")");
+ return state != PAUSED;
+ }
+
+ 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.
+ If the process executes the PAUSE syscall execution will be paused for 500ms and a warning will be displayed */
+ public final int run(String[] args, String[] env) {
+ start(args,env);
+ for(;;) {
+ if(execute()) break;
+ if(STDERR_DIAG) System.err.println("WARNING: Pause requested while executing run()");
+ }
+ if(state == EXECED && STDERR_DIAG) System.err.println("WARNING: Process exec()ed while being run under run()");
+ return state == EXITED ? exitStatus() : 0;
+ }
+
+ public final void start() { start(null); }
+ public final void start(String[] args) { start(args,null); }
+
+ /** Initializes the process and prepairs it to be executed with execute() */
+ 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< ARG_MAX) throw new IllegalArgumentException("args/environ too big");
+
+ // HACK: heapStart() isn't always available when the constructor
+ // is run and this sometimes doesn't get initialized
+ if(heapEnd == 0) {
+ heapEnd = heapStart();
+ if(heapEnd == 0) throw new Error("heapEnd == 0");
+ int pageSize = writePages.length == 1 ? 4096 : (1< 7) throw new IllegalArgumentException("args.length > 7");
+ CPUState state = new CPUState();
+ getCPUState(state);
+
+ int sp = state.r[SP];
+ int[] ia = new int[args.length];
+ for(int i=0;iaddr in the process setting A0-A3 and S0-S3 to the given arguments
+ and returns the contents of V1 when the the pause syscall is invoked */
+ //public final int call(int addr, int a0, int a1, int a2, int a3, int s0, int s1, int s2, int s3) {
+ public final int call(int addr, int a0, int[] rest) throws CallException {
+ if(rest.length > 7) throw new IllegalArgumentException("rest.length > 7");
+ if(state != PAUSED && state != CALLJAVA) throw new IllegalStateException("call() called in inappropriate state");
+ int oldState = state;
+ 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;
+ switch(rest.length) {
+ case 7: cpustate.r[S3] = rest[6];
+ case 6: cpustate.r[S2] = rest[5];
+ case 5: cpustate.r[S1] = rest[4];
+ case 4: cpustate.r[S0] = rest[3];
+ case 3: cpustate.r[A3] = rest[2];
+ case 2: cpustate.r[A2] = rest[1];
+ case 1: cpustate.r[A1] = rest[0];
+ }
+ cpustate.pc = addr;
+
+ state = RUNNING;
+
+ setCPUState(cpustate);
+ __execute();
+ getCPUState(cpustate);
+ setCPUState(saved);
+
+ if(state != PAUSED) throw new CallException("Process exit()ed while servicing a call() request");
+ state = oldState;
+
+ return cpustate.r[V1];
+ }
+
+ /** Allocated an entry in the FileDescriptor table for fd and returns the number.
+ Returns -1 if the table is full. This can be used by subclasses to use custom file
+ descriptors */
+ public final int addFD(FD fd) {
+ if(state == EXITED || state == EXECED) throw new IllegalStateException("addFD called in inappropriate state");
+ int i;
+ for(i=0;ifdn and removes it from the file descriptor table */
+ public final boolean closeFD(int fdn) {
+ if(state == EXITED || state == EXECED) throw new IllegalStateException("closeFD called in inappropriate state");
+ if(fdn < 0 || fdn >= OPEN_MAX) return false;
+ if(fds[fdn] == null) return false;
+ _preCloseFD(fds[fdn]);
+ fds[fdn].close();
+ _postCloseFD(fds[fdn]);
+ fds[fdn] = null;
+ return true;
+ }
+
+ /** Duplicates the file descriptor fdn and returns the new fs */
+ public final int dupFD(int fdn) {
+ int i;
+ if(fdn < 0 || fdn >= OPEN_MAX) return -1;
+ if(fds[fdn] == null) return -1;
+ for(i=0;i= 0) throw new ErrnoException(EACCES);
+ return null;
+ } catch(IOException e) { throw new ErrnoException(EIO); }
+
+ return new SeekableFD(sf,flags) { protected FStat _fstat() { return hostFStat(f,sf,data); } };
+ }
+
+ FStat hostFStat(File f, Seekable.File sf, Object data) { return new HostFStat(f,sf); }
+
+ FD hostFSDirFD(File f, Object data) { return null; }
+
+ FD _open(String path, int flags, int mode) throws ErrnoException {
+ return hostFSOpen(new File(path),flags,mode,null);
+ }
+
+ /** The open syscall */
+ private int sys_open(int addr, int flags, int mode) throws ErrnoException, FaultException {
+ String name = cstring(addr);
+
+ // HACK: TeX, or GPC, or something really sucks
+ if(name.length() == 1024 && getClass().getName().equals("tests.TeX")) name = name.trim();
+
+ flags &= ~O_NOCTTY; // this is meaningless under nestedvm
+ FD fd = _open(name,flags,mode);
+ if(fd == null) return -ENOENT;
+ int fdn = addFD(fd);
+ if(fdn == -1) { fd.close(); return -ENFILE; }
+ return fdn;
+ }
+
+ /** The write syscall */
+
+ private int sys_write(int fdn, int addr, int count) throws FaultException, ErrnoException {
+ count = Math.min(count,MAX_CHUNK);
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ copyin(addr,buf,count);
+ try {
+ return fds[fdn].write(buf,0,count);
+ } catch(ErrnoException e) {
+ if(e.errno == EPIPE) sys_exit(128+13);
+ throw e;
+ }
+ }
+
+ /** The read syscall */
+ private int sys_read(int fdn, int addr, int count) throws FaultException, ErrnoException {
+ count = Math.min(count,MAX_CHUNK);
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ int n = fds[fdn].read(buf,0,count);
+ copyout(buf,addr,n);
+ return n;
+ }
+
+ /** The 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) {
+ return closeFD(fdn) ? 0 : -EBADFD;
+ }
+
+
+ /** The seek syscall */
+ private int sys_lseek(int fdn, int offset, int whence) throws ErrnoException {
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ if(whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) return -EINVAL;
+ int n = fds[fdn].seek(offset,whence);
+ return n < 0 ? -ESPIPE : n;
+ }
+
+ /** The stat/fstat syscall helper */
+ int stat(FStat fs, int addr) throws FaultException {
+ memWrite(addr+0,(fs.dev()<<16)|(fs.inode()&0xffff)); // st_dev (top 16), // st_ino (bottom 16)
+ memWrite(addr+4,((fs.type()&0xf000))|(fs.mode()&0xfff)); // st_mode
+ memWrite(addr+8,fs.nlink()<<16|fs.uid()&0xffff); // st_nlink (top 16) // st_uid (bottom 16)
+ memWrite(addr+12,fs.gid()<<16|0); // st_gid (top 16) // st_rdev (bottom 16)
+ memWrite(addr+16,fs.size()); // st_size
+ memWrite(addr+20,fs.atime()); // st_atime
+ // memWrite(addr+24,0) // st_spare1
+ memWrite(addr+28,fs.mtime()); // st_mtime
+ // memWrite(addr+32,0) // st_spare2
+ memWrite(addr+36,fs.ctime()); // st_ctime
+ // memWrite(addr+40,0) // st_spare3
+ memWrite(addr+44,fs.blksize()); // st_bklsize;
+ memWrite(addr+48,fs.blocks()); // st_blocks
+ // memWrite(addr+52,0) // st_spare4[0]
+ // memWrite(addr+56,0) // st_spare4[1]
+ return 0;
+ }
+
+ /** The fstat syscall */
+ private int sys_fstat(int fdn, int addr) throws FaultException {
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ return stat(fds[fdn].fstat(),addr);
+ }
+
+ /*
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ };
+ */
+ private int sys_gettimeofday(int timevalAddr, int timezoneAddr) throws FaultException {
+ long now = System.currentTimeMillis();
+ int tv_sec = (int)(now / 1000);
+ int tv_usec = (int)((now%1000)*1000);
+ memWrite(timevalAddr+0,tv_sec);
+ memWrite(timevalAddr+4,tv_usec);
+ return 0;
+ }
+
+ private int sys_sleep(int sec) {
+ if(sec < 0) sec = Integer.MAX_VALUE;
+ try {
+ Thread.sleep((long)sec*1000);
+ return 0;
+ } catch(InterruptedException e) {
+ return -1;
+ }
+ }
+
+ /*
+ #define _CLOCKS_PER_SEC_ 1000
+ #define _CLOCK_T_ unsigned long
+ struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+ };*/
+
+ private int sys_times(int tms) {
+ long now = System.currentTimeMillis();
+ int userTime = (int)((now - startTime)/16);
+ int sysTime = (int)((now - startTime)/16);
+
+ try {
+ if(tms!=0) {
+ memWrite(tms+0,userTime);
+ memWrite(tms+4,sysTime);
+ memWrite(tms+8,userTime);
+ memWrite(tms+12,sysTime);
+ }
+ } catch(FaultException e) {
+ return -EFAULT;
+ }
+ return (int)now;
+ }
+
+ private int sys_sysconf(int n) {
+ switch(n) {
+ case _SC_CLK_TCK: return 1000;
+ case _SC_PAGESIZE: return writePages.length == 1 ? 4096 : (1<incr is how much to increase the break by */
+ public final int sbrk(int incr) {
+ if(incr < 0) return -ENOMEM;
+ if(incr==0) return heapEnd;
+ incr = (incr+3)&~3;
+ 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=start;i= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ FD fd = fds[fdn];
+
+ switch(cmd) {
+ case F_DUPFD:
+ if(arg < 0 || arg >= OPEN_MAX) return -EINVAL;
+ for(i=arg;i= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ FD fd = fds[fdn];
+
+ Seekable s = fd.seekable();
+ if (s == null) return -EINVAL;
+
+ try {
+ s.sync();
+ return 0;
+ } catch (IOException e) {
+ return -EIO;
+ }
+ }
+
+ /** 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
+ the contenst of A0, A1, A2, and A3. The call MAY change the state
+ @see Runtime#state state */
+ 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) 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) {
+ return -EFAULT;
+ } catch(RuntimeException ex) {
+ ex.printStackTrace();
+ throw new Error("Internal Error in _syscall()");
+ }
+ }
+
+ protected int _syscall(int syscall, int a, int b, int c, int d, int e, int f) throws ErrnoException, FaultException {
+ switch(syscall) {
+ case SYS_null: return 0;
+ case SYS_exit: return sys_exit(a);
+ case SYS_pause: return sys_pause();
+ case SYS_write: return sys_write(a,b,c);
+ case SYS_fstat: return sys_fstat(a,b);
+ case SYS_sbrk: return sbrk(a);
+ case SYS_open: return sys_open(a,b,c);
+ 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);
+ case SYS_sleep: return sys_sleep(a);
+ case SYS_times: return sys_times(a);
+ 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_fsync: return fsync(a);
+ case SYS_memcpy: memcpy(a,b,c); return a;
+ case SYS_memset: memset(a,b,c); return a;
+
+ case SYS_kill:
+ case SYS_fork:
+ case SYS_pipe:
+ case SYS_dup2:
+ case SYS_waitpid:
+ case SYS_stat:
+ case SYS_mkdir:
+ case SYS_getcwd:
+ case SYS_chdir:
+ if(STDERR_DIAG) System.err.println("Attempted to use a UnixRuntime syscall in Runtime (" + syscall + ")");
+ return -ENOSYS;
+ default:
+ if(STDERR_DIAG) System.err.println("Attempted to use unknown syscall: " + syscall);
+ return -ENOSYS;
+ }
+ }
+
+ 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; } }
+ public int malloc(int size) { try { return call("malloc",size); } catch(CallException e) { return 0; } }
+ public void free(int p) { try { if(p!=0) call("free",p); } catch(CallException e) { /*noop*/ } }
+
+ /** Helper function to create a cstring in main memory */
+ public int strdup(String s) {
+ byte[] a;
+ if(s == null) s = "(null)";
+ byte[] a2 = getBytes(s);
+ a = new byte[a2.length+1];
+ System.arraycopy(a2,0,a,0,a2.length);
+ int addr = malloc(a.length);
+ if(addr == 0) return 0;
+ try {
+ copyout(a,addr,a.length);
+ } catch(FaultException e) {
+ free(addr);
+ return 0;
+ }
+ 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);
+ switch(addr&3) {
+ case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
+ case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
+ case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
+ case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
+ }
+ }
+ }
+
+ /** File Descriptor class */
+ public static abstract class FD {
+ private int refCount = 1;
+ private String normalizedPath = null;
+ private boolean deleteOnClose = false;
+
+ public void setNormalizedPath(String path) { normalizedPath = path; }
+ public String getNormalizedPath() { return normalizedPath; }
+
+ public void markDeleteOnClose() { deleteOnClose = true; }
+ public boolean isMarkedForDeleteOnClose() { return deleteOnClose; }
+
+ /** Read some bytes. Should return the number of bytes read, 0 on EOF, or throw an IOException on error */
+ public int read(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
+ /** Write. Should return the number of bytes written or throw an IOException on error */
+ public int write(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
+
+ /** Seek in the filedescriptor. Whence is SEEK_SET, SEEK_CUR, or SEEK_END. Should return -1 on error or the new position. */
+ public int seek(int n, int whence) throws ErrnoException { return -1; }
+
+ public int getdents(byte[] a, int off, int length) throws ErrnoException { throw new ErrnoException(EBADFD); }
+
+ /** Return a Seekable object representing this file descriptor (can be read only)
+ This is required for exec() */
+ Seekable seekable() { return null; }
+
+ private FStat cachedFStat = null;
+ public final FStat fstat() {
+ if(cachedFStat == null) cachedFStat = _fstat();
+ return cachedFStat;
+ }
+
+ protected abstract FStat _fstat();
+ public abstract int flags();
+
+ /** Closes the fd */
+ public final void close() { if(--refCount==0) _close(); }
+ protected void _close() { /* noop*/ }
+
+ FD dup() { refCount++; return this; }
+ }
+
+ /** FileDescriptor class for normal files */
+ public abstract static class SeekableFD extends FD {
+ private final int flags;
+ private final Seekable data;
+
+ SeekableFD(Seekable data, int flags) { this.data = data; this.flags = flags; }
+
+ protected abstract FStat _fstat();
+ public int flags() { return flags; }
+
+ Seekable seekable() { return data; }
+
+ public int seek(int n, int whence) throws ErrnoException {
+ try {
+ switch(whence) {
+ case SEEK_SET: break;
+ case SEEK_CUR: n += data.pos(); break;
+ case SEEK_END: n += data.length(); break;
+ default: return -1;
+ }
+ data.seek(n);
+ return n;
+ } catch(IOException e) {
+ throw new ErrnoException(ESPIPE);
+ }
+ }
+
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ if((flags&3) == RD_ONLY) throw new ErrnoException(EBADFD);
+ // NOTE: There is race condition here but we can't fix it in pure java
+ if((flags&O_APPEND) != 0) seek(0,SEEK_END);
+ try {
+ return data.write(a,off,length);
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ if((flags&3) == WR_ONLY) throw new ErrnoException(EBADFD);
+ try {
+ int n = data.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ protected void _close() { try { data.close(); } catch(IOException e) { /*ignore*/ } }
+ }
+
+ public static class InputOutputStreamFD extends FD {
+ private final InputStream is;
+ private final OutputStream os;
+
+ public InputOutputStreamFD(InputStream is) { this(is,null); }
+ public InputOutputStreamFD(OutputStream os) { this(null,os); }
+ public InputOutputStreamFD(InputStream is, OutputStream os) {
+ this.is = is;
+ this.os = os;
+ if(is == null && os == null) throw new IllegalArgumentException("at least one stream must be supplied");
+ }
+
+ public int flags() {
+ if(is != null && os != null) return O_RDWR;
+ if(is != null) return O_RDONLY;
+ if(os != null) return O_WRONLY;
+ throw new Error("should never happen");
+ }
+
+ public void _close() {
+ if(is != null) try { is.close(); } catch(IOException e) { /*ignore*/ }
+ if(os != null) try { os.close(); } catch(IOException e) { /*ignore*/ }
+ }
+
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ if(is == null) return super.read(a,off,length);
+ try {
+ int n = is.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ if(os == null) return super.write(a,off,length);
+ try {
+ os.write(a,off,length);
+ return length;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public FStat _fstat() { return new SocketFStat(); }
+ }
+
+ static class TerminalFD extends InputOutputStreamFD {
+ public TerminalFD(InputStream is) { this(is,null); }
+ 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 SocketFStat() { public int type() { return S_IFCHR; } public int mode() { return 0600; } }; }
+ }
+
+ // 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 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();
+ if(c == '\r' && (c = parent.read()) != '\n') { pushedBack = c; return '\r'; }
+ return c;
+ }
+ public int read(byte[] buf, int pos, int len) throws IOException {
+ boolean pb = false;
+ if(pushedBack != -1 && len > 0) {
+ buf[0] = (byte) pushedBack;
+ pushedBack = -1;
+ pos++; len--; pb = true;
+ }
+ int n = parent.read(buf,pos,len);
+ if(n == -1) return pb ? 1 : -1;
+ for(int i=0;i 0) buf[n++] = prev | (int)(l>>>(56-left));
+ if(n < words) buf[n++] = (int) (l >>> (24-left));
+ left = (left + 8) & 0x1f;
+ prev = (int)(l << left);
+ }
+ return buf;
+ }
+
+ static byte[] getBytes(String s) {
+ try {
+ return s.getBytes("UTF-8");
+ } catch(UnsupportedEncodingException e) {
+ return null; // should never happen
+ }
+ }
+
+ static byte[] getNullTerminatedBytes(String s) {
+ byte[] buf1 = getBytes(s);
+ byte[] buf2 = new byte[buf1.length+1];
+ System.arraycopy(buf1,0,buf2,0,buf1.length);
+ return buf2;
+ }
+
+ final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+ final static int min(int a, int b) { return a < b ? a : b; }
+ final static int max(int a, int b) { return a > b ? a : b; }
+}
diff --git a/src/main/java/org/ibex/nestedvm/UnixRuntime.java b/src/main/java/org/ibex/nestedvm/UnixRuntime.java
new file mode 100644
index 0000000..eaf3466
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/UnixRuntime.java
@@ -0,0 +1,2512 @@
+// 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.
+
+package org.ibex.nestedvm;
+
+import org.ibex.nestedvm.util.*;
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.nio.file.*;
+import java.lang.reflect.*; // For lazily linked RuntimeCompiler
+
+// FEATURE: vfork
+
+public abstract class UnixRuntime extends Runtime implements Cloneable {
+ /** The pid of this "process" */
+ private int pid;
+ private UnixRuntime parent;
+ public final int getPid() {
+ return pid;
+ }
+
+ private static final GlobalState defaultGS = new GlobalState();
+ 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;
+ }
+
+ /** proceses' current working directory - absolute path WITHOUT leading slash
+ "" = root, "bin" = /bin "usr/bin" = /usr/bin */
+ private String cwd;
+
+ /** The runtime that should be run next when in state == EXECED */
+ private UnixRuntime execedRuntime;
+
+ private Object children; // used only for synchronizatin
+ private Vector activeChildren;
+ private Vector exitedChildren;
+
+ protected UnixRuntime(int pageSize, int totalPages) {
+ this(pageSize,totalPages,false);
+ }
+
+ protected UnixRuntime(int pageSize, int totalPages, boolean exec) {
+ super(pageSize,totalPages,exec);
+
+ if(!exec) {
+ gs = defaultGS;
+ String userdir = Platform.getProperty("user.dir");
+ cwd = userdir == null ? null : gs.mapHostPath(userdir);
+ if(cwd == null) cwd = "/";
+ cwd = cwd.substring(1);
+ }
+ }
+
+ private static String posixTZ() {
+ StringBuffer sb = new StringBuffer();
+ TimeZone zone = TimeZone.getDefault();
+ int off = zone.getRawOffset() / 1000;
+ sb.append(Platform.timeZoneGetDisplayName(zone,false,false));
+ if(off > 0) sb.append("-");
+ else off = -off;
+ sb.append(off/3600);
+ off = off%3600;
+ if(off > 0) sb.append(":").append(off/60);
+ off=off%60;
+ if(off > 0) sb.append(":").append(off);
+ if(zone.useDaylightTime())
+ sb.append(Platform.timeZoneGetDisplayName(zone,true,false));
+ return sb.toString();
+ }
+
+ private static boolean envHas(String key,String[] environ) {
+ for(int i=0; i= gs.tasks.length)) return -ECHILD;
+ if(children == null) return blocking ? -ECHILD : 0;
+
+ UnixRuntime done = null;
+
+ synchronized(children) {
+ for(;;) {
+ if(pid == -1) {
+ if(exitedChildren.size() > 0) {
+ done = (UnixRuntime)exitedChildren.elementAt(exitedChildren.size() - 1);
+ 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) {
+ if(!exitedChildren.removeElement(t)) throw new Error("should never happen");
+ done = t;
+ }
+ } else {
+ // process group stuff, EINVAL returned above
+ throw new Error("should never happen");
+ }
+ if(done == null) {
+ if(!blocking) return 0;
+ try {
+ children.wait();
+ }
+ catch(InterruptedException e) {}
+ //System.err.println("waitpid woke up: " + exitedChildren.size());
+ } else {
+ gs.tasks[done.pid] = null;
+ break;
+ }
+ }
+ }
+ if(statusAddr!=0) memWrite(statusAddr,done.exitStatus()<<8);
+ return done.pid;
+ }
+
+
+ void _exited() {
+ if(children != null) synchronized(children) {
+ for(Enumeration e = exitedChildren.elements(); e.hasMoreElements(); ) {
+ UnixRuntime child = (UnixRuntime) e.nextElement();
+ gs.tasks[child.pid] = null;
+ }
+ exitedChildren.removeAllElements();
+ for(Enumeration e = activeChildren.elements(); e.hasMoreElements(); ) {
+ UnixRuntime child = (UnixRuntime) e.nextElement();
+ child.parent = null;
+ }
+ activeChildren.removeAllElements();
+ }
+
+ UnixRuntime _parent = parent;
+ if(_parent == null) {
+ gs.tasks[pid] = null;
+ } else {
+ synchronized(_parent.children) {
+ if(parent == null) {
+ gs.tasks[pid] = null;
+ } else {
+ if(!parent.activeChildren.removeElement(this)) throw new Error("should never happen _exited: pid: " + pid);
+ parent.exitedChildren.addElement(this);
+ parent.children.notify();
+ }
+ }
+ }
+ }
+
+ protected Object clone() throws CloneNotSupportedException {
+ UnixRuntime r = (UnixRuntime) super.clone();
+ r.pid = 0;
+ r.parent = null;
+ r.children = null;
+ r.activeChildren = r.exitedChildren = null;
+ return r;
+ }
+
+ private int sys_fork() {
+ final UnixRuntime r;
+
+ try {
+ r = (UnixRuntime) clone();
+ } catch(Exception e) {
+ e.printStackTrace();
+ return -ENOMEM;
+ }
+
+ r.parent = this;
+
+ try {
+ r._started();
+ } catch(ProcessTableFullExn e) {
+ return -ENOMEM;
+ }
+
+ //System.err.println("fork " + pid + " -> " + r.pid + " tasks[" + r.pid + "] = " + gd.tasks[r.pid]);
+ if(children == null) {
+ children = new Object();
+ activeChildren = new Vector();
+ exitedChildren = new Vector();
+ }
+ 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);
+ r.state = PAUSED;
+
+ new ForkedProcess(r);
+
+ return r.pid;
+ }
+
+ public static final class ForkedProcess extends Thread {
+ private final UnixRuntime initial;
+ public ForkedProcess(UnixRuntime initial) {
+ this.initial = initial;
+ start();
+ }
+ public void run() {
+ UnixRuntime.executeAndExec(initial);
+ }
+ }
+
+ 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;
+ if(STDERR_DIAG) 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 c,String[] argv, String[] envp) {
+ 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;
+ }
+ }
+
+ private int exec(UnixRuntime r, String[] argv, String[] envp) {
+ //System.err.println("Execing " + r);
+ for(int i=0; i= OPEN_MAX) return -EBADFD;
+ if(newd < 0 || newd >= OPEN_MAX) return -EBADFD;
+ if(fds[oldd] == null) return -EBADFD;
+ if(fds[newd] != null) fds[newd].close();
+ fds[newd] = fds[oldd].dup();
+ return 0;
+ }
+
+ private int sys_dup(int oldd) {
+ if(oldd < 0 || oldd >= OPEN_MAX) return -EBADFD;
+ if(fds[oldd] == null) return -EBADFD;
+ FD fd = fds[oldd].dup();
+ int newd = addFD(fd);
+ if(newd < 0) {
+ fd.close();
+ return -ENFILE;
+ }
+ return newd;
+ }
+
+ private int sys_stat(int cstring, int addr) throws FaultException, ErrnoException {
+ FStat s = gs.stat(this,normalizePath(cstring(cstring)));
+ if(s == null) return -ENOENT;
+ return stat(s,addr);
+ }
+
+ private int sys_lstat(int cstring, int addr) throws FaultException, ErrnoException {
+ FStat s = gs.lstat(this,normalizePath(cstring(cstring)));
+ if(s == null) return -ENOENT;
+ return stat(s,addr);
+ }
+
+ private int sys_mkdir(int cstring, int mode) throws FaultException, ErrnoException {
+ gs.mkdir(this,normalizePath(cstring(cstring)),mode);
+ return 0;
+ }
+
+ private int sys_unlink(int cstring) throws FaultException, ErrnoException {
+ gs.unlink(this,normalizePath(cstring(cstring)));
+ return 0;
+ }
+
+ private int sys_link(int cstring1, int cstring2) throws FaultException, ErrnoException {
+ gs.link(this,normalizePath(cstring(cstring1)), normalizePath(cstring(cstring2)));
+ return 0;
+ }
+
+ private int sys_rmdir(int ptrPathName) throws ErrnoException, ReadFaultException {
+ gs.rmdir(this, normalizePath(cstring(ptrPathName)));
+ return 0;
+ }
+
+ private int sys_getcwd(int addr, int size) throws FaultException, ErrnoException {
+ byte[] b = getBytes(cwd);
+ if(size == 0) return -EINVAL;
+ if(size < b.length+2) return -ERANGE;
+ memset(addr,'/',1);
+ copyout(b,addr+1,b.length);
+ memset(addr+b.length+1,0,1);
+ return addr;
+ }
+
+ private int sys_chdir(int addr) throws ErrnoException, FaultException {
+ String path = normalizePath(cstring(addr));
+ FStat st = gs.stat(this,path);
+ if(st == null) return -ENOENT;
+ if(st.type() != FStat.S_IFDIR) return -ENOTDIR;
+ cwd = path;
+ return 0;
+ }
+
+ private int sys_getdents(int fdn, int addr, int count, int seekptr) throws FaultException, ErrnoException {
+ count = Math.min(count,MAX_CHUNK);
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ byte[] buf = byteBuf(count);
+ int n = fds[fdn].getdents(buf,0,count);
+ copyout(buf,addr,n);
+ return n;
+ }
+
+ void _preCloseFD(FD fd) {
+ // release all fcntl locks on this file
+ Seekable s = fd.seekable();
+ if (s == null) return;
+
+ try {
+ for (int i=0; i < gs.locks.length; i++) {
+ Seekable.Lock l = gs.locks[i];
+ if (l == null) continue;
+ if (s.equals(l.seekable()) && l.getOwner() == this) {
+ l.release();
+ gs.locks[i] = null;
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ void _postCloseFD(FD fd) {
+ if (fd.isMarkedForDeleteOnClose()) {
+ try {
+ gs.unlink(this, fd.getNormalizedPath());
+ }
+ catch (Throwable t) {}
+ }
+ }
+
+ /** 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.
+ * Uses GlobalState to ensure locking across processes in the same JVM.
+ 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(int fdn, int cmd, int arg) throws FaultException {
+ if (cmd != F_GETLK && cmd != F_SETLK) return sys_fcntl(fdn, cmd, arg);
+
+ if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
+ if(fds[fdn] == null) return -EBADFD;
+ FD fd = fds[fdn];
+
+ if (arg == 0) 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.Lock[] locks = gs.locks;
+ Seekable s = fd.seekable();
+ if (s == null) return -EINVAL;
+
+ try {
+
+ 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) {
+ // The simple Java file locking below will happily return
+ // a lock that overlaps one already held by the JVM. Thus
+ // we must check over all the locks held by other Runtimes
+ for (int i=0; i < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ if (!locks[i].overlaps(l_start, l_len))
+ continue;
+ if (locks[i].getOwner() == this)
+ continue;
+ if (locks[i].isShared() && l_type == F_RDLCK)
+ continue;
+
+ // overlapping lock held by another process
+ return 0;
+ }
+
+ // check if an area is lockable by attempting to obtain 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 < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ if (locks[i].getOwner() != this) 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 < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+
+ if (locks[i].getOwner() == this) {
+ // if this Runtime owns an overlapping lock work with it
+ if (locks[i].contained(l_start, l_len)) {
+ locks[i].release();
+ locks[i] = null;
+ } else if (locks[i].contains(l_start, l_len)) {
+ if (locks[i].isShared() == (l_type == F_RDLCK)) {
+ // return this more general lock
+ memWrite(arg+4, (int)locks[i].position());
+ memWrite(arg+8, (int)locks[i].size());
+ return 0;
+ } else {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ } else {
+ // if another Runtime has an lock and it is exclusive or
+ // we want an exclusive lock then fail
+ if (locks[i].overlaps(l_start, l_len)
+ && (!locks[i].isShared() || l_type == F_WRLCK))
+ return -EAGAIN;
+ }
+ }
+
+ // create the lock
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+ if (lock == null) return -EAGAIN;
+ lock.setOwner(this);
+
+ int i;
+ for (i=0; i < locks.length; i++)
+ if (locks[i] == null) break;
+ if (i == locks.length) return -ENOLCK;
+ locks[i] = lock;
+ return 0;
+
+ } else {
+ return -EINVAL;
+ }
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static class SocketFD extends FD {
+ public static final int TYPE_STREAM = 0;
+ public static final int TYPE_DGRAM = 1;
+ public static final int LISTEN = 2;
+ public int type() {
+ return flags & 1;
+ }
+ public boolean listen() {
+ return (flags & 2) != 0;
+ }
+
+ int flags;
+ int options;
+
+ Socket s;
+ ServerSocket ss;
+ DatagramSocket ds;
+
+ InetAddress bindAddr;
+ int bindPort = -1;
+ InetAddress connectAddr;
+ int connectPort = -1;
+
+ DatagramPacket dp;
+ InputStream is;
+ OutputStream os;
+
+ private static final byte[] EMPTY = new byte[0];
+ public SocketFD(int type) {
+ flags = type;
+ if(type == TYPE_DGRAM)
+ dp = new DatagramPacket(EMPTY,0);
+ }
+
+ public SocketAddress getLocalSocketAddress() {
+ int type = type();
+ if(type == SocketFD.TYPE_STREAM) {
+ if(listen()) {
+ return ss.getLocalSocketAddress();
+ } else {
+ return s.getLocalSocketAddress();
+ }
+ } else {
+ return ds.getLocalSocketAddress();
+ }
+ }
+
+ public void setOptions() {
+ try {
+ if(s != null && type() == TYPE_STREAM && !listen()) {
+ Platform.socketSetKeepAlive(s,(options & SO_KEEPALIVE) != 0);
+ }
+ } catch(SocketException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ }
+ }
+
+ public void _close() {
+ try {
+ if(s != null) s.close();
+ if(ss != null) ss.close();
+ if(ds != null) ds.close();
+ } catch(IOException e) {
+ /* ignore */
+ }
+ }
+
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ if(type() == TYPE_DGRAM) return recvfrom(a,off,length,null,null);
+ if(is == null) throw new ErrnoException(EPIPE);
+ try {
+ int n = is.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int recvfrom(byte[] a, int off, int length, InetAddress[] sockAddr, int[] port) throws ErrnoException {
+ if(type() == TYPE_STREAM) return read(a,off,length);
+
+ if(off != 0) throw new IllegalArgumentException("off must be 0");
+ dp.setData(a);
+ dp.setLength(length);
+ try {
+ if(ds == null) ds = new DatagramSocket();
+ ds.receive(dp);
+ } catch(IOException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ throw new ErrnoException(EIO);
+ }
+ if(sockAddr != null) {
+ sockAddr[0] = dp.getAddress();
+ port[0] = dp.getPort();
+ }
+ return dp.getLength();
+ }
+
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ if(type() == TYPE_DGRAM) return sendto(a,off,length,null,-1);
+
+ if(os == null) throw new ErrnoException(EPIPE);
+ try {
+ os.write(a,off,length);
+ return length;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int sendto(byte[] a, int off, int length, InetAddress destAddr, int destPort) throws ErrnoException {
+ if(off != 0) throw new IllegalArgumentException("off must be 0");
+ if(type() == TYPE_STREAM) return write(a,off,length);
+
+ if(destAddr == null) {
+ destAddr = connectAddr;
+ destPort = connectPort;
+
+ if(destAddr == null) throw new ErrnoException(ENOTCONN);
+ }
+
+ dp.setAddress(destAddr);
+ dp.setPort(destPort);
+ dp.setData(a);
+ dp.setLength(length);
+
+ try {
+ if(ds == null) ds = new DatagramSocket();
+ ds.send(dp);
+ } catch(IOException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ if("Network is unreachable".equals(e.getMessage())) throw new ErrnoException(EHOSTUNREACH);
+ throw new ErrnoException(EIO);
+ }
+ return dp.getLength();
+ }
+
+ public int flags() {
+ return O_RDWR;
+ }
+ public FStat _fstat() {
+ return new SocketFStat();
+ }
+ }
+
+ private int sys_socket(int domain, int type, int proto) {
+ if(domain != AF_INET || (type != SOCK_STREAM && type != SOCK_DGRAM)) return -EPROTONOSUPPORT;
+ return addFD(new SocketFD(type == SOCK_STREAM ? SocketFD.TYPE_STREAM : SocketFD.TYPE_DGRAM));
+ }
+
+ private SocketFD getSocketFD(int fdn) throws ErrnoException {
+ if(fdn < 0 || fdn >= OPEN_MAX) throw new ErrnoException(EBADFD);
+ if(fds[fdn] == null) throw new ErrnoException(EBADFD);
+ if(!(fds[fdn] instanceof SocketFD)) throw new ErrnoException(ENOTSOCK);
+
+ return (SocketFD) fds[fdn];
+ }
+
+ private int sys_connect(int fdn, int addr, int namelen) throws ErrnoException, FaultException {
+ SocketFD fd = getSocketFD(fdn);
+
+ 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;
+ byte[] ip = new byte[4];
+ copyin(addr+4,ip,4);
+
+ InetAddress inetAddr;
+ try {
+ inetAddr = Platform.inetAddressFromBytes(ip);
+ } catch(UnknownHostException e) {
+ return -EADDRNOTAVAIL;
+ }
+
+ fd.connectAddr = inetAddr;
+ fd.connectPort = port;
+
+ try {
+ switch(fd.type()) {
+ case SocketFD.TYPE_STREAM: {
+ Socket s = new Socket(inetAddr,port);
+ fd.s = s;
+ fd.setOptions();
+ fd.is = s.getInputStream();
+ fd.os = s.getOutputStream();
+ break;
+ }
+ case SocketFD.TYPE_DGRAM:
+ break;
+ default:
+ throw new Error("should never happen");
+ }
+ } catch(IOException e) {
+ return -ECONNREFUSED;
+ }
+
+ return 0;
+ }
+
+ private int sys_resolve_hostname(int chostname, int addr, int sizeAddr) throws FaultException {
+ String hostname = cstring(chostname);
+ int size = memRead(sizeAddr);
+ InetAddress[] inetAddrs;
+ try {
+ inetAddrs = InetAddress.getAllByName(hostname);
+ } catch(UnknownHostException e) {
+ return HOST_NOT_FOUND;
+ }
+ int count = min(size/4,inetAddrs.length);
+ for(int i=0; i>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT;
+ int port = word1 & 0xffff;
+ InetAddress inetAddr = null;
+ if(memRead(addr+4) != 0) {
+ byte[] ip = new byte[4];
+ copyin(addr+4,ip,4);
+
+ try {
+ inetAddr = Platform.inetAddressFromBytes(ip);
+ } catch(UnknownHostException e) {
+ return -EADDRNOTAVAIL;
+ }
+ }
+
+ switch(fd.type()) {
+ case SocketFD.TYPE_STREAM: {
+ fd.bindAddr = inetAddr;
+ fd.bindPort = port;
+ return 0;
+ }
+ case SocketFD.TYPE_DGRAM: {
+ if(fd.ds != null) fd.ds.close();
+ try {
+ fd.ds = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port);
+ } catch(IOException e) {
+ return -EADDRINUSE;
+ }
+ return 0;
+ }
+ default:
+ throw new Error("should never happen");
+ }
+ }
+
+ private int sys_listen(int fdn, int backlog) throws ErrnoException {
+ SocketFD fd = getSocketFD(fdn);
+ if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP;
+ if(fd.ss != null || fd.s != null) return -EISCONN;
+ if(fd.bindPort < 0) return -EOPNOTSUPP;
+
+ try {
+ fd.ss = new ServerSocket(fd.bindPort,backlog,fd.bindAddr);
+ fd.flags |= SocketFD.LISTEN;
+ return 0;
+ } catch(IOException e) {
+ return -EADDRINUSE;
+ }
+
+ }
+
+ private int sys_accept(int fdn, int addr, int lenaddr) throws ErrnoException, FaultException {
+ SocketFD fd = getSocketFD(fdn);
+ if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP;
+ if(!fd.listen()) return -EOPNOTSUPP;
+
+ int size = memRead(lenaddr);
+
+ ServerSocket s = fd.ss;
+ Socket client;
+ try {
+ client = s.accept();
+ } catch(IOException e) {
+ return -EIO;
+ }
+
+ if(size >= 8) {
+ memWrite(addr,(6 << 24) | (AF_INET << 16) | client.getPort());
+ byte[] b = client.getInetAddress().getAddress();
+ copyout(b,addr+4,4);
+ memWrite(lenaddr,8);
+ }
+
+ SocketFD clientFD = new SocketFD(SocketFD.TYPE_STREAM);
+ clientFD.s = client;
+ try {
+ clientFD.is = client.getInputStream();
+ clientFD.os = client.getOutputStream();
+ } catch(IOException e) {
+ return -EIO;
+ }
+ int n = addFD(clientFD);
+ if(n == -1) {
+ clientFD.close();
+ return -ENFILE;
+ }
+ return n;
+ }
+
+ 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.s == null) return -ENOTCONN;
+
+ Socket s = fd.s;
+
+ try {
+ if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false);
+ if(how == SHUT_WR || how == SHUT_RDWR) Platform.socketHalfClose(s,true);
+ } catch(IOException e) {
+ return -EIO;
+ }
+
+ 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();
+ } catch(UnknownHostException e) {
+ return "darkstar";
+ }
+ }
+
+ private int sys_sysctl(int nameaddr, int namelen, int oldp, int oldlenaddr, int newp, int newlen) throws FaultException {
+ if(newp != 0) return -EPERM;
+ if(namelen == 0) return -ENOENT;
+ if(oldp == 0) return 0;
+
+ Object o = null;
+ switch(memRead(nameaddr)) {
+ case CTL_KERN:
+ if(namelen != 2) break;
+ switch(memRead(nameaddr+4)) {
+ case KERN_OSTYPE:
+ o = "NestedVM";
+ break;
+ case KERN_HOSTNAME:
+ o = hostName();
+ break;
+ case KERN_OSRELEASE:
+ o = VERSION;
+ break;
+ case KERN_VERSION:
+ o = "NestedVM Kernel Version " + VERSION;
+ break;
+ }
+ break;
+ case CTL_HW:
+ if(namelen != 2) break;
+ switch(memRead(nameaddr+4)) {
+ case HW_MACHINE:
+ o = "NestedVM Virtual Machine";
+ break;
+ }
+ break;
+ }
+ if(o == null) return -ENOENT;
+ int len = memRead(oldlenaddr);
+ if(o instanceof String) {
+ byte[] b = getNullTerminatedBytes((String)o);
+ if(len < b.length) return -ENOMEM;
+ len = b.length;
+ copyout(b,oldp,len);
+ memWrite(oldlenaddr,len);
+ } else if(o instanceof Integer) {
+ if(len < 4) return -ENOMEM;
+ memWrite(oldp,((Integer)o).intValue());
+ } else {
+ throw new Error("should never happen");
+ }
+ return 0;
+ }
+
+ public static final class GlobalState {
+ Hashtable execCache = new Hashtable();
+
+ final UnixRuntime[] tasks;
+ int nextPID = 1;
+
+ /** Table of all current file locks held by this process. */
+ Seekable.Lock[] locks = new Seekable.Lock[16];
+
+ private MP[] mps = new MP[0];
+ private FS root;
+
+ public GlobalState() {
+ this(255);
+ }
+
+ public GlobalState(int maxProcs) {
+ this(maxProcs,true);
+ }
+
+ public GlobalState(int maxProcs, boolean defaultMounts) {
+ tasks = new UnixRuntime[maxProcs+1];
+ if(defaultMounts) {
+ File root = null;
+ if(Platform.getProperty("nestedvm.root") != null) {
+ root = new File(Platform.getProperty("nestedvm.root"));
+ if(!root.isDirectory()) throw new IllegalArgumentException("nestedvm.root is not a directory");
+ } else {
+ String cwd = Platform.getProperty("user.dir");
+ root = Platform.getRoot(new File(cwd != null ? cwd : "."));
+ }
+
+ addMount("/",new HostFS(root));
+
+ if(Platform.getProperty("nestedvm.root") == null) {
+ File[] roots = Platform.listRoots();
+ for(int i=0; i=0; i--) {
+ FS fs = i == mps.length ? root : mps[i].fs;
+ String path = i == mps.length ? "" : mps[i].path;
+ if(!(fs instanceof HostFS)) continue;
+ File fsroot = ((HostFS)fs).getRoot();
+ if(!fsroot.isAbsolute()) fsroot = new File(fsroot.getAbsolutePath());
+ if(f.getPath().startsWith(fsroot.getPath())) {
+ char sep = File.separatorChar;
+ String child = f.getPath().substring(fsroot.getPath().length());
+ if(sep != '/') {
+ char[] child_ = child.toCharArray();
+ for(int j=0; j 0) outp--;
+ while(outp > 0 && out[outp] != '/') outp--;
+ //System.err.println("After ..: " + new String(out,0,outp));
+ continue;
+ }
+ // Just read a /.[^.] or /..[^/$]
+ inp++;
+ out[outp++] = '/';
+ out[outp++] = '.';
+ }
+ if(outp > 0 && out[outp-1] == '/') outp--;
+ //System.err.println("normalize: " + path + " -> " + new String(out,0,outp) + " (cwd: " + cwd + ")");
+ int outStart = out[0] == '/' ? 1 : 0;
+ return new String(out,outStart,outp - outStart);
+ }
+
+ FStat hostFStat(final File f, Object data) {
+ boolean e = false;
+ try {
+ FileInputStream fis = new FileInputStream(f);
+ switch(fis.read()) {
+ case '\177':
+ e = fis.read() == 'E' && fis.read() == 'L' && fis.read() == 'F';
+ break;
+ case '#':
+ e = fis.read() == '!';
+ }
+ fis.close();
+ } catch(IOException e2) { }
+ HostFS fs = (HostFS) data;
+ final int inode = fs.inodes.get(f.getAbsolutePath());
+ final int devno = fs.devno;
+ return new HostFStat(f,e) {
+ public int inode() {
+ return inode;
+ }
+ public int dev() {
+ return devno;
+ }
+ };
+ }
+
+ FD hostFSDirFD(File f, Object _fs) {
+ HostFS fs = (HostFS) _fs;
+ return fs.new HostDirFD(f);
+ }
+
+ public static class HostFS extends FS {
+ InodeCache inodes = new InodeCache(4000);
+ protected File root;
+ public File getRoot() {
+ return root;
+ }
+
+ protected File hostFile(String path) {
+ char sep = File.separatorChar;
+ if(sep != '/') {
+ char buf[] = path.toCharArray();
+ for(int i=0; i 'z' || (path.length() > 1 && path.charAt(1) != '/'))
+ return null;
+ if (path.length() == 1) {
+ path = path + "/";
+ }
+
+ path = drive + ":" + path.substring(1).replace('/', '\\');
+ java.util.logging.Logger.getLogger(CygdriveFS.class.getName()).fine("path new = " + path);
+ return new File(path);
+ }
+
+ public CygdriveFS() {
+ super("/");
+ }
+ }
+
+ private static void putInt(byte[] buf, int off, int n) {
+ buf[off+0] = (byte)((n>>>24)&0xff);
+ buf[off+1] = (byte)((n>>>16)&0xff);
+ buf[off+2] = (byte)((n>>> 8)&0xff);
+ buf[off+3] = (byte)((n>>> 0)&0xff);
+ }
+
+ public static abstract class DirFD extends FD {
+ private int pos = -2;
+
+ protected abstract int size();
+ protected abstract String name(int n);
+ protected abstract int inode(int n);
+ protected abstract int myDev();
+ protected abstract int parentInode();
+ protected abstract int myInode();
+ public int flags() {
+ return O_RDONLY;
+ }
+
+ public int getdents(byte[] buf, int off, int len) {
+ int ooff = off;
+ int ino;
+ int reclen;
+ OUTER: for(; len > 0 && pos < size(); pos++) {
+ switch(pos) {
+ case -2:
+ case -1:
+ ino = pos == -1 ? parentInode() : myInode();
+ if(ino == -1) continue;
+ reclen = 9 + (pos == -1 ? 2 : 1);
+ if(reclen > len) break OUTER;
+ buf[off+8] = '.';
+ if(pos == -1) buf[off+9] = '.';
+ break;
+ default: {
+ String f = name(pos);
+ byte[] fb = getBytes(f);
+ reclen = fb.length + 9;
+ if(reclen > len) break OUTER;
+ ino = inode(pos);
+ System.arraycopy(fb,0,buf,off+8,fb.length);
+ }
+ }
+ buf[off+reclen-1] = 0; // null terminate
+ reclen = (reclen + 3) & ~3; // add padding
+ putInt(buf,off,reclen);
+ putInt(buf,off+4,ino);
+ off += reclen;
+ len -= reclen;
+ }
+ return off-ooff;
+ }
+
+ protected FStat _fstat() {
+ return new FStat() {
+ public int type() {
+ return S_IFDIR;
+ }
+ public int inode() {
+ return myInode();
+ }
+ public int dev() {
+ return myDev();
+ }
+ };
+ }
+ }
+
+ public static class DevFS extends FS {
+ private static final int ROOT_INODE = 1;
+ private static final int NULL_INODE = 2;
+ private static final int ZERO_INODE = 3;
+ private static final int FD_INODE = 4;
+ private static final int FD_INODES = 32;
+
+ private abstract class DevFStat extends FStat {
+ public int dev() {
+ return devno;
+ }
+ public int mode() {
+ return 0666;
+ }
+ public int type() {
+ return S_IFCHR;
+ }
+ public int nlink() {
+ return 1;
+ }
+ public abstract int inode();
+ }
+
+ private abstract class DevDirFD extends DirFD {
+ public int myDev() {
+ return devno;
+ }
+ }
+
+ private FD devZeroFD = new FD() {
+ public int read(byte[] a, int off, int length) {
+ /*Arrays.fill(a,off,off+length,(byte)0);*/
+ for(int i=off; i= OPEN_MAX) return null;
+ if(r.fds[n] == null) return null;
+ return r.fds[n].dup();
+ }
+ if(path.equals("fd")) {
+ int count=0;
+ for(int i=0; i= OPEN_MAX) return null;
+ if(r.fds[n] == null) return null;
+ return r.fds[n].fstat();
+ }
+ if(path.equals("fd")) return new FStat() {
+ public int inode() {
+ return FD_INODE;
+ }
+ public int dev() {
+ return devno;
+ }
+ public int type() {
+ return S_IFDIR;
+ }
+ public int mode() {
+ return 0444;
+ }
+ };
+ if(path.equals("")) return new FStat() {
+ public int inode() {
+ return ROOT_INODE;
+ }
+ public int dev() {
+ return devno;
+ }
+ public int type() {
+ return S_IFDIR;
+ }
+ public int mode() {
+ return 0444;
+ }
+ };
+ return null;
+ }
+
+ public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void rmdir(UnixRuntime r, String path) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void unlink(UnixRuntime r, String path) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void link(UnixRuntime r, String oldpath, String newpath) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ }
+
+
+ public static class ResourceFS extends FS {
+ final InodeCache inodes = new InodeCache(500);
+
+ public FStat lstat(UnixRuntime r, String path) throws ErrnoException {
+ return stat(r,path);
+ }
+ public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void unlink(UnixRuntime r, String path) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void rmdir(UnixRuntime r, String path) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+ public void link(UnixRuntime r, String oldpath, String newpath) throws ErrnoException {
+ throw new ErrnoException(EROFS);
+ }
+
+ FStat connFStat(final URLConnection conn) {
+ return new FStat() {
+ public int type() {
+ return S_IFREG;
+ }
+ public int nlink() {
+ return 1;
+ }
+ public int mode() {
+ return 0444;
+ }
+ public int size() {
+ return conn.getContentLength();
+ }
+ public int mtime() {
+ return (int)(conn.getDate() / 1000);
+ }
+ public int inode() {
+ return inodes.get(conn.getURL().toString());
+ }
+ public int dev() {
+ return devno;
+ }
+ };
+ }
+
+ public FStat stat(UnixRuntime r, String path) throws ErrnoException {
+ URL url = r.getClass().getResource("/" + path);
+ if(url == null) return null;
+ try {
+ return connFStat(url.openConnection());
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException {
+ if((flags & ~3) != 0) {
+ if(STDERR_DIAG)
+ System.err.println("WARNING: Unsupported flags passed to ResourceFS.open(\"" + path + "\"): " + toHex(flags & ~3));
+ throw new ErrnoException(ENOTSUP);
+ }
+ if((flags&3) != RD_ONLY) throw new ErrnoException(EROFS);
+ URL url = r.getClass().getResource("/" + path);
+ if(url == null) return null;
+ try {
+ final URLConnection conn = url.openConnection();
+ Seekable.InputStream si = new Seekable.InputStream(conn.getInputStream());
+ return new SeekableFD(si,flags) {
+ protected FStat _fstat() {
+ return connFStat(conn);
+ }
+ };
+ } catch(FileNotFoundException e) {
+ if(e.getMessage() != null && e.getMessage().indexOf("Permission denied") >= 0) throw new ErrnoException(EACCES);
+ return null;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/ibex/nestedvm/UsermodeConstants.java b/src/main/java/org/ibex/nestedvm/UsermodeConstants.java
new file mode 100644
index 0000000..0385965
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/UsermodeConstants.java
@@ -0,0 +1,480 @@
+// THIS FILE IS AUTOGENERATED! DO NOT EDIT!
+// run "make rebuild-constants" if it needs to be updated
+
+package org.ibex.nestedvm;
+public interface UsermodeConstants {
+ public static final int SYS_null = 0;
+ public static final int SYS_exit = 1;
+ public static final int SYS_pause = 2;
+ public static final int SYS_open = 3;
+ public static final int SYS_close = 4;
+ public static final int SYS_read = 5;
+ public static final int SYS_write = 6;
+ public static final int SYS_sbrk = 7;
+ public static final int SYS_fstat = 8;
+ public static final int SYS_lseek = 10;
+ public static final int SYS_kill = 11;
+ public static final int SYS_getpid = 12;
+ public static final int SYS_calljava = 13;
+ public static final int SYS_stat = 14;
+ public static final int SYS_gettimeofday = 15;
+ public static final int SYS_sleep = 16;
+ public static final int SYS_times = 17;
+ public static final int SYS_mkdir = 18;
+ public static final int SYS_getpagesize = 19;
+ public static final int SYS_unlink = 20;
+ public static final int SYS_utime = 21;
+ public static final int SYS_chdir = 22;
+ public static final int SYS_pipe = 23;
+ public static final int SYS_dup2 = 24;
+ public static final int SYS_fork = 25;
+ public static final int SYS_waitpid = 26;
+ public static final int SYS_getcwd = 27;
+ public static final int SYS_exec = 28;
+ public static final int SYS_fcntl = 29;
+ public static final int SYS_rmdir = 30;
+ public static final int SYS_sysconf = 31;
+ public static final int SYS_readlink = 32;
+ public static final int SYS_lstat = 33;
+ public static final int SYS_symlink = 34;
+ public static final int SYS_link = 35;
+ public static final int SYS_getdents = 36;
+ public static final int SYS_memcpy = 37;
+ public static final int SYS_memset = 38;
+ public static final int SYS_dup = 39;
+ public static final int SYS_vfork = 40;
+ public static final int SYS_chroot = 41;
+ public static final int SYS_mknod = 42;
+ public static final int SYS_lchown = 43;
+ public static final int SYS_ftruncate = 44;
+ public static final int SYS_usleep = 45;
+ public static final int SYS_getppid = 46;
+ public static final int SYS_mkfifo = 47;
+ public static final int SYS_klogctl = 51;
+ public static final int SYS_realpath = 52;
+ public static final int SYS_sysctl = 53;
+ public static final int SYS_setpriority = 54;
+ public static final int SYS_getpriority = 55;
+ public static final int SYS_socket = 56;
+ public static final int SYS_connect = 57;
+ public static final int SYS_resolve_hostname = 58;
+ public static final int SYS_accept = 59;
+ public static final int SYS_setsockopt = 60;
+ public static final int SYS_getsockopt = 61;
+ public static final int SYS_listen = 62;
+ public static final int SYS_bind = 63;
+ public static final int SYS_shutdown = 64;
+ public static final int SYS_sendto = 65;
+ public static final int SYS_recvfrom = 66;
+ public static final int SYS_select = 67;
+ public static final int SYS_getuid = 68;
+ public static final int SYS_getgid = 69;
+ public static final int SYS_geteuid = 70;
+ public static final int SYS_getegid = 71;
+ public static final int SYS_getgroups = 72;
+ public static final int SYS_umask = 73;
+ public static final int SYS_chmod = 74;
+ public static final int SYS_fchmod = 75;
+ public static final int SYS_chown = 76;
+ public static final int SYS_fchown = 77;
+ public static final int SYS_access = 78;
+ public static final int SYS_alarm = 79;
+ public static final int SYS_setuid = 80;
+ public static final int SYS_setgid = 81;
+ public static final int SYS_send = 82;
+ public static final int SYS_recv = 83;
+ public static final int SYS_getsockname = 84;
+ public static final int SYS_getpeername = 85;
+ public static final int SYS_seteuid = 86;
+ public static final int SYS_setegid = 87;
+ public static final int SYS_setgroups = 88;
+ public static final int SYS_resolve_ip = 89;
+ public static final int SYS_setsid = 90;
+ public static final int SYS_fsync = 91;
+ public static final int AF_UNIX = 1;
+ public static final int AF_INET = 2;
+ public static final int SOCK_STREAM = 1;
+ public static final int SOCK_DGRAM = 2;
+ public static final int HOST_NOT_FOUND = 1;
+ public static final int TRY_AGAIN = 2;
+ public static final int NO_RECOVERY = 3;
+ public static final int NO_DATA = 4;
+ public static final int SOL_SOCKET = 0xffff;
+ public static final int SO_REUSEADDR = 0x0004;
+ public static final int SO_KEEPALIVE = 0x0008;
+ public static final int SO_BROADCAST = 0x0020;
+ public static final int SO_TYPE = 0x1008;
+ public static final int SHUT_RD = 0;
+ public static final int SHUT_WR = 1;
+ public static final int SHUT_RDWR = 2;
+ public static final int INADDR_ANY = 0;
+ public static final int INADDR_LOOPBACK = 0x7f000001;
+ public static final int INADDR_BROADCAST = 0xffffffff;
+ public static final int EPERM = 1; /* Not super-user */
+ public static final int ENOENT = 2; /* No such file or directory */
+ public static final int ESRCH = 3; /* No such process */
+ public static final int EINTR = 4; /* Interrupted system call */
+ public static final int EIO = 5; /* I/O error */
+ public static final int ENXIO = 6; /* No such device or address */
+ public static final int E2BIG = 7; /* Arg list too long */
+ public static final int ENOEXEC = 8; /* Exec format error */
+ public static final int EBADF = 9; /* Bad file number */
+ public static final int ECHILD = 10; /* No children */
+ public static final int EAGAIN = 11; /* No more processes */
+ public static final int ENOMEM = 12; /* Not enough core */
+ public static final int EACCES = 13; /* Permission denied */
+ public static final int EFAULT = 14; /* Bad address */
+ public static final int ENOTBLK = 15; /* Block device required */
+ public static final int EBUSY = 16; /* Mount device busy */
+ public static final int EEXIST = 17; /* File exists */
+ public static final int EXDEV = 18; /* Cross-device link */
+ public static final int ENODEV = 19; /* No such device */
+ public static final int ENOTDIR = 20; /* Not a directory */
+ public static final int EISDIR = 21; /* Is a directory */
+ public static final int EINVAL = 22; /* Invalid argument */
+ public static final int ENFILE = 23; /* Too many open files in system */
+ public static final int EMFILE = 24; /* Too many open files */
+ public static final int ENOTTY = 25; /* Not a typewriter */
+ public static final int ETXTBSY = 26; /* Text file busy */
+ public static final int EFBIG = 27; /* File too large */
+ public static final int ENOSPC = 28; /* No space left on device */
+ public static final int ESPIPE = 29; /* Illegal seek */
+ public static final int EROFS = 30; /* Read only file system */
+ public static final int EMLINK = 31; /* Too many links */
+ public static final int EPIPE = 32; /* Broken pipe */
+ public static final int EDOM = 33; /* Math arg out of domain of func */
+ public static final int ERANGE = 34; /* Math result not representable */
+ public static final int ENOMSG = 35; /* No message of desired type */
+ public static final int EIDRM = 36; /* Identifier removed */
+ public static final int ECHRNG = 37; /* Channel number out of range */
+ public static final int EL2NSYNC = 38; /* Level 2 not synchronized */
+ public static final int EL3HLT = 39; /* Level 3 halted */
+ public static final int EL3RST = 40; /* Level 3 reset */
+ public static final int ELNRNG = 41; /* Link number out of range */
+ public static final int EUNATCH = 42; /* Protocol driver not attached */
+ public static final int ENOCSI = 43; /* No CSI structure available */
+ public static final int EL2HLT = 44; /* Level 2 halted */
+ public static final int EDEADLK = 45; /* Deadlock condition */
+ public static final int ENOLCK = 46; /* No record locks available */
+ public static final int EBADE = 50; /* Invalid exchange */
+ public static final int EBADR = 51; /* Invalid request descriptor */
+ public static final int EXFULL = 52; /* Exchange full */
+ public static final int ENOANO = 53; /* No anode */
+ public static final int EBADRQC = 54; /* Invalid request code */
+ public static final int EBADSLT = 55; /* Invalid slot */
+ public static final int EDEADLOCK = 56; /* File locking deadlock error */
+ public static final int EBFONT = 57; /* Bad font file fmt */
+ public static final int ENOSTR = 60; /* Device not a stream */
+ public static final int ENODATA = 61; /* No data (for no delay io) */
+ public static final int ETIME = 62; /* Timer expired */
+ public static final int ENOSR = 63; /* Out of streams resources */
+ public static final int ENONET = 64; /* Machine is not on the network */
+ public static final int ENOPKG = 65; /* Package not installed */
+ public static final int EREMOTE = 66; /* The object is remote */
+ public static final int ENOLINK = 67; /* The link has been severed */
+ public static final int EADV = 68; /* Advertise error */
+ public static final int ESRMNT = 69; /* Srmount error */
+ public static final int ECOMM = 70; /* Communication error on send */
+ public static final int EPROTO = 71; /* Protocol error */
+ public static final int EMULTIHOP = 74; /* Multihop attempted */
+ public static final int ELBIN = 75; /* Inode is remote (not really error) */
+ public static final int EDOTDOT = 76; /* Cross mount point (not really error) */
+ public static final int EBADMSG = 77; /* Trying to read unreadable message */
+ public static final int EFTYPE = 79; /* Inappropriate file type or format */
+ public static final int ENOTUNIQ = 80; /* Given log. name not unique */
+ public static final int EBADFD = 81; /* f.d. invalid for this operation */
+ public static final int EREMCHG = 82; /* Remote address changed */
+ public static final int ELIBACC = 83; /* Can't access a needed shared lib */
+ public static final int ELIBBAD = 84; /* Accessing a corrupted shared lib */
+ public static final int ELIBSCN = 85; /* .lib section in a.out corrupted */
+ public static final int ELIBMAX = 86; /* Attempting to link in too many libs */
+ public static final int ELIBEXEC = 87; /* Attempting to exec a shared library */
+ public static final int ENOSYS = 88; /* Function not implemented */
+ public static final int ENMFILE = 89; /* No more files */
+ public static final int ENOTEMPTY = 90; /* Directory not empty */
+ public static final int ENAMETOOLONG = 91; /* File or path name too long */
+ public static final int ELOOP = 92; /* Too many symbolic links */
+ public static final int EOPNOTSUPP = 95; /* Operation not supported on transport endpoint */
+ public static final int EPFNOSUPPORT = 96; /* Protocol family not supported */
+ public static final int ECONNRESET = 104; /* Connection reset by peer */
+ public static final int ENOBUFS = 105; /* No buffer space available */
+ public static final int EAFNOSUPPORT = 106; /* Address family not supported by protocol family */
+ public static final int EPROTOTYPE = 107; /* Protocol wrong type for socket */
+ public static final int ENOTSOCK = 108; /* Socket operation on non-socket */
+ public static final int ENOPROTOOPT = 109; /* Protocol not available */
+ public static final int ESHUTDOWN = 110; /* Can't send after socket shutdown */
+ public static final int ECONNREFUSED = 111; /* Connection refused */
+ public static final int EADDRINUSE = 112; /* Address already in use */
+ public static final int ECONNABORTED = 113; /* Connection aborted */
+ public static final int ENETUNREACH = 114; /* Network is unreachable */
+ public static final int ENETDOWN = 115; /* Network interface is not configured */
+ public static final int ETIMEDOUT = 116; /* Connection timed out */
+ public static final int EHOSTDOWN = 117; /* Host is down */
+ public static final int EHOSTUNREACH = 118; /* Host is unreachable */
+ public static final int EINPROGRESS = 119; /* Connection already in progress */
+ public static final int EALREADY = 120; /* Socket already connected */
+ public static final int EDESTADDRREQ = 121; /* Destination address required */
+ public static final int EMSGSIZE = 122; /* Message too long */
+ public static final int EPROTONOSUPPORT = 123; /* Unknown protocol */
+ public static final int ESOCKTNOSUPPORT = 124; /* Socket type not supported */
+ public static final int EADDRNOTAVAIL = 125; /* Address not available */
+ public static final int ENETRESET = 126;
+ public static final int EISCONN = 127; /* Socket is already connected */
+ public static final int ENOTCONN = 128; /* Socket is not connected */
+ public static final int ETOOMANYREFS = 129;
+ public static final int EPROCLIM = 130;
+ public static final int EUSERS = 131;
+ public static final int EDQUOT = 132;
+ public static final int ESTALE = 133;
+ public static final int ENOTSUP = 134; /* Not supported */
+ public static final int ENOMEDIUM = 135; /* No medium (in tape drive) */
+ public static final int ENOSHARE = 136; /* No such host or network path */
+ public static final int ECASECLASH = 137; /* Filename exists with different case */
+ public static final int EILSEQ = 138;
+ public static final int EOVERFLOW = 139; /* Value too large for defined data type */
+ public static final int __ELASTERROR = 2000; /* Users can add values starting here */
+ public static final int F_OK = 0;
+ public static final int R_OK = 4;
+ public static final int W_OK = 2;
+ public static final int X_OK = 1;
+ public static final int SEEK_SET = 0;
+ public static final int SEEK_CUR = 1;
+ public static final int SEEK_END = 2;
+ public static final int STDIN_FILENO = 0; /* standard input file descriptor */
+ public static final int STDOUT_FILENO = 1; /* standard output file descriptor */
+ public static final int STDERR_FILENO = 2; /* standard error file descriptor */
+ public static final int _SC_ARG_MAX = 0;
+ public static final int _SC_CHILD_MAX = 1;
+ public static final int _SC_CLK_TCK = 2;
+ public static final int _SC_NGROUPS_MAX = 3;
+ public static final int _SC_OPEN_MAX = 4;
+ public static final int _SC_JOB_CONTROL = 5;
+ public static final int _SC_SAVED_IDS = 6;
+ public static final int _SC_VERSION = 7;
+ public static final int _SC_PAGESIZE = 8;
+ public static final int _SC_NPROCESSORS_CONF = 9;
+ public static final int _SC_NPROCESSORS_ONLN = 10;
+ public static final int _SC_PHYS_PAGES = 11;
+ public static final int _SC_AVPHYS_PAGES = 12;
+ public static final int _SC_MQ_OPEN_MAX = 13;
+ public static final int _SC_MQ_PRIO_MAX = 14;
+ public static final int _SC_RTSIG_MAX = 15;
+ public static final int _SC_SEM_NSEMS_MAX = 16;
+ public static final int _SC_SEM_VALUE_MAX = 17;
+ public static final int _SC_SIGQUEUE_MAX = 18;
+ public static final int _SC_TIMER_MAX = 19;
+ public static final int _SC_TZNAME_MAX = 20;
+ public static final int _SC_ASYNCHRONOUS_IO = 21;
+ public static final int _SC_FSYNC = 22;
+ public static final int _SC_MAPPED_FILES = 23;
+ public static final int _SC_MEMLOCK = 24;
+ public static final int _SC_MEMLOCK_RANGE = 25;
+ public static final int _SC_MEMORY_PROTECTION = 26;
+ public static final int _SC_MESSAGE_PASSING = 27;
+ public static final int _SC_PRIORITIZED_IO = 28;
+ public static final int _SC_REALTIME_SIGNALS = 29;
+ public static final int _SC_SEMAPHORES = 30;
+ public static final int _SC_SHARED_MEMORY_OBJECTS = 31;
+ public static final int _SC_SYNCHRONIZED_IO = 32;
+ public static final int _SC_TIMERS = 33;
+ public static final int _SC_AIO_LISTIO_MAX = 34;
+ public static final int _SC_AIO_MAX = 35;
+ public static final int _SC_AIO_PRIO_DELTA_MAX = 36;
+ public static final int _SC_DELAYTIMER_MAX = 37;
+ public static final int _SC_THREAD_KEYS_MAX = 38;
+ public static final int _SC_THREAD_STACK_MIN = 39;
+ public static final int _SC_THREAD_THREADS_MAX = 40;
+ public static final int _SC_TTY_NAME_MAX = 41;
+ public static final int _SC_THREADS = 42;
+ public static final int _SC_THREAD_ATTR_STACKADDR = 43;
+ public static final int _SC_THREAD_ATTR_STACKSIZE = 44;
+ public static final int _SC_THREAD_PRIORITY_SCHEDULING = 45;
+ public static final int _SC_THREAD_PRIO_INHERIT = 46;
+ public static final int _SC_THREAD_PRIO_PROTECT = 47;
+ public static final int _SC_THREAD_PROCESS_SHARED = 48;
+ public static final int _SC_THREAD_SAFE_FUNCTIONS = 49;
+ public static final int _SC_GETGR_R_SIZE_MAX = 50;
+ public static final int _SC_GETPW_R_SIZE_MAX = 51;
+ public static final int _SC_LOGIN_NAME_MAX = 52;
+ public static final int _SC_THREAD_DESTRUCTOR_ITERATIONS = 53;
+ public static final int _SC_STREAM_MAX = 100;
+ public static final int _SC_PRIORITY_SCHEDULING = 101;
+ public static final int _PC_LINK_MAX = 0;
+ public static final int _PC_MAX_CANON = 1;
+ public static final int _PC_MAX_INPUT = 2;
+ public static final int _PC_NAME_MAX = 3;
+ public static final int _PC_PATH_MAX = 4;
+ public static final int _PC_PIPE_BUF = 5;
+ public static final int _PC_CHOWN_RESTRICTED = 6;
+ public static final int _PC_NO_TRUNC = 7;
+ public static final int _PC_VDISABLE = 8;
+ public static final int _PC_ASYNC_IO = 9;
+ public static final int _PC_PRIO_IO = 10;
+ public static final int _PC_SYNC_IO = 11;
+ public static final int _PC_POSIX_PERMISSIONS = 90;
+ public static final int _PC_POSIX_SECURITY = 91;
+ public static final int MAXPATHLEN = 1024;
+ public static final int ARG_MAX = 65536; /* max bytes for an exec function */
+ public static final int CHILD_MAX = 40; /* max simultaneous processes */
+ public static final int LINK_MAX = 32767; /* max file link count */
+ public static final int MAX_CANON = 255; /* max bytes in term canon input line */
+ public static final int MAX_INPUT = 255; /* max bytes in terminal input */
+ public static final int NAME_MAX = 255; /* max bytes in a file name */
+ public static final int NGROUPS_MAX = 16; /* max supplemental group id's */
+ public static final int OPEN_MAX = 64; /* max open files per process */
+ public static final int PATH_MAX = 1024; /* max bytes in pathname */
+ public static final int PIPE_BUF = 512; /* max bytes for atomic pipe writes */
+ public static final int IOV_MAX = 1024; /* max elements in i/o vector */
+ public static final int BC_BASE_MAX = 99; /* max ibase/obase values in bc(1) */
+ public static final int BC_DIM_MAX = 2048; /* max array elements in bc(1) */
+ public static final int BC_SCALE_MAX = 99; /* max scale value in bc(1) */
+ public static final int BC_STRING_MAX = 1000; /* max const string length in bc(1) */
+ public static final int COLL_WEIGHTS_MAX = 0; /* max weights for order keyword */
+ public static final int EXPR_NEST_MAX = 32; /* max expressions nested in expr(1) */
+ public static final int LINE_MAX = 2048; /* max bytes in an input line */
+ public static final int RE_DUP_MAX = 255; /* max RE's in interval notation */
+ public static final int CTL_MAXNAME = 12;
+ public static final int CTL_UNSPEC = 0; /* unused */
+ public static final int CTL_KERN = 1; /* "high kernel": proc, limits */
+ public static final int CTL_VM = 2; /* virtual memory */
+ public static final int CTL_VFS = 3; /* file system, mount type is next */
+ public static final int CTL_NET = 4; /* network, see socket.h */
+ public static final int CTL_DEBUG = 5; /* debugging parameters */
+ public static final int CTL_HW = 6; /* generic cpu/io */
+ public static final int CTL_MACHDEP = 7; /* machine dependent */
+ public static final int CTL_USER = 8; /* user-level */
+ public static final int CTL_P1003_1B = 9; /* POSIX 1003.1B */
+ public static final int CTL_MAXID = 10; /* number of valid top-level ids */
+ public static final int KERN_OSTYPE = 1; /* string: system version */
+ public static final int KERN_OSRELEASE = 2; /* string: system release */
+ public static final int KERN_OSREV = 3; /* int: system revision */
+ public static final int KERN_VERSION = 4; /* string: compile time info */
+ public static final int KERN_MAXVNODES = 5; /* int: max vnodes */
+ public static final int KERN_MAXPROC = 6; /* int: max processes */
+ public static final int KERN_MAXFILES = 7; /* int: max open files */
+ public static final int KERN_ARGMAX = 8; /* int: max arguments to exec */
+ public static final int KERN_SECURELVL = 9; /* int: system security level */
+ public static final int KERN_HOSTNAME = 10; /* string: hostname */
+ public static final int KERN_HOSTID = 11; /* int: host identifier */
+ public static final int KERN_CLOCKRATE = 12; /* struct: struct clockrate */
+ public static final int KERN_VNODE = 13; /* struct: vnode structures */
+ public static final int KERN_PROC = 14; /* struct: process entries */
+ public static final int KERN_FILE = 15; /* struct: file entries */
+ public static final int KERN_PROF = 16; /* node: kernel profiling info */
+ public static final int KERN_POSIX1 = 17; /* int: POSIX.1 version */
+ public static final int KERN_NGROUPS = 18; /* int: # of supplemental group ids */
+ public static final int KERN_JOB_CONTROL = 19; /* int: is job control available */
+ public static final int KERN_SAVED_IDS = 20; /* int: saved set-user/group-ID */
+ public static final int KERN_BOOTTIME = 21; /* struct: time kernel was booted */
+ public static final int KERN_NISDOMAINNAME = 22; /* string: YP domain name */
+ public static final int KERN_UPDATEINTERVAL = 23; /* int: update process sleep time */
+ public static final int KERN_OSRELDATE = 24; /* int: OS release date */
+ public static final int KERN_NTP_PLL = 25; /* node: NTP PLL control */
+ public static final int KERN_BOOTFILE = 26; /* string: name of booted kernel */
+ public static final int KERN_MAXFILESPERPROC = 27; /* int: max open files per proc */
+ public static final int KERN_MAXPROCPERUID = 28; /* int: max processes per uid */
+ public static final int KERN_DUMPDEV = 29; /* dev_t: device to dump on */
+ public static final int KERN_IPC = 30; /* node: anything related to IPC */
+ public static final int KERN_DUMMY = 31; /* unused */
+ public static final int KERN_PS_STRINGS = 32; /* int: address of PS_STRINGS */
+ public static final int KERN_USRSTACK = 33; /* int: address of USRSTACK */
+ public static final int KERN_LOGSIGEXIT = 34; /* int: do we log sigexit procs? */
+ public static final int KERN_MAXID = 35; /* number of valid kern ids */
+ public static final int KERN_PROC_ALL = 0; /* everything */
+ public static final int KERN_PROC_PID = 1; /* by process id */
+ public static final int KERN_PROC_PGRP = 2; /* by process group id */
+ public static final int KERN_PROC_SESSION = 3; /* by session of pid */
+ public static final int KERN_PROC_TTY = 4; /* by controlling tty */
+ public static final int KERN_PROC_UID = 5; /* by effective uid */
+ public static final int KERN_PROC_RUID = 6; /* by real uid */
+ public static final int KERN_PROC_ARGS = 7; /* get/set arguments/proctitle */
+ public static final int KIPC_MAXSOCKBUF = 1; /* int: max size of a socket buffer */
+ public static final int KIPC_SOCKBUF_WASTE = 2; /* int: wastage factor in sockbuf */
+ public static final int KIPC_SOMAXCONN = 3; /* int: max length of connection q */
+ public static final int KIPC_MAX_LINKHDR = 4; /* int: max length of link header */
+ public static final int KIPC_MAX_PROTOHDR = 5; /* int: max length of network header */
+ public static final int KIPC_MAX_HDR = 6; /* int: max total length of headers */
+ public static final int KIPC_MAX_DATALEN = 7; /* int: max length of data? */
+ public static final int KIPC_MBSTAT = 8; /* struct: mbuf usage statistics */
+ public static final int KIPC_NMBCLUSTERS = 9; /* int: maximum mbuf clusters */
+ public static final int HW_MACHINE = 1; /* string: machine class */
+ public static final int HW_MODEL = 2; /* string: specific machine model */
+ public static final int HW_NCPU = 3; /* int: number of cpus */
+ public static final int HW_BYTEORDER = 4; /* int: machine byte order */
+ public static final int HW_PHYSMEM = 5; /* int: total memory */
+ public static final int HW_USERMEM = 6; /* int: non-kernel memory */
+ public static final int HW_PAGESIZE = 7; /* int: software page size */
+ public static final int HW_DISKNAMES = 8; /* strings: disk drive names */
+ public static final int HW_DISKSTATS = 9; /* struct: diskstats[] */
+ public static final int HW_FLOATINGPT = 10; /* int: has HW floating point? */
+ public static final int HW_MACHINE_ARCH = 11; /* string: machine architecture */
+ public static final int HW_MAXID = 12; /* number of valid hw ids */
+ public static final int USER_CS_PATH = 1; /* string: _CS_PATH */
+ public static final int USER_BC_BASE_MAX = 2; /* int: BC_BASE_MAX */
+ public static final int USER_BC_DIM_MAX = 3; /* int: BC_DIM_MAX */
+ public static final int USER_BC_SCALE_MAX = 4; /* int: BC_SCALE_MAX */
+ public static final int USER_BC_STRING_MAX = 5; /* int: BC_STRING_MAX */
+ public static final int USER_COLL_WEIGHTS_MAX = 6; /* int: COLL_WEIGHTS_MAX */
+ public static final int USER_EXPR_NEST_MAX = 7; /* int: EXPR_NEST_MAX */
+ public static final int USER_LINE_MAX = 8; /* int: LINE_MAX */
+ public static final int USER_RE_DUP_MAX = 9; /* int: RE_DUP_MAX */
+ public static final int USER_POSIX2_VERSION = 10; /* int: POSIX2_VERSION */
+ public static final int USER_POSIX2_C_BIND = 11; /* int: POSIX2_C_BIND */
+ public static final int USER_POSIX2_C_DEV = 12; /* int: POSIX2_C_DEV */
+ public static final int USER_POSIX2_CHAR_TERM = 13; /* int: POSIX2_CHAR_TERM */
+ public static final int USER_POSIX2_FORT_DEV = 14; /* int: POSIX2_FORT_DEV */
+ public static final int USER_POSIX2_FORT_RUN = 15; /* int: POSIX2_FORT_RUN */
+ public static final int USER_POSIX2_LOCALEDEF = 16; /* int: POSIX2_LOCALEDEF */
+ public static final int USER_POSIX2_SW_DEV = 17; /* int: POSIX2_SW_DEV */
+ public static final int USER_POSIX2_UPE = 18; /* int: POSIX2_UPE */
+ public static final int USER_STREAM_MAX = 19; /* int: POSIX2_STREAM_MAX */
+ public static final int USER_TZNAME_MAX = 20; /* int: POSIX2_TZNAME_MAX */
+ public static final int USER_MAXID = 21; /* number of valid user ids */
+ public static final int CTL_P1003_1B_ASYNCHRONOUS_IO = 1; /* boolean */
+ public static final int CTL_P1003_1B_MAPPED_FILES = 2; /* boolean */
+ public static final int CTL_P1003_1B_MEMLOCK = 3; /* boolean */
+ public static final int CTL_P1003_1B_MEMLOCK_RANGE = 4; /* boolean */
+ public static final int CTL_P1003_1B_MEMORY_PROTECTION = 5; /* boolean */
+ public static final int CTL_P1003_1B_MESSAGE_PASSING = 6; /* boolean */
+ public static final int CTL_P1003_1B_PRIORITIZED_IO = 7; /* boolean */
+ public static final int CTL_P1003_1B_PRIORITY_SCHEDULING = 8; /* boolean */
+ public static final int CTL_P1003_1B_REALTIME_SIGNALS = 9; /* boolean */
+ public static final int CTL_P1003_1B_SEMAPHORES = 10; /* boolean */
+ public static final int CTL_P1003_1B_FSYNC = 11; /* boolean */
+ public static final int CTL_P1003_1B_SHARED_MEMORY_OBJECTS = 12; /* boolean */
+ public static final int CTL_P1003_1B_SYNCHRONIZED_IO = 13; /* boolean */
+ public static final int CTL_P1003_1B_TIMERS = 14; /* boolean */
+ public static final int CTL_P1003_1B_AIO_LISTIO_MAX = 15; /* int */
+ public static final int CTL_P1003_1B_AIO_MAX = 16; /* int */
+ public static final int CTL_P1003_1B_AIO_PRIO_DELTA_MAX = 17; /* int */
+ public static final int CTL_P1003_1B_DELAYTIMER_MAX = 18; /* int */
+ public static final int CTL_P1003_1B_MQ_OPEN_MAX = 19; /* int */
+ public static final int CTL_P1003_1B_PAGESIZE = 20; /* int */
+ public static final int CTL_P1003_1B_RTSIG_MAX = 21; /* int */
+ public static final int CTL_P1003_1B_SEM_NSEMS_MAX = 22; /* int */
+ public static final int CTL_P1003_1B_SEM_VALUE_MAX = 23; /* int */
+ public static final int CTL_P1003_1B_SIGQUEUE_MAX = 24; /* int */
+ public static final int CTL_P1003_1B_TIMER_MAX = 25; /* int */
+ public static final int CTL_P1003_1B_MAXID = 26;
+ public static final int F_UNLKSYS = 4;
+ public static final int F_CNVT = 12;
+ public static final int F_SETFD = 2;
+ public static final int F_SETFL = 4;
+ public static final int F_SETLK = 8;
+ public static final int F_SETOWN = 6;
+ public static final int F_RDLCK = 1;
+ public static final int F_WRLCK = 2;
+ public static final int F_SETLKW = 9;
+ public static final int F_GETFD = 1;
+ public static final int F_DUPFD = 0;
+ public static final int O_WRONLY = 1;
+ public static final int F_RSETLKW = 13;
+ public static final int O_RDWR = 2;
+ public static final int F_RGETLK = 10;
+ public static final int O_RDONLY = 0;
+ public static final int F_UNLCK = 3;
+ public static final int F_GETOWN = 5;
+ public static final int F_RSETLK = 11;
+ public static final int F_GETFL = 3;
+ public static final int F_GETLK = 7;
+}
diff --git a/src/main/java/org/ibex/nestedvm/util/ELF.java b/src/main/java/org/ibex/nestedvm/util/ELF.java
new file mode 100644
index 0000000..2f97071
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/util/ELF.java
@@ -0,0 +1,388 @@
+// 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.
+
+package org.ibex.nestedvm.util;
+
+import java.io.*;
+
+public class ELF {
+ private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
+
+ public static final int ELFCLASSNONE = 0;
+ public static final int ELFCLASS32 = 1;
+ public static final int ELFCLASS64 = 2;
+
+ public static final int ELFDATANONE = 0;
+ public static final int ELFDATA2LSB = 1;
+ public static final int ELFDATA2MSB = 2;
+
+ public static final int SHT_SYMTAB = 2;
+ public static final int SHT_STRTAB = 3;
+ public static final int SHT_NOBITS = 8;
+
+ public static final int SHF_WRITE = 1;
+ public static final int SHF_ALLOC = 2;
+ public static final int SHF_EXECINSTR = 4;
+
+ public static final int PF_X = 0x1;
+ public static final int PF_W = 0x2;
+ public static final int PF_R = 0x4;
+
+ public static final int PT_LOAD = 1;
+
+ public static final short ET_EXEC = 2;
+ public static final short EM_MIPS = 8;
+
+
+ private Seekable data;
+
+ public ELFIdent ident;
+ public ELFHeader header;
+ public PHeader[] pheaders;
+ public SHeader[] sheaders;
+
+ private byte[] stringTable;
+
+ private boolean sectionReaderActive;
+
+
+ private void readFully(byte[] buf) throws IOException {
+ int len = buf.length;
+ int pos = 0;
+ while(len > 0) {
+ int n = data.read(buf,pos,len);
+ if(n == -1) throw new IOException("EOF");
+ pos += n;
+ len -= n;
+ }
+ }
+
+ private int readIntBE() throws IOException {
+ byte[] buf = new byte[4];
+ readFully(buf);
+ return ((buf[0]&0xff)<<24)|((buf[1]&0xff)<<16)|((buf[2]&0xff)<<8)|((buf[3]&0xff)<<0);
+ }
+ private int readInt() throws IOException {
+ int x = readIntBE();
+ if(ident!=null && ident.data == ELFDATA2LSB)
+ x = ((x<<24)&0xff000000) | ((x<<8)&0xff0000) | ((x>>>8)&0xff00) | ((x>>24)&0xff);
+ return x;
+ }
+
+ private short readShortBE() throws IOException {
+ byte[] buf = new byte[2];
+ readFully(buf);
+ return (short)(((buf[0]&0xff)<<8)|((buf[1]&0xff)<<0));
+ }
+ private short readShort() throws IOException {
+ short x = readShortBE();
+ if(ident!=null && ident.data == ELFDATA2LSB)
+ x = (short)((((x<<8)&0xff00) | ((x>>8)&0xff))&0xffff);
+ return x;
+ }
+
+ private byte readByte() throws IOException {
+ byte[] buf = new byte[1];
+ readFully(buf);
+ return buf[0];
+ }
+
+ public class ELFIdent {
+ public byte klass;
+ public byte data;
+ public byte osabi;
+ public byte abiversion;
+
+ ELFIdent() throws IOException {
+ if(readIntBE() != ELF_MAGIC) throw new ELFException("Bad Magic");
+
+ klass = readByte();
+ if(klass != ELFCLASS32) throw new ELFException("org.ibex.nestedvm.util.ELF does not suport 64-bit binaries");
+
+ data = readByte();
+ if(data != ELFDATA2LSB && data != ELFDATA2MSB) throw new ELFException("Unknown byte order");
+
+ readByte(); // version
+ osabi = readByte();
+ abiversion = readByte();
+ for(int i=0;i<7;i++) readByte(); // padding
+ }
+ }
+
+ public class ELFHeader {
+ public short type;
+ public short machine;
+ public int version;
+ public int entry;
+ public int phoff;
+ public int shoff;
+ public int flags;
+ public short ehsize;
+ public short phentsize;
+ public short phnum;
+ public short shentsize;
+ public short shnum;
+ public short shstrndx;
+
+ ELFHeader() throws IOException {
+ type = readShort();
+ machine = readShort();
+ version = readInt();
+ if(version != 1) throw new ELFException("version != 1");
+ entry = readInt();
+ phoff = readInt();
+ shoff = readInt();
+ flags = readInt();
+ ehsize = readShort();
+ phentsize = readShort();
+ phnum = readShort();
+ shentsize = readShort();
+ shnum = readShort();
+ shstrndx = readShort();
+ }
+ }
+
+ public class PHeader {
+ public int type;
+ public int offset;
+ public int vaddr;
+ public int paddr;
+ public int filesz;
+ public int memsz;
+ public int flags;
+ public int align;
+
+ PHeader() throws IOException {
+ type = readInt();
+ offset = readInt();
+ vaddr = readInt();
+ paddr = readInt();
+ filesz = readInt();
+ memsz = readInt();
+ flags = readInt();
+ align = readInt();
+ if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz (" + toHex(filesz) + " > " + toHex(memsz) + ")");
+ }
+
+ public boolean writable() { return (flags & PF_W) != 0; }
+
+ public InputStream getInputStream() throws IOException {
+ return new BufferedInputStream(new SectionInputStream(
+ offset,offset+filesz));
+ }
+ }
+
+ public class SHeader {
+ int nameidx;
+ public String name;
+ public int type;
+ public int flags;
+ public int addr;
+ public int offset;
+ public int size;
+ public int link;
+ public int info;
+ public int addralign;
+ public int entsize;
+
+ SHeader() throws IOException {
+ nameidx = readInt();
+ type = readInt();
+ flags = readInt();
+ addr = readInt();
+ offset = readInt();
+ size = readInt();
+ link = readInt();
+ info = readInt();
+ addralign = readInt();
+ entsize = readInt();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return new BufferedInputStream(new SectionInputStream(
+ offset, type == SHT_NOBITS ? 0 : offset+size));
+ }
+
+ public boolean isText() { return name.equals(".text"); }
+ public boolean isData() { return name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"); }
+ public boolean isBSS() { return name.equals(".bss") || name.equals(".sbss"); }
+ }
+
+ public ELF(String file) throws IOException, ELFException { this(new Seekable.File(file,false)); }
+ public ELF(Seekable data) throws IOException, ELFException {
+ this.data = data;
+ ident = new ELFIdent();
+ header = new ELFHeader();
+ pheaders = new PHeader[header.phnum];
+ for(int i=0;i= header.shnum) throw new ELFException("Bad shstrndx");
+ data.seek(sheaders[header.shstrndx].offset);
+ stringTable = new byte[sheaders[header.shstrndx].size];
+ readFully(stringTable);
+
+ for(int i=0;i= strtab.length) return "";
+ while(off >= 0 && off < strtab.length && strtab[off] != 0) sb.append((char)strtab[off++]);
+ return sb.toString();
+ }
+
+ public SHeader sectionWithName(String name) {
+ for(int i=0;i 0) pos += n; return n;
+ }
+ public void close() { sectionReaderActive = false; }
+ }
+
+ private Symtab _symtab;
+ public Symtab getSymtab() throws IOException {
+ if(_symtab != null) return _symtab;
+
+ if(sectionReaderActive) throw new ELFException("Can't read the symtab while a section reader is active");
+
+ SHeader sh = sectionWithName(".symtab");
+ if(sh == null || sh.type != SHT_SYMTAB) return null;
+
+ SHeader sth = sectionWithName(".strtab");
+ if(sth == null || sth.type != SHT_STRTAB) return null;
+
+ byte[] strtab = new byte[sth.size];
+ DataInputStream dis = new DataInputStream(sth.getInputStream());
+ dis.readFully(strtab);
+ dis.close();
+
+ return _symtab = new Symtab(sh.offset, sh.size,strtab);
+ }
+
+ public class Symtab {
+ public Symbol[] symbols;
+
+ Symtab(int off, int size, byte[] strtab) throws IOException {
+ data.seek(off);
+ int count = size/16;
+ symbols = new Symbol[count];
+ for(int i=0;i>4);
+ other = readByte();
+ shndx = readShort();
+ }
+ }
+
+ private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+
+ /*public static void main(String[] args) throws IOException {
+ ELF elf = new ELF(new Seekable.InputStream(new FileInputStream(args[0])));
+ System.out.println("Type: " + toHex(elf.header.type));
+ System.out.println("Machine: " + toHex(elf.header.machine));
+ System.out.println("Entry: " + toHex(elf.header.entry));
+ for(int i=0;i " + toHex(symtab.symbols[i].addr));
+ } else {
+ System.out.println("Symbol table: None");
+ }
+ }*/
+}
diff --git a/src/main/java/org/ibex/nestedvm/util/InodeCache.java b/src/main/java/org/ibex/nestedvm/util/InodeCache.java
new file mode 100644
index 0000000..02913de
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/util/InodeCache.java
@@ -0,0 +1,207 @@
+// 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.
+
+package org.ibex.nestedvm.util;
+
+// Based on the various org.xwt.util.* classes by Adam Megacz
+
+public class InodeCache {
+ private static final Object PLACEHOLDER = new Object();
+ private static final short SHORT_PLACEHOLDER = -2;
+ private static final short SHORT_NULL = -1;
+ private static final int LOAD_FACTOR = 2;
+
+ private final int maxSize;
+ private final int totalSlots;
+ private final int maxUsedSlots;
+
+ private final Object[] keys;
+ private final short[] next;
+ private final short[] prev;
+ private final short[] inodes;
+ private final short[] reverse;
+
+ private int size, usedSlots;
+ private short mru, lru;
+
+ public InodeCache() { this(1024); }
+ public InodeCache(int maxSize) {
+ this.maxSize = maxSize;
+ totalSlots = maxSize*LOAD_FACTOR*2 + 3;
+ maxUsedSlots = totalSlots / LOAD_FACTOR;
+ if(totalSlots > Short.MAX_VALUE) throw new IllegalArgumentException("cache size too large");
+ keys = new Object[totalSlots];
+ next = new short[totalSlots];
+ prev = new short[totalSlots];
+ inodes = new short[totalSlots];
+ reverse = new short[totalSlots];
+ clear();
+ }
+
+ private static void fill(Object[] a,Object o) { for(int i=0;i " + inodes[i] + "(prev: " + prev[i] + " next: " + next[i] + ")");
+ if(i == lru) break;
+ }
+ }
+
+ private void stats() {
+ int freeKeys = 0;
+ int freeReverse = 0;
+ int placeholderKeys = 0;
+ int placeholderReverse = 0;
+ for(int i=0;i " + c.reverse(n));
+ } else {
+ //System.err.println("Adding " + s);
+ short n = c.get(s);
+ System.err.println("Added " + s + " -> " + n);
+ //c.dump();
+ }
+ }
+ good = true;
+ } finally {
+ if(!good) c.stats();
+ }
+ }*/
+}
diff --git a/src/main/java/org/ibex/nestedvm/util/Platform.java b/src/main/java/org/ibex/nestedvm/util/Platform.java
new file mode 100644
index 0000000..775af41
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/util/Platform.java
@@ -0,0 +1,241 @@
+// 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.
+
+package org.ibex.nestedvm.util;
+
+import java.io.*;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+
+import java.text.DateFormatSymbols;
+
+/*
+ GCCLASS_HINT: org.ibex.nestedvm.util.Platform. org.ibex.nestedvm.util.Platform$Jdk11.
+ GCCLASS_HINT: org.ibex.nestedvm.util.Platform. org.ibex.nestedvm.util.Platform$Jdk12.
+ GCCLASS_HINT: org.ibex.nestedvm.util.Platform. org.ibex.nestedvm.util.Platform$Jdk13.
+ GCCLASS_HINT: org.ibex.nestedvm.util.Platform. org.ibex.nestedvm.util.Platform$Jdk14.
+*/
+
+public abstract class Platform {
+ Platform() { }
+ private static final Platform p;
+
+ static {
+ float version;
+ try {
+ if(getProperty("java.vm.name").equals("SableVM"))
+ version = 1.2f;
+ else
+ version = Float.valueOf(getProperty("java.specification.version")).floatValue();
+ } catch(Exception e) {
+ System.err.println("WARNING: " + e + " while trying to find jvm version - assuming 1.1");
+ version = 1.1f;
+ }
+ String platformClass;
+ if(version >= 1.4f) platformClass = "Jdk14";
+ else if(version >= 1.3f) platformClass = "Jdk13";
+ else if(version >= 1.2f) platformClass = "Jdk12";
+ else if(version >= 1.1f) platformClass = "Jdk11";
+ else throw new Error("JVM Specification version: " + version + " is too old. (see org.ibex.util.Platform to add support)");
+
+ try {
+ p = (Platform) Class.forName(Platform.class.getName() + "$" + platformClass).newInstance();
+ } catch(Exception e) {
+ e.printStackTrace();
+ throw new Error("Error instansiating platform class");
+ }
+ }
+
+ public static String getProperty(String key) {
+ try {
+ return System.getProperty(key);
+ } catch(SecurityException e) {
+ return null;
+ }
+ }
+
+
+ abstract boolean _atomicCreateFile(File f) throws IOException;
+ public static boolean atomicCreateFile(File f) throws IOException { return p._atomicCreateFile(f); }
+
+ abstract Seekable.Lock _lockFile(Seekable s, RandomAccessFile raf, long pos, long size, boolean shared) throws IOException;
+ public static Seekable.Lock lockFile(Seekable s, RandomAccessFile raf, long pos, long size, boolean shared) throws IOException {
+ return p._lockFile(s, raf, pos, size, shared); }
+
+ abstract void _socketHalfClose(Socket s, boolean output) throws IOException;
+ public static void socketHalfClose(Socket s, boolean output) throws IOException { p._socketHalfClose(s,output); }
+
+ abstract void _socketSetKeepAlive(Socket s, boolean on) throws SocketException;
+ public static void socketSetKeepAlive(Socket s, boolean on) throws SocketException { p._socketSetKeepAlive(s,on); }
+
+ abstract InetAddress _inetAddressFromBytes(byte[] a) throws UnknownHostException;
+ public static InetAddress inetAddressFromBytes(byte[] a) throws UnknownHostException { return p._inetAddressFromBytes(a); }
+
+ abstract String _timeZoneGetDisplayName(TimeZone tz, boolean dst, boolean showlong, Locale l);
+ public static String timeZoneGetDisplayName(TimeZone tz, boolean dst, boolean showlong, Locale l) { return p._timeZoneGetDisplayName(tz,dst,showlong,l); }
+ public static String timeZoneGetDisplayName(TimeZone tz, boolean dst, boolean showlong) { return timeZoneGetDisplayName(tz,dst,showlong,Locale.getDefault()); }
+
+ abstract void _setFileLength(RandomAccessFile f, int length)
+ throws IOException;
+ public static void setFileLength(RandomAccessFile f, int length)
+ throws IOException { p._setFileLength(f, length); }
+
+ abstract File[] _listRoots();
+ public static File[] listRoots() { return p._listRoots(); }
+
+ abstract File _getRoot(File f);
+ public static File getRoot(File f) { return p._getRoot(f); }
+
+ static class Jdk11 extends Platform {
+ boolean _atomicCreateFile(File f) throws IOException {
+ // This is not atomic, but its the best we can do on jdk 1.1
+ if(f.exists()) return false;
+ new FileOutputStream(f).close();
+ return true;
+ }
+ Seekable.Lock _lockFile(Seekable s, RandomAccessFile raf, long p, long size, boolean shared) throws IOException {
+ throw new IOException("file locking requires jdk 1.4+");
+ }
+ void _socketHalfClose(Socket s, boolean output) throws IOException {
+ throw new IOException("half closing sockets not supported");
+ }
+ InetAddress _inetAddressFromBytes(byte[] a) throws UnknownHostException {
+ if(a.length != 4) throw new UnknownHostException("only ipv4 addrs supported");
+ return InetAddress.getByName(""+(a[0]&0xff)+"."+(a[1]&0xff)+"."+(a[2]&0xff)+"."+(a[3]&0xff));
+ }
+ void _socketSetKeepAlive(Socket s, boolean on) throws SocketException {
+ if(on) throw new SocketException("keepalive not supported");
+ }
+ String _timeZoneGetDisplayName(TimeZone tz, boolean dst, boolean showlong, Locale l) {
+ String[][] zs = new DateFormatSymbols(l).getZoneStrings();
+ String id = tz.getID();
+ for(int i=0;i 0) sb.append(":").append(off/60); off=off%60;
+ if(off > 0) sb.append(":").append(off);
+ return sb.toString();
+ }
+
+ void _setFileLength(RandomAccessFile f, int length) throws IOException{
+ InputStream in = new FileInputStream(f.getFD());
+ OutputStream out = new FileOutputStream(f.getFD());
+
+ byte[] buf = new byte[1024];
+ for (int len; length > 0; length -= len) {
+ len = in.read(buf, 0, Math.min(length, buf.length));
+ if (len == -1) break;
+ out.write(buf, 0, len);
+ }
+ if (length == 0) return;
+
+ // fill the rest of the space with zeros
+ for (int i=0; i < buf.length; i++) buf[i] = 0;
+ while (length > 0) {
+ out.write(buf, 0, Math.min(length, buf.length));
+ length -= buf.length;
+ }
+ }
+
+ RandomAccessFile _truncatedRandomAccessFile(File f, String mode) throws IOException {
+ new FileOutputStream(f).close();
+ return new RandomAccessFile(f,mode);
+ }
+
+ File[] _listRoots() {
+ String[] rootProps = new String[]{"java.home","java.class.path","java.library.path","java.io.tmpdir","java.ext.dirs","user.home","user.dir" };
+ Hashtable known = new Hashtable();
+ for(int i=0;i " + root);
+ known.put(root,Boolean.TRUE);
+ if(p == -1) break;
+ }
+ }
+ File[] ret = new File[known.size()];
+ int i=0;
+ for(Enumeration e = known.keys();e.hasMoreElements();)
+ ret[i++] = (File) e.nextElement();
+ return ret;
+ }
+
+ File _getRoot(File f) {
+ if(!f.isAbsolute()) f = new File(f.getAbsolutePath());
+ String p;
+ while((p = f.getParent()) != null) f = new File(p);
+ if(f.getPath().length() == 0) f = new File("/"); // work around a classpath bug
+ return f;
+ }
+ }
+
+ static class Jdk12 extends Jdk11 {
+ boolean _atomicCreateFile(File f) throws IOException {
+ return f.createNewFile();
+ }
+
+ String _timeZoneGetDisplayName(TimeZone tz, boolean dst, boolean showlong, Locale l) {
+ return tz.getDisplayName(dst,showlong ? TimeZone.LONG : TimeZone.SHORT, l);
+ }
+
+ void _setFileLength(RandomAccessFile f, int length) throws IOException {
+ f.setLength(length);
+ }
+
+ File[] _listRoots() { return File.listRoots(); }
+ }
+
+ static class Jdk13 extends Jdk12 {
+ void _socketHalfClose(Socket s, boolean output) throws IOException {
+ if(output) s.shutdownOutput();
+ else s.shutdownInput();
+ }
+
+ void _socketSetKeepAlive(Socket s, boolean on) throws SocketException {
+ s.setKeepAlive(on);
+ }
+ }
+
+ static class Jdk14 extends Jdk13 {
+ InetAddress _inetAddressFromBytes(byte[] a) throws UnknownHostException { return InetAddress.getByAddress(a); }
+
+ Seekable.Lock _lockFile(Seekable s, RandomAccessFile r, long pos, long size, boolean shared) throws IOException {
+ FileLock flock;
+ try {
+ flock = pos == 0 && size == 0 ? r.getChannel().lock() :
+ r.getChannel().tryLock(pos, size, shared);
+ } catch (OverlappingFileLockException e) { flock = null; }
+ if (flock == null) return null; // region already locked
+ return new Jdk14FileLock(s, flock);
+ }
+ }
+
+ private static final class Jdk14FileLock extends Seekable.Lock {
+ private final Seekable s;
+ private final FileLock l;
+
+ Jdk14FileLock(Seekable sk, FileLock flock) { s = sk; l = flock; }
+ public Seekable seekable() { return s; }
+ public boolean isShared() { return l.isShared(); }
+ public boolean isValid() { return l.isValid(); }
+ public void release() throws IOException { l.release(); }
+ public long position() { return l.position(); }
+ public long size() { return l.size(); }
+ public String toString() { return l.toString(); }
+ }
+}
diff --git a/src/main/java/org/ibex/nestedvm/util/Seekable.java b/src/main/java/org/ibex/nestedvm/util/Seekable.java
new file mode 100644
index 0000000..485d364
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/util/Seekable.java
@@ -0,0 +1,182 @@
+// 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.
+
+package org.ibex.nestedvm.util;
+
+import java.io.*;
+
+public abstract class Seekable {
+ public abstract int read(byte[] buf, int offset, int length) throws IOException;
+ public abstract int write(byte[] buf, int offset, int length) throws IOException;
+ public abstract int length() throws IOException;
+ public abstract void seek(int pos) throws IOException;
+ public abstract void close() throws IOException;
+ public abstract int pos() throws IOException;
+
+ public void sync() throws IOException {
+ throw new IOException("sync not implemented for " + getClass());
+ }
+ public void resize(long length) throws IOException {
+ throw new IOException("resize not implemented for " + getClass());
+ }
+ /** If pos == 0 and size == 0 lock covers whole file. */
+ public Lock lock(long pos, long size, boolean shared) throws IOException {
+ throw new IOException("lock not implemented for " + getClass());
+ }
+
+ public int read() throws IOException {
+ byte[] buf = new byte[1];
+ int n = read(buf,0,1);
+ return n == -1 ? -1 : buf[0]&0xff;
+ }
+
+ public int tryReadFully(byte[] buf, int off, int len) throws IOException {
+ int total = 0;
+ while(len > 0) {
+ int n = read(buf,off,len);
+ if(n == -1) break;
+ off += n;
+ len -= n;
+ total += n;
+ }
+ return total == 0 ? -1 : total;
+ }
+
+ public static class ByteArray extends Seekable {
+ protected byte[] data;
+ protected int pos;
+ private final boolean writable;
+
+ public ByteArray(byte[] data, boolean writable) {
+ this.data = data;
+ this.pos = 0;
+ this.writable = writable;
+ }
+
+ public int read(byte[] buf, int off, int len) {
+ len = Math.min(len,data.length-pos);
+ if(len <= 0) return -1;
+ System.arraycopy(data,pos,buf,off,len);
+ pos += len;
+ return len;
+ }
+
+ public int write(byte[] buf, int off, int len) throws IOException {
+ if(!writable) throw new IOException("read-only data");
+ len = Math.min(len,data.length-pos);
+ if(len <= 0) throw new IOException("no space");
+ System.arraycopy(buf,off,data,pos,len);
+ pos += len;
+ return len;
+ }
+
+ public int length() { return data.length; }
+ public int pos() { return pos; }
+ public void seek(int pos) { this.pos = pos; }
+ public void close() { /*noop*/ }
+ }
+
+ public static class File extends Seekable {
+ private final java.io.File file;
+ private final RandomAccessFile raf;
+
+ public File(String fileName) throws IOException { this(fileName,false); }
+ public File(String fileName, boolean writable) throws IOException { this(new java.io.File(fileName),writable,false); }
+
+ public File(java.io.File file, boolean writable, boolean truncate) throws IOException {
+ this.file = file;
+ String mode = writable ? "rw" : "r";
+ raf = new RandomAccessFile(file,mode);
+ if (truncate) Platform.setFileLength(raf, 0);
+ }
+
+ public int read(byte[] buf, int offset, int length) throws IOException { return raf.read(buf,offset,length); }
+ public int write(byte[] buf, int offset, int length) throws IOException { raf.write(buf,offset,length); return length; }
+ public void sync() throws IOException { raf.getFD().sync(); }
+ public void seek(int pos) throws IOException{ raf.seek(pos); }
+ public int pos() throws IOException { return (int) raf.getFilePointer(); }
+ public int length() throws IOException { return (int)raf.length(); }
+ public void close() throws IOException { raf.close(); }
+ public void resize(long length) throws IOException { Platform.setFileLength(raf, (int)length); }
+ public boolean equals(Object o) {
+ return o != null && o instanceof File
+ && file.equals(((File)o).file);
+ }
+ public Lock lock(long pos, long size, boolean shared)
+ throws IOException {
+ return Platform.lockFile(this, raf, pos, size, shared);
+ }
+ }
+
+ public static class InputStream extends Seekable {
+ private byte[] buffer = new byte[4096];
+ private int bytesRead = 0;
+ private boolean eof = false;
+ private int pos;
+ private java.io.InputStream is;
+
+ public InputStream(java.io.InputStream is) { this.is = is; }
+
+ public int read(byte[] outbuf, int off, int len) throws IOException {
+ if(pos >= bytesRead && !eof) readTo(pos + 1);
+ len = Math.min(len,bytesRead-pos);
+ if(len <= 0) return -1;
+ System.arraycopy(buffer,pos,outbuf,off,len);
+ pos += len;
+ return len;
+ }
+
+ private void readTo(int target) throws IOException {
+ if(target >= buffer.length) {
+ byte[] buf2 = new byte[Math.max(buffer.length+Math.min(buffer.length,65536),target)];
+ System.arraycopy(buffer,0,buf2,0,bytesRead);
+ buffer = buf2;
+ }
+ while(bytesRead < target) {
+ int n = is.read(buffer,bytesRead,buffer.length-bytesRead);
+ if(n == -1) {
+ eof = true;
+ break;
+ }
+ bytesRead += n;
+ }
+ }
+
+ public int length() throws IOException {
+ while(!eof) readTo(bytesRead+4096);
+ return bytesRead;
+ }
+
+ public int write(byte[] buf, int off, int len) throws IOException { throw new IOException("read-only"); }
+ public void seek(int pos) { this.pos = pos; }
+ public int pos() { return pos; }
+ public void close() throws IOException { is.close(); }
+ }
+
+ public abstract static class Lock {
+ private Object owner = null;
+
+ public abstract Seekable seekable();
+ public abstract boolean isShared();
+ public abstract boolean isValid();
+ public abstract void release() throws IOException;
+ public abstract long position();
+ public abstract long size();
+
+ public void setOwner(Object o) { owner = o; }
+ public Object getOwner() { return owner; }
+
+ public final boolean contains(int start, int len) {
+ return start >= position() && position() + size() >= start + len;
+ }
+
+ public final boolean contained(int start, int len) {
+ return start < position() && position() + size() < start + len;
+ }
+
+ public final boolean overlaps(int start, int len) {
+ return contains(start, len) || contained(start, len);
+ }
+ }
+}
diff --git a/src/main/java/org/ibex/nestedvm/util/Sort.java b/src/main/java/org/ibex/nestedvm/util/Sort.java
new file mode 100644
index 0000000..79fe029
--- /dev/null
+++ b/src/main/java/org/ibex/nestedvm/util/Sort.java
@@ -0,0 +1,47 @@
+package org.ibex.nestedvm.util;
+
+public final class Sort {
+ private Sort() { }
+
+ public interface Comparable { public int compareTo(Object o); }
+ public interface CompareFunc { public int compare(Object a, Object b); }
+
+ private static final CompareFunc comparableCompareFunc = new CompareFunc() {
+ public int compare(Object a,Object b) { return ((Comparable)a).compareTo(b); }
+ };
+
+ public static void sort(Comparable[] a) { sort(a,comparableCompareFunc); }
+ public static void sort(Object[] a, CompareFunc c) { sort(a,c,0,a.length-1); }
+
+ private static void sort(Object[] a, CompareFunc c, int start, int end) {
+ Object tmp;
+ if(start >= end) return;
+ if(end-start <= 6) {
+ for(int i=start+1;i<=end;i++) {
+ tmp = a[i];
+ int j;
+ for(j=i-1;j>=start;j--) {
+ if(c.compare(a[j],tmp) <= 0) break;
+ a[j+1] = a[j];
+ }
+ a[j+1] = tmp;
+ }
+ return;
+ }
+
+ Object pivot = a[end];
+ int lo = start - 1;
+ int hi = end;
+
+ do {
+ while((lo < hi) && c.compare(a[++lo],pivot) < 0) { }
+ while((hi > lo) && c.compare(a[--hi],pivot) > 0) { }
+ tmp = a[lo]; a[lo] = a[hi]; a[hi] = tmp;
+ } while(lo < hi);
+
+ tmp = a[lo]; a[lo] = a[end]; a[end] = tmp;
+
+ sort(a, c, start, lo-1);
+ sort(a, c, lo+1, end);
+ }
+}