1 // gloss.cxx - Gloss routines. -*- C++ -*-
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.
11 // ??? For now. grep for newlib below.
19 // Some usings not mentioned in gloss.h.
20 using sid::little_int_1;
21 using sid::little_int_4;
24 using sidutil::parse_attribute;
25 using sidutil::make_numeric_attribute;
26 using sidutil::make_attribute;
29 reset_pin(this, &gloss32::reset_pin_handler),
30 trap_type_ipin(this, &gloss32::trap_pin_handler),
31 rx_pin(this, &gloss32::rx_handler),
34 command_line("<unknown>"),
38 // ??? There's a naming disconnect between "cpu" and "target_memory".
39 add_accessor("target-memory", &this->cpu_memory_bus);
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);
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);
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");
53 add_uni_relation("cpu", &this->cpu);
55 add_attribute("command-line", &this->command_line, "setting");
56 add_attribute("verbose?", &this->verbose_p, "setting");
58 add_attribute("max-fds", &this->max_fds, "setting");
71 gloss32::reset_pin_handler(host_int_4 ignore)
73 // Call a virtual method to do the work so derived classes can override.
80 if (max_fds < 0 || max_fds > 256)
82 cerr << "*** Bad value " << max_fds << " for max_fds." << endl;
87 // Close any open files.
88 // FIXME: Undoubtedly incomplete.
89 for (int i = 0; i < max_fds; ++i)
93 if (! host_ops->close (fd_table[i], errcode))
94 cerr << "*** While resetting, close("
96 << ") unexpectedly failed." << endl;
100 fd_table = new int[max_fds];
101 for (int i = 0; i < max_fds; ++i)
108 // Called when rx pin is driven. Record byte in buffer.
111 gloss32::rx_handler(host_int_4 byte)
113 rx_buffer.push_back(byte);
116 // Update our knowledge of what the cpu's endianness is.
119 gloss32::update_endian()
123 cerr << "*** CPU not specified!" << endl;
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))
132 cerr << "Unknown endianness (" << attr_value << "), assuming big" << endl;
133 this->endian = sidutil::endian_big;
137 // Memory access methods.
140 gloss32::get_string(address32 address, string& value, unsigned length)
142 if (! this->cpu_memory_bus)
144 cerr << "*** CPU memory bus not configured!" << endl;
150 cerr << "Reading " << length << " byte(s) from target memory at "
151 << make_numeric_attribute (address, ios::hex | ios::showbase) << ": ";
154 for (unsigned i = 0; i < length; i++)
156 little_int_1 byte; // equivalent to big_int_1
159 bus::status s = this->cpu_memory_bus->read(address, byte);
162 else if (s == bus::delayed)
167 cerr << "failed" << endl;
175 cerr << "[" << c << "]";
177 address = address + 1;
189 gloss32::set_string(address32 address, const string& value)
191 if (! this->cpu_memory_bus)
193 cerr << "*** CPU memory bus not configured!" << endl;
199 cerr << "Writing " << value.size() << " byte(s) to target memory at "
200 << make_numeric_attribute (address, ios::hex | ios::showbase)
204 for (unsigned i=0; i < value.size(); i++)
207 little_int_1 byte = c; // equivalent to big_int_1
210 bus::status s = this->cpu_memory_bus->write(address, byte);
213 else if (s == bus::delayed)
218 cerr << "failed" << endl;
224 cerr << "[" << c << "]";
226 address = address + 1;
236 gloss32::get_word(address32 address, int32& value)
238 if (! cpu_memory_bus)
240 cerr << "*** CPU memory bus not configured!" << endl;
246 cerr << "Reading word from target memory at "
247 << make_numeric_attribute (address, ios::hex | ios::showbase)
255 if (this->endian == sidutil::endian_big)
258 s = this->cpu_memory_bus->read(address, word);
264 s = this->cpu_memory_bus->read(address, word);
270 else if (s == bus::delayed)
275 cerr << "failed" << endl;
281 cerr << make_numeric_attribute (value, ios::hex | ios::showbase) << endl;
287 gloss32::set_word(address32 address, int32 value)
289 if (! cpu_memory_bus)
291 cerr << "*** Target memory bus not configured!" << endl;
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);
306 if (this->endian == sidutil::endian_big)
308 big_int_4 word = value;
309 s = this->cpu_memory_bus->write(address, word);
313 little_int_4 word = value;
314 s = this->cpu_memory_bus->write(address, word);
319 else if (s == bus::delayed)
324 cerr << ": failed" << endl;
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).
342 gloss32::get_pc(address32& value)
346 cerr << "*** CPU not specified!" << endl;
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";
354 string attr_value = this->cpu->attribute_value(attr_name);
355 if (attr_value == "")
357 cerr << "*** Could not read pc!" << endl;
361 host_int_4 value_number;
362 parse_attribute(attr_value, value_number);
363 value = value_number;
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).
373 gloss32::trap_pin_handler(host_int_4 traptype)
376 cerr << "gloss trap " << traptype << " code " << trap_code_pin.sense() << endl;
378 host_int_4 trapcode = this->trap_code_pin.sense ();
380 // Emulatable system call?
381 if (syscall_trap_p())
384 this->blocked_p = false;
385 syscall_trap(); // may set blocked_p
387 trap_type_opin.drive(sidutil::cpu_trap_reissue);
389 trap_type_opin.drive(sidutil::cpu_trap_skip);
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)
400 this->trap_type_opin.drive (chain_response);
403 // No response from handler chain.
405 // Dispatch to general fault handler here.
407 fault_trap (traptype, trapcode);
412 gloss32::fault_trap(host_int_4 trap_type, host_int_4 trap_code)
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" :
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 :
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 :
444 cerr << "Fault (" << trapname;
446 cerr << ", " << make_numeric_attribute (trap_code, ios::hex | ios::showbase);
451 cerr << " pc=" << make_numeric_attribute (pc, ios::hex | ios::showbase) << endl;
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?
456 process_signal_pin.drive(trapsig);
459 trap_type_opin.drive(sidutil::cpu_trap_skip);
463 gloss32::set_host_error_result (int32 host_errno)
465 return set_error_result (host_to_target_errno (host_errno));
468 // Convert host errno value to target.
471 gloss32::host_to_target_errno (int host_errno)
473 return newlib::host_to_target_errno (host_errno);
477 gloss32::get_int_argument(unsigned index, int32& value)
480 string attrName = "syscall-arg";
481 attrName.append(1,'0' + index);
482 assert (attrName != "");
484 string attrValue = cpu->attribute_value (attrName);
487 cerr << "Could not read attribute " << attrName
488 << " for ABI argument #" << index << endl;
492 host_int_4 value_number;
493 parse_attribute(attrValue, value_number);
494 value = value_number;
498 // default argument handling routines
500 gloss32::set_int_result(int32 value)
504 host_int_4 value_number = value;
505 string attrValue = make_attribute(value_number);
507 cpu->set_attribute_value ("syscall-result", attrValue);
508 return true; // XXX: check?
512 gloss32::set_error_result(int32 value)
516 host_int_4 value_number = value;
517 string attrValue = make_attribute(value_number);
519 cpu->set_attribute_value ("syscall-error", attrValue);
520 return true; // XXX: safe to assume success?
525 // default syscall conversion routine
527 gloss32::target_to_host_syscall (int32 target_syscall)
529 return target_syscall;
532 // System call support.
534 gloss32::syscall_trap_p()
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));
544 gloss32::syscall_trap()
548 this->get_int_argument(0, syscall);
550 cerr << "System call number " << syscall << endl;
552 switch (target_to_host_syscall(syscall))
554 case libgloss::SYS_read:
557 case libgloss::SYS_write:
560 case libgloss::SYS_exit:
563 case libgloss::SYS_lseek:
566 case libgloss::SYS_close:
569 case libgloss::SYS_open:
572 case libgloss::SYS_time:
573 set_int_result(time(NULL));
576 do_nonstandard_target_syscalls (syscall);
582 gloss32::do_nonstandard_target_syscalls (int32 target_syscall)
585 cerr << "Unimplemented syscall " << target_syscall << endl;
587 set_error_result(newlib::eNoSys);
591 gloss32::do_sys_exit()
594 get_int_argument(1, value);
596 cerr << "*** exit(" << value << ")" << endl;
599 process_signal_pin.drive(newlib::sigQuit);
601 process_signal_pin.drive(newlib::sigAbrt);
605 gloss32::do_sys_lseek()
607 int32 handle, offset, seek_type;
608 hostops::seek_type whence;
610 get_int_argument(1, handle);
611 get_int_argument(2, offset);
612 get_int_argument(3, seek_type);
617 whence = hostops::seek_cur;
619 whence = hostops::seek_end;
622 whence = hostops::seek_set;
628 if (! this->lseek(handle, offset, whence, new_pos, errcode))
630 set_host_error_result(errcode);
638 gloss32::do_sys_read()
640 int32 handle, str_ptr, str_length;
642 get_int_argument(1, handle);
643 get_int_argument(2, str_ptr);
644 get_int_argument(3, str_length);
648 if (! this->read (handle, str_ptr, str_length, len_read, errcode))
650 set_host_error_result(errcode);
651 // FIXME: what is proper result here?
656 // return number of bytes read.
657 set_int_result(len_read);
661 gloss32::do_sys_write()
664 int32 handle, str_ptr, str_length;
666 get_int_argument(1, handle);
667 get_int_argument(2, str_ptr);
668 get_int_argument(3, str_length);
672 if (! this->write (handle, str_ptr, str_length, len_written, errcode))
674 set_host_error_result(errcode);
679 // return number of bytes written
680 set_int_result(len_written);
684 gloss32::do_sys_close()
688 get_int_argument(1, handle);
691 if (! this->close(handle, errcode))
693 set_host_error_result(errcode);
701 gloss32::do_sys_open()
704 int32 str_ptr, str_length, open_flags, mode, flags;
706 get_int_argument(1, str_ptr);
707 get_int_argument(2, open_flags);
708 get_int_argument(3, mode);
710 get_string(str_ptr, filename, 100);
712 if (!target_to_host_open_flags (open_flags, flags))
714 set_error_result(newlib::eInval);
719 // Check for standard I/O. ":tt" is a magic filename for stdin/stdout.
720 if (filename == ":tt")
723 case (hostops::open_read_only | hostops::open_text):
726 case (hostops::open_write_only | hostops::open_create | hostops::open_trunc | hostops::open_text):
730 set_error_result(newlib::eInval);
737 int result_fd,errcode;
739 if ((flags & hostops::open_create) != 0)
741 if (! this->open (filename, flags, mode, result_fd, errcode))
743 set_host_error_result (errcode);
747 set_int_result (result_fd);
751 if (! this->open (filename, flags, result_fd, errcode))
753 set_host_error_result (errcode);
757 set_int_result (result_fd);
762 gloss32::target_to_host_open_flags (int open_flags, int& flags)
767 flags = hostops::open_read_only | hostops::open_text;
770 flags = hostops::open_read_only;
773 flags = hostops::open_read_write | hostops::open_text;
776 flags = hostops::open_read_write;
779 flags = hostops::open_write_only | hostops::open_create | hostops::open_trunc | hostops::open_text;
782 flags = hostops::open_write_only | hostops::open_create | hostops::open_trunc;
785 flags = hostops::open_read_write | hostops::open_create | hostops::open_trunc | hostops::open_text;
788 flags = hostops::open_read_write | hostops::open_create | hostops::open_trunc;
791 flags = hostops::open_write_only | hostops::open_create | hostops::open_append | hostops::open_text;
794 flags = hostops::open_write_only | hostops::open_create | hostops::open_append;
797 flags = hostops::open_read_write | hostops::open_create | hostops::open_append | hostops::open_text;
800 flags = hostops::open_read_write | hostops::open_create | hostops::open_append;
809 gloss32::lookup_fd (int target_fd)
811 if (target_fd < 0 || target_fd >= max_fds)
813 return fd_table[target_fd];
816 // Return unused fd or -1 if table is full.
817 // Allocating the fd is left to the caller.
820 gloss32::unused_fd ()
822 for (int i = 0; i < max_fds; ++i)
824 if (fd_table[i] == -1)
830 // Record target_fd/host_fd mapping.
833 gloss32::alloc_fd (int target_fd, int host_fd)
835 fd_table[target_fd] = host_fd;
839 gloss32::free_fd (int target_fd)
841 assert (target_fd >= 0 && target_fd < max_fds);
842 fd_table[target_fd] = -1;
846 gloss32::open (string filename, int flags, int& result_fd, int& errcode)
848 int host_fd,target_fd;
851 cerr << "*** open(" << filename << ", " << flags << ")";
853 target_fd = unused_fd ();
857 cerr << " -> failed, EMFILE" << endl;
862 if (! host_ops->open (filename.c_str (), flags, host_fd, errcode))
865 cerr << " -> failed, " << errcode << endl;
868 alloc_fd (target_fd, host_fd);
869 result_fd = target_fd;
872 cerr << " -> " << result_fd << endl;
878 gloss32::open (string filename, int flags, int mode, int& result_fd, int& errcode)
880 int host_fd,target_fd;
883 cerr << "*** open(" << filename << ", " << flags << ", " << mode << ")";
885 target_fd = unused_fd ();
889 cerr << " -> failed, EMFILE" << endl;
894 if (! host_ops->open (filename.c_str (), flags, mode, host_fd, errcode))
897 cerr << " -> failed, " << errcode << endl;
900 alloc_fd (target_fd, host_fd);
901 result_fd = target_fd;
904 cerr << " -> " << result_fd << endl;
910 gloss32::close (int fd, int& errcode)
916 host_fd = lookup_fd (fd);
923 if (! host_ops->close (host_fd, errcode))
929 // ??? 64 bit host edge conditions
932 gloss32::read (int fd, address32 addr, size32 len,
933 size32& len_read, int& errcode)
935 int host_fd = lookup_fd (fd);
937 // Special handling for stdin.
938 // If it hasn't been closed/reopened, use rx-pin.
939 int use_rx_p = (fd == 0
943 cerr << "*** read(" << fd << "," << addr << "," << len << ")" << endl;
951 // Read a chunk at a time to reduce number of host syscalls.
952 const unsigned int xfr_size = 4096; // ???
954 string strbuf; // ???
956 size32 total_read = 0;
965 if (rx_buffer.size() > 0)
967 c = rx_buffer.front();
968 rx_buffer.erase(rx_buffer.begin());
972 this->blocked_p = true;
981 size32 count = len > xfr_size ? xfr_size : len;
983 // Read the next chunk from the file.
985 if (! host_ops->read32 (host_fd, buf, count, count_read, errcode))
987 // If we've already read something, return with that.
990 len_read = total_read;
997 len_read = total_read;
1000 strbuf.assign (buf, count_read); // ???
1003 // Write chunk to memory.
1005 if (! set_string (addr, strbuf))
1007 // FIXME: Signal error or return amount read (through to
1008 // memory) thus far?
1009 // FIXME: Should reset file position.
1013 len_read = total_read;
1017 errcode = EINVAL; // ???
1021 addr = addr + count_read;
1022 total_read += count_read;
1026 len_read = total_read;
1030 // ??? 64 bit host edge conditions
1033 gloss32::write (int fd, address32 addr, size32 len,
1034 size32& len_written, int& errcode)
1036 int host_fd = lookup_fd (fd);
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)
1045 cerr << "*** write(" << fd << "," << addr << "," << len << ")" << endl;
1053 // Write a chunk at a time to reduce number of host system calls.
1054 const unsigned int xfr_size = 4096; // ???
1056 size32 total_written = 0;
1059 string buf; // ??? Previously allocated char array?
1061 size32 count = len > xfr_size ? xfr_size : len;
1063 // Read next chunk from memory.
1065 if (! get_string (addr, buf, count))
1067 // FIXME: Signal error or return amount written thus far?
1068 // FIXME: Should reset file position.
1070 if (total_written > 0)
1072 len_written = total_written;
1076 errcode = EINVAL; // ???
1080 addr = addr + count;
1082 // Write chunk to file.
1084 unsigned int count_written;
1089 for (i = 0; i < count; ++i)
1091 host_int_4 value = buf[i];
1092 tx_pin.drive(value);
1098 if (! host_ops->write32 (host_fd, buf.c_str(), count, count_written, errcode))
1100 // If we've already written something, return with that.
1101 if (total_written > 0)
1103 len_written = total_written;
1109 if (count_written == 0)
1111 len_written = total_written;
1115 total_written += count_written;
1116 len -= count_written;
1119 len_written = total_written;
1124 gloss32::remove (string filename, int& errcode)
1126 return host_ops->remove (filename.c_str (), errcode);
1130 gloss32::rename (string oldname, string newname, int& errcode)
1132 return host_ops->rename (oldname.c_str (), newname.c_str (), errcode);
1136 gloss32::lseek (int fd, offset32 offset, hostops::seek_type how,
1137 size32& result, int& errcode)
1140 cerr << "*** lseek(" << fd << ", " << offset << ", " << (int) how << ")";
1142 int host_fd = lookup_fd (fd);
1146 cerr << " -> failed, EBADF" << endl;
1152 if (! host_ops->lseek32 (host_fd, offset, how, new_pos, errcode))
1155 cerr << " -> failed, " << errcode << endl;
1160 cerr << " -> " << new_pos << endl;
1166 gloss32::getsize (int fd, size32& size, int& errcode)
1168 int host_fd = lookup_fd (fd);
1174 return host_ops->getsize32 (host_fd, size, errcode);
1178 gloss32::tmpnam (string& filename, int& errcode)
1180 char filename_buf[1024]; // FIXME
1182 if (! host_ops->tmpnam (filename_buf, errcode))
1184 filename = filename_buf;
1189 gloss32::isatty (int fd, bool& result, int& errcode)
1191 int host_fd = lookup_fd (fd);
1198 // FIXME: Quick hack.
1199 if (host_fd == 0 || host_fd == 1 || host_fd == 2)