support fsync()
[nestedvm.git] / src / org / ibex / nestedvm / Runtime.java
index f286620..201fde9 100644 (file)
@@ -98,7 +98,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
     
     /** Subclasses should return the address of the symbol <i>symbol</i> or -1 it it doesn't exits in this method 
         This method is only required if the call() function is used */
-    protected int lookupSymbol(String symbol) { return -1; }
+    public int lookupSymbol(String symbol) { return -1; }
     
     /** Subclasses should populate a CPUState object representing the cpu state */
     protected abstract void getCPUState(CPUState state);
@@ -556,7 +556,6 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
     public final void start(String[] args, String[] environ)  {
         int top, sp, argsAddr, envAddr;
         if(state != STOPPED) throw new IllegalStateException("start() called in inappropriate state");
-
         if(args == null) args = new String[]{getClass().getName()};
         
         sp = top = writePages.length*(1<<pageShift);
@@ -591,7 +590,12 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
         
         _started();        
     }
-    
+
+    public final void stop() {
+        if (state != RUNNING && state != PAUSED) throw new IllegalStateException("stop() called in inappropriate state");
+        exit(0, false);
+    }
+
     /** Hook for subclasses to do their own startup */
     void _started() {  }
     
@@ -694,11 +698,17 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
         return i;
     }
 
+    /** Hook for subclasses to do something when the process closes an FD */
+    void _closedFD(FD fd) {  }
+
     /** Closes file descriptor <i>fdn</i> 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;
+
+        _closedFD(fds[fdn]);
+
         fds[fdn].close();
         fds[fdn] = null;        
         return true;
@@ -1007,7 +1017,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
         return 0;
     }
        
-    private int sys_fcntl(int fdn, int cmd, int arg) {
+    final int sys_fcntl(int fdn, int cmd, int arg) throws FaultException {
         int i;
             
         if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD;
@@ -1028,12 +1038,32 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
                 return 0;
             case F_GETFD:
                 return closeOnExec[fdn] ? 1 : 0;
+            case F_GETLK:
+            case F_SETLK:
+                if(STDERR_DIAG) System.err.println("WARNING: file locking requires UnixRuntime");
+                return -ENOSYS;
             default:
                 if(STDERR_DIAG) System.err.println("WARNING: Unknown fcntl command: " + cmd);
                 return -ENOSYS;
         }
     }
-          
+
+    final int fsync(int fdn) {
+        if(fdn < 0 || fdn >= 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.
         <i>syscall</i> should be the contents of V0 and <i>a</i>, <i>b</i>, <i>c</i>, and <i>d</i> should be 
@@ -1083,6 +1113,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
             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;
 
@@ -1131,9 +1162,38 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
         }
         return addr;
     }
-    
+
+    // TODO: less memory copying (custom utf-8 reader)
+    //       or at least roll strlen() into copyin()
+    public final String utfstring(int addr) throws ReadFaultException {
+        if (addr == 0) return null;
+
+        // determine length
+        int i=addr;
+        for(int word = 1; word != 0; i++) {
+            word = memRead(i&~3);
+            switch(i&3) {
+                case 0: word = (word>>>24)&0xff; break;
+                case 1: word = (word>>>16)&0xff; break;
+                case 2: word = (word>>> 8)&0xff; break;
+                case 3: word = (word>>> 0)&0xff; break;
+            }
+        }
+        if (i > addr) i--; // do not count null
+
+        byte[] bytes = new byte[i-addr];
+        copyin(addr, bytes, bytes.length);
+
+        try {
+            return new String(bytes, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e); // should never happen with UTF-8
+        }
+    }
+
     /** Helper function to read a cstring from main memory */
     public final String cstring(int addr) throws ReadFaultException {
+        if (addr == 0) return null;
         StringBuffer sb = new StringBuffer();
         for(;;) {
             int word = memRead(addr&~3);
@@ -1470,7 +1530,7 @@ public abstract class Runtime implements UsermodeConstants,Registers,Cloneable {
     
     static byte[] getBytes(String s) {
         try {
-            return s.getBytes("ISO-8859-1");
+            return s.getBytes("UTF-8");
         } catch(UnsupportedEncodingException e) {
             return null; // should never happen
         }