2003/11/03 02:10:52
[org.ibex.core.git] / src / org / xwt / mips / VM.java
1 package org.xwt.mips;
2 import java.io.*;
3
4 public abstract class VM implements Syscalls, Errno {
5     // Register Names
6     protected final static int ZERO = 0; // Immutable, hardwired to 0
7     protected final static int AT = 1;  // Reserved for assembler
8     protected final static int K0 = 26; // Reserved for kernel 
9     protected final static int K1 = 27; // Reserved for kernel 
10     protected final static int GP = 28; // Global pointer (the middle of .sdata/.sbss)
11     protected final static int SP = 29; // Stack pointer
12     protected final static int FP = 30; // Frame Pointer
13     protected final static int RA = 31; // Return Address
14     
15     // Return values (caller saved)
16     protected final static int V0 = 2;
17     protected final static int V1 = 3;
18     // Argument Registers (caller saved)
19     protected final static int A0 = 4; 
20     protected final static int A1 = 5;
21     protected final static int A2 = 6;
22     protected final static int A3 = 7;
23     // Temporaries (caller saved)
24     protected final static int T0 = 8;
25     protected final static int T1 = 9;
26     protected final static int T2 = 10;
27     protected final static int T3 = 11;
28     protected final static int T4 = 12;
29     protected final static int T5 = 13;
30     protected final static int T6 = 14;
31     protected final static int T7 = 15;
32     protected final static int T8 = 24;
33     protected final static int T9 = 25;
34     // Saved (callee saved)
35     protected final static int S0 = 16;
36     protected final static int S1 = 17;
37     protected final static int S2 = 18;
38     protected final static int S3 = 19;
39     protected final static int S4 = 20;
40     protected final static int S5 = 21;
41     protected final static int S6 = 22;
42     protected final static int S7 = 23;
43
44     // Page Constants
45     // Page Size: 4k
46     // Total Pages: 64k
47     // Maxiumum Addressable memory 256mb
48     // 1mb of stack space
49     protected final static int PAGE_SIZE = 4096;
50     protected final static int PAGE_WORDS = (int)(PAGE_SIZE >>> 2);
51     protected final static int PAGE_SHIFT = 12;
52     protected final static int STACK_PAGES = 256;
53     // NOTE: If you change TOTAL_PAGES crt0.c needs to be updated to reflect the
54     // new location of INITIAL_SP
55     protected final static int TOTAL_PAGES = 65536;
56     protected final static int BRK_LIMIT = 32768;
57     // Top page is always empty
58     // next page down contains command line arguments
59     protected final static int ARGS_ADDR = (TOTAL_PAGES-2)*PAGE_SIZE;
60     // next page down contains _user_info data
61     protected final static int USER_INFO_ADDR = (TOTAL_PAGES-3)*PAGE_SIZE;
62     // next page down is the start of the stack
63     protected final static int INITIAL_SP = (TOTAL_PAGES-3)*PAGE_SIZE;
64     // magic page that signified an allocated but empty (untouched) page
65     private final static int[] emptyPage = new int[0];
66     
67     // Main memory
68     protected final int[][] readPages;
69     protected final int[][] writePages;
70     
71     // Brk
72     protected int brk; // PAGE not address
73         
74     // Entry point - what start() sets pc to
75     protected int entryPoint;
76     
77     // State constants
78     public final static int UNINITIALIZED = 0;
79     public final static int INITIALIZED = 1;
80     public final static int RUNNING = 2;
81     public final static int PAUSED = 3;
82     public final static int DONE = 4;
83     
84     // State
85     protected int state = UNINITIALIZED;
86     public final int getState() { return state; }
87     protected int exitStatus;
88     
89     // File descriptors
90     private final static int OPEN_MAX = 256;
91     private FileDescriptor[] fds;
92     
93     // Temporary buffer for read/write operations
94     private byte[] _byteBuf = null;
95     private final static int MAX_CHUNK = 4*1024*1024-8;
96     
97     // Abstract methods
98     // This should start executing at pc
99     public abstract void execute() throws EmulationException;
100     // This should initialize the cpu registers to point to the entry point
101     protected abstract void _start(int pc);
102    
103     public static final int PID = 1;
104     
105     public VM() {
106         readPages = new int[TOTAL_PAGES][];
107         writePages = new int[TOTAL_PAGES][];
108         for(int i=0;i<STACK_PAGES;i++)
109             readPages[TOTAL_PAGES-1-i] = writePages[TOTAL_PAGES-1-i] = emptyPage;
110     }
111     
112     public void copyin(int addr, byte[] a, int length) throws ReadFaultException {
113         int n=0;
114         if((addr&3)!=0) {
115             int word = memRead(addr&~3);
116              switch(addr&3) {
117                 case 1: a[n++] = (byte)((word>>>16)&0xff); if(length-n==0) break;
118                 case 2: a[n++] = (byte)((word>>> 8)&0xff); if(length-n==0) break;
119                 case 3: a[n++] = (byte)((word>>> 0)&0xff); if(length-n==0) break;
120             }
121             addr = (addr&~3)+4;
122         }
123         while(length-n > 3) {
124             int start = (addr&(PAGE_SIZE-1))>>2;
125             int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
126             int[] page = readPages[addr >>> PAGE_SHIFT];
127             if(page == null) throw new ReadFaultException(addr);
128             if(page == emptyPage) { addr+=(end-start)<<2; n+=(end-start)<<2; continue; }
129             for(int i=start;i<end;i++,addr+=4) {
130                 int word = page[i];
131                 a[n++] = (byte)((word>>>24)&0xff); a[n++] = (byte)((word>>>16)&0xff);
132                 a[n++] = (byte)((word>>> 8)&0xff); a[n++] = (byte)((word>>> 0)&0xff);
133             }
134         }
135         if(length-n > 0) {
136             int word = memRead(addr);
137             if(length-n >= 1) a[n] = (byte)((word>>>24)&0xff);
138             if(length-n >= 2) a[n+1] = (byte)((word>>>16)&0xff);
139             if(length-n >= 3) a[n+2] = (byte)((word>>> 8)&0xff);
140         }
141     }
142     
143     public void copyout(byte[] a, int addr, int length) throws FaultException {
144         int n=0;
145         if((addr&3)!=0) {
146             int word = memRead(addr&~3);
147              switch(addr&3) {
148                 case 1: word = (word&0xff00ffff)|((a[n]&0xff)<<16); n++; if(length-n==0) break;
149                 case 2: word = (word&0xffff00ff)|((a[n]&0xff)<< 8); n++; if(length-n==0) break;
150                 case 3: word = (word&0xffffff00)|((a[n]&0xff)<< 0); n++; if(length-n==0) break;
151             }
152             memWrite(addr&~3,word);
153             addr = (addr&~3)+4;
154         }
155         
156         while(length-n > 3) {
157             int start = (addr&(PAGE_SIZE-1))>>2;
158             int end = start + (min(PAGE_SIZE-(addr&(PAGE_SIZE-1)),(length-n)&~3) >> 2);
159             int[] page = writePages[addr >>> PAGE_SHIFT];
160             if(page == null) throw new WriteFaultException(addr);
161             if(page == emptyPage) { memWrite(addr,0); page = writePages[addr >>> PAGE_SHIFT]; }
162             for(int i=start;i<end;i++,addr+=4) {
163                 int word = ((a[n+0]&0xff)<<24)|((a[n+1]&0xff)<<16)|((a[n+2]&0xff)<<8)|((a[n+3]&0xff)<<0); n+=4;
164                 page[i] = word;
165             }
166         }
167         if(length-n > 0) {
168             int word = memRead(addr);
169             word = (word&0x00ffffff)|((a[n]&0xff)<<24);
170             if(length-n > 1) { word = (word&0xff00ffff)|((a[n+1]&0xff)<<16); }
171             if(length-n > 2) { word = (word&0xffff00ff)|((a[n+2]&0xff)<< 8); }
172             memWrite(addr,word);
173         }
174     }
175     
176     public final int memRead(int addr) throws ReadFaultException  {
177         if((addr & 3) != 0) throw new ReadFaultException(addr);
178         int page = addr >>> PAGE_SHIFT;
179         int entry = (addr >>> 2) & (PAGE_WORDS-1);
180         try {
181             return readPages[page][entry];
182         } catch(ArrayIndexOutOfBoundsException e) {
183             if(page < 0) throw e; // should never happen
184             if(page > readPages.length) throw new ReadFaultException(addr);
185             if(readPages[page] != emptyPage) throw e; // should never happen
186             initPage(page);
187             return 0;
188         } catch(NullPointerException e) {
189             throw new ReadFaultException(addr);
190         }
191     }
192     
193     protected final void memWrite(int addr, int value) throws WriteFaultException  {
194         if((addr & 3) != 0) throw new WriteFaultException(addr);
195         int page = addr >>> PAGE_SHIFT;
196         int entry = (addr>>>2)&(PAGE_WORDS-1);
197         try {
198             writePages[page][entry] = value;
199         } catch(ArrayIndexOutOfBoundsException e) {
200             if(page < 0) throw e;// should never happen
201             if(page > writePages.length) throw new WriteFaultException(addr);
202             if(readPages[page] != emptyPage) throw e; // should never happen
203             initPage(page);
204             writePages[page][entry] = value;
205         } catch(NullPointerException e) {
206             throw new WriteFaultException(addr);
207         }
208     }
209     
210     protected void initPage(int page) { writePages[page] = readPages[page] = new int[PAGE_WORDS]; }
211     
212     public final int exitStatus() {
213         if(state != DONE) throw new IllegalStateException("exitStatus() called in an inappropriate state");
214         return exitStatus;
215     }
216      
217     public final int run(String[] args) throws EmulationException {
218         start(args);
219         for(;;) {
220             execute();
221             if(state != PAUSED) break;
222             System.err.println("WARNING: Pause requested while executing run()");
223             try { Thread.sleep(500); } catch(InterruptedException e) { }
224         }
225         if(state != DONE) throw new IllegalStateException("run() ended up in an inappropriate state");
226         return exitStatus();
227     }
228     
229     private void addArgs(String[] args) throws EmulationException {
230         if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("addArgs() called in inappropriate state");
231         int count = args.length;
232         byte[] nullTerminator = new byte[1];
233         int total = 4; /* null last table entry  */
234         for(int i=0;i<count;i++) total += args[i].length() + 1/*null terminator*/ + 4/*table entry*/;
235         if(total > PAGE_SIZE) throw new EmulationException("Arguments too large");
236         int start = ARGS_ADDR;
237         int addr = start + (count+1)*4;
238         int[] table = new int[count+1];
239         for(int i=0;i<count;i++) {
240             byte[] a;
241             try { a = args[i].getBytes("US-ASCII"); } catch(UnsupportedEncodingException e){ throw  new Error(e.getMessage()); }
242             table[i] = addr;
243
244                 copyout(a,addr,a.length);
245                 addr += a.length;
246                 copyout(nullTerminator,addr,1);
247                 addr += 1;
248
249         }
250         addr=start;
251         for(int i=0;i<count;i++) {
252             memWrite(addr,table[i]);
253             addr += 4;
254         }
255     }
256     
257     public void setUserInfo(int index, int word) throws EmulationException {
258         if(index < 0 ||  index >= 1024) throw new EmulationException("setUserInfo called with index >= 1024");
259         memWrite(USER_INFO_ADDR+index*4,word);
260     }
261     
262     public int getUserInfo(int index) throws EmulationException {
263         if(index < 0 ||  index >= 1024) throw new EmulationException("getUserInfo called with index >= 1024");
264         return memRead(USER_INFO_ADDR+index*4);
265     }
266     
267     public final void start(String[] args) throws EmulationException {
268         if(state == UNINITIALIZED || state == RUNNING || state == PAUSED) throw new IllegalStateException("start() called in inappropriate state");
269         _start(entryPoint);
270         addArgs(args);
271         fds = new FileDescriptor[OPEN_MAX];
272         fds[0] = new InputStreamFD(System.in)   { public boolean isatty() { return true; } };
273         fds[1] = new OutputStreamFD(System.out) { public boolean isatty() { return true; } };
274         fds[2] = new OutputStreamFD(System.err) { public boolean isatty() { return true; } };
275         state = PAUSED;
276     }
277     
278         
279     // Syscalls
280     private int write(int fdn, int addr, int count) {
281         int n = 0;
282         int r;
283         FileDescriptor fd;
284         count = Math.min(count,MAX_CHUNK);
285         try {
286             fd = fds[fdn];
287             if(fd == null || !fd.writable()) return -EBADFD;
288         } catch(ArrayIndexOutOfBoundsException e) {
289             return -EBADFD;
290         }
291         try {
292             byte[] buf = byteBuf(count);
293             copyin(addr,buf,count);
294             return fd.write(buf,0,count);
295         } catch(FaultException e) {
296             System.err.println(e);
297             return -EFAULT;
298         } catch(IOException e) {
299             System.err.println(e);
300             return -EIO;
301         }
302     }
303
304     private int read(int fdn, int addr, int count) {
305         FileDescriptor fd;
306         count = Math.min(count,MAX_CHUNK);
307         try {
308             fd = fds[fdn];
309             if(fd == null || !fd.readable()) return -EBADFD;
310         } catch(ArrayIndexOutOfBoundsException e) {
311             return -EBADFD;
312         }
313         try {
314             byte[] buf = byteBuf(count);
315             int n = fd.read(buf,0,count);
316             copyout(buf,addr,n);
317             return n;
318         } catch(FaultException e) {
319             System.err.println(e);
320             return -EFAULT;
321         } catch(IOException e) {
322             System.err.println(e);
323             return -EIO;
324         }
325     }
326     
327     private int close(int fdn) {
328         FileDescriptor fd;
329         try {
330             fd = fds[fdn];
331             if(fd == null) return -EBADFD;
332         } catch(ArrayIndexOutOfBoundsException e) {
333             return -EBADFD;
334         }
335         fds[fdn] = null;
336         fd.close();
337         return 0;
338     }
339     
340     private int stat(FileInfo fi, int addr) {
341         int size = fi.size();
342         try {
343             memWrite(addr+0,0); // st_dev (top 16), // st_ino (bottom 16)
344             memWrite(addr+4,(fi.type() & 0xf000)|0644); // st_mode
345             memWrite(addr+8,1); // st_nlink (top 16) // st_uid (bottom 16)
346             memWrite(addr+12,0); // st_gid (top 16) // st_rdev (bottom 16)
347             memWrite(addr+16,size); // st_size
348             memWrite(addr+20,0); // st_atime
349             // memWrite(addr+24,0) // st_spare1
350             memWrite(addr+28,(int)(fi.modTime()/1000)); // st_mtime
351             // memWrite(addr+32,0) // st_spare2
352             memWrite(addr+36,0); // st_atime
353             // memWrite(addr+40,0) // st_spare3
354             memWrite(addr+44,512); // st_bklsize;
355             memWrite(addr+48,(size+511)&(~511)); // st_blocks
356             // memWrite(addr+52,0) // st_spare4[0]
357             // memWrite(addr+56,0) // st_spare4[1]
358         } catch(FaultException e) {
359             System.err.println(e);
360             return -EFAULT;
361         }
362         return 0;
363     }
364     
365     private int fstat(int fdn, int addr) {
366         FileDescriptor fd;
367         try {
368             fd = fds[fdn];
369             if(fd == null) return -EBADFD;
370         } catch(ArrayIndexOutOfBoundsException e) {
371             return -EBADFD;
372         }
373         return stat(fd.fileInfo(),addr);
374     }
375     
376     public int sbrk(int incr) {
377         if(incr==0) return brk<<PAGE_SHIFT;
378         int oldBrk = brk;
379         int newBrk = oldBrk + ((incr+PAGE_SIZE-1)>>PAGE_SHIFT);
380         if(newBrk >= BRK_LIMIT) {
381             System.err.println("Hit BRK_LIMIT");
382             return -ENOMEM;
383         }
384         for(int i=oldBrk;i<newBrk+256;i++)
385             readPages[i] = writePages[i] = emptyPage;
386         brk = newBrk;
387         return oldBrk<<PAGE_SHIFT;
388     }
389         
390     private int open(int addr, int flags, int mode) {
391         final int O_RDONLY = 0;
392         final int O_WRONLY = 1;
393         final int O_RDWR = 2;
394         final int O_APPEND = 0x0008;
395         final int O_CREAT = 0x0200;
396         final int O_NONBLOCK = 0x4000;
397         final int O_EXCL = 0x0800;
398         
399         if((flags & O_APPEND) != 0) {
400             System.err.println("WARNING: O_APPEND not supported");
401             return -EOPNOTSUPP;
402         }
403         if((flags & O_NONBLOCK) != 0) {
404             System.err.println("WARNING: O_NONBLOCK not supported");
405             return -EOPNOTSUPP;
406         }
407         
408         try {
409             int fdn=-1;
410             File f = new File(cstring(addr));
411             System.err.println("Opening: " + f);
412             if((flags & O_EXCL) != 0 && (flags & O_CREAT) != 0)
413                 if(!f.createNewFile()) return -EEXIST;
414             if(f.exists()) {
415                 if(f.length() >= Integer.MAX_VALUE) return -EOPNOTSUPP;
416             } else {
417                 if((flags & O_CREAT) == 0) return -ENOENT;
418             }
419             for(int i=0;i<OPEN_MAX;i++) if(fds[i] == null) { fdn = i; break; }
420             if(fdn==-1) return -ENFILE;
421             fds[fdn] = new RegularFileDescriptor(f,flags&3);
422             return fdn;
423         } catch(FaultException e) {
424             return -EFAULT;
425         } catch(FileNotFoundException e) { 
426             if(e.getMessage().indexOf("Permission denied") >= 0) return -EACCES;
427             return -ENOENT;
428         } catch(IOException e) {
429             return -EIO;
430         }
431     }
432     
433     private int seek(int fdn, int offset, int whence) {
434         FileDescriptor fd;
435         try {
436             fd = fds[fdn];
437             if(fd == null || !fd.readable()) return -EBADFD;
438         } catch(ArrayIndexOutOfBoundsException e) {
439             return -EBADFD;
440         }
441         try {
442             return fd.seek(offset,whence);
443         } catch(IOException e) {
444             System.err.println(e);
445             return -EPIPE;
446         }
447     }
448     
449     // This will only be called by raise() to invoke the default handler
450     // We don't have to worry about actually delivering the signal
451     private int kill(int pid, int signal) {
452         if(pid != PID) return -ESRCH;
453         if(signal < 0 || signal >= 32) return -EINVAL;
454         switch(signal) {
455             case 0: return 0;
456             case 17: // SIGSTOP
457             case 18: // SIGTSTP
458             case 21: // SIGTTIN
459             case 22: // SIGTTOU
460                 state = PAUSED;
461                 break;
462             case 19: // SIGCONT
463             case 20: // SIGCHLD
464             case 23: // SIGIO
465             case 28: // SIGWINCH
466                 break;
467             default: {
468                 String msg = "Terminating on signal: " + signal + "\n";
469                 exitStatus = 1;
470                 state = DONE;
471                 if(fds[2]==null) {
472                     System.out.print(msg);
473                 } else {
474                     byte[] b = msg.getBytes();
475                     try {
476                         fds[2].write(b,0,b.length);
477                     } catch(IOException e) { }
478                 }
479             }
480         }
481         return 0;
482     }
483     
484     private int getpid() { return PID; }
485     
486     protected int syscall(int syscall, int a, int b, int c, int d) {
487         switch(syscall) {
488             case SYS_null: return 0;
489             case SYS_exit: exitStatus = a; state = DONE; return 0;
490             case SYS_pause: state = PAUSED; return 0;
491             case SYS_write: return write(a,b,c);
492             case SYS_fstat: return fstat(a,b);
493             case SYS_sbrk: return sbrk(a);
494             case SYS_open: return open(a,b,c);
495             case SYS_close: return close(a);
496             case SYS_read: return read(a,b,c);
497             case SYS_seek: return seek(a,b,c);
498             case SYS_kill: return kill(a,b);
499             case SYS_getpid: return getpid();
500             default:
501                 System.err.println("Attempted to use unknown syscall: " + syscall);
502                 return -ENOSYS;
503         }
504     }
505     
506     // Helper function to read a cstring from main memory
507     public String cstring(int addr) throws ReadFaultException {
508         StringBuffer sb = new StringBuffer();
509         for(;;) {
510             int word = memRead(addr&~3);
511             switch(addr&3) {
512                 case 0: if(((word>>>24)&0xff)==0) return sb.toString(); sb.append((char)((word>>>24)&0xff)); addr++;
513                 case 1: if(((word>>>16)&0xff)==0) return sb.toString(); sb.append((char)((word>>>16)&0xff)); addr++;
514                 case 2: if(((word>>> 8)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 8)&0xff)); addr++;
515                 case 3: if(((word>>> 0)&0xff)==0) return sb.toString(); sb.append((char)((word>>> 0)&0xff)); addr++;
516             }
517         }
518     }
519      
520     // Exceptions
521     public static class ReadFaultException extends FaultException {
522         public ReadFaultException(int addr) { super(addr); }
523     }
524     public static class WriteFaultException extends FaultException {
525         public WriteFaultException(int addr) { super(addr); }
526     }
527     public static abstract class FaultException extends EmulationException {
528         private int addr;
529         public FaultException(int addr) { this.addr = addr; }
530         public String getMessage() { return "fault at: " + toHex(addr); }
531     }
532     public static class EmulationException extends Exception {
533         public EmulationException() { }
534         public EmulationException(String s) { super(s); }
535     }
536     
537     // FileInfo classes - used by stat(2)
538     static class FileInfo {
539         public static final int S_IFIFO = 0010000;
540         public static final int S_FCHR =  0020000;
541         public static final int S_IFDIR = 0040000;
542         public static final int S_IFREG = 0100000;
543         
544         public int size() { return 0; }
545         public int type() { return S_IFIFO; }
546         public long modTime() { return 0; }
547     }
548         
549     public static class FileFileInfo extends FileInfo {
550         public File f;
551         public FileFileInfo(File f) { this.f = f; }
552         public int size() { return (int)f.length(); }
553         public int type() { return f.isDirectory() ? S_IFDIR : S_IFREG; }
554         public long modTime() { return f.lastModified(); }
555     }
556
557     // File descriptor classes
558     public static abstract class FileDescriptor {
559         public boolean readable() { return false; }
560         public boolean writable() { return false; }
561         
562         private static final FileInfo nullFi = new FileInfo();
563         private FileInfo fi;
564         public FileInfo fileInfo() { return fi; }
565         
566         FileDescriptor() { this(null); }
567         FileDescriptor(FileInfo fi) { this.fi = fi==null ? nullFi : fi; }
568         
569         public int read(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
570         public int write(byte[] a, int off, int length) throws IOException { throw new IOException("no definition"); }
571         
572         public int seek(int n, int whence)  throws IOException  { return -ESPIPE; }
573         public boolean isatty() { return false; }
574         
575         void close() { }
576     }
577     
578     public static class RegularFileDescriptor extends FileDescriptor {
579         private int mode;
580         private RandomAccessFile raf;
581         public boolean readable() { return mode != 1; }
582         public boolean writable() { return mode != 0; }
583         
584         RegularFileDescriptor(File f,int m) throws IOException {
585             super(new FileFileInfo(f));
586             String mode = m == 0 ? "r" : "rw";
587             this.mode = m;
588             raf = new RandomAccessFile(f,mode);
589             if(raf.length() >= Integer.MAX_VALUE) throw new IOException("File too large");
590         }
591         
592         public int seek(int n, int whence) throws IOException {
593             final int SEEK_SET = 0;
594             final int SEEK_CUR = 1;
595             final int SEEK_END = 2;
596             
597             switch(whence) {
598                 case SEEK_SET: break;
599                 case SEEK_CUR: n = (int)(raf.getFilePointer()+n); break;
600                 case SEEK_END: n = (int)(raf.length()+n); break;
601                 default: return -EINVAL;
602             }
603             raf.seek(n);
604             return n;
605         }
606         
607         public int write(byte[] a, int off, int length) throws IOException { raf.write(a,off,length); return length; }
608         public int read(byte[] a, int off, int length) throws IOException { int n = raf.read(a,off,length); return n < 0 ? 0 : n; }
609         
610         void close() { try { raf.close(); } catch(Exception e) { } }
611     }
612     
613     public class OutputStreamFD extends FileDescriptor {
614         private OutputStream os;
615         public boolean writable() { return true; }
616         public OutputStreamFD(OutputStream os) { this.os = os; }
617         public int write(byte[] a, int off, int length) throws IOException { os.write(a,off,length); return length; }
618     }
619     
620     public class InputStreamFD extends FileDescriptor {
621         private InputStream is;
622         public boolean readable() { return true; }
623         public InputStreamFD(InputStream is) { this.is = is; }
624         public int read(byte[] a, int off, int length) throws IOException { int n = is.read(a,off,length); return n < 0 ? 0 : n; }
625     }
626     
627     // Utility functions
628     private byte[] byteBuf(int size) {
629         if(_byteBuf==null) _byteBuf = new byte[size];
630         else if(_byteBuf.length < size)
631             _byteBuf = new byte[min(max(_byteBuf.length*2,size),MAX_CHUNK+8)];
632         return _byteBuf;
633     }
634     protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
635     protected final static int min(int a, int b) { return a < b ? a : b; }
636     protected final static int max(int a, int b) { return a > b ? a : b; }
637 }
638
639
640
641 interface Errno {
642     public static final int EPERM = 1;
643     public static final int ENOENT = 2;
644     public static final int ESRCH = 3;
645     public static final int EINTR = 4;
646     public static final int EIO = 5;
647     public static final int ENXIO = 6;
648     public static final int ENOEXEC = 8;
649     public static final int EBADF = 9;
650     public static final int ECHILD = 10;
651     public static final int EAGAIN = 11;
652     public static final int ENOMEM = 12;
653     public static final int EACCES = 13;
654     public static final int EFAULT = 14;
655     public static final int ENOTBLK = 15;
656     public static final int EBUSY = 16;
657     public static final int EEXIST = 17;
658     public static final int EXDEV = 18;
659     public static final int ENODEV = 19;
660     public static final int ENOTDIR = 20;
661     public static final int EISDIR = 21;
662     public static final int EINVAL = 22;
663     public static final int ENFILE = 23;
664     public static final int EMFILE = 24;
665     public static final int ENOTTY = 25;
666     public static final int ETXTBSY = 26;
667     public static final int EFBIG = 27;
668     public static final int ENOSPC = 28;
669     public static final int ESPIPE = 29;
670     public static final int EROFS = 30;
671     public static final int EMLINK = 31;
672     public static final int EPIPE = 32;
673     public static final int EDOM = 33;
674     public static final int ERANGE = 34;
675     public static final int ENOMSG = 35;
676     public static final int EIDRM = 36;
677     public static final int ECHRNG = 37;
678     public static final int ELNRNG = 41;
679     public static final int EUNATCH = 42;
680     public static final int ENOCSI = 43;
681     public static final int EDEADLK = 45;
682     public static final int ENOLCK = 46;
683     public static final int EBADE = 50;
684     public static final int EBADR = 51;
685     public static final int EXFULL = 52;
686     public static final int ENOANO = 53;
687     public static final int EBADRQC = 54;
688     public static final int EBADSLT = 55;
689     public static final int EDEADLOCK = 56;
690     public static final int EBFONT = 57;
691     public static final int ENOSTR = 60;
692     public static final int ENODATA = 61;
693     public static final int ETIME = 62;
694     public static final int ENOSR = 63;
695     public static final int ENONET = 64;
696     public static final int ENOPKG = 65;
697     public static final int EREMOTE = 66;
698     public static final int ENOLINK = 67;
699     public static final int EADV = 68;
700     public static final int ESRMNT = 69;
701     public static final int ECOMM = 70;
702     public static final int EPROTO = 71;
703     public static final int EMULTIHOP = 74;
704     public static final int ELBIN = 75;
705     public static final int EDOTDOT = 76;
706     public static final int EBADMSG = 77;
707     public static final int EFTYPE = 79;
708     public static final int ENOTUNIQ = 80;
709     public static final int EBADFD = 81;
710     public static final int EREMCHG = 82;
711     public static final int ELIBACC = 83;
712     public static final int ELIBBAD = 84;
713     public static final int ELIBSCN = 85;
714     public static final int ELIBMAX = 86;
715     public static final int ELIBEXEC = 87;
716     public static final int ENOSYS = 88;
717     public static final int ENMFILE = 89;
718     public static final int ENOTEMPTY = 90;
719     public static final int ENAMETOOLONG = 91;
720     public static final int ELOOP = 92;
721     public static final int EOPNOTSUPP = 95;
722     public static final int EPFNOSUPPORT = 96;
723     public static final int ECONNRESET = 104;
724     public static final int ENOBUFS = 105;
725     public static final int EAFNOSUPPORT = 106;
726     public static final int EPROTOTYPE = 107;
727     public static final int ENOTSOCK = 108;
728     public static final int ENOPROTOOPT = 109;
729     public static final int ESHUTDOWN = 110;
730     public static final int ECONNREFUSED = 111;
731     public static final int EADDRINUSE = 112;
732     public static final int ECONNABORTED = 113;
733     public static final int ENETUNREACH = 114;
734     public static final int ENETDOWN = 115;
735     public static final int ETIMEDOUT = 116;
736     public static final int EHOSTDOWN = 117;
737     public static final int EHOSTUNREACH = 118;
738     public static final int EINPROGRESS = 119;
739     public static final int EALREADY = 120;
740     public static final int EDESTADDRREQ = 121;
741     public static final int EMSGSIZE = 122;
742     public static final int EPROTONOSUPPORT = 123;
743     public static final int ESOCKTNOSUPPORT = 124;
744     public static final int EADDRNOTAVAIL = 125;
745     public static final int ENETRESET = 126;
746     public static final int EISCONN = 127;
747     public static final int ENOTCONN = 128;
748     public static final int ETOOMANYREFS = 129;
749     public static final int EPROCLIM = 130;
750     public static final int EUSERS = 131;
751     public static final int EDQUOT = 132;
752     public static final int ESTALE = 133;
753     public static final int ENOTSUP = 134;
754     public static final int ENOMEDIUM = 135;
755     public static final int ENOSHARE = 136;
756     public static final int ECASECLASH = 137;
757     public static final int EILSEQ = 138;
758     public static final int EOVERFLOW = 139;
759     public static final int __ELASTERROR = 2000;
760 }
761
762 interface Syscalls {
763     public static final int SYS_null = 0;
764     public static final int SYS_exit = 1;
765     public static final int SYS_pause = 2;
766     public static final int SYS_open = 3;
767     public static final int SYS_close = 4;
768     public static final int SYS_read = 5;
769     public static final int SYS_write = 6;
770     public static final int SYS_sbrk = 7;
771     public static final int SYS_fstat = 8;
772     public static final int SYS_isatty = 9;
773     public static final int SYS_seek = 10;
774     public static final int SYS_kill = 11;
775     public static final int SYS_getpid = 12;
776 }