diff options
Diffstat (limited to 'tools/ioemu/iodev/devices.cc')
-rw-r--r-- | tools/ioemu/iodev/devices.cc | 685 |
1 files changed, 685 insertions, 0 deletions
diff --git a/tools/ioemu/iodev/devices.cc b/tools/ioemu/iodev/devices.cc new file mode 100644 index 0000000000..5dd7f5daa3 --- /dev/null +++ b/tools/ioemu/iodev/devices.cc @@ -0,0 +1,685 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +#include "bochs.h" +#define LOG_THIS bx_devices. + + + +/* main memory size (in Kbytes) + * subtract 1k for extended BIOS area + * report only base memory, not extended mem + */ +#define BASE_MEMORY_IN_K 640 + + +bx_devices_c bx_devices; + + + + +// constructor for bx_devices_c +bx_devices_c::bx_devices_c(void) +{ + put("DEV"); + settype(DEVLOG); + +#if BX_PCI_SUPPORT + pluginPciBridge = &stubPci; + pluginPci2IsaBridge = NULL; +#if BX_PCI_VGA_SUPPORT + pluginPciVgaAdapter = NULL; +#endif +#if BX_PCI_USB_SUPPORT + pluginPciUSBAdapter = NULL; +#endif +#endif + pit = NULL; + pluginKeyboard = &stubKeyboard; + pluginDmaDevice = &stubDma; + pluginFloppyDevice = &stubFloppy; + pluginBiosDevice = NULL; + pluginCmosDevice = &stubCmos; + pluginSerialDevice = NULL; + pluginParallelDevice = NULL; + pluginUnmapped = NULL; + pluginVgaDevice = &stubVga; + pluginPicDevice = &stubPic; + pluginHardDrive = &stubHardDrive; + pluginSB16Device = NULL; + pluginNE2kDevice =&stubNE2k; + pluginExtFpuIrq = NULL; + pluginGameport = NULL; + g2h = NULL; +#if BX_IODEBUG_SUPPORT + iodebug = NULL; +#endif +} + + +bx_devices_c::~bx_devices_c(void) +{ + // nothing needed for now + BX_DEBUG(("Exit.")); + timer_handle = BX_NULL_TIMER_HANDLE; +} + + + void +bx_devices_c::init(BX_MEM_C *newmem) +{ + unsigned i; + + BX_DEBUG(("Init $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $")); + mem = newmem; + + /* no read / write handlers defined */ + num_read_handles = 0; + num_write_handles = 0; + + /* set unused elements to appropriate values */ + for (i=0; i < BX_MAX_IO_DEVICES; i++) { + io_read_handler[i].funct = NULL; + io_write_handler[i].funct = NULL; + } + + /* set no-default handlers, will be overwritten by the real default handler */ + io_read_handler[BX_DEFAULT_IO_DEVICE].handler_name = "Default"; + io_read_handler[BX_DEFAULT_IO_DEVICE].funct = &default_read_handler; + io_read_handler[BX_DEFAULT_IO_DEVICE].this_ptr = NULL; + io_read_handler[BX_DEFAULT_IO_DEVICE].mask = 7; + io_write_handler[BX_DEFAULT_IO_DEVICE].handler_name = "Default"; + io_write_handler[BX_DEFAULT_IO_DEVICE].funct = &default_write_handler; + io_write_handler[BX_DEFAULT_IO_DEVICE].this_ptr = NULL; + io_write_handler[BX_DEFAULT_IO_DEVICE].mask = 7; + + /* set handlers to the default one */ + for (i=0; i < 0x10000; i++) { + read_handler_id[i] = BX_DEFAULT_IO_DEVICE; + write_handler_id[i] = BX_DEFAULT_IO_DEVICE; + } + + for (i=0; i < BX_MAX_IRQS; i++) { + irq_handler_name[i] = NULL; + } + + // BBD: At present, the only difference between "core" and "optional" + // plugins is that initialization and reset of optional plugins is handled + // by the plugin device list (). Init and reset of core plugins is done + // "by hand" in this file. Basically, we're using core plugins when we + // want to control the init order. + // + // CB: UNMAPPED and BIOSDEV should maybe be optional + PLUG_load_plugin(unmapped, PLUGTYPE_CORE); + PLUG_load_plugin(biosdev, PLUGTYPE_CORE); + PLUG_load_plugin(cmos, PLUGTYPE_CORE); + PLUG_load_plugin(dma, PLUGTYPE_CORE); + PLUG_load_plugin(pic, PLUGTYPE_CORE); + PLUG_load_plugin(vga, PLUGTYPE_CORE); + PLUG_load_plugin(floppy, PLUGTYPE_CORE); + PLUG_load_plugin(harddrv, PLUGTYPE_OPTIONAL); + PLUG_load_plugin(keyboard, PLUGTYPE_OPTIONAL); + if (is_serial_enabled ()) + PLUG_load_plugin(serial, PLUGTYPE_OPTIONAL); + if (is_parallel_enabled ()) + PLUG_load_plugin(parallel, PLUGTYPE_OPTIONAL); + PLUG_load_plugin(extfpuirq, PLUGTYPE_OPTIONAL); +#if BX_SUPPORT_GAME + PLUG_load_plugin(gameport, PLUGTYPE_OPTIONAL); +#endif + + // Start with registering the default (unmapped) handler + pluginUnmapped->init (); + + // PCI logic (i440FX) + if (bx_options.Oi440FXSupport->get ()) { +#if BX_PCI_SUPPORT + PLUG_load_plugin(pci, PLUGTYPE_OPTIONAL); + PLUG_load_plugin(pci2isa, PLUGTYPE_OPTIONAL); +#if BX_PCI_VGA_SUPPORT + PLUG_load_plugin(pcivga, PLUGTYPE_OPTIONAL); +#endif +#if BX_PCI_USB_SUPPORT + PLUG_load_plugin(pciusb, PLUGTYPE_OPTIONAL); +#endif +#else + BX_ERROR(("Bochs is not compiled with PCI support")); +#endif + } + +#if BX_SUPPORT_APIC + // I/O APIC 82093AA + ioapic = & bx_ioapic; + ioapic->init (); +#endif + + // BIOS log + pluginBiosDevice->init (); + + // CMOS RAM & RTC + pluginCmosDevice->init (); + + /*--- 8237 DMA ---*/ + pluginDmaDevice->init(); + + //--- FLOPPY --- + pluginFloppyDevice->init(); + + //--- SOUND --- + if (bx_options.sb16.Opresent->get ()) { +#if BX_SUPPORT_SB16 + PLUG_load_plugin(sb16, PLUGTYPE_OPTIONAL); +#else + BX_ERROR(("Bochs is not compiled with SB16 support")); +#endif + } + + /*--- VGA adapter ---*/ + pluginVgaDevice->init (); + + /*--- 8259A PIC ---*/ + pluginPicDevice->init(); + + /*--- 8254 PIT ---*/ + pit = & bx_pit; + pit->init(); + + bx_virt_timer.init(); + + bx_slowdown_timer.init(); + +#if BX_IODEBUG_SUPPORT + iodebug = &bx_iodebug; + iodebug->init(); +#endif + + // NE2000 NIC + if (bx_options.ne2k.Opresent->get ()) { +#if BX_NE2K_SUPPORT + PLUG_load_plugin(ne2k, PLUGTYPE_OPTIONAL); +#else + BX_ERROR(("Bochs is not compiled with NE2K support")); +#endif + } + +#if 0 + // Guest to Host interface. Used with special guest drivers + // which move data to/from the host environment. + g2h = &bx_g2h; + g2h->init(); +#endif + + // system hardware + register_io_read_handler( this, + &read_handler, + 0x0092, + "Port 92h System Control", 1 ); + register_io_write_handler(this, + &write_handler, + 0x0092, + "Port 92h System Control", 1 ); + + // misc. CMOS + Bit32u extended_memory_in_k = mem->get_memory_in_k() > 1024 ? (mem->get_memory_in_k() - 1024) : 0; + if (extended_memory_in_k > 0xffff) extended_memory_in_k = 0xffff; + + DEV_cmos_set_reg(0x15, (Bit8u) BASE_MEMORY_IN_K); + DEV_cmos_set_reg(0x16, (Bit8u) (BASE_MEMORY_IN_K >> 8)); + DEV_cmos_set_reg(0x17, (Bit8u) (extended_memory_in_k & 0xff) ); + DEV_cmos_set_reg(0x18, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) ); + DEV_cmos_set_reg(0x30, (Bit8u) (extended_memory_in_k & 0xff) ); + DEV_cmos_set_reg(0x31, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) ); + + Bit32u extended_memory_in_64k = mem->get_memory_in_k() > 16384 ? (mem->get_memory_in_k() - 16384) / 64 : 0; + if (extended_memory_in_64k > 0xffff) extended_memory_in_64k = 0xffff; + + DEV_cmos_set_reg(0x34, (Bit8u) (extended_memory_in_64k & 0xff) ); + DEV_cmos_set_reg(0x35, (Bit8u) ((extended_memory_in_64k >> 8) & 0xff) ); + + if (timer_handle != BX_NULL_TIMER_HANDLE) { + timer_handle = bx_pc_system.register_timer( this, timer_handler, + (unsigned) BX_IODEV_HANDLER_PERIOD, 1, 1, "devices.cc"); + } + + // Clear fields for bulk IO acceleration transfers. + bulkIOHostAddr = 0; + bulkIOQuantumsRequested = 0; + bulkIOQuantumsTransferred = 0; + + bx_init_plugins(); + + /* now perform checksum of CMOS memory */ + DEV_cmos_checksum(); +} + + + void +bx_devices_c::reset(unsigned type) +{ + pluginUnmapped->reset(type); +#if BX_PCI_SUPPORT + if (bx_options.Oi440FXSupport->get ()) { + pluginPciBridge->reset(type); + pluginPci2IsaBridge->reset(type); +#if BX_PCI_VGA_SUPPORT + pluginPciVgaAdapter->reset(type); +#endif +#if BX_PCI_USB_SUPPORT + pluginPciUSBAdapter->reset(type); +#endif + } +#endif +#if BX_SUPPORT_IOAPIC + ioapic->reset (type); +#endif + pluginBiosDevice->reset(type); + pluginCmosDevice->reset(type); + pluginDmaDevice->reset(type); + pluginFloppyDevice->reset(type); +#if BX_SUPPORT_SB16 + if (pluginSB16Device) pluginSB16Device->reset(type); +#endif + pluginVgaDevice->reset(type); + pluginPicDevice->reset(type); + pit->reset(type); + bx_slowdown_timer.reset(type); +#if BX_IODEBUG_SUPPORT + iodebug->reset(type); +#endif +#if BX_NE2K_SUPPORT + if (pluginNE2kDevice) pluginNE2kDevice->reset(type); +#endif + + bx_reset_plugins(type); +} + + + Bit32u +bx_devices_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len) +{ +#if !BX_USE_DEV_SMF + bx_devices_c *class_ptr = (bx_devices_c *) this_ptr; + + return( class_ptr->port92_read(address, io_len) ); +} + + + Bit32u +bx_devices_c::port92_read(Bit32u address, unsigned io_len) +{ +#else + UNUSED(this_ptr); +#endif // !BX_USE_DEV_SMF + + BX_DEBUG(("port92h read partially supported!!!")); + BX_DEBUG((" returning %02x", (unsigned) (BX_GET_ENABLE_A20() << 1))); + return(BX_GET_ENABLE_A20() << 1); +} + + + void +bx_devices_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len) +{ +#if !BX_USE_DEV_SMF + bx_devices_c *class_ptr = (bx_devices_c *) this_ptr; + + class_ptr->port92_write(address, value, io_len); +} + + void +bx_devices_c::port92_write(Bit32u address, Bit32u value, unsigned io_len) +{ +#else + UNUSED(this_ptr); +#endif // !BX_USE_DEV_SMF + bx_bool bx_cpu_reset; + + BX_DEBUG(("port92h write of %02x partially supported!!!", + (unsigned) value)); + BX_DEBUG(("A20: set_enable_a20() called")); + BX_SET_ENABLE_A20( (value & 0x02) >> 1 ); + BX_DEBUG(("A20: now %u", (unsigned) BX_GET_ENABLE_A20())); + bx_cpu_reset = (value & 0x01); /* high speed reset */ + if (bx_cpu_reset) { + BX_PANIC(("PORT 92h write: CPU reset requested!")); + } +} + + +// This defines a no-default read handler, +// so Bochs does not segfault if unmapped is not loaded + Bit32u +bx_devices_c::default_read_handler(void *this_ptr, Bit32u address, unsigned io_len) +{ + UNUSED(this_ptr); + BX_PANIC(("No default io-read handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len)); + return 0xffffffff; +} + +// This defines a no-default write handler, +// so Bochs does not segfault if unmapped is not loaded + void +bx_devices_c::default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len) +{ + UNUSED(this_ptr); + BX_PANIC(("No default io-write handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len)); +} + + void +bx_devices_c::timer_handler(void *this_ptr) +{ + bx_devices_c *class_ptr = (bx_devices_c *) this_ptr; + + class_ptr->timer(); +} + + void +bx_devices_c::timer() +{ +#if (BX_USE_NEW_PIT==0) + if ( pit->periodic( BX_IODEV_HANDLER_PERIOD ) ) { + // This is a hack to make the IRQ0 work + DEV_pic_lower_irq(0); + DEV_pic_raise_irq(0); + } +#endif + + + // separate calls to bx_gui->handle_events from the keyboard code. + { + static int multiple=0; + if ( ++multiple==10) + { + multiple=0; + SIM->periodic (); + if (!BX_CPU(0)->kill_bochs_request) + bx_gui->handle_events(); + } + } + +// KPL Removed lapic periodic timer registration here. +} + + + bx_bool +bx_devices_c::register_irq(unsigned irq, const char *name) +{ + if (irq >= BX_MAX_IRQS) { + BX_PANIC(("IO device %s registered with IRQ=%d above %u", + name, irq, (unsigned) BX_MAX_IRQS-1)); + return false; + } + if (irq_handler_name[irq]) { + BX_PANIC(("IRQ %u conflict, %s with %s", irq, + irq_handler_name[irq], name)); + return false; + } + irq_handler_name[irq] = name; + return true; +} + + bx_bool +bx_devices_c::unregister_irq(unsigned irq, const char *name) +{ + if (irq >= BX_MAX_IRQS) { + BX_PANIC(("IO device %s tried to unregister IRQ %d above %u", + name, irq, (unsigned) BX_MAX_IRQS-1)); + return false; + } + + if (!irq_handler_name[irq]) { + BX_INFO(("IO device %s tried to unregister IRQ %d, not registered", + name, irq)); + return false; + } + + if (strcmp(irq_handler_name[irq], name)) { + BX_INFO(("IRQ %u not registered to %s but to %s", irq, + name, irq_handler_name[irq])); + return false; + } + irq_handler_name[irq] = NULL; + return true; +} + + bx_bool +bx_devices_c::register_io_read_handler( void *this_ptr, bx_read_handler_t f, + Bit32u addr, const char *name, Bit8u mask ) +{ + unsigned handle; + + addr &= 0x0000ffff; + + /* first find existing handle for function or create new one */ + for (handle=0; handle < num_read_handles; handle++) { + if ((io_read_handler[handle].funct == f) && + (io_read_handler[handle].mask == mask)) break; + } + + if (handle >= num_read_handles) { + /* no existing handle found, create new one */ + if (num_read_handles >= BX_DEFAULT_IO_DEVICE) { + BX_INFO(("too many IO devices installed.")); + BX_PANIC((" try increasing BX_MAX_IO_DEVICES")); + } + num_read_handles++; + io_read_handler[handle].funct = f; + io_read_handler[handle].this_ptr = this_ptr; + io_read_handler[handle].handler_name = name; + io_read_handler[handle].mask = mask; + } + + /* change table to reflect new handler id for that address */ + if (read_handler_id[addr] < BX_DEFAULT_IO_DEVICE) { + // another handler is already registered for that address + BX_ERROR(("IO device address conflict(read) at IO address %Xh", + (unsigned) addr)); + BX_ERROR((" conflicting devices: %s & %s", + io_read_handler[handle].handler_name, io_read_handler[read_handler_id[addr]].handler_name)); + return false; // address not available, return false. + } + read_handler_id[addr] = handle; + return true; // address mapped successfully +} + + + + bx_bool +bx_devices_c::register_io_write_handler( void *this_ptr, bx_write_handler_t f, + Bit32u addr, const char *name, Bit8u mask ) +{ + unsigned handle; + + addr &= 0x0000ffff; + + /* first find existing handle for function or create new one */ + for (handle=0; handle < num_write_handles; handle++) { + if ((io_write_handler[handle].funct == f) && + (io_write_handler[handle].mask == mask)) break; + } + + if (handle >= num_write_handles) { + /* no existing handle found, create new one */ + if (num_write_handles >= BX_DEFAULT_IO_DEVICE) { + BX_INFO(("too many IO devices installed.")); + BX_PANIC((" try increasing BX_MAX_IO_DEVICES")); + } + num_write_handles++; + io_write_handler[handle].funct = f; + io_write_handler[handle].this_ptr = this_ptr; + io_write_handler[handle].handler_name = name; + io_write_handler[handle].mask = mask; + } + + /* change table to reflect new handler id for that address */ + if (write_handler_id[addr] < BX_DEFAULT_IO_DEVICE) { + // another handler is already registered for that address + BX_ERROR(("IO device address conflict(write) at IO address %Xh", + (unsigned) addr)); + BX_ERROR((" conflicting devices: %s & %s", + io_write_handler[handle].handler_name, io_write_handler[write_handler_id[addr]].handler_name)); + return false; //unable to map iodevice. + } + write_handler_id[addr] = handle; + return true; // done! +} + + +// Registration of default handlers (mainly be the unmapped device) +// The trick here is to define a handler for the max index, so +// unregisterd io address will get handled by the default function +// This will be helpful when we want to unregister io handlers + + bx_bool +bx_devices_c::register_default_io_read_handler( void *this_ptr, bx_read_handler_t f, + const char *name, Bit8u mask ) +{ + unsigned handle; + + /* handle is fixed to the default I/O device */ + handle = BX_DEFAULT_IO_DEVICE; + + if (strcmp(io_read_handler[handle].handler_name, "Default")) { + BX_ERROR(("Default io read handler already registered '%s'",io_read_handler[handle].handler_name)); + return false; + } + + io_read_handler[handle].funct = f; + io_read_handler[handle].this_ptr = this_ptr; + io_read_handler[handle].handler_name = name; + io_read_handler[handle].mask = mask; + + return true; +} + + + + bx_bool +bx_devices_c::register_default_io_write_handler( void *this_ptr, bx_write_handler_t f, + const char *name, Bit8u mask ) +{ + unsigned handle; + + /* handle is fixed to the MAX */ + handle = BX_DEFAULT_IO_DEVICE; + + if (strcmp(io_write_handler[handle].handler_name, "Default")) { + BX_ERROR(("Default io write handler already registered '%s'",io_write_handler[handle].handler_name)); + return false; + } + + io_write_handler[handle].funct = f; + io_write_handler[handle].this_ptr = this_ptr; + io_write_handler[handle].handler_name = name; + io_write_handler[handle].mask = mask; + + return true; +} + + + +/* + * Read a byte of data from the IO memory address space + */ + + Bit32u BX_CPP_AttrRegparmN(2) +bx_devices_c::inp(Bit16u addr, unsigned io_len) +{ + Bit8u handle; + Bit32u ret; + + BX_INSTR_INP(addr, io_len); + + handle = read_handler_id[addr]; + if ((io_read_handler[handle].funct != NULL) && + (io_read_handler[handle].mask & io_len)) { + ret = (* io_read_handler[handle].funct)(io_read_handler[handle].this_ptr, + (Bit32u) addr, io_len); + } else { + switch (io_len) { + case 1: ret = 0xff; break; + case 2: ret = 0xffff; break; + default: ret = 0xffffffff; break; + } + BX_ERROR(("read from port 0x%04x with len %d returns 0x%x", addr, io_len, ret)); + } + BX_INSTR_INP2(addr, io_len, ret); + BX_DBG_IO_REPORT(addr, io_len, BX_READ, ret); + + return(ret); +} + + +/* + * Write a byte of data to the IO memory address space. + */ + + void BX_CPP_AttrRegparmN(3) +bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned io_len) +{ + Bit8u handle; + + BX_INSTR_OUTP(addr, io_len); + BX_INSTR_OUTP2(addr, io_len, value); + + BX_DBG_IO_REPORT(addr, io_len, BX_WRITE, value); + handle = write_handler_id[addr]; + if ((io_write_handler[handle].funct != NULL) && + (io_write_handler[handle].mask & io_len)) { + (* io_write_handler[handle].funct)(io_write_handler[handle].this_ptr, + (Bit32u) addr, value, io_len); + } else { + BX_ERROR(("write to port 0x%04x with len %d ignored", addr, io_len)); + } +} + +bx_bool bx_devices_c::is_serial_enabled () +{ + for (int i=0; i<BX_N_SERIAL_PORTS; i++) { + if (SIM->get_param_bool (BXP_COMx_ENABLED(i+1))->get()) + return true; + } + return false; +} + +bx_bool bx_devices_c::is_usb_enabled () +{ + for (int i=0; i<BX_N_USB_HUBS; i++) { + if (SIM->get_param_bool (BXP_USBx_ENABLED(i+1))->get()) + return true; + } + return false; +} + +bx_bool bx_devices_c::is_parallel_enabled () +{ + for (int i=0; i<BX_N_PARALLEL_PORTS; i++) { + if (SIM->get_param_bool (BXP_PARPORTx_ENABLED(i+1))->get()) + return true; + } + return false; +} |