X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2Fmips%2FRuntime.java;fp=src%2Forg%2Fxwt%2Fmips%2FVM.java;h=89918a76ca5a811345251a780fe163dfbe1102f7;hb=0b0673bbc7f06c5d5418d5ab7ad5961a464e2de0;hp=b0bbf7b0dc2787c66d19ae65745e6f64e58fe590;hpb=7f5df8070a5551fe66abd11a589677e285ca62f8;p=org.ibex.core.git diff --git a/src/org/xwt/mips/VM.java b/src/org/xwt/mips/Runtime.java similarity index 51% rename from src/org/xwt/mips/VM.java rename to src/org/xwt/mips/Runtime.java index b0bbf7b..89918a7 100644 --- a/src/org/xwt/mips/VM.java +++ b/src/org/xwt/mips/Runtime.java @@ -1,119 +1,171 @@ +// Copyright 2003 Brian Alliet +// Based on org.xwt.imp.MIPS by Adam Megacz +// Portions Copyright 2003 Adam Megacz package org.xwt.mips; import java.io.*; -public abstract class VM implements Syscalls, Errno { - // Register Names - protected final static int ZERO = 0; // Immutable, hardwired to 0 - protected final static int AT = 1; // Reserved for assembler - protected final static int K0 = 26; // Reserved for kernel - protected final static int K1 = 27; // Reserved for kernel - protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss) - protected final static int SP = 29; // Stack pointer - protected final static int FP = 30; // Frame Pointer - protected final static int RA = 31; // Return Address - - // Return values (caller saved) - protected final static int V0 = 2; - protected final static int V1 = 3; - // Argument Registers (caller saved) - protected final static int A0 = 4; - protected final static int A1 = 5; - protected final static int A2 = 6; - protected final static int A3 = 7; - // Temporaries (caller saved) - protected final static int T0 = 8; - protected final static int T1 = 9; - protected final static int T2 = 10; - protected final static int T3 = 11; - protected final static int T4 = 12; - protected final static int T5 = 13; - protected final static int T6 = 14; - protected final static int T7 = 15; - protected final static int T8 = 24; - protected final static int T9 = 25; - // Saved (callee saved) - protected final static int S0 = 16; - protected final static int S1 = 17; - protected final static int S2 = 18; - protected final static int S3 = 19; - protected final static int S4 = 20; - protected final static int S5 = 21; - protected final static int S6 = 22; - protected final static int S7 = 23; - - // Page Constants - // Page Size: 4k - // Total Pages: 64k - // Maxiumum Addressable memory 256mb - // 1mb of stack space - protected final static int PAGE_SIZE = 4096; - protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2); - protected final static int PAGE_SHIFT = 12; - protected final static int STACK_PAGES = 256; - // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the - // new location of INITIAL_SP +public abstract class Runtime implements Syscalls, Errno,Registers { + /** Pages are 4k in size */ + final static int PAGE_SIZE = 4096; + final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2); + final static int PAGE_SHIFT = 12; + /** There are 65536 pages available for a total of 256mb of addressable memory */ protected final static int TOTAL_PAGES = 65536; - protected final static int BRK_LIMIT = 32768; - // Top page is always empty - // next page down contains command line arguments - protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE; - // next page down contains _user_info data - protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE; - // next page down is the start of the stack - protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE; - // magic page that signified an allocated but empty (untouched) page - private final static int[] emptyPage = new int[0]; - - // Main memory + /** The top 256 pages are reserved for the stack. Arguments and userdata info use up the first few pages */ + protected final static int STACK_PAGES = 256; + /** This is the upper limit of the pages allocated by the brk() syscall. */ + protected final static int BRK_LIMIT = TOTAL_PAGES - STACK_PAGES - 1024; + + /* High memory layout + TOP + <-- ((TOTAL_PAGES-0)*PAGE_SIZE) --> + Empty Page + <-- ((TOTAL_PAGES-1)*PAGE_SIZE) --> + Args (1 page) + <-- ((TOTAL_PAGES-2)*PAGE_SIZE) --> + User info (1 page) + <-- ((TOTAL_PAGES-3)*PAGE_SIZE) --> + Empty page + <-- ((TOTAL_PAGES-4)*PAGE_SIZE) --> + Stack top + */ + + /** The base address for the args and user_info (this will be passed to crt0.c) + The args must be at STUFF_BASE+1 page and user_info must be at STUFF_BASE */ + protected final static int STUFF_BASE = (TOTAL_PAGES-3)*PAGE_SIZE; + protected final static int ARGS_ADDR = STUFF_BASE + PAGE_SIZE; + protected final static int USER_INFO_ADDR = STUFF_BASE; + + /** The initial stack pointer address */ + protected final static int INITIAL_SP = STUFF_BASE - PAGE_SIZE; + + /** True if we allow empty pages (_emptyPage) to exist in memory. + Empty pages are pages which are allocated by the program but do not contain any + data yet (they are all 0s). If empty pages are allowed subclasses must always + access main memory with the memRead and memWrite functions */ + private final boolean allowEmptyPages; + /** the "empty page" */ + private final static int[] _emptyPage = new int[0]; + + /** Returns a new empty page (_emptyPage is empty pages are enabled or a new zero'd page) */ + private final int[] emptyPage() { return allowEmptyPages ? _emptyPage : new int[PAGE_WORDS]; } + + /** Readable main memory pages */ protected final int[][] readPages; + /** Writable main memory pages. + If the page is writable writePages[x] == readPages[x]; if not writePages[x] == null. */ protected final int[][] writePages; - // Brk - protected int brk; // PAGE not address + /** The current break between the heap and unallocated memory and the stack. + This is the page number NOT an address */ + protected int brk; - // Entry point - what start() sets pc to + /** The program's entry point */ protected int entryPoint; - // State constants - public final static int UNINITIALIZED = 0; + /** State contant: There is no program loaded in memory */ + public final static int UNINITIALIZED = 0; + /** Text/Data loaded in memory */ public final static int INITIALIZED = 1; + /** Program is executing instructions */ public final static int RUNNING = 2; + /** Prgram has been started but is paused */ public final static int PAUSED = 3; + /** Program has exited (it cannot currently be restarted) */ public final static int DONE = 4; - // State + /** The current state (UNINITIALIZED, INITIALIZED, RUNNING, PAUSED, or DONE) */ protected int state = UNINITIALIZED; + /** @see Runtime#state state */ public final int getState() { return state; } + + /** The exit status if the process (only valid if state==DONE) + @see Runtime#state */ protected int exitStatus; - // File descriptors + /** Maximum number of open file descriptors */ private final static int OPEN_MAX = 256; + /** Table containing all open file descriptors. (Entries are null if the fd is not in use */ private FileDescriptor[] fds; - // Temporary buffer for read/write operations + /** Temporary buffer for read/write operations */ private byte[] _byteBuf = null; - private final static int MAX_CHUNK = 4*1024*1024-8; + /** Max size of temporary buffer + @see Runtime#_byteBuf */ + private final static int MAX_CHUNK = 4*1024*1024; - // Abstract methods - // This should start executing at pc - public abstract void execute() throws EmulationException; - // This should initialize the cpu registers to point to the entry point - protected abstract void _start(int pc); - + /** The pid of this "process" */ public static final int PID = 1; + + /** Subclasses should actually execute program in this method. They should continue + executing until state != RUNNING. Only syscall() can modify state. It is safe + to only check the state attribyte after a call to syscall() */ + protected abstract void _execute() throws ExecutionException; + + /** This should setup the system to begin executing at pc and + initialize the cpu registers as follows + K0 (r26) = STUFF_BASE + K1 (r27) = PAGE_SIZE + SP (r29) = INITIAL_SP + RA (r31) = 0xdeadbeef + */ + protected abstract void _start(int pc); - public VM() { + /** Initialize the Runtime with empty pages disabled + @see Runtime#Runtime(boolean) */ + public Runtime() { this(false); } + + /** Initialize the Runtime. Empty pages are enabled if allowEmptyPages is set */ + public Runtime(boolean allowEmptyPages) { + this.allowEmptyPages = allowEmptyPages; readPages = new int[TOTAL_PAGES][]; writePages = new int[TOTAL_PAGES][]; for(int i=0;isrc 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) { + for(int i=0;i>> PAGE_SHIFT; + int start = (addr&(PAGE_SIZE-1))>>2; + int elements = min(PAGE_WORDS-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; + } } - public void copyin(int addr, byte[] a, int length) throws ReadFaultException { + /** Initialize words of pages starting at addr to 0 */ + protected final void clearPages(int addr, int words) { + for(int i=0;i>> PAGE_SHIFT; + int start = (addr&(PAGE_SIZE-1))>>2; + int elements = min(PAGE_WORDS-start,words-i); + if(readPages[page]==null) { + readPages[page] = writePages[page] = emptyPage(); + } 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[] a, int length) throws ReadFaultException { int n=0; if((addr&3)!=0) { int word = memRead(addr&~3); - switch(addr&3) { + switch(addr&3) { case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break; case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break; case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break; @@ -125,7 +177,7 @@ public abstract class VM implements Syscalls, Errno { int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); int[] page = readPages[addr >>> PAGE_SHIFT]; if(page == null) throw new ReadFaultException(addr); - if(page == emptyPage) { addr+=(end-start)<<2; n+=(end-start)<<2; continue; } + if(page == _emptyPage) { addr+=(end-start)<<2; n+=(end-start)<<2; continue; } for(int i=start;i>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff); @@ -134,17 +186,19 @@ public abstract class VM implements Syscalls, Errno { } if(length-n > 0) { int word = memRead(addr); - if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff); + if(length-n >= 1) a[n+0] = (byte)((word>>>24)&0xff); if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff); if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff); } } - public void copyout(byte[] a, int addr, int length) throws FaultException { + /** Copies length bytes OUT OF the java array a into the processes memory + space at addr */ + public final void copyout(byte[] a, int addr, int length) throws FaultException { int n=0; if((addr&3)!=0) { int word = memRead(addr&~3); - switch(addr&3) { + switch(addr&3) { case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break; case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break; case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break; @@ -158,7 +212,7 @@ public abstract class VM implements Syscalls, Errno { int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2); int[] page = writePages[addr >>> PAGE_SHIFT]; if(page == null) throw new WriteFaultException(addr); - if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; } + if(page == _emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; } for(int i=start;i 0) { int word = memRead(addr); - word = (word&0x00ffffff)|((a[n]&0xff)<<24); - if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); } - if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); } + if(length-n >= 1) { word = (word&0x00ffffff)|((a[n+0]&0xff)<<24); } + if(length-n >= 2) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); } + if(length-n >= 3) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); } memWrite(addr,word); } } + /** Read a word from the processes memory at addr */ public final int memRead(int addr) throws ReadFaultException { if((addr & 3) != 0) throw new ReadFaultException(addr); int page = addr >>> PAGE_SHIFT; @@ -182,7 +237,7 @@ public abstract class VM implements Syscalls, Errno { } catch(ArrayIndexOutOfBoundsException e) { if(page < 0) throw e; // should never happen if(page > readPages.length) throw new ReadFaultException(addr); - if(readPages[page] != emptyPage) throw e; // should never happen + if(readPages[page] != _emptyPage) throw e; // should never happen initPage(page); return 0; } catch(NullPointerException e) { @@ -190,7 +245,8 @@ public abstract class VM implements Syscalls, Errno { } } - protected final void memWrite(int addr, int value) throws WriteFaultException { + /** 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); int page = addr >>> PAGE_SHIFT; int entry = (addr>>>2)&(PAGE_WORDS-1); @@ -199,7 +255,7 @@ public abstract class VM implements Syscalls, Errno { } catch(ArrayIndexOutOfBoundsException e) { if(page < 0) throw e;// should never happen if(page > writePages.length) throw new WriteFaultException(addr); - if(readPages[page] != emptyPage) throw e; // should never happen + if(readPages[page] != _emptyPage) throw e; // should never happen initPage(page); writePages[page][entry] = value; } catch(NullPointerException e) { @@ -207,45 +263,52 @@ public abstract class VM implements Syscalls, Errno { } } - protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; } + /** Created a new non-empty writable page at page number page */ + private final void initPage(int page) { 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 void initPage(int page, boolean ro) { + int[] buf = new int[PAGE_WORDS]; + writePages[page] = ro ? null : buf; + readPages[page] = buf; + } + /** Returns the exit status of the process. (only valid if state == DONE) + @see Runtime#state */ public final int exitStatus() { if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state"); return exitStatus; } - - public final int run(String[] args) throws EmulationException { + + /** 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) throws ExecutionException { start(args); for(;;) { - execute(); - if(state != PAUSED) break; + if(execute()) break; System.err.println("WARNING: Pause requested while executing run()"); try { Thread.sleep(500); } catch(InterruptedException e) { } } - if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state"); return exitStatus(); } - private void addArgs(String[] args) throws EmulationException { - if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state"); + /** Adds the String[] array, args, to the arguments page in main memory */ + private void addArgs(String[] args) throws ExecutionException { int count = args.length; byte[] nullTerminator = new byte[1]; int total = 4; /* null last table entry */ for(int i=0;i PAGE_SIZE) throw new EmulationException("Arguments too large"); + if(total >= PAGE_SIZE-4) throw new ExecutionException("Arguments too large"); int start = ARGS_ADDR; int addr = start + (count+1)*4; int[] table = new int[count+1]; for(int i=0;i= 1024) throw new EmulationException("setUserInfo called with index >= 1024"); - memWrite(USER_INFO_ADDR+index*4,word); + /** Sets word number index in the _user_info table to word + _user_info is a 4096 byte table in the process's memory. It contains 1024 32-bit entries. This + can be used by the process to communicate with the caller of the process. Each entry is 32-bit + wide and can be used to store integers or pointers */ + public void setUserInfo(int index, int word) { + if(index < 0 || index >= 1024) throw new IllegalStateException("setUserInfo called with index >= 1024"); + try { + memWrite(USER_INFO_ADDR+index*4,word); + } catch(FaultException e) { throw new Error("should never happen: " + e); } + } + + /** 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 >= 1024) throw new IllegalStateException("setUserInfo called with index >= 1024"); + try { + return memRead(USER_INFO_ADDR+index*4); + } catch(FaultException e) { throw new Error("should never happen: " + e); } } - public int getUserInfo(int index) throws EmulationException { - if(index < 0 || index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024"); - return memRead(USER_INFO_ADDR+index*4); + /** Executes the process until the PAUSE syscall is invoked or the process exits. Returns true if the process exited. */ + public final boolean execute() throws ExecutionException { + if(state == PAUSED) state = RUNNING; + if(state != RUNNING) throw new IllegalStateException("execute() called in inappropriate state"); + _execute(); + if(state != PAUSED && state != DONE) throw new IllegalStateException("execute() ended up in an inappropriate state"); + return state == DONE; } - public final void start(String[] args) throws EmulationException { - if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state"); + /** Initializes the process and prepairs it to be executed with execute() */ + public final void start(String[] args) throws ExecutionException { + if(state != INITIALIZED) throw new IllegalStateException("start() called in inappropriate state"); _start(entryPoint); addArgs(args); fds = new FileDescriptor[OPEN_MAX]; @@ -275,9 +358,69 @@ public abstract class VM implements Syscalls, Errno { state = PAUSED; } + /** Determines if the process can access fileName. The default implementation simply logs + the request and allows it */ + protected boolean allowFileAccess(String fileName, boolean write) { + System.err.println("Allowing " + (write?"write":"read-only") + " to " + fileName); + return true; + } + + /** 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 */ + protected int allocFDEnt(FileDescriptor fd) { + int i; + for(i=0;i= Integer.MAX_VALUE) return -EOPNOTSUPP; + } else { + if((flags & O_CREAT) == 0) return -ENOENT; + } + int fdn = allocFDEnt(new RegularFileDescriptor(f,flags&3)); + return fdn == -1 ? -ENFILE : fdn; + } catch(FaultException e) { + return -EFAULT; + } catch(FileNotFoundException e) { + if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES; + return -ENOENT; + } catch(IOException e) { + return -EIO; + } + } + + /** The write syscall */ + private int sys_write(int fdn, int addr, int count) { int n = 0; int r; FileDescriptor fd; @@ -301,7 +444,8 @@ public abstract class VM implements Syscalls, Errno { } } - private int read(int fdn, int addr, int count) { + /** The read syscall */ + private int sys_read(int fdn, int addr, int count) { FileDescriptor fd; count = Math.min(count,MAX_CHUNK); try { @@ -324,7 +468,8 @@ public abstract class VM implements Syscalls, Errno { } } - private int close(int fdn) { + /** The close syscall */ + private int sys_close(int fdn) { FileDescriptor fd; try { fd = fds[fdn]; @@ -337,19 +482,38 @@ public abstract class VM implements Syscalls, Errno { return 0; } + /** The seek syscall */ + private int sys_seek(int fdn, int offset, int whence) { + FileDescriptor fd; + try { + fd = fds[fdn]; + if(fd == null || !fd.readable()) return -EBADFD; + } catch(ArrayIndexOutOfBoundsException e) { + return -EBADFD; + } + if(whence != FileDescriptor.SEEK_SET && whence != FileDescriptor.SEEK_CUR && whence != FileDescriptor.SEEK_END) return -EINVAL; + try { + int n = fd.seek(offset,whence); + return n < 0 ? -ESPIPE : n; + } catch(IOException e) { + return -ESPIPE; + } + } + + /** The stat/fstat syscall helper */ private int stat(FileInfo fi, int addr) { int size = fi.size(); try { - memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16) + memWrite(addr+0,(1<<16)|1); // st_dev (top 16), // st_ino (bottom 16) memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode - memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16) + memWrite(addr+8,1<<16); // st_nlink (top 16) // st_uid (bottom 16) memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16) memWrite(addr+16,size); // st_size memWrite(addr+20,0); // st_atime // memWrite(addr+24,0) // st_spare1 memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime // memWrite(addr+32,0) // st_spare2 - memWrite(addr+36,0); // st_atime + memWrite(addr+36,0); // st_ctime // memWrite(addr+40,0) // st_spare3 memWrite(addr+44,512); // st_bklsize; memWrite(addr+48,(size+511)&(~511)); // st_blocks @@ -362,7 +526,8 @@ public abstract class VM implements Syscalls, Errno { return 0; } - private int fstat(int fdn, int addr) { + /** The fstat syscall */ + private int sys_fstat(int fdn, int addr) { FileDescriptor fd; try { fd = fds[fdn]; @@ -373,6 +538,8 @@ public abstract class VM implements Syscalls, Errno { return stat(fd.fileInfo(),addr); } + /** The sbrk syscall. This can also be used by subclasses to allocate memory. + incr is how much to increase the break by */ public int sbrk(int incr) { if(incr==0) return brk<= Integer.MAX_VALUE) return -EOPNOTSUPP; - } else { - if((flags & O_CREAT) == 0) return -ENOENT; - } - for(int i=0;i= 0) return -EACCES; - return -ENOENT; - } catch(IOException e) { - return -EIO; - } - } - - private int seek(int fdn, int offset, int whence) { - FileDescriptor fd; - try { - fd = fds[fdn]; - if(fd == null || !fd.readable()) return -EBADFD; - } catch(ArrayIndexOutOfBoundsException e) { - return -EBADFD; - } - try { - return fd.seek(offset,whence); - } catch(IOException e) { - System.err.println(e); - return -EPIPE; - } - } - - // This will only be called by raise() to invoke the default handler - // We don't have to worry about actually delivering the signal - private int kill(int pid, int signal) { + /** The kill syscall. + SIGSTOP, SIGTSTO, SIGTTIN, and SIGTTOUT pause the process. + SIGCONT, SIGCHLD, SIGIO, and SIGWINCH are ignored. + Anything else terminates the process. */ + private int sys_kill(int pid, int signal) { + // This will only be called by raise() in newlib to invoke the default handler + // We don't have to worry about actually delivering the signal if(pid != PID) return -ESRCH; if(signal < 0 || signal >= 32) return -EINVAL; switch(signal) { @@ -471,39 +583,47 @@ public abstract class VM implements Syscalls, Errno { if(fds[2]==null) { System.out.print(msg); } else { - byte[] b = msg.getBytes(); try { + byte[] b = msg.getBytes("US-ASCII"); fds[2].write(b,0,b.length); - } catch(IOException e) { } + } + catch(UnsupportedEncodingException e){ throw new Error(e.getMessage()); } + catch(IOException e) { } } } } return 0; } - private int getpid() { return PID; } + /** The getpid syscall */ + private int sys_getpid() { return PID; } + /** 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 int syscall(int syscall, int a, int b, int c, int d) { switch(syscall) { case SYS_null: return 0; case SYS_exit: exitStatus = a; state = DONE; return 0; case SYS_pause: state = PAUSED; return 0; - case SYS_write: return write(a,b,c); - case SYS_fstat: return fstat(a,b); + 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 open(a,b,c); - case SYS_close: return close(a); - case SYS_read: return read(a,b,c); - case SYS_seek: return seek(a,b,c); - case SYS_kill: return kill(a,b); - case SYS_getpid: return getpid(); + 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_seek: return sys_seek(a,b,c); + case SYS_kill: return sys_kill(a,b); + case SYS_getpid: return sys_getpid(); default: System.err.println("Attempted to use unknown syscall: " + syscall); return -ENOSYS; } } - // Helper function to read a cstring from main memory + /** Helper function to read a cstring from main memory */ public String cstring(int addr) throws ReadFaultException { StringBuffer sb = new StringBuffer(); for(;;) { @@ -516,26 +636,9 @@ public abstract class VM implements Syscalls, Errno { } } } - - // Exceptions - public static class ReadFaultException extends FaultException { - public ReadFaultException(int addr) { super(addr); } - } - public static class WriteFaultException extends FaultException { - public WriteFaultException(int addr) { super(addr); } - } - public static abstract class FaultException extends EmulationException { - private int addr; - public FaultException(int addr) { this.addr = addr; } - public String getMessage() { return "fault at: " + toHex(addr); } - } - public static class EmulationException extends Exception { - public EmulationException() { } - public EmulationException(String s) { super(s); } - } - // FileInfo classes - used by stat(2) - static class FileInfo { + /** FileInfo class - used by stat */ + public static class FileInfo { public static final int S_IFIFO = 0010000; public static final int S_FCHR = 0020000; public static final int S_IFDIR = 0040000; @@ -545,7 +648,8 @@ public abstract class VM implements Syscalls, Errno { public int type() { return S_IFIFO; } public long modTime() { return 0; } } - + + /** FileInfo subclass for normal files */ public static class FileFileInfo extends FileInfo { public File f; public FileFileInfo(File f) { this.f = f; } @@ -554,27 +658,42 @@ public abstract class VM implements Syscalls, Errno { public long modTime() { return f.lastModified(); } } - // File descriptor classes + /** File Descriptor class */ public static abstract class FileDescriptor { + protected final static int SEEK_SET = 0; + protected final static int SEEK_CUR = 1; + protected final static int SEEK_END = 2; + + /** returns true if the fd is readable */ public boolean readable() { return false; } + /** returns true if the fd is writable */ public boolean writable() { return false; } private static final FileInfo nullFi = new FileInfo(); private FileInfo fi; public FileInfo fileInfo() { return fi; } + /** Initializes the FileDescriptor with no FileInfo struct */ FileDescriptor() { this(null); } + /** Initializes the FileDescriptor with the given FileInfo struct (used by fstat) */ FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; } + /** 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 IOException { throw new IOException("no definition"); } + /** Write. Should return the number of bytes written or throw an IOException on error */ public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); } + + /** 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 IOException { return -1; } - public int seek(int n, int whence) throws IOException { return -ESPIPE; } + /** Should return true if this is a tty */ public boolean isatty() { return false; } + /** Closes the fd */ void close() { } } + /** FileDescriptor class for normal files */ public static class RegularFileDescriptor extends FileDescriptor { private int mode; private RandomAccessFile raf; @@ -589,19 +708,16 @@ public abstract class VM implements Syscalls, Errno { if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large"); } - public int seek(int n, int whence) throws IOException { - final int SEEK_SET = 0; - final int SEEK_CUR = 1; - final int SEEK_END = 2; - + public int seek(int n_, int whence) throws IOException { + long n = n_; switch(whence) { case SEEK_SET: break; - case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break; - case SEEK_END: n = (int)(raf.length()+n); break; - default: return -EINVAL; + case SEEK_CUR: n += raf.getFilePointer(); break; + case SEEK_END: n += raf.length(); break; + default: return -1; } raf.seek(n); - return n; + return (int)n; } public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; } @@ -623,154 +739,33 @@ public abstract class VM implements Syscalls, Errno { public InputStreamFD(InputStream is) { this.is = is; } public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; } } + + // Exceptions + public static class ReadFaultException extends FaultException { + public ReadFaultException(int addr) { super(addr); } + } + public static class WriteFaultException extends FaultException { + public WriteFaultException(int addr) { super(addr); } + } + public static abstract class FaultException extends ExecutionException { + private int addr; + public FaultException(int addr) { this.addr = addr; } + public String getMessage() { return "fault at: " + toHex(addr); } + } + public static class ExecutionException extends Exception { + public ExecutionException() { } + public ExecutionException(String s) { super(s); } + } // Utility functions private byte[] byteBuf(int size) { if(_byteBuf==null) _byteBuf = new byte[size]; else if(_byteBuf.length < size) - _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)]; + _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK)]; return _byteBuf; } + protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } protected final static int min(int a, int b) { return a < b ? a : b; } protected final static int max(int a, int b) { return a > b ? a : b; } } - - - -interface Errno { - public static final int EPERM = 1; - public static final int ENOENT = 2; - public static final int ESRCH = 3; - public static final int EINTR = 4; - public static final int EIO = 5; - public static final int ENXIO = 6; - public static final int ENOEXEC = 8; - public static final int EBADF = 9; - public static final int ECHILD = 10; - public static final int EAGAIN = 11; - public static final int ENOMEM = 12; - public static final int EACCES = 13; - public static final int EFAULT = 14; - public static final int ENOTBLK = 15; - public static final int EBUSY = 16; - public static final int EEXIST = 17; - public static final int EXDEV = 18; - public static final int ENODEV = 19; - public static final int ENOTDIR = 20; - public static final int EISDIR = 21; - public static final int EINVAL = 22; - public static final int ENFILE = 23; - public static final int EMFILE = 24; - public static final int ENOTTY = 25; - public static final int ETXTBSY = 26; - public static final int EFBIG = 27; - public static final int ENOSPC = 28; - public static final int ESPIPE = 29; - public static final int EROFS = 30; - public static final int EMLINK = 31; - public static final int EPIPE = 32; - public static final int EDOM = 33; - public static final int ERANGE = 34; - public static final int ENOMSG = 35; - public static final int EIDRM = 36; - public static final int ECHRNG = 37; - public static final int ELNRNG = 41; - public static final int EUNATCH = 42; - public static final int ENOCSI = 43; - public static final int EDEADLK = 45; - public static final int ENOLCK = 46; - public static final int EBADE = 50; - public static final int EBADR = 51; - public static final int EXFULL = 52; - public static final int ENOANO = 53; - public static final int EBADRQC = 54; - public static final int EBADSLT = 55; - public static final int EDEADLOCK = 56; - public static final int EBFONT = 57; - public static final int ENOSTR = 60; - public static final int ENODATA = 61; - public static final int ETIME = 62; - public static final int ENOSR = 63; - public static final int ENONET = 64; - public static final int ENOPKG = 65; - public static final int EREMOTE = 66; - public static final int ENOLINK = 67; - public static final int EADV = 68; - public static final int ESRMNT = 69; - public static final int ECOMM = 70; - public static final int EPROTO = 71; - public static final int EMULTIHOP = 74; - public static final int ELBIN = 75; - public static final int EDOTDOT = 76; - public static final int EBADMSG = 77; - public static final int EFTYPE = 79; - public static final int ENOTUNIQ = 80; - public static final int EBADFD = 81; - public static final int EREMCHG = 82; - public static final int ELIBACC = 83; - public static final int ELIBBAD = 84; - public static final int ELIBSCN = 85; - public static final int ELIBMAX = 86; - public static final int ELIBEXEC = 87; - public static final int ENOSYS = 88; - public static final int ENMFILE = 89; - public static final int ENOTEMPTY = 90; - public static final int ENAMETOOLONG = 91; - public static final int ELOOP = 92; - public static final int EOPNOTSUPP = 95; - public static final int EPFNOSUPPORT = 96; - public static final int ECONNRESET = 104; - public static final int ENOBUFS = 105; - public static final int EAFNOSUPPORT = 106; - public static final int EPROTOTYPE = 107; - public static final int ENOTSOCK = 108; - public static final int ENOPROTOOPT = 109; - public static final int ESHUTDOWN = 110; - public static final int ECONNREFUSED = 111; - public static final int EADDRINUSE = 112; - public static final int ECONNABORTED = 113; - public static final int ENETUNREACH = 114; - public static final int ENETDOWN = 115; - public static final int ETIMEDOUT = 116; - public static final int EHOSTDOWN = 117; - public static final int EHOSTUNREACH = 118; - public static final int EINPROGRESS = 119; - public static final int EALREADY = 120; - public static final int EDESTADDRREQ = 121; - public static final int EMSGSIZE = 122; - public static final int EPROTONOSUPPORT = 123; - public static final int ESOCKTNOSUPPORT = 124; - public static final int EADDRNOTAVAIL = 125; - public static final int ENETRESET = 126; - public static final int EISCONN = 127; - public static final int ENOTCONN = 128; - 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; - public static final int ENOMEDIUM = 135; - public static final int ENOSHARE = 136; - public static final int ECASECLASH = 137; - public static final int EILSEQ = 138; - public static final int EOVERFLOW = 139; - public static final int __ELASTERROR = 2000; -} - -interface Syscalls { - 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_isatty = 9; - public static final int SYS_seek = 10; - public static final int SYS_kill = 11; - public static final int SYS_getpid = 12; -}