OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / gloss / gloss.cxx
1 // gloss.cxx - Gloss routines.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #include "config.h"
8 #include <errno.h>
9 #include "gloss.h"
10 #include "libgloss.h"
11 // ??? For now.  grep for newlib below.
12 #include "newlib.h"
13
14 #include <cstdlib>
15 #include <unistd.h>
16 #include <ctime>
17
18
19 // Some usings not mentioned in gloss.h.
20 using sid::little_int_1;
21 using sid::little_int_4;
22 using sid::big_int_4;
23
24 using sidutil::parse_attribute;
25 using sidutil::make_numeric_attribute;
26 using sidutil::make_attribute;
27
28 gloss32::gloss32() :
29   reset_pin(this, &gloss32::reset_pin_handler),
30   trap_type_ipin(this, &gloss32::trap_pin_handler),
31   rx_pin(this, &gloss32::rx_handler),
32   cpu (0),
33   cpu_memory_bus (0),
34   command_line("<unknown>"),
35   max_fds(32),
36   verbose_p(false)
37 {
38   // ??? There's a naming disconnect between "cpu" and "target_memory".
39   add_accessor("target-memory", &this->cpu_memory_bus);
40
41   add_pin("reset", &this->reset_pin);
42   add_pin("trap", &this->trap_type_ipin, &this->trap_type_opin);
43   add_pin("trap-code", &this->trap_code_pin);
44   add_pin("trap-chain",
45           &this->trap_type_chain_ipin, &this->trap_type_chain_opin);
46   add_pin("trap-code-chain", &this->trap_code_chain_pin);
47   add_pin("process-signal", &this->process_signal_pin);
48
49   add_pin("debug-tx", &this->tx_pin);
50   add_pin("debug-rx", &this->rx_pin);
51   add_attribute_ro_value ("tk tty", string("hw-visual-tty"), "gui");
52
53   add_uni_relation("cpu", &this->cpu);
54
55   add_attribute("command-line", &this->command_line, "setting");
56   add_attribute("verbose?", &this->verbose_p, "setting");
57
58   add_attribute("max-fds", &this->max_fds, "setting");
59   host_ops = 0;
60   fd_table = 0;
61 }
62
63 gloss32::~gloss32()
64 {
65   if (host_ops)
66     delete host_ops;
67   delete [] fd_table;
68 }
69
70 void
71 gloss32::reset_pin_handler(host_int_4 ignore)
72 {
73   // Call a virtual method to do the work so derived classes can override.
74   reset();
75 }
76
77 void
78 gloss32::reset()
79 {
80   if (max_fds < 0 || max_fds > 256)
81     {
82       cerr << "*** Bad value " << max_fds << " for max_fds." << endl;
83       max_fds = 32;
84     }
85   if (fd_table)
86     {
87       // Close any open files.
88       // FIXME: Undoubtedly incomplete.
89       for (int i = 0; i < max_fds; ++i)
90         {
91           int errcode;
92           if (fd_table[i] > 2)
93             if (! host_ops->close (fd_table[i], errcode))
94               cerr << "*** While resetting, close("
95                    << fd_table[i]
96                    << ") unexpectedly failed." << endl;
97         }
98       delete [] fd_table;
99     }
100   fd_table = new int[max_fds];
101   for (int i = 0; i < max_fds; ++i)
102     fd_table[i] = -1;
103   fd_table[0] = 0;
104   fd_table[1] = 1;
105   fd_table[2] = 2;
106 }
107
108 // Called when rx pin is driven.  Record byte in buffer.
109
110 void
111 gloss32::rx_handler(host_int_4 byte)
112 {
113   rx_buffer.push_back(byte);
114 }
115
116 // Update our knowledge of what the cpu's endianness is.
117
118 void
119 gloss32::update_endian()
120 {
121   if (! this->cpu)
122     {
123       cerr << "*** CPU not specified!" << endl;
124       return;
125     }
126
127   string attr_name = "endian";
128   string attr_value = this->cpu->attribute_value(attr_name);
129   component::status s = parse_attribute(attr_value, this->endian);
130   if ((s != component::ok) || (this->endian == sidutil::endian_unknown))
131     {
132       cerr << "Unknown endianness (" << attr_value << "), assuming big" << endl;
133       this->endian = sidutil::endian_big;
134     }
135 }
136 \f
137 // Memory access methods.
138
139 bool
140 gloss32::get_string(address32 address, string& value, unsigned length)
141 {
142   if (! this->cpu_memory_bus)
143     {
144       cerr << "*** CPU memory bus not configured!" << endl;
145       return false;
146     }
147   
148   if (verbose_p)
149     {
150       cerr << "Reading " << length << " byte(s) from target memory at "
151            << make_numeric_attribute (address, ios::hex | ios::showbase) << ": ";
152     }
153
154   for (unsigned i = 0; i < length; i++)
155     {
156       little_int_1 byte; // equivalent to big_int_1
157       while(true)
158         {
159           bus::status s = this->cpu_memory_bus->read(address, byte);
160           if (s == bus::ok) 
161             break;
162           else if (s == bus::delayed) 
163             continue;
164           else 
165             {
166               if (verbose_p)
167                 cerr << "failed" << endl;
168               return false;
169             }
170         }
171
172       char c = byte;
173       value += c;
174       if (verbose_p)
175         cerr << "[" << c << "]";
176
177       address = address + 1;
178
179       if (c == '\0')
180         break;
181     }
182   
183   if (verbose_p)
184     cerr << endl;
185   return true;
186 }
187
188 bool
189 gloss32::set_string(address32 address, const string& value) 
190 {
191   if (! this->cpu_memory_bus)
192     {
193       cerr << "*** CPU memory bus not configured!" << endl;
194       return false;
195     }
196   
197   if (verbose_p)
198     {
199       cerr << "Writing " << value.size() << " byte(s) to target memory at "
200            << make_numeric_attribute (address, ios::hex | ios::showbase)
201            << ": ";
202     }
203   
204   for (unsigned i=0; i < value.size(); i++)
205     {
206       char c = value[i];
207       little_int_1 byte = c; // equivalent to big_int_1
208       while (true)
209         {
210           bus::status s = this->cpu_memory_bus->write(address, byte);
211           if (s == bus::ok) 
212             break;
213           else if (s == bus::delayed) 
214             continue;
215           else 
216             {
217               if (verbose_p)
218                 cerr << "failed" << endl;
219               return false;
220             }
221         }
222
223       if (verbose_p)
224         cerr << "[" << c << "]";
225
226       address = address + 1;
227     }
228
229   if (verbose_p)
230     cerr << endl;
231
232   return true;
233 }
234
235 bool
236 gloss32::get_word(address32 address, int32& value)
237 {
238   if (! cpu_memory_bus)
239     {
240       cerr << "*** CPU memory bus not configured!" << endl;
241       return false;
242     }
243
244   if (verbose_p)
245     {
246       cerr << "Reading word from target memory at "
247            << make_numeric_attribute (address, ios::hex | ios::showbase)
248            << ": ";
249     }
250
251   while (true)
252     {
253       bus::status s;
254
255       if (this->endian == sidutil::endian_big)
256         {
257           big_int_4 word;
258           s = this->cpu_memory_bus->read(address, word);
259           value = word;
260         }
261       else
262         {
263           little_int_4 word;
264           s = this->cpu_memory_bus->read(address, word);
265           value = word;
266         }
267
268       if (s == bus::ok)
269         break;
270       else if (s == bus::delayed)
271         continue;
272       else
273         {
274           if (verbose_p)
275             cerr << "failed" << endl;
276           return false;
277         }
278     }
279
280   if (verbose_p)
281     cerr << make_numeric_attribute (value, ios::hex | ios::showbase) << endl;
282
283   return true;
284 }
285
286 bool
287 gloss32::set_word(address32 address, int32 value)
288 {
289   if (! cpu_memory_bus)
290     {
291       cerr << "*** Target memory bus not configured!" << endl;
292       return false;
293     }
294
295   if (verbose_p)
296     {
297       cerr << "Write word " << make_numeric_attribute (value, ios::hex | ios::showbase)
298            << " to target memory at "
299            << make_numeric_attribute (address, ios::hex | ios::showbase);
300     }
301
302   while (true)
303     {
304       bus::status s;
305
306       if (this->endian == sidutil::endian_big)
307         {
308           big_int_4 word = value;
309           s = this->cpu_memory_bus->write(address, word);
310         }
311       else
312         {
313           little_int_4 word = value;
314           s = this->cpu_memory_bus->write(address, word);
315         }
316
317       if (s == bus::ok)
318         break;
319       else if (s == bus::delayed)
320         continue;
321       else
322         {
323           if (verbose_p)
324             cerr << ": failed" << endl;
325           return false;
326         }
327     }
328
329   if (verbose_p)
330     cerr << endl;
331
332   return true;
333 }
334 \f
335 // Return the value of the cpu's program counter.
336 // This is (currently) for informational purposes.  Thus we needn't care if
337 // the value returned is the address of the trap or faulting instruction, or
338 // some offset past it.
339 // ??? Might want to require the accuracy though (future concerns).
340
341 bool
342 gloss32::get_pc(address32& value)
343 {
344   if (! this->cpu)
345     {
346       cerr << "*** CPU not specified!" << endl;
347       return false;
348     }
349
350   // ??? If target needs to override this method, probably the only reason
351   // will be to use a different string here.  Make member?
352   string attr_name = "pc";
353
354   string attr_value = this->cpu->attribute_value(attr_name);
355   if (attr_value == "")
356     {
357       cerr << "*** Could not read pc!" << endl;
358       return false;
359     }
360
361   host_int_4 value_number;
362   parse_attribute(attr_value, value_number);
363   value = value_number;
364   return true;
365 }
366 \f
367 // Handle an incoming trap request.
368 // This is split into 32 and 64 bit versions.
369 // 64 bit versions may need to pass 64 bit values through (1 or more) pins
370 // (??? maybe not though).
371
372 void
373 gloss32::trap_pin_handler(host_int_4 traptype)
374 {
375   if (verbose_p)
376     cerr << "gloss trap " << traptype << " code " << trap_code_pin.sense() << endl;
377
378   host_int_4 trapcode = this->trap_code_pin.sense ();
379
380   // Emulatable system call?
381   if (syscall_trap_p())
382     {
383       update_endian();
384       this->blocked_p = false;
385       syscall_trap(); // may set blocked_p
386       if (this->blocked_p)
387         trap_type_opin.drive(sidutil::cpu_trap_reissue);
388       else
389         trap_type_opin.drive(sidutil::cpu_trap_skip);
390       return;
391     }
392
393   // Dispatch it up the handler chain.
394   this->trap_type_chain_ipin.driven (sidutil::cpu_trap_unhandled);
395   this->trap_code_chain_pin.drive (trapcode);
396   this->trap_type_chain_opin.drive (traptype);
397   host_int_4 chain_response = this->trap_type_chain_ipin.sense();
398   if (chain_response != sidutil::cpu_trap_unhandled)
399     {
400       this->trap_type_opin.drive (chain_response);
401       return;
402     }
403   // No response from handler chain.
404
405   // Dispatch to general fault handler here.
406   update_endian ();
407   fault_trap (traptype, trapcode);
408 }
409
410
411 void
412 gloss32::fault_trap(host_int_4 trap_type, host_int_4 trap_code)
413 {
414   string trapname =
415     trap_type == sidutil::cpu_trap_software ? "software" :
416     trap_type == sidutil::cpu_trap_breakpoint ? "breakpoint" :
417     trap_type == sidutil::cpu_trap_syscall ? "syscall" :
418     trap_type == sidutil::cpu_trap_invalid_insn ? "invalid insn" :
419     trap_type == sidutil::cpu_trap_memory_fault ? "memory" :
420     trap_type == sidutil::cpu_trap_overflow ? "overflow" :
421     trap_type == sidutil::cpu_trap_stepped ? "stepped" :
422     "unknown";
423
424   host_int_4 trapsig =
425     trap_type == sidutil::cpu_trap_software ? newlib::sigTrap :
426     trap_type == sidutil::cpu_trap_breakpoint ? newlib::sigTrap :
427     trap_type == sidutil::cpu_trap_syscall ? newlib::sigTrap :
428     trap_type == sidutil::cpu_trap_invalid_insn ? newlib::sigIll :
429     trap_type == sidutil::cpu_trap_memory_fault ? newlib::sigSegv :
430     trap_type == sidutil::cpu_trap_overflow ? newlib::sigFpe :
431     trap_type == sidutil::cpu_trap_stepped ? newlib::sigTrap :
432     newlib::sigAbrt;
433
434   bool printcode =
435     trap_type == sidutil::cpu_trap_software ? true :
436     trap_type == sidutil::cpu_trap_breakpoint ? true :
437     trap_type == sidutil::cpu_trap_syscall ? true :
438     trap_type == sidutil::cpu_trap_invalid_insn ? false :
439     trap_type == sidutil::cpu_trap_memory_fault ? true :
440     trap_type == sidutil::cpu_trap_overflow ? false :
441     trap_type == sidutil::cpu_trap_stepped ? false :
442     true;
443
444   cerr << "Fault (" << trapname;
445   if (printcode) 
446     cerr << ", " << make_numeric_attribute (trap_code, ios::hex | ios::showbase);
447   cerr << ")";
448
449   address32 pc;
450   if (get_pc(pc))
451     cerr << " pc=" << make_numeric_attribute (pc, ios::hex | ios::showbase) << endl;
452
453   // ??? Probably the only reason a subclass would want to override us is to
454   // use a different value here.  Make member?  Canonicalize the value?
455
456   process_signal_pin.drive(trapsig);
457   
458   // Acknowlege trap.
459   trap_type_opin.drive(sidutil::cpu_trap_skip);
460 }
461
462 bool
463 gloss32::set_host_error_result (int32 host_errno)
464 {
465   return set_error_result (host_to_target_errno (host_errno));
466 }
467
468 // Convert host errno value to target.
469
470 int
471 gloss32::host_to_target_errno (int host_errno)
472 {
473   return newlib::host_to_target_errno (host_errno);
474 }
475
476 bool
477 gloss32::get_int_argument(unsigned index, int32& value)
478 {
479   assert (cpu);
480   string attrName = "syscall-arg";
481   attrName.append(1,'0' + index);
482   assert (attrName != "");
483
484   string attrValue = cpu->attribute_value (attrName);
485   if (attrValue == "")
486     {
487       cerr << "Could not read attribute " << attrName
488            << " for ABI argument #" << index << endl;
489       return false;
490     }
491
492   host_int_4 value_number;
493   parse_attribute(attrValue, value_number);
494   value = value_number;
495   return true;
496 }
497
498 // default argument handling routines
499 bool
500 gloss32::set_int_result(int32 value) 
501 {
502   assert (cpu);
503
504   host_int_4 value_number = value;
505   string attrValue = make_attribute(value_number);
506
507   cpu->set_attribute_value ("syscall-result", attrValue);
508   return true; // XXX: check?
509 }
510
511 bool
512 gloss32::set_error_result(int32 value) 
513 {
514   assert (cpu);
515
516   host_int_4 value_number = value;
517   string attrValue = make_attribute(value_number);
518
519   cpu->set_attribute_value ("syscall-error", attrValue);
520   return true; // XXX: safe to assume success?
521 }
522
523 \f
524
525 // default syscall conversion routine
526 int32 
527 gloss32::target_to_host_syscall (int32 target_syscall)
528 {
529   return target_syscall;
530 }
531
532 // System call support.
533 bool
534 gloss32::syscall_trap_p()
535 {
536   string attrValue = cpu->attribute_value ("syscall-trap");
537   host_int_4 syscall_trap;
538   parse_attribute(attrValue, syscall_trap);
539   return ((trap_type_ipin.sense() == sidutil::cpu_trap_software)
540           && (trap_code_pin.sense() == syscall_trap));
541 }
542
543 void
544 gloss32::syscall_trap()
545 {
546   int32 syscall;
547
548   this->get_int_argument(0, syscall);
549   if (verbose_p)
550     cerr << "System call number " << syscall << endl;
551
552   switch (target_to_host_syscall(syscall))
553     {
554     case libgloss::SYS_read:
555       do_sys_read();
556       break;
557     case libgloss::SYS_write:
558       do_sys_write();
559       break;
560     case libgloss::SYS_exit:
561       do_sys_exit();
562       break;
563     case libgloss::SYS_lseek:
564       do_sys_lseek();
565       break;
566     case libgloss::SYS_close:
567       do_sys_close();
568       break;
569     case libgloss::SYS_open:
570       do_sys_open();
571       break;
572     case libgloss::SYS_time:
573       set_int_result(time(NULL));
574       break;
575     default:
576       do_nonstandard_target_syscalls (syscall);
577       break;
578     }
579 }
580
581 void
582 gloss32::do_nonstandard_target_syscalls (int32 target_syscall)
583 {
584   if (verbose_p)
585     cerr << "Unimplemented syscall " << target_syscall << endl;
586   set_int_result(-1);
587   set_error_result(newlib::eNoSys);
588 }
589
590 void
591 gloss32::do_sys_exit()
592 {
593   int32 value;
594   get_int_argument(1, value);
595   if (verbose_p)
596     cerr << "*** exit(" << value << ")" << endl;
597   
598   if (value == 0)
599     process_signal_pin.drive(newlib::sigQuit);
600   else
601     process_signal_pin.drive(newlib::sigAbrt);
602 }
603
604 void
605 gloss32::do_sys_lseek()
606 {
607   int32 handle, offset, seek_type;
608   hostops::seek_type whence;
609
610   get_int_argument(1, handle);
611   get_int_argument(2, offset);
612   get_int_argument(3, seek_type);
613
614   switch (seek_type)
615     {
616     case 1:
617       whence = hostops::seek_cur;
618     case 2:
619       whence = hostops::seek_end;
620     default:
621     case 0:
622       whence = hostops::seek_set;
623     }
624
625   size32 new_pos;
626   int errcode;
627   
628   if (! this->lseek(handle, offset, whence, new_pos, errcode))
629     {
630       set_host_error_result(errcode);
631       set_int_result(1);
632       return;
633     }
634   set_int_result(0);
635 }
636
637 void
638 gloss32::do_sys_read()
639 {
640   int32 handle, str_ptr, str_length;
641
642   get_int_argument(1, handle);
643   get_int_argument(2, str_ptr);
644   get_int_argument(3, str_length);
645
646   size32 len_read;
647   int errcode;
648   if (! this->read (handle, str_ptr, str_length, len_read, errcode))
649     {
650       set_host_error_result(errcode);
651       // FIXME: what is proper result here?
652       set_int_result(-1);
653       return;
654     }
655
656   // return number of bytes read.
657   set_int_result(len_read);
658 }
659
660 void
661 gloss32::do_sys_write()
662 {
663   string str;
664   int32 handle, str_ptr, str_length;
665
666   get_int_argument(1, handle);
667   get_int_argument(2, str_ptr);
668   get_int_argument(3, str_length);
669
670   size32 len_written;
671   int errcode;
672   if (! this->write (handle, str_ptr, str_length, len_written, errcode))
673     {
674       set_host_error_result(errcode);
675       set_int_result(-1);
676       return;
677     }
678
679   // return number of bytes written
680   set_int_result(len_written);
681 }
682
683 void
684 gloss32::do_sys_close()
685 {
686   int32 handle;
687
688   get_int_argument(1, handle);
689
690   int errcode;
691   if (! this->close(handle, errcode))
692     {
693       set_host_error_result(errcode);
694       set_int_result(1);
695       return;
696     }
697   set_int_result(0);
698 }
699
700 void
701 gloss32::do_sys_open()
702 {
703   string filename;
704   int32 str_ptr, str_length, open_flags, mode, flags;
705
706   get_int_argument(1, str_ptr);
707   get_int_argument(2, open_flags);
708   get_int_argument(3, mode);
709
710   get_string(str_ptr, filename, 100);
711
712   if (!target_to_host_open_flags (open_flags, flags))
713     {
714       set_error_result(newlib::eInval);
715       set_int_result(-1);
716       return;
717     }
718
719   // Check for standard I/O. ":tt" is a magic filename for stdin/stdout.
720   if (filename == ":tt")
721     {
722       switch (flags) {
723       case (hostops::open_read_only | hostops::open_text):
724         set_int_result(0);
725         break;
726       case (hostops::open_write_only | hostops::open_create | hostops::open_trunc | hostops::open_text):
727         set_int_result(1);
728         break;
729       default:
730         set_error_result(newlib::eInval);
731         set_int_result(-1);
732         break;
733       }
734       return;
735     }
736  
737   int result_fd,errcode;
738
739   if ((flags & hostops::open_create) != 0)
740     {
741       if (! this->open (filename, flags, mode, result_fd, errcode))
742         {
743           set_host_error_result (errcode);
744           set_int_result (-1);
745         }
746       else
747         set_int_result (result_fd);
748     }
749   else
750     {
751       if (! this->open (filename, flags, result_fd, errcode))
752         {
753           set_host_error_result (errcode);
754           set_int_result (-1);
755         }
756       else
757         set_int_result (result_fd);
758     }
759 }
760
761 bool
762 gloss32::target_to_host_open_flags (int open_flags, int& flags)
763 {
764   switch (open_flags)
765     {
766     case 0:
767       flags = hostops::open_read_only | hostops::open_text;
768       break;
769     case 1:
770       flags = hostops::open_read_only;
771       break;
772     case 2:
773       flags = hostops::open_read_write | hostops::open_text;
774       break;
775     case 3:
776       flags = hostops::open_read_write;
777       break;
778     case 4:
779       flags = hostops::open_write_only | hostops::open_create | hostops::open_trunc | hostops::open_text;
780       break;
781     case 5:
782       flags = hostops::open_write_only | hostops::open_create | hostops::open_trunc;
783       break;
784     case 6:
785       flags = hostops::open_read_write | hostops::open_create | hostops::open_trunc | hostops::open_text;
786       break;
787     case 7:
788       flags = hostops::open_read_write | hostops::open_create | hostops::open_trunc;
789       break;
790     case 8:
791       flags = hostops::open_write_only | hostops::open_create | hostops::open_append | hostops::open_text;
792       break;
793     case 9:
794       flags = hostops::open_write_only | hostops::open_create | hostops::open_append;
795       break;
796     case 10:
797       flags = hostops::open_read_write | hostops::open_create | hostops::open_append | hostops::open_text;
798       break;
799     case 11:
800       flags = hostops::open_read_write | hostops::open_create | hostops::open_append;
801       break;
802     default:
803       return false;
804     }
805   return true;
806 }
807
808 int
809 gloss32::lookup_fd (int target_fd)
810 {
811   if (target_fd < 0 || target_fd >= max_fds)
812     return -1;
813   return fd_table[target_fd];
814 }
815
816 // Return unused fd or -1 if table is full.
817 // Allocating the fd is left to the caller.
818
819 int
820 gloss32::unused_fd ()
821 {
822   for (int i = 0; i < max_fds; ++i)
823     {
824       if (fd_table[i] == -1)
825         return i;
826     }
827   return -1;
828 }
829
830 // Record target_fd/host_fd mapping.
831
832 void
833 gloss32::alloc_fd (int target_fd, int host_fd)
834 {
835   fd_table[target_fd] = host_fd;
836 }
837
838 void
839 gloss32::free_fd (int target_fd)
840 {
841   assert (target_fd >= 0 && target_fd < max_fds);
842   fd_table[target_fd] = -1;
843 }
844
845 bool
846 gloss32::open (string filename, int flags, int& result_fd, int& errcode)
847 {
848   int host_fd,target_fd;
849
850   if (verbose_p)
851     cerr << "*** open(" << filename << ", " << flags << ")";
852
853   target_fd = unused_fd ();
854   if (target_fd == -1)
855     {
856       if (verbose_p)
857         cerr << " -> failed, EMFILE" << endl;
858       errcode = EMFILE;
859       return false;
860     }
861
862   if (! host_ops->open (filename.c_str (), flags, host_fd, errcode))
863     {
864       if (verbose_p)
865         cerr << " -> failed, " << errcode << endl;
866       return false;
867     }
868   alloc_fd (target_fd, host_fd);
869   result_fd = target_fd;
870
871   if (verbose_p)
872     cerr << " -> " << result_fd << endl;
873
874   return true;
875 }
876
877 bool
878 gloss32::open (string filename, int flags, int mode, int& result_fd, int& errcode)
879 {
880   int host_fd,target_fd;
881   
882   if (verbose_p)
883     cerr << "*** open(" << filename << ", " << flags << ", " << mode << ")";
884
885   target_fd = unused_fd ();
886   if (target_fd == -1)
887     {
888       if (verbose_p)
889         cerr << " -> failed, EMFILE" << endl;
890       errcode = EMFILE;
891       return false;
892     }
893
894   if (! host_ops->open (filename.c_str (), flags, mode, host_fd, errcode))
895     {
896       if (verbose_p)
897         cerr << " -> failed, " << errcode << endl;
898       return false;
899     }
900   alloc_fd (target_fd, host_fd);
901   result_fd = target_fd;
902
903   if (verbose_p)
904     cerr << " -> " << result_fd << endl;
905
906   return true;
907 }
908
909 bool
910 gloss32::close (int fd, int& errcode)
911 {
912   int host_fd;
913
914   // FIXME: 0,1,2?
915
916   host_fd = lookup_fd (fd);
917   if (host_fd == -1)
918     {
919       errcode = EBADF;
920       return false;
921     }
922
923   if (! host_ops->close (host_fd, errcode))
924     return false;
925   free_fd (fd);
926   return true;
927 }
928
929 // ??? 64 bit host edge conditions
930
931 bool
932 gloss32::read (int fd, address32 addr, size32 len,
933                size32& len_read, int& errcode)
934 {
935   int host_fd = lookup_fd (fd);
936
937   // Special handling for stdin.
938   // If it hasn't been closed/reopened, use rx-pin.
939   int use_rx_p = (fd == 0
940                   && host_fd == 0);
941
942   if (verbose_p)
943     cerr << "*** read(" << fd << "," << addr << "," << len << ")" << endl;
944
945   if (host_fd == -1)
946     {
947       errcode = EBADF;
948       return false;
949     }
950
951   // Read a chunk at a time to reduce number of host syscalls.
952   const unsigned int xfr_size = 4096; // ???
953   char buf[xfr_size];
954   string strbuf; // ???
955
956   size32 total_read = 0;
957   while (len > 0)
958     {
959       size32 count_read;
960
961       if (use_rx_p)
962         {
963           char c;
964
965           if (rx_buffer.size() > 0)
966             {
967               c = rx_buffer.front();
968               rx_buffer.erase(rx_buffer.begin());
969             }
970           else
971             {
972               this->blocked_p = true;
973               errcode = EAGAIN;
974               return false;
975             }
976           count_read = 1;
977           strbuf = c;
978         }
979       else
980         {
981           size32 count = len > xfr_size ? xfr_size : len;
982
983           // Read the next chunk from the file.
984
985           if (! host_ops->read32 (host_fd, buf, count, count_read, errcode))
986             {
987               // If we've already read something, return with that.
988               if (total_read > 0)
989                 {
990                   len_read = total_read;
991                   return true;
992                 }
993               return false;
994             }
995           if (count_read == 0)
996             {
997               len_read = total_read;
998               return true;
999             }
1000           strbuf.assign (buf, count_read); // ???
1001         }
1002
1003       // Write chunk to memory.
1004
1005       if (! set_string (addr, strbuf))
1006         {
1007           // FIXME: Signal error or return amount read (through to
1008           // memory) thus far?
1009           // FIXME: Should reset file position.
1010 #if 0
1011           if (total_read > 0)
1012             {
1013               len_read = total_read;
1014               return true;
1015             }
1016 #endif
1017           errcode = EINVAL; // ???
1018           return false;
1019         }
1020
1021       addr = addr + count_read;
1022       total_read += count_read;
1023       len -= count_read;
1024     }
1025
1026   len_read = total_read;
1027   return true;
1028 }
1029
1030 // ??? 64 bit host edge conditions
1031
1032 bool
1033 gloss32::write (int fd, address32 addr, size32 len,
1034                 size32& len_written, int& errcode)
1035 {
1036   int host_fd = lookup_fd (fd);
1037
1038   // Special handling for stdout/stderr.
1039   // If it hasn't been closed/reopened, use tx-pin.
1040   // ??? Allow separating stdout,stderr.
1041   int use_tx_p = ((fd == 1 || fd == 2)
1042                   && host_fd == fd);
1043
1044   if (verbose_p)
1045     cerr << "*** write(" << fd << "," << addr << "," << len << ")" << endl;
1046
1047   if (host_fd == -1)
1048     {
1049       errcode = EBADF;
1050       return false;
1051     }
1052
1053   // Write a chunk at a time to reduce number of host system calls.
1054   const unsigned int xfr_size = 4096; // ???
1055
1056   size32 total_written = 0;
1057   while (len > 0)
1058     {
1059       string buf; // ??? Previously allocated char array?
1060
1061       size32 count = len > xfr_size ? xfr_size : len;
1062
1063       // Read next chunk from memory.
1064
1065       if (! get_string (addr, buf, count))
1066         {
1067           // FIXME: Signal error or return amount written thus far?
1068           // FIXME: Should reset file position.
1069 #if 0
1070           if (total_written > 0)
1071             {
1072               len_written = total_written;
1073               return true;
1074             }
1075 #endif
1076           errcode = EINVAL; // ???
1077           return false;
1078         }
1079
1080       addr = addr + count;
1081
1082       // Write chunk to file.
1083
1084       unsigned int count_written;
1085
1086       if (use_tx_p)
1087         {
1088           unsigned i;
1089           for (i = 0; i < count; ++i)
1090             {
1091               host_int_4 value = buf[i];
1092               tx_pin.drive(value);
1093             }
1094           count_written = i;
1095         }
1096       else
1097         {
1098           if (! host_ops->write32 (host_fd, buf.c_str(), count, count_written, errcode))
1099             {
1100               // If we've already written something, return with that.
1101               if (total_written > 0)
1102                 {
1103                   len_written = total_written;
1104                   return true;
1105                 }
1106               return false;
1107             }
1108         }
1109       if (count_written == 0)
1110         {
1111           len_written = total_written;
1112           return true;
1113         }
1114
1115       total_written += count_written;
1116       len -= count_written;
1117     }
1118
1119   len_written = total_written;
1120   return true;
1121 }
1122
1123 bool
1124 gloss32::remove (string filename, int& errcode)
1125 {
1126   return host_ops->remove (filename.c_str (), errcode);
1127 }
1128
1129 bool
1130 gloss32::rename (string oldname, string newname, int& errcode)
1131 {
1132   return host_ops->rename (oldname.c_str (), newname.c_str (), errcode);
1133 }
1134
1135 bool
1136 gloss32::lseek (int fd, offset32 offset, hostops::seek_type how,
1137                 size32& result, int& errcode)
1138 {
1139   if (verbose_p)
1140     cerr << "*** lseek(" << fd << ", " << offset << ", " << (int) how << ")";
1141
1142   int host_fd = lookup_fd (fd);
1143   if (host_fd == -1)
1144     {
1145       if (verbose_p)
1146         cerr << " -> failed, EBADF" << endl;
1147       errcode = EBADF;
1148       return false;
1149     }
1150
1151   size32 new_pos;
1152   if (! host_ops->lseek32 (host_fd, offset, how, new_pos, errcode))
1153     {
1154       if (verbose_p)
1155         cerr << " -> failed, " << errcode << endl;
1156       return false;
1157     }
1158
1159   if (verbose_p)
1160     cerr << " -> " << new_pos << endl;
1161   result = new_pos;
1162   return true;
1163 }
1164
1165 bool
1166 gloss32::getsize (int fd, size32& size, int& errcode)
1167 {
1168   int host_fd = lookup_fd (fd);
1169   if (host_fd == -1)
1170     {
1171       errcode = EBADF;
1172       return false;
1173     }
1174   return host_ops->getsize32 (host_fd, size, errcode);
1175 }
1176
1177 bool
1178 gloss32::tmpnam (string& filename, int& errcode)
1179 {
1180   char filename_buf[1024]; // FIXME
1181
1182   if (! host_ops->tmpnam (filename_buf, errcode))
1183     return false;
1184   filename = filename_buf;
1185   return true;
1186 }
1187
1188 bool
1189 gloss32::isatty (int fd, bool& result, int& errcode)
1190 {
1191   int host_fd = lookup_fd (fd);
1192   if (host_fd == -1)
1193     {
1194       errcode = EBADF;
1195       return false;
1196     }
1197
1198   // FIXME: Quick hack.
1199   if (host_fd == 0 || host_fd == 1 || host_fd == 2)
1200     result = true;
1201   else
1202     result = false;
1203   return true;
1204 }