another directory rename: failstar -> fail

"failstar" sounds like a name for a cruise liner from the 80s.  As "*" isn't a
desirable part of directory names, just name the whole thing "fail/", the core
parts being stored in "fail/core/".

Additionally fixing two build system dependency issues:
 - missing jobserver -> protomessages dependency
 - broken bochs -> fail dependency (add_custom_target DEPENDS only allows plain
   file dependencies ... cmake for the win)


git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@956 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
hsc
2012-03-08 19:43:02 +00:00
commit b70b6fb43a
921 changed files with 473161 additions and 0 deletions

899
bochs/iodev/Makefile.in Normal file
View File

@ -0,0 +1,899 @@
# Copyright (C) 2001 The Bochs Project
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# Makefile for the iodev component of bochs
@SUFFIX_LINE@
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = @srcdir@
bindir = @bindir@
libdir = @libdir@
datarootdir = @datarootdir@
mandir = @mandir@
man1dir = $(mandir)/man1
man5dir = $(mandir)/man5
docdir = $(datarootdir)/doc/bochs
sharedir = $(datarootdir)/bochs
top_builddir = ..
top_srcdir = @top_srcdir@
SHELL = /bin/sh
@SET_MAKE@
CXX = @CXX@
CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@ @GUI_CXXFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
RANLIB = @RANLIB@
PLUGIN_PATH=@libdir@
top_builddir = ..
LIBTOOL=@LIBTOOL@
WIN32_DLL_IMPORT_LIBRARY=../dllexports.a
CDROM_OBJS = @CDROM_OBJS@
SOUNDLOW_OBJS = @SOUNDLOW_OBJS@
NETLOW_OBJS = @NETLOW_OBJS@
USBDEV_OBJS = @USBDEV_OBJS@
SCSI_OBJS = @SCSI_OBJS@
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
LOCAL_CXXFLAGS = $(MCH_CFLAGS)
PCIDEV_CXXFLAGS = -I$(srcdir)/../host/linux/pcidev
OBJS_THAT_CANNOT_BE_PLUGINS = \
devices.o \
virt_timer.o \
slowdown_timer.o \
$(MCH_OBJS)
OBJS_THAT_CAN_BE_PLUGINS = \
pic.o \
pit_wrap.o \
serial.o \
parallel.o \
floppy.o \
keyboard.o \
vga.o \
biosdev.o \
cmos.o \
harddrv.o \
hdimage.o \
dma.o \
unmapped.o \
extfpuirq.o \
speaker.o \
busmouse.o \
ioapic.o \
soundmod.o \
@GAME_OBJS@ \
@PCI_OBJ@ \
@USBCORE_OBJ@ \
@SB16_OBJS@ \
@NE2K_OBJS@ \
@IODEBUG_OBJS@
OBJS_THAT_SUPPORT_OTHER_PLUGINS = \
pit82c54.o \
scancodes.o \
serial_raw.o \
svga_cirrus.o \
vmware3.o \
vmware4.o \
vvfat.o \
$(CDROM_OBJS) \
$(SOUNDLOW_OBJS) \
$(NETLOW_OBJS) \
$(USBDEV_OBJS) \
$(SCSI_OBJS)
NONPLUGIN_OBJS = @IODEV_NON_PLUGIN_OBJS@
PLUGIN_OBJS = @IODEV_PLUGIN_OBJS@
SOUND_LINK_OPTS = @SOUND_LINK_OPTS@
all: libiodev.a
plugins: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@)
libiodev.a: $(NONPLUGIN_OBJS)
@RMCOMMAND@ libiodev.a
@MAKELIB@ $(NONPLUGIN_OBJS)
@RANLIB@ libiodev.a
# standard compile rule for C++ files
.@CPP_SUFFIX@.o:
$(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
pcidev.o : pcidev.@CPP_SUFFIX@
$(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(PCIDEV_CXXFLAGS) @CXXFP@$< @OFP@$@
##### building plugins with libtool
%.lo: %.@CPP_SUFFIX@
$(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
pcidev.lo : pcidev.@CPP_SUFFIX@
$(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(PCIDEV_CXXFLAGS) $< -o $@
libbx_%.la: %.lo
$(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH)
# special link rules for plugins that require more than one object file
libbx_harddrv.la: harddrv.lo $(CDROM_OBJS:.o=.lo)
$(LIBTOOL) --mode=link $(CXX) -module harddrv.lo $(CDROM_OBJS:.o=.lo) -o libbx_harddrv.la -rpath $(PLUGIN_PATH)
libbx_hdimage.la: hdimage.lo vmware3.lo vmware4.lo vvfat.lo
$(LIBTOOL) --mode=link $(CXX) -module hdimage.lo vmware3.lo vmware4.lo vvfat.lo -o libbx_hdimage.la -rpath $(PLUGIN_PATH)
libbx_keyboard.la: keyboard.lo scancodes.lo
$(LIBTOOL) --mode=link $(CXX) -module keyboard.lo scancodes.lo -o libbx_keyboard.la -rpath $(PLUGIN_PATH)
libbx_pit_wrap.la: pit82c54.lo pit_wrap.lo
$(LIBTOOL) --mode=link $(CXX) -module pit82c54.lo pit_wrap.lo -o libbx_pit.la -rpath $(PLUGIN_PATH)
libbx_soundmod.la: soundmod.lo $(SOUNDLOW_OBJS:.o=.lo)
$(LIBTOOL) --mode=link $(CXX) -module soundmod.lo $(SOUNDLOW_OBJS:.o=.lo) -o libbx_soundmod.la -rpath $(PLUGIN_PATH) $(SOUND_LINK_OPTS)
libbx_ne2k.la: ne2k.lo $(NETLOW_OBJS:.o=.lo)
$(LIBTOOL) --mode=link $(CXX) -module ne2k.lo $(NETLOW_OBJS:.o=.lo) -o libbx_ne2k.la -rpath $(PLUGIN_PATH)
libbx_pcipnic.la: pcipnic.lo $(NETLOW_OBJS:.o=.lo)
$(LIBTOOL) --mode=link $(CXX) -module pcipnic.lo $(NETLOW_OBJS:.o=.lo) -o libbx_pcipnic.la -rpath $(PLUGIN_PATH)
libbx_serial.la: serial.lo serial_raw.lo
$(LIBTOOL) --mode=link $(CXX) -module serial.lo serial_raw.lo -o libbx_serial.la -rpath $(PLUGIN_PATH)
libbx_vga.la: vga.lo svga_cirrus.lo
$(LIBTOOL) --mode=link $(CXX) -module vga.lo svga_cirrus.lo -o libbx_vga.la -rpath $(PLUGIN_PATH)
libbx_usb_common.la: usb_common.lo $(USBDEV_OBJS:.o=.lo) scsi_device.lo $(CDROM_OBJS:.o=.lo)
$(LIBTOOL) --mode=link $(CXX) -module usb_common.lo $(USBDEV_OBJS:.o=.lo) scsi_device.lo $(CDROM_OBJS:.o=.lo) -o libbx_usb_common.la -rpath $(PLUGIN_PATH)
#### building DLLs for win32 (tested on cygwin only)
bx_%.dll: %.o
$(CXX) $(CXXFLAGS) -shared -o $@ $< $(WIN32_DLL_IMPORT_LIBRARY)
# special link rules for plugins that require more than one object file
bx_harddrv.dll: harddrv.o $(CDROM_OBJS)
$(CXX) $(CXXFLAGS) -shared -o bx_harddrv.dll harddrv.o $(CDROM_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
bx_hdimage.dll: hdimage.o vmware3.o vmware4.o vvfat.o
$(CXX) $(CXXFLAGS) -shared -o bx_hdimage.dll hdimage.o vmware3.o vmware4.o vvfat.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_keyboard.dll: keyboard.o scancodes.o
$(CXX) $(CXXFLAGS) -shared -o bx_keyboard.dll keyboard.o scancodes.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_pit_wrap.dll: pit82c54.o pit_wrap.o
$(CXX) $(CXXFLAGS) -shared -o bx_pit.dll pit82c54.o pit_wrap.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_soundmod.dll: soundmod.o $(SOUNDLOW_OBJS)
$(CXX) $(CXXFLAGS) -shared -o bx_soundmod.dll soundmod.o $(SOUNDLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY) -lwinmm
bx_ne2k.dll: ne2k.o $(NETLOW_OBJS)
$(CXX) $(CXXFLAGS) -shared -o bx_ne2k.dll ne2k.o $(NETLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
bx_pcipnic.dll: pcipnic.o $(NETLOW_OBJS)
$(CXX) $(CXXFLAGS) -shared -o bx_pcipnic.dll pcipnic.o $(NETLOW_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
bx_gameport.dll: gameport.o
$(CXX) $(CXXFLAGS) -shared -o bx_gameport.dll gameport.o $(WIN32_DLL_IMPORT_LIBRARY) -lwinmm
bx_serial.dll: serial.o serial_raw.o
$(CXX) $(CXXFLAGS) -shared -o bx_serial.dll serial.o serial_raw.o $(WIN32_DLL_IMPORT_LIBRARY) -lwsock32
bx_vga.dll: vga.o svga_cirrus.o
$(CXX) $(CXXFLAGS) -shared -o bx_vga.dll vga.o svga_cirrus.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_usb_common.dll: usb_common.o $(USBDEV_OBJS) scsi_device.o $(CDROM_OBJS)
$(CXX) $(CXXFLAGS) -shared -o bx_usb_common.dll usb_common.o $(USBDEV_OBJS) scsi_device.o $(CDROM_OBJS) $(WIN32_DLL_IMPORT_LIBRARY)
##### end DLL section
clean:
@RMCOMMAND@ -rf .libs *.lo *.o *.la *.a *.dll
dist-clean: clean
@RMCOMMAND@ Makefile
###########################################
# dependencies generated by
# gcc -MM -I.. -I../instrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g'
# gcc -MM -I.. -I../instrument/stubs *.cc | \
# sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's/\.o:/.lo:/g'
#
# This means that every source file is listed twice, once with a .o rule
# and then again with an identical .lo rule. The .lo rules are used when
# building plugins.
###########################################
acpi.o: acpi.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h acpi.h
biosdev.o: biosdev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h biosdev.h
busmouse.o: busmouse.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h busmouse.h
cdrom_amigaos.o: cdrom_amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h scsi_commands.h cdrom.h
cdrom_beos.o: cdrom_beos.@CPP_SUFFIX@ cdrom_beos.h
cdrom.o: cdrom.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
cdrom.h
cmos.o: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h cmos.h
crc32.o: crc32.@CPP_SUFFIX@ crc32.h ../config.h
devices.o: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ../iodev/virt_timer.h \
../iodev/slowdown_timer.h
dma.o: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h dma.h
eth_arpback.o: eth_arpback.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth.o: eth.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_fbsd.o: eth_fbsd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth_linux.o: eth_linux.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_null.o: eth_null.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_packetmaker.o: eth_packetmaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h \
../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth_tap.o: eth_tap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_tuntap.o: eth_tuntap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_vde.o: eth_vde.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_vnet.o: eth_vnet.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_win32.o: eth_win32.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
extfpuirq.o: extfpuirq.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h extfpuirq.h
floppy.o: floppy.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h floppy.h
gameport.o: gameport.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h gameport.h
guest2host.o: guest2host.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h guest2host.h
harddrv.o: harddrv.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h harddrv.h hdimage.h \
cdrom.h
hdimage.o: hdimage.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h \
vmware4.h vvfat.h
ioapic.o: ioapic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ioapic.h
iodebug.o: iodebug.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
keyboard.o: keyboard.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ../gui/keymap.h \
keyboard.h scancodes.h
ne2k.o: ne2k.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h ne2k.h eth.h
parallel.o: parallel.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h parallel.h
pci2isa.o: pci2isa.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pci2isa.h
pci.o: pci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h
pcidev.o: pcidev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
pci_ide.o: pci_ide.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pci_ide.h
pcipnic.o: pcipnic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
pcivga.o: pcivga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pcivga.h
pic.o: pic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pic.h
pit82c54.o: pit82c54.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pit82c54.h
pit_wrap.o: pit_wrap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pit_wrap.h pit82c54.h \
virt_timer.h speaker.h
sb16.o: sb16.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h sb16.h soundmod.h \
soundlnx.h soundwin.h soundosx.h
scancodes.o: scancodes.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h scancodes.h
scsi_device.o: scsi_device.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h cdrom.h \
scsi_device.h
serial.o: serial.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h serial.h
serial_raw.o: serial_raw.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
slowdown_timer.o: slowdown_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h slowdown_timer.h
soundlnx.o: soundlnx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h
soundmod.o: soundmod.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h \
soundosx.h soundwin.h
soundosx.o: soundosx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundosx.h
soundwin.o: soundwin.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundwin.h
speaker.o: speaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h speaker.h
svga_cirrus.o: svga_cirrus.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h vga.h svga_cirrus.h
unmapped.o: unmapped.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h unmapped.h
usb_common.o: usb_common.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hid.h usb_hub.h usb_msd.h usb_printer.h
usb_hid.o: usb_hid.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hid.h
usb_hub.o: usb_hub.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hub.h
usb_msd.o: usb_msd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h cdrom.h \
hdimage.h scsi_device.h usb_msd.h
usb_ohci.o: usb_ohci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
usb_ohci.h
usb_printer.o: usb_printer.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_printer.h
usb_uhci.o: usb_uhci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
usb_uhci.h
vga.o: vga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h vga.h
virt_timer.o: virt_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h virt_timer.h
vmware3.o: vmware3.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h
vmware4.o: vmware4.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware4.h
vvfat.o: vvfat.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vvfat.h
acpi.lo: acpi.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h acpi.h
biosdev.lo: biosdev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h biosdev.h
busmouse.lo: busmouse.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h busmouse.h
cdrom_amigaos.lo: cdrom_amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h scsi_commands.h cdrom.h
cdrom_beos.lo: cdrom_beos.@CPP_SUFFIX@ cdrom_beos.h
cdrom.lo: cdrom.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
cdrom.h
cmos.lo: cmos.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h cmos.h
crc32.lo: crc32.@CPP_SUFFIX@ crc32.h ../config.h
devices.lo: devices.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ../iodev/virt_timer.h \
../iodev/slowdown_timer.h
dma.lo: dma.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h dma.h
eth_arpback.lo: eth_arpback.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth.lo: eth.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_fbsd.lo: eth_fbsd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth_linux.lo: eth_linux.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_null.lo: eth_null.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_packetmaker.lo: eth_packetmaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h \
../osdep.h ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
eth_tap.lo: eth_tap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_tuntap.lo: eth_tuntap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_vde.lo: eth_vde.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_vnet.lo: eth_vnet.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h eth.h
eth_win32.lo: eth_win32.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
extfpuirq.lo: extfpuirq.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h extfpuirq.h
floppy.lo: floppy.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h floppy.h
gameport.lo: gameport.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h gameport.h
guest2host.lo: guest2host.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h guest2host.h
harddrv.lo: harddrv.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h harddrv.h hdimage.h \
cdrom.h
hdimage.lo: hdimage.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h \
vmware4.h vvfat.h
ioapic.lo: ioapic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ioapic.h
iodebug.lo: iodebug.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
keyboard.lo: keyboard.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h ../gui/keymap.h \
keyboard.h scancodes.h
ne2k.lo: ne2k.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h ne2k.h eth.h
parallel.lo: parallel.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h parallel.h
pci2isa.lo: pci2isa.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pci2isa.h
pci.lo: pci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h
pcidev.lo: pcidev.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
pci_ide.lo: pci_ide.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pci_ide.h
pcipnic.lo: pcipnic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
pcivga.lo: pcivga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h pcivga.h
pic.lo: pic.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pic.h
pit82c54.lo: pit82c54.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pit82c54.h
pit_wrap.lo: pit_wrap.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pit_wrap.h pit82c54.h \
virt_timer.h speaker.h
sb16.lo: sb16.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h sb16.h soundmod.h \
soundlnx.h soundwin.h soundosx.h
scancodes.lo: scancodes.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h scancodes.h
scsi_device.lo: scsi_device.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h cdrom.h \
scsi_device.h
serial.lo: serial.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h serial.h
serial_raw.lo: serial_raw.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h
slowdown_timer.lo: slowdown_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h slowdown_timer.h
soundlnx.lo: soundlnx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h
soundmod.lo: soundmod.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundlnx.h \
soundosx.h soundwin.h
soundosx.lo: soundosx.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundosx.h
soundwin.lo: soundwin.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h soundmod.h soundwin.h
speaker.lo: speaker.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h speaker.h
svga_cirrus.lo: svga_cirrus.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h vga.h svga_cirrus.h
unmapped.lo: unmapped.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h unmapped.h
usb_common.lo: usb_common.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hid.h usb_hub.h usb_msd.h usb_printer.h
usb_hid.lo: usb_hid.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hid.h
usb_hub.lo: usb_hub.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_hub.h
usb_msd.lo: usb_msd.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h cdrom.h \
hdimage.h scsi_device.h usb_msd.h
usb_ohci.lo: usb_ohci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
usb_ohci.h
usb_printer.lo: usb_printer.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h usb_common.h \
usb_printer.h
usb_uhci.lo: usb_uhci.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h pci.h usb_common.h \
usb_uhci.h
vga.lo: vga.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h vga.h
virt_timer.lo: virt_timer.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h virt_timer.h
vmware3.lo: vmware3.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware3.h
vmware4.lo: vmware4.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vmware4.h
vvfat.lo: vvfat.@CPP_SUFFIX@ iodev.h ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../param_names.h hdimage.h vvfat.h

586
bochs/iodev/acpi.cc Normal file
View File

@ -0,0 +1,586 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2006 Volker Ruppert
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// PIIX4 ACPI support
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_ACPI
#include "pci.h"
#include "acpi.h"
#define LOG_THIS theACPIController->
bx_acpi_ctrl_c* theACPIController = NULL;
// FIXME
const Bit8u acpi_pm_iomask[64] = {2, 0, 2, 0, 2, 0, 0, 0, 4, 0, 0, 0, 7, 7, 7, 7,
7, 7, 7, 7, 1, 1, 0, 0, 7, 7, 0, 0, 7, 7, 7, 7,
7, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7,
1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
const Bit8u acpi_sm_iomask[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 2, 0, 0, 0};
#define PM_FREQ 3579545
#define ACPI_DBG_IO_ADDR 0xb044
#define RSM_STS (1 << 15)
#define PWRBTN_STS (1 << 8)
#define RTC_EN (1 << 10)
#define PWRBTN_EN (1 << 8)
#define GBL_EN (1 << 5)
#define TMROF_EN (1 << 0)
#define SCI_EN (1 << 0)
#define SUS_EN (1 << 13)
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
extern void apic_bus_deliver_smi(void);
int libacpi_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theACPIController = new bx_acpi_ctrl_c();
bx_devices.pluginACPIController = theACPIController;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theACPIController, BX_PLUGIN_ACPI);
return 0; // Success
}
void libacpi_LTX_plugin_fini(void)
{
delete theACPIController;
}
/* ported from QEMU: compute with 96 bit intermediate result: (a*b)/c */
Bit64u muldiv64(Bit64u a, Bit32u b, Bit32u c)
{
union {
Bit64u ll;
struct {
#ifdef WORDS_BIGENDIAN
Bit32u high, low;
#else
Bit32u low, high;
#endif
} l;
} u, res;
Bit64u rl, rh;
u.ll = a;
rl = (Bit64u)u.l.low * (Bit64u)b;
rh = (Bit64u)u.l.high * (Bit64u)b;
rh += (rl >> 32);
res.l.high = (Bit32u)(rh / c);
res.l.low = (Bit32u)(((rh % c) << 32) + (rl & 0xffffffff)) / c;
return res.ll;
}
bx_acpi_ctrl_c::bx_acpi_ctrl_c()
{
put("ACPI");
s.timer_index = BX_NULL_TIMER_HANDLE;
}
bx_acpi_ctrl_c::~bx_acpi_ctrl_c()
{
BX_DEBUG(("Exit"));
}
void bx_acpi_ctrl_c::init(void)
{
// called once when bochs initializes
unsigned i;
BX_ACPI_THIS s.devfunc = BX_PCI_DEVICE(1, 3);
DEV_register_pci_handlers(this, &BX_ACPI_THIS s.devfunc, BX_PLUGIN_ACPI,
"ACPI Controller");
if (BX_ACPI_THIS s.timer_index == BX_NULL_TIMER_HANDLE) {
BX_ACPI_THIS s.timer_index =
bx_pc_system.register_timer(this, timer_handler, 1000, 0, 0, "ACPI");
}
DEV_register_iowrite_handler(this, write_handler, ACPI_DBG_IO_ADDR, "ACPI", 4);
for (i=0; i<256; i++) {
BX_ACPI_THIS s.pci_conf[i] = 0x0;
}
BX_ACPI_THIS s.pm_base = 0x0;
BX_ACPI_THIS s.sm_base = 0x0;
// readonly registers
static const struct init_vals_t {
unsigned addr;
unsigned char val;
} init_vals[] = {
{ 0x00, 0x86 }, { 0x01, 0x80 },
{ 0x02, 0x13 }, { 0x03, 0x71 },
{ 0x08, 0x03 }, // revision number
{ 0x0a, 0x80 }, // other bridge device
{ 0x0b, 0x06 }, // bridge device
{ 0x0e, 0x00 }, // header type
{ 0x3d, BX_PCI_INTA } // interrupt pin #1
};
for (i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
BX_ACPI_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
}
}
void bx_acpi_ctrl_c::reset(unsigned type)
{
BX_ACPI_THIS s.pci_conf[0x04] = 0x00; // command_io + command_mem
BX_ACPI_THIS s.pci_conf[0x05] = 0x00;
BX_ACPI_THIS s.pci_conf[0x06] = 0x80; // status_devsel_medium
BX_ACPI_THIS s.pci_conf[0x07] = 0x02;
BX_ACPI_THIS s.pci_conf[0x3c] = 0x00; // IRQ
// PM base 0x40 - 0x43
BX_ACPI_THIS s.pci_conf[0x40] = 0x01;
BX_ACPI_THIS s.pci_conf[0x41] = 0x00;
BX_ACPI_THIS s.pci_conf[0x42] = 0x00;
BX_ACPI_THIS s.pci_conf[0x43] = 0x00;
// clear DEVACTB register on PIIX4 ACPI reset
BX_ACPI_THIS s.pci_conf[0x58] = 0x00;
BX_ACPI_THIS s.pci_conf[0x59] = 0x00;
// device resources
BX_ACPI_THIS s.pci_conf[0x5a] = 0x00;
BX_ACPI_THIS s.pci_conf[0x5b] = 0x00;
BX_ACPI_THIS s.pci_conf[0x5f] = 0x90;
BX_ACPI_THIS s.pci_conf[0x63] = 0x60;
BX_ACPI_THIS s.pci_conf[0x67] = 0x98;
// SM base 0x90 - 0x93
BX_ACPI_THIS s.pci_conf[0x90] = 0x01;
BX_ACPI_THIS s.pci_conf[0x91] = 0x00;
BX_ACPI_THIS s.pci_conf[0x92] = 0x00;
BX_ACPI_THIS s.pci_conf[0x93] = 0x00;
BX_ACPI_THIS s.pmsts = 0;
BX_ACPI_THIS s.pmen = 0;
BX_ACPI_THIS s.pmcntrl = 0;
BX_ACPI_THIS s.tmr_overflow_time = 0xffffff;
BX_ACPI_THIS s.smbus.stat = 0;
BX_ACPI_THIS s.smbus.ctl = 0;
BX_ACPI_THIS s.smbus.cmd = 0;
BX_ACPI_THIS s.smbus.addr = 0;
BX_ACPI_THIS s.smbus.data0 = 0;
BX_ACPI_THIS s.smbus.data1 = 0;
BX_ACPI_THIS s.smbus.index = 0;
for (unsigned i = 0; i < 32; i++) {
BX_ACPI_THIS s.smbus.data[i] = 0;
}
}
void bx_acpi_ctrl_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "acpi", "ACPI Controller State", 6);
BXRS_HEX_PARAM_FIELD(list, pmsts, BX_ACPI_THIS s.pmsts);
BXRS_HEX_PARAM_FIELD(list, pmen, BX_ACPI_THIS s.pmen);
BXRS_HEX_PARAM_FIELD(list, pmcntrl, BX_ACPI_THIS s.pmcntrl);
BXRS_HEX_PARAM_FIELD(list, tmr_overflow_time, BX_ACPI_THIS s.tmr_overflow_time);
bx_list_c *smbus = new bx_list_c(list, "smbus", "ACPI SMBus", 8);
BXRS_HEX_PARAM_FIELD(smbus, stat, BX_ACPI_THIS s.smbus.stat);
BXRS_HEX_PARAM_FIELD(smbus, ctl, BX_ACPI_THIS s.smbus.ctl);
BXRS_HEX_PARAM_FIELD(smbus, cmd, BX_ACPI_THIS s.smbus.cmd);
BXRS_HEX_PARAM_FIELD(smbus, addr, BX_ACPI_THIS s.smbus.addr);
BXRS_HEX_PARAM_FIELD(smbus, data0, BX_ACPI_THIS s.smbus.data0);
BXRS_HEX_PARAM_FIELD(smbus, data1, BX_ACPI_THIS s.smbus.data1);
BXRS_HEX_PARAM_FIELD(smbus, index, BX_ACPI_THIS s.smbus.index);
bx_list_c *data = new bx_list_c(smbus, "data", "ACPI SMBus data", 32);
for (unsigned i = 0; i < 32; i++) {
char name[6];
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(data, name, &BX_ACPI_THIS s.smbus.data[i], BASE_HEX);
}
register_pci_state(list, BX_ACPI_THIS s.pci_conf);
}
void bx_acpi_ctrl_c::after_restore_state(void)
{
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
&BX_ACPI_THIS s.pm_base,
&BX_ACPI_THIS s.pci_conf[0x40],
64, &acpi_pm_iomask[0], "ACPI PM base"))
{
BX_INFO(("new PM base address: 0x%04x", BX_ACPI_THIS s.pm_base));
}
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
&BX_ACPI_THIS s.sm_base,
&BX_ACPI_THIS s.pci_conf[0x90],
16, &acpi_sm_iomask[0], "ACPI SM base"))
{
BX_INFO(("new SM base address: 0x%04x", BX_ACPI_THIS s.sm_base));
}
}
void bx_acpi_ctrl_c::set_irq_level(bx_bool level)
{
DEV_pci_set_irq(BX_ACPI_THIS s.devfunc, BX_ACPI_THIS s.pci_conf[0x3d], level);
}
Bit32u bx_acpi_ctrl_c::get_pmtmr(void)
{
Bit64u value = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
return (Bit32u)(value & 0xffffff);
}
Bit16u bx_acpi_ctrl_c::get_pmsts(void)
{
Bit16u pmsts = BX_ACPI_THIS s.pmsts;
Bit64u value = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
if (value >= BX_ACPI_THIS s.tmr_overflow_time)
BX_ACPI_THIS s.pmsts |= TMROF_EN;
return pmsts;
}
void bx_acpi_ctrl_c::pm_update_sci(void)
{
Bit16u pmsts = get_pmsts();
bx_bool sci_level = (((pmsts & BX_ACPI_THIS s.pmen) &
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
BX_ACPI_THIS set_irq_level(sci_level);
// schedule a timer interruption if needed
if ((BX_ACPI_THIS s.pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
Bit64u expire_time = muldiv64(BX_ACPI_THIS s.tmr_overflow_time, 1000000, PM_FREQ);
bx_pc_system.activate_timer(BX_ACPI_THIS s.timer_index, (Bit32u)expire_time, 0);
} else {
bx_pc_system.deactivate_timer(BX_ACPI_THIS s.timer_index);
}
}
void bx_acpi_ctrl_c::generate_smi(Bit8u value)
{
/* ACPI specs 3.0, 4.7.2.5 */
if (value == ACPI_ENABLE) {
BX_ACPI_THIS s.pmcntrl |= SCI_EN;
} else if (value == ACPI_DISABLE) {
BX_ACPI_THIS s.pmcntrl &= ~SCI_EN;
}
if (BX_ACPI_THIS s.pci_conf[0x5b] & 0x02) {
apic_bus_deliver_smi();
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_acpi_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_ACPI_SMF
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_acpi_ctrl_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_ACPI_SMF
Bit8u reg = address & 0x3f;
Bit32u value = 0xffffffff;
if ((address & 0xffc0) == BX_ACPI_THIS s.pm_base) {
if ((BX_ACPI_THIS s.pci_conf[0x80] & 0x01) == 0) {
return value;
}
switch (reg) {
case 0x00:
value = BX_ACPI_THIS get_pmsts();
break;
case 0x02:
value = BX_ACPI_THIS s.pmen;
break;
case 0x04:
value = BX_ACPI_THIS s.pmcntrl;
break;
case 0x08:
value = BX_ACPI_THIS get_pmtmr();
break;
default:
BX_INFO(("ACPI read from PM register 0x%02x not implemented yet", reg));
}
BX_DEBUG(("ACPI read from PM register 0x%02x returns 0x%08x", reg, value));
} else {
if (((BX_ACPI_THIS s.pci_conf[0x04] & 0x01) == 0) &&
((BX_ACPI_THIS s.pci_conf[0xd2] & 0x01) == 0)) {
return value;
}
switch (reg) {
case 0x00:
value = BX_ACPI_THIS s.smbus.stat;
break;
case 0x02:
BX_ACPI_THIS s.smbus.index = 0;
value = BX_ACPI_THIS s.smbus.ctl & 0x1f;
break;
case 0x03:
value = BX_ACPI_THIS s.smbus.cmd;
break;
case 0x04:
value = BX_ACPI_THIS s.smbus.addr;
break;
case 0x05:
value = BX_ACPI_THIS s.smbus.data0;
break;
case 0x06:
value = BX_ACPI_THIS s.smbus.data1;
break;
case 0x07:
value = BX_ACPI_THIS s.smbus.data[BX_ACPI_THIS s.smbus.index++];
if (BX_ACPI_THIS s.smbus.index > 31) {
BX_ACPI_THIS s.smbus.index = 0;
}
break;
default:
value = 0;
BX_INFO(("ACPI read from SMBus register 0x%02x not implemented yet", reg));
}
BX_DEBUG(("ACPI read from SMBus register 0x%02x returns 0x%08x", reg, value));
}
return value;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_acpi_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_ACPI_SMF
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_acpi_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_ACPI_SMF
Bit8u reg = address & 0x3f;
if ((address & 0xffc0) == BX_ACPI_THIS s.pm_base) {
if ((BX_ACPI_THIS s.pci_conf[0x80] & 0x01) == 0) {
return;
}
BX_DEBUG(("ACPI write to PM register 0x%02x, value = 0x%04x", reg, value));
switch (reg) {
case 0x00:
{
Bit16u pmsts = BX_ACPI_THIS get_pmsts();
if (pmsts & value & TMROF_EN) {
// if TMRSTS is reset, then compute the new overflow time
Bit64u d = muldiv64(bx_pc_system.time_usec(), PM_FREQ, 1000000);
BX_ACPI_THIS s.tmr_overflow_time = (d + BX_CONST64(0x800000)) & ~BX_CONST64(0x7fffff);
}
BX_ACPI_THIS s.pmsts &= ~value;
BX_ACPI_THIS pm_update_sci();
}
break;
case 0x02:
BX_ACPI_THIS s.pmen = value;
BX_ACPI_THIS pm_update_sci();
break;
case 0x04:
{
BX_ACPI_THIS s.pmcntrl = value & ~(SUS_EN);
if (value & SUS_EN) {
// change suspend type
Bit16u sus_typ = (value >> 10) & 7;
switch (sus_typ) {
case 0: // soft power off
bx_user_quit = 1;
LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
BX_PANIC(("ACPI control: soft power off"));
break;
case 1:
BX_INFO(("ACPI control: suspend to ram"));
BX_ACPI_THIS s.pmsts |= (RSM_STS | PWRBTN_STS);
DEV_cmos_set_reg(0xF, 0xFE);
bx_pc_system.Reset(BX_RESET_HARDWARE);
break;
default:
break;
}
}
}
break;
default:
BX_INFO(("ACPI write to PM register 0x%02x not implemented yet", reg));
}
} else if ((address & 0xfff0) == BX_ACPI_THIS s.sm_base) {
if (((BX_ACPI_THIS s.pci_conf[0x04] & 0x01) == 0) &&
((BX_ACPI_THIS s.pci_conf[0xd2] & 0x01) == 0)) {
return;
}
BX_DEBUG(("ACPI write to SMBus register 0x%02x, value = 0x%04x", reg, value));
switch (reg) {
case 0x00:
BX_ACPI_THIS s.smbus.stat = 0;
BX_ACPI_THIS s.smbus.index = 0;
break;
case 0x02:
BX_ACPI_THIS s.smbus.ctl = 0;
// TODO: execute SMBus command
break;
case 0x03:
BX_ACPI_THIS s.smbus.cmd = 0;
break;
case 0x04:
BX_ACPI_THIS s.smbus.addr = 0;
break;
case 0x05:
BX_ACPI_THIS s.smbus.data0 = 0;
break;
case 0x06:
BX_ACPI_THIS s.smbus.data1 = 0;
break;
case 0x07:
BX_ACPI_THIS s.smbus.data[BX_ACPI_THIS s.smbus.index++] = value;
if (BX_ACPI_THIS s.smbus.index > 31) {
BX_ACPI_THIS s.smbus.index = 0;
}
break;
default:
BX_INFO(("ACPI write to SMBus register 0x%02x not implemented yet", reg));
}
} else {
BX_DEBUG(("DBG: 0x%08x", value));
}
}
void bx_acpi_ctrl_c::timer_handler(void *this_ptr)
{
bx_acpi_ctrl_c *class_ptr = (bx_acpi_ctrl_c *) this_ptr;
class_ptr->timer();
}
void bx_acpi_ctrl_c::timer()
{
BX_ACPI_THIS pm_update_sci();
}
// pci configuration space read callback handler
Bit32u bx_acpi_ctrl_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_ACPI_THIS s.pci_conf[address+i] << (i*8));
}
if (io_len == 1)
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
return value;
}
// static pci configuration space write callback handler
void bx_acpi_ctrl_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
Bit8u value8, oldval;
bx_bool pm_base_change = 0, sm_base_change = 0;
if ((address >= 0x10) && (address < 0x34))
return;
for (unsigned i=0; i<io_len; i++) {
value8 = (value >> (i*8)) & 0xFF;
oldval = BX_ACPI_THIS s.pci_conf[address+i];
switch (address+i) {
case 0x04:
value8 = (value8 & 0xfe) | (value & 0x01);
goto set_value;
break;
case 0x06: // disallowing write to status lo-byte (is that expected?)
break;
case 0x3c:
if (value8 != oldval) {
BX_INFO(("new irq line = %d", value8));
}
goto set_value;
break;
case 0x40:
value8 = (value8 & 0xc0) | 0x01;
case 0x41:
case 0x42:
case 0x43:
pm_base_change |= (value8 != oldval);
goto set_value;
break;
case 0x90:
value8 = (value8 & 0xf0) | 0x01;
case 0x91:
case 0x92:
case 0x93:
sm_base_change |= (value8 != oldval);
default:
set_value:
BX_ACPI_THIS s.pci_conf[address+i] = value8;
}
}
if (pm_base_change) {
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
&BX_ACPI_THIS s.pm_base,
&BX_ACPI_THIS s.pci_conf[0x40],
64, &acpi_pm_iomask[0], "ACPI PM base"))
{
BX_INFO(("new PM base address: 0x%04x", BX_ACPI_THIS s.pm_base));
}
}
if (sm_base_change) {
if (DEV_pci_set_base_io(BX_ACPI_THIS_PTR, read_handler, write_handler,
&BX_ACPI_THIS s.sm_base,
&BX_ACPI_THIS s.pci_conf[0x90],
16, &acpi_sm_iomask[0], "ACPI SM base"))
{
BX_INFO(("new SM base address: 0x%04x", BX_ACPI_THIS s.sm_base));
}
}
if (io_len == 1)
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
}
#endif // BX_SUPPORT_PCI

86
bochs/iodev/acpi.h Normal file
View File

@ -0,0 +1,86 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2006 Volker Ruppert
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_ACPI_H
#define BX_IODEV_ACPI_H
#if BX_USE_ACPI_SMF
# define BX_ACPI_SMF static
# define BX_ACPI_THIS theACPIController->
# define BX_ACPI_THIS_PTR theACPIController
#else
# define BX_ACPI_SMF
# define BX_ACPI_THIS this->
# define BX_ACPI_THIS_PTR this
#endif
class bx_acpi_ctrl_c : public bx_acpi_ctrl_stub_c {
public:
bx_acpi_ctrl_c();
virtual ~bx_acpi_ctrl_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void generate_smi(Bit8u value);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_ACPI_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
BX_ACPI_SMF void timer(void);
private:
BX_ACPI_SMF void set_irq_level(bx_bool level);
BX_ACPI_SMF Bit32u get_pmtmr(void);
BX_ACPI_SMF Bit16u get_pmsts(void);
BX_ACPI_SMF void pm_update_sci(void);
static void timer_handler(void *);
struct {
Bit8u pci_conf[256];
Bit8u devfunc;
Bit32u pm_base;
Bit32u sm_base;
Bit16u pmsts;
Bit16u pmen;
Bit16u pmcntrl;
Bit64u tmr_overflow_time;
int timer_index;
struct {
Bit8u stat;
Bit8u ctl;
Bit8u cmd;
Bit8u addr;
Bit8u data0;
Bit8u data1;
Bit8u index;
Bit8u data[32];
} smbus;
} s;
};
#endif

210
bochs/iodev/aspi-win32.h Normal file
View File

@ -0,0 +1,210 @@
//
// iodev/aspi-win32.h
// $Id$
//
// This file was copied from cdrecord 1.9 under libscg/scg/aspi-win32.h.
// The only modification is related to use of the PACKED keyword.
//
#ifndef __ASPI_WIN32_H_
#define __ASPI_WIN32_H_
#include <windows.h>
#ifndef PACKED
// It seems that VC++ has no PACKED keyword but Cygwin does. We can just
// define PACKED to be empty if it's not already defined by the system
// headers.
#define PACKED /* empty */
#endif
/***************************************************************************
** SCSI MISCELLANEOUS EQUATES
***************************************************************************/
#define SENSE_LEN 14 /* Default sense buffer length */
#define SRB_DIR_SCSI 0x00 /* Direction determined by SCSI */
#define SRB_POSTING 0x01 /* Enable ASPI posting */
#define SRB_ENABLE_RESIDUAL_COUNT 0x04 /* Enable residual byte count */
/* reporting */
#define SRB_DIR_IN 0x08 /* Transfer from SCSI target to */
/* host */
#define SRB_DIR_OUT 0x10 /* Transfer from host to SCSI */
/* target */
#define SRB_EVENT_NOTIFY 0x40 /* Enable ASPI event notification */
#define RESIDUAL_COUNT_SUPPORTED 0x02 /* Extended buffer flag */
#define MAX_SRB_TIMEOUT 1080001u /* 30 hour maximum timeout in sec */
#define DEFAULT_SRB_TIMEOUT 1080001u /* use max.timeout by default */
/***************************************************************************
** ASPI command definitions
***************************************************************************/
#define SC_HA_INQUIRY 0x00 /* Host adapter inquiry */
#define SC_GET_DEV_TYPE 0x01 /* Get device type */
#define SC_EXEC_SCSI_CMD 0x02 /* Execute SCSI command */
#define SC_ABORT_SRB 0x03 /* Abort an SRB */
#define SC_RESET_DEV 0x04 /* SCSI bus device reset */
#define SC_SET_HA_PARMS 0x05 /* Set HA parameters */
#define SC_GET_DISK_INFO 0x06 /* Get Disk */
#define SC_RESCAN_SCSI_BUS 0x07 /* Rebuild SCSI device map */
#define SC_GETSET_TIMEOUTS 0x08 /* Get/Set target timeouts */
/***************************************************************************
** SRB Status
***************************************************************************/
#define SS_PENDING 0x00 /* SRB being processed */
#define SS_COMP 0x01 /* SRB completed without error */
#define SS_ABORTED 0x02 /* SRB aborted */
#define SS_ABORT_FAIL 0x03 /* Unable to abort SRB */
#define SS_ERR 0x04 /* SRB completed with error */
#define SS_INVALID_CMD 0x80 /* Invalid ASPI command */
#define SS_INVALID_HA 0x81 /* Invalid host adapter number */
#define SS_NO_DEVICE 0x82 /* SCSI device not installed */
#define SS_INVALID_SRB 0xE0 /* Invalid parameter set in SRB */
#define SS_OLD_MANAGER 0xE1 /* ASPI manager doesn't support */
/* windows */
#define SS_BUFFER_ALIGN 0xE1 /* Buffer not aligned (replaces */
/* SS_OLD_MANAGER in Win32) */
#define SS_ILLEGAL_MODE 0xE2 /* Unsupported Windows mode */
#define SS_NO_ASPI 0xE3 /* No ASPI managers */
#define SS_FAILED_INIT 0xE4 /* ASPI for windows failed init */
#define SS_ASPI_IS_BUSY 0xE5 /* No resources available to */
/* execute command */
#define SS_BUFFER_TO_BIG 0xE6 /* Buffer size too big to handle */
#define SS_BUFFER_TOO_BIG 0xE6 /* Correct spelling of 'too' */
#define SS_MISMATCHED_COMPONENTS 0xE7 /* The DLLs/EXEs of ASPI don't */
/* version check */
#define SS_NO_ADAPTERS 0xE8 /* No host adapters to manager */
#define SS_INSUFFICIENT_RESOURCES 0xE9 /* Couldn't allocate resources */
/* needed to init */
#define SS_ASPI_IS_SHUTDOWN 0xEA /* Call came to ASPI after */
/* PROCESS_DETACH */
#define SS_BAD_INSTALL 0xEB /* The DLL or other components */
/* are installed wrong */
/***************************************************************************
** Host Adapter Status
***************************************************************************/
#define HASTAT_OK 0x00 /* No error detected by HA */
#define HASTAT_SEL_TO 0x11 /* Selection Timeout */
#define HASTAT_DO_DU 0x12 /* Data overrun/data underrun */
#define HASTAT_BUS_FREE 0x13 /* Unexpected bus free */
#define HASTAT_PHASE_ERR 0x14 /* Target bus phase sequence */
#define HASTAT_TIMEOUT 0x09 /* Timed out while SRB was */
/* waiting to be processed */
#define HASTAT_COMMAND_TIMEOUT 0x0B /* Adapter timed out while */
/* processing SRB */
#define HASTAT_MESSAGE_REJECT 0x0D /* While processing the SRB, the */
/* adapter received a MESSAGE */
#define HASTAT_BUS_RESET 0x0E /* A bus reset was detected */
#define HASTAT_PARITY_ERROR 0x0F /* A parity error was detected */
#define HASTAT_REQUEST_SENSE_FAILED 0x10 /* The adapter failed in issuing */
/***************************************************************************
** SRB - HOST ADAPTER INQUIRIY - SC_HA_INQUIRY (0)
***************************************************************************/
typedef struct {
BYTE SRB_Cmd; /* 00/000 ASPI command code == SC_HA_INQUIRY */
BYTE SRB_Status; /* 01/001 ASPI command status byte */
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
BYTE SRB_Flags; /* 03/003 ASPI request flags */
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
BYTE HA_Count; /* 08/008 Number of host adapters present */
BYTE HA_SCSI_ID; /* 09/009 SCSI ID of host adapter */
BYTE HA_ManagerId[16]; /* 0a/010 String describing the manager */
BYTE HA_Identifier[16]; /* 1a/026 String describing the host adapter */
BYTE HA_Unique[16]; /* 2a/042 Host Adapter Unique parameters */
WORD HA_Rsvd1; /* 3a/058 Reserved, must = 0 */
} PACKED SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry;
/***************************************************************************
** SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1)
***************************************************************************/
typedef struct
{
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE */
BYTE SRB_Status; /* 01/001 ASPI command status byte */
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
BYTE SRB_Lun; /* 09/009 Target's LUN number */
BYTE SRB_DeviceType; /* 0a/010 Target's peripheral device type */
BYTE SRB_Rsvd1; /* 0b/011 Reserved, must = 0 */
} PACKED SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock;
/***************************************************************************
** SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2)
***************************************************************************/
typedef struct
{
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_EXEC_SCSI_CMD */
BYTE SRB_Status; /* 01/001 ASPI command status byte */
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
BYTE SRB_Lun; /* 09/009 Target's LUN */
WORD SRB_Rsvd1; /* 0a/010 Reserved for alignment */
DWORD SRB_BufLen; /* 0c/012 Data Allocation Length */
BYTE FAR *SRB_BufPointer; /* 10/016 Data Buffer Pointer */
BYTE SRB_SenseLen; /* 14/020 Sense Allocation Length */
BYTE SRB_CDBLen; /* 15/021 CDB Length */
BYTE SRB_HaStat; /* 16/022 Host Adapter Status */
BYTE SRB_TargStat; /* 17/023 Target Status */
VOID FAR *SRB_PostProc; /* 18/024 Post routine */
BYTE SRB_Rsvd2[20]; /* 1c/028 Reserved, must = 0 */
BYTE CDBByte[16]; /* 30/048 SCSI CDB */
BYTE SenseArea[SENSE_LEN+2]; /* 40/064 Request Sense buffer */
} PACKED SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd;
typedef struct
{
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_ABORT_SRB */
BYTE SRB_Status; /* 01/001 ASPI command status byte */
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
BYTE SRB_Flags; /* 03/003 Reserved, must = 0 */
DWORD SRB_Hdr_Rsvd; /* 04/004 Reserved, must = 0 */
void *SRB_ToAbort; /* 08/008 Pointer to SRB to abort */
} PACKED SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort;
/***************************************************************************
** SRB - BUS DEVICE RESET - SC_RESET_DEV (4)
***************************************************************************/
typedef struct
{
BYTE SRB_Cmd; /* 00/000 ASPI cmd code == SC_RESET_DEV */
BYTE SRB_Status; /* 01/001 ASPI command status byte */
BYTE SRB_HaId; /* 02/002 ASPI host adapter number */
DWORD SRB_Flags; /* 04/004 Reserved */
BYTE SRB_Target; /* 08/008 Target's SCSI ID */
BYTE SRB_Lun; /* 09/009 Target's LUN number */
BYTE SRB_Rsvd1[12]; /* 0A/010 Reserved for alignment */
BYTE SRB_HaStat; /* 16/022 Host Adapter Status */
BYTE SRB_TargStat; /* 17/023 Target Status */
VOID FAR *SRB_PostProc; /* 18/024 Post routine */
BYTE SRB_Rsvd2[36]; /* 1C/028 Reserved, must = 0 */
} SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset;
typedef struct tag_ASPI32BUFF
{
PBYTE AB_BufPointer;
DWORD AB_BufLen;
DWORD AB_ZeroFill;
DWORD AB_Reserved;
} PACKED ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF;
typedef struct
{
BYTE SRB_Cmd;
BYTE SRB_Status;
BYTE SRB_HaId;
BYTE SRB_Flags;
DWORD SRB_Hdr_Rsvd;
} SRB, *PSRB, FAR *LPSRB;
#endif

219
bochs/iodev/biosdev.cc Normal file
View File

@ -0,0 +1,219 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Here are the virtual ports use to display messages from the bioses :
//
// 0x0400 : rombios Panic port with line number
// 0x0401 : rombios Panic port with message, panic flag or line number
// 0x0402 : rombios Info port with message
// 0x0403 : rombios Debug port with message
//
// 0x0500 : vgabios Info port with message
// 0x0501 : vgabios Panic port with line number
// 0x0502 : vgabios Panic port with message, panic flag or line number
// 0x0503 : vgabios Debug port with message
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "biosdev.h"
bx_biosdev_c *theBiosDevice = NULL;
logfunctions *bioslog;
logfunctions *vgabioslog;
int libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theBiosDevice = new bx_biosdev_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
return(0); // Success
}
void libbiosdev_LTX_plugin_fini(void)
{
delete theBiosDevice;
}
bx_biosdev_c::bx_biosdev_c(void)
{
bioslog = new logfunctions();
bioslog->put("BIOS");
vgabioslog = new logfunctions();
vgabioslog->put("VBIOS");
}
bx_biosdev_c::~bx_biosdev_c(void)
{
bioslog->ldebug("Exit");
if (bioslog != NULL) {
delete bioslog;
bioslog = NULL;
}
if (vgabioslog != NULL) {
delete vgabioslog;
vgabioslog = NULL;
}
}
void bx_biosdev_c::init(void)
{
DEV_register_iowrite_handler(this, write_handler, 0x0400, "Bios Panic Port 1", 3);
DEV_register_iowrite_handler(this, write_handler, 0x0401, "Bios Panic Port 2", 3);
DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios Info Port", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0403, "Bios Debug Port", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0501, "VGABios Panic Port 1", 3);
DEV_register_iowrite_handler(this, write_handler, 0x0502, "VGABios Panic Port 2", 3);
DEV_register_iowrite_handler(this, write_handler, 0x0503, "VGABios Debug Port", 1);
s.bios_message_i = 0;
s.bios_panic_flag = 0;
s.vgabios_message_i = 0;
s.vgabios_panic_flag = 0;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_biosdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_BIOS_SMF
bx_biosdev_c *class_ptr = (bx_biosdev_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_biosdev_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_BIOS_SMF
UNUSED(io_len);
switch (address) {
// 0x400-0x401 are used as panic ports for the rombios
case 0x0401:
if (value==0) {
// The next message sent to the info port will cause a panic
BX_BIOS_THIS s.bios_panic_flag = 1;
break;
} else if (BX_BIOS_THIS s.bios_message_i > 0) {
// if there are bits of message in the buffer, print them as the
// panic message. Otherwise fall into the next case.
if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE)
BX_BIOS_THIS s.bios_message_i = BX_BIOS_MESSAGE_SIZE-1;
BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i] = 0;
BX_BIOS_THIS s.bios_message_i = 0;
bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
break;
}
case 0x0400:
if (value > 0) {
bioslog->panic("BIOS panic at rombios.c, line %d", value);
}
break;
// 0x0402 is used as the info port for the rombios
// 0x0403 is used as the debug port for the rombios
case 0x0402:
case 0x0403:
BX_BIOS_THIS s.bios_message[BX_BIOS_THIS s.bios_message_i] =
(Bit8u) value;
BX_BIOS_THIS s.bios_message_i ++;
if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE) {
BX_BIOS_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
BX_BIOS_THIS s.bios_message_i = 0;
if (address==0x403)
bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
else
bioslog->info("%s", BX_BIOS_THIS s.bios_message);
} else if ((value & 0xff) == '\n') {
BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i - 1 ] = 0;
BX_BIOS_THIS s.bios_message_i = 0;
if (BX_BIOS_THIS s.bios_panic_flag==1)
bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
else if (address==0x403)
bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
else
bioslog->info("%s", BX_BIOS_THIS s.bios_message);
BX_BIOS_THIS s.bios_panic_flag = 0;
}
break;
// 0x501-0x502 are used as panic ports for the vgabios
case 0x0502:
if (value==0) {
BX_BIOS_THIS s.vgabios_panic_flag = 1;
break;
} else if (BX_BIOS_THIS s.vgabios_message_i > 0) {
// if there are bits of message in the buffer, print them as the
// panic message. Otherwise fall into the next case.
if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE)
BX_BIOS_THIS s.vgabios_message_i = BX_BIOS_MESSAGE_SIZE-1;
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i] = 0;
BX_BIOS_THIS s.vgabios_message_i = 0;
vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
break;
}
case 0x0501:
if (value > 0) {
vgabioslog->panic("VGABIOS panic at vgabios.c, line %d", value);
}
break;
// 0x0500 is used as the message port for the vgabios
case 0x0500:
case 0x0503:
BX_BIOS_THIS s.vgabios_message[BX_BIOS_THIS s.vgabios_message_i] =
(Bit8u) value;
BX_BIOS_THIS s.vgabios_message_i ++;
if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE) {
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
BX_BIOS_THIS s.vgabios_message_i = 0;
if (address==0x503)
vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
else
vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
} else if ((value & 0xff) == '\n') {
BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i - 1 ] = 0;
BX_BIOS_THIS s.vgabios_message_i = 0;
if (BX_BIOS_THIS s.vgabios_panic_flag==1)
vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
else if (address==0x503)
vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
else
vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
BX_BIOS_THIS s.vgabios_panic_flag = 0;
}
break;
default:
break;
}
}

61
bochs/iodev/biosdev.h Normal file
View File

@ -0,0 +1,61 @@
////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_BIOSDEV_H
#define BX_IODEV_BIOSDEV_H
#define BX_BIOS_MESSAGE_SIZE 80
#if BX_USE_BIOS_SMF
# define BX_BIOS_SMF static
# define BX_BIOS_THIS theBiosDevice->
#else
# define BX_BIOS_SMF
# define BX_BIOS_THIS this->
#endif
class bx_biosdev_c : public bx_devmodel_c {
public:
bx_biosdev_c();
virtual ~bx_biosdev_c();
virtual void init(void);
virtual void reset(unsigned type) {}
private:
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_BIOS_SMF
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
struct {
Bit8u bios_message[BX_BIOS_MESSAGE_SIZE];
unsigned int bios_message_i;
bx_bool bios_panic_flag;
Bit8u vgabios_message[BX_BIOS_MESSAGE_SIZE];
unsigned int vgabios_message_i;
bx_bool vgabios_panic_flag;
} s; // state information
};
#endif

331
bochs/iodev/busmouse.cc Normal file
View File

@ -0,0 +1,331 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Initial code by Ben Lunt 'fys frontiernet net'
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "busmouse.h"
#if BX_SUPPORT_BUSMOUSE
#define LOG_THIS theBusMouse->
bx_busm_c *theBusMouse = NULL;
int libbusmouse_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
// Create one instance of the busmouse device object.
theBusMouse = new bx_busm_c();
// Register this device.
BX_REGISTER_DEVICE_DEVMODEL (plugin, type, theBusMouse, BX_PLUGIN_BUSMOUSE);
return(0); // Success
}
void libbusmouse_LTX_plugin_fini(void)
{
delete theBusMouse;
}
bx_busm_c::bx_busm_c()
{
put("BUSM");
}
bx_busm_c::~bx_busm_c()
{
BX_DEBUG(("Exit"));
}
void bx_busm_c::init(void)
{
BX_DEBUG(("Init $Id$"));
DEV_register_irq(BUS_MOUSE_IRQ, "Bus Mouse");
// Call our timer routine at 30hz
BX_BUSM_THIS timer_index =
bx_pc_system.register_timer(this, timer_handler, 33334, 1, 1, "bus mouse timer");
for (int i=0x23C; i<=0x23F; i++) {
DEV_register_ioread_handler(this, read_handler, i, "Bus Mouse", 1);
DEV_register_iowrite_handler(this, write_handler, i, "Bus Mouse", 1);
}
DEV_register_default_mouse(this, mouse_enq_static, NULL);
BX_BUSM_THIS mouse_delayed_dx = 0;
BX_BUSM_THIS mouse_delayed_dy = 0;
BX_BUSM_THIS current_x =
BX_BUSM_THIS current_y =
BX_BUSM_THIS current_b = 0;
BX_BUSM_THIS sig_port_sequ = 0;
BX_BUSM_THIS interrupts = 0; // interrupts off
BX_BUSM_THIS command_val = 0; // command byte
BX_BUSM_THIS cur_command = 0;
// the control port values
BX_BUSM_THIS control_val =
BX_BUSM_THIS control.mode_set =
BX_BUSM_THIS control.modeA_select =
BX_BUSM_THIS control.portA_dir =
BX_BUSM_THIS control.portC_upper_dir =
BX_BUSM_THIS control.modeBC_select =
BX_BUSM_THIS control.portB_dir =
BX_BUSM_THIS control.portC_lower_dir =
BX_BUSM_THIS control_val = 0;
BX_INFO(("Initialized BusMouse"));
}
void bx_busm_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "busmouse", "Busmouse State", 12);
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dx);
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dy);
BXRS_HEX_PARAM_FIELD(list, current_x, BX_BUSM_THIS current_x);
BXRS_HEX_PARAM_FIELD(list, current_y, BX_BUSM_THIS current_y);
BXRS_HEX_PARAM_FIELD(list, current_b, BX_BUSM_THIS current_b);
BXRS_HEX_PARAM_FIELD(list, sig_port_sequ, BX_BUSM_THIS sig_port_sequ);
BXRS_HEX_PARAM_FIELD(list, control_val, BX_BUSM_THIS control_val);
bx_list_c *ctrl = new bx_list_c(list, "control", 7);
BXRS_PARAM_BOOL(ctrl, mode_set, BX_BUSM_THIS control.mode_set);
BXRS_HEX_PARAM_FIELD(ctrl, modeA_select, BX_BUSM_THIS control.modeA_select);
BXRS_PARAM_BOOL(ctrl, portA_dir, BX_BUSM_THIS control.portA_dir);
BXRS_PARAM_BOOL(ctrl, portC_upper_dir, BX_BUSM_THIS control.portC_upper_dir);
BXRS_PARAM_BOOL(ctrl, modeBC_select, BX_BUSM_THIS control.modeBC_select);
BXRS_PARAM_BOOL(ctrl, portB_dir, BX_BUSM_THIS control.portB_dir);
BXRS_PARAM_BOOL(ctrl, portC_lower_dir, BX_BUSM_THIS control.portC_lower_dir);
BXRS_PARAM_BOOL(list, interrupts, BX_BUSM_THIS interrupts);
BXRS_PARAM_BOOL(list, packet_update, BX_BUSM_THIS packet_update);
BXRS_HEX_PARAM_FIELD(list, cur_command, BX_BUSM_THIS cur_command);
BXRS_HEX_PARAM_FIELD(list, command_val, BX_BUSM_THIS command_val);
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_busm_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_BUSM_SMF
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_busm_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_BUSM_SMF
Bit8u value = 0;
switch (address) {
case 0x023C:
value = BX_BUSM_THIS control_val;
/* value = (BX_BUSM_THIS control.mode_set ? 1<<7 : 0)
* | (BX_BUSM_THIS control.modeA_select <<5)
* | (BX_BUSM_THIS control.portA_dir ? 1<<4 : 0)
* | (BX_BUSM_THIS control.portC_upper_dir ? 1<<3 : 0)
* | (BX_BUSM_THIS control.modeBC_select ? 1<<2 : 0)
* | (BX_BUSM_THIS control.portB_dir ? 1<<1 : 0)
* | (BX_BUSM_THIS control.portC_lower_dir ? 1<<0 : 0);
*/ break;
case 0x023D: // data
switch (BX_BUSM_THIS cur_command) {
case 0x00: // read buttons
value = BX_BUSM_THIS current_b;
break;
case 0x01: // read x
value = BX_BUSM_THIS current_x;
break;
case 0x02: // read y
value = BX_BUSM_THIS current_y;
break;
case 0x07: // command mode
value = BX_BUSM_THIS command_val;
break;
default:
BX_PANIC(("Unknown command to data port: %x", BX_BUSM_THIS cur_command));
}
break;
case 0x023E: // sig
if (!(BX_BUSM_THIS sig_port_sequ & 1))
value = 0xDE;
else
value = 0x22; // Manufacture id?
BX_BUSM_THIS sig_port_sequ++;
break;
case 0x023F:
BX_PANIC(("Read from port 0x023F"));
break;
}
BX_INFO(("read from address 0x%04x, value = 0x%02x ", address, value));
return value;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_busm_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_BUSM_SMF
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_busm_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_BUSM_SMF
BX_INFO(("write to address 0x%04x, value = 0x%02x ", address, value));
switch (address) {
case 0x023C: // control
BX_BUSM_THIS control.mode_set = (value & 0x80) ? 1 : 0;
BX_BUSM_THIS control.modeA_select = (value & 0x60) >> 5;
BX_BUSM_THIS control.portA_dir = (value & 0x10) ? 1 : 0;
BX_BUSM_THIS control.portC_upper_dir = (value & 0x08) ? 1 : 0;
BX_BUSM_THIS control.modeBC_select = (value & 0x04) ? 1 : 0;
BX_BUSM_THIS control.portB_dir = (value & 0x02) ? 1 : 0;
BX_BUSM_THIS control.portC_lower_dir = (value & 0x01) ? 1 : 0;
BX_BUSM_THIS control_val = value;
/*
switch (value) {
case 0x00: // read buttons
case 0x01: // read x
case 0x02: // read y
case 0x07:
BX_BUSM_THIS cur_command = (Bit8u) value;
break;
case 0x80: // reset
BX_BUSM_THIS cur_command = 0x00;
BX_BUSM_THIS command_val = 0x80;
break;
default:
BX_PANIC(("Unknown command to control port %x", value));
}
*/
break;
case 0x023D: // data port
switch (BX_BUSM_THIS cur_command) {
case 0x07: // command mode
switch (value) {
case 0x10: // interrupts off
BX_BUSM_THIS interrupts = 0;
break;
case 0x11: // interrupts on
BX_BUSM_THIS interrupts = 1;
break;
default:
BX_BUSM_THIS command_val = value;
if ((value & 0x20) == 0)
DEV_pic_lower_irq(BUS_MOUSE_IRQ);
}
break;
default:
BX_PANIC(("Unknown command written to data port: %x", BX_BUSM_THIS cur_command));
}
break;
case 0x023E:
BX_PANIC(("Write to port 0x023E"));
break;
case 0x023F:
BX_PANIC(("Write to port 0x023F"));
break;
}
}
void bx_busm_c::mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state)
{
((bx_busm_c*)dev)->mouse_enq(delta_x, delta_y, delta_z, button_state);
}
void bx_busm_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state)
{
// scale down the motion
if ((delta_x < -1) || (delta_x > 1))
delta_x /= 2;
if ((delta_y < -1) || (delta_y > 1))
delta_y /= 2;
if(delta_x>127) delta_x=127;
if(delta_y>127) delta_y=127;
if(delta_x<-128) delta_x=-128;
if(delta_y<-128) delta_y=-128;
BX_BUSM_THIS mouse_delayed_dx+=delta_x;
BX_BUSM_THIS mouse_delayed_dy-=delta_y;
if (BX_BUSM_THIS mouse_delayed_dx > 127) {
delta_x = 127;
BX_BUSM_THIS mouse_delayed_dx -= 127;
} else if (BX_BUSM_THIS mouse_delayed_dx < -128) {
delta_x = -128;
BX_BUSM_THIS mouse_delayed_dx += 128;
} else {
delta_x = BX_BUSM_THIS mouse_delayed_dx;
BX_BUSM_THIS mouse_delayed_dx = 0;
}
if (BX_BUSM_THIS mouse_delayed_dy > 127) {
delta_y = 127;
BX_BUSM_THIS mouse_delayed_dy -= 127;
} else if (BX_BUSM_THIS mouse_delayed_dy < -128) {
delta_y = -128;
BX_BUSM_THIS mouse_delayed_dy += 128;
} else {
delta_y = BX_BUSM_THIS mouse_delayed_dy;
BX_BUSM_THIS mouse_delayed_dy = 0;
}
if ((BX_BUSM_THIS cur_command & 0x20) == 0x00) {
BX_BUSM_THIS current_x = (Bit8u) delta_x;
BX_BUSM_THIS current_y = (Bit8u) delta_y;
BX_BUSM_THIS current_b = (Bit8u) ~(((button_state & 0x01)<<2) | ((button_state & 0x02) >> 1));
}
}
void bx_busm_c::timer_handler(void *this_ptr)
{
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
class_ptr->busm_timer();
}
// Called at 30hz
void bx_busm_c::busm_timer(void)
{
// if interrupts are on, fire the interrupt
if (BX_BUSM_THIS interrupts) {
DEV_pic_raise_irq(BUS_MOUSE_IRQ);
}
}
#endif // BX_SUPPORT_BUSMOUSE

108
bochs/iodev/busmouse.h Normal file
View File

@ -0,0 +1,108 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#if BX_SUPPORT_BUSMOUSE
#ifndef _PCBUSM_H
#define _PCBUSM_H
// these keywords should only be used in busmouse.cc
#if BX_USE_BUSM_SMF
# define BX_BUSM_SMF static
# define BX_BUSM_THIS theBusMouse->
#else
# define BX_BUSM_SMF
# define BX_BUSM_THIS
#endif
#define BUS_MOUSE_IRQ 5
#define PORT_CONTROL 0x023C
#define PORT_DATA 0x023D
#define PORT_SIGNATURE 0x023E
#define PORT_CONFIG 0x023F
class bx_busm_c : public bx_devmodel_c {
public:
bx_busm_c();
virtual ~bx_busm_c();
virtual void init(void);
virtual void reset(unsigned type) {}
virtual void register_state(void);
private:
static void timer_handler(void *);
void busm_timer(void);
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
void mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_BUSM_SMF
void write(Bit32u address, Bit32u value, unsigned io_len);
Bit32u read(Bit32u address, unsigned io_len);
#endif
int timer_index; // our timer index
int mouse_delayed_dx;
int mouse_delayed_dy;
Bit8u current_x, current_y, current_b;
// signature port
Bit8u sig_port_sequ; // bit0: 0 or 1. A register read rotates between two values? 0xDE and Hardware ID?
// D7 = Mode set flag (1 = active)
// D6,D5 = Mode selection (port A)
// 00 = Mode 0 = Basic I/O
// 01 = Mode 1 = Strobed I/O
// 10 = Mode 2 = Bi-dir bus
// D4 = Port A direction (1 = input)
// D3 = Port C (upper 4 bits)
// direction. (1 = input)
// D2 = Mode selection (port B & C)
// 0 = Mode 0 = Basic I/O
// 1 = Mode 1 = Strobed I/O
// D1 = Port B direction (1 = input)
// D0 = Port C (lower 4 bits)
// direction. (1 = input)
Bit8u control_val;
struct {
bx_bool mode_set;
Bit8u modeA_select;
bx_bool portA_dir; // 1 = input
bx_bool portC_upper_dir; // 1 = input
bx_bool modeBC_select;
bx_bool portB_dir; // 1 = input
bx_bool portC_lower_dir; // 1 = input
} control;
bx_bool interrupts; // 0 or 1. interrupts off or on.
bx_bool packet_update; // 0 or 1. allow the mouse to update the packet?
Bit8u cur_command; // current command
Bit8u command_val; // current command val
};
#endif // #ifndef _PCBUSM_H
#endif // BX_SUPPORT_BUSMOUSE

1471
bochs/iodev/cdrom.cc Normal file

File diff suppressed because it is too large Load Diff

65
bochs/iodev/cdrom.h Normal file
View File

@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Header file for low-level OS specific CDROM emulation
class cdrom_interface : public logfunctions {
public:
cdrom_interface(const char *dev);
virtual ~cdrom_interface(void);
void init(void);
// Load CD-ROM. Returns 0 if CD is not ready.
bx_bool insert_cdrom(const char *dev = NULL);
// Logically eject the CD.
void eject_cdrom();
// Read CD TOC. Returns 0 if start track is out of bounds.
bx_bool read_toc(Bit8u* buf, int* length, bx_bool msf, int start_track, int format);
// Return CD-ROM capacity (in 2048 byte frames)
Bit32u capacity();
// Read a single block from the CD. Returns 0 on failure.
bx_bool read_block(Bit8u* buf, Bit32u lba, int blocksize) BX_CPP_AttrRegparmN(3);
// Start (spin up) the CD.
bx_bool start_cdrom();
// Seek for new block address.
void seek(Bit32u lba);
private:
int fd;
char *path;
int using_file;
#ifdef WIN32
BOOL bUseASPI;
HANDLE hFile;
int hid;
int tid;
int lun;
#endif
};

View File

@ -0,0 +1,271 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// These are the low-level CDROM functions which are called
// from 'harddrv.cc'. They effect the OS specific functionality
// needed by the CDROM emulation in 'harddrv.cc'. Mostly, just
// ioctl() calls and such. Should be fairly easy to add support
// for your OS if it is not supported yet.
#include "bochs.h"
#include "scsi_commands.h"
#include "cdrom.h"
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/trackdisk.h>
#include <devices/scsidisk.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <clib/alib_protos.h>
#include <stdio.h>
#define LOG_THIS /* no SMF tricks here, not needed */
#define BX_CD_FRAMESIZE 2048
#define CD_FRAMESIZE 2048
#define SENSELEN 32
#define MAX_DATA_LEN 252
int amiga_cd_unit;
char amiga_cd_device[256];
struct MsgPort *CDMP; /* Pointer for message port */
struct IOExtTD *CDIO; /* Pointer for IORequest */
int cd_error;
typedef struct {
UBYTE pad0;
UBYTE trackType;
UBYTE trackNum;
UBYTE pad1;
ULONG startFrame;
} TOCENTRY;
typedef struct {
UWORD length;
UBYTE firstTrack;
UBYTE lastTrack;
TOCENTRY tocs[100];
} TOC;
typedef struct {
ULONG sectors;
ULONG blocksize;
} CAPACITY;
unsigned char sensebuf[SENSELEN];
int DoSCSI (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
cdrom_interface::cdrom_interface(char *dev)
{
char buf[256];
sscanf(dev, "%s%s", amiga_cd_device, buf);
amiga_cd_unit = atoi(buf);
CDMP = CreateMsgPort();
if (CDMP != NULL) {
CDIO = (struct IOExtTD *)CreateIORequest(CDMP, sizeof(struct IOExtTD));
if (CDIO != NULL) {
cd_error = OpenDevice(amiga_cd_device, amiga_cd_unit, (struct IORequest *)CDIO, 0);
if (cd_error != 0)
BX_PANIC(("CD_Open: could not open device %s unit %d\n", amiga_cd_device, amiga_cd_unit));
}
}
}
cdrom_interface::~cdrom_interface(void)
{
if (cd_error == 0) {
CloseDevice((struct IORequest *)CDIO);
}
if (CDIO != NULL) {
DeleteIORequest((struct IORequest *)CDIO);
}
if (CDMP != NULL) {
DeleteMsgPort(CDMP);
}
}
bx_bool
cdrom_interface::insert_cdrom(char *dev)
{
Bit8u cdb[6];
Bit8u buf[2*BX_CD_FRAMESIZE];
Bit8u i = 0;
memset(cdb,0,sizeof(cdb));
cdb[0] = SCSI_DA_START_STOP_UNIT;
cdb[4] = 1 | 2;
DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ);
/*Check if there's a valid media present in the drive*/
CDIO->iotd_Req.io_Data = buf;
CDIO->iotd_Req.io_Command = CMD_READ;
CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE;
CDIO->iotd_Req.io_Offset = BX_CD_FRAMESIZE;
for(i = 0; i < 200; i++) /*it takes a while for the cdrom to validate*/
{
DoIO((struct IORequest *)CDIO);
if (CDIO->iotd_Req.io_Error == 0)
break;
Delay (10);
}
if (CDIO->iotd_Req.io_Error != 0)
return false;
else
return true;
}
void
cdrom_interface::eject_cdrom()
{
Bit8u cdb[6];
memset(cdb,0,sizeof(cdb));
cdb[0] = SCSI_DA_START_STOP_UNIT;
cdb[4] = 0 | 2;
DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ);
}
bx_bool
cdrom_interface::read_toc(Bit8u* buf, int* length, bx_bool msf, int start_track, int format)
{
Bit8u cdb[10];
TOC *toc;
toc = (TOC*) buf;
if (format != 0)
return false;
memset(cdb,0,sizeof(cdb));
cdb[0] = SCSI_CD_READ_TOC;
if (msf)
cdb[1] = 2;
else
cdb[1] = 0;
cdb[6] = start_track;
cdb[7] = sizeof(TOC)>>8;
cdb[8] = sizeof(TOC)&0xFF;
DoSCSI((UBYTE *)buf, sizeof(TOC), cdb, sizeof(cdb), SCSIF_READ);
*length = toc->length + 4;
return true;
}
Bit32u
cdrom_interface::capacity()
{
CAPACITY cap;
Bit8u cdb[10];
memset(cdb,0,sizeof(cdb));
cdb[0] = SCSI_DA_READ_CAPACITY;
int err;
if ((err = DoSCSI((UBYTE *)&cap, sizeof(cap),
cdb, sizeof (cdb),
(SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
return(cap.sectors);
else
BX_PANIC (("Couldn't get media capacity"));
}
bx_bool
cdrom_interface::read_block(Bit8u* buf, int lba, int blocksize)
{
CDIO->iotd_Req.io_Data = buf;
CDIO->iotd_Req.io_Command = CMD_READ;
CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE;
CDIO->iotd_Req.io_Offset = lba * BX_CD_FRAMESIZE;
DoIO((struct IORequest *)CDIO);
if (CDIO->iotd_Req.io_Error != 0) {
BX_PANIC(("Error %d reading CD data sector: %ld", CDIO->iotd_Req.io_Error, lba));
return 0;
}
return 1;
}
bx_bool
cdrom_interface::start_cdrom()
{
// Spin up the cdrom drive.
if (fd >= 0) {
BX_INFO(("start_cdrom: your OS is not supported yet."));
return 0; // OS not supported yet, return 0 always.
}
return 0;
}
int DoSCSI(UBYTE *data, int datasize, Bit8u *cmd,int cmdsize, UBYTE direction)
{
struct SCSICmd scmd;
CDIO->iotd_Req.io_Command = HD_SCSICMD;
CDIO->iotd_Req.io_Data = &scmd;
CDIO->iotd_Req.io_Length = sizeof(scmd);
scmd.scsi_Data = (UWORD *)data;
scmd.scsi_Length = datasize;
scmd.scsi_SenseActual = 0;
scmd.scsi_SenseData = sensebuf;
scmd.scsi_SenseLength = SENSELEN;
scmd.scsi_Command = cmd;
scmd.scsi_CmdLength = cmdsize;
scmd.scsi_Flags = SCSIF_AUTOSENSE | direction;
DoIO((struct IORequest *)CDIO);
if (CDIO->iotd_Req.io_Error != 0) {
BX_PANIC(("DoSCSI: error %d", CDIO->iotd_Req.io_Error));
}
return CDIO->iotd_Req.io_Error;
}
void cdrom_interface::seek(int lba)
{
unsigned char buffer[BX_CD_FRAMESIZE];
read_block(buffer, lba, BX_CD_FRAMESIZE);
}

74
bochs/iodev/cdrom_beos.cc Normal file
View File

@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <SupportDefs.h>
#include <Drivers.h>
#include <sys/stat.h>
#include <unistd.h>
#include "cdrom_beos.h"
int GetLogicalBlockSize(int fd)
{
partition_info p_info;
if (ioctl(fd, B_GET_PARTITION_INFO, &p_info) == B_NO_ERROR)
{
//dprintf("GetLogicalBlockSize: ioctl suceed\n");
return p_info.logical_block_size;
}
else //dprintf("GetLogicalBlockSize = ioctl returned error\n");
return 0;
}
int GetDeviceBlockSize(int fd)
{
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) < 0)
{
if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode))
return 0;
return 512; /* just assume it's a plain old file or something */
}
return dg.bytes_per_sector;
}
off_t GetNumDeviceBlocks(int fd, int block_size)
{
struct stat st;
device_geometry dg;
if (ioctl(fd, B_GET_GEOMETRY, &dg) >= 0)
{
return (off_t)dg.cylinder_count *
(off_t)dg.sectors_per_track *
(off_t)dg.head_count;
}
/* if the ioctl fails, try just stat'ing in case it's a regular file */
if (fstat(fd, &st) < 0)
return 0;
return st.st_size / block_size;
}

33
bochs/iodev/cdrom_beos.h Normal file
View File

@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef CDROM_BEOS_H
#define CDROM_BEOS_H
#include <stddef.h> // for off_t
off_t GetNumDeviceBlocks(int fd, int block_size);
int GetLogicalBlockSize(int fd);
int GetDeviceBlockSize(int fd);
#endif

828
bochs/iodev/cmos.cc Normal file
View File

@ -0,0 +1,828 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "cmos.h"
#define LOG_THIS theCmosDevice->
bx_cmos_c *theCmosDevice = NULL;
// CMOS register definitions from Ralf Brown's interrupt list v6.1, in a file
// called cmos.lst. In cases where there are multiple uses for a given
// register in the interrupt list, I only listed the purpose that Bochs
// actually uses it for, but I wrote "alternatives" next to it.
#define REG_SEC 0x00
#define REG_SEC_ALARM 0x01
#define REG_MIN 0x02
#define REG_MIN_ALARM 0x03
#define REG_HOUR 0x04
#define REG_HOUR_ALARM 0x05
#define REG_WEEK_DAY 0x06
#define REG_MONTH_DAY 0x07
#define REG_MONTH 0x08
#define REG_YEAR 0x09
#define REG_STAT_A 0x0a
#define REG_STAT_B 0x0b
#define REG_STAT_C 0x0c
#define REG_STAT_D 0x0d
#define REG_DIAGNOSTIC_STATUS 0x0e /* alternatives */
#define REG_SHUTDOWN_STATUS 0x0f
#define REG_EQUIPMENT_BYTE 0x14
#define REG_CSUM_HIGH 0x2e
#define REG_CSUM_LOW 0x2f
#define REG_IBM_CENTURY_BYTE 0x32 /* alternatives */
#define REG_IBM_PS2_CENTURY_BYTE 0x37 /* alternatives */
// Bochs CMOS map
//
// Idx Len Description
// 0x10 1 floppy drive types
// 0x11 1 configuration bits
// 0x12 1 harddisk types
// 0x13 1 advanced configuration bits
// 0x15 2 base memory in 1k
// 0x17 2 memory size above 1M in 1k
// 0x19 2 extended harddisk types
// 0x1b 9 harddisk configuration (hd0)
// 0x24 9 harddisk configuration (hd1)
// 0x2d 1 boot sequence (fd/hd)
// 0x30 2 memory size above 1M in 1k
// 0x34 2 memory size above 16M in 64k
// 0x38 1 eltorito boot sequence (#3) + bootsig check
// 0x39 2 ata translation policy (ata0...ata3)
// 0x3d 1 eltorito boot sequence (#1 + #2)
//
// Qemu CMOS map
//
// Idx Len Description
// 0x5b 3 extra memory above 4GB
// 0x5f 1 number of processors
Bit8u bcd_to_bin(Bit8u value, bx_bool is_binary)
{
if (is_binary)
return value;
else
return ((value >> 4) * 10) + (value & 0x0f);
}
Bit8u bin_to_bcd(Bit8u value, bx_bool is_binary)
{
if (is_binary)
return value;
else
return ((value / 10) << 4) | (value % 10);
}
int libcmos_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theCmosDevice = new bx_cmos_c();
bx_devices.pluginCmosDevice = theCmosDevice;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theCmosDevice, BX_PLUGIN_CMOS);
return(0); // Success
}
void libcmos_LTX_plugin_fini(void)
{ if (theCmosDevice != NULL)
{ delete theCmosDevice;
theCmosDevice = NULL;
}
}
bx_cmos_c::bx_cmos_c(void)
{
put("CMOS");
for (unsigned i=0; i<128; i++) s.reg[i] = 0;
s.periodic_timer_index = BX_NULL_TIMER_HANDLE;
s.one_second_timer_index = BX_NULL_TIMER_HANDLE;
s.uip_timer_index = BX_NULL_TIMER_HANDLE;
}
bx_cmos_c::~bx_cmos_c(void)
{
save_image();
char *tmptime;
if ((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) != NULL) {
tmptime[strlen(tmptime)-1]='\0';
BX_INFO(("Last time is %u (%s)", (unsigned) get_timeval(), tmptime));
free(tmptime);
}
BX_DEBUG(("Exit"));
}
void bx_cmos_c::init(void)
{
BX_DEBUG(("Init $Id$"));
// CMOS RAM & RTC
DEV_register_ioread_handler(this, read_handler, 0x0070, "CMOS RAM", 1);
DEV_register_ioread_handler(this, read_handler, 0x0071, "CMOS RAM", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0070, "CMOS RAM", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0071, "CMOS RAM", 1);
DEV_register_irq(8, "CMOS RTC");
if (BX_CMOS_THIS s.periodic_timer_index == BX_NULL_TIMER_HANDLE) {
BX_CMOS_THIS s.periodic_timer_index =
DEV_register_timer(this, periodic_timer_handler,
1000000, 1,0, "cmos"); // continuous, not-active
}
if (BX_CMOS_THIS s.one_second_timer_index == BX_NULL_TIMER_HANDLE) {
BX_CMOS_THIS s.one_second_timer_index =
DEV_register_timer(this, one_second_timer_handler,
1000000, 1,0, "cmos"); // continuous, not-active
}
if (BX_CMOS_THIS s.uip_timer_index == BX_NULL_TIMER_HANDLE) {
BX_CMOS_THIS s.uip_timer_index =
DEV_register_timer(this, uip_timer_handler,
244, 0, 0, "cmos"); // one-shot, not-active
}
if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_LOCAL) {
BX_INFO(("Using local time for initial clock"));
BX_CMOS_THIS s.timeval = time(NULL);
} else if (SIM->get_param_num(BXPN_CLOCK_TIME0)->get() == BX_CLOCK_TIME0_UTC) {
bx_bool utc_ok = 0;
BX_INFO(("Using utc time for initial clock"));
BX_CMOS_THIS s.timeval = time(NULL);
#if BX_HAVE_GMTIME
#if BX_HAVE_MKTIME
struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
utc_holder->tm_isdst = -1;
utc_ok = 1;
BX_CMOS_THIS s.timeval = mktime(utc_holder);
#elif BX_HAVE_TIMELOCAL
struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
utc_holder->tm_isdst = 0; // XXX Is this correct???
utc_ok = 1;
BX_CMOS_THIS s.timeval = timelocal(utc_holder);
#endif //BX_HAVE_MKTIME
#endif //BX_HAVE_GMTIME
if (!utc_ok) {
BX_ERROR(("UTC time is not supported on your platform. Using current time(NULL)"));
}
} else {
BX_INFO(("Using specified time for initial clock"));
BX_CMOS_THIS s.timeval = SIM->get_param_num(BXPN_CLOCK_TIME0)->get();
}
// load CMOS from image file if requested.
if (SIM->get_param_bool(BXPN_CMOSIMAGE_ENABLED)->get()) {
int fd, ret;
struct stat stat_buf;
fd = open(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr(), O_RDONLY
#ifdef O_BINARY
| O_BINARY
#endif
);
if (fd < 0) {
BX_PANIC(("trying to open cmos image file '%s'",
SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()));
}
ret = fstat(fd, &stat_buf);
if (ret) {
BX_PANIC(("CMOS: could not fstat() image file."));
}
if ((stat_buf.st_size != 64) && (stat_buf.st_size != 128)) {
BX_PANIC(("CMOS: image file size must be 64 or 128"));
}
ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, (unsigned)stat_buf.st_size);
if (ret != stat_buf.st_size) {
BX_PANIC(("CMOS: error reading cmos file."));
}
close(fd);
BX_INFO(("successfuly read from image file '%s'.",
SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr()));
BX_CMOS_THIS s.rtc_mode_12hour = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x02) == 0);
BX_CMOS_THIS s.rtc_mode_binary = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x04) != 0);
if (SIM->get_param_bool(BXPN_CMOSIMAGE_RTC_INIT)->get()) {
update_timeval();
} else {
update_clock();
}
} else {
// CMOS values generated
BX_CMOS_THIS s.reg[REG_STAT_A] = 0x26;
BX_CMOS_THIS s.reg[REG_STAT_B] = 0x02;
BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
BX_CMOS_THIS s.reg[REG_STAT_D] = 0x80;
#if BX_SUPPORT_FPU == 1
BX_CMOS_THIS s.reg[REG_EQUIPMENT_BYTE] |= 0x02;
#endif
BX_CMOS_THIS s.rtc_mode_12hour = 0;
BX_CMOS_THIS s.rtc_mode_binary = 0;
update_clock();
}
char *tmptime;
while((tmptime = strdup(ctime(&(BX_CMOS_THIS s.timeval)))) == NULL) {
BX_PANIC(("Out of memory."));
}
tmptime[strlen(tmptime)-1]='\0';
BX_INFO(("Setting initial clock to: %s (time0=%u)", tmptime, (Bit32u)BX_CMOS_THIS s.timeval));
free(tmptime);
BX_CMOS_THIS s.timeval_change = 0;
}
void bx_cmos_c::reset(unsigned type)
{
BX_CMOS_THIS s.cmos_mem_address = 0;
// RESET affects the following registers:
// CRA: no effects
// CRB: bits 4,5,6 forced to 0
// CRC: bits 4,5,6,7 forced to 0
// CRD: no effects
BX_CMOS_THIS s.reg[REG_STAT_B] &= 0x8f;
BX_CMOS_THIS s.reg[REG_STAT_C] = 0;
// One second timer for updating clock & alarm functions
bx_pc_system.activate_timer(BX_CMOS_THIS s.one_second_timer_index,
1000000, 1);
// handle periodic interrupt rate select
BX_CMOS_THIS CRA_change();
}
void bx_cmos_c::save_image(void)
{
int fd, ret;
// save CMOS to image file if requested.
if (SIM->get_param_bool(BXPN_CMOSIMAGE_ENABLED)->get()) {
fd = open(SIM->get_param_string(BXPN_CMOSIMAGE_PATH)->getptr(), O_WRONLY
#ifdef O_BINARY
| O_BINARY
#endif
);
ret = ::write(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, 128);
if (ret != 128) {
BX_PANIC(("CMOS: error writing cmos file."));
}
close(fd);
}
}
void bx_cmos_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "cmos", "CMOS State", 2);
BXRS_HEX_PARAM_FIELD(list, mem_address, BX_CMOS_THIS s.cmos_mem_address);
bx_list_c *ram = new bx_list_c(list, "ram", 128);
for (unsigned i=0; i<128; i++) {
char name[6];
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(ram, name, &BX_CMOS_THIS s.reg[i], BASE_HEX);
}
}
void bx_cmos_c::after_restore_state(void)
{
BX_CMOS_THIS s.rtc_mode_12hour = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x02) == 0);
BX_CMOS_THIS s.rtc_mode_binary = ((BX_CMOS_THIS s.reg[REG_STAT_B] & 0x04) != 0);
BX_CMOS_THIS update_timeval();
BX_CMOS_THIS CRA_change();
}
void bx_cmos_c::CRA_change(void)
{
Bit8u nibble, dcc;
// Periodic Interrupt timer
nibble = BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f;
dcc = (BX_CMOS_THIS s.reg[REG_STAT_A] >> 4) & 0x07;
if ((nibble == 0) || ((dcc & 0x06) == 0)) {
// No Periodic Interrupt Rate when 0, deactivate timer
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
BX_CMOS_THIS s.periodic_interval_usec = (Bit32u) -1; // max value
} else {
// values 0001b and 0010b are the same as 1000b and 1001b
if (nibble <= 2)
nibble += 7;
BX_CMOS_THIS s.periodic_interval_usec = (unsigned) (1000000.0L /
(32768.0L / (1 << (nibble - 1))));
// if Periodic Interrupt Enable bit set, activate timer
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40)
bx_pc_system.activate_timer(BX_CMOS_THIS s.periodic_timer_index,
BX_CMOS_THIS s.periodic_interval_usec, 1);
else
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_cmos_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_CMOS_SMF
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_cmos_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif
Bit8u ret8;
BX_DEBUG(("CMOS read of CMOS register 0x%02x", (unsigned) BX_CMOS_THIS s.cmos_mem_address));
switch (address) {
case 0x0070:
// this register is write-only on most machines
BX_DEBUG(("read of index port 0x70. returning 0xff"));
return(0xff);
case 0x0071:
ret8 = BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address];
// all bits of Register C are cleared after a read occurs.
if (BX_CMOS_THIS s.cmos_mem_address == REG_STAT_C) {
BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
DEV_pic_lower_irq(8);
}
return(ret8);
default:
BX_PANIC(("unsupported cmos read, address=0x%04x!", (unsigned) address));
return(0);
}
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_cmos_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_CMOS_SMF
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_cmos_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_CMOS_SMF
BX_DEBUG(("CMOS write to address: 0x%04x = 0x%02x", address, value));
switch (address) {
case 0x0070:
BX_CMOS_THIS s.cmos_mem_address = value & 0x7F;
break;
case 0x0071:
switch (BX_CMOS_THIS s.cmos_mem_address) {
case REG_SEC_ALARM: // seconds alarm
case REG_MIN_ALARM: // minutes alarm
case REG_HOUR_ALARM: // hours alarm
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
BX_DEBUG(("alarm time changed to %02x:%02x:%02x", BX_CMOS_THIS s.reg[REG_HOUR_ALARM],
BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM]));
break;
case REG_SEC: // seconds
case REG_MIN: // minutes
case REG_HOUR: // hours
case REG_WEEK_DAY: // day of the week
case REG_MONTH_DAY: // day of the month
case REG_MONTH: // month
case REG_YEAR: // year
case REG_IBM_CENTURY_BYTE: // century
case REG_IBM_PS2_CENTURY_BYTE: // century (PS/2)
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
if (BX_CMOS_THIS s.cmos_mem_address == REG_IBM_PS2_CENTURY_BYTE) {
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = value;
}
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80) {
BX_CMOS_THIS s.timeval_change = 1;
} else {
update_timeval();
}
break;
case REG_STAT_A: // Control Register A
// bit 7: Update in Progress (read-only)
// 1 = signifies time registers will be updated within 244us
// 0 = time registers will not occur before 244us
// note: this bit reads 0 when CRB bit 7 is 1
// bit 6..4: Divider Chain Control
// 000 oscillator disabled
// 001 oscillator disabled
// 010 Normal operation
// 011 TEST
// 100 TEST
// 101 TEST
// 110 Divider Chain RESET
// 111 Divider Chain RESET
// bit 3..0: Periodic Interrupt Rate Select
// 0000 None
// 0001 3.90625 ms
// 0010 7.8125 ms
// 0011 122.070 us
// 0100 244.141 us
// 0101 488.281 us
// 0110 976.562 us
// 0111 1.953125 ms
// 1000 3.90625 ms
// 1001 7.8125 ms
// 1010 15.625 ms
// 1011 31.25 ms
// 1100 62.5 ms
// 1101 125 ms
// 1110 250 ms
// 1111 500 ms
unsigned dcc;
dcc = (value >> 4) & 0x07;
if ((dcc & 0x06) == 0x06) {
BX_INFO(("CRA: divider chain RESET"));
} else if (dcc > 0x02) {
BX_PANIC(("CRA: divider chain control 0x%02x", dcc));
}
BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x80;
BX_CMOS_THIS s.reg[REG_STAT_A] |= (value & 0x7f);
BX_CMOS_THIS CRA_change();
break;
case REG_STAT_B: // Control Register B
// bit 0: Daylight Savings Enable
// 1 = enable daylight savings
// 0 = disable daylight savings
// bit 1: 24/12 hour mode
// 1 = 24 hour format
// 0 = 12 hour format
// bit 2: Data Mode
// 1 = binary format
// 0 = BCD format
// bit 3: "square wave enable"
// Not supported and always read as 0
// bit 4: Update Ended Interrupt Enable
// 1 = enable generation of update ended interrupt
// 0 = disable
// bit 5: Alarm Interrupt Enable
// 1 = enable generation of alarm interrupt
// 0 = disable
// bit 6: Periodic Interrupt Enable
// 1 = enable generation of periodic interrupt
// 0 = disable
// bit 7: Set mode
// 1 = user copy of time is "frozen" allowing time registers
// to be accessed without regard for an occurance of an update
// 0 = time updates occur normally
if (value & 0x01)
BX_ERROR(("write status reg B, daylight savings unsupported"));
value &= 0xf7; // bit3 always 0
// Note: setting bit 7 clears bit 4
if (value & 0x80)
value &= 0xef;
unsigned prev_CRB;
prev_CRB = BX_CMOS_THIS s.reg[REG_STAT_B];
BX_CMOS_THIS s.reg[REG_STAT_B] = value;
if ((prev_CRB & 0x02) != (value & 0x02)) {
BX_CMOS_THIS s.rtc_mode_12hour = ((value & 0x02) == 0);
update_clock();
}
if ((prev_CRB & 0x04) != (value & 0x04)) {
BX_CMOS_THIS s.rtc_mode_binary = ((value & 0x04) != 0);
update_clock();
}
if ((prev_CRB & 0x40) != (value & 0x40)) {
// Periodic Interrupt Enabled changed
if (prev_CRB & 0x40) {
// transition from 1 to 0, deactivate timer
bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
} else {
// transition from 0 to 1
// if rate select is not 0, activate timer
if ((BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f) != 0) {
bx_pc_system.activate_timer(
BX_CMOS_THIS s.periodic_timer_index,
BX_CMOS_THIS s.periodic_interval_usec, 1);
}
}
}
if ((prev_CRB >= 0x80) && (value < 0x80) && BX_CMOS_THIS s.timeval_change) {
update_timeval();
BX_CMOS_THIS s.timeval_change = 0;
}
break;
case REG_STAT_C: // Control Register C
case REG_STAT_D: // Control Register D
BX_ERROR(("write to control register 0x%02x ignored (read-only)",
BX_CMOS_THIS s.cmos_mem_address));
break;
case REG_DIAGNOSTIC_STATUS:
BX_DEBUG(("write register 0x0e: 0x%02x", value));
BX_CMOS_THIS s.reg[REG_DIAGNOSTIC_STATUS] = value;
break;
case REG_SHUTDOWN_STATUS:
switch (value) {
case 0x00: /* proceed with normal POST (soft reset) */
BX_DEBUG(("Reg 0Fh(00): shutdown action = normal POST"));
break;
case 0x01: /* shutdown after memory size check */
BX_DEBUG(("Reg 0Fh(01): request to change shutdown action"
" to shutdown after memory size check"));
break;
case 0x02: /* shutdown after successful memory test */
BX_DEBUG(("Reg 0Fh(02): request to change shutdown action"
" to shutdown after successful memory test"));
break;
case 0x03: /* shutdown after failed memory test */
BX_DEBUG(("Reg 0Fh(03): request to change shutdown action"
" to shutdown after successful memory test"));
break;
case 0x04: /* jump to disk bootstrap routine */
BX_DEBUG(("Reg 0Fh(04): request to change shutdown action "
"to jump to disk bootstrap routine."));
break;
case 0x05: /* flush keyboard (issue EOI) and jump via 40h:0067h */
BX_DEBUG(("Reg 0Fh(05): request to change shutdown action "
"to flush keyboard (issue EOI) and jump via 40h:0067h."));
break;
case 0x06:
BX_DEBUG(("Reg 0Fh(06): Shutdown after memory test !"));
break;
case 0x07: /* reset (after failed test in virtual mode) */
BX_DEBUG(("Reg 0Fh(07): request to change shutdown action "
"to reset (after failed test in virtual mode)."));
break;
case 0x08: /* used by POST during protected-mode RAM test (return to POST) */
BX_DEBUG(("Reg 0Fh(08): request to change shutdown action "
"to return to POST (used by POST during protected-mode RAM test)."));
break;
case 0x09: /* return to BIOS extended memory block move
(interrupt 15h, func 87h was in progress) */
BX_DEBUG(("Reg 0Fh(09): request to change shutdown action "
"to return to BIOS extended memory block move."));
break;
case 0x0a: /* jump to DWORD pointer at 40:67 */
BX_DEBUG(("Reg 0Fh(0a): request to change shutdown action"
" to jump to DWORD at 40:67"));
break;
case 0x0b: /* iret to DWORD pointer at 40:67 */
BX_DEBUG(("Reg 0Fh(0b): request to change shutdown action"
" to iret to DWORD at 40:67"));
break;
case 0x0c: /* retf to DWORD pointer at 40:67 */
BX_DEBUG(("Reg 0Fh(0c): request to change shutdown action"
" to retf to DWORD at 40:67"));
break;
default:
BX_ERROR(("unsupported shutdown status: 0x%02x!", value));
}
BX_CMOS_THIS s.reg[REG_SHUTDOWN_STATUS] = value;
break;
default:
BX_DEBUG(("write reg 0x%02x: value = 0x%02x",
BX_CMOS_THIS s.cmos_mem_address, value));
BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
}
break;
}
}
void bx_cmos_c::checksum_cmos(void)
{
Bit16u sum = 0;
for (unsigned i=0x10; i<=0x2d; i++)
sum += BX_CMOS_THIS s.reg[i];
BX_CMOS_THIS s.reg[REG_CSUM_HIGH] = (sum >> 8) & 0xff; /* checksum high */
BX_CMOS_THIS s.reg[REG_CSUM_LOW] = (sum & 0xff); /* checksum low */
}
void bx_cmos_c::periodic_timer_handler(void *this_ptr)
{
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
class_ptr->periodic_timer();
}
void bx_cmos_c::periodic_timer()
{
// if periodic interrupts are enabled, trip IRQ 8, and
// update status register C
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40) {
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xc0; // Interrupt Request, Periodic Int
DEV_pic_raise_irq(8);
}
}
void bx_cmos_c::one_second_timer_handler(void *this_ptr)
{
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
class_ptr->one_second_timer();
}
void bx_cmos_c::one_second_timer()
{
// divider chain reset - RTC stopped
if ((BX_CMOS_THIS s.reg[REG_STAT_A] & 0x60) == 0x60)
return;
// update internal time/date buffer
BX_CMOS_THIS s.timeval++;
// Dont update CMOS user copy of time/date if CRB bit7 is 1
// Nothing else do to
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80)
return;
BX_CMOS_THIS s.reg[REG_STAT_A] |= 0x80; // set UIP bit
// UIP timer for updating clock & alarm functions
bx_pc_system.activate_timer(BX_CMOS_THIS s.uip_timer_index, 244, 0);
}
void bx_cmos_c::uip_timer_handler(void *this_ptr)
{
bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
class_ptr->uip_timer();
}
void bx_cmos_c::uip_timer()
{
update_clock();
// if update interrupts are enabled, trip IRQ 8, and
// update status register C
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x10) {
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0x90; // Interrupt Request, Update Ended
DEV_pic_raise_irq(8);
}
// compare CMOS user copy of time/date to alarm time/date here
if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x20) {
// Alarm interrupts enabled
bx_bool alarm_match = 1;
if ((BX_CMOS_THIS s.reg[REG_SEC_ALARM] & 0xc0) != 0xc0) {
// seconds alarm not in dont care mode
if (BX_CMOS_THIS s.reg[REG_SEC] != BX_CMOS_THIS s.reg[REG_SEC_ALARM])
alarm_match = 0;
}
if ((BX_CMOS_THIS s.reg[REG_MIN_ALARM] & 0xc0) != 0xc0) {
// minutes alarm not in dont care mode
if (BX_CMOS_THIS s.reg[REG_MIN] != BX_CMOS_THIS s.reg[REG_MIN_ALARM])
alarm_match = 0;
}
if ((BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0xc0) != 0xc0) {
// hours alarm not in dont care mode
if (BX_CMOS_THIS s.reg[REG_HOUR] != BX_CMOS_THIS s.reg[REG_HOUR_ALARM])
alarm_match = 0;
}
if (alarm_match) {
BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xa0; // Interrupt Request, Alarm Int
DEV_pic_raise_irq(8);
}
}
BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x7f; // clear UIP bit
}
void bx_cmos_c::update_clock()
{
struct tm *time_calendar;
unsigned year, month, day, century;
Bit8u val_bcd, hour;
time_calendar = localtime(& BX_CMOS_THIS s.timeval);
// update seconds
BX_CMOS_THIS s.reg[REG_SEC] = bin_to_bcd(time_calendar->tm_sec,
BX_CMOS_THIS s.rtc_mode_binary);
// update minutes
BX_CMOS_THIS s.reg[REG_MIN] = bin_to_bcd(time_calendar->tm_min,
BX_CMOS_THIS s.rtc_mode_binary);
// update hours
if (BX_CMOS_THIS s.rtc_mode_12hour) {
hour = time_calendar->tm_hour;
val_bcd = (hour > 11) ? 0x80 : 0x00;
if (hour > 11) hour -= 12;
if (hour == 0) hour = 12;
val_bcd |= bin_to_bcd(hour, BX_CMOS_THIS s.rtc_mode_binary);
BX_CMOS_THIS s.reg[REG_HOUR] = val_bcd;
} else {
BX_CMOS_THIS s.reg[REG_HOUR] = bin_to_bcd(time_calendar->tm_hour,
BX_CMOS_THIS s.rtc_mode_binary);
}
// update day of the week
day = time_calendar->tm_wday + 1; // 0..6 to 1..7
BX_CMOS_THIS s.reg[REG_WEEK_DAY] = bin_to_bcd(day,
BX_CMOS_THIS s.rtc_mode_binary);
// update day of the month
day = time_calendar->tm_mday;
BX_CMOS_THIS s.reg[REG_MONTH_DAY] = bin_to_bcd(day,
BX_CMOS_THIS s.rtc_mode_binary);
// update month
month = time_calendar->tm_mon + 1;
BX_CMOS_THIS s.reg[REG_MONTH] = bin_to_bcd(month,
BX_CMOS_THIS s.rtc_mode_binary);
// update year
year = time_calendar->tm_year % 100;
BX_CMOS_THIS s.reg[REG_YEAR] = bin_to_bcd(year,
BX_CMOS_THIS s.rtc_mode_binary);
// update century
century = (time_calendar->tm_year / 100) + 19;
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = bin_to_bcd(century,
BX_CMOS_THIS s.rtc_mode_binary);
// Raul Hudea pointed out that some bioses also use reg 0x37 for the
// century byte. Tony Heller says this is critical in getting WinXP to run.
BX_CMOS_THIS s.reg[REG_IBM_PS2_CENTURY_BYTE] =
BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE];
}
void bx_cmos_c::update_timeval()
{
struct tm time_calendar;
Bit8u val_bin, pm_flag;
// update seconds
time_calendar.tm_sec = bcd_to_bin(BX_CMOS_THIS s.reg[REG_SEC],
BX_CMOS_THIS s.rtc_mode_binary);
// update minutes
time_calendar.tm_min = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MIN],
BX_CMOS_THIS s.rtc_mode_binary);
// update hours
if (BX_CMOS_THIS s.rtc_mode_12hour) {
pm_flag = BX_CMOS_THIS s.reg[REG_HOUR] & 0x80;
val_bin = bcd_to_bin(BX_CMOS_THIS s.reg[REG_HOUR] & 0x70,
BX_CMOS_THIS s.rtc_mode_binary);
if ((val_bin < 12) & (pm_flag > 0)) {
val_bin += 12;
} else if ((val_bin == 12) & (pm_flag == 0)) {
val_bin = 0;
}
time_calendar.tm_hour = val_bin;
} else {
time_calendar.tm_hour = bcd_to_bin(BX_CMOS_THIS s.reg[REG_HOUR],
BX_CMOS_THIS s.rtc_mode_binary);
}
// update day of the month
time_calendar.tm_mday = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MONTH_DAY],
BX_CMOS_THIS s.rtc_mode_binary);
// update month
time_calendar.tm_mon = bcd_to_bin(BX_CMOS_THIS s.reg[REG_MONTH],
BX_CMOS_THIS s.rtc_mode_binary) - 1;
// update year
val_bin = bcd_to_bin(BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE],
BX_CMOS_THIS s.rtc_mode_binary);
val_bin = (val_bin - 19) * 100;
val_bin += bcd_to_bin(BX_CMOS_THIS s.reg[REG_YEAR],
BX_CMOS_THIS s.rtc_mode_binary);
time_calendar.tm_year = val_bin;
BX_CMOS_THIS s.timeval = mktime(& time_calendar);
}

91
bochs/iodev/cmos.h Normal file
View File

@ -0,0 +1,91 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_CMOS_H
#define BX_IODEV_CMOS_H
#if BX_USE_CMOS_SMF
# define BX_CMOS_SMF static
# define BX_CMOS_THIS theCmosDevice->
#else
# define BX_CMOS_SMF
# define BX_CMOS_THIS this->
#endif
class bx_cmos_c : public bx_cmos_stub_c {
public:
bx_cmos_c();
virtual ~bx_cmos_c();
virtual void init(void);
virtual void checksum_cmos(void);
virtual void reset(unsigned type);
virtual void save_image(void);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u get_reg(unsigned reg) {
return s.reg[reg];
}
virtual void set_reg(unsigned reg, Bit32u val) {
s.reg[reg] = val;
}
virtual time_t get_timeval() {
return s.timeval;
}
struct {
int periodic_timer_index;
Bit32u periodic_interval_usec;
int one_second_timer_index;
int uip_timer_index;
time_t timeval;
Bit8u cmos_mem_address;
bx_bool timeval_change;
bx_bool rtc_mode_12hour;
bx_bool rtc_mode_binary;
Bit8u reg[128];
} s; // state information
private:
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_CMOS_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned len);
#endif
public:
static void periodic_timer_handler(void *);
static void one_second_timer_handler(void *);
static void uip_timer_handler(void *);
BX_CMOS_SMF void periodic_timer(void);
BX_CMOS_SMF void one_second_timer(void);
BX_CMOS_SMF void uip_timer(void);
private:
BX_CMOS_SMF void update_clock(void);
BX_CMOS_SMF void update_timeval(void);
BX_CMOS_SMF void CRA_change(void);
};
#endif

52
bochs/iodev/crc32.cc Normal file
View File

@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
/* CRC-32 calculator
* Adapted from http://www.createwindow.org/programming/crc32/
*/
#include "crc32.h"
CRC_Generator::CRC_Generator() {
init();
}
void CRC_Generator::init(void)
{
Bit32u POLYNOMIAL = 0x04c11db7;
int i;
for(i = 0; i<0xFF; i++) {
int j;
crc32_table[i]=reflect(i,8) << 24;
for(j=0; j<8; j++)
crc32_table[i] = (crc32_table[i]<<1)^(crc32_table[i] & (1<<31) ? POLYNOMIAL : 0);
crc32_table[i] = reflect(crc32_table[i], 32);
}
}
Bit32u CRC_Generator::reflect(Bit32u ref, Bit8u ch)
{
Bit32u value(0);
int i;
for(i=1; i<(ch+1); i++) {
if(ref & 1)
value |= 1 << (ch-i);
ref >>= 1;
}
return value;
}
Bit32u CRC_Generator::get_CRC(Bit8u * buf, Bit32u buflen)
{
Bit32u ulCRC(0xFFFFFFFF);
Bit32u len(buflen);
Bit8u * buffer=(Bit8u *) buf;
while(len--)
ulCRC=(ulCRC>>8)^crc32_table[(ulCRC & 0xFF)^*buffer++];
return ulCRC ^ 0xFFFFFFFF;
}

25
bochs/iodev/crc32.h Normal file
View File

@ -0,0 +1,25 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
/* CRC-32 calculator
* Adapted from http://www.createwindow.org/programming/crc32/
*/
#ifndef _CRC_32_H_
#define _CRC_32_H_
#include "config.h"
class CRC_Generator {
private:
Bit32u crc32_table[256];
Bit32u reflect(Bit32u ref, Bit8u ch);
public:
void init(void);
CRC_Generator();
Bit32u get_CRC(Bit8u * buf, Bit32u buflen);
};
#endif //_CRC_32_H_

1212
bochs/iodev/devices.cc Normal file

File diff suppressed because it is too large Load Diff

109
bochs/iodev/devices.txt Executable file
View File

@ -0,0 +1,109 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
MOTHER BOARD (i440FX Support) devices.cc
|
+---- 82441FX (PMC) and 82442 (DBX) emulation pci.cc
|
+---- 82371SB (PIIX3) PCI ISA IDE XCELERATOR
| |
| +---- PCI-to-ISA bridge pci2isa.cc
| +---- PCI IDE controller pci_ide.cc
| |
| +---- PIIX4 ACPI support acpi.cc
|
+---- PCI host device mapping (Linux only) pcidev.cc
|
+---- Integrated peripherals
| |
| +---- 8259A PIC pic.cc
| +---- 82093AA I/O APIC ioapic.cc
| +---- 8254/82C54 Programmable Interval Timer pit_wrap.cc, pit82c54.cc
| | |
| | +---- PC Speaker (lowlevel) speaker.cc
|
| +---- 8237 DMA controller dma.cc
| +---- 82077A Floppy Drive Controller (*) floppy.cc
| +---- CMOS device cmos.cc
| +---- External circuit for #FERR pin extfpuirq.cc
| +---- Parallel ports emulation parallel.cc
| +---- UART 16550A Serial Port serial.cc
| | |
| | +---- Host specific Modules serial_raw.cc
| |
| +---- Standard PC gameport gameport.cc
|
+-------------- Debugging/Instrumentation biosdev.cc, iodebug.cc, unmapped.cc
Attached devices
|
+---- PS/2 Keyboard and Mouse keyboard.cc, scancodes.cc
|
+---- Bus Mouse (not complete) busmouse.cc
|
+---- Hard Drive + ATA controller harddrv.cc
| |
| +---- Hard Drive image support (*) hdimage.cc
| | |
| | +---- Additional Modules vmware3.cc, vmware4.cc, vvfat.cc
| |
| +---- CD/DVD-ROM image / device access (*) cdrom.cc
| |
| +---- Host specific Modules cdrom_amigaos.cc, cdrom_beos.cc
+---- Network Support
| |
| +---- Network Devices
| | |
| | +---- NE2000 (ISA/PCI) ne2k.cc, pcipnic.cc
| | +---- PCI Pseudo NIC pcipnic.cc
| |
| +---- Networking Modules eth.cc
| | |
| | +-- Host specific Modules eth_fbsd.cc, eth_linux.cc, eth_win32.cc
| |
| +---- Dummy module eth_null.cc
| +---- ARP simulator eth_arpback.cc, eth_packetmaker.cc, crc32.cc
| +---- TAP Interface eth_tap.cc
| +---- TUN/TAP Interface eth_tuntap.cc
| +---- VDE Interface eth_vde.cc
| +---- virtual Ethernet locator eth_vnet.cc
|
+---- Graphics
| |
| +---- VGA, PCI VGA adapter vga.cc, pci_vga.cc
| +---- Cirrus Logic PCI/ISA CLGD5446 SVGA adapter svga_cirrus.cc
|
+---- Sound support
| |
| +---- Sound Blaster SB16 sb16.cc
| | |
| | +-- Dummy / Control Module soundmod.cc
| |
| +---- Host specific Modules soundlnx.cc, soundosx.cc, soundwin.cc
|
+---- PCI USB adapter usb_common.cc
|
+---- Host Controllers
| |
| +---- USB OHCI adapter usb_ohci.cc
| +---- USB UHCI adapter (PIIX3) usb_uhci.cc
|
+---- Attached USB devices
| |
| +-- Control Module usb_common.cc
|
+---- USB HID emulation usb_hid.cc
+---- USB external HUB usb_hub.cc
+---- USB mass storage device (*) usb_msd.cc, scsi_device.cc
+---- USB HP DeskJet 920C printer usb_printer.cc
(*) USB MSD uses hdimage code and cdrom.cc for image / device access
Floppy uses hdimage code for VVFAT support
BOCHS timer sycronisation modules
|
+---- Slowdown timer slowdown_timer.cc
+---- Virtual timer virt_timer.cc
TODO:

812
bochs/iodev/dma.cc Normal file
View File

@ -0,0 +1,812 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "dma.h"
#define LOG_THIS theDmaDevice->
#define DMA_MODE_DEMAND 0
#define DMA_MODE_SINGLE 1
#define DMA_MODE_BLOCK 2
#define DMA_MODE_CASCADE 3
bx_dma_c *theDmaDevice = NULL;
int libdma_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theDmaDevice = new bx_dma_c ();
bx_devices.pluginDmaDevice = theDmaDevice;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theDmaDevice, BX_PLUGIN_DMA);
return(0); // Success
}
void libdma_LTX_plugin_fini(void)
{
delete theDmaDevice;
}
bx_dma_c::bx_dma_c()
{
put("DMA");
}
bx_dma_c::~bx_dma_c()
{
BX_DEBUG(("Exit"));
}
unsigned bx_dma_c::registerDMA8Channel(unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
const char *name)
{
if (channel > 3) {
BX_PANIC(("registerDMA8Channel: invalid channel number(%u).", channel));
return 0; // Fail
}
if (BX_DMA_THIS s[0].chan[channel].used) {
BX_PANIC(("registerDMA8Channel: channel(%u) already in use.", channel));
return 0; // Fail
}
BX_INFO(("channel %u used by %s", channel, name));
BX_DMA_THIS h[channel].dmaRead8 = dmaRead;
BX_DMA_THIS h[channel].dmaWrite8 = dmaWrite;
BX_DMA_THIS s[0].chan[channel].used = 1;
return 1; // OK
}
unsigned bx_dma_c::registerDMA16Channel(unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
const char *name)
{
if ((channel < 4) || (channel > 7)) {
BX_PANIC(("registerDMA16Channel: invalid channel number(%u).", channel));
return 0; // Fail
}
if (BX_DMA_THIS s[1].chan[channel & 0x03].used) {
BX_PANIC(("registerDMA16Channel: channel(%u) already in use.", channel));
return 0; // Fail
}
BX_INFO(("channel %u used by %s", channel, name));
channel &= 0x03;
BX_DMA_THIS h[channel].dmaRead16 = dmaRead;
BX_DMA_THIS h[channel].dmaWrite16 = dmaWrite;
BX_DMA_THIS s[1].chan[channel].used = 1;
return 1; // OK
}
unsigned bx_dma_c::unregisterDMAChannel(unsigned channel)
{
bx_bool ma_sl = (channel > 3);
BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used = 0;
BX_INFO(("channel %u no longer used", channel));
return 1;
}
unsigned bx_dma_c::get_TC(void)
{
return BX_DMA_THIS TC;
}
void bx_dma_c::init(void)
{
unsigned c, i, j;
BX_DEBUG(("Init $Id$"));
/* 8237 DMA controller */
for (i=0; i < 2; i++) {
for (j=0; j < 4; j++) {
BX_DMA_THIS s[i].DRQ[j] = 0;
BX_DMA_THIS s[i].DACK[j] = 0;
}
}
BX_DMA_THIS HLDA = 0;
BX_DMA_THIS TC = 0;
// 0000..000F
for (i=0x0000; i<=0x000F; i++) {
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
}
// 00080..008F
for (i=0x0080; i<=0x008F; i++) {
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
}
// 000C0..00DE
for (i=0x00C0; i<=0x00DE; i+=2) {
DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
}
for (i=0; i<2; i++) {
for (c=0; c<4; c++) {
BX_DMA_THIS s[i].chan[c].mode.mode_type = 0; // demand mode
BX_DMA_THIS s[i].chan[c].mode.address_decrement = 0; // address increment
BX_DMA_THIS s[i].chan[c].mode.autoinit_enable = 0; // autoinit disable
BX_DMA_THIS s[i].chan[c].mode.transfer_type = 0; // verify
BX_DMA_THIS s[i].chan[c].base_address = 0;
BX_DMA_THIS s[i].chan[c].current_address = 0;
BX_DMA_THIS s[i].chan[c].base_count = 0;
BX_DMA_THIS s[i].chan[c].current_count = 0;
BX_DMA_THIS s[i].chan[c].page_reg = 0;
BX_DMA_THIS s[i].chan[c].used = 0;
}
}
memset(&BX_DMA_THIS ext_page_reg[0], 0, 16);
BX_DMA_THIS s[1].chan[0].used = 1; // cascade channel in use
BX_INFO(("channel 4 used by cascade"));
}
void bx_dma_c::reset(unsigned type)
{
reset_controller(0);
reset_controller(1);
}
void bx_dma_c::reset_controller(unsigned num)
{
BX_DMA_THIS s[num].mask[0] = 1;
BX_DMA_THIS s[num].mask[1] = 1;
BX_DMA_THIS s[num].mask[2] = 1;
BX_DMA_THIS s[num].mask[3] = 1;
BX_DMA_THIS s[num].ctrl_disabled = 0;
BX_DMA_THIS s[num].command_reg = 0;
BX_DMA_THIS s[num].status_reg = 0;
BX_DMA_THIS s[num].flip_flop = 0;
}
void bx_dma_c::register_state(void)
{
unsigned i, c;
char name[6];
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "dma", "DMA State", 3);
for (i=0; i<2; i++) {
sprintf(name, "%d", i);
bx_list_c *ctrl = new bx_list_c(list, name, 8);
BXRS_PARAM_BOOL(ctrl, flip_flop, BX_DMA_THIS s[i].flip_flop);
BXRS_HEX_PARAM_FIELD(ctrl, status_reg, BX_DMA_THIS s[i].status_reg);
BXRS_HEX_PARAM_FIELD(ctrl, command_reg, BX_DMA_THIS s[i].command_reg);
BXRS_PARAM_BOOL(ctrl, ctrl_disabled, BX_DMA_THIS s[i].ctrl_disabled);
for (c=0; c<4; c++) {
sprintf(name, "%d", c);
bx_list_c *chan = new bx_list_c(ctrl, name, 12);
BXRS_PARAM_BOOL(chan, DRQ, BX_DMA_THIS s[i].DRQ[c]);
BXRS_PARAM_BOOL(chan, DACK, BX_DMA_THIS s[i].DACK[c]);
BXRS_PARAM_BOOL(chan, mask, BX_DMA_THIS s[i].mask[c]);
BXRS_DEC_PARAM_FIELD(chan, mode_type, BX_DMA_THIS s[i].chan[c].mode.mode_type);
BXRS_DEC_PARAM_FIELD(chan, address_decrement, BX_DMA_THIS s[i].chan[c].mode.address_decrement);
BXRS_DEC_PARAM_FIELD(chan, autoinit_enable, BX_DMA_THIS s[i].chan[c].mode.autoinit_enable);
BXRS_DEC_PARAM_FIELD(chan, transfer_type, BX_DMA_THIS s[i].chan[c].mode.transfer_type);
BXRS_HEX_PARAM_FIELD(chan, base_address, BX_DMA_THIS s[i].chan[c].base_address);
BXRS_HEX_PARAM_FIELD(chan, current_address, BX_DMA_THIS s[i].chan[c].current_address);
BXRS_HEX_PARAM_FIELD(chan, base_count, BX_DMA_THIS s[i].chan[c].base_count);
BXRS_HEX_PARAM_FIELD(chan, current_count, BX_DMA_THIS s[i].chan[c].current_count);
BXRS_HEX_PARAM_FIELD(chan, page_reg, BX_DMA_THIS s[i].chan[c].page_reg);
}
}
bx_list_c *extpg = new bx_list_c(list, "ext_page", 16);
for (i=0; i<16; i++) {
sprintf(name, "0x%02x", 0x80+i);
new bx_shadow_num_c(extpg, name, &BX_DMA_THIS ext_page_reg[i], BASE_HEX);
}
}
// index to find channel from register number (only [0],[1],[2],[6] used)
Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0};
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_dma_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_DMA_SMF
bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
return class_ptr->read(address, io_len);
}
/* 8237 DMA controller */
Bit32u BX_CPP_AttrRegparmN(2)
bx_dma_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_DMA_SMF
Bit8u retval;
Bit8u channel;
BX_DEBUG(("read addr=%04x", (unsigned) address));
#if BX_DMA_FLOPPY_IO < 1
/* if we're not supporting DMA/floppy IO just return a bogus value */
return(0xff);
#endif
bx_bool ma_sl = (address >= 0xc0);
switch (address) {
case 0x00: /* DMA-1 current address, channel 0 */
case 0x02: /* DMA-1 current address, channel 1 */
case 0x04: /* DMA-1 current address, channel 2 */
case 0x06: /* DMA-1 current address, channel 3 */
case 0xc0: /* DMA-2 current address, channel 0 */
case 0xc4: /* DMA-2 current address, channel 1 */
case 0xc8: /* DMA-2 current address, channel 2 */
case 0xcc: /* DMA-2 current address, channel 3 */
channel = (address >> (1 + ma_sl)) & 0x03;
if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
return (BX_DMA_THIS s[ma_sl].chan[channel].current_address & 0xff);
} else {
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
return (BX_DMA_THIS s[ma_sl].chan[channel].current_address >> 8);
}
case 0x01: /* DMA-1 current count, channel 0 */
case 0x03: /* DMA-1 current count, channel 1 */
case 0x05: /* DMA-1 current count, channel 2 */
case 0x07: /* DMA-1 current count, channel 3 */
case 0xc2: /* DMA-2 current count, channel 0 */
case 0xc6: /* DMA-2 current count, channel 1 */
case 0xca: /* DMA-2 current count, channel 2 */
case 0xce: /* DMA-2 current count, channel 3 */
channel = (address >> (1 + ma_sl)) & 0x03;
if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
return (BX_DMA_THIS s[ma_sl].chan[channel].current_count & 0xff);
} else {
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
return (BX_DMA_THIS s[ma_sl].chan[channel].current_count >> 8);
}
case 0x08: // DMA-1 Status Register
case 0xd0: // DMA-2 Status Register
// bit 7: 1 = channel 3 request
// bit 6: 1 = channel 2 request
// bit 5: 1 = channel 1 request
// bit 4: 1 = channel 0 request
// bit 3: 1 = channel 3 has reached terminal count
// bit 2: 1 = channel 2 has reached terminal count
// bit 1: 1 = channel 1 has reached terminal count
// bit 0: 1 = channel 0 has reached terminal count
// reading this register clears lower 4 bits (hold flags)
retval = BX_DMA_THIS s[ma_sl].status_reg;
BX_DMA_THIS s[ma_sl].status_reg &= 0xf0;
return retval;
case 0x0d: // DMA-1: temporary register
case 0xda: // DMA-2: temporary register
// only used for memory-to-memory transfers
// write to 0x0d / 0xda clears temporary register
BX_ERROR(("DMA-%d: read of temporary register always returns 0", ma_sl+1));
return 0;
case 0x0081: // DMA-1 page register, channel 2
case 0x0082: // DMA-1 page register, channel 3
case 0x0083: // DMA-1 page register, channel 1
case 0x0087: // DMA-1 page register, channel 0
channel = channelindex[address - 0x81];
return BX_DMA_THIS s[0].chan[channel].page_reg;
case 0x0089: // DMA-2 page register, channel 2
case 0x008a: // DMA-2 page register, channel 3
case 0x008b: // DMA-2 page register, channel 1
case 0x008f: // DMA-2 page register, channel 0
channel = channelindex[address - 0x89];
return BX_DMA_THIS s[1].chan[channel].page_reg;
case 0x0080:
case 0x0084:
case 0x0085:
case 0x0086:
case 0x0088:
case 0x008c:
case 0x008d:
case 0x008e:
BX_DEBUG(("read: extra page register 0x%04x (unused)", (unsigned) address));
return BX_DMA_THIS ext_page_reg[address & 0x0f];
case 0x0f: // DMA-1: undocumented: read all mask bits
case 0xde: // DMA-2: undocumented: read all mask bits
retval = BX_DMA_THIS s[ma_sl].mask[0] |
(BX_DMA_THIS s[ma_sl].mask[1] << 1) |
(BX_DMA_THIS s[ma_sl].mask[2] << 2) |
(BX_DMA_THIS s[ma_sl].mask[3] << 3);
return (0xf0 | retval);
default:
BX_ERROR(("read: unsupported address=%04x", (unsigned) address));
return 0;
}
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_dma_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_DMA_SMF
bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
/* 8237 DMA controller */
void BX_CPP_AttrRegparmN(3)
bx_dma_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_DMA_SMF
Bit8u set_mask_bit;
Bit8u channel;
if (io_len > 1) {
if ((io_len == 2) && (address == 0x0b)) {
#if BX_USE_DMA_SMF
BX_DMA_THIS write_handler(NULL, address, value & 0xff, 1);
BX_DMA_THIS write_handler(NULL, address+1, value >> 8, 1);
#else
BX_DMA_THIS write(address, value & 0xff, 1);
BX_DMA_THIS write(address+1, value >> 8, 1);
#endif
return;
}
BX_ERROR(("io write to address %08x, len=%u",
(unsigned) address, (unsigned) io_len));
return;
}
BX_DEBUG(("write: address=%04x value=%02x",
(unsigned) address, (unsigned) value));
#if BX_DMA_FLOPPY_IO < 1
/* if we're not supporting DMA/floppy IO just return */
return;
#endif
bx_bool ma_sl = (address >= 0xc0);
switch (address) {
case 0x00:
case 0x02:
case 0x04:
case 0x06:
case 0xc0:
case 0xc4:
case 0xc8:
case 0xcc:
channel = (address >> (1 + ma_sl)) & 0x03;
BX_DEBUG((" DMA-%d base and current address, channel %d", ma_sl+1, channel));
if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
BX_DMA_THIS s[ma_sl].chan[channel].base_address = value;
BX_DMA_THIS s[ma_sl].chan[channel].current_address = value;
} else { /* 2nd byte */
BX_DMA_THIS s[ma_sl].chan[channel].base_address |= (value << 8);
BX_DMA_THIS s[ma_sl].chan[channel].current_address |= (value << 8);
BX_DEBUG((" base = %04x",
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_address));
BX_DEBUG((" curr = %04x",
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_address));
}
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
break;
case 0x01:
case 0x03:
case 0x05:
case 0x07:
case 0xc2:
case 0xc6:
case 0xca:
case 0xce:
channel = (address >> (1 + ma_sl)) & 0x03;
BX_DEBUG((" DMA-%d base and current count, channel %d", ma_sl+1, channel));
if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
BX_DMA_THIS s[ma_sl].chan[channel].base_count = value;
BX_DMA_THIS s[ma_sl].chan[channel].current_count = value;
} else { /* 2nd byte */
BX_DMA_THIS s[ma_sl].chan[channel].base_count |= (value << 8);
BX_DMA_THIS s[ma_sl].chan[channel].current_count |= (value << 8);
BX_DEBUG((" base = %04x",
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
BX_DEBUG((" curr = %04x",
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_count));
}
BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
break;
case 0x08: /* DMA-1: command register */
case 0xd0: /* DMA-2: command register */
if ((value & 0xfb) != 0x00)
BX_ERROR(("write to command register: value 0x%02x not supported",
(unsigned) value));
BX_DMA_THIS s[ma_sl].command_reg = value;
BX_DMA_THIS s[ma_sl].ctrl_disabled = (value >> 2) & 0x01;
control_HRQ(ma_sl);
break;
case 0x09: // DMA-1: request register
case 0xd2: // DMA-2: request register
channel = value & 0x03;
// note: write to 0x0d / 0xda clears this register
if (value & 0x04) {
// set request bit
BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
BX_DEBUG(("DMA-%d: set request bit for channel %u", ma_sl+1, (unsigned) channel));
} else {
// clear request bit
BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
BX_DEBUG(("DMA-%d: cleared request bit for channel %u", ma_sl+1, (unsigned) channel));
}
control_HRQ(ma_sl);
break;
case 0x0a:
case 0xd4:
set_mask_bit = value & 0x04;
channel = value & 0x03;
BX_DMA_THIS s[ma_sl].mask[channel] = (set_mask_bit > 0);
BX_DEBUG(("DMA-%d: set_mask_bit=%u, channel=%u, mask now=%02xh", ma_sl+1,
(unsigned) set_mask_bit, (unsigned) channel, (unsigned) BX_DMA_THIS s[ma_sl].mask[channel]));
control_HRQ(ma_sl);
break;
case 0x0b: /* DMA-1 mode register */
case 0xd6: /* DMA-2 mode register */
channel = value & 0x03;
BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type = (value >> 6) & 0x03;
BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement = (value >> 5) & 0x01;
BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable = (value >> 4) & 0x01;
BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type = (value >> 2) & 0x03;
BX_DEBUG(("DMA-%d: mode register[%u] = %02x", ma_sl+1,
(unsigned) channel, (unsigned) value));
break;
case 0x0c: /* DMA-1 clear byte flip/flop */
case 0xd8: /* DMA-2 clear byte flip/flop */
BX_DEBUG(("DMA-%d: clear flip/flop", ma_sl+1));
BX_DMA_THIS s[ma_sl].flip_flop = 0;
break;
case 0x0d: // DMA-1: master clear
case 0xda: // DMA-2: master clear
BX_DEBUG(("DMA-%d: master clear", ma_sl+1));
// writing any value to this port resets DMA controller 1 / 2
// same action as a hardware reset
// mask register is set (chan 0..3 disabled)
// command, status, request, temporary, and byte flip-flop are all cleared
reset_controller(ma_sl);
break;
case 0x0e: // DMA-1: clear mask register
case 0xdc: // DMA-2: clear mask register
BX_DEBUG(("DMA-%d: clear mask register", ma_sl+1));
BX_DMA_THIS s[ma_sl].mask[0] = 0;
BX_DMA_THIS s[ma_sl].mask[1] = 0;
BX_DMA_THIS s[ma_sl].mask[2] = 0;
BX_DMA_THIS s[ma_sl].mask[3] = 0;
control_HRQ(ma_sl);
break;
case 0x0f: // DMA-1: write all mask bits
case 0xde: // DMA-2: write all mask bits
BX_DEBUG(("DMA-%d: write all mask bits", ma_sl+1));
BX_DMA_THIS s[ma_sl].mask[0] = value & 0x01; value >>= 1;
BX_DMA_THIS s[ma_sl].mask[1] = value & 0x01; value >>= 1;
BX_DMA_THIS s[ma_sl].mask[2] = value & 0x01; value >>= 1;
BX_DMA_THIS s[ma_sl].mask[3] = value & 0x01;
control_HRQ(ma_sl);
break;
case 0x81: /* DMA-1 page register, channel 2 */
case 0x82: /* DMA-1 page register, channel 3 */
case 0x83: /* DMA-1 page register, channel 1 */
case 0x87: /* DMA-1 page register, channel 0 */
/* address bits A16-A23 for DMA channel */
channel = channelindex[address - 0x81];
BX_DMA_THIS s[0].chan[channel].page_reg = value;
BX_DEBUG(("DMA-1: page register %d = %02x", channel, (unsigned) value));
break;
case 0x89: /* DMA-2 page register, channel 2 */
case 0x8a: /* DMA-2 page register, channel 3 */
case 0x8b: /* DMA-2 page register, channel 1 */
case 0x8f: /* DMA-2 page register, channel 0 */
/* address bits A16-A23 for DMA channel */
channel = channelindex[address - 0x89];
BX_DMA_THIS s[1].chan[channel].page_reg = value;
BX_DEBUG(("DMA-2: page register %d = %02x", channel + 4, (unsigned) value));
break;
case 0x0080:
case 0x0084:
case 0x0085:
case 0x0086:
case 0x0088:
case 0x008c:
case 0x008d:
case 0x008e:
BX_DEBUG(("write: extra page register 0x%04x (unused)", (unsigned) address));
BX_DMA_THIS ext_page_reg[address & 0x0f] = value;
break;
default:
BX_ERROR(("write ignored: %04xh = %02xh",
(unsigned) address, (unsigned) value));
}
}
void bx_dma_c::set_DRQ(unsigned channel, bx_bool val)
{
Bit32u dma_base, dma_roof;
bx_bool ma_sl;
if (channel > 7) {
BX_PANIC(("set_DRQ() channel > 7"));
return;
}
ma_sl = (channel > 3);
BX_DMA_THIS s[ma_sl].DRQ[channel & 0x03] = val;
if (!BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used) {
BX_PANIC(("set_DRQ(): channel %d not connected to device", channel));
return;
}
channel &= 0x03;
if (!val) {
//BX_DEBUG(("bx_dma_c::DRQ(): val == 0"));
// clear bit in status reg
BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
control_HRQ(ma_sl);
return;
}
#if 0
BX_INFO(("mask[%d]: %02x", channel, (unsigned) BX_DMA_THIS s[0].mask[channel]));
BX_INFO(("flip_flop: %u", (unsigned) BX_DMA_THIS s[0].flip_flop));
BX_INFO(("status_reg: %02x", (unsigned) BX_DMA_THIS s[0].status_reg));
BX_INFO(("mode_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.mode_type));
BX_INFO(("address_decrement: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.address_decrement));
BX_INFO(("autoinit_enable: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.autoinit_enable));
BX_INFO(("transfer_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.transfer_type));
BX_INFO(("base_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_address));
BX_INFO(("current_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_address));
BX_INFO(("base_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_count));
BX_INFO(("current_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_count));
BX_INFO(("page_reg: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].page_reg));
#endif
BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
if ((BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_SINGLE) &&
(BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_DEMAND) &&
(BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_CASCADE))
{
BX_PANIC(("set_DRQ: mode_type(%02x) not handled",
(unsigned) BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type));
}
dma_base = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
(BX_DMA_THIS s[ma_sl].chan[channel].base_address << ma_sl);
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0) {
dma_roof = dma_base + (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
} else {
dma_roof = dma_base - (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
}
if ((dma_base & (0x7fff0000 << ma_sl)) != (dma_roof & (0x7fff0000 << ma_sl))) {
BX_INFO(("dma_base = %08x", (unsigned) dma_base));
BX_INFO(("dma_base_count = %08x", (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
BX_INFO(("dma_roof = %08x", (unsigned) dma_roof));
BX_PANIC(("request outside %dk boundary", 64 << ma_sl));
}
control_HRQ(ma_sl);
}
void bx_dma_c::control_HRQ(bx_bool ma_sl)
{
unsigned channel;
// do nothing if controller is disabled
if (BX_DMA_THIS s[ma_sl].ctrl_disabled)
return;
// deassert HRQ if no DRQ is pending
if ((BX_DMA_THIS s[ma_sl].status_reg & 0xf0) == 0) {
if (ma_sl) {
bx_pc_system.set_HRQ(0);
} else {
BX_DMA_THIS set_DRQ(4, 0);
}
return;
}
// find highest priority channel
for (channel=0; channel<4; channel++) {
if ((BX_DMA_THIS s[ma_sl].status_reg & (1 << (channel+4))) &&
(BX_DMA_THIS s[ma_sl].mask[channel]==0)) {
if (ma_sl) {
// assert Hold ReQuest line to CPU
bx_pc_system.set_HRQ(1);
} else {
// send DRQ to cascade channel of the master
BX_DMA_THIS set_DRQ(4, 1);
}
break;
}
}
}
void bx_dma_c::raise_HLDA(void)
{
unsigned channel;
bx_phy_address phy_addr;
bx_bool count_expired = 0;
bx_bool ma_sl = 0;
BX_DMA_THIS HLDA = 1;
// find highest priority channel
for (channel=0; channel<4; channel++) {
if ((BX_DMA_THIS s[1].status_reg & (1 << (channel+4))) &&
(BX_DMA_THIS s[1].mask[channel]==0)) {
ma_sl = 1;
break;
}
}
if (channel == 0) { // master cascade channel
BX_DMA_THIS s[1].DACK[0] = 1;
for (channel=0; channel<4; channel++) {
if ((BX_DMA_THIS s[0].status_reg & (1 << (channel+4))) &&
(BX_DMA_THIS s[0].mask[channel]==0)) {
ma_sl = 0;
break;
}
}
}
if (channel >= 4) {
// wait till they're unmasked
return;
}
//BX_DEBUG(("hlda: OK in response to DRQ(%u)", (unsigned) channel));
phy_addr = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
(BX_DMA_THIS s[ma_sl].chan[channel].current_address << ma_sl);
BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
// check for expiration of count, so we can signal TC and DACK(n)
// at the same time.
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0)
BX_DMA_THIS s[ma_sl].chan[channel].current_address++;
else
BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
BX_DMA_THIS s[ma_sl].chan[channel].current_count--;
if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
// count expired, done with transfer
// assert TC, deassert HRQ & DACK(n) lines
BX_DMA_THIS s[ma_sl].status_reg |= (1 << channel); // hold TC in status reg
BX_DMA_THIS TC = 1;
count_expired = 1;
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable == 0) {
// set mask bit if not in autoinit mode
BX_DMA_THIS s[ma_sl].mask[channel] = 1;
}
else {
// count expired, but in autoinit mode
// reload count and base address
BX_DMA_THIS s[ma_sl].chan[channel].current_address =
BX_DMA_THIS s[ma_sl].chan[channel].base_address;
BX_DMA_THIS s[ma_sl].chan[channel].current_count =
BX_DMA_THIS s[ma_sl].chan[channel].base_count;
}
}
Bit8u data_byte;
Bit16u data_word;
if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 1) { // write
// DMA controlled xfer of byte from I/O to Memory
if (!ma_sl) {
if (BX_DMA_THIS h[channel].dmaWrite8)
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
DEV_MEM_WRITE_PHYSICAL(phy_addr, 1, &data_byte);
BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte);
}
else {
if (BX_DMA_THIS h[channel].dmaWrite16)
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
DEV_MEM_WRITE_PHYSICAL(phy_addr, 2, (Bit8u*) &data_word);
BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
// DMA controlled xfer of byte from Memory to I/O
if (!ma_sl) {
DEV_MEM_READ_PHYSICAL(phy_addr, 1, &data_byte);
if (BX_DMA_THIS h[channel].dmaRead8)
BX_DMA_THIS h[channel].dmaRead8(&data_byte);
BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte);
}
else {
DEV_MEM_READ_PHYSICAL(phy_addr, 2, (Bit8u*) &data_word);
if (BX_DMA_THIS h[channel].dmaRead16)
BX_DMA_THIS h[channel].dmaRead16(&data_word);
BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
}
}
else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
// verify
if (!ma_sl) {
if (BX_DMA_THIS h[channel].dmaWrite8)
BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
else {
if (BX_DMA_THIS h[channel].dmaWrite16)
BX_DMA_THIS h[channel].dmaWrite16(&data_word);
else
BX_PANIC(("no dmaWrite handler for channel %u.", channel));
}
}
else {
BX_PANIC(("hlda: transfer_type 3 is undefined"));
}
if (count_expired) {
BX_DMA_THIS TC = 0; // clear TC, adapter card already notified
BX_DMA_THIS HLDA = 0;
bx_pc_system.set_HRQ(0); // clear HRQ to CPU
BX_DMA_THIS s[ma_sl].DACK[channel] = 0; // clear DACK to adapter card
if (!ma_sl) {
BX_DMA_THIS set_DRQ(4, 0); // clear DRQ to cascade
BX_DMA_THIS s[1].DACK[0] = 0; // clear DACK to cascade
}
}
}

104
bochs/iodev/dma.h Normal file
View File

@ -0,0 +1,104 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef _PCDMA_H
#define _PCDMA_H
#if BX_USE_DMA_SMF
# define BX_DMA_SMF static
# define BX_DMA_THIS theDmaDevice->
#else
# define BX_DMA_SMF
# define BX_DMA_THIS this->
#endif
class bx_dma_c : public bx_dma_stub_c {
public:
bx_dma_c();
virtual ~bx_dma_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void raise_HLDA(void);
virtual void set_DRQ(unsigned channel, bx_bool val);
virtual unsigned get_TC(void);
virtual void register_state(void);
virtual unsigned registerDMA8Channel(unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
const char *name);
virtual unsigned registerDMA16Channel(unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
const char *name);
virtual unsigned unregisterDMAChannel(unsigned channel);
private:
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_DMA_SMF
Bit32u read (Bit32u address, unsigned io_len) BX_CPP_AttrRegparmN(2);
void write(Bit32u address, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
#endif
BX_DMA_SMF void control_HRQ(bx_bool ma_sl);
BX_DMA_SMF void reset_controller(unsigned num);
struct {
bx_bool DRQ[4]; // DMA Request
bx_bool DACK[4]; // DMA Acknowlege
bx_bool mask[4];
bx_bool flip_flop;
Bit8u status_reg;
Bit8u command_reg;
bx_bool ctrl_disabled;
struct {
struct {
Bit8u mode_type;
Bit8u address_decrement;
Bit8u autoinit_enable;
Bit8u transfer_type;
} mode;
Bit16u base_address;
Bit16u current_address;
Bit16u base_count;
Bit16u current_count;
Bit8u page_reg;
bx_bool used;
} chan[4]; /* DMA channels 0..3 */
} s[2]; // state information DMA-1 / DMA-2
bx_bool HLDA; // Hold Acknowlege
bx_bool TC; // Terminal Count
Bit8u ext_page_reg[16]; // Extra page registers (unused)
struct {
void (* dmaRead8)(Bit8u *data_byte);
void (* dmaWrite8)(Bit8u *data_byte);
void (* dmaRead16)(Bit16u *data_word);
void (* dmaWrite16)(Bit16u *data_word);
} h[4]; // DMA read and write handlers
};
#endif // #ifndef _PCDMA_H

214
bochs/iodev/eth.cc Normal file
View File

@ -0,0 +1,214 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// eth.cc - helper code to find and create pktmover classes
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING
#include "eth.h"
#define LOG_THIS /* not needed */
eth_locator_c *eth_locator_c::all;
//
// Each pktmover module has a static locator class that registers
// here
//
eth_locator_c::eth_locator_c(const char *type)
{
next = all;
all = this;
this->type = type;
}
#ifdef ETH_NULL
extern class bx_null_locator_c bx_null_match;
#endif
#ifdef ETH_FBSD
extern class bx_fbsd_locator_c bx_fbsd_match;
#endif
#ifdef ETH_LINUX
extern class bx_linux_locator_c bx_linux_match;
#endif
#ifdef ETH_WIN32
extern class bx_win32_locator_c bx_win32_match;
#endif
#if HAVE_ETHERTAP
extern class bx_tap_locator_c bx_tap_match;
#endif
#if HAVE_TUNTAP
extern class bx_tuntap_locator_c bx_tuntap_match;
#endif
#if HAVE_VDE
extern class bx_vde_locator_c bx_vde_match;
#endif
#ifdef ETH_ARPBACK
extern class bx_arpback_locator_c bx_arpback_match;
#endif
extern class bx_vnet_locator_c bx_vnet_match;
//
// Called by ethernet chip emulations to locate and create a pktmover
// object
//
eth_pktmover_c *
eth_locator_c::create(const char *type, const char *netif,
const char *macaddr,
eth_rx_handler_t rxh, bx_devmodel_c *dev,
const char *script)
{
#ifdef eth_static_constructors
for (eth_locator_c *p = all; p != NULL; p = p->next) {
if (strcmp(type, p->type) == 0)
return (p->allocate(netif, macaddr, rxh, dev, script));
}
#else
eth_locator_c *ptr = 0;
#ifdef ETH_ARPBACK
{
if (!strcmp(type, "arpback"))
ptr = (eth_locator_c *) &bx_arpback_match;
}
#endif
#ifdef ETH_NULL
{
if (!strcmp(type, "null"))
ptr = (eth_locator_c *) &bx_null_match;
}
#endif
#ifdef ETH_FBSD
{
if (!strcmp(type, "fbsd"))
ptr = (eth_locator_c *) &bx_fbsd_match;
}
#endif
#ifdef ETH_LINUX
{
if (!strcmp(type, "linux"))
ptr = (eth_locator_c *) &bx_linux_match;
}
#endif
#if HAVE_TUNTAP
{
if (!strcmp(type, "tuntap"))
ptr = (eth_locator_c *) &bx_tuntap_match;
}
#endif
#if HAVE_VDE
{
if (!strcmp(type, "vde"))
ptr = (eth_locator_c *) &bx_vde_match;
}
#endif
#if HAVE_ETHERTAP
{
if (!strcmp(type, "tap"))
ptr = (eth_locator_c *) &bx_tap_match;
}
#endif
#ifdef ETH_WIN32
{
if(!strcmp(type, "win32"))
ptr = (eth_locator_c *) &bx_win32_match;
}
#endif
{
if (!strcmp(type, "vnet"))
ptr = (eth_locator_c *) &bx_vnet_match;
}
if (ptr)
return (ptr->allocate(netif, macaddr, rxh, dev, script));
#endif
return (NULL);
}
#if (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1) || (HAVE_VDE==1)
extern "C" {
#include <sys/wait.h>
};
// This is a utility script used for tuntap or ethertap
int execute_script(bx_devmodel_c *netdev, const char* scriptname, char* arg1)
{
int pid,status;
if (!(pid=fork())) {
char filename[BX_PATHNAME_LEN];
if (scriptname[0]=='/') {
strcpy(filename, scriptname);
}
else {
getcwd(filename, BX_PATHNAME_LEN);
strcat(filename, "/");
strcat(filename, scriptname);
}
// execute the script
netdev->info("Executing script '%s %s'",filename,arg1);
execle(filename, scriptname, arg1, NULL, NULL);
// if we get here there has been a problem
exit(-1);
}
wait (&status);
if (!WIFEXITED(status)) {
return -1;
}
return WEXITSTATUS(status);
}
#endif // (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1)
void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool host_to_guest)
{
Bit8u *charbuf = (Bit8u *)buf;
unsigned n;
if (!host_to_guest) {
fprintf(pktlog_txt, "a packet from guest to host, length %u\n", len);
} else {
fprintf(pktlog_txt, "a packet from host to guest, length %u\n", len);
}
for (n = 0; n < len; n++) {
if (((n % 16) == 0) && (n > 0))
fprintf(pktlog_txt, "\n");
fprintf(pktlog_txt, "%02x ", (unsigned)charbuf[n]);
}
fprintf(pktlog_txt, "\n--\n");
fflush(pktlog_txt);
}
#endif /* if BX_NETWORKING */

83
bochs/iodev/eth.h Normal file
View File

@ -0,0 +1,83 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.
// eth.h - see eth_null.cc for implementation details
#ifndef BX_ETH_H
#define BX_ETH_H
#define BX_PACKET_BUFSIZE 2048 // Enough for an ether frame
typedef void (*eth_rx_handler_t)(void *arg, const void *buf, unsigned len);
static const Bit8u broadcast_macaddr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
int execute_script(bx_devmodel_c *netdev, const char *name, char* arg1);
void write_pktlog_txt(FILE *pktlog_txt, const Bit8u *buf, unsigned len, bx_bool host_to_guest);
//
// The eth_pktmover class is used by ethernet chip emulations
// to interface to the outside world. An instance of this
// would allow frames to be sent to and received from some
// entity. An example would be the packet filter on a Unix
// system, an NDIS driver in promisc mode on WinNT, or maybe
// a simulated network that talks to another process.
//
class eth_pktmover_c {
public:
virtual void sendpkt(void *buf, unsigned io_len) = 0;
virtual ~eth_pktmover_c () {}
protected:
bx_devmodel_c *netdev;
eth_rx_handler_t rxh; // receive callback
};
//
// The eth_locator class is used by pktmover classes to register
// their name. Chip emulations use the static 'create' method
// to locate and instantiate a pktmover class.
//
class eth_locator_c {
public:
static eth_pktmover_c *create(const char *type, const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script);
protected:
eth_locator_c(const char *type);
virtual ~eth_locator_c() {}
virtual eth_pktmover_c *allocate(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script) = 0;
private:
static eth_locator_c *all;
eth_locator_c *next;
const char *type;
};
#endif

188
bochs/iodev/eth_arpback.cc Normal file
View File

@ -0,0 +1,188 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// eth_arpback.cc - basic ethernet packetmover, only responds to ARP
// Various networking docs:
// http://www.graphcomp.com/info/rfc/
// rfc0826: arp
// rfc0903: rarp
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(ETH_ARPBACK)
#include "eth.h"
#include "crc32.h"
#include "eth_packetmaker.h"
#define LOG_THIS netdev->
//static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
//static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x00, 0x00, 0x00, 0x00};
//static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
//static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
//
// Define the class. This is private to this module
//
class bx_arpback_pktmover_c : public eth_pktmover_c {
public:
bx_arpback_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev);
void sendpkt(void *buf, unsigned io_len);
private:
int rx_timer_index;
static void rx_timer_handler(void *);
void rx_timer(void);
FILE *pktlog, *pktlog_txt;
//Bit8u arpbuf[MAX_FRAME_SIZE];
//Bit32u buflen;
//bx_bool bufvalid;
//CRC_Generator mycrc;
eth_ETHmaker packetmaker;
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_arpback_locator_c : public eth_locator_c {
public:
bx_arpback_locator_c(void) : eth_locator_c("arpback") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_arpback_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_arpback_match;
//
// Define the methods for the bx_arpback_pktmover derived class
//
// the constructor
bx_arpback_pktmover_c::bx_arpback_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
this->netdev = dev;
BX_INFO(("arpback network driver"));
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
1, 1, "eth_arpback"); // continuous, active
this->rxh = rxh;
//bufvalid=0;
packetmaker.init();
#if BX_ETH_NULL_LOGGING
// Start the rx poll
// eventually Bryce wants txlog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
pktlog = fopen("ne2k-pkt.log", "wb");
if (!pktlog) BX_PANIC(("open ne2k-pkt.log failed"));
pktlog_txt = fopen("ne2k-pktlog.txt", "wb");
if (!pktlog_txt) BX_PANIC(("open ne2k-pktlog.txt failed"));
fprintf(pktlog_txt, "arpback packetmover readable log file\n");
fprintf(pktlog_txt, "net IF = %s\n", netif);
fprintf(pktlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(pktlog_txt, "\n--\n");
fflush(pktlog_txt);
#endif
}
void
bx_arpback_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
if(io_len<BX_PACKET_BUFSIZE) {
eth_packet barney;
memcpy(barney.buf,buf,io_len);
barney.len=io_len;
if(packetmaker.ishandler(barney)) {
packetmaker.sendpacket(barney);
}
/*
if(( (!memcmp(buf, external_mac, 6)) || (!memcmp(buf, broadcast_macaddr, 6)) )
&& (!memcmp(((Bit8u *)buf)+12, ethtype_arp, 2)) ) {
Bit32u tempcrc;
memcpy(arpbuf,buf,io_len); //move to temporary buffer
memcpy(arpbuf, arpbuf+6, 6); //set destination to sender
memcpy(arpbuf+6, external_mac, 6); //set sender to us
memcpy(arpbuf+32, arpbuf+22, 10); //move destination to sender
memcpy(arpbuf+22, external_mac, 6); //set sender to us
memcpy(arpbuf+28, external_ip, 4); //set sender to us
arpbuf[21]=2; //make this a reply and not a request
tempcrc=mycrc.get_CRC(arpbuf,io_len);
memcpy(arpbuf+io_len, &tempcrc, 4);
buflen=io_len;//+4
bufvalid=1;
}
*/
}
#if BX_ETH_NULL_LOGGING
BX_DEBUG(("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite (buf, io_len, 1, pktlog);
if (n != 1) BX_ERROR (("fwrite to pktlog failed, length %u", io_len));
// dump packet in hex into an ascii log file
write_pktlog_txt(pktlog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(pktlog);
#endif
}
void bx_arpback_pktmover_c::rx_timer_handler (void * this_ptr)
{
#if BX_ETH_NULL_LOGGING
BX_DEBUG(("rx_timer_handler"));
#endif
bx_arpback_pktmover_c *class_ptr = ((bx_arpback_pktmover_c *)this_ptr);
class_ptr->rx_timer();
}
void bx_arpback_pktmover_c::rx_timer (void)
{
eth_packet rubble;
if (packetmaker.getpacket(rubble)) {
#if BX_ETH_NULL_LOGGING
write_pktlog_txt(pktlog_txt, rubble.buf, rubble.len, 1);
#endif
(*rxh)(this->netdev, rubble.buf, rubble.len);
}
}
#endif /* if BX_NETWORKING && defined(ETH_ARPBACK) */

373
bochs/iodev/eth_fbsd.cc Normal file
View File

@ -0,0 +1,373 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.
// eth_fbsd.cc - A FreeBSD packet filter implementation of
// an ethernet pktmover. There are some problems and limitations
// with FreeBSD:
// - the source address of the frame is overwritten by
// the hosts's source address. This causes problems with
// learning bridges - since they cannot determine where
// BOCHS 'is', they broadcast the frame to all ports.
// - packets cannot be sent from BOCHS to the host
// - TCP performance seems to be abysmal; I think this is
// a timing problem somewhere.
// - I haven't handled the case where multiple frames arrive
// in a single BPF read.
//
// The /dev/bpf* devices need to be set up with the appropriate
// permissions for this to work.
//
// The config line in .bochsrc should look something like:
//
// ne2k: ioaddr=0x280, irq=9, mac=00:a:b:c:1:2, ethmod=fbsd, ethdev=fxp0
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(ETH_FBSD)
#include "eth.h"
#define LOG_THIS netdev->
extern "C" {
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/bpf.h>
#include <errno.h>
};
#define BX_BPF_POLL 1000 // Poll for a frame every 250 usecs
#define BX_BPF_INSNSIZ 8 // number of bpf insns
// template filter for a unicast mac address and all
// multicast/broadcast frames
static const struct bpf_insn macfilter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), // A <- P[2:4]
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2), // if A != 0xaaaaaaa GOTO LABEL-1
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0), // A <- P[0:2]
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0), // if A == 0xaaaa GOTO ACCEPT
// LABEL-1
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0), // A <- P[0:1]
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1), // if !(A & 1) GOTO LABEL-REJECT
// LABEL-ACCEPT
BPF_STMT(BPF_RET, 1514), // Accept packet
// LABEL-REJECT
BPF_STMT(BPF_RET, 0), // Reject packet
};
// template filter for all frames
static const struct bpf_insn promiscfilter[] = {
BPF_STMT(BPF_RET, 1514)
};
//
// Define the class. This is private to this module
//
class bx_fbsd_pktmover_c : public eth_pktmover_c {
public:
bx_fbsd_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
char *fbsd_macaddr[6];
int bpf_fd;
static void rx_timer_handler(void *);
void rx_timer(void);
int rx_timer_index;
struct bpf_insn filter[BX_BPF_INSNSIZ];
FILE *ne2klog, *ne2klog_txt;
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_fbsd_locator_c : public eth_locator_c {
public:
bx_fbsd_locator_c(void) : eth_locator_c("fbsd") {}
protected:
eth_pktmover_c *allocate(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_fbsd_match;
//
// Define the methods for the bx_fbsd_pktmover derived class
//
// the constructor
//
// Open a bpf file descriptor, and attempt to bind to
// the specified netif (Replicates libpcap open code)
//
bx_fbsd_pktmover_c::bx_fbsd_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
char device[sizeof "/dev/bpf000"];
int tmpfd;
int n = 0;
struct ifreq ifr;
struct bpf_version bv;
struct bpf_program bp;
u_int v;
this->netdev = dev;
BX_INFO(("freebsd network driver"));
memcpy(fbsd_macaddr, macaddr, 6);
do {
(void)sprintf(device, "/dev/bpf%d", n++);
this->bpf_fd = open(device, O_RDWR);
BX_DEBUG(("tried %s, returned %d (%s)",device,this->bpf_fd,strerror(errno)));
if(errno == EACCES)
break;
} while (this->bpf_fd == -1);
if (this->bpf_fd == -1) {
BX_PANIC(("eth_freebsd: could not open packet filter: %s", strerror(errno)));
return;
}
if (ioctl(this->bpf_fd, BIOCVERSION, (caddr_t)&bv) < 0) {
BX_PANIC(("eth_freebsd: could not retrieve bpf version"));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) {
BX_PANIC(("eth_freebsd: bpf version mismatch between compilation and runtime"));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
// Set buffer size
v = BX_PACKET_BUFSIZE;
if (ioctl(this->bpf_fd, BIOCSBLEN, (caddr_t)&v) < 0) {
BX_PANIC(("eth_freebsd: could not set buffer size: %s", strerror(errno)));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
(void)strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
if (ioctl(this->bpf_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
BX_PANIC(("eth_freebsd: could not enable interface '%s': %s", netif, strerror(errno)));
close(this->bpf_fd);
this->bpf_fd == -1;
}
// Verify that the device is an ethernet.
if (ioctl(this->bpf_fd, BIOCGDLT, (caddr_t)&v) < 0) {
BX_PANIC(("eth_freebsd: could not retrieve datalink type: %s", strerror(errno)));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
if (v != DLT_EN10MB) {
BX_PANIC(("eth_freebsd: incorrect datalink type %d, expected 10mb ethernet", v));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
// Put the device into promisc mode. This could be optimised
// to filter on a MAC address, broadcast, and all-multi,
// but this will do for now.
//
if (ioctl(this->bpf_fd, BIOCPROMISC, NULL) < 0) {
BX_PANIC(("eth_freebsd: could not enable promisc mode: %s", strerror(errno)));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
v = 1;
if (ioctl(this->bpf_fd, BIOCIMMEDIATE, &v) < 0) {
BX_PANIC(("eth_freebsd: could not enable immediate mode"));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
// Set up non-blocking i/o
v = 1;
if (ioctl(this->bpf_fd, FIONBIO, &v) < 0) {
BX_PANIC(("eth_freebsd: could not enable non-blocking i/o: %s", strerror(errno)));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
// Install a filter
#ifdef notdef
memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
bp.bf_len = 1;
#else
memcpy(&this->filter, macfilter, sizeof(macfilter));
this->filter[1].k =
(macaddr[2] & 0xff) << 24 |
(macaddr[3] & 0xff) << 16 |
(macaddr[4] & 0xff) << 8 |
(macaddr[5] & 0xff);
this->filter[3].k =
(macaddr[0] & 0xff) << 8 |
(macaddr[1] & 0xff);
bp.bf_len = 8;
#endif
bp.bf_insns = &this->filter[0];
if (ioctl(this->bpf_fd, BIOCSETF, &bp) < 0) {
BX_PANIC(("eth_freebsd: could not set filter: %s", strerror(errno)));
close(this->bpf_fd);
this->bpf_fd = -1;
return;
}
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, BX_BPF_POLL,
1, 1, "eth_fbsd"); // continuous, active
this->rxh = rxh;
#if BX_ETH_FBSD_LOGGING
// eventually Bryce wants ne2klog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
ne2klog = fopen("ne2k.raw", "wb");
if (!ne2klog) BX_PANIC(("open ne2k-tx.log failed"));
ne2klog_txt = fopen("ne2k.txt", "wb");
if (!ne2klog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
fprintf(ne2klog_txt, "null packetmover readable log file\n");
fprintf(ne2klog_txt, "net IF = %s\n", netif);
fprintf(ne2klog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(ne2klog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(ne2klog_txt, "\n--\n");
fflush(ne2klog_txt);
#endif
}
// the output routine - called with pre-formatted ethernet frame.
void
bx_fbsd_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#if BX_ETH_FBSD_LOGGING
BX_DEBUG(("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(buf, io_len, 1, ne2klog);
if (n != 1) BX_ERROR(("fwrite to ne2klog failed", io_len));
// dump packet in hex into an ascii log file
write_pktlog_txt(ne2klog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(ne2klog);
#endif
int status;
if (this->bpf_fd != -1)
status = write(this->bpf_fd, buf, io_len);
}
// The receive poll process
void
bx_fbsd_pktmover_c::rx_timer_handler(void *this_ptr)
{
bx_fbsd_pktmover_c *class_ptr = (bx_fbsd_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void
bx_fbsd_pktmover_c::rx_timer(void)
{
int nbytes = 0;
unsigned char rxbuf[BX_PACKET_BUFSIZE];
struct bpf_hdr *bhdr;
struct bpf_stat bstat;
static struct bpf_stat previous_bstat;
int counter = 10;
#define phdr ((unsigned char*)bhdr)
bhdr = (struct bpf_hdr *) rxbuf;
nbytes = read(this->bpf_fd, rxbuf, sizeof(rxbuf));
while (phdr < (rxbuf + nbytes)) {
if (ioctl(this->bpf_fd, BIOCGSTATS, &bstat) < 0) {
BX_PANIC(("eth_freebsd: could not stat filter: %s", strerror(errno)));
}
if (bstat.bs_drop > previous_bstat.bs_drop) {
BX_INFO(("eth_freebsd: %d packets dropped by the kernel.",
bstat.bs_drop - previous_bstat.bs_drop));
}
previous_bstat = bstat;
if (bhdr->bh_caplen < 20 || bhdr->bh_caplen > 1514) {
BX_ERROR(("eth_freebsd: received too weird packet length: %d", bhdr->bh_caplen));
}
// filter out packets sourced from this node
if (memcmp(bhdr + bhdr->bh_hdrlen + 6, this->fbsd_macaddr, 6)) {
(*rxh)(this->netdev, phdr + bhdr->bh_hdrlen, bhdr->bh_caplen);
}
#if BX_ETH_FBSD_LOGGING
BX_DEBUG(("receive packet length %u", nbytes));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
if (1 != fwrite(bhdr, bhdr->bh_caplen, 1, ne2klog)) {
BX_PANIC(("fwrite to ne2klog failed: %s", strerror(errno)));
}
// dump packet in hex into an ascii log file
write_pktlog_txt(ne2klog_txt, rxbuf, bhdr->bh_caplen, 1);
// flush log so that we see the packets as they arrive w/o buffering
fflush (this->ne2klog);
#endif
// Advance bhdr and phdr pointers to next packet
bhdr = (struct bpf_hdr*) ((char*) bhdr + BPF_WORDALIGN(bhdr->bh_hdrlen + bhdr->bh_caplen));
}
}
#endif /* if BX_NETWORKING && defined(ETH_FBSD) */

284
bochs/iodev/eth_linux.cc Normal file
View File

@ -0,0 +1,284 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.
// eth_linux.cc - A Linux socket filter adaptation of the FreeBSD BPF driver
// <splite@purdue.edu> 21 June 2001
//
// Problems and limitations:
// - packets cannot be sent from BOCHS to the host
// - Linux kernel sometimes gets network watchdog timeouts under emulation
// - author doesn't know C++
//
// The config line in .bochsrc should look something like:
//
// ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:2, ethmod=linux, ethdev=eth0
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined (ETH_LINUX)
#include "eth.h"
#define LOG_THIS netdev->
extern "C" {
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netpacket/packet.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <linux/types.h>
#include <linux/filter.h>
};
#define BX_PACKET_POLL 1000 // Poll for a frame every 1000 usecs
// template filter for a unicast mac address and all
// multicast/broadcast frames
static const struct sock_filter macfilter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
BPF_STMT(BPF_RET, 1514),
BPF_STMT(BPF_RET, 0),
};
#define BX_LSF_ICNT 8 // number of lsf instructions in macfilter
#if 0
// template filter for all frames
static const struct sock_filter promiscfilter[] = {
BPF_STMT(BPF_RET, 1514)
};
#endif
//
// Define the class. This is private to this module
//
class bx_linux_pktmover_c : public eth_pktmover_c {
public:
bx_linux_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
unsigned char *linux_macaddr[6];
int fd;
int ifindex;
static void rx_timer_handler(void *);
void rx_timer(void);
int rx_timer_index;
struct sock_filter filter[BX_LSF_ICNT];
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_linux_locator_c : public eth_locator_c {
public:
bx_linux_locator_c(void) : eth_locator_c("linux") {}
protected:
eth_pktmover_c *allocate(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_linux_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_linux_match;
//
// Define the methods for the bx_linux_pktmover derived class
//
// the constructor
//
bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
struct sockaddr_ll sll;
struct packet_mreq mr;
struct ifreq ifr;
struct sock_fprog fp;
this->netdev = dev;
memcpy(linux_macaddr, macaddr, 6);
// Open packet socket
//
if ((this->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
if (errno == EACCES)
BX_PANIC(("eth_linux: must be root or have CAP_NET_RAW capability to open socket"));
else
BX_PANIC(("eth_linux: could not open socket: %s", strerror(errno)));
this->fd = -1;
return;
}
// Translate interface name to index
//
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, netif);
if (ioctl(this->fd, SIOCGIFINDEX, &ifr) == -1) {
BX_PANIC(("eth_linux: could not get index for interface '%s'\n", netif));
close(fd);
this->fd = -1;
return;
}
this->ifindex = ifr.ifr_ifindex;
// Bind to given interface
//
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = this->ifindex;
if (bind(fd, (struct sockaddr *)&sll, (socklen_t)sizeof(sll)) == -1) {
BX_PANIC(("eth_linux: could not bind to interface '%s': %s\n", netif, strerror(errno)));
close(fd);
this->fd = -1;
return;
}
// Put the device into promisc mode.
//
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = this->ifindex;
mr.mr_type = PACKET_MR_PROMISC;
if (setsockopt(this->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *)&mr, (socklen_t)sizeof(mr)) == -1) {
BX_PANIC(("eth_linux: could not enable promisc mode: %s\n", strerror(errno)));
close(this->fd);
this->fd = -1;
return;
}
// Set up non-blocking i/o
if (fcntl(this->fd, F_SETFL, O_NONBLOCK) == -1) {
BX_PANIC(("eth_linux: could not set non-blocking i/o on socket"));
close(this->fd);
this->fd = -1;
return;
}
// Install a filter
#ifdef notdef
memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
fp.len = 1;
#endif
memcpy(&this->filter, macfilter, sizeof(macfilter));
this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 |
(macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
fp.len = BX_LSF_ICNT;
fp.filter = this->filter;
BX_INFO(("eth_linux: fp.len=%d fp.filter=%lx", fp.len, (unsigned long) fp.filter));
if (setsockopt(this->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fp, sizeof(fp)) < 0) {
BX_PANIC(("eth_linux: could not set socket filter: %s", strerror(errno)));
close(this->fd);
this->fd = -1;
return;
}
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, BX_PACKET_POLL,
1, 1, "eth_linux"); // continuous, active
this->rxh = rxh;
BX_INFO(("linux network driver initialized: using interface %s", netif));
}
// the output routine - called with pre-formatted ethernet frame.
void
bx_linux_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
int status;
if (this->fd != -1) {
status = write(this->fd, buf, io_len);
if (status == -1)
BX_INFO(("eth_linux: write failed: %s", strerror(errno)));
}
}
// The receive poll process
void
bx_linux_pktmover_c::rx_timer_handler(void *this_ptr)
{
bx_linux_pktmover_c *class_ptr = (bx_linux_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void
bx_linux_pktmover_c::rx_timer(void)
{
int nbytes = 0;
Bit8u rxbuf[BX_PACKET_BUFSIZE];
struct sockaddr_ll sll;
socklen_t fromlen;
if (this->fd == -1)
return;
fromlen = sizeof(sll);
nbytes = recvfrom(this->fd, rxbuf, sizeof(rxbuf), 0, (struct sockaddr *)&sll, &fromlen);
if (nbytes == -1) {
if (errno != EAGAIN)
BX_INFO(("eth_linux: error receiving packet: %s\n", strerror(errno)));
return;
}
// this should be done with LSF someday
// filter out packets sourced by us
if (memcmp(sll.sll_addr, this->linux_macaddr, 6) == 0)
return;
// let through broadcast, multicast, and our mac address
// if ((memcmp(rxbuf, broadcast_macaddr, 6) == 0) || (memcmp(rxbuf, this->linux_macaddr, 6) == 0) || rxbuf[0] & 0x01) {
BX_DEBUG(("eth_linux: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
(*rxh)(netdev, rxbuf, nbytes);
// }
}
#endif /* if BX_NETWORKING && defined ETH_LINUX */

148
bochs/iodev/eth_null.cc Normal file
View File

@ -0,0 +1,148 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// eth_null.cc - skeleton code for an ethernet pktmover
// Various networking docs:
// http://www.graphcomp.com/info/rfc/
// rfc0826: arp
// rfc0903: rarp
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING
#include "eth.h"
#define LOG_THIS netdev->
//
// Define the class. This is private to this module
//
class bx_null_pktmover_c : public eth_pktmover_c {
public:
bx_null_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
int rx_timer_index;
static void rx_timer_handler(void *);
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_null_locator_c : public eth_locator_c {
public:
bx_null_locator_c(void) : eth_locator_c("null") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_null_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_null_match;
//
// Define the methods for the bx_null_pktmover derived class
//
// the constructor
bx_null_pktmover_c::bx_null_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
this->netdev = dev;
BX_INFO(("null network driver"));
#if BX_ETH_NULL_LOGGING
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
1, 1, "eth_null"); // continuous, active
this->rxh = rxh;
// eventually Bryce wants txlog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
txlog = fopen("ne2k-tx.log", "wb");
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
txlog_txt = fopen("ne2k-txdump.txt", "wb");
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
fprintf(txlog_txt, "null packetmover readable log file\n");
fprintf(txlog_txt, "net IF = %s\n", netif);
fprintf(txlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(txlog_txt, "\n--\n");
fflush(txlog_txt);
#endif
}
void bx_null_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#if BX_ETH_NULL_LOGGING
BX_DEBUG (("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
size_t n = fwrite (buf, io_len, 1, txlog);
if (n != 1) BX_ERROR(("fwrite to txlog failed, io_len = %u", io_len));
// dump packet in hex into an ascii log file
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(txlog);
#endif
}
void bx_null_pktmover_c::rx_timer_handler (void *this_ptr)
{
#if BX_ETH_NULL_LOGGING
/// hey wait there is no receive data with a NULL ethernet, is there....
int io_len = 0;
Bit8u buf[1];
bx_null_pktmover_c *class_ptr = (bx_null_pktmover_c *) this_ptr;
bx_devmodel_c *netdev = class_ptr->netdev;
if (io_len > 0) {
BX_DEBUG(("receive packet length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
size_t n = fwrite (buf, io_len, 1, class_ptr->rxlog);
if (n != 1) BX_ERROR(("fwrite to rxlog failed, io_len = %u", io_len));
// dump packet in hex into an ascii log file
write_pktlog_txt(class_ptr->rxlog_txt, buf, io_len, 1);
// flush log so that we see the packets as they arrive w/o buffering
fflush(class_ptr->rxlog);
}
#endif
}
#endif /* if BX_NETWORKING */

View File

@ -0,0 +1,202 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(ETH_ARPBACK)
#include "eth_packetmaker.h"
bx_bool sendable(const eth_packet& outpacket) {
//FINISH ME!
return 0;
}
Bit32u eth_IPmaker::datalen(const eth_packet& outpacket)
{
Bit32u out;
out=((outpacket.buf[16]<<8)+outpacket.buf[17])-(4*(0xF & outpacket.buf[14]));
return out;
}
const Bit8u *eth_IPmaker::datagram(const eth_packet& outpacket)
{
const Bit8u *out;
out=outpacket.buf+14+(4*(0xF & outpacket.buf[14]));
return out;
}
Bit32u eth_IPmaker::build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen)
{
Bit32u temp;
Bit32u i;
memcpy(pending.buf,internal_mac,6);
memcpy(pending.buf+6,external_mac,6);
memcpy(pending.buf+12,ethtype_ip,2);
pending.buf[14]=0x45;
pending.buf[15]=0;
temp=datalen+20;
pending.buf[16]=(temp>>8) & 0xFF;
pending.buf[17]=temp & 0xFF;
pending.buf[18]=0;
pending.buf[19]=0;
pending.buf[20]=0;
pending.buf[21]=0;
pending.buf[22]=30;
pending.buf[23]=protocol;
pending.buf[24]=0;
pending.buf[25]=0;
pending.buf[26]=(source>>24) & 0xFF;
pending.buf[27]=(source>>16) & 0xFF;
pending.buf[28]=(source>>8) & 0xFF;
pending.buf[29]=(source) & 0xFF;
pending.buf[30]=(dest>>24) & 0xFF;
pending.buf[31]=(dest>>16) & 0xFF;
pending.buf[32]=(dest>>8) & 0xFF;
pending.buf[33]=(dest) & 0xFF;
//Compute Checksum
temp=0;
for(i=14;i<34;i=i+2) {
Bit32u addee=pending.buf[i];
addee=(addee<<8) & pending.buf[i+1];
temp=temp+addee;
}
temp=(temp>>16)+(temp&0xFFFF);
temp=(temp>>16)+(temp&0xFFFF);
pending.buf[24]=~(Bit8u)((temp>>8) & 0xFF);
pending.buf[25]=~(Bit8u)(temp & 0xFF);
return(34);
}
Bit8u eth_IPmaker::protocol(const eth_packet& outpacket)
{
return (*(outpacket.buf+23) & 0xff);
}
Bit32u eth_IPmaker::source(const eth_packet& outpacket)
{
Bit32u out=0xFF & *(outpacket.buf+26);
out=(out<<8) | (0xFF & *(outpacket.buf+27));
out=(out<<8) | (0xFF & *(outpacket.buf+28));
out=(out<<8) | (0xFF & *(outpacket.buf+29));
return out;
}
Bit32u eth_IPmaker::destination(const eth_packet& outpacket)
{
Bit32u out=0xFF & *(outpacket.buf+30);
out=(out<<8) | (0xFF & *(outpacket.buf+31));
out=(out<<8) | (0xFF & *(outpacket.buf+32));
out=(out<<8) | (0xFF & *(outpacket.buf+33));
return out;
}
void eth_IPmaker::init(void)
{
is_pending=0;
}
void eth_ETHmaker::init(void)
{
arper.init();
}
bx_bool eth_ETHmaker::getpacket(eth_packet& inpacket)
{
return arper.getpacket(inpacket);
}
bx_bool eth_ETHmaker::ishandler(const eth_packet& outpacket)
{
if((outpacket.len>=60) &&
( (!memcmp(outpacket.buf, external_mac, 6))
|| (!memcmp(outpacket.buf, broadcast_macaddr, 6))) &&
( (!memcmp(outpacket.buf+12, ethtype_arp, 2)) ||
(!memcmp(outpacket.buf+12, ethtype_ip, 2))) &&
(outpacket.len<PACKET_BUF_SIZE)
) {
return 1;
}
return 0;
}
bx_bool eth_ETHmaker::sendpacket(const eth_packet& outpacket)
{
return arper.sendpacket(outpacket);
}
void eth_ARPmaker::init(void)
{
is_pending=0;
pending.len=0;
}
bx_bool eth_ARPmaker::getpacket(eth_packet& inpacket)
{
if(is_pending) {
memcpy(inpacket.buf,pending.buf,pending.len);
inpacket.len=pending.len;
is_pending=0;
return 1;
}
return 0;
}
bx_bool eth_ARPmaker::ishandler(const eth_packet& outpacket)
{
if((outpacket.len>=60) &&
(!memcmp(outpacket.buf+12, ethtype_arp, 2)) &&
(outpacket.len<PACKET_BUF_SIZE) &&
( (!memcmp(outpacket.buf, external_mac, 6))
|| (!memcmp(outpacket.buf, broadcast_macaddr, 6)) ) &&
(!memcmp(outpacket.buf+38, external_ip, 4))
) {
return 1;
}
return 0;
}
bx_bool eth_ARPmaker::sendpacket(const eth_packet& outpacket)
{
if(is_pending || !ishandler(outpacket)) {
return 0;
} else {
//Bit32u tempcrc;
memcpy(pending.buf,outpacket.buf,outpacket.len); //move to temporary buffer
memcpy(pending.buf, pending.buf+6, 6); //set destination to sender
memcpy(pending.buf+6, external_mac, 6); //set sender to us
memcpy(pending.buf+32, pending.buf+22, 10); //move destination to sender
memcpy(pending.buf+22, external_mac, 6); //set sender to us
memcpy(pending.buf+28, external_ip, 4); //set sender to us
pending.buf[21]=2; //make this a reply and not a request
//tempcrc=mycrc.get_CRC(pending.buf,len);
//memcpy(pending.buf+len, &tempcrc, 4);
pending.len=outpacket.len; //+4
is_pending=1;
return 1;
}
}
#endif /* if BX_NETWORKING && defined(ETH_ARPBACK) */

View File

@ -0,0 +1,146 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef _ETH_PACKETMAKER_H_
#define _ETH_PACKETMAKER_H_
#ifdef ETH_ARPBACK
static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
static const Bit8u ethtype_ip[]={0x08, 0x00, 0x00};
static const Bit8u prot_udp=17;
static const Bit8u prot_tcp=6;
class eth_packet {
public:
Bit8u buf[BX_PACKET_BUFSIZE];
Bit32u len;
};
class eth_packetmaker {
public:
virtual bx_bool getpacket(eth_packet& inpacket) = 0;
virtual bx_bool ishandler(const eth_packet& outpacket) = 0;
virtual bx_bool sendpacket(const eth_packet& outpacket) = 0;
};
class eth_ARPmaker : public eth_packetmaker {
public:
void init(void);
bx_bool ishandler(const eth_packet& outpacket);
bx_bool sendpacket(const eth_packet& outpacket);
bx_bool getpacket(eth_packet& inpacket);
private:
eth_packet pending;
bx_bool is_pending;
};
class eth_IPmaker : eth_packetmaker {
public:
void init(void);
virtual bx_bool ishandler(const eth_packet& outpacket)=0;
virtual bx_bool sendpacket(const eth_packet& outpacket)=0;
virtual bx_bool getpacket(eth_packet& inpacket)=0;
protected:
bx_bool sendable(const eth_packet& outpacket);
Bit32u source(const eth_packet& outpacket);
Bit32u destination(const eth_packet& outpacket);
Bit8u protocol(const eth_packet& outpacket);
const Bit8u * datagram(const eth_packet& outpacket);
Bit32u datalen(const eth_packet& outpacket);
//Build a header in pending, return header length in bytes.
Bit32u build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen);
eth_packet pending;
bx_bool is_pending;
//Bit8u Version; //=4 (4 bits)
//It better be!
//Bit8u IHL; //Header length in 32-bit bytes (4 bits)
//Used to strip layer
//Bit8u Type_of_Service; //not relevent, set to 0;
//Ignore on receive, set to 0 on send.
//Bit16u Total_Length;//length of the datagram in octets. use 576 or less;
//Use 576 or less on send.
//Use to get length on receive
//Bit16u Identification;//Identifier for assembling fragments
//Ignore, we'll drop fragments
//Bit8u Flags;//0,Don't fragment, More Fragments (vs last fragment)
//Set to 0 on send
//Drop if more fragments set.
//Bit16u Fragment Offset;//where in the datagram this fragment belongs
//Should be 0 for send and receive.
//Bit8u TTL;//Set to something sorta big.
//Shouldn't be 0 on receive
//Set to something big on send
//Bit8u Protocol;
//Defines Protocol.
//TCP=?, UDP=?
//Bit16u Header_Checksum;//16-bit one's complement of the one's complement
//sum of all 16-bit words in header;
//Could check on receive, must set on send.
//Bit32u Source;//source address
//Bit32u Destination;//destination address
};
/*
class eth_TCPmaker : eth_packetmaker {
};
class eth_UDPmaker : eth_packetmaker {
};
*/
class eth_ETHmaker : public eth_packetmaker {
public:
//handles all packets to a MAC addr.
void init(void);
virtual bx_bool getpacket(eth_packet& inpacket);
virtual bx_bool ishandler(const eth_packet& outpacket);
virtual bx_bool sendpacket(const eth_packet& outpacket);
private:
eth_ARPmaker arper;
};
#endif // ETH_ARPBACK
#endif // _ETH_PACKETMAKER_H_

415
bochs/iodev/eth_tap.cc Normal file
View File

@ -0,0 +1,415 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// eth_tap.cc - TAP interface by Bryce Denney
//
// Here's how to get this working. On the host machine:
// $ su root
// # /sbin/insmod ethertap
// Using /lib/modules/2.2.14-5.0/net/ethertap.o
// # mknod /dev/tap0 c 36 16 # if not already there
// # /sbin/ifconfig tap0 10.0.0.1
// # /sbin/route add -host 10.0.0.2 gw 10.0.0.1
//
// Now you have a tap0 device which you can on the ifconfig output. The
// tap0 interface has the IP address of 10.0.0.1. The bochs machine will have
// the IP address 10.0.0.2.
//
// Compile a bochs version from March 8, 2002 or later with --enable-ne2000.
// Add this ne2k line to your .bochsrc to activate the tap device.
// ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
// Don't change the mac or ethmod!
//
// Boot up DLX Linux in Bochs. Log in as root and then type the following
// commands to set up networking:
// # ifconfig eth0 10.0.0.2
// # route add -net 10.0.0.0
// # route add default gw 10.0.0.1
// Now you should be able to ping from guest OS to your host machine, if
// you give its IP number. I'm still having trouble with pings from the
// host machine to the guest, so something is still not right. Symptoms: I
// ping from the host to the guest's IP address 10.0.0.2. With tcpdump I can
// see the ping going to Bochs, and then the ping reply coming from Bochs.
// But the ping program itself does not see the responses....well every
// once in a while it does, like 1 in 60 pings.
//
// host$ ping 10.0.0.2
// PING 10.0.0.2 (10.0.0.2) from 10.0.0.1 : 56(84) bytes of data.
//
// Netstat output:
// 20:29:59.018776 fe:fd:0:0:0:0 fe:fd:0:0:0:1 0800 98: 10.0.0.1 > 10.0.0.2: icmp: echo request
// 4500 0054 2800 0000 4001 3ea7 0a00 0001
// 0a00 0002 0800 09d3 a53e 0400 9765 893c
// 3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
// 1415 1617 1819
// 20:29:59.023017 fe:fd:0:0:0:1 fe:fd:0:0:0:0 0800 98: 10.0.0.2 > 10.0.0.1: icmp: echo reply
// 4500 0054 004a 0000 4001 665d 0a00 0002
// 0a00 0001 0000 11d3 a53e 0400 9765 893c
// 3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
// 1415 1617 1819
//
// I suspect it may be related to the fact that ping 10.0.0.1 from the
// host also doesn't work. Why wouldn't the host respond to its own IP
// address on the tap0 device?
//
// Theoretically, if you set up packet forwarding (with masquerading) on the
// host, you should be able to get Bochs talking to anyone on the internet.
//
// Pavel Dufek (PD), CZ, 2008 - quick & dirty hack for Solaris 10 sparc tap
// ala Qemu.
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(HAVE_ETHERTAP)
#include "eth.h"
#define LOG_THIS netdev->
#include <signal.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#ifndef __APPLE__
#include <sys/poll.h>
#endif
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#if defined(__linux__)
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/if.h>
#elif BX_HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#if defined(__sun__)
// Sun/Solaris specific defines/includes
#define TUNNEWPPA (('T'<<16) | 0x0001)
#include <stropts.h>
#endif
#define BX_ETH_TAP_LOGGING 0
//
// Define the class. This is private to this module
//
class bx_tap_pktmover_c : public eth_pktmover_c {
public:
bx_tap_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
int fd;
int rx_timer_index;
static void rx_timer_handler(void *);
void rx_timer ();
Bit8u guest_macaddr[6];
#if BX_ETH_TAP_LOGGING
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
#endif
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_tap_locator_c : public eth_locator_c {
public:
bx_tap_locator_c(void) : eth_locator_c("tap") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_tap_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_tap_match;
//
// Define the methods for the bx_tap_pktmover derived class
//
// the constructor
bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
int flags;
char filename[BX_PATHNAME_LEN];
this->netdev = dev;
if (strncmp (netif, "tap", 3) != 0) {
BX_PANIC(("eth_tap: interface name (%s) must be tap0..tap15", netif));
}
#if defined(__sun__)
strcpy(filename,"/dev/tap"); /* PD - device on Solaris is always the same */
#else
sprintf(filename, "/dev/%s", netif);
#endif
#if defined(__linux__)
// check if the TAP devices is running, and turn on ARP. This is based
// on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
BX_PANIC(("socket creation: %s", strerror(errno)));
return;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
BX_PANIC(("SIOCGIFFLAGS on %s: %s", netif, strerror(errno)));
close(sock);
return;
}
if (!(ifr.ifr_flags & IFF_RUNNING)) {
BX_PANIC(("%s device is not running", netif));
close(sock);
return;
}
if ((ifr.ifr_flags & IFF_NOARP)){
BX_INFO(("turn on ARP for %s device", netif));
ifr.ifr_flags &= ~IFF_NOARP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
BX_PANIC(("SIOCSIFFLAGS: %s", strerror(errno)));
close(sock);
return;
}
}
close(sock);
#endif
fd = open (filename, O_RDWR);
if (fd < 0) {
BX_PANIC(("open failed on TAP %s: %s", netif, strerror(errno)));
return;
}
#if defined(__sun__)
char *ptr; /* PD - ppa allocation ala qemu */
char my_dev[10]; /* enough ... */
int ppa=-1;
struct strioctl strioc_ppa;
my_dev[10-1]=0;
strncpy(my_dev,netif,10); /* following ptr= does not work with const char* */
if( *my_dev ) { /* find the ppa number X from string tapX */
ptr = my_dev;
while( *ptr && !isdigit((int)*ptr) ) ptr++;
ppa = atoi(ptr);
}
/* Assign a new PPA and get its unit number. */
strioc_ppa.ic_cmd = TUNNEWPPA;
strioc_ppa.ic_timout = 0;
strioc_ppa.ic_len = sizeof(ppa);
strioc_ppa.ic_dp = (char *)&ppa;
if ((ppa = ioctl (fd, I_STR, &strioc_ppa)) < 0)
BX_PANIC(("Can't assign new interface tap%d !",ppa));
#endif
/* set O_ASYNC flag so that we can poll with read() */
if ((flags = fcntl(fd, F_GETFL)) < 0) {
BX_PANIC(("getflags on tap device: %s", strerror(errno)));
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) {
BX_PANIC(("set tap device flags: %s", strerror(errno)));
}
BX_INFO(("tap network drive: opened %s device", netif));
/* Execute the configuration script */
char intname[IFNAMSIZ];
strcpy(intname,netif);
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
{
if (execute_script(this->netdev, script, intname) < 0)
BX_ERROR(("execute script '%s' on %s failed", script, intname));
}
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
1, 1, "eth_tap"); // continuous, active
this->rxh = rxh;
memcpy(&guest_macaddr[0], macaddr, 6);
#if BX_ETH_TAP_LOGGING
// eventually Bryce wants txlog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
txlog = fopen("ne2k-tx.log", "wb");
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
txlog_txt = fopen("ne2k-txdump.txt", "wb");
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
fprintf(txlog_txt, "tap packetmover readable log file\n");
fprintf(txlog_txt, "net IF = %s\n", netif);
fprintf(txlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(txlog_txt, "\n--\n");
fflush(txlog_txt);
rxlog = fopen("ne2k-rx.log", "wb");
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
fprintf(rxlog_txt, "tap packetmover readable log file\n");
fprintf(rxlog_txt, "net IF = %s\n", netif);
fprintf(rxlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(rxlog_txt, "\n--\n");
fflush(rxlog_txt);
#endif
}
void bx_tap_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
Bit8u txbuf[BX_PACKET_BUFSIZE];
txbuf[0] = 0;
txbuf[1] = 0;
unsigned int size;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__APPLE__) || defined(__OpenBSD__) || defined(__sun__) // Should be fixed for other *BSD
memcpy(txbuf, buf, io_len);
/* PD - for Sun variant the retry cycle from qemu - mainly to be sure packet
is really out */
#if defined(__sun__)
int ret;
for(;;) {
ret=write(fd, txbuf, io_len);
if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
} else {
size=ret;
break;
}
}
#else /* not defined __sun__ */
size = write(fd, txbuf, io_len);
#endif /* whole condition about defined __sun__ */
if (size != io_len) {
#else /* not bsd/apple/sun style */
memcpy(txbuf+2, buf, io_len);
size = write(fd, txbuf, io_len+2);
if (size != io_len+2) {
#endif
BX_PANIC(("write on tap device: %s", strerror(errno)));
} else {
BX_DEBUG(("wrote %d bytes + ev. 2 byte pad on tap", io_len));
}
#if BX_ETH_TAP_LOGGING
BX_DEBUG(("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(buf, io_len, 1, txlog);
if (n != 1) BX_ERROR(("fwrite to txlog failed, io_len = %u", io_len));
// dump packet in hex into an ascii log file
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(txlog);
#endif
}
void bx_tap_pktmover_c::rx_timer_handler(void *this_ptr)
{
bx_tap_pktmover_c *class_ptr = (bx_tap_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void bx_tap_pktmover_c::rx_timer()
{
int nbytes;
Bit8u buf[BX_PACKET_BUFSIZE];
Bit8u *rxbuf;
if (fd<0) return;
#if defined(__sun__)
struct strbuf sbuf;
int f = 0;
sbuf.maxlen = sizeof(buf);
sbuf.buf = (char *)buf;
nbytes = getmsg(fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
#else
nbytes = read (fd, buf, sizeof(buf));
#endif
// hack: discard first two bytes
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__sun__) // Should be fixed for other *BSD
rxbuf = buf;
#else
rxbuf = buf+2;
nbytes-=2;
#endif
#if defined(__linux__)
// hack: TAP device likes to create an ethernet header which has
// the same source and destination address FE:FD:00:00:00:00.
// Change the dest address to FE:FD:00:00:00:01.
if (!memcmp(&rxbuf[0], &rxbuf[6], 6)) {
rxbuf[5] = guest_macaddr[5];
}
#endif
if (nbytes>0)
BX_DEBUG(("tap read returned %d bytes", nbytes));
if (nbytes<0) {
if (errno != EAGAIN)
BX_ERROR(("tap read error: %s", strerror(errno)));
return;
}
#if BX_ETH_TAP_LOGGING
if (nbytes > 0) {
BX_DEBUG(("receive packet length %u", nbytes));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(rxbuf, nbytes, 1, rxlog);
if (n != 1) BX_ERROR(("fwrite to rxlog failed, nbytes = %d", nbytes));
// dump packet in hex into an ascii log file
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
// flush log so that we see the packets as they arrive w/o buffering
fflush(rxlog);
}
#endif
BX_DEBUG(("eth_tap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
if (nbytes < 60) {
BX_INFO(("packet too short (%d), padding to 60", nbytes));
nbytes = 60;
}
(*rxh)(netdev, rxbuf, nbytes);
}
#endif /* if BX_NETWORKING && defined HAVE_ETHERTAP */

381
bochs/iodev/eth_tuntap.cc Normal file
View File

@ -0,0 +1,381 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// eth_tuntap.cc - TUN/TAP interface by Renzo Davoli <renzo@cs.unibo.it>
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(HAVE_TUNTAP)
#include "eth.h"
#define DIFNAMSIZ (IFNAMSIZ*2)
#define LOG_THIS netdev->
#include <signal.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#ifndef __APPLE__
#include <sys/poll.h>
#endif
#include <sys/time.h>
#include <sys/resource.h>
#ifdef __linux__
#include <asm/types.h>
#else
#include <sys/types.h>
#endif
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/wait.h>
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#else
#include <net/if.h>
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
#include <net/if_tap.h>
#endif
#endif
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#define BX_ETH_TUNTAP_LOGGING 0
int tun_alloc(char *dev);
//
// Define the class. This is private to this module
//
class bx_tuntap_pktmover_c : public eth_pktmover_c {
public:
bx_tuntap_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
int fd;
int rx_timer_index;
static void rx_timer_handler(void *);
void rx_timer ();
Bit8u guest_macaddr[6];
#if BX_ETH_TUNTAP_LOGGING
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
#endif
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_tuntap_locator_c : public eth_locator_c {
public:
bx_tuntap_locator_c(void) : eth_locator_c("tuntap") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_tuntap_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_tuntap_match;
//
// Define the methods for the bx_tuntap_pktmover derived class
//
// the constructor
bx_tuntap_pktmover_c::bx_tuntap_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
int flags;
this->netdev = dev;
#ifdef NEVERDEF
if (strncmp (netif, "tun", 3) != 0) {
BX_PANIC(("eth_tuntap: interface name (%s) must be tun", netif));
}
char filename[BX_PATHNAME_LEN];
sprintf(filename, "/dev/net/%s", netif);
// check if the TUN/TAP devices is running, and turn on ARP. This is based
// on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
BX_PANIC(("socket creation: %s", strerror(errno)));
return;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
BX_PANIC(("SIOCGIFFLAGS on %s: %s", netif, strerror (errno)));
close(sock);
return;
}
if (!(ifr.ifr_flags & IFF_RUNNING)) {
BX_PANIC(("%s device is not running", netif));
close(sock);
return;
}
if ((ifr.ifr_flags & IFF_NOARP)) {
BX_INFO(("turn on ARP for %s device", netif));
ifr.ifr_flags &= ~IFF_NOARP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
BX_PANIC(("SIOCSIFFLAGS: %s", strerror(errno)));
close(sock);
return;
}
}
close(sock);
fd = open (filename, O_RDWR);
#endif
char intname[DIFNAMSIZ];
strncpy(intname,netif, DIFNAMSIZ);
fd=tun_alloc(intname);
if (fd < 0) {
BX_PANIC(("open failed on %s: %s", netif, strerror (errno)));
return;
}
/* set O_ASYNC flag so that we can poll with read() */
if ((flags = fcntl(fd, F_GETFL)) < 0) {
BX_PANIC(("getflags on tun device: %s", strerror (errno)));
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) {
BX_PANIC(("set tun device flags: %s", strerror (errno)));
}
BX_INFO(("tuntap network driver: opened %s device", netif));
/* Execute the configuration script */
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
{
if (execute_script(this->netdev, script, intname) < 0)
BX_ERROR(("execute script '%s' on %s failed", script, intname));
}
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
1, 1, "eth_tuntap"); // continuous, active
this->rxh = rxh;
memcpy(&guest_macaddr[0], macaddr, 6);
#if BX_ETH_TUNTAP_LOGGING
// eventually Bryce wants txlog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
txlog = fopen("ne2k-tx.log", "wb");
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
txlog_txt = fopen("ne2k-txdump.txt", "wb");
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
fprintf(txlog_txt, "tuntap packetmover readable log file\n");
fprintf(txlog_txt, "net IF = %s\n", netif);
fprintf(txlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(txlog_txt, "\n--\n");
fflush(txlog_txt);
rxlog = fopen("ne2k-rx.log", "wb");
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
fprintf(rxlog_txt, "tuntap packetmover readable log file\n");
fprintf(rxlog_txt, "net IF = %s\n", netif);
fprintf(rxlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(rxlog_txt, "\n--\n");
fflush(rxlog_txt);
#endif
}
void bx_tuntap_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#ifdef __APPLE__ //FIXME
unsigned int size = write (fd, (char*)buf+14, io_len-14);
if (size != io_len-14) {
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
} else {
BX_DEBUG(("wrote %d bytes on tuntap - 14 bytes Ethernet header", io_len));
}
#elif NEVERDEF
Bit8u txbuf[BX_PACKET_BUFSIZE];
txbuf[0] = 0;
txbuf[1] = 0;
memcpy (txbuf+2, buf, io_len);
unsigned int size = write (fd, txbuf, io_len+2);
if (size != io_len+2) {
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
} else {
BX_DEBUG(("wrote %d bytes + 2 byte pad on tuntap", io_len));
}
#else
unsigned int size = write (fd, buf, io_len);
if (size != io_len) {
BX_PANIC(("write on tuntap device: %s", strerror (errno)));
} else {
BX_DEBUG(("wrote %d bytes on tuntap", io_len));
}
#endif
#if BX_ETH_TUNTAP_LOGGING
BX_DEBUG(("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(buf, io_len, 1, txlog);
if (n != 1) BX_ERROR(("fwrite to txlog failed"));
// dump packet in hex into an ascii log file
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(txlog);
#endif
}
void bx_tuntap_pktmover_c::rx_timer_handler (void *this_ptr)
{
bx_tuntap_pktmover_c *class_ptr = (bx_tuntap_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void bx_tuntap_pktmover_c::rx_timer()
{
int nbytes;
Bit8u buf[BX_PACKET_BUFSIZE];
Bit8u *rxbuf;
if (fd<0) return;
#ifdef __APPLE__ //FIXME:hack
nbytes = 14;
bzero(buf, nbytes);
buf[0] = buf[6] = 0xFE;
buf[1] = buf[7] = 0xFD;
buf[12] = 8;
nbytes += read (fd, buf+nbytes, sizeof(buf)-nbytes);
rxbuf=buf;
#elif NEVERDEF
nbytes = read (fd, buf, sizeof(buf));
// hack: discard first two bytes
rxbuf = buf+2;
nbytes-=2;
#else
nbytes = read (fd, buf, sizeof(buf));
rxbuf=buf;
#endif
// hack: TUN/TAP device likes to create an ethernet header which has
// the same source and destination address FE:FD:00:00:00:00.
// Change the dest address to FE:FD:00:00:00:01.
if (!memcmp(&rxbuf[0], &rxbuf[6], 6)) {
rxbuf[5] = guest_macaddr[5];
}
#ifdef __APPLE__ //FIXME:hack
if (nbytes>14)
#else
if (nbytes>0)
#endif
BX_DEBUG(("tuntap read returned %d bytes", nbytes));
#ifdef __APPLE__ //FIXME:hack
if (nbytes<14) {
#else
if (nbytes<0) {
#endif
if (errno != EAGAIN)
BX_ERROR(("tuntap read error: %s", strerror(errno)));
return;
}
#if BX_ETH_TUNTAP_LOGGING
if (nbytes > 0) {
BX_DEBUG(("receive packet length %u", nbytes));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(rxbuf, nbytes, 1, rxlog);
if (n != 1) BX_ERROR (("fwrite to rxlog failed"));
// dump packet in hex into an ascii log file
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
// flush log so that we see the packets as they arrive w/o buffering
fflush(rxlog);
}
#endif
BX_DEBUG(("eth_tuntap: got packet: %d bytes, dst=%02x:%02x:%02x:%02x:%02x:%02x, src=%02x:%02x:%02x:%02x:%02x:%02x", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
if (nbytes < 60) {
BX_INFO(("packet too short (%d), padding to 60", nbytes));
nbytes = 60;
}
(*rxh)(this->netdev, rxbuf, nbytes);
}
int tun_alloc(char *dev)
{
struct ifreq ifr;
char *ifname;
int fd, err;
// split name into device:ifname if applicable, to allow for opening
// persistent tuntap devices
for (ifname = dev; *ifname; ifname++) {
if (*ifname == ':') {
*(ifname++) = '\0';
break;
}
}
if ((fd = open(dev, O_RDWR)) < 0)
return -1;
#ifdef __linux__
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) {
close(fd);
return err;
}
strncpy(dev, ifr.ifr_name, IFNAMSIZ);
dev[IFNAMSIZ-1]=0;
ioctl(fd, TUNSETNOCSUM, 1);
#endif
return fd;
}
#endif /* if BX_NETWORKING && defined HAVE_TUNTAP */

327
bochs/iodev/eth_vde.cc Normal file
View File

@ -0,0 +1,327 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003 Renzo Davoli
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// eth_vde.cc - Virtual Distributed Ethernet interface by Renzo Davoli <renzo@cs.unibo.it>
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(HAVE_VDE)
#include "eth.h"
#define LOG_THIS netdev->
#include <signal.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/socket.h>
#if defined(__linux__)
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/if.h>
#elif BX_HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <sys/uio.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#define SWITCH_MAGIC 0xfeedface
#define BX_ETH_VDE_LOGGING 0
int vde_alloc(char *dev,int *fdp,struct sockaddr_un *pdataout);
//
// Define the class. This is private to this module
//
class bx_vde_pktmover_c : public eth_pktmover_c {
public:
bx_vde_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
int fd;
int rx_timer_index;
static void rx_timer_handler(void *);
void rx_timer();
FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
int fddata;
struct sockaddr_un dataout;
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_vde_locator_c : public eth_locator_c {
public:
bx_vde_locator_c(void) : eth_locator_c("vde") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_vde_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_vde_match;
//
// Define the methods for the bx_vde_pktmover derived class
//
// the constructor
bx_vde_pktmover_c::bx_vde_pktmover_c(const char *netif,
const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev,
const char *script)
{
int flags;
this->netdev = dev;
//if (strncmp (netif, "vde", 3) != 0) {
// BX_PANIC (("eth_vde: interface name (%s) must be vde", netif));
//}
char intname[IFNAMSIZ];
if (netif == NULL || strcmp(netif,"") == 0)
strcpy(intname,"/tmp/vde.ctl");
else
strcpy(intname,netif);
fd=vde_alloc(intname,&fddata,&dataout);
if (fd < 0) {
BX_PANIC(("open failed on %s: %s", netif, strerror (errno)));
return;
}
/* set O_ASYNC flag so that we can poll with read() */
if ((flags = fcntl(fd, F_GETFL)) < 0) {
BX_PANIC(("getflags on vde device: %s", strerror (errno)));
}
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) {
BX_PANIC(("set vde device flags: %s", strerror (errno)));
}
BX_INFO(("eth_vde: opened %s device", netif));
/* Execute the configuration script */
if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0))
{
if (execute_script(this->netdev, script, intname) < 0)
BX_ERROR(("execute script '%s' on %s failed", script, intname));
}
// Start the rx poll
this->rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
1, 1, "eth_vde"); // continuous, active
this->rxh = rxh;
#if BX_ETH_VDE_LOGGING
// eventually Bryce wants txlog to dump in pcap format so that
// tcpdump -r FILE can read it and interpret packets.
txlog = fopen("ne2k-tx.log", "wb");
if (!txlog) BX_PANIC(("open ne2k-tx.log failed"));
txlog_txt = fopen("ne2k-txdump.txt", "wb");
if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed"));
fprintf(txlog_txt, "vde packetmover readable log file\n");
fprintf(txlog_txt, "net IF = %s\n", netif);
fprintf(txlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(txlog_txt, "\n--\n");
fflush(txlog_txt);
rxlog = fopen("ne2k-rx.log", "wb");
if (!rxlog) BX_PANIC(("open ne2k-rx.log failed"));
rxlog_txt = fopen("ne2k-rxdump.txt", "wb");
if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed"));
fprintf(rxlog_txt, "vde packetmover readable log file\n");
fprintf(rxlog_txt, "net IF = %s\n", netif);
fprintf(rxlog_txt, "MAC address = ");
for (int i=0; i<6; i++)
fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
fprintf(rxlog_txt, "\n--\n");
fflush(rxlog_txt);
#endif
}
void bx_vde_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
unsigned int size;
//size = write (fd, buf, io_len);
//size=send(fd,buf,io_len,0);
size=sendto(fddata,buf,io_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un));
if (size != io_len) {
BX_PANIC(("write on vde device: %s", strerror (errno)));
} else {
BX_INFO(("wrote %d bytes on vde", io_len));
}
#if BX_ETH_VDE_LOGGING
BX_DEBUG(("sendpkt length %u", io_len));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(buf, io_len, 1, txlog);
if (n != 1) BX_ERROR(("fwrite to txlog failed"));
// dump packet in hex into an ascii log file
write_pktlog_txt(txlog_txt, (const Bit8u *)buf, io_len, 0);
// flush log so that we see the packets as they arrive w/o buffering
fflush(txlog);
#endif
}
void bx_vde_pktmover_c::rx_timer_handler(void *this_ptr)
{
bx_vde_pktmover_c *class_ptr = (bx_vde_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void bx_vde_pktmover_c::rx_timer()
{
int nbytes;
Bit8u buf[BX_PACKET_BUFSIZE];
Bit8u *rxbuf;
struct sockaddr_un datain;
socklen_t datainsize;
if (fd<0) return;
//nbytes = read (fd, buf, sizeof(buf));
nbytes=recvfrom(fddata,buf,sizeof(buf),MSG_DONTWAIT|MSG_WAITALL,(struct sockaddr *) &datain, &datainsize);
rxbuf=buf;
if (nbytes>0)
BX_INFO(("vde read returned %d bytes", nbytes));
if (nbytes<0) {
if (errno != EAGAIN)
BX_ERROR(("vde read error: %s", strerror(errno)));
return;
}
#if BX_ETH_VDE_LOGGING
if (nbytes > 0) {
BX_DEBUG(("receive packet length %u", nbytes));
// dump raw bytes to a file, eventually dump in pcap format so that
// tcpdump -r FILE can interpret them for us.
int n = fwrite(rxbuf, nbytes, 1, rxlog);
if (n != 1) BX_ERROR(("fwrite to rxlog failed"));
// dump packet in hex into an ascii log file
write_pktlog_txt(rxlog_txt, rxbuf, nbytes, 1);
// flush log so that we see the packets as they arrive w/o buffering
fflush(rxlog);
}
#endif
BX_DEBUG(("eth_vde: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
if (nbytes < 60) {
BX_INFO(("packet too short (%d), padding to 60", nbytes));
nbytes = 60;
}
(*rxh)(this->netdev, rxbuf, nbytes);
}
//enum request_type { REQ_NEW_CONTROL };
#define REQ_NEW_CONTROL 0
struct request_v3 {
Bit32u magic;
Bit32u version;
//enum request_type type;
int type;
struct sockaddr_un sock;
};
static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int group)
{
int pid = getpid();
struct request_v3 req;
int fdctl;
struct sockaddr_un sock;
if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
return(-1);
}
sock.sun_family = AF_UNIX;
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))) {
perror("connect");
return(-1);
}
req.magic=SWITCH_MAGIC;
req.version=3;
req.type=((int)REQ_NEW_CONTROL)+((group > 0)?((geteuid()<<8) + group) << 8:0);
req.sock.sun_family=AF_UNIX;
memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
sprintf(&req.sock.sun_path[1], "%5d", pid);
if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0) {
perror("bind");
return(-1);
}
if (send(fdctl,&req,sizeof(req),0) < 0) {
perror("send");
return(-1);
}
if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0) < 0) {
perror("recv");
return(-1);
}
return fdctl;
}
int vde_alloc(char *dev, int *fdp, struct sockaddr_un *pdataout)
{
//struct ifreq ifr;
//int err;
int fd, fddata;
if ((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
return -1;
if ((fd = send_fd(dev, fddata, pdataout, 0)) < 0)
return -1;
//memset(&ifr, 0, sizeof(ifr));
*fdp=fddata;
return fd;
}
#endif /* if BX_NETWORKING && defined HAVE_VDE */

1422
bochs/iodev/eth_vnet.cc Normal file

File diff suppressed because it is too large Load Diff

386
bochs/iodev/eth_win32.cc Normal file
View File

@ -0,0 +1,386 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// eth_win32.cc - packet mover for win32
// All win32 coding by Don Becker <x-odus@iname.com>
// with patches from various sources
//
// Various networking docs:
// http://www.graphcomp.com/info/rfc/
// rfc0826: arp
// rfc0903: rarp
//
// For ethernet support under win32 to work, you must install WinPCap.
// Download it from http://netgroup-serv.polito.it/winpcap
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_NETWORKING && defined(ETH_WIN32)
#include "eth.h"
// windows.h included by bochs.h
#define LOG_THIS netdev->
#define BX_ETH_WIN32_LOGGING 0
#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
#define Packet_ALIGNMENT sizeof(int)
#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
typedef int bpf_int32;
typedef u_int bpf_u_int32;
/*
* The instruction encondings.
*/
/* instruction classes */
#define BPF_CLASS(code) ((code) & 0x07)
#define BPF_LD 0x00
#define BPF_LDX 0x01
#define BPF_ST 0x02
#define BPF_STX 0x03
#define BPF_ALU 0x04
#define BPF_JMP 0x05
#define BPF_RET 0x06
#define BPF_MISC 0x07
/* ld/ldx fields */
#define BPF_SIZE(code) ((code) & 0x18)
#define BPF_W 0x00
#define BPF_H 0x08
#define BPF_B 0x10
#define BPF_MODE(code) ((code) & 0xe0)
#define BPF_IMM 0x00
#define BPF_ABS 0x20
#define BPF_IND 0x40
#define BPF_MEM 0x60
#define BPF_LEN 0x80
#define BPF_MSH 0xa0
/* alu/jmp fields */
#define BPF_OP(code) ((code) & 0xf0)
#define BPF_ADD 0x00
#define BPF_SUB 0x10
#define BPF_MUL 0x20
#define BPF_DIV 0x30
#define BPF_OR 0x40
#define BPF_AND 0x50
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
#define BPF_JA 0x00
#define BPF_JEQ 0x10
#define BPF_JGT 0x20
#define BPF_JGE 0x30
#define BPF_JSET 0x40
#define BPF_SRC(code) ((code) & 0x08)
#define BPF_K 0x00
#define BPF_X 0x08
/* ret - BPF_K and BPF_X also apply */
#define BPF_RVAL(code) ((code) & 0x18)
#define BPF_A 0x10
/* misc */
#define BPF_MISCOP(code) ((code) & 0xf8)
#define BPF_TAX 0x00
#define BPF_TXA 0x80
#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
/*
* The instruction data structure.
*/
struct bpf_insn {
u_short code;
u_char jt;
u_char jf;
bpf_int32 k;
};
struct bpf_program {
u_int bf_len;
struct bpf_insn *bf_insns;
};
struct bpf_hdr {
struct timeval bh_tstamp; /* time stamp */
UINT bh_caplen; /* length of captured portion */
UINT bh_datalen; /* original length of packet */
USHORT bh_hdrlen; /* length of bpf header (this struct
plus alignment padding) */
};
#define MAX_LINK_NAME_LENGTH 64
// Why don't these definitions come from including winpcap.h or something?
// -Bryce
typedef struct _ADAPTER {
HANDLE hFile;
TCHAR SymbolicLink[MAX_LINK_NAME_LENGTH];
int NumWrites;
HANDLE ReadEvent;
UINT ReadTimeOut; // WARNING: maybe invalid before winpcap 2.2
} ADAPTER, *LPADAPTER;
typedef struct _PACKET {
HANDLE hEvent;
OVERLAPPED OverLapped;
PVOID Buffer;
UINT Length;
UINT ulBytesReceived;
BOOLEAN bIoComplete;
} PACKET, *LPPACKET;
HINSTANCE hPacket;
LPADAPTER lpAdapter = 0;
LPPACKET pkSend;
LPPACKET pkRecv;
char buffer[256000];
DWORD dwVersion, dwMajorVersion;
char AdapterList[10][1024];
char cMacAddr[6];
char NetDev[512];
BOOL IsNT = FALSE;
LPADAPTER (*PacketOpenAdapter) (LPTSTR);
VOID (*PacketCloseAdapter) (LPADAPTER);
BOOLEAN (*PacketSetHwFilter) (LPADAPTER, ULONG);
BOOLEAN (*PacketSetBpf) (LPADAPTER, struct bpf_program *);
BOOLEAN (*PacketGetAdapterNames) (PTSTR, PULONG);
BOOLEAN (*PacketSendPacket) (LPADAPTER, LPPACKET, BOOLEAN);
BOOLEAN (*PacketReceivePacket) (LPADAPTER, LPPACKET, BOOLEAN);
BOOLEAN (*PacketSetBuff) (LPADAPTER, int);
BOOLEAN (*PacketSetReadTimeout) (LPADAPTER, int);
LPPACKET (*PacketAllocatePacket) (void);
VOID (*PacketInitPacket) (LPPACKET, PVOID, UINT);
VOID (*PacketFreePacket) (LPPACKET);
// template filter for a unicast mac address and all
// multicast/broadcast frames
static const struct bpf_insn macfilter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
BPF_STMT(BPF_RET, 1514),
BPF_STMT(BPF_RET, 0),
};
//
// Define the class. This is private to this module
//
class bx_win32_pktmover_c : public eth_pktmover_c {
public:
bx_win32_pktmover_c(const char *netif, const char *macaddr,
eth_rx_handler_t rxh, bx_devmodel_c *dev,
const char *script);
void sendpkt(void *buf, unsigned io_len);
private:
struct bpf_insn filter[8];
int rx_timer_index;
static void rx_timer_handler(void *);
void rx_timer(void);
#if BX_ETH_WIN32_LOGGING
FILE *pktlog_txt;
#endif
};
//
// Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_win32_locator_c : public eth_locator_c {
public:
bx_win32_locator_c(void) : eth_locator_c("win32") {}
protected:
eth_pktmover_c *allocate(const char *netif, const char *macaddr,
eth_rx_handler_t rxh,
bx_devmodel_c *dev, const char *script) {
return (new bx_win32_pktmover_c(netif, macaddr, rxh, dev, script));
}
} bx_win32_match;
//
// Define the methods for the bx_win32_pktmover derived class
//
// the constructor
bx_win32_pktmover_c::bx_win32_pktmover_c(
const char *netif, const char *macaddr,
eth_rx_handler_t rxh, bx_devmodel_c *dev, const char *script)
{
this->netdev = dev;
BX_INFO(("win32 network driver"));
// Open Packet Driver Here.
DWORD dwVersion;
DWORD dwWindowsMajorVersion;
this->rxh = rxh;
hPacket = LoadLibrary("PACKET.DLL");
memcpy(cMacAddr, macaddr, 6);
if (hPacket) {
PacketOpenAdapter = (LPADAPTER (*)(LPTSTR)) GetProcAddress(hPacket, "PacketOpenAdapter");
PacketCloseAdapter = (VOID (*)(LPADAPTER)) GetProcAddress(hPacket, "PacketCloseAdapter");
PacketSetHwFilter = (BOOLEAN (*)(LPADAPTER, ULONG)) GetProcAddress(hPacket, "PacketSetHwFilter");
PacketSetBpf = (BOOLEAN (*)(LPADAPTER, struct bpf_program *)) GetProcAddress(hPacket, "PacketSetBpf");
PacketGetAdapterNames = (BOOLEAN (*)(PTSTR, PULONG)) GetProcAddress(hPacket, "PacketGetAdapterNames");
PacketSendPacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketSendPacket");
PacketReceivePacket = (BOOLEAN (*)(LPADAPTER, LPPACKET, BOOLEAN)) GetProcAddress(hPacket, "PacketReceivePacket");
PacketSetBuff = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetBuff");
PacketSetReadTimeout = (BOOLEAN (*)(LPADAPTER, int)) GetProcAddress(hPacket, "PacketSetReadTimeout");
PacketAllocatePacket = (LPPACKET (*)(void)) GetProcAddress(hPacket, "PacketAllocatePacket");
PacketInitPacket = (VOID (*)(LPPACKET, PVOID, UINT)) GetProcAddress(hPacket, "PacketInitPacket");
PacketFreePacket = (VOID (*)(LPPACKET)) GetProcAddress(hPacket, "PacketFreePacket");
} else {
BX_PANIC(("Could not load WPCap Drivers for ethernet support!"));
}
memset(&NetDev, 0, sizeof(NetDev));
dwVersion=GetVersion();
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4))
{ // Windows NT/2k
int nLen = MultiByteToWideChar(CP_ACP, 0, netif, -1, NULL, 0);
MultiByteToWideChar(CP_ACP, 0, netif, -1, (WCHAR *)NetDev, nLen);
IsNT = TRUE;
} else { // Win9x
strcpy(NetDev, netif);
}
lpAdapter = PacketOpenAdapter(NetDev);
if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE)) {
BX_PANIC(("Could not open adapter for ethernet reception"));
return;
}
PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_PROMISCUOUS);
/* The code below sets a BPF mac address filter
that seems to really kill performance, for now
im just using code to filter, and it works
better
*/
// memcpy(&this->filter, macfilter, sizeof(macfilter));
// this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 | (macaddr[4] & 0xff) << 8 | (macaddr[5] & 0xff);
// this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
// bp.bf_len = 8;
// bp.bf_insns = &this->filter[0];
// if (!PacketSetBpf(lpAdapter, &bp)) {
// BX_PANIC(("Could not set mac address BPF filter"));
// }
PacketSetBuff(lpAdapter, 512000);
PacketSetReadTimeout(lpAdapter, -1);
if ((pkSend = PacketAllocatePacket()) == NULL) {
BX_PANIC(("Could not allocate a send packet"));
}
if ((pkRecv = PacketAllocatePacket()) == NULL) {
BX_PANIC(("Could not allocate a recv packet"));
}
rx_timer_index =
bx_pc_system.register_timer(this, this->rx_timer_handler, 10000, 1, 1, "eth_win32");
#if BX_ETH_WIN32_LOGGING
pktlog_txt = fopen("ne2k-pktlog.txt", "wb");
if (!pktlog_txt) BX_PANIC(("ne2k-pktlog.txt failed"));
fprintf(pktlog_txt, "win32 packetmover readable log file\n");
fprintf(pktlog_txt, "host adapter = %s\n", netif);
fprintf(pktlog_txt, "guest MAC address = ");
int i;
for (i=0; i<6; i++)
fprintf(pktlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "\n");
fprintf(pktlog_txt, "--\n");
fflush(pktlog_txt);
#endif
}
void bx_win32_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#if BX_ETH_WIN32_LOGGING
write_pktlog_txt(pktlog_txt, (const Bit8u *)buf, io_len, 0);
#endif
// SendPacket Here.
PacketInitPacket(pkSend, (char *)buf, io_len);
if (!PacketSendPacket(lpAdapter, pkSend, TRUE)) {
fprintf(stderr, "[ETH-WIN32] Error sending packet: %lu\n", GetLastError());
}
}
void bx_win32_pktmover_c::rx_timer_handler (void *this_ptr)
{
bx_win32_pktmover_c *class_ptr = (bx_win32_pktmover_c *) this_ptr;
class_ptr->rx_timer();
}
void bx_win32_pktmover_c::rx_timer(void)
{
// Recieve Packet ????
char *pBuf;
unsigned char *pPacket;
unsigned int iOffset = 0;
struct bpf_hdr *hdr;
int pktlen;
PacketInitPacket(pkRecv, (char *)buffer, 256000);
if (WaitForSingleObject(lpAdapter->ReadEvent,0) == WAIT_OBJECT_0 || IsNT) {
PacketReceivePacket(lpAdapter, pkRecv, TRUE);
pBuf = (char *)pkRecv->Buffer;
iOffset = 0;
while(iOffset < pkRecv->ulBytesReceived)
{
hdr = (struct bpf_hdr *)(pBuf + iOffset);
pPacket = (unsigned char *)(pBuf + iOffset + hdr->bh_hdrlen);
if (memcmp(pPacket + 6, cMacAddr, 6) != 0) // src field != ours
{
if(memcmp(pPacket, cMacAddr, 6) == 0 || memcmp(pPacket, broadcast_macaddr, 6) == 0)
{
pktlen = hdr->bh_caplen;
if (pktlen < 60) pktlen = 60;
#if BX_ETH_WIN32_LOGGING
write_pktlog_txt(pktlog_txt, pPacket, pktlen, 1);
#endif
(*this->rxh)(this->netdev, pPacket, pktlen);
}
}
iOffset = Packet_WORDALIGN(iOffset + (hdr->bh_hdrlen + hdr->bh_caplen));
}
}
}
#endif /* if BX_NETWORKING && defined ETH_WIN32 */

90
bochs/iodev/extfpuirq.cc Normal file
View File

@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// External circuit for MSDOS compatible FPU exceptions
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "extfpuirq.h"
#define LOG_THIS theExternalFpuIrq->
bx_extfpuirq_c *theExternalFpuIrq = NULL;
int libextfpuirq_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theExternalFpuIrq = new bx_extfpuirq_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theExternalFpuIrq, BX_PLUGIN_EXTFPUIRQ);
return(0); // Success
}
void libextfpuirq_LTX_plugin_fini(void)
{
delete theExternalFpuIrq;
}
bx_extfpuirq_c::bx_extfpuirq_c(void)
{
put("EFIRQ");
}
bx_extfpuirq_c::~bx_extfpuirq_c(void)
{
BX_DEBUG(("Exit"));
}
void bx_extfpuirq_c::init(void)
{
// called once when bochs initializes
DEV_register_iowrite_handler(this, write_handler, 0x00F0, "External FPU IRQ", 1);
DEV_register_irq(13, "External FPU IRQ");
}
void bx_extfpuirq_c::reset(unsigned type)
{
// We should handle IGNNE here
DEV_pic_lower_irq(13);
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_extfpuirq_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_EFI_SMF
bx_extfpuirq_c *class_ptr = (bx_extfpuirq_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_extfpuirq_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_EFI_SMF
// We should handle IGNNE here
DEV_pic_lower_irq(13);
}

50
bochs/iodev/extfpuirq.h Normal file
View File

@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_EXTFPUIRQ_H
#define BX_IODEV_EXTFPUIRQ_H
#if BX_USE_EFI_SMF
# define BX_EXTFPUIRQ_SMF static
# define BX_EXTFPUIRQ_THIS theExternalFpuIrq->
#else
# define BX_EXTFPUIRQ_SMF
# define BX_EXTFPUIRQ_THIS this->
#endif
class bx_extfpuirq_c : public bx_devmodel_c {
public:
bx_extfpuirq_c();
virtual ~bx_extfpuirq_c();
virtual void init(void);
virtual void reset(unsigned type);
private:
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_EFI_SMF
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

1983
bochs/iodev/floppy.cc Normal file

File diff suppressed because it is too large Load Diff

201
bochs/iodev/floppy.h Normal file
View File

@ -0,0 +1,201 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_FLOPPY_H
#define BX_IODEV_FLOPPY_H
#define FROM_FLOPPY 10
#define TO_FLOPPY 11
#if BX_USE_FD_SMF
# define BX_FD_SMF static
# define BX_FD_THIS theFloppyController->
#else
# define BX_FD_SMF
# define BX_FD_THIS this->
#endif
typedef struct {
int fd; /* file descriptor of floppy image file */
unsigned sectors_per_track; /* number of sectors/track */
unsigned sectors; /* number of formatted sectors on diskette */
unsigned tracks; /* number of tracks */
unsigned heads; /* number of heads */
unsigned type;
unsigned write_protected;
unsigned char raw_floppy_win95;
#ifdef WIN32
unsigned char raw_floppy_win95_drv;
#endif
bx_bool vvfat_floppy;
device_image_t *vvfat;
} floppy_t;
class bx_floppy_ctrl_c : public bx_floppy_stub_c {
public:
bx_floppy_ctrl_c();
virtual ~bx_floppy_ctrl_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual unsigned set_media_status(unsigned drive, bx_bool status);
virtual void register_state(void);
private:
struct {
Bit8u data_rate;
Bit8u command[10]; /* largest command size ??? */
Bit8u command_index;
Bit8u command_size;
bx_bool command_complete;
Bit8u pending_command;
bx_bool multi_track;
bx_bool pending_irq;
Bit8u reset_sensei;
Bit8u format_count;
Bit8u format_fillbyte;
Bit8u result[10];
Bit8u result_index;
Bit8u result_size;
Bit8u DOR; // Digital Ouput Register
Bit8u TDR; // Tape Drive Register
Bit8u cylinder[4]; // really only using 2 drives
Bit8u head[4]; // really only using 2 drives
Bit8u sector[4]; // really only using 2 drives
Bit8u eot[4]; // really only using 2 drives
bx_bool TC; // Terminal Count status from DMA controller
/* MAIN STATUS REGISTER
* b7: MRQ: main request 1=data register ready 0=data register not ready
* b6: DIO: data input/output:
* 1=controller->CPU (ready for data read)
* 0=CPU->controller (ready for data write)
* b5: NDMA: non-DMA mode: 1=controller not in DMA modes
* 0=controller in DMA mode
* b4: BUSY: instruction(device busy) 1=active 0=not active
* b3-0: ACTD, ACTC, ACTB, ACTA:
* drive D,C,B,A in positioning mode 1=active 0=not active
*/
Bit8u main_status_reg;
Bit8u status_reg0;
Bit8u status_reg1;
Bit8u status_reg2;
Bit8u status_reg3;
// drive field allows up to 4 drives, even though probably only 2 will
// ever be used.
floppy_t media[4];
unsigned num_supported_floppies;
Bit8u floppy_buffer[512+2]; // 2 extra for good measure
unsigned floppy_buffer_index;
int floppy_timer_index;
bx_bool media_present[4];
Bit8u device_type[4];
Bit8u DIR[4]; // Digital Input Register:
// b7: 0=diskette is present and has not been changed
// 1=diskette missing or changed
bx_bool lock; // FDC lock status
Bit8u SRT; // step rate time
Bit8u HUT; // head unload time
Bit8u HLT; // head load time
Bit8u config; // configure byte #1
Bit8u pretrk; // precompensation track
Bit8u perp_mode; // perpendicular mode
int statusbar_id[2]; // IDs of the status LEDs
} s; // state information
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_FD_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
BX_FD_SMF void dma_write(Bit8u *data_byte);
BX_FD_SMF void dma_read(Bit8u *data_byte);
BX_FD_SMF void floppy_command(void);
BX_FD_SMF void floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
BX_FD_SMF void raise_interrupt(void);
BX_FD_SMF void lower_interrupt(void);
BX_FD_SMF void enter_idle_phase(void);
BX_FD_SMF void enter_result_phase(void);
BX_FD_SMF Bit32u calculate_step_delay(Bit8u drive, Bit8u new_cylinder);
BX_FD_SMF void reset_changeline(void);
BX_FD_SMF bx_bool get_tc(void);
static void timer_handler(void *);
BX_FD_SMF void timer(void);
BX_FD_SMF void increment_sector(void);
BX_FD_SMF bx_bool evaluate_media(Bit8u devtype, Bit8u type, char *path, floppy_t *media);
BX_FD_SMF void close_media(floppy_t *media);
// runtime options
static Bit64s floppy_param_handler(bx_param_c *param, int set, Bit64s val);
static const char* floppy_param_string_handler(bx_param_string_c *param, int set, const char *oldval, const char *val, int maxlen);
};
#ifdef WIN32
// used for direct floppy access in Win95
#define VWIN32_DIOC_DOS_IOCTL 1
#define VWIN32_DIOC_DOS_INT25 2
#define VWIN32_DIOC_DOS_INT26 3
typedef struct _DIOC_REGISTERS {
DWORD reg_EBX;
DWORD reg_EDX;
DWORD reg_ECX;
DWORD reg_EAX;
DWORD reg_EDI;
DWORD reg_ESI;
DWORD reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;
#pragma pack(push, 1)
typedef struct _BLOCK_DEV_PARAMS {
BYTE features;
BYTE dev_type;
WORD attribs;
WORD cylinders;
BYTE media_type;
// BPB
WORD bytes_per_sector;
BYTE sect_per_cluster;
WORD reserved_sectors;
BYTE fats;
WORD root_entries;
WORD tot_sectors;
BYTE media_id;
WORD sects_per_fat;
WORD sects_per_track;
WORD num_heads;
WORD hidden_sectors;
BYTE remainder[5];
} BLOCK_DEV_PARAMS, *PBLOCK_DEV_PARAMS;
#pragma pack(pop)
#endif /* WIN32 */
#endif

234
bochs/iodev/gameport.cc Normal file
View File

@ -0,0 +1,234 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Standard PC gameport
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "gameport.h"
#ifdef __linux__
#include <linux/joystick.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#elif defined(WIN32)
#ifndef JOY_BUTTON1
#define JOY_BUTTON1 1
#define JOY_BUTTON2 2
UINT STDCALL joyGetPos(UINT, LPJOYINFO);
#endif
#define JOYSTICKID1 0
#endif
#define LOG_THIS theGameport->
bx_gameport_c *theGameport = NULL;
int libgameport_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theGameport = new bx_gameport_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theGameport, BX_PLUGIN_GAMEPORT);
return(0); // Success
}
void libgameport_LTX_plugin_fini(void)
{
delete theGameport;
}
bx_gameport_c::bx_gameport_c()
{
put("GAME");
joyfd = -1;
}
bx_gameport_c::~bx_gameport_c()
{
if (joyfd >= 0) close(joyfd);
BX_DEBUG(("Exit"));
}
void bx_gameport_c::init(void)
{
// Allocate the gameport IO address range 0x200..0x207
for (unsigned addr=0x200; addr<0x208; addr++) {
DEV_register_ioread_handler(this, read_handler, addr, "Gameport", 1);
DEV_register_iowrite_handler(this, write_handler, addr, "Gameport", 1);
}
BX_GAMEPORT_THIS port = 0xf0;
BX_GAMEPORT_THIS write_usec = 0;
BX_GAMEPORT_THIS timer_x = 0;
BX_GAMEPORT_THIS timer_y = 0;
#ifdef __linux__
BX_GAMEPORT_THIS joyfd = open("/dev/input/js0", O_RDONLY);
if (BX_GAMEPORT_THIS joyfd >= 0) {
for (unsigned i=0; i<4; i++) poll_joydev();
}
#elif defined(WIN32)
JOYINFO joypos;
if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
BX_GAMEPORT_THIS joyfd = 1;
} else {
BX_GAMEPORT_THIS joyfd = -1;
}
#else
BX_GAMEPORT_THIS joyfd = -1;
#endif
}
void bx_gameport_c::reset(unsigned type)
{
// nothing for now
}
void bx_gameport_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "gameport", "Gameport State", 6);
BXRS_HEX_PARAM_FIELD(list, port, BX_GAMEPORT_THIS port);
BXRS_DEC_PARAM_FIELD(list, delay_x, BX_GAMEPORT_THIS delay_x);
BXRS_DEC_PARAM_FIELD(list, delay_y, BX_GAMEPORT_THIS delay_y);
BXRS_PARAM_BOOL(list, timer_x, BX_GAMEPORT_THIS timer_x);
BXRS_PARAM_BOOL(list, timer_y, BX_GAMEPORT_THIS timer_y);
BXRS_DEC_PARAM_FIELD(list, write_usec, BX_GAMEPORT_THIS write_usec);
}
void bx_gameport_c::poll_joydev(void)
{
#ifdef __linux__
struct js_event e;
fd_set joyfds;
struct timeval tv;
memset(&tv, 0, sizeof(tv));
FD_ZERO(&joyfds);
FD_SET(BX_GAMEPORT_THIS joyfd, &joyfds);
e.type = 0;
if (select(BX_GAMEPORT_THIS joyfd+1, &joyfds, NULL, NULL, &tv)) {
read(BX_GAMEPORT_THIS joyfd, &e, sizeof(struct js_event));
if (e.type & JS_EVENT_BUTTON) {
if (e.value == 1) {
BX_GAMEPORT_THIS port &= ~(0x10 << e.number);
} else {
BX_GAMEPORT_THIS port |= (0x10 << e.number);
}
}
if (e.type & JS_EVENT_AXIS) {
if (e.number == 0) {
BX_GAMEPORT_THIS delay_x = 25 + ((e.value + 0x8000) / 60);
}
if (e.number == 1) {
BX_GAMEPORT_THIS delay_y = 25 + ((e.value + 0x8000) / 62);
}
}
}
#elif defined(WIN32)
JOYINFO joypos;
if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
if (joypos.wButtons & JOY_BUTTON1) {
BX_GAMEPORT_THIS port &= ~0x10;
} else {
BX_GAMEPORT_THIS port |= 0x10;
}
if (joypos.wButtons & JOY_BUTTON2) {
BX_GAMEPORT_THIS port &= ~0x20;
} else {
BX_GAMEPORT_THIS port |= 0x20;
}
BX_GAMEPORT_THIS delay_x = 25 + (joypos.wXpos / 60);
BX_GAMEPORT_THIS delay_y = 25 + (joypos.wYpos / 60);
}
#endif
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_gameport_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_GAMEPORT_SMF
bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_gameport_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_GAMEPORT_SMF
Bit64u usec;
if (BX_GAMEPORT_THIS joyfd >= 0) {
poll_joydev();
usec = bx_pc_system.time_usec();
if (BX_GAMEPORT_THIS timer_x) {
if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_x) {
BX_GAMEPORT_THIS port &= 0xfe;
BX_GAMEPORT_THIS timer_x = 0;
}
}
if (BX_GAMEPORT_THIS timer_y) {
if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_y) {
BX_GAMEPORT_THIS port &= 0xfd;
BX_GAMEPORT_THIS timer_y = 0;
}
}
} else {
BX_DEBUG(("read: joystick not present"));
}
return BX_GAMEPORT_THIS port;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_gameport_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_GAMEPORT_SMF
bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_gameport_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_GAMEPORT_SMF
BX_GAMEPORT_THIS write_usec = bx_pc_system.time_usec();
BX_GAMEPORT_THIS timer_x = 1;
BX_GAMEPORT_THIS timer_y = 1;
BX_GAMEPORT_THIS port |= 0x0f;
}

62
bochs/iodev/gameport.h Normal file
View File

@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_GAMEPORT_H
#define BX_IODEV_GAMEPORT_H
#if BX_USE_GAMEPORT_SMF
# define BX_GAMEPORT_SMF static
# define BX_GAMEPORT_THIS theGameport->
#else
# define BX_GAMEPORT_SMF
# define BX_GAMEPORT_THIS this->
#endif
class bx_gameport_c : public bx_devmodel_c {
public:
bx_gameport_c();
virtual ~bx_gameport_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
private:
int joyfd;
Bit8u port;
Bit16u delay_x;
Bit16u delay_y;
bx_bool timer_x;
bx_bool timer_y;
Bit64u write_usec;
BX_GAMEPORT_SMF void poll_joydev(void);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_GAMEPORT_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

135
bochs/iodev/guest2host.cc Normal file
View File

@ -0,0 +1,135 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#include "iodev.h"
#include "guest2host.h"
#define LOG_THIS bx_g2h.
bx_g2h_c bx_g2h;
bx_g2h_c::bx_g2h_c()
{
put("G2H");
unsigned i;
for (i=0; i<BX_MAX_G2H_CHANNELS; i++) {
s.callback[i].f = NULL;
s.callback[i].used = 0;
}
}
bx_g2h_c::~bx_g2h_c()
{
// nothing for now
}
void bx_g2h_c::init(void)
{
BX_DEBUG(("Init $Id$"));
// Reserve a dword port for this interface
for (Bit32u addr=BX_G2H_PORT; addr<=(BX_G2H_PORT+3); addr++) {
bx_devices.register_io_read_handler(&bx_g2h,
inp_handler, addr, "g2h");
bx_devices.register_io_write_handler(&bx_g2h,
outp_handler, addr, "g2h");
}
memset(&bx_g2h.s, 0, sizeof(bx_g2h.s));
}
void bx_g2h_c::reset(unsigned type)
{
}
unsigned bx_g2h_c::acquire_channel(bx_g2h_callback_t f)
{
unsigned i;
for (i=0; i<BX_MAX_G2H_CHANNELS; i++) {
if (bx_g2h.s.callback[i].used==0) {
bx_g2h.s.callback[i].f = f;
bx_g2h.s.callback[i].used = 1;
return(i);
}
}
BX_INFO(("g2h: attempt to acquire channel: maxed out"));
return BX_G2H_ERROR; // No more free channels
}
unsigned bx_g2h_c::deacquire_channel(unsigned channel)
{
if ((channel >= BX_MAX_G2H_CHANNELS) ||
(bx_g2h.s.callback[channel].used==0))
{
BX_PANIC(("g2h: attempt to deacquire channel %u: not acquired", channel));
}
bx_g2h.s.callback[channel].used = 0;
bx_g2h.s.callback[channel].f = NULL;
return 0;
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_g2h_c::inp_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
UNUSED(this_ptr);
if (addr != BX_G2H_PORT)
BX_PANIC(("g2h: IO read not aligned on dword boundary."));
if (io_len != 4)
BX_PANIC(("g2h: IO read not dword."));
BX_PANIC(("g2h: IO read not complete."));
return(0);
}
void bx_g2h_c::outp_handler(void *this_ptr, Bit32u addr, Bit32u val32, unsigned io_len)
{
UNUSED(this_ptr);
if (addr != BX_G2H_PORT)
BX_PANIC(("g2h: IO write not aligned on dword boundary."));
if (io_len != 4)
BX_PANIC(("g2h: IO write not dword."));
if ((bx_g2h.s.packet_count==0) && (val32!=BX_G2H_MAGIC)) {
BX_INFO(("g2h: IO W: Not magic header."));
return;
}
bx_g2h.s.guest_packet[bx_g2h.s.packet_count++] = val32;
if (bx_g2h.s.packet_count >= BX_G2H_PACKET_SIZE) {
unsigned channel;
// Full packet received from guest. Pass on to the host code.
channel = bx_g2h.s.guest_packet[1];
if (channel >= BX_MAX_G2H_CHANNELS) {
BX_PANIC(("g2h: channel (%u) out of bounds", channel));
}
if (bx_g2h.s.callback[channel].used==0) {
BX_PANIC(("g2h: channel (%u) not active", channel));
}
bx_g2h.s.callback[channel].f(&bx_g2h.s.guest_packet);
bx_g2h.s.packet_count = 0; // Ready for next packet
}
}

68
bochs/iodev/guest2host.h Normal file
View File

@ -0,0 +1,68 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#define BX_MAX_G2H_CHANNELS 8
#define BX_G2H_ERROR ((unsigned) -1)
// IO port number for this interface. Align on dword boundary.
#define BX_G2H_PORT 0x2000
// Magic number which is first dword passed by guest
#define BX_G2H_MAGIC 0xffeeddcc
// Number of dwords in packet from guest
#define BX_G2H_PACKET_SIZE 5
typedef Bit32u bx_guest_packet_t[BX_G2H_PACKET_SIZE];
typedef void (*bx_g2h_callback_t)(bx_guest_packet_t *);
class bx_g2h_c : public logfunctions {
public:
bx_g2h_c();
virtual ~bx_g2h_c();
static void init(void);
void reset(unsigned type);
unsigned acquire_channel(bx_g2h_callback_t);
unsigned deacquire_channel(unsigned channel);
private:
static Bit32u inp_handler(void *this_ptr, Bit32u addr, unsigned io_len);
static void outp_handler(void *this_ptr, Bit32u addr,
Bit32u value, unsigned io_len);
// state info
struct {
struct {
bx_g2h_callback_t f;
bx_bool used;
} callback[BX_MAX_G2H_CHANNELS];
// Define the data received from the guest OS.
// dword0: magic number, should be BX_G2H_MAGIC
// dword1: channel ID
// dword2: address of data structure in guest physical memory
// dword3: size of data structure in guest physical memory
// dword4: address of return data structure in guest physical memory
unsigned packet_count;
bx_guest_packet_t guest_packet;
} s;
};
extern bx_g2h_c bx_g2h;

3462
bochs/iodev/harddrv.cc Normal file

File diff suppressed because it is too large Load Diff

258
bochs/iodev/harddrv.h Normal file
View File

@ -0,0 +1,258 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2010 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_HDDRIVE_H
#define BX_IODEV_HDDRIVE_H
#define MAX_MULTIPLE_SECTORS 16
typedef enum _sense {
SENSE_NONE = 0, SENSE_NOT_READY = 2, SENSE_ILLEGAL_REQUEST = 5,
SENSE_UNIT_ATTENTION = 6
} sense_t;
typedef enum _asc {
ASC_ILLEGAL_OPCODE = 0x20,
ASC_LOGICAL_BLOCK_OOR = 0x21,
ASC_INV_FIELD_IN_CMD_PACKET = 0x24,
ASC_MEDIUM_MAY_HAVE_CHANGED = 0x28,
ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
ASC_MEDIUM_NOT_PRESENT = 0x3a
} asc_t;
class device_image_t;
class LOWLEVEL_CDROM;
typedef struct {
struct {
bx_bool busy;
bx_bool drive_ready;
bx_bool write_fault;
bx_bool seek_complete;
bx_bool drq;
bx_bool corrected_data;
bx_bool index_pulse;
unsigned index_pulse_count;
bx_bool err;
} status;
Bit8u error_register;
Bit8u head_no;
union {
Bit8u sector_count;
struct {
#ifdef BX_LITTLE_ENDIAN
unsigned c_d : 1;
unsigned i_o : 1;
unsigned rel : 1;
unsigned tag : 5;
#else /* BX_BIG_ENDIAN */
unsigned tag : 5;
unsigned rel : 1;
unsigned i_o : 1;
unsigned c_d : 1;
#endif
} interrupt_reason;
};
Bit8u sector_no;
union {
Bit16u cylinder_no;
Bit16u byte_count;
};
Bit8u buffer[MAX_MULTIPLE_SECTORS*512 + 4];
Bit32u buffer_size;
Bit32u buffer_index;
Bit32u drq_index;
Bit8u current_command;
Bit8u multiple_sectors;
Bit8u lba_mode;
bx_bool packet_dma;
Bit8u mdma_mode;
Bit8u udma_mode;
struct {
bx_bool reset; // 0=normal, 1=reset controller
bx_bool disable_irq; // 0=allow irq, 1=disable irq
} control;
Bit8u reset_in_progress;
Bit8u features;
struct {
Bit8u feature;
Bit8u nsector;
Bit8u sector;
Bit8u lcyl;
Bit8u hcyl;
} hob;
Bit32u num_sectors;
bx_bool lba48;
} controller_t;
struct sense_info_t {
sense_t sense_key;
struct {
Bit8u arr[4];
} information;
struct {
Bit8u arr[4];
} specific_inf;
struct {
Bit8u arr[3];
} key_spec;
Bit8u fruc;
Bit8u asc;
Bit8u ascq;
};
struct error_recovery_t {
unsigned char data[8];
error_recovery_t ();
};
Bit16u read_16bit(const Bit8u* buf) BX_CPP_AttrRegparmN(1);
Bit32u read_32bit(const Bit8u* buf) BX_CPP_AttrRegparmN(1);
struct cdrom_t
{
bx_bool ready;
bx_bool locked;
#ifdef LOWLEVEL_CDROM
LOWLEVEL_CDROM* cd;
#endif
Bit32u capacity;
int next_lba;
int remaining_blocks;
struct currentStruct {
error_recovery_t error_recovery;
} current;
};
struct atapi_t
{
Bit8u command;
int drq_bytes;
int total_bytes_remaining;
};
#if BX_USE_HD_SMF
# define BX_HD_SMF static
# define BX_HD_THIS theHardDrive->
#else
# define BX_HD_SMF
# define BX_HD_THIS this->
#endif
typedef enum {
IDE_NONE, IDE_DISK, IDE_CDROM
} device_type_t;
class bx_hard_drive_c : public bx_hard_drive_stub_c {
public:
bx_hard_drive_c();
virtual ~bx_hard_drive_c();
virtual void init();
virtual void reset(unsigned type);
virtual Bit32u get_device_handle(Bit8u channel, Bit8u device);
virtual Bit32u get_first_cd_handle(void);
virtual unsigned get_cd_media_status(Bit32u handle);
virtual unsigned set_cd_media_status(Bit32u handle, unsigned status);
#if BX_SUPPORT_PCI
virtual bx_bool bmdma_read_sector(Bit8u channel, Bit8u *buffer, Bit32u *sector_size);
virtual bx_bool bmdma_write_sector(Bit8u channel, Bit8u *buffer);
virtual void bmdma_complete(Bit8u channel);
#endif
virtual void register_state(void);
virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len)
{
return read_handler(this, address, io_len);
}
virtual void virt_write_handler(Bit32u address, Bit32u value, unsigned io_len)
{
write_handler(this, address, value, io_len);
}
#if !BX_USE_HD_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
static void iolight_timer_handler(void *);
BX_HD_SMF void iolight_timer(void);
private:
BX_HD_SMF bx_bool calculate_logical_address(Bit8u channel, Bit64s *sector) BX_CPP_AttrRegparmN(2);
BX_HD_SMF void increment_address(Bit8u channel) BX_CPP_AttrRegparmN(1);
BX_HD_SMF void identify_drive(Bit8u channel);
BX_HD_SMF void identify_ATAPI_drive(Bit8u channel);
BX_HD_SMF void command_aborted(Bit8u channel, unsigned command);
BX_HD_SMF void init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bx_bool lazy = 0);
BX_HD_SMF void ready_to_send_atapi(Bit8u channel) BX_CPP_AttrRegparmN(1);
BX_HD_SMF void raise_interrupt(Bit8u channel) BX_CPP_AttrRegparmN(1);
BX_HD_SMF void atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc, bx_bool show);
BX_HD_SMF void init_mode_sense_single(Bit8u channel, const void* src, int size);
BX_HD_SMF void atapi_cmd_nop(Bit8u channel) BX_CPP_AttrRegparmN(1);
BX_HD_SMF bx_bool bmdma_present(void);
BX_HD_SMF void set_signature(Bit8u channel, Bit8u id);
BX_HD_SMF bx_bool ide_read_sector(Bit8u channel, Bit8u *buffer, Bit32u buffer_size);
BX_HD_SMF bx_bool ide_write_sector(Bit8u channel, Bit8u *buffer, Bit32u buffer_size);
BX_HD_SMF void lba48_transform(Bit8u channel, bx_bool lba48);
// FIXME:
// For each ATA channel we should have one controller struct
// and an array of two drive structs
struct channel_t {
struct drive_t {
device_image_t* hdimage;
device_type_t device_type;
// 512 byte buffer for ID drive command
// These words are stored in native word endian format, as
// they are fetched and returned via a return(), so
// there's no need to keep them in x86 endian format.
Bit16u id_drive[256];
bx_bool identify_set;
controller_t controller;
cdrom_t cdrom;
sense_info_t sense;
atapi_t atapi;
Bit8u model_no[41];
int statusbar_id;
int iolight_counter;
Bit8u device_num; // for ATAPI identify & inquiry
} drives[2];
unsigned drive_select;
Bit16u ioaddr1;
Bit16u ioaddr2;
Bit8u irq;
} channels[BX_MAX_ATA_CHANNEL];
int iolight_timer_index;
Bit8u cdrom_count;
};
#endif

1897
bochs/iodev/hdimage.cc Normal file

File diff suppressed because it is too large Load Diff

590
bochs/iodev/hdimage.h Normal file
View File

@ -0,0 +1,590 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2005-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_HDIMAGE_H
#define BX_HDIMAGE_H
// hdimage capabilities
#define HDIMAGE_READONLY 1
#define HDIMAGE_HAS_GEOMETRY 2
#define HDIMAGE_AUTO_GEOMETRY 4
// SPARSE IMAGES HEADER
#define SPARSE_HEADER_MAGIC (0x02468ace)
#define SPARSE_HEADER_VERSION 2
#define SPARSE_HEADER_V1 1
#define SPARSE_HEADER_SIZE (256) // Plenty of room for later
#define SPARSE_PAGE_NOT_ALLOCATED (0xffffffff)
typedef struct
{
Bit32u magic;
Bit32u version;
Bit32u pagesize;
Bit32u numpages;
Bit64u disk;
Bit32u padding[58];
} sparse_header_t;
#define STANDARD_HEADER_MAGIC "Bochs Virtual HD Image"
#define STANDARD_HEADER_V1 (0x00010000)
#define STANDARD_HEADER_VERSION (0x00020000)
#define STANDARD_HEADER_SIZE (512)
// WARNING : headers are kept in x86 (little) endianness
typedef struct
{
Bit8u magic[32];
Bit8u type[16];
Bit8u subtype[16];
Bit32u version;
Bit32u header;
} standard_header_t;
#define REDOLOG_TYPE "Redolog"
#define REDOLOG_SUBTYPE_UNDOABLE "Undoable"
#define REDOLOG_SUBTYPE_VOLATILE "Volatile"
#define REDOLOG_SUBTYPE_GROWING "Growing"
// #define REDOLOG_SUBTYPE_Z_UNDOABLE "z-Undoable"
// #define REDOLOG_SUBTYPE_Z_VOLATILE "z-Volatile"
#define REDOLOG_PAGE_NOT_ALLOCATED (0xffffffff)
#define UNDOABLE_REDOLOG_EXTENSION ".redolog"
#define UNDOABLE_REDOLOG_EXTENSION_LENGTH (strlen(UNDOABLE_REDOLOG_EXTENSION))
#define VOLATILE_REDOLOG_EXTENSION ".XXXXXX"
#define VOLATILE_REDOLOG_EXTENSION_LENGTH (strlen(VOLATILE_REDOLOG_EXTENSION))
typedef struct
{
// the fields in the header are kept in little endian
Bit32u catalog; // #entries in the catalog
Bit32u bitmap; // bitmap size in bytes
Bit32u extent; // extent size in bytes
Bit32u reserved; // for data alignment
Bit64u disk; // disk size in bytes
} redolog_specific_header_t;
typedef struct
{
// the fields in the header are kept in little endian
Bit32u catalog; // #entries in the catalog
Bit32u bitmap; // bitmap size in bytes
Bit32u extent; // extent size in bytes
Bit64u disk; // disk size in bytes
} redolog_specific_header_v1_t;
typedef struct
{
standard_header_t standard;
redolog_specific_header_t specific;
Bit8u padding[STANDARD_HEADER_SIZE - (sizeof (standard_header_t) + sizeof (redolog_specific_header_t))];
} redolog_header_t;
typedef struct
{
standard_header_t standard;
redolog_specific_header_v1_t specific;
Bit8u padding[STANDARD_HEADER_SIZE - (sizeof (standard_header_t) + sizeof (redolog_specific_header_v1_t))];
} redolog_header_v1_t;
// htod : convert host to disk (little) endianness
// dtoh : convert disk (little) to host endianness
#if defined (BX_LITTLE_ENDIAN)
#define htod32(val) (val)
#define dtoh32(val) (val)
#define htod64(val) (val)
#define dtoh64(val) (val)
#else
#define htod32(val) ( (((val)&0xff000000)>>24) | (((val)&0xff0000)>>8) | (((val)&0xff00)<<8) | (((val)&0xff)<<24) )
#define dtoh32(val) htod32(val)
#define htod64(val) ( (((val)&0xff00000000000000LL)>>56) | (((val)&0xff000000000000LL)>>40) | (((val)&0xff0000000000LL)>>24) | (((val)&0xff00000000LL)>>8) | (((val)&0xff000000LL)<<8) | (((val)&0xff0000LL)<<24) | (((val)&0xff00LL)<<40) | (((val)&0xffLL)<<56) )
#define dtoh64(val) htod64(val)
#endif
#ifndef HDIMAGE_HEADERS_ONLY
class device_image_t
{
public:
// Default constructor
device_image_t();
virtual ~device_image_t() {}
// Open a image. Returns non-negative if successful.
virtual int open(const char* pathname) = 0;
// Close the image.
virtual void close() = 0;
// Position ourselves. Return the resulting offset from the
// beginning of the file.
virtual Bit64s lseek(Bit64s offset, int whence) = 0;
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
virtual ssize_t read(void* buf, size_t count) = 0;
// Write count bytes from buf. Return the number of bytes
// written (count).
virtual ssize_t write(const void* buf, size_t count) = 0;
// Get image capabilities
virtual Bit32u get_capabilities();
unsigned cylinders;
unsigned heads;
unsigned sectors;
Bit64u hd_size;
};
// FLAT MODE
class default_image_t : public device_image_t
{
public:
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Open an image with specific flags. Returns non-negative if successful.
int open(const char* pathname, int flags);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
int fd;
};
// CONCAT MODE
class concat_image_t : public device_image_t
{
public:
// Default constructor
concat_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
#define BX_CONCAT_MAX_IMAGES 8
int fd_table[BX_CONCAT_MAX_IMAGES];
Bit64s start_offset_table[BX_CONCAT_MAX_IMAGES];
Bit64s length_table[BX_CONCAT_MAX_IMAGES];
void increment_string(char *str);
int maxfd; // number of entries in tables that are valid
// notice if anyone does sequential read or write without seek in between.
// This can be supported pretty easily, but needs additional checks.
// 0=something other than seek was last operation
// 1=seek was last operation
int seek_was_last_op;
// the following variables tell which partial image file to use for
// the next read and write.
int index; // index into table
int fd; // fd to use for reads and writes
Bit64s thismin, thismax; // byte offset boundary of this image
};
// SPARSE MODE
class sparse_image_t : public device_image_t
{
// Format of a sparse file:
// 256 byte header, containing details such as page size and number of pages
// Page indirection table, mapping virtual pages to physical pages within file
// Physical pages till end of file
public:
// Default constructor
sparse_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
int fd;
#ifdef _POSIX_MAPPED_FILES
void * mmap_header;
size_t mmap_length;
size_t system_pagesize_mask;
#endif
Bit32u * pagetable;
// Header is written to disk in little-endian (x86) format
// Thus needs to be converted on big-endian systems before read
// The pagetable is also kept little endian
sparse_header_t header;
Bit32u pagesize;
int pagesize_shift;
Bit32u pagesize_mask;
Bit64s data_start;
Bit64s underlying_filesize;
char * pathname;
Bit64s position;
Bit32u position_virtual_page;
Bit32u position_physical_page;
Bit32u position_page_offset;
Bit64s underlying_current_filepos;
Bit64s total_size;
void panic(const char * message);
Bit64s get_physical_offset();
void set_virtual_page(Bit32u new_virtual_page);
void read_header();
ssize_t read_page_fragment(Bit32u read_virtual_page, Bit32u read_page_offset, size_t read_size, void * buf);
sparse_image_t * parent_image;
};
#if EXTERNAL_DISK_SIMULATOR
#include "external-disk-simulator.h"
#endif
#if DLL_HD_SUPPORT
class dll_image_t : public device_image_t
{
public:
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
int vunit,vblk;
};
#endif
// REDOLOG class
class redolog_t
{
public:
redolog_t();
int make_header(const char* type, Bit64u size);
int create(const char* filename, const char* type, Bit64u size);
int create(int filedes, const char* type, Bit64u size);
int open(const char* filename, const char* type);
void close();
Bit64u get_size();
Bit64s lseek(Bit64s offset, int whence);
ssize_t read(void* buf, size_t count);
ssize_t write(const void* buf, size_t count);
private:
void print_header();
int fd;
redolog_header_t header; // Header is kept in x86 (little) endianness
Bit32u *catalog;
Bit8u *bitmap;
Bit32u extent_index;
Bit32u extent_offset;
Bit32u extent_next;
Bit32u bitmap_blocks;
Bit32u extent_blocks;
Bit64s imagepos;
};
// GROWING MODE
class growing_image_t : public device_image_t
{
public:
// Contructor
growing_image_t();
virtual ~growing_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
redolog_t *redolog;
};
// UNDOABLE MODE
class undoable_image_t : public device_image_t
{
public:
// Contructor
undoable_image_t(const char* redolog_name);
virtual ~undoable_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
redolog_t *redolog; // Redolog instance
default_image_t *ro_disk; // Read-only flat disk instance
char *redolog_name; // Redolog name
};
// VOLATILE MODE
class volatile_image_t : public device_image_t
{
public:
// Contructor
volatile_image_t(const char* redolog_name);
virtual ~volatile_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
redolog_t *redolog; // Redolog instance
default_image_t *ro_disk; // Read-only flat disk instance
char *redolog_name; // Redolog name
char *redolog_temp; // Redolog temporary file name
};
#if BX_COMPRESSED_HD_SUPPORT
#include <zlib.h>
// Default compressed READ-ONLY image class
class z_ro_image_t : public device_image_t
{
public:
// Contructor
z_ro_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
Bit64s offset;
int fd;
gzFile gzfile;
};
// Z-UNDOABLE MODE
class z_undoable_image_t : public device_image_t
{
public:
// Contructor
z_undoable_image_t(Bit64u size, const char* redolog_name);
virtual ~z_undoable_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
redolog_t *redolog; // Redolog instance
z_ro_image_t *ro_disk; // Read-only compressed flat disk instance
Bit64u size;
char *redolog_name; // Redolog name
};
// Z-VOLATILE MODE
class z_volatile_image_t : public device_image_t
{
public:
// Contructor
z_volatile_image_t(Bit64u size, const char* redolog_name);
virtual ~z_volatile_image_t();
// Open a image. Returns non-negative if successful.
int open(const char* pathname);
// Close the image.
void close();
// Position ourselves. Return the resulting offset from the
// beginning of the file.
Bit64s lseek(Bit64s offset, int whence);
// Read count bytes to the buffer buf. Return the number of
// bytes read (count).
ssize_t read(void* buf, size_t count);
// Write count bytes from buf. Return the number of bytes
// written (count).
ssize_t write(const void* buf, size_t count);
private:
redolog_t *redolog; // Redolog instance
z_ro_image_t *ro_disk; // Read-only compressed flat disk instance
Bit64u size;
char *redolog_name; // Redolog name
char *redolog_temp; // Redolog temporary file name
};
#endif
class bx_hdimage_ctl_c : public bx_hdimage_ctl_stub_c {
public:
bx_hdimage_ctl_c();
virtual ~bx_hdimage_ctl_c() {}
virtual device_image_t *init_image(Bit8u image_mode, Bit64u disk_size, const char *journal);
};
#endif // HDIMAGE_HEADERS_ONLY
#endif

308
bochs/iodev/ioapic.cc Normal file
View File

@ -0,0 +1,308 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_APIC
#include "ioapic.h"
#define LOG_THIS theIOAPIC->
bx_ioapic_c *theIOAPIC = NULL;
int libioapic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theIOAPIC = new bx_ioapic_c();
bx_devices.pluginIOAPIC = theIOAPIC;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIOAPIC, BX_PLUGIN_IOAPIC);
return(0); // Success
}
void libioapic_LTX_plugin_fini(void)
{
delete theIOAPIC;
}
static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
if((a20addr & ~0x3) != ((a20addr+len-1) & ~0x3)) {
BX_PANIC(("I/O APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", a20addr));
return 1;
}
Bit32u value = theIOAPIC->read_aligned(a20addr & ~0x3);
if(len == 4) { // must be 32-bit aligned
*((Bit32u *)data) = value;
return 1;
}
// handle partial read, independent of endian-ness
value >>= (a20addr&3)*8;
if (len == 1)
*((Bit8u *) data) = value & 0xff;
else if (len == 2)
*((Bit16u *)data) = value & 0xffff;
else
BX_PANIC(("Unsupported I/O APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", a20addr, len));
return 1;
}
static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
if (len != 4) {
BX_PANIC(("I/O apic write with len=%d (should be 4)", len));
return 1;
}
if(a20addr & 0xf) {
BX_PANIC(("I/O apic write at unaligned address 0x" FMT_PHY_ADDRX, a20addr));
return 1;
}
theIOAPIC->write_aligned(a20addr, *((Bit32u*) data));
return 1;
}
void bx_io_redirect_entry_t::sprintf_self(char *buf)
{
sprintf(buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x",
(unsigned) destination(),
(unsigned) is_masked(),
(unsigned) trigger_mode(),
(unsigned) remote_irr(),
(unsigned) pin_polarity(),
(unsigned) delivery_status(),
(unsigned) destination_mode(),
(unsigned) delivery_mode(),
(unsigned) vector());
}
void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
{
BXRS_HEX_PARAM_SIMPLE(parent, lo);
BXRS_HEX_PARAM_SIMPLE(parent, hi);
}
#define BX_IOAPIC_BASE_ADDR (0xfec00000)
#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)
bx_ioapic_c::bx_ioapic_c(): base_addr(BX_IOAPIC_BASE_ADDR)
{
set_id(BX_IOAPIC_DEFAULT_ID);
put("IOAP");
}
void bx_ioapic_c::init(void)
{
BX_INFO(("initializing I/O APIC"));
DEV_register_memory_handlers(theIOAPIC,
ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
reset(BX_RESET_HARDWARE);
}
void bx_ioapic_c::reset(unsigned type)
{
// all interrupts masked
for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
ioredtbl[i].set_lo_part(0x00010000);
ioredtbl[i].set_hi_part(0x00000000);
}
intin = 0;
irr = 0;
ioregsel = 0;
}
Bit32u bx_ioapic_c::read_aligned(bx_phy_address address)
{
BX_DEBUG(("IOAPIC: read aligned addr=0x" FMT_PHY_ADDRX, address));
address &= 0xff;
if (address == 0x00) {
// select register
return ioregsel;
} else {
if (address != 0x10)
BX_PANIC(("IOAPIC: read from unsupported address"));
}
Bit32u data = 0;
// only reached when reading data register
switch (ioregsel) {
case 0x00: // APIC ID, note this is 4bits, the upper 4 are reserved
data = ((id & apic_id_mask) << 24);
break;
case 0x01: // version
data = BX_IOAPIC_VERSION_ID;
break;
case 0x02:
BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
break;
default:
int index = (ioregsel - 0x10) >> 1;
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
bx_io_redirect_entry_t *entry = ioredtbl + index;
data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
break;
}
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
}
return data;
}
void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u value)
{
BX_DEBUG(("IOAPIC: write aligned addr=%08x, data=%08x", (unsigned) address, value));
address &= 0xff;
if (address == 0x00) {
ioregsel = value;
return;
} else {
if (address != 0x10)
BX_PANIC(("IOAPIC: write to unsupported address"));
}
// only reached when writing data register
switch (ioregsel) {
case 0x00: // set APIC ID
{
Bit8u newid = (value >> 24) & apic_id_mask;
BX_INFO(("IOAPIC: setting id to 0x%x", newid));
set_id (newid);
return;
}
case 0x01: // version
case 0x02: // arbitration id
BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
return;
default:
int index = (ioregsel - 0x10) >> 1;
if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
bx_io_redirect_entry_t *entry = ioredtbl + index;
if (ioregsel&1)
entry->set_hi_part(value);
else
entry->set_lo_part(value);
char buf[1024];
entry->sprintf_self(buf);
BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
service_ioapic();
return;
}
BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
}
}
void bx_ioapic_c::set_irq_level(Bit8u int_in, bx_bool level)
{
BX_DEBUG(("set_irq_level(): INTIN%d: level=%d", int_in, level));
if (int_in < BX_IOAPIC_NUM_PINS) {
Bit32u bit = 1<<int_in;
if ((level<<int_in) != (intin & bit)) {
bx_io_redirect_entry_t *entry = ioredtbl + int_in;
if (entry->trigger_mode()) {
// level triggered
if (level) {
intin |= bit;
irr |= bit;
service_ioapic();
} else {
intin &= ~bit;
irr &= ~bit;
}
} else {
// edge triggered
if (level) {
intin |= bit;
irr |= bit;
service_ioapic();
} else {
intin &= ~bit;
}
}
}
}
}
void bx_ioapic_c::receive_eoi(Bit8u vector)
{
BX_DEBUG(("IOAPIC: received EOI for vector %d", vector));
}
void bx_ioapic_c::service_ioapic()
{
static unsigned int stuck = 0;
Bit8u vector = 0;
// look in IRR and deliver any interrupts that are not masked.
BX_DEBUG(("IOAPIC: servicing"));
for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
Bit32u mask = 1<<bit;
if (irr & mask) {
bx_io_redirect_entry_t *entry = ioredtbl + bit;
if (! entry->is_masked()) {
// clear irr bit and deliver
if (entry->delivery_mode() == 7) {
vector = DEV_pic_iac();
} else {
vector = entry->vector();
}
bx_bool done = apic_bus_deliver_interrupt(vector, entry->destination(), entry->delivery_mode(), entry->destination_mode(), entry->pin_polarity(), entry->trigger_mode());
if (done) {
if (! entry->trigger_mode())
irr &= ~mask;
entry->clear_delivery_status();
stuck = 0;
} else {
entry->set_delivery_status();
stuck++;
if (stuck > 5)
BX_INFO(("vector %#x stuck?", vector));
}
}
else {
BX_DEBUG(("service_ioapic(): INTIN%d is masked", bit));
}
}
}
}
void bx_ioapic_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
BXRS_HEX_PARAM_SIMPLE(list, intin);
BXRS_HEX_PARAM_SIMPLE(list, irr);
bx_list_c *table = new bx_list_c(list, "ioredtbl", BX_IOAPIC_NUM_PINS);
for (unsigned i=0; i<BX_IOAPIC_NUM_PINS; i++) {
char name[6];
sprintf(name, "0x%02x", i);
bx_list_c *entry = new bx_list_c(table, name, 2);
ioredtbl[i].register_state(entry);
}
}
#endif /* if BX_SUPPORT_APIC */

112
bochs/iodev/ioapic.h Normal file
View File

@ -0,0 +1,112 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef BX_DEVICES_IOAPIC_H
#define BX_DEVICES_IOAPIC_H
#if BX_SUPPORT_APIC
typedef Bit32u apic_dest_t; /* same definition in apic.h */
extern int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast);
extern int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bx_bool logical_dest, bx_bool level, bx_bool trig_mode);
extern int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bx_bool trig_mode, int exclude_cpu);
#define BX_IOAPIC_NUM_PINS (0x18)
// use the same version as 82093 IOAPIC (0x00170011)
#define BX_IOAPIC_VERSION_ID (((BX_IOAPIC_NUM_PINS - 1) << 16) | 0x11)
class bx_io_redirect_entry_t {
Bit32u hi, lo;
public:
bx_io_redirect_entry_t(): hi(0), lo(0x10000) {}
Bit8u destination() const { return (Bit8u)(hi >> 24); }
bx_bool is_masked() const { return (bx_bool)((lo >> 16) & 1); }
Bit8u trigger_mode() const { return (Bit8u)((lo >> 15) & 1); }
bx_bool remote_irr() const { return (bx_bool)((lo >> 14) & 1); }
Bit8u pin_polarity() const { return (Bit8u)((lo >> 13) & 1); }
bx_bool delivery_status() const { return (bx_bool)((lo >> 12) & 1); }
Bit8u destination_mode() const { return (Bit8u)((lo >> 11) & 1); }
Bit8u delivery_mode() const { return (Bit8u)((lo >> 8) & 7); }
Bit8u vector() const { return (Bit8u)(lo & 0xff); }
void set_delivery_status() { lo |= (1<<12); }
void clear_delivery_status() { lo &= ~(1<<12); }
void set_remote_irr() { lo |= (1<<14); }
void clear_remote_irr() { lo &= ~(1<<14); }
Bit32u get_lo_part () const { return lo; }
Bit32u get_hi_part () const { return hi; }
void set_lo_part (Bit32u val_lo_part) {
// keep high 32 bits of value, replace low 32, ignore R/O bits
lo = val_lo_part & 0xffffafff;
}
void set_hi_part (Bit32u val_hi_part) {
// keep low 32 bits of value, replace high 32
hi = val_hi_part;
}
void sprintf_self(char *buf);
void register_state(bx_param_c *parent);
};
class bx_ioapic_c : public bx_ioapic_stub_c {
public:
bx_ioapic_c();
virtual ~bx_ioapic_c() {}
virtual void init();
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void receive_eoi(Bit8u vector);
virtual void set_irq_level(Bit8u int_in, bx_bool level);
Bit32u read_aligned(bx_phy_address address);
void write_aligned(bx_phy_address address, Bit32u data);
private:
bx_phy_address get_base(void) const { return base_addr; }
void set_id(Bit32u new_id) { id = new_id; }
Bit32u get_id() const { return id; }
void service_ioapic(void);
bx_phy_address base_addr;
Bit32u id;
Bit32u ioregsel; // selects between various registers
Bit32u intin;
// interrupt request bitmask, not visible from the outside. Bits in the
// irr are set when trigger_irq is called, and cleared when the interrupt
// is delivered to the processor. If an interrupt is masked, the irr
// will still be set but delivery will not occur until it is unmasked.
// It's not clear if this is how the real device works.
Bit32u irr;
bx_io_redirect_entry_t ioredtbl[BX_IOAPIC_NUM_PINS]; // table of redirections
};
#endif
#endif

343
bochs/iodev/iodebug.cc Normal file
View File

@ -0,0 +1,343 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_IODEBUG
#include "cpu/cpu.h"
#include "iodebug.h"
#define BX_IODEBUG_THIS this->
bx_iodebug_c *theIODebugDevice = NULL;
int libiodebug_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theIODebugDevice = new bx_iodebug_c();
bx_devices.pluginIODebug = theIODebugDevice;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIODebugDevice, BX_PLUGIN_IODEBUG);
return(0); // Success
}
void libiodebug_LTX_plugin_fini(void)
{
delete theIODebugDevice;
}
struct bx_iodebug_s_type {
bx_bool enabled;
unsigned register_select;
Bit32u registers[2];
bx_phy_address monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
bx_phy_address monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
} bx_iodebug_s;
bx_iodebug_c::bx_iodebug_c()
{
put("IODBG");
}
void bx_iodebug_c::init(void)
{
DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 2);
DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 2);
DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 2);
bx_iodebug_s.enabled = 0;
bx_iodebug_s.register_select = 0;
for(int i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
bx_iodebug_s.monitored_mem_areas_start[i] = 0;
bx_iodebug_s.monitored_mem_areas_end[i] = 0;
}
}
Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
return bx_iodebug_ptr->read(addr, io_len);
}
Bit32u bx_iodebug_c::read(Bit32u addr, unsigned io_len)
{
if (bx_iodebug_s.enabled) return 0x8A00;
return(0);
}
void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
bx_iodebug_ptr->write(addr, dvalue, io_len);
}
void bx_iodebug_c::write(Bit32u addr, Bit32u dvalue, unsigned io_len)
{
//fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned) addr, (unsigned) dvalue, io_len);
if (addr == 0x8A01)
{
bx_iodebug_s.registers[bx_iodebug_s.register_select] =
(bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
(dvalue & 0xFFFF);
}
if (addr != 0x8A00) return;
if (!bx_iodebug_s.enabled)
{
if(dvalue == 0x8A00)
{
bx_iodebug_s.enabled = 1;
// fprintf(stderr, "IODEBUG enabled\n");
bx_iodebug_s.registers[0] = 0;
bx_iodebug_s.registers[1] = 0;
}
return;
}
switch(dvalue)
{
case 0x8A01:
bx_iodebug_s.register_select = 0;
// fprintf(stderr, "IODEBUG register 0 selected\n");
break;
case 0x8A02:
bx_iodebug_s.register_select = 1;
// fprintf(stderr, "IODEBUG register 1 selected\n");
break;
case 0x8A80:
bx_iodebug_s.register_select = 0;
bx_iodebug_c::add_range(bx_iodebug_s.registers[0],
bx_iodebug_s.registers[1]);
bx_iodebug_s.registers[0] = 0;
bx_iodebug_s.registers[1] = 0;
break;
#if BX_DEBUGGER
case 0x8AE0:
fprintf(stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
bx_guard.interrupt_requested=1;
break;
case 0x8AE2:
fprintf(stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
BX_CPU(dbg_cpu)->trace = 0;
break;
case 0x8AE3:
fprintf(stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
BX_CPU(dbg_cpu)->trace = 1;
break;
case 0x8AE4:
fprintf(stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
BX_CPU(dbg_cpu)->trace_reg = 0;
break;
case 0x8AE5:
fprintf(stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
BX_CPU(dbg_cpu)->trace_reg = 1;
break;
#endif
case 0x8AFF:
bx_iodebug_s.enabled = 0;
// fprintf(stderr, "IODEBUG device deactivated\n");
// break;
// default:
// fprintf(stderr,"IODEBUG unsupported register code\n");
}
}
// Static function
void bx_iodebug_c::mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
if(! bx_iodebug_s.enabled) return;
unsigned area = bx_iodebug_c::range_test(addr, len);
// Device is enabled, testing address ranges
if(area)
{
area--;
#if BX_DEBUGGER
if (cpu != NULL) {
fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " write at monitored memory location %8X\n",
cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
}
else {
fprintf(stdout, "IODEBUG write at monitored memory location %8X\n", addr);
}
bx_guard.interrupt_requested=1;
#else
fprintf(stderr, "IODEBUG write to monitored memory area: %2i\t", area);
if (cpu != NULL)
fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
else
fprintf(stderr, "(device origin)\t");
fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
bx_iodebug_s.monitored_mem_areas_start[area],
bx_iodebug_s.monitored_mem_areas_end[area],
(unsigned) addr);
switch(len)
{
case 1: {
Bit8u data8 = * ((Bit8u *) data);
fprintf(stderr,"%02X\n", (unsigned) data8);
break;
}
case 2: {
Bit16u data16 = * ((Bit16u *) data);
fprintf(stderr,"%04X\n", (unsigned) data16);
break;
}
case 4: {
Bit32u data32 = * ((Bit32u *) data);
fprintf(stderr,"%08X\n", (unsigned) data32);
break;
}
case 8: {
Bit64u data64 = * ((Bit64u *) data);
fprintf(stderr,"%08X%08x\n",
(unsigned) (data64 >> 32),
(unsigned) (data64 & 0xffffffff));
break;
}
default:
fprintf(stderr, "unsupported write size\n");
}
#endif
}
}
void bx_iodebug_c::mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
if(! bx_iodebug_s.enabled) return;
unsigned area = bx_iodebug_c::range_test(addr, len);
// Device is enabled, testing address ranges
if(area)
{
area--;
#if BX_DEBUGGER
if (cpu != NULL) {
fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " read at monitored memory location %8X\n",
cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
}
else {
fprintf(stdout, "IODEBUG read at monitored memory location %8X\n", addr);
}
bx_guard.interrupt_requested=1;
#else
fprintf(stderr, "IODEBUG read at monitored memory area: %2i\t", area);
if (cpu != NULL)
fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
else
fprintf(stderr, "(device origin)\t");
fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
bx_iodebug_s.monitored_mem_areas_start[area],
bx_iodebug_s.monitored_mem_areas_end[area],
(unsigned) addr);
switch(len)
{
case 1: {
Bit8u data8 = * ((Bit8u *) data);
fprintf(stderr,"%02X\n", (unsigned) data8);
break;
}
case 2: {
Bit16u data16 = * ((Bit16u *) data);
fprintf(stderr,"%04X\n", (unsigned) data16);
break;
}
case 4: {
Bit32u data32 = * ((Bit32u *) data);
fprintf(stderr,"%08X\n", (unsigned) data32);
break;
}
case 8: {
Bit64u data64 = * ((Bit64u *) data);
fprintf(stderr,"%08X%08x\n",
(unsigned) (data64 >> 32),
(unsigned) (data64 & 0xffffffff));
break;
}
default:
fprintf(stderr, "unsupported read size\n");
}
#endif
}
}
unsigned bx_iodebug_c::range_test(bx_phy_address addr, unsigned len)
{
for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
{
if(bx_iodebug_s.monitored_mem_areas_start[i] != 0 ||
bx_iodebug_s.monitored_mem_areas_end[i] != 0)
{
if((Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i])
continue;
if(addr < bx_iodebug_s.monitored_mem_areas_end[i])
{
return(++i);
}
}
}
return(0);
}
void bx_iodebug_c::add_range(bx_phy_address addr_start, bx_phy_address addr_end)
{
for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
{
if(!bx_iodebug_s.monitored_mem_areas_start[i] &&
!bx_iodebug_s.monitored_mem_areas_end[i])
{
bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
// fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
return;
}
}
//fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}
#endif /* if BX_SUPPORT_IODEBUG */

49
bochs/iodev/iodebug.h Normal file
View File

@ -0,0 +1,49 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
#ifndef _BX_IODEBUG_H
#define _BX_IODEBUG_H
#if BX_SUPPORT_IODEBUG
#define BX_IODEBUG_MAX_AREAS 30
class bx_iodebug_c : public bx_iodebug_stub_c {
public:
bx_iodebug_c();
virtual ~bx_iodebug_c() {}
virtual void init(void);
virtual void reset (unsigned type) {}
virtual void mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data);
virtual void mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data);
private:
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
Bit32u read(Bit32u addr, unsigned io_len);
void write(Bit32u addr, Bit32u dvalue, unsigned io_len);
static unsigned range_test(bx_phy_address addr, unsigned len);
static void add_range(bx_phy_address addr_start, bx_phy_address addr_end);
};
#endif
#endif

619
bochs/iodev/iodev.h Normal file
View File

@ -0,0 +1,619 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2011 The Bochs Project
//
// I/O port handlers API Copyright (C) 2003 by Frank Cornelis
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef IODEV_H
#define IODEV_H
#include "bochs.h"
#include "param_names.h"
/* number of IRQ lines supported. In an ISA PC there are two
PIC chips cascaded together. each has 8 IRQ lines, so there
should be 16 IRQ's total */
#define BX_MAX_IRQS 16
/* size of internal buffer for mouse devices */
#define BX_MOUSE_BUFF_SIZE 48
#if 0
class bx_g2h_c;
#endif
typedef Bit32u (*bx_read_handler_t)(void *, Bit32u, unsigned);
typedef void (*bx_write_handler_t)(void *, Bit32u, Bit32u, unsigned);
typedef bx_bool (*bx_keyb_enq_t)(void *, Bit8u *);
typedef void (*bx_mouse_enq_t)(void *, int, int, int, unsigned);
typedef void (*bx_mouse_enabled_changed_t)(void *, bx_bool);
#if BX_USE_DEV_SMF
# define BX_DEV_SMF static
# define BX_DEV_THIS bx_devices.
#else
# define BX_DEV_SMF
# define BX_DEV_THIS this->
#endif
//////////////////////////////////////////////////////////////////////
// bx_devmodel_c declaration
//////////////////////////////////////////////////////////////////////
// This class defines virtual methods that are common to all devices.
// Child classes do not need to implement all of them, because in this
// definition they are defined as empty, as opposed to being pure
// virtual (= 0).
class BOCHSAPI bx_devmodel_c : public logfunctions {
public:
virtual ~bx_devmodel_c() {}
virtual void init(void) {}
virtual void reset(unsigned type) {}
virtual void register_state(void) {}
virtual void after_restore_state(void) {}
#if BX_DEBUGGER
virtual void debug_dump(void) {}
#endif
};
//////////////////////////////////////////////////////////////////////
// declare stubs for PCI devices
//////////////////////////////////////////////////////////////////////
class bx_list_c;
class device_image_t;
// the best should be deriving of bx_pci_device_stub_c from bx_devmodel_c
// but it make serious problems for cirrus_svga device
class BOCHSAPI bx_pci_device_stub_c {
public:
virtual ~bx_pci_device_stub_c() {}
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len) {
return 0;
}
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len) {}
void register_pci_state(bx_list_c *list, Bit8u *pci_conf);
};
//////////////////////////////////////////////////////////////////////
// declare stubs for devices
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
#define STUBFUNC(dev,method) \
pluginlog->panic("%s called in %s stub. you must not have loaded the %s plugin", #dev, #method, #dev)
//////////////////////////////////////////////////////////////////////
class BOCHSAPI bx_keyb_stub_c : public bx_devmodel_c {
public:
virtual ~bx_keyb_stub_c() {}
// stubs for bx_keyb_c methods
virtual void gen_scancode(Bit32u key) {
STUBFUNC(keyboard, gen_scancode);
}
virtual void paste_bytes(Bit8u *data, Bit32s length) {
STUBFUNC(keyboard, paste_bytes);
}
};
class BOCHSAPI bx_hard_drive_stub_c : public bx_devmodel_c {
public:
virtual void init() {
STUBFUNC(HD, init);
}
virtual void reset(unsigned type) {
STUBFUNC(HD, reset);
}
virtual Bit32u get_device_handle(Bit8u channel, Bit8u device) {
STUBFUNC(HD, get_device_handle); return 0;
}
virtual Bit32u get_first_cd_handle(void) {
STUBFUNC(HD, get_first_cd_handle); return 0;
}
virtual unsigned get_cd_media_status(Bit32u handle) {
STUBFUNC(HD, get_cd_media_status); return 0;
}
virtual unsigned set_cd_media_status(Bit32u handle, unsigned status) {
STUBFUNC(HD, set_cd_media_status); return 0;
}
virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len)
{
STUBFUNC(HD, virt_read_handler); return 0;
}
virtual void virt_write_handler(Bit32u address,
Bit32u value, unsigned io_len)
{
STUBFUNC(HD, virt_write_handler);
}
virtual bx_bool bmdma_read_sector(Bit8u channel, Bit8u *buffer, Bit32u *sector_size) {
STUBFUNC(HD, bmdma_read_sector); return 0;
}
virtual bx_bool bmdma_write_sector(Bit8u channel, Bit8u *buffer) {
STUBFUNC(HD, bmdma_write_sector); return 0;
}
virtual void bmdma_complete(Bit8u channel) {
STUBFUNC(HD, bmdma_complete);
}
};
class BOCHSAPI bx_floppy_stub_c : public bx_devmodel_c {
public:
virtual unsigned set_media_status(unsigned drive, unsigned status) {
STUBFUNC(floppy, set_media_status); return 0;
}
};
class BOCHSAPI bx_cmos_stub_c : public bx_devmodel_c {
public:
virtual Bit32u get_reg(unsigned reg) {
STUBFUNC(cmos, get_reg); return 0;
}
virtual void set_reg(unsigned reg, Bit32u val) {
STUBFUNC(cmos, set_reg);
}
virtual time_t get_timeval() {
return 0;
}
virtual void checksum_cmos(void) {
STUBFUNC(cmos, checksum);
}
};
class BOCHSAPI bx_dma_stub_c : public bx_devmodel_c {
public:
virtual unsigned registerDMA8Channel(
unsigned channel,
void (* dmaRead)(Bit8u *data_byte),
void (* dmaWrite)(Bit8u *data_byte),
const char *name)
{
STUBFUNC(dma, registerDMA8Channel); return 0;
}
virtual unsigned registerDMA16Channel(
unsigned channel,
void (* dmaRead)(Bit16u *data_word),
void (* dmaWrite)(Bit16u *data_word),
const char *name)
{
STUBFUNC(dma, registerDMA16Channel); return 0;
}
virtual unsigned unregisterDMAChannel(unsigned channel) {
STUBFUNC(dma, unregisterDMAChannel); return 0;
}
virtual unsigned get_TC(void) {
STUBFUNC(dma, get_TC); return 0;
}
virtual void set_DRQ(unsigned channel, bx_bool val) {
STUBFUNC(dma, set_DRQ);
}
virtual void raise_HLDA(void) {
STUBFUNC(dma, raise_HLDA);
}
};
class BOCHSAPI bx_pic_stub_c : public bx_devmodel_c {
public:
virtual void raise_irq(unsigned irq_no) {
STUBFUNC(pic, raise_irq);
}
virtual void lower_irq(unsigned irq_no) {
STUBFUNC(pic, lower_irq);
}
virtual void set_mode(bx_bool ma_sl, Bit8u mode) {
STUBFUNC(pic, set_mode);
}
virtual Bit8u IAC(void) {
STUBFUNC(pic, IAC); return 0;
}
};
class BOCHSAPI bx_vga_stub_c : public bx_devmodel_c {
public:
virtual void redraw_area(unsigned x0, unsigned y0,
unsigned width, unsigned height) {
STUBFUNC(vga, redraw_area);
}
virtual Bit8u mem_read(bx_phy_address addr) {
STUBFUNC(vga, mem_read); return 0;
}
virtual void mem_write(bx_phy_address addr, Bit8u value) {
STUBFUNC(vga, mem_write);
}
virtual void get_text_snapshot(Bit8u **text_snapshot,
unsigned *txHeight, unsigned *txWidth) {
STUBFUNC(vga, get_text_snapshot);
}
virtual void trigger_timer(void *this_ptr) {
STUBFUNC(vga, trigger_timer);
}
virtual Bit8u get_actl_palette_idx(Bit8u index) {
return 0;
}
virtual bx_bool vbe_set_base_addr(Bit32u *addr, Bit8u *pci_conf) {
return 0;
}
};
class BOCHSAPI bx_pci_bridge_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
virtual bx_bool register_pci_handlers(bx_pci_device_stub_c *device,
Bit8u *devfunc, const char *name,
const char *descr)
{
STUBFUNC(pci, register_pci_handlers); return 0;
}
virtual bx_bool is_pci_device(const char *name) {
return 0;
}
virtual bx_bool pci_set_base_mem(void *this_ptr, memory_handler_t f1, memory_handler_t f2,
Bit32u *addr, Bit8u *pci_conf, unsigned size) {
STUBFUNC(pci, pci_set_base_mem);
return 0;
}
virtual bx_bool pci_set_base_io(void *this_ptr, bx_read_handler_t f1, bx_write_handler_t f2,
Bit32u *addr, Bit8u *pci_conf, unsigned size,
const Bit8u *iomask, const char *name) {
STUBFUNC(pci, pci_set_base_io);
return 0;
}
virtual Bit8u rd_memType(Bit32u addr) { return 0; }
virtual Bit8u wr_memType(Bit32u addr) { return 0; }
};
class BOCHSAPI bx_pci2isa_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
virtual void pci_set_irq (Bit8u devfunc, unsigned line, bx_bool level) {
STUBFUNC(pci2isa, pci_set_irq);
}
};
class BOCHSAPI bx_pci_ide_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
virtual bx_bool bmdma_present(void) {
return 0;
}
virtual void bmdma_set_irq(Bit8u channel) {}
};
class BOCHSAPI bx_ne2k_stub_c : public bx_devmodel_c {
public:
virtual void print_info(FILE *file, int page, int reg, int nodups) {}
};
class BOCHSAPI bx_speaker_stub_c : public bx_devmodel_c {
public:
virtual void beep_on(float frequency) {
bx_gui->beep_on(frequency);
}
virtual void beep_off() {
bx_gui->beep_off();
}
};
#if BX_SUPPORT_ACPI
class BOCHSAPI bx_acpi_ctrl_stub_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
virtual void generate_smi(Bit8u value) {}
};
#endif
#if BX_SUPPORT_IODEBUG
class BOCHSAPI bx_iodebug_stub_c : public bx_devmodel_c {
public:
virtual void mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data) {
STUBFUNC(iodebug, mem_write);
}
virtual void mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data) {
STUBFUNC(iodebug, mem_read);
}
};
#endif
#if BX_SUPPORT_APIC
class BOCHSAPI bx_ioapic_stub_c : public bx_devmodel_c {
public:
virtual void receive_eoi(Bit8u vector) {}
virtual void set_irq_level(Bit8u int_in, bx_bool level) {}
};
#endif
#if BX_SUPPORT_PCIUSB
class BOCHSAPI bx_usb_devctl_stub_c : public bx_devmodel_c {
public:
virtual int init_device(bx_list_c *portconf, logfunctions *hub, void **dev, bx_list_c *sr_list) {
STUBFUNC(usb_devctl, init_device); return 0;
}
virtual void usb_send_msg(void *dev, int msg) {}
};
#endif
class BOCHSAPI bx_hdimage_ctl_stub_c : public bx_devmodel_c {
public:
virtual device_image_t* init_image(Bit8u image_mode, Bit64u disk_size, const char *journal) {
STUBFUNC(hdimage_ctl, init_image); return NULL;
}
};
#if BX_SUPPORT_SB16
class BOCHSAPI bx_soundmod_ctl_stub_c : public bx_devmodel_c {
public:
virtual int init_module(const char *type, void **module, logfunctions *dev) {
STUBFUNC(soundmod_ctl, init_module); return 0;
}
};
#endif
class BOCHSAPI bx_devices_c : public logfunctions {
public:
bx_devices_c();
~bx_devices_c();
// Initialize the device stubs (in constructur and exit())
void init_stubs(void);
// Register I/O addresses and IRQ lines. Initialize any internal
// structures. init() is called only once, even if the simulator
// reboots or is restarted.
void init(BX_MEM_C *);
// Enter reset state in response to a reset condition.
// The types of reset conditions are defined in bochs.h:
// power-on, hardware, or software.
void reset(unsigned type);
// Cleanup the devices when the simulation quits.
void exit(void);
void register_state(void);
void after_restore_state(void);
BX_MEM_C *mem; // address space associated with these devices
bx_bool register_io_read_handler(void *this_ptr, bx_read_handler_t f,
Bit32u addr, const char *name, Bit8u mask);
bx_bool unregister_io_read_handler(void *this_ptr, bx_read_handler_t f,
Bit32u addr, Bit8u mask);
bx_bool register_io_write_handler(void *this_ptr, bx_write_handler_t f,
Bit32u addr, const char *name, Bit8u mask);
bx_bool unregister_io_write_handler(void *this_ptr, bx_write_handler_t f,
Bit32u addr, Bit8u mask);
bx_bool register_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
Bit32u begin_addr, Bit32u end_addr,
const char *name, Bit8u mask);
bx_bool register_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
Bit32u begin_addr, Bit32u end_addr,
const char *name, Bit8u mask);
bx_bool unregister_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
Bit32u begin, Bit32u end, Bit8u mask);
bx_bool unregister_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
Bit32u begin, Bit32u end, Bit8u mask);
bx_bool register_default_io_read_handler(void *this_ptr, bx_read_handler_t f, const char *name, Bit8u mask);
bx_bool register_default_io_write_handler(void *this_ptr, bx_write_handler_t f, const char *name, Bit8u mask);
bx_bool register_irq(unsigned irq, const char *name);
bx_bool unregister_irq(unsigned irq, const char *name);
Bit32u inp(Bit16u addr, unsigned io_len) BX_CPP_AttrRegparmN(2);
void outp(Bit16u addr, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
void register_removable_keyboard(void *dev, bx_keyb_enq_t keyb_enq);
void unregister_removable_keyboard(void *dev);
void register_default_mouse(void *dev, bx_mouse_enq_t mouse_enq, bx_mouse_enabled_changed_t mouse_enabled_changed);
void register_removable_mouse(void *dev, bx_mouse_enq_t mouse_enq, bx_mouse_enabled_changed_t mouse_enabled_changed);
void unregister_removable_mouse(void *dev);
bx_bool optional_key_enq(Bit8u *scan_code);
void mouse_enabled_changed(bx_bool enabled);
void mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state);
static void timer_handler(void *);
void timer(void);
bx_pci_bridge_stub_c *pluginPciBridge;
bx_pci2isa_stub_c *pluginPci2IsaBridge;
bx_pci_ide_stub_c *pluginPciIdeController;
#if BX_SUPPORT_ACPI
bx_acpi_ctrl_stub_c *pluginACPIController;
#endif
bx_devmodel_c *pluginPitDevice;
bx_keyb_stub_c *pluginKeyboard;
bx_dma_stub_c *pluginDmaDevice;
bx_floppy_stub_c *pluginFloppyDevice;
bx_cmos_stub_c *pluginCmosDevice;
bx_vga_stub_c *pluginVgaDevice;
bx_pic_stub_c *pluginPicDevice;
bx_hard_drive_stub_c *pluginHardDrive;
bx_hdimage_ctl_stub_c *pluginHDImageCtl;
bx_ne2k_stub_c *pluginNE2kDevice[4];
bx_speaker_stub_c *pluginSpeaker;
#if BX_SUPPORT_IODEBUG
bx_iodebug_stub_c *pluginIODebug;
#endif
#if BX_SUPPORT_APIC
bx_ioapic_stub_c *pluginIOAPIC;
#endif
#if BX_SUPPORT_PCIUSB
bx_usb_devctl_stub_c *pluginUsbDevCtl;
#endif
#if BX_SUPPORT_SB16
bx_soundmod_ctl_stub_c *pluginSoundModCtl;
#endif
#if 0
bx_g2h_c *g2h;
#endif
// stub classes that the pointers (above) can point to until a plugin is
// loaded
bx_cmos_stub_c stubCmos;
bx_keyb_stub_c stubKeyboard;
bx_hard_drive_stub_c stubHardDrive;
bx_hdimage_ctl_stub_c stubHDImage;
bx_dma_stub_c stubDma;
bx_pic_stub_c stubPic;
bx_floppy_stub_c stubFloppy;
bx_vga_stub_c stubVga;
bx_pci_bridge_stub_c stubPci;
bx_pci2isa_stub_c stubPci2Isa;
bx_pci_ide_stub_c stubPciIde;
bx_ne2k_stub_c stubNE2k;
bx_speaker_stub_c stubSpeaker;
#if BX_SUPPORT_ACPI
bx_acpi_ctrl_stub_c stubACPIController;
#endif
#if BX_SUPPORT_IODEBUG
bx_iodebug_stub_c stubIODebug;
#endif
#if BX_SUPPORT_APIC
bx_ioapic_stub_c stubIOAPIC;
#endif
#if BX_SUPPORT_PCIUSB
bx_usb_devctl_stub_c stubUsbDevCtl;
#endif
#if BX_SUPPORT_SB16
bx_soundmod_ctl_stub_c stubSoundModCtl;
#endif
// Some info to pass to devices which can handled bulk IO. This allows
// the interface to remain the same for IO devices which can't handle
// bulk IO. We should probably implement special INPBulk() and OUTBulk()
// functions which stick these values in the bx_devices_c class, and
// then call the normal functions rather than having gross globals
// variables.
Bit8u* bulkIOHostAddr;
unsigned bulkIOQuantumsRequested;
unsigned bulkIOQuantumsTransferred;
private:
struct io_handler_struct {
struct io_handler_struct *next;
struct io_handler_struct *prev;
void *funct; // C++ type checking is great, but annoying
void *this_ptr;
char *handler_name; // name of device
int usage_count;
Bit8u mask; // io_len mask
};
struct io_handler_struct io_read_handlers;
struct io_handler_struct io_write_handlers;
#define PORTS 0x10000
struct io_handler_struct **read_port_to_handler;
struct io_handler_struct **write_port_to_handler;
// more for informative purposes, the names of the devices which
// are use each of the IRQ 0..15 lines are stored here
char *irq_handler_name[BX_MAX_IRQS];
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
BX_DEV_SMF Bit32u port92_read(Bit32u address, unsigned io_len);
BX_DEV_SMF void port92_write(Bit32u address, Bit32u value, unsigned io_len);
static Bit32u default_read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
bx_bool mouse_captured; // host mouse capture enabled
Bit8u mouse_type;
struct {
void *dev;
bx_mouse_enq_t enq_event;
bx_mouse_enabled_changed_t enabled_changed;
} bx_mouse[2];
struct {
void *dev;
bx_keyb_enq_t enq_event;
} bx_keyboard;
int timer_handle;
bx_bool is_harddrv_enabled();
bx_bool is_serial_enabled();
bx_bool is_parallel_enabled();
bx_bool is_usb_ohci_enabled();
bx_bool is_usb_uhci_enabled();
};
// memory stub has an assumption that there are no memory accesses splitting 4K page
BX_CPP_INLINE void DEV_MEM_READ_PHYSICAL(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
{
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
if (len <= remainingInPage) {
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, len, ptr);
}
else {
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, remainingInPage, ptr);
ptr += remainingInPage;
phy_addr += remainingInPage;
len -= remainingInPage;
BX_MEM(0)->readPhysicalPage(NULL, phy_addr, len, ptr);
}
}
BX_CPP_INLINE void DEV_MEM_READ_PHYSICAL_BLOCK(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
{
Bit8u *memptr;
while(len > 0) {
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
if (len < remainingInPage) remainingInPage = len;
memptr = BX_MEM(0)->getHostMemAddr(NULL, phy_addr, BX_READ);
if (memptr != NULL) {
memcpy(ptr, memptr, remainingInPage);
}
ptr += remainingInPage;
phy_addr += remainingInPage;
len -= remainingInPage;
}
}
// memory stub has an assumption that there are no memory accesses splitting 4K page
BX_CPP_INLINE void DEV_MEM_WRITE_PHYSICAL(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
{
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
if (len <= remainingInPage) {
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, len, ptr);
}
else {
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, remainingInPage, ptr);
ptr += remainingInPage;
phy_addr += remainingInPage;
len -= remainingInPage;
BX_MEM(0)->writePhysicalPage(NULL, phy_addr, len, ptr);
}
}
BX_CPP_INLINE void DEV_MEM_WRITE_PHYSICAL_BLOCK(bx_phy_address phy_addr, unsigned len, Bit8u *ptr)
{
Bit8u *memptr;
while(len > 0) {
unsigned remainingInPage = 0x1000 - (phy_addr & 0xfff);
if (len < remainingInPage) remainingInPage = len;
memptr = BX_MEM(0)->getHostMemAddr(NULL, phy_addr, BX_WRITE);
if (memptr != NULL) {
memcpy(memptr, ptr, remainingInPage);
}
ptr += remainingInPage;
phy_addr += remainingInPage;
len -= remainingInPage;
}
}
BOCHSAPI extern bx_devices_c bx_devices;
#endif /* IODEV_H */

1685
bochs/iodev/keyboard.cc Normal file

File diff suppressed because it is too large Load Diff

234
bochs/iodev/keyboard.h Normal file
View File

@ -0,0 +1,234 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef _PCKEY_H
#define _PCKEY_H
#define BX_KBD_ELEMENTS 16
// these keywords should only be used in keyboard.cc
#if BX_USE_KEY_SMF
# define BX_KEY_SMF static
# define BX_KEY_THIS theKeyboard->
#else
# define BX_KEY_SMF
# define BX_KEY_THIS this->
#endif
#define MOUSE_MODE_RESET 10
#define MOUSE_MODE_STREAM 11
#define MOUSE_MODE_REMOTE 12
#define MOUSE_MODE_WRAP 13
class bx_keyb_c : public bx_keyb_stub_c {
public:
bx_keyb_c();
virtual ~bx_keyb_c();
// implement bx_devmodel_c interface
virtual void init(void);
virtual void reset(unsigned type);
// override stubs from bx_keyb_stub_c
virtual void gen_scancode(Bit32u key);
virtual void paste_bytes(Bit8u *data, Bit32s length);
virtual void register_state(void);
virtual void after_restore_state(void);
// runtime options
static Bit64s kbd_param_handler(bx_param_c *param, int set, Bit64s val);
BX_KEY_SMF void paste_delay_changed(Bit32u value);
private:
BX_KEY_SMF Bit8u get_kbd_enable(void);
BX_KEY_SMF void service_paste_buf ();
BX_KEY_SMF void create_mouse_packet(bx_bool force_enq);
BX_KEY_SMF unsigned periodic(Bit32u usec_delta);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_KEY_SMF
void write(Bit32u address, Bit32u value, unsigned io_len);
Bit32u read(Bit32u address, unsigned io_len);
#endif
struct {
struct {
/* status bits matching the status port*/
bx_bool pare; // Bit7, 1= parity error from keyboard/mouse - ignored.
bx_bool tim; // Bit6, 1= timeout from keyboard - ignored.
bx_bool auxb; // Bit5, 1= mouse data waiting for CPU to read.
bx_bool keyl; // Bit4, 1= keyswitch in lock position - ignored.
bx_bool c_d; /* Bit3, 1=command to port 64h, 0=data to port 60h */
bx_bool sysf; // Bit2,
bx_bool inpb; // Bit1,
bx_bool outb; // Bit0, 1= keyboard data or mouse data ready for CPU
// check aux to see which. Or just keyboard
// data before AT style machines
/* internal to our version of the keyboard controller */
bx_bool kbd_clock_enabled;
bx_bool aux_clock_enabled;
bx_bool allow_irq1;
bx_bool allow_irq12;
Bit8u kbd_output_buffer;
Bit8u aux_output_buffer;
Bit8u last_comm;
Bit8u expecting_port60h;
Bit8u expecting_mouse_parameter;
Bit8u last_mouse_command;
Bit32u timer_pending;
bx_bool irq1_requested;
bx_bool irq12_requested;
bx_bool scancodes_translate;
bx_bool expecting_scancodes_set;
Bit8u current_scancodes_set;
bx_bool bat_in_progress;
} kbd_controller;
struct mouseStruct {
Bit8u type;
Bit8u sample_rate;
Bit8u resolution_cpmm; // resolution in counts per mm
Bit8u scaling;
Bit8u mode;
Bit8u saved_mode; // the mode prior to entering wrap mode
bx_bool enable;
Bit8u get_status_byte ()
{
// top bit is 0 , bit 6 is 1 if remote mode.
Bit8u ret = (Bit8u) ((mode == MOUSE_MODE_REMOTE) ? 0x40 : 0);
ret |= (enable << 5);
ret |= (scaling == 1) ? 0 : (1 << 4);
ret |= ((button_status & 0x1) << 2);
ret |= ((button_status & 0x2) << 0);
return ret;
}
Bit8u get_resolution_byte ()
{
Bit8u ret = 0;
switch (resolution_cpmm) {
case 1:
ret = 0;
break;
case 2:
ret = 1;
break;
case 4:
ret = 2;
break;
case 8:
ret = 3;
break;
default:
genlog->panic("mouse: invalid resolution_cpmm");
};
return ret;
}
Bit8u button_status;
Bit16s delayed_dx;
Bit16s delayed_dy;
Bit16s delayed_dz;
Bit8u im_request;
bx_bool im_mode;
} mouse;
struct {
int num_elements;
Bit8u buffer[BX_KBD_ELEMENTS];
int head;
bx_bool expecting_typematic;
bx_bool expecting_led_write;
Bit8u delay;
Bit8u repeat_rate;
Bit8u led_status;
bx_bool scanning_enabled;
} kbd_internal_buffer;
struct {
int num_elements;
Bit8u buffer[BX_MOUSE_BUFF_SIZE];
int head;
} mouse_internal_buffer;
#define BX_KBD_CONTROLLER_QSIZE 5
Bit8u controller_Q[BX_KBD_CONTROLLER_QSIZE];
unsigned controller_Qsize;
unsigned controller_Qsource; // 0=keyboard, 1=mouse
} s; // State information for saving/loading
// The paste buffer does NOT exist in the hardware. It is a bochs
// construction that allows the user to "paste" arbitrary length sequences of
// keystrokes into the emulated machine. Since the hardware buffer is only
// 16 bytes, a very small amount of data can be added to the hardware buffer
// at a time. The paste buffer keeps track of the bytes that have not yet
// been pasted.
//
// Lifetime of a paste buffer: The paste data comes from the system
// clipboard, which must be accessed using platform independent code in the
// gui. Because every gui has its own way of managing the clipboard memory
// (in X windows, you're supposed to call Xfree for example), in the platform
// specific code we make a copy of the clipboard buffer with
// "new Bit8u[length]". Then the pointer is passed into
// bx_keyb_c::paste_bytes, along with the length. The gui code never touches
// the pastebuf again, and does not free it. The keyboard code is
// responsible for deallocating the paste buffer using delete [] buf. The
// paste buffer is binary data, and it is probably NOT null terminated.
//
// Summary: A paste buffer is allocated (new) in the platform-specific gui
// code, passed to the keyboard model, and is freed (delete[]) when it is no
// longer needed.
Bit8u *pastebuf; // ptr to bytes to be pasted, or NULL if none in progress
Bit32u pastebuf_len; // length of pastebuf
Bit32u pastebuf_ptr; // ptr to next byte to be added to hw buffer
Bit32u pastedelay; // count before paste
bx_bool paste_service; // set to 1 when gen_scancode() is called from paste service
bx_bool stop_paste; // stop the current paste operation on keypress or hardware reset
BX_KEY_SMF void resetinternals(bx_bool powerup);
BX_KEY_SMF void set_kbd_clock_enable(Bit8u value) BX_CPP_AttrRegparmN(1);
BX_KEY_SMF void set_aux_clock_enable(Bit8u value);
BX_KEY_SMF void kbd_ctrl_to_kbd(Bit8u value);
BX_KEY_SMF void kbd_ctrl_to_mouse(Bit8u value);
BX_KEY_SMF void kbd_enQ(Bit8u scancode);
BX_KEY_SMF void kbd_enQ_imm(Bit8u val);
BX_KEY_SMF void activate_timer(void);
BX_KEY_SMF void controller_enQ(Bit8u data, unsigned source);
BX_KEY_SMF bx_bool mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3, Bit8u b4);
BX_KEY_SMF void mouse_enQ(Bit8u mouse_data);
static void mouse_enabled_changed_static(void *dev, bx_bool enabled);
void mouse_enabled_changed(bx_bool enabled);
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
void mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state);
static void timer_handler(void *);
void timer(void);
int timer_handle;
int statusbar_id[3];
};
#endif // #ifndef _PCKEY_H

1931
bochs/iodev/ne2k.cc Normal file

File diff suppressed because it is too large Load Diff

263
bochs/iodev/ne2k.h Normal file
View File

@ -0,0 +1,263 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.
//
// An implementation of an ne2000 ISA ethernet adapter. This part uses
// a National Semiconductor DS-8390 ethernet MAC chip, with some h/w
// to provide a windowed memory region for the chip and a MAC address.
//
#ifndef BX_IODEV_NE2K
#define BX_IODEV_NE2K
#if BX_USE_NE2K_SMF
#error Ne2K cannot user Static functions with multiple NICS
#error Change BX USER NE2K SMF in config.h to 0
# define BX_NE2K_SMF static
# define BX_NE2K_THIS theNE2kDevice->
# define BX_NE2K_THIS_PTR theNE2kDevice
#else
# define BX_NE2K_SMF
# define BX_NE2K_THIS this->
# define BX_NE2K_THIS_PTR this
#endif
#define BX_NE2K_MEMSIZ (32*1024)
#define BX_NE2K_MEMSTART (16*1024)
#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
#define BX_NE2K_MAXDEV 4
class eth_pktmover_c;
typedef struct {
//
// ne2k register state
//
// Page 0
//
// Command Register - 00h read/write
struct {
bx_bool stop; // STP - Software Reset command
bx_bool start; // START - start the NIC
bx_bool tx_packet; // TXP - initiate packet transmission
Bit8u rdma_cmd; // RD0,RD1,RD2 - Remote DMA command
Bit8u pgsel; // PS0,PS1 - Page select
} CR;
// Interrupt Status Register - 07h read/write
struct {
bx_bool pkt_rx; // PRX - packet received with no errors
bx_bool pkt_tx; // PTX - packet transmitted with no errors
bx_bool rx_err; // RXE - packet received with 1 or more errors
bx_bool tx_err; // TXE - packet tx'd " " " " "
bx_bool overwrite; // OVW - rx buffer resources exhausted
bx_bool cnt_oflow; // CNT - network tally counter MSB's set
bx_bool rdma_done; // RDC - remote DMA complete
bx_bool reset; // RST - reset status
} ISR;
// Interrupt Mask Register - 0fh write
struct {
bx_bool rx_inte; // PRXE - packet rx interrupt enable
bx_bool tx_inte; // PTXE - packet tx interrput enable
bx_bool rxerr_inte; // RXEE - rx error interrupt enable
bx_bool txerr_inte; // TXEE - tx error interrupt enable
bx_bool overw_inte; // OVWE - overwrite warn int enable
bx_bool cofl_inte; // CNTE - counter o'flow int enable
bx_bool rdma_inte; // RDCE - remote DMA complete int enable
bx_bool reserved; // D7 - reserved
} IMR;
// Data Configuration Register - 0eh write
struct {
bx_bool wdsize; // WTS - 8/16-bit select
bx_bool endian; // BOS - byte-order select
bx_bool longaddr; // LAS - long-address select
bx_bool loop; // LS - loopback select
bx_bool auto_rx; // AR - auto-remove rx packets with remote DMA
Bit8u fifo_size; // FT0,FT1 - fifo threshold
} DCR;
// Transmit Configuration Register - 0dh write
struct {
bx_bool crc_disable; // CRC - inhibit tx CRC
Bit8u loop_cntl; // LB0,LB1 - loopback control
bx_bool ext_stoptx; // ATD - allow tx disable by external mcast
bx_bool coll_prio; // OFST - backoff algorithm select
Bit8u reserved; // D5,D6,D7 - reserved
} TCR;
// Transmit Status Register - 04h read
struct {
bx_bool tx_ok; // PTX - tx complete without error
bx_bool reserved; // D1 - reserved
bx_bool collided; // COL - tx collided >= 1 times
bx_bool aborted; // ABT - aborted due to excessive collisions
bx_bool no_carrier; // CRS - carrier-sense lost
bx_bool fifo_ur; // FU - FIFO underrun
bx_bool cd_hbeat; // CDH - no tx cd-heartbeat from transceiver
bx_bool ow_coll; // OWC - out-of-window collision
} TSR;
// Receive Configuration Register - 0ch write
struct {
bx_bool errors_ok; // SEP - accept pkts with rx errors
bx_bool runts_ok; // AR - accept < 64-byte runts
bx_bool broadcast; // AB - accept eth broadcast address
bx_bool multicast; // AM - check mcast hash array
bx_bool promisc; // PRO - accept all packets
bx_bool monitor; // MON - check pkts, but don't rx
Bit8u reserved; // D6,D7 - reserved
} RCR;
// Receive Status Register - 0ch read
struct {
bx_bool rx_ok; // PRX - rx complete without error
bx_bool bad_crc; // CRC - Bad CRC detected
bx_bool bad_falign; // FAE - frame alignment error
bx_bool fifo_or; // FO - FIFO overrun
bx_bool rx_missed; // MPA - missed packet error
bx_bool rx_mbit; // PHY - unicast or mcast/bcast address match
bx_bool rx_disabled; // DIS - set when in monitor mode
bx_bool deferred; // DFR - collision active
} RSR;
Bit16u local_dma; // 01,02h read ; current local DMA addr
Bit8u page_start; // 01h write ; page start register
Bit8u page_stop; // 02h write ; page stop register
Bit8u bound_ptr; // 03h read/write ; boundary pointer
Bit8u tx_page_start; // 04h write ; transmit page start register
Bit8u num_coll; // 05h read ; number-of-collisions register
Bit16u tx_bytes; // 05,06h write ; transmit byte-count register
Bit8u fifo; // 06h read ; FIFO
Bit16u remote_dma; // 08,09h read ; current remote DMA addr
Bit16u remote_start; // 08,09h write ; remote start address register
Bit16u remote_bytes; // 0a,0bh write ; remote byte-count register
Bit8u tallycnt_0; // 0dh read ; tally counter 0 (frame align errors)
Bit8u tallycnt_1; // 0eh read ; tally counter 1 (CRC errors)
Bit8u tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors)
//
// Page 1
//
// Command Register 00h (repeated)
//
Bit8u physaddr[6]; // 01-06h read/write ; MAC address
Bit8u curr_page; // 07h read/write ; current page register
Bit8u mchash[8]; // 08-0fh read/write ; multicast hash array
//
// Page 2 - diagnostic use only
//
// Command Register 00h (repeated)
//
// Page Start Register 01h read (repeated)
// Page Stop Register 02h read (repeated)
// Current Local DMA Address 01,02h write (repeated)
// Transmit Page start address 04h read (repeated)
// Receive Configuration Register 0ch read (repeated)
// Transmit Configuration Register 0dh read (repeated)
// Data Configuration Register 0eh read (repeated)
// Interrupt Mask Register 0fh read (repeated)
//
Bit8u rempkt_ptr; // 03h read/write ; remote next-packet pointer
Bit8u localpkt_ptr; // 05h read/write ; local next-packet pointer
Bit16u address_cnt; // 06,07h read/write ; address counter
//
// Page 3 - should never be modified.
//
// Novell ASIC state
Bit8u macaddr[32]; // ASIC ROM'd MAC address, even bytes
Bit8u mem[BX_NE2K_MEMSIZ]; // on-chip packet memory
// ne2k internal state
Bit32u base_address;
int base_irq;
int tx_timer_index;
bx_bool tx_timer_active;
// pci stuff
bx_bool pci_enabled;
#if BX_SUPPORT_PCI
Bit8u devfunc;
Bit8u pci_conf[256];
#endif
} bx_ne2k_t;
class bx_ne2k_c : public bx_ne2k_stub_c
#if BX_SUPPORT_PCI
, public bx_pci_device_stub_c
#endif
{
public:
bx_ne2k_c();
virtual ~bx_ne2k_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void print_info (FILE *file, int page, int reg, int nodups);
virtual void register_state(void);
#if BX_SUPPORT_PCI
virtual void after_restore_state(void);
#endif
#if BX_SUPPORT_PCI
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
#endif
int interfaceNo;
private:
bx_ne2k_t s;
eth_pktmover_c *ethdev;
BX_NE2K_SMF Bit32u read_cr(void);
BX_NE2K_SMF void write_cr(Bit32u value);
BX_NE2K_SMF void set_irq_level(bx_bool level);
BX_NE2K_SMF Bit32u chipmem_read(Bit32u address, unsigned io_len) BX_CPP_AttrRegparmN(2);
BX_NE2K_SMF Bit32u asic_read(Bit32u offset, unsigned io_len) BX_CPP_AttrRegparmN(2);
BX_NE2K_SMF Bit32u page0_read(Bit32u offset, unsigned io_len);
BX_NE2K_SMF Bit32u page1_read(Bit32u offset, unsigned io_len);
BX_NE2K_SMF Bit32u page2_read(Bit32u offset, unsigned io_len);
BX_NE2K_SMF Bit32u page3_read(Bit32u offset, unsigned io_len);
BX_NE2K_SMF void chipmem_write(Bit32u address, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
BX_NE2K_SMF void asic_write(Bit32u address, Bit32u value, unsigned io_len);
BX_NE2K_SMF void page0_write(Bit32u address, Bit32u value, unsigned io_len);
BX_NE2K_SMF void page1_write(Bit32u address, Bit32u value, unsigned io_len);
BX_NE2K_SMF void page2_write(Bit32u address, Bit32u value, unsigned io_len);
BX_NE2K_SMF void page3_write(Bit32u address, Bit32u value, unsigned io_len);
static void tx_timer_handler(void *);
BX_NE2K_SMF void tx_timer(void);
static void rx_handler(void *arg, const void *buf, unsigned len);
BX_NE2K_SMF unsigned mcast_index(const void *dst);
BX_NE2K_SMF void rx_frame(const void *buf, unsigned io_len);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_NE2K_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

343
bochs/iodev/parallel.cc Normal file
View File

@ -0,0 +1,343 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
////////////////////////////////////////////////////////
// This code was just a few stubs until Volker.Ruppert@t-online.de
// fixed it up in November 2001.
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "parallel.h"
#define LOG_THIS theParallelDevice->
bx_parallel_c *theParallelDevice = NULL;
int libparallel_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theParallelDevice = new bx_parallel_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theParallelDevice, BX_PLUGIN_PARALLEL);
return(0); // Success
}
void libparallel_LTX_plugin_fini(void)
{
delete theParallelDevice;
}
bx_parallel_c::bx_parallel_c()
{
put("PAR");
for (int i=0; i<BX_PARPORT_MAXDEV; i++) {
s[i].output = NULL;
}
}
bx_parallel_c::~bx_parallel_c()
{
for (int i=0; i<BX_PARPORT_MAXDEV; i++) {
if (s[i].output != NULL)
fclose(s[i].output);
}
BX_DEBUG(("Exit"));
}
void bx_parallel_c::init(void)
{
Bit16u ports[BX_PARPORT_MAXDEV] = {0x0378, 0x0278};
Bit8u irqs[BX_PARPORT_MAXDEV] = {7, 5};
char name[16], pname[20];
bx_list_c *base;
BX_DEBUG(("Init $Id$"));
for (unsigned i=0; i<BX_N_PARALLEL_PORTS; i++) {
sprintf(pname, "ports.parallel.%d", i+1);
base = (bx_list_c*) SIM->get_param(pname);
if (SIM->get_param_bool("enabled", base)->get()) {
sprintf(name, "Parallel Port %d", i + 1);
/* parallel interrupt and i/o ports */
BX_PAR_THIS s[i].IRQ = irqs[i];
for (unsigned addr=ports[i]; addr<=(unsigned)(ports[i]+2); addr++) {
DEV_register_ioread_handler(this, read_handler, addr, name, 1);
}
DEV_register_iowrite_handler(this, write_handler, ports[i], name, 1);
DEV_register_iowrite_handler(this, write_handler, ports[i]+2, name, 1);
BX_INFO (("parallel port %d at 0x%04x irq %d", i+1, ports[i], irqs[i]));
/* internal state */
BX_PAR_THIS s[i].STATUS.error = 1;
BX_PAR_THIS s[i].STATUS.slct = 1;
BX_PAR_THIS s[i].STATUS.pe = 0;
BX_PAR_THIS s[i].STATUS.ack = 1;
BX_PAR_THIS s[i].STATUS.busy = 1;
BX_PAR_THIS s[i].CONTROL.strobe = 0;
BX_PAR_THIS s[i].CONTROL.autofeed = 0;
BX_PAR_THIS s[i].CONTROL.init = 1;
BX_PAR_THIS s[i].CONTROL.slct_in = 1;
BX_PAR_THIS s[i].CONTROL.irq = 0;
BX_PAR_THIS s[i].CONTROL.input = 0;
BX_PAR_THIS s[i].initmode = 0;
/* output file */
char *outfile = SIM->get_param_string("outfile", base)->getptr();
if (strlen(outfile) > 0) {
s[i].output = fopen(outfile, "wb");
if (!s[i].output)
BX_PANIC(("Could not open '%s' to write parport%d output",
outfile, i+1));
}
}
}
}
void bx_parallel_c::reset(unsigned type)
{
}
void bx_parallel_c::register_state(void)
{
unsigned i;
char name[4], pname[20];
bx_list_c *base, *port;
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "parallel", "Parallel Port State", BX_N_PARALLEL_PORTS);
for (i=0; i<BX_N_PARALLEL_PORTS; i++) {
sprintf(pname, "ports.parallel.%d", i+1);
base = (bx_list_c*) SIM->get_param(pname);
if (SIM->get_param_bool("enabled", base)->get()) {
sprintf(name, "%d", i);
port = new bx_list_c(list, name, 11);
new bx_shadow_num_c(port, "data", &BX_PAR_THIS s[i].data, BASE_HEX);
new bx_shadow_bool_c(port, "slct", &BX_PAR_THIS s[i].STATUS.slct);
new bx_shadow_bool_c(port, "ack", &BX_PAR_THIS s[i].STATUS.ack);
new bx_shadow_bool_c(port, "busy", &BX_PAR_THIS s[i].STATUS.busy);
new bx_shadow_bool_c(port, "strobe", &BX_PAR_THIS s[i].CONTROL.strobe);
new bx_shadow_bool_c(port, "autofeed", &BX_PAR_THIS s[i].CONTROL.autofeed);
new bx_shadow_bool_c(port, "init", &BX_PAR_THIS s[i].CONTROL.init);
new bx_shadow_bool_c(port, "slct_in", &BX_PAR_THIS s[i].CONTROL.slct_in);
new bx_shadow_bool_c(port, "irq", &BX_PAR_THIS s[i].CONTROL.irq);
new bx_shadow_bool_c(port, "input", &BX_PAR_THIS s[i].CONTROL.input);
new bx_shadow_bool_c(port, "initmode", &BX_PAR_THIS s[i].initmode);
}
}
}
void bx_parallel_c::virtual_printer(Bit8u port)
{
if (BX_PAR_THIS s[port].STATUS.slct) {
if (BX_PAR_THIS s[port].output != NULL) {
fputc(BX_PAR_THIS s[port].data, BX_PAR_THIS s[port].output);
fflush (BX_PAR_THIS s[port].output);
}
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
DEV_pic_raise_irq(BX_PAR_THIS s[port].IRQ);
}
BX_PAR_THIS s[port].STATUS.ack = 0;
BX_PAR_THIS s[port].STATUS.busy = 1;
}
else {
BX_ERROR(("data is valid, but printer is offline"));
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_parallel_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PAR_SMF
bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_parallel_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PAR_SMF
Bit8u offset;
Bit8u port = 0;
Bit32u retval;
offset = address & 0x07;
switch (address & 0x03f8) {
case 0x0378: port = 0; break;
case 0x0278: port = 1; break;
}
switch (offset) {
case BX_PAR_DATA:
if (!BX_PAR_THIS s[port].CONTROL.input) {
return (Bit32u)BX_PAR_THIS s[port].data;
} else {
BX_ERROR(("read: input mode not supported"));
return (0xFF);
}
break;
case BX_PAR_STAT:
{
retval = ((BX_PAR_THIS s[port].STATUS.busy << 7) |
(BX_PAR_THIS s[port].STATUS.ack << 6) |
(BX_PAR_THIS s[port].STATUS.pe << 5) |
(BX_PAR_THIS s[port].STATUS.slct << 4) |
(BX_PAR_THIS s[port].STATUS.error << 3));
if (BX_PAR_THIS s[port].STATUS.ack == 0) {
BX_PAR_THIS s[port].STATUS.ack = 1;
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
DEV_pic_lower_irq(BX_PAR_THIS s[port].IRQ);
}
}
if (BX_PAR_THIS s[port].initmode == 1) {
BX_PAR_THIS s[port].STATUS.busy = 1;
BX_PAR_THIS s[port].STATUS.slct = 1;
BX_PAR_THIS s[port].STATUS.ack = 0;
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
DEV_pic_raise_irq(BX_PAR_THIS s[port].IRQ);
}
BX_PAR_THIS s[port].initmode = 0;
}
BX_DEBUG(("read: parport%d status register returns 0x%02x", port+1, retval));
return retval;
}
break;
case BX_PAR_CTRL:
{
retval = ((BX_PAR_THIS s[port].CONTROL.input << 5) |
(BX_PAR_THIS s[port].CONTROL.irq << 4) |
(BX_PAR_THIS s[port].CONTROL.slct_in << 3) |
(BX_PAR_THIS s[port].CONTROL.init << 2) |
(BX_PAR_THIS s[port].CONTROL.autofeed << 1) |
(BX_PAR_THIS s[port].CONTROL.strobe));
BX_DEBUG(("read: parport%d control register returns 0x%02x", port+1, retval));
return retval;
}
break;
}
return(0);
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_parallel_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PAR_SMF
bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_parallel_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PAR_SMF
Bit8u offset;
Bit8u port = 0;
char name[16];
offset = address & 0x07;
switch (address & 0x03f8) {
case 0x0378: port = 0; break;
case 0x0278: port = 1; break;
}
switch (offset) {
case BX_PAR_DATA:
BX_PAR_THIS s[port].data = (Bit8u)value;
BX_DEBUG(("write: parport%d data output register = 0x%02x", port+1, (Bit8u)value));
break;
case BX_PAR_CTRL:
{
if ((value & 0x01) == 0x01) {
if (BX_PAR_THIS s[port].CONTROL.strobe == 0) {
BX_PAR_THIS s[port].CONTROL.strobe = 1;
virtual_printer(port); // data is valid now
}
} else {
if (BX_PAR_THIS s[port].CONTROL.strobe == 1) {
BX_PAR_THIS s[port].CONTROL.strobe = 0;
}
}
BX_PAR_THIS s[port].CONTROL.autofeed = ((value & 0x02) == 0x02);
if ((value & 0x04) == 0x04) {
if (BX_PAR_THIS s[port].CONTROL.init == 0) {
BX_PAR_THIS s[port].CONTROL.init = 1;
BX_PAR_THIS s[port].STATUS.busy = 0;
BX_PAR_THIS s[port].STATUS.slct = 0;
BX_PAR_THIS s[port].initmode = 1;
BX_DEBUG(("parport%d: printer init requested", port+1));
}
} else {
if (BX_PAR_THIS s[port].CONTROL.init == 1) {
BX_PAR_THIS s[port].CONTROL.init = 0;
}
}
if ((value & 0x08) == 0x08) {
if (BX_PAR_THIS s[port].CONTROL.slct_in == 0) {
BX_PAR_THIS s[port].CONTROL.slct_in = 1;
BX_DEBUG(("parport%d: printer now online", port+1));
}
} else {
if (BX_PAR_THIS s[port].CONTROL.slct_in == 1) {
BX_PAR_THIS s[port].CONTROL.slct_in = 0;
BX_DEBUG(("parport%d: printer now offline", port+1));
}
}
BX_PAR_THIS s[port].STATUS.slct = BX_PAR_THIS s[port].CONTROL.slct_in;
if ((value & 0x10) == 0x10) {
if (BX_PAR_THIS s[port].CONTROL.irq == 0) {
BX_PAR_THIS s[port].CONTROL.irq = 1;
sprintf(name, "Parallel Port %d", port+1);
DEV_register_irq(BX_PAR_THIS s[port].IRQ, name);
BX_DEBUG(("parport%d: irq mode selected", port+1));
}
} else {
if (BX_PAR_THIS s[port].CONTROL.irq == 1) {
BX_PAR_THIS s[port].CONTROL.irq = 0;
sprintf(name, "Parallel Port %d", port+1);
DEV_unregister_irq(BX_PAR_THIS s[port].IRQ, name);
BX_DEBUG(("parport%d: polling mode selected", port+1));
}
}
if ((value & 0x20) == 0x20) {
if (BX_PAR_THIS s[port].CONTROL.input == 0) {
BX_PAR_THIS s[port].CONTROL.input = 1;
BX_DEBUG(("parport%d: data input mode selected", port+1));
}
} else {
if (BX_PAR_THIS s[port].CONTROL.input == 1) {
BX_PAR_THIS s[port].CONTROL.input = 0;
BX_DEBUG(("parport%d: data output mode selected", port+1));
}
}
if ((value & 0xC0) > 0) {
BX_ERROR(("write: parport%d: unsupported control bit ignored", port+1));
}
}
break;
}
}

81
bochs/iodev/parallel.h Normal file
View File

@ -0,0 +1,81 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PARPORT_H
#define BX_IODEV_PARPORT_H
#if BX_USE_PAR_SMF
# define BX_PAR_SMF static
# define BX_PAR_THIS theParallelDevice->
#else
# define BX_PAR_SMF
# define BX_PAR_THIS this->
#endif
#define BX_PARPORT_MAXDEV 2
#define BX_PAR_DATA 0
#define BX_PAR_STAT 1
#define BX_PAR_CTRL 2
typedef struct {
Bit8u data;
struct {
bx_bool error;
bx_bool slct;
bx_bool pe;
bx_bool ack;
bx_bool busy;
} STATUS;
struct {
bx_bool strobe;
bx_bool autofeed;
bx_bool init;
bx_bool slct_in;
bx_bool irq;
bx_bool input;
} CONTROL;
Bit8u IRQ;
FILE *output;
bx_bool initmode;
} bx_par_t;
class bx_parallel_c : public bx_devmodel_c {
public:
bx_parallel_c();
virtual ~bx_parallel_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
private:
bx_par_t s[BX_PARPORT_MAXDEV];
static void virtual_printer(Bit8u port);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PAR_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

603
bochs/iodev/pci.cc Normal file
View File

@ -0,0 +1,603 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// i440FX Support - PMC/DBX
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI
#include "pci.h"
#define LOG_THIS thePciBridge->
bx_pci_bridge_c *thePciBridge = NULL;
int libpci_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePciBridge = new bx_pci_bridge_c();
bx_devices.pluginPciBridge = thePciBridge;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciBridge, BX_PLUGIN_PCI);
return(0); // Success
}
void libpci_LTX_plugin_fini(void)
{
delete thePciBridge;
}
bx_pci_bridge_c::bx_pci_bridge_c()
{
put("PCI");
}
bx_pci_bridge_c::~bx_pci_bridge_c()
{
debug_dump();
BX_DEBUG(("Exit"));
}
void bx_pci_bridge_c::init(void)
{
// called once when bochs initializes
unsigned i;
BX_PCI_THIS num_pci_handlers = 0;
/* set unused elements to appropriate values */
for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
BX_PCI_THIS pci_handler[i].handler = NULL;
}
for (i=0; i < 0x100; i++) {
BX_PCI_THIS pci_handler_id[i] = BX_MAX_PCI_DEVICES; // not assigned
}
for (i=0; i < BX_N_PCI_SLOTS; i++) {
BX_PCI_THIS slot_used[i] = 0; // no device connected
}
BX_PCI_THIS slots_checked = 0;
// confAddr accepts dword i/o only
DEV_register_ioread_handler(this, read_handler, 0x0CF8, "i440FX", 4);
DEV_register_iowrite_handler(this, write_handler, 0x0CF8, "i440FX", 4);
for (i=0x0CFC; i<=0x0CFF; i++) {
DEV_register_ioread_handler(this, read_handler, i, "i440FX", 7);
}
for (i=0x0CFC; i<=0x0CFF; i++) {
DEV_register_iowrite_handler(this, write_handler, i, "i440FX", 7);
}
Bit8u devfunc = BX_PCI_DEVICE(0,0);
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI, "440FX Host bridge");
for (i=0; i<256; i++)
BX_PCI_THIS s.i440fx.pci_conf[i] = 0x0;
// readonly registers
BX_PCI_THIS s.i440fx.pci_conf[0x00] = 0x86;
BX_PCI_THIS s.i440fx.pci_conf[0x01] = 0x80;
BX_PCI_THIS s.i440fx.pci_conf[0x02] = 0x37;
BX_PCI_THIS s.i440fx.pci_conf[0x03] = 0x12;
BX_PCI_THIS s.i440fx.pci_conf[0x0b] = 0x06;
}
void
bx_pci_bridge_c::reset(unsigned type)
{
unsigned i;
char devname[80];
char *device;
if (!BX_PCI_THIS slots_checked) {
for (i=0; i<BX_N_PCI_SLOTS; i++) {
sprintf(devname, "pci.slot.%d", i+1);
device = SIM->get_param_string(devname)->getptr();
if ((strlen(device) > 0) && !BX_PCI_THIS slot_used[i]) {
BX_PANIC(("Unknown plugin '%s' at PCI slot #%d", device, i+1));
}
}
BX_PCI_THIS slots_checked = 1;
}
BX_PCI_THIS s.i440fx.confAddr = 0;
BX_PCI_THIS s.i440fx.confData = 0;
BX_PCI_THIS s.i440fx.pci_conf[0x04] = 0x06;
BX_PCI_THIS s.i440fx.pci_conf[0x05] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x06] = 0x80;
BX_PCI_THIS s.i440fx.pci_conf[0x07] = 0x02;
BX_PCI_THIS s.i440fx.pci_conf[0x0d] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x0f] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x50] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x51] = 0x01;
BX_PCI_THIS s.i440fx.pci_conf[0x52] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x53] = 0x80;
BX_PCI_THIS s.i440fx.pci_conf[0x54] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x55] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x56] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x57] = 0x01;
BX_PCI_THIS s.i440fx.pci_conf[0x58] = 0x10;
for (i=0x59; i<0x60; i++)
BX_PCI_THIS s.i440fx.pci_conf[i] = 0x00;
BX_PCI_THIS s.i440fx.pci_conf[0x72] = 0x02;
}
void bx_pci_bridge_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_bridge", "PCI Bridge State", 3);
BXRS_HEX_PARAM_FIELD(list, confAddr, BX_PCI_THIS s.i440fx.confAddr);
BXRS_HEX_PARAM_FIELD(list, confData, BX_PCI_THIS s.i440fx.confData);
bx_list_c *pci_conf = new bx_list_c(list, "pci_conf", 256);
for (unsigned i=0; i<256; i++) {
char name[6];
sprintf(name, "0x%02x", i);
new bx_shadow_num_c(pci_conf, name, &BX_PCI_THIS s.i440fx.pci_conf[i], BASE_HEX);
}
}
void bx_pci_bridge_c::after_restore_state(void)
{
BX_PCI_THIS smram_control(BX_PCI_THIS s.i440fx.pci_conf[0x72]);
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_pci_bridge_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PCI_SMF
bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_pci_bridge_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PCI_SMF
switch (address) {
case 0x0CF8:
return BX_PCI_THIS s.i440fx.confAddr;
case 0x0CFC:
case 0x0CFD:
case 0x0CFE:
case 0x0CFF:
{
Bit32u handle, retval;
Bit8u devfunc, regnum;
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
handle = BX_PCI_THIS pci_handler_id[devfunc];
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES))
retval = BX_PCI_THIS pci_handler[handle].handler->pci_read_handler(regnum, io_len);
else
retval = 0xFFFFFFFF;
}
else
retval = 0xFFFFFFFF;
BX_PCI_THIS s.i440fx.confData = retval;
return retval;
}
}
BX_PANIC(("unsupported IO read to port 0x%x", (unsigned) address));
return(0xffffffff);
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_pci_bridge_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PCI_SMF
bx_pci_bridge_c *class_ptr = (bx_pci_bridge_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_pci_bridge_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PCI_SMF
switch (address) {
case 0xCF8:
BX_PCI_THIS s.i440fx.confAddr = value;
if ((value & 0x80FFFF00) == 0x80000000) {
BX_DEBUG(("440FX PMC register 0x%02x selected", value & 0xfc));
} else if ((value & 0x80000000) == 0x80000000) {
BX_DEBUG(("440FX request for bus 0x%02x device 0x%02x function 0x%02x",
(value >> 16) & 0xFF, (value >> 11) & 0x1F, (value >> 8) & 0x07));
}
break;
case 0xCFC:
case 0xCFD:
case 0xCFE:
case 0xCFF:
if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
Bit8u devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
Bit8u regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
Bit32u handle = BX_PCI_THIS pci_handler_id[devfunc];
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
if (((regnum>=4) && (regnum<=7)) || (regnum==12) || (regnum==13) || (regnum>14)) {
BX_PCI_THIS pci_handler[handle].handler->pci_write_handler(regnum, value, io_len);
BX_PCI_THIS s.i440fx.confData = value << (8 * (address & 0x03));
}
else
BX_DEBUG(("read only register, write ignored"));
}
}
break;
default:
BX_PANIC(("IO write to port 0x%x", (unsigned) address));
}
}
// pci configuration space read callback handler
Bit32u bx_pci_bridge_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_PCI_THIS s.i440fx.pci_conf[address+i] << (i*8));
}
BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x", address, value));
return value;
}
// pci configuration space write callback handler
void bx_pci_bridge_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
Bit8u value8;
if ((address >= 0x10) && (address < 0x34))
return;
for (unsigned i=0; i<io_len; i++) {
value8 = (value >> (i*8)) & 0xFF;
switch (address+i) {
case 0x04:
BX_PCI_THIS s.i440fx.pci_conf[address+i] = (value8 & 0x40) | 0x06;
break;
case 0x06:
case 0x0c:
break;
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
BX_INFO(("440FX PMC write to PAM register %x (TLB Flush)", address+i));
BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
bx_pc_system.MemoryMappingChanged();
break;
case 0x72:
smram_control(value); // SMRAM conrol register
break;
default:
BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x", address+i, value8));
}
}
}
void bx_pci_bridge_c::smram_control(Bit8u value8)
{
//
// From i440FX chipset manual:
//
// [7:7] Reserved.
// [6:6] SMM Space Open (DOPEN), when DOPEN=1 and DLCK=0, SMM space DRAM
// became visible even CPU not indicte SMM mode access. This is
// indended to help BIOS to initialize SMM space.
// [5:5] SMM Space Closed (DCLS), when DCLS=1, SMM space is not accessible
// for data references, even if CPU indicates SMM mode access. Code
// references may still access SMM space DRAM.
// [4:4] SMM Space Locked (DLCK), when DLCK=1, DOPEN is set to 0 and
// both DLCK and DOPEN became R/O. DLCK can only be cleared by
// a power-on reset.
// [3:3] SMRAM Enable (SMRAME)
// [2:0] SMM space base segment, program the location of SMM space
// reserved.
//
// SMRAM space access cycles:
// | SMRAME | DLCK | DCLS | DOPEN | CPU_SMM | | Code | Data |
// ------------------------------------------ ---------------
// | 0 | X | X | X | X | -> | PCI | PCI |
// | 1 | 0 | X | 0 | 0 | -> | PCI | PCI |
// | 1 | 0 | 0 | 0 | 1 | -> | DRAM | DRAM |
// | 1 | 0 | 0 | 1 | X | -> | DRAM | DRAM |
// | 1 | 1 | 0 | X | 1 | -> | DRAM | DRAM |
// | 1 | 0 | 1 | 0 | 1 | -> | DRAM | PCI |
// | 1 | 0 | 1 | 1 | X | -> | ---- | ---- |
// | 1 | 1 | X | X | 0 | -> | PCI | PCI |
// | 1 | 1 | 1 | X | 1 | -> | DRAM | PCI |
// ------------------------------------------ ---------------
value8 = (value8 & 0x78) | 0x2; // ignore reserved bits
if (BX_PCI_THIS s.i440fx.pci_conf[0x72] & 0x10)
{
value8 &= 0xbf; // set DOPEN=0, DLCK=1
value8 |= 0x10;
}
if ((value8 & 0x08) == 0) {
bx_devices.mem->disable_smram();
}
else {
bx_bool DOPEN = (value8 & 0x40) > 0, DCLS = (value8 & 0x20) > 0;
if(DOPEN && DCLS) BX_PANIC(("SMRAM control: DOPEN not mutually exclusive with DCLS !"));
bx_devices.mem->enable_smram(DOPEN, DCLS);
}
BX_INFO(("setting SMRAM control register to 0x%02x", value8));
BX_PCI_THIS s.i440fx.pci_conf[0x72] = value8;
}
Bit8u bx_pci_bridge_c::rd_memType(Bit32u addr)
{
switch ((addr & 0xFC000) >> 12) {
case 0xC0:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5A] & 0x1);
case 0xC4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 4) & 0x1);
case 0xC8:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5B] & 0x1);
case 0xCC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 4) & 0x1);
case 0xD0:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5C] & 0x1);
case 0xD4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 4) & 0x1);
case 0xD8:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5D] & 0x1);
case 0xDC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 4) & 0x1);
case 0xE0:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5E] & 0x1);
case 0xE4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 4) & 0x1);
case 0xE8:
return (BX_PCI_THIS s.i440fx.pci_conf[0x5F] & 0x1);
case 0xEC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 4) & 0x1);
case 0xF0:
case 0xF4:
case 0xF8:
case 0xFC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 4) & 0x1);
default:
BX_PANIC(("rd_memType () Error: Memory Type not known !"));
break;
}
return(0); // keep compiler happy
}
Bit8u bx_pci_bridge_c::wr_memType(Bit32u addr)
{
switch ((addr & 0xFC000) >> 12) {
case 0xC0:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 1) & 0x1);
case 0xC4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 5) & 0x1);
case 0xC8:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 1) & 0x1);
case 0xCC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 5) & 0x1);
case 0xD0:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 1) & 0x1);
case 0xD4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 5) & 0x1);
case 0xD8:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 1) & 0x1);
case 0xDC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 5) & 0x1);
case 0xE0:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 1) & 0x1);
case 0xE4:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 5) & 0x1);
case 0xE8:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 1) & 0x1);
case 0xEC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 5) & 0x1);
case 0xF0:
case 0xF4:
case 0xF8:
case 0xFC:
return ((BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 5) & 0x1);
default:
BX_PANIC(("wr_memType () Error: Memory Type not known !"));
break;
}
return(0); // keep compiler happy
}
void bx_pci_bridge_c::debug_dump()
{
int i;
BX_DEBUG(("i440fxConfAddr:0x%08x", BX_PCI_THIS s.i440fx.confAddr));
BX_DEBUG(("i440fxConfData:0x%08x", BX_PCI_THIS s.i440fx.confData));
#ifdef DUMP_FULL_I440FX
for (i=0; i<256; i++) {
BX_DEBUG(("i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i]));
}
#else /* DUMP_FULL_I440FX */
for (i=0x59; i<0x60; i++) {
BX_DEBUG(("i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i]));
}
#endif /* DUMP_FULL_I440FX */
}
bx_bool bx_pci_bridge_c::register_pci_handlers(bx_pci_device_stub_c *dev,
Bit8u *devfunc, const char *name,
const char *descr)
{
unsigned i, handle;
char devname[80];
char *device;
if (strcmp(name, "pci") && strcmp(name, "pci2isa") && strcmp(name, "pci_ide")
&& (*devfunc == 0x00)) {
for (i = 0; i < BX_N_PCI_SLOTS; i++) {
sprintf(devname, "pci.slot.%d", i+1);
device = SIM->get_param_string(devname)->getptr();
if ((strlen(device) > 0) && (!strcmp(name, device))) {
*devfunc = (i + 2) << 3;
BX_PCI_THIS slot_used[i] = 1;
BX_INFO(("PCI slot #%d used by plugin '%s'", i+1, name));
break;
}
}
if (*devfunc == 0x00) {
BX_ERROR(("Plugin '%s' not connected to a PCI slot", name));
}
}
/* check if device/function is available */
if (BX_PCI_THIS pci_handler_id[*devfunc] == BX_MAX_PCI_DEVICES) {
if (BX_PCI_THIS num_pci_handlers >= BX_MAX_PCI_DEVICES) {
BX_INFO(("too many PCI devices installed."));
BX_PANIC((" try increasing BX_MAX_PCI_DEVICES"));
return false;
}
handle = BX_PCI_THIS num_pci_handlers++;
BX_PCI_THIS pci_handler[handle].handler = dev;
BX_PCI_THIS pci_handler_id[*devfunc] = handle;
BX_INFO(("%s present at device %d, function %d", descr, *devfunc >> 3,
*devfunc & 0x07));
return true; // device/function mapped successfully
}
else {
return false; // device/function not available, return false.
}
}
bx_bool bx_pci_bridge_c::is_pci_device(const char *name)
{
unsigned i;
char devname[80];
char *device;
for (i = 0; i < BX_N_PCI_SLOTS; i++) {
sprintf(devname, "pci.slot.%d", i+1);
device = SIM->get_param_string(devname)->getptr();
if ((strlen(device) > 0) && (!strcmp(name, device))) {
return 1;
}
}
return 0;
}
bx_bool bx_pci_bridge_c::pci_set_base_mem(void *this_ptr, memory_handler_t f1, memory_handler_t f2,
Bit32u *addr, Bit8u *pci_conf, unsigned size)
{
Bit32u newbase;
Bit32u oldbase = *addr;
Bit32u mask = ~(size - 1);
Bit8u pci_flags = pci_conf[0x00] & 0x0f;
if ((pci_flags & 0x06) > 0) {
BX_PANIC(("PCI base memory flag 0x%02x not supported", pci_flags));
return 0;
}
pci_conf[0x00] &= (mask & 0xf0);
pci_conf[0x01] &= (mask >> 8) & 0xff;
pci_conf[0x02] &= (mask >> 16) & 0xff;
pci_conf[0x03] &= (mask >> 24) & 0xff;
ReadHostDWordFromLittleEndian(pci_conf, newbase);
pci_conf[0x00] |= pci_flags;
if ((newbase != mask) && (newbase != oldbase)) { // skip PCI probe
if (oldbase > 0) {
DEV_unregister_memory_handlers(f1, f2, oldbase, oldbase + size - 1);
}
if (newbase > 0) {
DEV_register_memory_handlers(this_ptr, f1, f2, newbase, newbase + size - 1);
}
*addr = newbase;
return 1;
}
return 0;
}
bx_bool bx_pci_bridge_c::pci_set_base_io(void *this_ptr, bx_read_handler_t f1, bx_write_handler_t f2,
Bit32u *addr, Bit8u *pci_conf, unsigned size,
const Bit8u *iomask, const char *name)
{
unsigned i;
Bit32u newbase;
Bit32u oldbase = *addr;
Bit16u mask = ~(size - 1);
Bit8u pci_flags = pci_conf[0x00] & 0x03;
pci_conf[0x00] &= (mask & 0xfc);
pci_conf[0x01] &= (mask >> 8);
ReadHostDWordFromLittleEndian(pci_conf, newbase);
pci_conf[0x00] |= pci_flags;
if (((newbase & 0xfffc) != mask) && (newbase != oldbase)) { // skip PCI probe
if (oldbase > 0) {
for (i=0; i<size; i++) {
if (iomask[i] > 0) {
DEV_unregister_ioread_handler(this_ptr, f1, oldbase + i, iomask[i]);
DEV_unregister_iowrite_handler(this_ptr, f2, oldbase + i, iomask[i]);
}
}
}
if (newbase > 0) {
for (i=0; i<size; i++) {
if (iomask[i] > 0) {
DEV_register_ioread_handler(this_ptr, f1, newbase + i, name, iomask[i]);
DEV_register_iowrite_handler(this_ptr, f2, newbase + i, name, iomask[i]);
}
}
}
*addr = newbase;
return 1;
}
return 0;
}
#endif /* BX_SUPPORT_PCI */

100
bochs/iodev/pci.h Normal file
View File

@ -0,0 +1,100 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PCI_BRIDGE_H
#define BX_IODEV_PCI_BRIDGE_H
#define BX_MAX_PCI_DEVICES 20
#define BX_PCI_DEVICE(device, function) ((device)<<3 | (function))
#if BX_USE_PCI_SMF
# define BX_PCI_SMF static
# define BX_PCI_THIS thePciBridge->
#else
# define BX_PCI_SMF
# define BX_PCI_THIS this->
#endif
#define BX_PCI_INTA 1
#define BX_PCI_INTB 2
#define BX_PCI_INTC 3
#define BX_PCI_INTD 4
typedef struct {
Bit32u confAddr;
Bit32u confData;
Bit8u pci_conf[256];
} bx_def440fx_t;
class bx_pci_device_stub_c;
class bx_pci_bridge_c : public bx_pci_bridge_stub_c {
public:
bx_pci_bridge_c();
virtual ~bx_pci_bridge_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual bx_bool register_pci_handlers(bx_pci_device_stub_c *device,
Bit8u *devfunc, const char *name,
const char *descr);
virtual bx_bool is_pci_device(const char *name);
virtual bx_bool pci_set_base_mem(void *this_ptr, memory_handler_t f1,
memory_handler_t f2, Bit32u *addr,
Bit8u *pci_conf, unsigned size);
virtual bx_bool pci_set_base_io(void *this_ptr, bx_read_handler_t f1,
bx_write_handler_t f2, Bit32u *addr,
Bit8u *pci_conf, unsigned size,
const Bit8u *iomask, const char *name);
virtual Bit8u rd_memType(Bit32u addr);
virtual Bit8u wr_memType(Bit32u addr);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
virtual void debug_dump(void);
private:
Bit8u pci_handler_id[0x100]; // 256 devices/functions
struct {
bx_pci_device_stub_c *handler;
} pci_handler[BX_MAX_PCI_DEVICES];
unsigned num_pci_handlers;
bx_bool slot_used[BX_N_PCI_SLOTS];
bx_bool slots_checked;
struct {
bx_def440fx_t i440fx;
} s;
void smram_control(Bit8u value);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PCI_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

377
bochs/iodev/pci2isa.cc Normal file
View File

@ -0,0 +1,377 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// i440FX Support - PCI-to-ISA bridge (PIIX3)
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI
#include "pci.h"
#include "pci2isa.h"
#define LOG_THIS thePci2IsaBridge->
bx_piix3_c *thePci2IsaBridge = NULL;
int libpci2isa_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePci2IsaBridge = new bx_piix3_c();
bx_devices.pluginPci2IsaBridge = thePci2IsaBridge;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePci2IsaBridge, BX_PLUGIN_PCI2ISA);
return(0); // Success
}
void libpci2isa_LTX_plugin_fini(void)
{
delete thePci2IsaBridge;
}
bx_piix3_c::bx_piix3_c()
{
put("P2I");
}
bx_piix3_c::~bx_piix3_c()
{
BX_DEBUG(("Exit"));
}
void bx_piix3_c::init(void)
{
unsigned i;
// called once when bochs initializes
Bit8u devfunc = BX_PCI_DEVICE(1,0);
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCI2ISA,
"PIIX3 PCI-to-ISA bridge");
DEV_register_iowrite_handler(this, write_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_iowrite_handler(this, write_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_iowrite_handler(this, write_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_iowrite_handler(this, write_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_ioread_handler(this, read_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_ioread_handler(this, read_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_ioread_handler(this, read_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_ioread_handler(this, read_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
DEV_register_ioread_handler(this, read_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
for (i=0; i<256; i++)
BX_P2I_THIS s.pci_conf[i] = 0x0;
for (i=0; i<16; i++)
BX_P2I_THIS s.irq_registry[i] = 0x0;
for (i=0; i<16; i++)
BX_P2I_THIS s.irq_level[i] = 0x0;
// readonly registers
BX_P2I_THIS s.pci_conf[0x00] = 0x86;
BX_P2I_THIS s.pci_conf[0x01] = 0x80;
BX_P2I_THIS s.pci_conf[0x02] = 0x00;
BX_P2I_THIS s.pci_conf[0x03] = 0x70;
BX_P2I_THIS s.pci_conf[0x04] = 0x07;
BX_P2I_THIS s.pci_conf[0x0a] = 0x01;
BX_P2I_THIS s.pci_conf[0x0b] = 0x06;
BX_P2I_THIS s.pci_conf[0x0e] = 0x80;
// irq routing registers
BX_P2I_THIS s.pci_conf[0x60] = 0x80;
BX_P2I_THIS s.pci_conf[0x61] = 0x80;
BX_P2I_THIS s.pci_conf[0x62] = 0x80;
BX_P2I_THIS s.pci_conf[0x63] = 0x80;
}
void bx_piix3_c::reset(unsigned type)
{
BX_P2I_THIS s.pci_conf[0x05] = 0x00;
BX_P2I_THIS s.pci_conf[0x06] = 0x00;
BX_P2I_THIS s.pci_conf[0x07] = 0x02;
BX_P2I_THIS s.pci_conf[0x4c] = 0x4d;
BX_P2I_THIS s.pci_conf[0x4e] = 0x03;
BX_P2I_THIS s.pci_conf[0x4f] = 0x00;
BX_P2I_THIS s.pci_conf[0x69] = 0x02;
BX_P2I_THIS s.pci_conf[0x70] = 0x80;
BX_P2I_THIS s.pci_conf[0x76] = 0x0c;
BX_P2I_THIS s.pci_conf[0x77] = 0x0c;
BX_P2I_THIS s.pci_conf[0x78] = 0x02;
BX_P2I_THIS s.pci_conf[0x79] = 0x00;
BX_P2I_THIS s.pci_conf[0x80] = 0x00;
BX_P2I_THIS s.pci_conf[0x82] = 0x00;
BX_P2I_THIS s.pci_conf[0xa0] = 0x08;
BX_P2I_THIS s.pci_conf[0xa2] = 0x00;
BX_P2I_THIS s.pci_conf[0xa3] = 0x00;
BX_P2I_THIS s.pci_conf[0xa4] = 0x00;
BX_P2I_THIS s.pci_conf[0xa5] = 0x00;
BX_P2I_THIS s.pci_conf[0xa6] = 0x00;
BX_P2I_THIS s.pci_conf[0xa7] = 0x00;
BX_P2I_THIS s.pci_conf[0xa8] = 0x0f;
BX_P2I_THIS s.pci_conf[0xaa] = 0x00;
BX_P2I_THIS s.pci_conf[0xab] = 0x00;
BX_P2I_THIS s.pci_conf[0xac] = 0x00;
BX_P2I_THIS s.pci_conf[0xae] = 0x00;
for (unsigned i = 0; i < 4; i++) {
pci_set_irq(0x08, i+1, 0);
pci_unregister_irq(i);
}
BX_P2I_THIS s.elcr1 = 0x00;
BX_P2I_THIS s.elcr2 = 0x00;
BX_P2I_THIS s.pci_reset = 0x00;
BX_P2I_THIS s.apms = 0x00;
BX_P2I_THIS s.apmc = 0x00;
}
void bx_piix3_c::register_state(void)
{
unsigned i;
char name[6];
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci2isa", "PCI-to-ISA Bridge State", 8);
register_pci_state(list, BX_P2I_THIS s.pci_conf);
BXRS_HEX_PARAM_FIELD(list, elcr1, BX_P2I_THIS s.elcr1);
BXRS_HEX_PARAM_FIELD(list, elcr2, BX_P2I_THIS s.elcr2);
BXRS_HEX_PARAM_FIELD(list, apmc, BX_P2I_THIS s.apmc);
BXRS_HEX_PARAM_FIELD(list, apms, BX_P2I_THIS s.apms);
BXRS_HEX_PARAM_FIELD(list, pci_reset, BX_P2I_THIS s.pci_reset);
bx_list_c *irqr = new bx_list_c(list, "irq_registry", 16);
for (i=0; i<16; i++) {
sprintf(name, "%d", i);
new bx_shadow_num_c(irqr, name, &BX_P2I_THIS s.irq_registry[i]);
}
bx_list_c *irql = new bx_list_c(list, "irq_level", 16);
for (i=0; i<16; i++) {
sprintf(name, "%d", i);
new bx_shadow_num_c(irql, name, &BX_P2I_THIS s.irq_level[i]);
}
}
void bx_piix3_c::after_restore_state(void)
{
for (unsigned i=0; i<16; i++) {
if (BX_P2I_THIS s.irq_registry[i]) {
DEV_register_irq(i, "PIIX3 IRQ routing");
}
}
}
void bx_piix3_c::pci_register_irq(unsigned pirq, unsigned irq)
{
if ((irq < 16) && (((1 << irq) & 0xdef8) > 0)) {
if (BX_P2I_THIS s.pci_conf[0x60 + pirq] < 16) {
pci_unregister_irq(pirq);
}
BX_P2I_THIS s.pci_conf[0x60 + pirq] = irq;
if (!BX_P2I_THIS s.irq_registry[irq]) {
DEV_register_irq(irq, "PIIX3 IRQ routing");
}
BX_P2I_THIS s.irq_registry[irq] |= (1 << pirq);
}
}
void bx_piix3_c::pci_unregister_irq(unsigned pirq)
{
Bit8u irq = BX_P2I_THIS s.pci_conf[0x60 + pirq];
if (irq < 16) {
BX_P2I_THIS s.irq_registry[irq] &= ~(1 << pirq);
if (!BX_P2I_THIS s.irq_registry[irq]) {
BX_P2I_THIS pci_set_irq(0x08, pirq+1, 0);
DEV_unregister_irq(irq, "PIIX3 IRQ routing");
}
BX_P2I_THIS s.pci_conf[0x60 + pirq] = 0x80;
}
}
void bx_piix3_c::pci_set_irq(Bit8u devfunc, unsigned line, bx_bool level)
{
Bit8u pirq = ((devfunc >> 3) + line - 2) & 0x03;
#if BX_SUPPORT_APIC
// forward this function call to the ioapic too
if (DEV_ioapic_present()) {
DEV_ioapic_set_irq_level(pirq + 16, level);
}
#endif
Bit8u irq = BX_P2I_THIS s.pci_conf[0x60 + pirq];
if ((irq < 16) && (((1 << irq) & 0xdef8) > 0)) {
if (level == 1) {
if (!BX_P2I_THIS s.irq_level[irq]) {
DEV_pic_raise_irq(irq);
BX_DEBUG(("PIRQ%c -> IRQ %d = 1", pirq+65, irq));
}
BX_P2I_THIS s.irq_level[irq] |= (1 << (devfunc >> 3));
} else {
BX_P2I_THIS s.irq_level[irq] &= ~(1 << (devfunc >> 3));
if (!BX_P2I_THIS s.irq_level[irq]) {
DEV_pic_lower_irq(irq);
BX_DEBUG(("PIRQ%c -> IRQ %d = 0", pirq+65, irq));
}
}
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_piix3_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_P2I_SMF
bx_piix3_c *class_ptr = (bx_piix3_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_piix3_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_P2I_SMF
switch (address) {
case 0x00b2:
return(BX_P2I_THIS s.apmc);
case 0x00b3:
return(BX_P2I_THIS s.apms);
case 0x04d0:
return(BX_P2I_THIS s.elcr1);
case 0x04d1:
return(BX_P2I_THIS s.elcr2);
case 0x0cf9:
return(BX_P2I_THIS s.pci_reset);
}
return(0xffffffff);
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_piix3_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_P2I_SMF
bx_piix3_c *class_ptr = (bx_piix3_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_piix3_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_P2I_SMF
switch (address) {
case 0x00b2:
#if BX_SUPPORT_ACPI
DEV_acpi_generate_smi((Bit8u)value);
#else
BX_ERROR(("write %08x: APM command register not supported yet", value));
#endif
BX_P2I_THIS s.apmc = value & 0xff;
break;
case 0x00b3:
BX_P2I_THIS s.apms = value & 0xff;
break;
case 0x04d0:
value &= 0xf8;
if (value != BX_P2I_THIS s.elcr1) {
BX_P2I_THIS s.elcr1 = value;
BX_INFO(("write: ELCR1 = 0x%02x", BX_P2I_THIS s.elcr1));
DEV_pic_set_mode(1, BX_P2I_THIS s.elcr1); // master PIC
}
break;
case 0x04d1:
value &= 0xde;
if (value != BX_P2I_THIS s.elcr2) {
BX_P2I_THIS s.elcr2 = value;
BX_INFO(("write: ELCR2 = 0x%02x", BX_P2I_THIS s.elcr2));
DEV_pic_set_mode(0, BX_P2I_THIS s.elcr2); // slave PIC
}
break;
case 0x0cf9:
BX_INFO(("write: CPU reset register = 0x%02x", value));
BX_P2I_THIS s.pci_reset = value & 0x02;
if (value & 0x04) {
if (BX_P2I_THIS s.pci_reset) {
bx_pc_system.Reset(BX_RESET_HARDWARE);
} else {
bx_pc_system.Reset(BX_RESET_SOFTWARE);
}
}
break;
}
}
// pci configuration space read callback handler
Bit32u bx_piix3_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_P2I_THIS s.pci_conf[address+i] << (i*8));
}
BX_DEBUG(("PIIX3 PCI-to-ISA read register 0x%02x value 0x%08x", address, value));
return value;
}
// pci configuration space write callback handler
void bx_piix3_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
if ((address >= 0x10) && (address < 0x34))
return;
for (unsigned i=0; i<io_len; i++) {
Bit8u value8 = (value >> (i*8)) & 0xFF;
switch (address+i) {
case 0x04:
case 0x06:
break;
case 0x60:
case 0x61:
case 0x62:
case 0x63:
if (value8 != BX_P2I_THIS s.pci_conf[address+i]) {
if (value8 >= 0x80) {
pci_unregister_irq((address+i) & 0x03);
} else {
pci_register_irq((address+i) & 0x03, value8);
}
BX_INFO(("PCI IRQ routing: PIRQ%c# set to 0x%02x", address+i-31,
value8));
}
break;
default:
BX_P2I_THIS s.pci_conf[address+i] = value8;
BX_DEBUG(("PIIX3 PCI-to-ISA write register 0x%02x value 0x%02x", address+i,
value8));
}
}
}
#endif /* BX_SUPPORT_PCI */

70
bochs/iodev/pci2isa.h Normal file
View File

@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PIC2ISA_H
#define BX_IODEV_PIC2ISA_H
#if BX_USE_P2I_SMF
# define BX_P2I_SMF static
# define BX_P2I_THIS thePci2IsaBridge->
#else
# define BX_P2I_SMF
# define BX_P2I_THIS this->
#endif
class bx_piix3_c : public bx_pci2isa_stub_c {
public:
bx_piix3_c();
virtual ~bx_piix3_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void pci_set_irq(Bit8u devfunc, unsigned line, bx_bool level);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
private:
struct {
Bit8u pci_conf[256];
Bit8u elcr1;
Bit8u elcr2;
Bit8u apmc;
Bit8u apms;
Bit8u irq_registry[16];
Bit32u irq_level[16];
Bit8u pci_reset;
} s;
static void pci_register_irq(unsigned pirq, unsigned irq);
static void pci_unregister_irq(unsigned pirq);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_P2I_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

460
bochs/iodev/pci_ide.cc Normal file
View File

@ -0,0 +1,460 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// i440FX Support - PCI IDE controller (PIIX3)
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI
#include "pci.h"
#include "pci_ide.h"
#define LOG_THIS thePciIdeController->
bx_pci_ide_c *thePciIdeController = NULL;
const Bit8u bmdma_iomask[16] = {1, 0, 1, 0, 4, 0, 0, 0, 1, 0, 1, 0, 4, 0, 0, 0};
int libpci_ide_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePciIdeController = new bx_pci_ide_c();
bx_devices.pluginPciIdeController = thePciIdeController;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciIdeController, BX_PLUGIN_PCI_IDE);
return(0); // Success
}
void libpci_ide_LTX_plugin_fini(void)
{
delete thePciIdeController;
}
bx_pci_ide_c::bx_pci_ide_c()
{
put("PIDE");
s.bmdma[0].timer_index = BX_NULL_TIMER_HANDLE;
s.bmdma[1].timer_index = BX_NULL_TIMER_HANDLE;
s.bmdma[0].buffer = NULL;
s.bmdma[1].buffer = NULL;
}
bx_pci_ide_c::~bx_pci_ide_c()
{
if (s.bmdma[0].buffer != NULL) {
delete [] s.bmdma[0].buffer;
}
if (s.bmdma[1].buffer != NULL) {
delete [] s.bmdma[1].buffer;
}
BX_DEBUG(("Exit"));
}
void bx_pci_ide_c::init(void)
{
unsigned i;
Bit8u devfunc = BX_PCI_DEVICE(1,1);
DEV_register_pci_handlers(this, &devfunc,
BX_PLUGIN_PCI_IDE, "PIIX3 PCI IDE controller");
// register BM-DMA timer
for (i=0; i<2; i++) {
if (BX_PIDE_THIS s.bmdma[i].timer_index == BX_NULL_TIMER_HANDLE) {
BX_PIDE_THIS s.bmdma[i].timer_index =
DEV_register_timer(this, timer_handler, 1000, 0,0, "PIIX3 BM-DMA timer");
}
}
BX_PIDE_THIS s.bmdma[0].buffer = new Bit8u[0x20000];
BX_PIDE_THIS s.bmdma[1].buffer = new Bit8u[0x20000];
for (i=0; i<256; i++)
BX_PIDE_THIS s.pci_conf[i] = 0x0;
// readonly registers
BX_PIDE_THIS s.pci_conf[0x00] = 0x86;
BX_PIDE_THIS s.pci_conf[0x01] = 0x80;
BX_PIDE_THIS s.pci_conf[0x02] = 0x10;
BX_PIDE_THIS s.pci_conf[0x03] = 0x70;
BX_PIDE_THIS s.pci_conf[0x09] = 0x80;
BX_PIDE_THIS s.pci_conf[0x0a] = 0x01;
BX_PIDE_THIS s.pci_conf[0x0b] = 0x01;
BX_PIDE_THIS s.pci_conf[0x0e] = 0x00;
BX_PIDE_THIS s.pci_conf[0x20] = 0x01;
BX_PIDE_THIS s.bmdma_addr = 0;
}
void bx_pci_ide_c::reset(unsigned type)
{
BX_PIDE_THIS s.pci_conf[0x04] = 0x01;
BX_PIDE_THIS s.pci_conf[0x06] = 0x80;
BX_PIDE_THIS s.pci_conf[0x07] = 0x02;
if (SIM->get_param_bool(BXPN_ATA0_ENABLED)->get()) {
BX_PIDE_THIS s.pci_conf[0x40] = 0x00;
BX_PIDE_THIS s.pci_conf[0x41] = 0x80;
}
if (SIM->get_param_bool(BXPN_ATA1_ENABLED)->get()) {
BX_PIDE_THIS s.pci_conf[0x42] = 0x00;
BX_PIDE_THIS s.pci_conf[0x43] = 0x80;
}
BX_PIDE_THIS s.pci_conf[0x44] = 0x00;
for (unsigned i=0; i<2; i++) {
BX_PIDE_THIS s.bmdma[i].cmd_ssbm = 0;
BX_PIDE_THIS s.bmdma[i].cmd_rwcon = 0;
BX_PIDE_THIS s.bmdma[i].status = 0;
BX_PIDE_THIS s.bmdma[i].dtpr = 0;
BX_PIDE_THIS s.bmdma[i].prd_current = 0;
BX_PIDE_THIS s.bmdma[i].buffer_top = BX_PIDE_THIS s.bmdma[i].buffer;
BX_PIDE_THIS s.bmdma[i].buffer_idx = BX_PIDE_THIS s.bmdma[i].buffer;
}
}
// save/restore code begin
void bx_pci_ide_c::register_state(void)
{
char name[6];
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pci_ide", "PCI IDE Controller State", 5);
register_pci_state(list, BX_PIDE_THIS s.pci_conf);
new bx_shadow_data_c(list, "buffer0", BX_PIDE_THIS s.bmdma[0].buffer, 0x20000);
new bx_shadow_data_c(list, "buffer1", BX_PIDE_THIS s.bmdma[1].buffer, 0x20000);
for (unsigned i=0; i<2; i++) {
sprintf(name, "%d", i);
bx_list_c *ctrl = new bx_list_c(list, name, 7);
BXRS_PARAM_BOOL(ctrl, cmd_ssbm, BX_PIDE_THIS s.bmdma[i].cmd_ssbm);
BXRS_PARAM_BOOL(ctrl, cmd_rwcon, BX_PIDE_THIS s.bmdma[i].cmd_rwcon);
BXRS_HEX_PARAM_FIELD(ctrl, status, BX_PIDE_THIS s.bmdma[i].status);
BXRS_HEX_PARAM_FIELD(ctrl, dtpr, BX_PIDE_THIS s.bmdma[i].dtpr);
BXRS_HEX_PARAM_FIELD(ctrl, prd_current, BX_PIDE_THIS s.bmdma[i].prd_current);
BXRS_PARAM_SPECIAL32(ctrl, buffer_top,
BX_PIDE_THIS param_save_handler, BX_PIDE_THIS param_restore_handler);
BXRS_PARAM_SPECIAL32(ctrl, buffer_idx,
BX_PIDE_THIS param_save_handler, BX_PIDE_THIS param_restore_handler);
}
}
void bx_pci_ide_c::after_restore_state(void)
{
if (DEV_pci_set_base_io(BX_PIDE_THIS_PTR, read_handler, write_handler,
&BX_PIDE_THIS s.bmdma_addr, &BX_PIDE_THIS s.pci_conf[0x20],
16, &bmdma_iomask[0], "PIIX3 PCI IDE controller"))
{
BX_INFO(("new BM-DMA address: 0x%04x", BX_PIDE_THIS s.bmdma_addr));
}
}
Bit64s bx_pci_ide_c::param_save_handler(void *devptr, bx_param_c *param)
{
#if !BX_USE_PIDE_SMF
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) devptr;
return class_ptr->param_save(param, val);
}
Bit64s bx_pci_ide_c::param_save(bx_param_c *param)
{
#else
UNUSED(devptr);
#endif // !BX_USE_PIDE_SMF
int chan = atoi(param->get_parent()->get_name());
Bit64s val = 0;
if (!strcmp(param->get_name(), "buffer_top")) {
val = (Bit32u)(BX_PIDE_THIS s.bmdma[chan].buffer_top - BX_PIDE_THIS s.bmdma[chan].buffer);
} else if (!strcmp(param->get_name(), "buffer_idx")) {
val = (Bit32u)(BX_PIDE_THIS s.bmdma[chan].buffer_idx - BX_PIDE_THIS s.bmdma[chan].buffer);
}
return val;
}
void bx_pci_ide_c::param_restore_handler(void *devptr, bx_param_c *param, Bit64s val)
{
#if !BX_USE_PIDE_SMF
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) devptr;
class_ptr->param_restore(param, val);
}
void bx_pci_ide_c::param_restore(bx_param_c *param, Bit64s val)
{
#else
UNUSED(devptr);
#endif // !BX_USE_PIDE_SMF
int chan = atoi(param->get_parent()->get_name());
if (!strcmp(param->get_name(), "buffer_top")) {
BX_PIDE_THIS s.bmdma[chan].buffer_top = BX_PIDE_THIS s.bmdma[chan].buffer + val;
} else if (!strcmp(param->get_name(), "buffer_idx")) {
BX_PIDE_THIS s.bmdma[chan].buffer_idx = BX_PIDE_THIS s.bmdma[chan].buffer + val;
}
}
// save/restore code end
bx_bool bx_pci_ide_c::bmdma_present(void)
{
return (BX_PIDE_THIS s.bmdma_addr > 0);
}
void bx_pci_ide_c::bmdma_set_irq(Bit8u channel)
{
if (channel < 2) {
BX_PIDE_THIS s.bmdma[channel].status |= 0x04;
}
}
void bx_pci_ide_c::timer_handler(void *this_ptr)
{
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
class_ptr->timer();
}
void bx_pci_ide_c::timer()
{
int timer_id, count;
Bit8u channel;
Bit32u size, sector_size;
struct {
Bit32u addr;
Bit32u size;
} prd;
timer_id = bx_pc_system.triggeredTimerID();
if (timer_id == BX_PIDE_THIS s.bmdma[0].timer_index) {
channel = 0;
} else {
channel = 1;
}
if (((BX_PIDE_THIS s.bmdma[channel].status & 0x01) == 0) ||
(BX_PIDE_THIS s.bmdma[channel].prd_current == 0)) {
return;
}
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current, 4, (Bit8u *)&prd.addr);
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current+4, 4, (Bit8u *)&prd.size);
size = prd.size & 0xfffe;
if (size == 0) {
size = 0x10000;
}
if (BX_PIDE_THIS s.bmdma[channel].cmd_rwcon) {
BX_DEBUG(("READ DMA to addr=0x%08x, size=0x%08x", prd.addr, size));
count = size - (BX_PIDE_THIS s.bmdma[channel].buffer_top - BX_PIDE_THIS s.bmdma[channel].buffer_idx);
while (count > 0) {
sector_size = count;
if (DEV_hd_bmdma_read_sector(channel, BX_PIDE_THIS s.bmdma[channel].buffer_top, &sector_size)) {
BX_PIDE_THIS s.bmdma[channel].buffer_top += sector_size;
count -= sector_size;
} else {
break;
}
};
if (count > 0) {
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
BX_PIDE_THIS s.bmdma[channel].status |= 0x06;
return;
} else {
DEV_MEM_WRITE_PHYSICAL_BLOCK(prd.addr, size, BX_PIDE_THIS s.bmdma[channel].buffer_idx);
BX_PIDE_THIS s.bmdma[channel].buffer_idx += size;
}
} else {
BX_DEBUG(("WRITE DMA from addr=0x%08x, size=0x%08x", prd.addr, size));
DEV_MEM_READ_PHYSICAL_BLOCK(prd.addr, size, BX_PIDE_THIS s.bmdma[channel].buffer_top);
BX_PIDE_THIS s.bmdma[channel].buffer_top += size;
count = BX_PIDE_THIS s.bmdma[channel].buffer_top - BX_PIDE_THIS s.bmdma[channel].buffer_idx;
while (count > 511) {
if (DEV_hd_bmdma_write_sector(channel, BX_PIDE_THIS s.bmdma[channel].buffer_idx)) {
BX_PIDE_THIS s.bmdma[channel].buffer_idx += 512;
count -= 512;
} else {
break;
}
};
if (count > 511) {
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
BX_PIDE_THIS s.bmdma[channel].status |= 0x06;
return;
}
}
if (prd.size & 0x80000000) {
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
BX_PIDE_THIS s.bmdma[channel].status |= 0x04;
BX_PIDE_THIS s.bmdma[channel].prd_current = 0;
DEV_hd_bmdma_complete(channel);
} else {
BX_PIDE_THIS s.bmdma[channel].prd_current += 8;
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current, 4, (Bit8u *)&prd.addr);
DEV_MEM_READ_PHYSICAL(BX_PIDE_THIS s.bmdma[channel].prd_current+4, 4, (Bit8u *)&prd.size);
size = prd.size & 0xfffe;
if (size == 0) {
size = 0x10000;
}
bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, (size >> 4) | 0x10, 0);
}
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_pci_ide_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PIDE_SMF
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_pci_ide_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIDE_SMF
Bit8u offset, channel;
Bit32u value = 0xffffffff;
offset = address - BX_PIDE_THIS s.bmdma_addr;
channel = (offset >> 3);
offset &= 0x07;
switch (offset) {
case 0x00:
value = BX_PIDE_THIS s.bmdma[channel].cmd_ssbm |
(BX_PIDE_THIS s.bmdma[channel].cmd_rwcon << 3);
BX_DEBUG(("BM-DMA read command register, channel %d, value = 0x%02x", channel, value));
break;
case 0x02:
value = BX_PIDE_THIS s.bmdma[channel].status;
BX_DEBUG(("BM-DMA read status register, channel %d, value = 0x%02x", channel, value));
break;
case 0x04:
value = BX_PIDE_THIS s.bmdma[channel].dtpr;
BX_DEBUG(("BM-DMA read DTP register, channel %d, value = 0x%04x", channel, value));
break;
}
return value;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_pci_ide_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PIDE_SMF
bx_pci_ide_c *class_ptr = (bx_pci_ide_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_pci_ide_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIDE_SMF
Bit8u offset, channel;
offset = address - BX_PIDE_THIS s.bmdma_addr;
channel = (offset >> 3);
offset &= 0x07;
switch (offset) {
case 0x00:
BX_DEBUG(("BM-DMA write command register, channel %d, value = 0x%02x", channel, value));
BX_PIDE_THIS s.bmdma[channel].cmd_rwcon = (value >> 3) & 1;
if ((value & 0x01) && !BX_PIDE_THIS s.bmdma[channel].cmd_ssbm) {
BX_PIDE_THIS s.bmdma[channel].cmd_ssbm = 1;
BX_PIDE_THIS s.bmdma[channel].status |= 0x01;
BX_PIDE_THIS s.bmdma[channel].prd_current = BX_PIDE_THIS s.bmdma[channel].dtpr;
BX_PIDE_THIS s.bmdma[channel].buffer_top = BX_PIDE_THIS s.bmdma[channel].buffer;
BX_PIDE_THIS s.bmdma[channel].buffer_idx = BX_PIDE_THIS s.bmdma[channel].buffer;
bx_pc_system.activate_timer(BX_PIDE_THIS s.bmdma[channel].timer_index, 1000, 0);
} else if (!(value & 0x01) && BX_PIDE_THIS s.bmdma[channel].cmd_ssbm) {
BX_PIDE_THIS s.bmdma[channel].cmd_ssbm = 0;
BX_PIDE_THIS s.bmdma[channel].status &= ~0x01;
}
break;
case 0x02:
BX_PIDE_THIS s.bmdma[channel].status = (value & 0x60)
| (BX_PIDE_THIS s.bmdma[channel].status & 0x01)
| (BX_PIDE_THIS s.bmdma[channel].status & (~value & 0x06));
BX_DEBUG(("BM-DMA write status register, channel %d, value = 0x%02x", channel, value));
break;
case 0x04:
BX_PIDE_THIS s.bmdma[channel].dtpr = value & 0xfffffffc;
BX_DEBUG(("BM-DMA write DTP register, channel %d, value = 0x%04x", channel, value));
break;
}
}
// pci configuration space read callback handler
Bit32u bx_pci_ide_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_PIDE_THIS s.pci_conf[address+i] << (i*8));
}
BX_DEBUG(("PIIX3 PCI IDE read register 0x%02x value 0x%08x", address, value));
return value;
}
// pci configuration space write callback handler
void bx_pci_ide_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
Bit8u value8, oldval;
bx_bool bmdma_change = 0;
if (((address >= 0x10) && (address < 0x20)) ||
((address > 0x23) && (address < 0x40)))
return;
for (unsigned i=0; i<io_len; i++) {
oldval = BX_PIDE_THIS s.pci_conf[address+i];
value8 = (value >> (i*8)) & 0xFF;
switch (address+i) {
case 0x05:
case 0x06:
break;
case 0x04:
BX_PIDE_THIS s.pci_conf[address+i] = value8 & 0x05;
break;
case 0x20:
value8 = (value8 & 0xfc) | 0x01;
case 0x21:
case 0x22:
case 0x23:
bmdma_change |= (value8 != oldval);
default:
BX_PIDE_THIS s.pci_conf[address+i] = value8;
BX_DEBUG(("PIIX3 PCI IDE write register 0x%02x value 0x%02x", address+i,
value8));
}
}
if (bmdma_change) {
if (DEV_pci_set_base_io(BX_PIDE_THIS_PTR, read_handler, write_handler,
&BX_PIDE_THIS s.bmdma_addr, &BX_PIDE_THIS s.pci_conf[0x20],
16, &bmdma_iomask[0], "PIIX3 PCI IDE controller")) {
BX_INFO(("new BM-DMA address: 0x%04x", BX_PIDE_THIS s.bmdma_addr));
}
}
}
#endif /* BX_SUPPORT_PCI */

83
bochs/iodev/pci_ide.h Normal file
View File

@ -0,0 +1,83 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PCIIDE_H
#define BX_IODEV_PCIIDE_H
#if BX_USE_PIDE_SMF
# define BX_PIDE_SMF static
# define BX_PIDE_THIS thePciIdeController->
# define BX_PIDE_THIS_PTR thePciIdeController
#else
# define BX_PIDE_SMF
# define BX_PIDE_THIS this->
# define BX_PIDE_THIS_PTR this
#endif
class bx_pci_ide_c : public bx_pci_ide_stub_c {
public:
bx_pci_ide_c();
virtual ~bx_pci_ide_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual bx_bool bmdma_present(void);
virtual void bmdma_set_irq(Bit8u channel);
virtual void register_state(void);
virtual void after_restore_state(void);
static Bit64s param_save_handler(void *devptr, bx_param_c *param);
static void param_restore_handler(void *devptr, bx_param_c *param, Bit64s val);
#if !BX_USE_PIDE_SMF
Bit64s param_save(bx_param_c *param);
void param_restore(bx_param_c *param, Bit64s val);
#endif
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
static void timer_handler(void *);
BX_PIDE_SMF void timer(void);
private:
struct {
Bit8u pci_conf[256];
Bit32u bmdma_addr;
struct {
bx_bool cmd_ssbm;
bx_bool cmd_rwcon;
Bit8u status;
Bit32u dtpr;
Bit32u prd_current;
int timer_index;
Bit8u *buffer;
Bit8u *buffer_top;
Bit8u *buffer_idx;
} bmdma[2];
} s;
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PIDE_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

464
bochs/iodev/pcidev.cc Normal file
View File

@ -0,0 +1,464 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
/*
* PCIDEV: PCI host device mapping
* Copyright (C) 2003 - Frank Cornelis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Based on pcivga code:
* Copyright (C) 2002,2003 Mike Nordell
*/
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIDEV
#include "pcidev.h"
#include "kernel_pcidev.h"
#include <sys/ioctl.h>
#include <signal.h>
#include <linux/pci.h>
#define LOG_THIS thePciDevAdapter->
bx_pcidev_c* thePciDevAdapter = NULL;
int libpcidev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePciDevAdapter = new bx_pcidev_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciDevAdapter, BX_PLUGIN_PCIDEV);
return 0; // Success
}
void libpcidev_LTX_plugin_fini(void)
{
delete thePciDevAdapter;
}
bx_pcidev_c::bx_pcidev_c()
{
put("PCI2H");
}
bx_pcidev_c::~bx_pcidev_c()
{
BX_DEBUG(("Exit"));
}
static void pcidev_sighandler(int param)
{
bx_pcidev_c *pcidev = thePciDevAdapter;
BX_INFO(("Interrupt received."));
DEV_pci_set_irq(pcidev->devfunc, pcidev->intpin, 0);
/*
* We need to first lower the IRQ line or else we don't
* get any IRQs through
*/
DEV_pci_set_irq(pcidev->devfunc, pcidev->intpin, 1);
}
static bx_bool pcidev_mem_read_handler(bx_phy_address addr, unsigned len, void *data, void *param)
{
struct region_struct *region = (struct region_struct *)param;
bx_pcidev_c *pcidev = region->pcidev;
int fd = pcidev->pcidev_fd;
int ret = -1;
if (fd == -1)
return false; /* we failed to handle the request, so let a default handler do it for us */
BX_INFO(("Reading I/O memory at 0x%08x", (unsigned)addr));
struct pcidev_io_struct io;
io.address = addr + region->host_start - region->start;
switch(len) {
case 1:
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_BYTE, &io);
*(Bit8u *)data = io.value;
break;
case 2:
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_WORD, &io);
*(Bit16u *)data = io.value;
break;
case 4:
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_DWORD, &io);
*(Bit32u *)data = io.value;
break;
default:
BX_ERROR(("Unsupported pcidev read mem operation"));
break;
}
if (ret == -1) {
BX_ERROR(("pcidev read mem error"));
}
return true; // ok, we handled the request
}
static bx_bool pcidev_mem_write_handler(bx_phy_address addr, unsigned len, void *data, void *param)
{
struct region_struct *region = (struct region_struct *)param;
bx_pcidev_c *pcidev = region->pcidev;
int fd = pcidev->pcidev_fd;
int ret = -1;
if (fd == -1)
return false; /* we failed to handle the request, so let a default handler do it for us */
BX_INFO(("Writing I/O memory at 0x%08x", (unsigned)addr));
struct pcidev_io_struct io;
io.address = addr + region->host_start - region->start;
switch(len) {
case 1:
io.value = *(Bit8u *)data;
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_BYTE, &io);
break;
case 2:
io.value = *(Bit16u *)data;
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_WORD, &io);
break;
case 4:
io.value = *(Bit32u *)data;
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_DWORD, &io);
break;
default:
BX_ERROR(("Unsupported pcidev write mem operation"));
break;
}
if (ret == -1) {
BX_ERROR(("pcidev write mem error"));
}
return true;
}
static const char * const pcidev_name = "Experimental PCI 2 host PCI";
void bx_pcidev_c::init(void)
{
// called once when bochs initializes
BX_PCIDEV_THIS pcidev_fd = -1;
int fd;
fd = open("/dev/pcidev", O_RDWR);
if (fd == -1) {
switch(errno) {
case ENODEV:
BX_PANIC(("The pcidev kernel module is not loaded!"));
break;
default:
BX_PANIC(("open /dev/pcidev: %s", strerror(errno)));
break;
}
return;
}
BX_PCIDEV_THIS pcidev_fd = fd;
struct pcidev_find_struct find;
unsigned short vendor = SIM->get_param_num(BXPN_PCIDEV_VENDOR)->get();
unsigned short device = SIM->get_param_num(BXPN_PCIDEV_DEVICE)->get();
find.deviceID = device;
find.vendorID = vendor;
if (ioctl(fd, PCIDEV_IOCTL_FIND, &find) == -1) {
switch (errno) {
case ENOENT:
BX_PANIC(("PCI device not found on host system."));
break;
case EBUSY:
BX_PANIC(("PCI device already used by another kernel module."));
break;
default:
perror("ioctl");
break;
}
close(fd);
BX_PCIDEV_THIS pcidev_fd = -1;
return;
}
BX_INFO(("vendor: %04x; device: %04x @ host %04x:%04x.%d", vendor, device,
(unsigned)find.bus, (unsigned)find.device, (unsigned)find.func));
BX_PCIDEV_THIS devfunc = 0x00;
DEV_register_pci_handlers(this, &BX_PCIDEV_THIS devfunc, BX_PLUGIN_PCIDEV,
pcidev_name);
BX_PCIDEV_THIS irq = 0;
struct pcidev_io_struct io;
io.address = 0x3d;
int ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_BYTE, &io);
if (ret != -1) {
BX_PCIDEV_THIS intpin = io.value;
} else {
BX_PCIDEV_THIS intpin = 0;
}
for (int idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++) {
BX_PCIDEV_THIS regions[idx].start = 0; // emulated device not yet initialized
if (!find.resources[idx].start)
continue;
BX_INFO(("PCI resource @ %x-%x (%s)", (unsigned)find.resources[idx].start,
(unsigned)find.resources[idx].end,
(find.resources[idx].flags & PCIDEV_RESOURCE_IO ? "I/O" : "Mem")));
BX_PCIDEV_THIS regions[idx].size = find.resources[idx].end - find.resources[idx].start + 1;
BX_PCIDEV_THIS regions[idx].host_start = find.resources[idx].start;
struct pcidev_io_struct io;
io.address = PCI_BASE_ADDRESS_0 + idx * 4;
if (ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io) == -1)
BX_ERROR(("Error reading a base address config reg"));
BX_PCIDEV_THIS regions[idx].config_value = io.value;
/*
* We will use &region[idx] as parameter for our I/O or memory
* handler. So we provide a pcidev pointer to the pcidev object
* in order for the handle to be able to use its pcidev object
*/
BX_PCIDEV_THIS regions[idx].pcidev = this;
}
struct sigaction sa;
sa.sa_handler = pcidev_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGUSR1, &sa, NULL);
/*
* The kernel pcidev will fire SIGUSR1 signals when it receives
* interrupts from the host PCI device.
*/
ioctl(fd, PCIDEV_IOCTL_INTERRUPT, 1);
}
void bx_pcidev_c::reset(unsigned type) { }
// pci configuration space read callback handler
Bit32u bx_pcidev_c::pci_read_handler(Bit8u address, unsigned io_len)
{
int ret = -1;
int fd = BX_PCIDEV_THIS pcidev_fd;
if (fd == -1)
return 0xffffffff;
struct pcidev_io_struct io;
io.address = address;
switch(io_len) {
case 1:
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_BYTE, &io);
break;
case 2:
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_WORD, &io);
break;
case 4:
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io);
break;
}
if (ret == -1)
BX_ERROR(("pcidev config read error"));
// we don't use the host irq line but our own bochs irq line
if (address == PCI_INTERRUPT_LINE) {
io.value = (io.value & 0xffffff00) | (BX_PCIDEV_THIS irq & 0xff);
}
if (PCI_BASE_ADDRESS_0 <= address && address <= PCI_BASE_ADDRESS_5) {
BX_INFO(("Reading pcidev base address #%d", (address - PCI_BASE_ADDRESS_0) / 4));
io.value = BX_PCIDEV_THIS regions[(address - PCI_BASE_ADDRESS_0) >> 2].config_value;
if (address & 3) {
io.value >>= (8 * (address & 3));
}
}
return io.value;
}
// pci configuration space write callback handler
void bx_pcidev_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
int ret = -1;
Bit8u *iomask;
Bit32u bitmask;
int fd = BX_PCIDEV_THIS pcidev_fd;
if (fd == -1)
return;
// we do a host 2 guest irq line mapping
if (address == PCI_INTERRUPT_LINE) {
value &= 0xff;
BX_INFO(("Changing the pcidev irq line from %d to %d", BX_PCIDEV_THIS irq, value));
BX_PCIDEV_THIS irq = value;
return;
}
if ((PCI_BASE_ADDRESS_0 <= address) && (address <= PCI_BASE_ADDRESS_5)) {
/*
* Two things to do here:
* - update the cached config space value via a probe
* - remap the I/O or memory handler if required
*/
int io_reg_idx = (address - PCI_BASE_ADDRESS_0) >> 2;
switch (io_len) {
case 1: bitmask = 0xff; break;
case 2: bitmask = 0xffff; break;
default: bitmask = 0xffffffff;
}
bitmask <<= (8 * (address & 3));
value <<= (8 * (address & 3));
value |= BX_PCIDEV_THIS regions[io_reg_idx].config_value & ~bitmask;
BX_INFO(("Changing pcidev base address #%d - New value: %#x",
(address - PCI_BASE_ADDRESS_0) / 4, value));
struct pcidev_io_struct io;
io.address = address;
io.value = value;
ret = ioctl(fd, PCIDEV_IOCTL_PROBE_CONFIG_DWORD, &io);
if (ret == -1) {
BX_ERROR(("Error probing a base address reg!"));
return;
}
unsigned long base = io.value;
BX_PCIDEV_THIS regions[io_reg_idx].config_value = base;
/* remap the I/O or memory handler if required using io.value
* We assume that an I/O memory region will stay and I/O memory
* region. And that an I/O port region also will stay an I/O port
* region.
*/
if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
if (DEV_pci_set_base_mem(&(BX_PCIDEV_THIS regions[io_reg_idx]),
pcidev_mem_read_handler,
pcidev_mem_write_handler,
&BX_PCIDEV_THIS regions[io_reg_idx].start,
(Bit8u*)&BX_PCIDEV_THIS regions[io_reg_idx].config_value,
BX_PCIDEV_THIS regions[io_reg_idx].size)) {
BX_INFO(("new base #%d memory address: 0x%08x", io_reg_idx,
BX_PCIDEV_THIS regions[io_reg_idx].start));
}
} else {
/*
* Remap our I/O port handlers here.
*/
iomask = (Bit8u*)malloc(BX_PCIDEV_THIS regions[io_reg_idx].size);
memset(iomask, 7, BX_PCIDEV_THIS regions[io_reg_idx].size);
if (DEV_pci_set_base_io(&(BX_PCIDEV_THIS regions[io_reg_idx]),
read_handler, write_handler,
&BX_PCIDEV_THIS regions[io_reg_idx].start,
(Bit8u*)&BX_PCIDEV_THIS regions[io_reg_idx].config_value,
BX_PCIDEV_THIS regions[io_reg_idx].size, iomask, "pcidev")) {
BX_INFO(("new base #%d i/o address: 0x%04x", io_reg_idx,
(Bit16u)BX_PCIDEV_THIS regions[io_reg_idx].start));
}
free(iomask);
}
return;
}
struct pcidev_io_struct io;
io.address = address;
io.value = value;
switch(io_len) {
case 1:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_BYTE, &io);
break;
case 2:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_WORD, &io);
break;
case 4:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_DWORD, &io);
break;
}
if (ret == -1)
BX_ERROR(("pcidev config write error"));
}
Bit32u bx_pcidev_c::read_handler(void *param, Bit32u address, unsigned io_len)
{
#if !BX_USE_PCIDEV_SMF
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
return class_ptr->read(param, address, io_len);
}
Bit32u bx_pcidev_c::read(void *param, Bit32u address, unsigned io_len)
{
#endif
struct region_struct *region = (struct region_struct *)param;
int ret = -1;
int fd = BX_PCIDEV_THIS pcidev_fd;
if (fd == -1)
return 0xffffffff;
struct pcidev_io_struct io;
// here we map the io address
io.address = address + region->host_start - region->start;
switch(io_len) {
case 1:
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_BYTE, &io);
break;
case 2:
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_WORD, &io);
break;
case 4:
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_DWORD, &io);
break;
}
if (ret == -1) {
BX_ERROR(("pcidev read I/O error"));
io.value = 0xffffffff;
}
return io.value;
}
void bx_pcidev_c::write_handler(void *param, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PCIDEV_SMF
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
class_ptr->write(param, address, value, io_len);
}
void bx_pcidev_c::write(void *param, Bit32u address, Bit32u value, unsigned io_len)
{
#endif
struct region_struct *region = (struct region_struct *)param;
int ret = -1;
int fd = BX_PCIDEV_THIS pcidev_fd;
if (fd == -1)
return;
struct pcidev_io_struct io;
// here we map the I/O address
io.address = address + region->host_start - region->start;
io.value = value;
switch(io_len) {
case 1:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_BYTE, &io);
break;
case 2:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_WORD, &io);
break;
case 4:
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_DWORD, &io);
break;
}
if (ret == -1)
BX_ERROR(("pcidev I/O write error"));
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIDEV

69
bochs/iodev/pcidev.h Normal file
View File

@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
/*
* PCIDEV: PCI host device mapping
* Copyright (C) 2003 - Frank Cornelis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BX_IODEV_PCIDEV_H
#define BX_IODEV_PCIDEV_H
#if BX_USE_PCIDEV_SMF
# define BX_PCIDEV_THIS thePciDevAdapter->
# define BX_PCIDEV_THIS_ thePciDevAdapter
#else
# define BX_PCIDEV_THIS this->
# define BX_PCIDEV_THIS_ this
#endif
struct region_struct {
Bit32u config_value;
Bit32u start; // can change
Bit32u size;
Bit32u host_start; // never changes!!!
class bx_pcidev_c *pcidev;
};
class bx_pcidev_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
bx_pcidev_c();
virtual ~bx_pcidev_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
int pcidev_fd; // to access the pcidev
// resource mapping
struct region_struct regions[6];
Bit8u devfunc;
Bit8u intpin;
Bit8u irq;
private:
static Bit32u read_handler(void *param, Bit32u address, unsigned io_len);
static void write_handler(void *param, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PCIDEV_SMF
Bit32u read(void *param, Bit32u address, unsigned io_len);
void write(void *param, Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

522
bochs/iodev/pcipnic.cc Normal file
View File

@ -0,0 +1,522 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003 Fen Systems Ltd.
// http://www.fensystems.co.uk/
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIPNIC
#include "pci.h"
#include "eth.h"
#include "pcipnic.h"
#define LOG_THIS thePNICDevice->
bx_pcipnic_c* thePNICDevice = NULL;
const Bit8u pnic_iomask[16] = {2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int libpcipnic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePNICDevice = new bx_pcipnic_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePNICDevice, BX_PLUGIN_PCIPNIC);
return 0; // Success
}
void libpcipnic_LTX_plugin_fini(void)
{
delete thePNICDevice;
}
bx_pcipnic_c::bx_pcipnic_c()
{
put("PNIC");
}
bx_pcipnic_c::~bx_pcipnic_c()
{
BX_DEBUG(("Exit"));
}
void bx_pcipnic_c::init(void)
{
bx_list_c *base;
// Read in values from config interface
base = (bx_list_c*) SIM->get_param(BXPN_PNIC);
memcpy(BX_PNIC_THIS s.macaddr, SIM->get_param_string("macaddr", base)->getptr(), 6);
BX_PNIC_THIS s.devfunc = 0x00;
DEV_register_pci_handlers(this, &BX_PNIC_THIS s.devfunc, BX_PLUGIN_PCIPNIC,
"Experimental PCI Pseudo NIC");
for (unsigned i=0; i<256; i++) {
BX_PNIC_THIS s.pci_conf[i] = 0x0;
}
// This code ripped wholesale from ne2k.cc:
// Attach to the simulated ethernet dev
const char *ethmod = SIM->get_param_enum("ethmod", base)->get_selected();
BX_PNIC_THIS ethdev = eth_locator_c::create(ethmod,
SIM->get_param_string("ethdev", base)->getptr(),
(const char *) SIM->get_param_string("macaddr", base)->getptr(),
rx_handler,
this,
SIM->get_param_string("script", base)->getptr());
if (BX_PNIC_THIS ethdev == NULL) {
BX_PANIC(("could not find eth module %s", ethmod));
// if they continue, use null.
BX_INFO(("could not find eth module %s - using null instead", ethmod));
BX_PNIC_THIS ethdev = eth_locator_c::create("null", NULL,
(const char *) SIM->get_param_string("macaddr", base)->getptr(),
rx_handler,
this, "");
if (BX_PNIC_THIS ethdev == NULL)
BX_PANIC(("could not locate null module"));
}
BX_PNIC_THIS s.base_ioaddr = 0;
BX_INFO(("PCI Pseudo NIC initialized - I/O base and IRQ assigned by PCI BIOS"));
}
void bx_pcipnic_c::reset(unsigned type)
{
unsigned i;
static const struct reset_vals_t {
unsigned addr;
unsigned char val;
} reset_vals[] = {
{ 0x00, PNIC_PCI_VENDOR & 0xff },
{ 0x01, PNIC_PCI_VENDOR >> 8 },
{ 0x02, PNIC_PCI_DEVICE & 0xff },
{ 0x03, PNIC_PCI_DEVICE >> 8 },
{ 0x04, 0x05 }, { 0x05, 0x00 }, // command_io
{ 0x06, 0x80 }, { 0x07, 0x02 }, // status
{ 0x08, 0x01 }, // revision number
{ 0x09, 0x00 }, // interface
{ 0x0a, 0x00 }, // class_sub
{ 0x0b, 0x02 }, // class_base Network Controller
{ 0x0D, 0x20 }, // bus latency
{ 0x0e, 0x00 }, // header_type_generic
// address space 0x20 - 0x23
{ 0x20, 0x01 }, { 0x21, 0x00 },
{ 0x22, 0x00 }, { 0x23, 0x00 },
{ 0x3c, 0x00, }, // IRQ
{ 0x3d, BX_PCI_INTA }, // INT
{ 0x6a, 0x01 }, // PNIC clock
{ 0xc1, 0x20 } // PIRQ enable
};
for (i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
BX_PNIC_THIS s.pci_conf[reset_vals[i].addr] = reset_vals[i].val;
}
// Set up initial register values
BX_PNIC_THIS s.rCmd = PNIC_CMD_NOOP;
BX_PNIC_THIS s.rStatus = PNIC_STATUS_OK;
BX_PNIC_THIS s.rLength = 0;
BX_PNIC_THIS s.rDataCursor = 0;
BX_PNIC_THIS s.recvIndex = 0;
BX_PNIC_THIS s.recvQueueLength = 0;
BX_PNIC_THIS s.irqEnabled = 0;
// Deassert IRQ
set_irq_level(0);
}
void bx_pcipnic_c::register_state(void)
{
unsigned i;
char name[6];
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pcipnic", "PCI Pseudo NIC State", 11);
new bx_shadow_num_c(list, "irqEnabled", &BX_PNIC_THIS s.irqEnabled);
new bx_shadow_num_c(list, "rCmd", &BX_PNIC_THIS s.rCmd);
new bx_shadow_num_c(list, "rStatus", &BX_PNIC_THIS s.rStatus);
new bx_shadow_num_c(list, "rLength", &BX_PNIC_THIS s.rLength);
new bx_shadow_num_c(list, "rDataCursor", &BX_PNIC_THIS s.rDataCursor);
new bx_shadow_num_c(list, "recvIndex", &BX_PNIC_THIS s.recvIndex);
new bx_shadow_num_c(list, "recvQueueLength", &BX_PNIC_THIS s.recvQueueLength);
bx_list_c *recvRL = new bx_list_c(list, "recvRingLength", PNIC_RECV_RINGS);
for (i=0; i<PNIC_RECV_RINGS; i++) {
sprintf(name, "%d", i);
new bx_shadow_num_c(recvRL, name, &BX_PNIC_THIS s.recvRingLength[i]);
}
new bx_shadow_data_c(list, "rData", BX_PNIC_THIS s.rData, PNIC_DATA_SIZE);
new bx_shadow_data_c(list, "recvRing", (Bit8u*)BX_PNIC_THIS s.recvRing, PNIC_RECV_RINGS*PNIC_DATA_SIZE);
register_pci_state(list, BX_PNIC_THIS s.pci_conf);
}
void bx_pcipnic_c::after_restore_state(void)
{
if (DEV_pci_set_base_io(BX_PNIC_THIS_PTR, read_handler, write_handler,
&BX_PNIC_THIS s.base_ioaddr,
&BX_PNIC_THIS s.pci_conf[0x10],
16, &pnic_iomask[0], "PNIC")) {
BX_INFO(("new base address: 0x%04x", BX_PNIC_THIS s.base_ioaddr));
}
}
void bx_pcipnic_c::set_irq_level(bx_bool level)
{
DEV_pci_set_irq(BX_PNIC_THIS s.devfunc, BX_PNIC_THIS s.pci_conf[0x3d], level);
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_pcipnic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PCIPNIC_SMF
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_pcipnic_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PCIPNIC_SMF
Bit32u val = 0x0;
Bit8u offset;
BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
offset = address - BX_PNIC_THIS s.base_ioaddr;
switch (offset) {
case PNIC_REG_STAT:
val = BX_PNIC_THIS s.rStatus;
break;
case PNIC_REG_LEN:
val = BX_PNIC_THIS s.rLength;
break;
case PNIC_REG_DATA:
if (BX_PNIC_THIS s.rDataCursor >= BX_PNIC_THIS s.rLength)
BX_PANIC(("PNIC read at %u, beyond end of data register array",
BX_PNIC_THIS s.rDataCursor));
val = BX_PNIC_THIS s.rData[BX_PNIC_THIS s.rDataCursor++];
break;
default :
val = 0; // keep compiler happy
BX_PANIC(("unsupported io read from address=0x%04x!", (unsigned) address));
break;
}
BX_DEBUG(("val = 0x%04x", (Bit16u) val));
return(val);
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_pcipnic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PCIPNIC_SMF
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_pcipnic_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PCIPNIC_SMF
Bit8u offset;
BX_DEBUG(("register write to address 0x%04x - ", (unsigned) address));
offset = address - BX_PNIC_THIS s.base_ioaddr;
switch (offset) {
case PNIC_REG_CMD:
BX_PNIC_THIS s.rCmd = value;
BX_PNIC_THIS exec_command();
break;
case PNIC_REG_LEN:
if (value > PNIC_DATA_SIZE)
BX_PANIC(("PNIC bad length %u written to length register, max is %u",
value, PNIC_DATA_SIZE));
BX_PNIC_THIS s.rLength = value;
BX_PNIC_THIS s.rDataCursor = 0;
break;
case PNIC_REG_DATA:
if (BX_PNIC_THIS s.rDataCursor >= BX_PNIC_THIS s.rLength)
BX_PANIC(("PNIC write at %u, beyond end of data register array",
BX_PNIC_THIS s.rDataCursor));
BX_PNIC_THIS s.rData[BX_PNIC_THIS s.rDataCursor++] = value;
break;
default:
BX_PANIC(("unsupported io write to address=0x%04x!", (unsigned) address));
break;
}
}
void bx_pcipnic_c::pnic_timer_handler(void *this_ptr)
{
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) this_ptr;
class_ptr->pnic_timer();
}
// Called once every 1ms
void bx_pcipnic_c::pnic_timer(void)
{
// Do nothing atm
}
// pci configuration space read callback handler
Bit32u bx_pcipnic_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_PNIC_THIS s.pci_conf[address+i] << (i*8));
}
if (io_len == 1)
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
return value;
}
// pci configuration space write callback handler
void bx_pcipnic_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
Bit8u value8, oldval;
bx_bool baseaddr_change = 0;
if (((address >= 0x10) && (address < 0x20)) ||
((address > 0x23) && (address < 0x34)))
return;
for (unsigned i=0; i<io_len; i++) {
value8 = (value >> (i*8)) & 0xFF;
oldval = BX_PNIC_THIS s.pci_conf[address+i];
switch (address+i) {
case 0x3d: //
case 0x05: // disallowing write to command hi-byte
case 0x06: // disallowing write to status lo-byte (is that expected?)
break;
case 0x3c:
if (value8 != oldval) {
BX_INFO(("new irq line = %d", value8));
BX_PNIC_THIS s.pci_conf[address+i] = value8;
}
break;
case 0x20:
value8 = (value8 & 0xfc) | 0x01;
case 0x21:
case 0x22:
case 0x23:
baseaddr_change = (value8 != oldval);
default:
BX_PNIC_THIS s.pci_conf[address+i] = value8;
}
}
if (baseaddr_change) {
if (DEV_pci_set_base_io(BX_PNIC_THIS_PTR, read_handler, write_handler,
&BX_PNIC_THIS s.base_ioaddr,
&BX_PNIC_THIS s.pci_conf[0x20],
16, &pnic_iomask[0], "PNIC")) {
BX_INFO(("new base address: 0x%04x", BX_PNIC_THIS s.base_ioaddr));
}
}
if (io_len == 1)
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
}
/*
* Execute a hardware command.
*/
void bx_pcipnic_c::exec_command(void)
{
Bit16u command = BX_PNIC_THIS s.rCmd;
Bit16u ilength = BX_PNIC_THIS s.rLength;
Bit8u *data = BX_PNIC_THIS s.rData;
// Default return values
Bit16u status = PNIC_STATUS_UNKNOWN_CMD;
Bit16u olength = 0;
if (ilength != BX_PNIC_THIS s.rDataCursor)
BX_PANIC(("PNIC command issued with incomplete data (should be %u, is %u)",
ilength, BX_PNIC_THIS s.rDataCursor));
switch (command) {
case PNIC_CMD_NOOP:
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_API_VER:
Bit16u api_version;
api_version = PNIC_API_VERSION;
olength = sizeof(api_version);
memcpy (data, &api_version, sizeof(api_version));
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_READ_MAC:
olength = sizeof (BX_PNIC_THIS s.macaddr);
memcpy (data, BX_PNIC_THIS s.macaddr, olength);
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_RESET:
/* Flush the receive queue */
BX_PNIC_THIS s.recvQueueLength = 0;
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_XMIT:
BX_PNIC_THIS ethdev->sendpkt(data, ilength);
if (BX_PNIC_THIS s.irqEnabled) {
set_irq_level(1);
}
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_RECV:
if (BX_PNIC_THIS s.recvQueueLength > 0) {
int idx = (BX_PNIC_THIS s.recvIndex - BX_PNIC_THIS s.recvQueueLength
+ PNIC_RECV_RINGS) % PNIC_RECV_RINGS;
olength = BX_PNIC_THIS s.recvRingLength[idx];
memcpy (data, BX_PNIC_THIS s.recvRing[idx], olength);
BX_PNIC_THIS s.recvQueueLength--;
}
if (! BX_PNIC_THIS s.recvQueueLength) {
set_irq_level(0);
}
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_RECV_QLEN:
Bit16u qlen;
qlen = BX_PNIC_THIS s.recvQueueLength;
olength = sizeof(qlen);
memcpy (data, &qlen, sizeof(qlen));
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_MASK_IRQ:
Bit8u enabled;
enabled = *((Bit8u*)data);
BX_PNIC_THIS s.irqEnabled = enabled;
if (enabled && BX_PNIC_THIS s.recvQueueLength) {
set_irq_level(1);
} else {
set_irq_level(0);
}
status = PNIC_STATUS_OK;
break;
case PNIC_CMD_FORCE_IRQ:
set_irq_level(1);
status = PNIC_STATUS_OK;
break;
default:
BX_ERROR(("Unknown PNIC command %x (data length %u)", command, ilength));
status = PNIC_STATUS_UNKNOWN_CMD;
break;
}
// Set registers
BX_PNIC_THIS s.rStatus = status;
BX_PNIC_THIS s.rLength = olength;
BX_PNIC_THIS s.rDataCursor = 0;
}
/*
* Callback from the eth system driver when a frame has arrived
*/
void bx_pcipnic_c::rx_handler(void *arg, const void *buf, unsigned len)
{
// BX_DEBUG(("rx_handler with length %d", len));
bx_pcipnic_c *class_ptr = (bx_pcipnic_c *) arg;
class_ptr->rx_frame(buf, len);
}
/*
* rx_frame() - called by the platform-specific code when an
* ethernet frame has been received. The destination address
* is tested to see if it should be accepted, and if the
* rx ring has enough room, it is copied into it and
* the receive process is updated
*/
void bx_pcipnic_c::rx_frame(const void *buf, unsigned io_len)
{
// Check packet length
if (io_len > PNIC_DATA_SIZE) {
BX_PANIC(("PNIC receive: data size %u exceeded buffer size %u",
io_len, PNIC_DATA_SIZE));
// Truncate if user continues
io_len = PNIC_DATA_SIZE;
}
// Check receive ring is not full
if (BX_PNIC_THIS s.recvQueueLength == PNIC_RECV_RINGS) {
BX_ERROR(("PNIC receive: receive ring full, discarding packet"));
return;
}
// Copy data to receive ring and record length
memcpy (BX_PNIC_THIS s.recvRing[BX_PNIC_THIS s.recvIndex], buf, io_len);
BX_PNIC_THIS s.recvRingLength[BX_PNIC_THIS s.recvIndex] = io_len;
// Move to next ring entry
BX_PNIC_THIS s.recvIndex = (BX_PNIC_THIS s.recvIndex + 1) % PNIC_RECV_RINGS;
BX_PNIC_THIS s.recvQueueLength++;
// Generate interrupt if enabled
if (BX_PNIC_THIS s.irqEnabled) {
set_irq_level(1);
}
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIPNIC

96
bochs/iodev/pcipnic.h Normal file
View File

@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003 Fen Systems Ltd.
// http://www.fensystems.co.uk/
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PCIPNIC_H
#define BX_IODEV_PCIPNIC_H
#include "pnic_api.h"
#if BX_USE_PCIPNIC_SMF
# define BX_PNIC_SMF static
# define BX_PNIC_THIS thePNICDevice->
# define BX_PNIC_THIS_PTR thePNICDevice
#else
# define BX_PNIC_SMF
# define BX_PNIC_THIS this->
# define BX_PNIC_THIS_PTR this
#endif
#define PNIC_DATA_SIZE 4096
#define PNIC_RECV_RINGS 4
typedef struct {
Bit32u base_ioaddr;
Bit8u macaddr[6];
Bit8u irqEnabled;
Bit16u rCmd; // Command register
Bit16u rStatus; // Status register
Bit16u rLength; // Length register
Bit8u rData[PNIC_DATA_SIZE]; // Data register array
Bit16u rDataCursor;
int recvIndex;
int recvQueueLength;
Bit8u recvRing[PNIC_RECV_RINGS][PNIC_DATA_SIZE]; // Receive buffer
Bit16u recvRingLength[PNIC_RECV_RINGS];
Bit8u devfunc;
Bit8u pci_conf[256];
} bx_pnic_t;
class bx_pcipnic_c : public bx_ne2k_stub_c, bx_pci_device_stub_c {
public:
bx_pcipnic_c();
virtual ~bx_pcipnic_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
private:
bx_pnic_t s;
static void set_irq_level(bx_bool level);
static void pnic_timer_handler(void *);
void pnic_timer(void);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PCIPNIC_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
eth_pktmover_c *ethdev;
static void exec_command(void);
static void rx_handler(void *arg, const void *buf, unsigned len);
BX_PNIC_SMF void rx_frame(const void *buf, unsigned io_len);
};
#endif

195
bochs/iodev/pcivga.cc Normal file
View File

@ -0,0 +1,195 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002,2003 Mike Nordell
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Experimental PCI VGA adapter
//
// Note: This "driver" was created for the SOLE PURPOSE of getting BeOS
// to boot. It currently does NOTHING more than presenting a generic VGA
// device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
// Furthermore, almost all of the PCI registers are currently acting like RAM.
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIVGA
#include "pci.h"
#include "pcivga.h"
#define LOG_THIS thePciVgaAdapter->
bx_pcivga_c* thePciVgaAdapter = 0;
int libpcivga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePciVgaAdapter = new bx_pcivga_c();
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciVgaAdapter, BX_PLUGIN_PCIVGA);
return 0; // Success
}
void libpcivga_LTX_plugin_fini(void)
{
delete thePciVgaAdapter;
}
bx_pcivga_c::bx_pcivga_c()
{
put("PCIVGA");
}
bx_pcivga_c::~bx_pcivga_c()
{
BX_DEBUG(("Exit"));
}
void bx_pcivga_c::init(void)
{
// called once when bochs initializes
Bit8u devfunc = 0x00;
unsigned i;
DEV_register_pci_handlers(this, &devfunc, BX_PLUGIN_PCIVGA,
"Experimental PCI VGA");
for (i=0; i<256; i++) {
BX_PCIVGA_THIS s.pci_conf[i] = 0x0;
}
// readonly registers
static const struct init_vals_t {
unsigned addr;
unsigned char val;
} init_vals[] = {
// Note that the values for vendor and device id are selected at random!
// There might actually be "real" values for "experimental" vendor and
// device that should be used!
{ 0x00, 0x34 }, { 0x01, 0x12 }, // 0x1234 - experimental vendor
{ 0x02, 0x11 }, { 0x03, 0x11 }, // 0x1111 - experimental device
{ 0x0a, 0x00 }, // class_sub VGA controller
{ 0x0b, 0x03 }, // class_base display
{ 0x0e, 0x00 } // header_type_generic
};
for (i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
BX_PCIVGA_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
}
WriteHostDWordToLittleEndian(&BX_PCIVGA_THIS s.pci_conf[0x10], 0x08);
BX_PCIVGA_THIS s.base_address = 0;
}
void bx_pcivga_c::reset(unsigned type)
{
static const struct reset_vals_t {
unsigned addr;
unsigned char val;
} reset_vals[] = {
{ 0x04, 0x03 }, { 0x05, 0x00 }, // command_io + command_mem
{ 0x06, 0x00 }, { 0x07, 0x02 } // status_devsel_medium
};
for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
BX_PCIVGA_THIS s.pci_conf[reset_vals[i].addr] = reset_vals[i].val;
}
}
void bx_pcivga_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pcivga", "PCI VGA Adapter State", 1);
register_pci_state(list, BX_PCIVGA_THIS s.pci_conf);
}
void bx_pcivga_c::after_restore_state(void)
{
if (DEV_vbe_set_base_addr(&BX_PCIVGA_THIS s.base_address,
&BX_PCIVGA_THIS s.pci_conf[0x10])) {
BX_INFO(("new base address: 0x%08x", BX_PCIVGA_THIS s.base_address));
}
}
// pci configuration space read callback handler
Bit32u bx_pcivga_c::pci_read_handler(Bit8u address, unsigned io_len)
{
Bit32u value = 0;
for (unsigned i=0; i<io_len; i++) {
value |= (BX_PCIVGA_THIS s.pci_conf[address+i] << (i*8));
}
if (io_len == 1)
BX_DEBUG(("read PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("read PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("read PCI register 0x%02x value 0x%08x", address, value));
return value;
}
// static pci configuration space write callback handler
void bx_pcivga_c::pci_write_handler(Bit8u address, Bit32u value, unsigned io_len)
{
unsigned i;
unsigned write_addr;
Bit8u new_value, old_value;
bx_bool baseaddr_change = 0;
if ((address >= 0x14) && (address < 0x34))
return;
for (i = 0; i < io_len; i++) {
write_addr = address + i;
old_value = BX_PCIVGA_THIS s.pci_conf[write_addr];
new_value = (Bit8u)(value & 0xff);
switch (write_addr) {
case 0x04: // disallowing write to command
case 0x06: // disallowing write to status lo-byte (is that expected?)
break;
case 0x10: // base address #0
new_value = (new_value & 0xf0) | (old_value & 0x0f);
case 0x11: case 0x12: case 0x13:
baseaddr_change |= (old_value != new_value);
default:
BX_PCIVGA_THIS s.pci_conf[write_addr] = new_value;
}
value >>= 8;
}
if (baseaddr_change) {
if (DEV_vbe_set_base_addr(&BX_PCIVGA_THIS s.base_address,
&BX_PCIVGA_THIS s.pci_conf[0x10])) {
BX_INFO(("new base address: 0x%08x", BX_PCIVGA_THIS s.base_address));
}
}
if (io_len == 1)
BX_DEBUG(("write PCI register 0x%02x value 0x%02x", address, value));
else if (io_len == 2)
BX_DEBUG(("write PCI register 0x%02x value 0x%04x", address, value));
else if (io_len == 4)
BX_DEBUG(("write PCI register 0x%02x value 0x%08x", address, value));
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIVGA

49
bochs/iodev/pcivga.h Normal file
View File

@ -0,0 +1,49 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002,2003 Mike Nordell
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PCIVGA_H
#define BX_IODEV_PCIVGA_H
#if BX_USE_PCIVGA_SMF
# define BX_PCIVGA_THIS thePciVgaAdapter->
#else
# define BX_PCIVGA_THIS this->
#endif
class bx_pcivga_c : public bx_devmodel_c, public bx_pci_device_stub_c {
public:
bx_pcivga_c();
virtual ~bx_pcivga_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void after_restore_state(void);
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
private:
struct {
Bit32u base_address;
Bit8u pci_conf[256];
} s;
};
#endif

889
bochs/iodev/pic.cc Normal file
View File

@ -0,0 +1,889 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "pic.h"
#define LOG_THIS thePic->
bx_pic_c *thePic = NULL;
int libpic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePic = new bx_pic_c();
bx_devices.pluginPicDevice = thePic;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePic, BX_PLUGIN_PIC);
return(0); // Success
}
void libpic_LTX_plugin_fini(void)
{
delete thePic;
}
bx_pic_c::bx_pic_c(void)
{
put("PIC");
}
bx_pic_c::~bx_pic_c(void)
{
BX_DEBUG(("Exit"));
}
void bx_pic_c::init(void)
{
/* 8259 PIC (Programmable Interrupt Controller) */
DEV_register_ioread_handler(this, read_handler, 0x0020, "8259 PIC", 1);
DEV_register_ioread_handler(this, read_handler, 0x0021, "8259 PIC", 1);
DEV_register_ioread_handler(this, read_handler, 0x00A0, "8259 PIC", 1);
DEV_register_ioread_handler(this, read_handler, 0x00A1, "8259 PIC", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0020, "8259 PIC", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0021, "8259 PIC", 1);
DEV_register_iowrite_handler(this, write_handler, 0x00A0, "8259 PIC", 1);
DEV_register_iowrite_handler(this, write_handler, 0x00A1, "8259 PIC", 1);
BX_PIC_THIS s.master_pic.single_PIC = 0;
BX_PIC_THIS s.master_pic.interrupt_offset = 0x08; /* IRQ0 = INT 0x08 */
/* slave PIC connected to IRQ2 of master */
BX_PIC_THIS s.master_pic.u.slave_connect_mask = 0x04;
BX_PIC_THIS s.master_pic.sfnm = 0; /* normal nested mode */
BX_PIC_THIS s.master_pic.buffered_mode = 0; /* unbuffered mode */
BX_PIC_THIS s.master_pic.master_slave = 1; /* master PIC */
BX_PIC_THIS s.master_pic.auto_eoi = 0; /* manual EOI from CPU */
BX_PIC_THIS s.master_pic.imr = 0xFF; /* all IRQ's initially masked */
BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
BX_PIC_THIS s.master_pic.read_reg_select = 0; /* IRR */
BX_PIC_THIS s.master_pic.irq = 0;
BX_PIC_THIS s.master_pic.INT = 0;
BX_PIC_THIS s.master_pic.init.in_init = 0;
BX_PIC_THIS s.master_pic.init.requires_4 = 0;
BX_PIC_THIS s.master_pic.init.byte_expected = 0;
BX_PIC_THIS s.master_pic.special_mask = 0;
BX_PIC_THIS s.master_pic.lowest_priority = 7;
BX_PIC_THIS s.master_pic.polled = 0;
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
BX_PIC_THIS s.master_pic.edge_level = 0;
BX_PIC_THIS s.master_pic.IRQ_in = 0;
BX_PIC_THIS s.slave_pic.single_PIC = 0;
BX_PIC_THIS s.slave_pic.interrupt_offset = 0x70; /* IRQ8 = INT 0x70 */
BX_PIC_THIS s.slave_pic.u.slave_id = 0x02; /* slave PIC connected to IRQ2 of master */
BX_PIC_THIS s.slave_pic.sfnm = 0; /* normal nested mode */
BX_PIC_THIS s.slave_pic.buffered_mode = 0; /* unbuffered mode */
BX_PIC_THIS s.slave_pic.master_slave = 0; /* slave PIC */
BX_PIC_THIS s.slave_pic.auto_eoi = 0; /* manual EOI from CPU */
BX_PIC_THIS s.slave_pic.imr = 0xFF; /* all IRQ's initially masked */
BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
BX_PIC_THIS s.slave_pic.read_reg_select = 0; /* IRR */
BX_PIC_THIS s.slave_pic.irq = 0;
BX_PIC_THIS s.slave_pic.INT = 0;
BX_PIC_THIS s.slave_pic.init.in_init = 0;
BX_PIC_THIS s.slave_pic.init.requires_4 = 0;
BX_PIC_THIS s.slave_pic.init.byte_expected = 0;
BX_PIC_THIS s.slave_pic.special_mask = 0;
BX_PIC_THIS s.slave_pic.lowest_priority = 7;
BX_PIC_THIS s.slave_pic.polled = 0;
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
BX_PIC_THIS s.slave_pic.edge_level = 0;
BX_PIC_THIS s.slave_pic.IRQ_in = 0;
}
void bx_pic_c::reset(unsigned type) {}
void bx_pic_c::register_state(void)
{
bx_list_c *ctrl;
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pic", "PIC State", 2);
ctrl = new bx_list_c(list, "master", 17);
new bx_shadow_num_c(ctrl, "interrupt_offset", &BX_PIC_THIS s.master_pic.interrupt_offset, BASE_HEX);
new bx_shadow_num_c(ctrl, "auto_eoi", &BX_PIC_THIS s.master_pic.auto_eoi, BASE_HEX);
new bx_shadow_num_c(ctrl, "imr", &BX_PIC_THIS s.master_pic.imr, BASE_HEX);
new bx_shadow_num_c(ctrl, "isr", &BX_PIC_THIS s.master_pic.isr, BASE_HEX);
new bx_shadow_num_c(ctrl, "irr", &BX_PIC_THIS s.master_pic.irr, BASE_HEX);
new bx_shadow_num_c(ctrl, "read_reg_select", &BX_PIC_THIS s.master_pic.read_reg_select);
new bx_shadow_num_c(ctrl, "irq", &BX_PIC_THIS s.master_pic.irq, BASE_HEX);
new bx_shadow_num_c(ctrl, "lowest_priority", &BX_PIC_THIS s.master_pic.lowest_priority, BASE_HEX);
new bx_shadow_bool_c(ctrl, "INT", &BX_PIC_THIS s.master_pic.INT);
new bx_shadow_num_c(ctrl, "IRQ_in", &BX_PIC_THIS s.master_pic.IRQ_in, BASE_HEX);
new bx_shadow_bool_c(ctrl, "in_init", &BX_PIC_THIS s.master_pic.init.in_init);
new bx_shadow_bool_c(ctrl, "requires_4", &BX_PIC_THIS s.master_pic.init.requires_4);
new bx_shadow_num_c(ctrl, "byte_expected", &BX_PIC_THIS s.master_pic.init.byte_expected);
new bx_shadow_bool_c(ctrl, "special_mask", &BX_PIC_THIS s.master_pic.special_mask);
new bx_shadow_bool_c(ctrl, "polled", &BX_PIC_THIS s.master_pic.polled);
new bx_shadow_bool_c(ctrl, "rotate_on_autoeoi", &BX_PIC_THIS s.master_pic.rotate_on_autoeoi);
new bx_shadow_num_c(ctrl, "edge_level", &BX_PIC_THIS s.master_pic.edge_level, BASE_HEX);
ctrl = new bx_list_c(list, "slave", 17);
new bx_shadow_num_c(ctrl, "interrupt_offset", &BX_PIC_THIS s.slave_pic.interrupt_offset, BASE_HEX);
new bx_shadow_num_c(ctrl, "auto_eoi", &BX_PIC_THIS s.slave_pic.auto_eoi, BASE_HEX);
new bx_shadow_num_c(ctrl, "imr", &BX_PIC_THIS s.slave_pic.imr, BASE_HEX);
new bx_shadow_num_c(ctrl, "isr", &BX_PIC_THIS s.slave_pic.isr, BASE_HEX);
new bx_shadow_num_c(ctrl, "irr", &BX_PIC_THIS s.slave_pic.irr, BASE_HEX);
new bx_shadow_num_c(ctrl, "read_reg_select", &BX_PIC_THIS s.slave_pic.read_reg_select);
new bx_shadow_num_c(ctrl, "irq", &BX_PIC_THIS s.slave_pic.irq, BASE_HEX);
new bx_shadow_num_c(ctrl, "lowest_priority", &BX_PIC_THIS s.slave_pic.lowest_priority, BASE_HEX);
new bx_shadow_bool_c(ctrl, "INT", &BX_PIC_THIS s.slave_pic.INT);
new bx_shadow_num_c(ctrl, "IRQ_in", &BX_PIC_THIS s.slave_pic.IRQ_in, BASE_HEX);
new bx_shadow_bool_c(ctrl, "in_init", &BX_PIC_THIS s.slave_pic.init.in_init);
new bx_shadow_bool_c(ctrl, "requires_4", &BX_PIC_THIS s.slave_pic.init.requires_4);
new bx_shadow_num_c(ctrl, "byte_expected", &BX_PIC_THIS s.slave_pic.init.byte_expected);
new bx_shadow_bool_c(ctrl, "special_mask", &BX_PIC_THIS s.slave_pic.special_mask);
new bx_shadow_bool_c(ctrl, "polled", &BX_PIC_THIS s.slave_pic.polled);
new bx_shadow_bool_c(ctrl, "rotate_on_autoeoi", &BX_PIC_THIS s.slave_pic.rotate_on_autoeoi);
new bx_shadow_num_c(ctrl, "edge_level", &BX_PIC_THIS s.slave_pic.edge_level, BASE_HEX);
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_pic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PIC_SMF
bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_pic_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIC_SMF
BX_DEBUG(("IO read from %04x", (unsigned) address));
/*
8259A PIC
*/
if((address == 0x20 || address == 0x21) && BX_PIC_THIS s.master_pic.polled) {
// In polled mode. Treat this as an interrupt acknowledge
clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
BX_PIC_THIS s.master_pic.polled = 0;
service_master_pic();
return io_len==1?BX_PIC_THIS s.master_pic.irq:(BX_PIC_THIS s.master_pic.irq)<<8|(BX_PIC_THIS s.master_pic.irq); // Return the current irq requested
}
if((address == 0xa0 || address == 0xa1) && BX_PIC_THIS s.slave_pic.polled) {
// In polled mode. Treat this as an interrupt acknowledge
clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
BX_PIC_THIS s.slave_pic.polled = 0;
service_slave_pic();
return io_len==1?BX_PIC_THIS s.slave_pic.irq:(BX_PIC_THIS s.slave_pic.irq)<<8|(BX_PIC_THIS s.slave_pic.irq); // Return the current irq requested
}
switch (address) {
case 0x20:
if (BX_PIC_THIS s.master_pic.read_reg_select) { /* ISR */
BX_DEBUG(("read master ISR = %02x",
(unsigned) BX_PIC_THIS s.master_pic.isr));
return(BX_PIC_THIS s.master_pic.isr);
}
else { /* IRR */
BX_DEBUG(("read master IRR = %02x",
(unsigned) BX_PIC_THIS s.master_pic.irr));
return(BX_PIC_THIS s.master_pic.irr);
}
break;
case 0x21:
BX_DEBUG(("read master IMR = %02x",
(unsigned) BX_PIC_THIS s.master_pic.imr));
return(BX_PIC_THIS s.master_pic.imr);
case 0xA0:
if (BX_PIC_THIS s.slave_pic.read_reg_select) { /* ISR */
BX_DEBUG(("read slave ISR = %02x",
(unsigned) BX_PIC_THIS s.slave_pic.isr));
return(BX_PIC_THIS s.slave_pic.isr);
}
else { /* IRR */
BX_DEBUG(("read slave IRR = %02x",
(unsigned) BX_PIC_THIS s.slave_pic.irr));
return(BX_PIC_THIS s.slave_pic.irr);
}
break;
case 0xA1:
BX_DEBUG(("read slave IMR = %02x",
(unsigned) BX_PIC_THIS s.slave_pic.imr));
return(BX_PIC_THIS s.slave_pic.imr);
}
BX_PANIC(("io read to address %04x", (unsigned) address));
return(0); /* default if not found above */
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_pic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_PIC_SMF
bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
class_ptr->write(address, value, io_len);
}
void bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIC_SMF
BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value));
/*
8259A PIC
*/
switch (address) {
case 0x20:
if (value & 0x10) { /* initialization command 1 */
BX_DEBUG(("master: init command 1 found"));
BX_DEBUG((" requires 4 = %u", (unsigned) (value & 0x01)));
BX_DEBUG((" cascade mode: [0=cascade,1=single] %u",
(unsigned) ((value & 0x02) >> 1)));
BX_PIC_THIS s.master_pic.init.in_init = 1;
BX_PIC_THIS s.master_pic.init.requires_4 = (value & 0x01);
BX_PIC_THIS s.master_pic.init.byte_expected = 2; /* operation command 2 */
BX_PIC_THIS s.master_pic.imr = 0x00; /* clear the irq mask register */
BX_PIC_THIS s.master_pic.isr = 0x00; /* no IRQ's in service */
BX_PIC_THIS s.master_pic.irr = 0x00; /* no IRQ's requested */
BX_PIC_THIS s.master_pic.lowest_priority = 7;
BX_PIC_THIS s.master_pic.INT = 0; /* reprogramming clears previous INTR request */
BX_PIC_THIS s.master_pic.auto_eoi = 0;
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
if (value & 0x02)
BX_PANIC(("master: ICW1: single mode not supported"));
if (value & 0x08) {
BX_PANIC(("master: ICW1: level sensitive mode not supported"));
}
else {
BX_DEBUG(("master: ICW1: edge triggered mode selected"));
}
BX_SET_INTR(0);
return;
}
if ((value & 0x18) == 0x08) { /* OCW3 */
Bit8u special_mask, poll, read_op;
special_mask = (value & 0x60) >> 5;
poll = (value & 0x04) >> 2;
read_op = (value & 0x03);
if (poll) {
BX_PIC_THIS s.master_pic.polled = 1;
return;
}
if (read_op == 0x02) /* read IRR */
BX_PIC_THIS s.master_pic.read_reg_select = 0;
else if (read_op == 0x03) /* read ISR */
BX_PIC_THIS s.master_pic.read_reg_select = 1;
if (special_mask == 0x02) { /* cancel special mask */
BX_PIC_THIS s.master_pic.special_mask = 0;
}
else if (special_mask == 0x03) { /* set specific mask */
BX_PIC_THIS s.master_pic.special_mask = 1;
service_master_pic();
}
return;
}
/* OCW2 */
switch (value) {
case 0x00: // Rotate in auto eoi mode clear
case 0x80: // Rotate in auto eoi mode set
BX_PIC_THIS s.master_pic.rotate_on_autoeoi = (value != 0);
break;
case 0x0A: /* select read interrupt request register */
BX_PIC_THIS s.master_pic.read_reg_select = 0;
break;
case 0x0B: /* select read interrupt in-service register */
BX_PIC_THIS s.master_pic.read_reg_select = 1;
break;
case 0xA0: // Rotate on non-specific end of interrupt
case 0x20: /* end of interrupt command */
clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
if(value == 0xA0) {// Rotate in Auto-EOI mode
BX_PIC_THIS s.master_pic.lowest_priority ++;
if(BX_PIC_THIS s.master_pic.lowest_priority > 7)
BX_PIC_THIS s.master_pic.lowest_priority = 0;
}
service_master_pic();
break;
case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
BX_INFO(("IRQ no-op"));
break;
case 0x60: /* specific EOI 0 */
case 0x61: /* specific EOI 1 */
case 0x62: /* specific EOI 2 */
case 0x63: /* specific EOI 3 */
case 0x64: /* specific EOI 4 */
case 0x65: /* specific EOI 5 */
case 0x66: /* specific EOI 6 */
case 0x67: /* specific EOI 7 */
BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0x60));
service_master_pic();
break;
// IRQ lowest priority commands
case 0xC0: // 0 7 6 5 4 3 2 1
case 0xC1: // 1 0 7 6 5 4 3 2
case 0xC2: // 2 1 0 7 6 5 4 3
case 0xC3: // 3 2 1 0 7 6 5 4
case 0xC4: // 4 3 2 1 0 7 6 5
case 0xC5: // 5 4 3 2 1 0 7 6
case 0xC6: // 6 5 4 3 2 1 0 7
case 0xC7: // 7 6 5 4 3 2 1 0
BX_INFO(("IRQ lowest command 0x%x", value));
BX_PIC_THIS s.master_pic.lowest_priority = value - 0xC0;
break;
case 0xE0: // specific EOI and rotate 0
case 0xE1: // specific EOI and rotate 1
case 0xE2: // specific EOI and rotate 2
case 0xE3: // specific EOI and rotate 3
case 0xE4: // specific EOI and rotate 4
case 0xE5: // specific EOI and rotate 5
case 0xE6: // specific EOI and rotate 6
case 0xE7: // specific EOI and rotate 7
BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0xE0));
BX_PIC_THIS s.master_pic.lowest_priority = (value - 0xE0);
service_master_pic();
break;
case 0x02: // single mode bit: 1 = single, 0 = cascade
// ignore. 386BSD writes this value but works with it ignored.
break;
default:
BX_PANIC(("write to port 20h = %02x", value));
} /* switch (value) */
break;
case 0x21:
/* initialization mode operation */
if (BX_PIC_THIS s.master_pic.init.in_init) {
switch (BX_PIC_THIS s.master_pic.init.byte_expected) {
case 2:
BX_PIC_THIS s.master_pic.interrupt_offset = value & 0xf8;
BX_PIC_THIS s.master_pic.init.byte_expected = 3;
BX_DEBUG(("master: init command 2 = %02x", (unsigned) value));
BX_DEBUG((" offset = INT %02x",
BX_PIC_THIS s.master_pic.interrupt_offset));
return;
break;
case 3:
BX_DEBUG(("master: init command 3 = %02x", (unsigned) value));
if (BX_PIC_THIS s.master_pic.init.requires_4) {
BX_PIC_THIS s.master_pic.init.byte_expected = 4;
}
else {
BX_PIC_THIS s.master_pic.init.in_init = 0;
}
return;
break;
case 4:
BX_DEBUG(("master: init command 4 = %02x", (unsigned) value));
if (value & 0x02) {
BX_DEBUG((" auto EOI"));
BX_PIC_THIS s.master_pic.auto_eoi = 1;
}
else {
BX_DEBUG(("normal EOI interrupt"));
BX_PIC_THIS s.master_pic.auto_eoi = 0;
}
if (value & 0x01) {
BX_DEBUG((" 80x86 mode"));
} else
BX_PANIC((" not 80x86 mode"));
BX_PIC_THIS s.master_pic.init.in_init = 0;
return;
default:
BX_PANIC(("master expecting bad init command"));
}
}
/* normal operation */
BX_DEBUG(("setting master pic IMR to %02x", value));
BX_PIC_THIS s.master_pic.imr = value;
service_master_pic();
return;
case 0xA0:
if (value & 0x10) { /* initialization command 1 */
BX_DEBUG(("slave: init command 1 found"));
BX_DEBUG((" requires 4 = %u",
(unsigned) (value & 0x01)));
BX_DEBUG((" cascade mode: [0=cascade,1=single] %u",
(unsigned) ((value & 0x02) >> 1)));
BX_PIC_THIS s.slave_pic.init.in_init = 1;
BX_PIC_THIS s.slave_pic.init.requires_4 = (value & 0x01);
BX_PIC_THIS s.slave_pic.init.byte_expected = 2; /* operation command 2 */
BX_PIC_THIS s.slave_pic.imr = 0x00; /* clear irq mask */
BX_PIC_THIS s.slave_pic.isr = 0x00; /* no IRQ's in service */
BX_PIC_THIS s.slave_pic.irr = 0x00; /* no IRQ's requested */
BX_PIC_THIS s.slave_pic.lowest_priority = 7;
BX_PIC_THIS s.slave_pic.INT = 0; /* reprogramming clears previous INTR request */
BX_PIC_THIS s.master_pic.IRQ_in &= ~(1 << 2);
BX_PIC_THIS s.slave_pic.auto_eoi = 0;
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
if (value & 0x02)
BX_PANIC(("slave: ICW1: single mode not supported"));
if (value & 0x08) {
BX_PANIC(("slave: ICW1: level sensitive mode not supported"));
}
else {
BX_DEBUG(("slave: ICW1: edge triggered mode selected"));
}
return;
}
if ((value & 0x18) == 0x08) { /* OCW3 */
Bit8u special_mask, poll, read_op;
special_mask = (value & 0x60) >> 5;
poll = (value & 0x04) >> 2;
read_op = (value & 0x03);
if (poll) {
BX_PIC_THIS s.slave_pic.polled = 1;
return;
}
if (read_op == 0x02) /* read IRR */
BX_PIC_THIS s.slave_pic.read_reg_select = 0;
else if (read_op == 0x03) /* read ISR */
BX_PIC_THIS s.slave_pic.read_reg_select = 1;
if (special_mask == 0x02) { /* cancel special mask */
BX_PIC_THIS s.slave_pic.special_mask = 0;
}
else if (special_mask == 0x03) { /* set specific mask */
BX_PIC_THIS s.slave_pic.special_mask = 1;
service_slave_pic();
}
return;
}
switch (value) {
case 0x00: // Rotate in auto eoi mode clear
case 0x80: // Rotate in auto eoi mode set
BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = (value != 0);
break;
case 0x0A: /* select read interrupt request register */
BX_PIC_THIS s.slave_pic.read_reg_select = 0;
break;
case 0x0B: /* select read interrupt in-service register */
BX_PIC_THIS s.slave_pic.read_reg_select = 1;
break;
case 0xA0: // Rotate on non-specific end of interrupt
case 0x20: /* end of interrupt command */
clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
if(value == 0xA0) {// Rotate in Auto-EOI mode
BX_PIC_THIS s.slave_pic.lowest_priority ++;
if(BX_PIC_THIS s.slave_pic.lowest_priority > 7)
BX_PIC_THIS s.slave_pic.lowest_priority = 0;
}
service_slave_pic();
break;
case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
BX_INFO(("IRQ no-op"));
break;
case 0x60: /* specific EOI 0 */
case 0x61: /* specific EOI 1 */
case 0x62: /* specific EOI 2 */
case 0x63: /* specific EOI 3 */
case 0x64: /* specific EOI 4 */
case 0x65: /* specific EOI 5 */
case 0x66: /* specific EOI 6 */
case 0x67: /* specific EOI 7 */
BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0x60));
service_slave_pic();
break;
// IRQ lowest priority commands
case 0xC0: // 0 7 6 5 4 3 2 1
case 0xC1: // 1 0 7 6 5 4 3 2
case 0xC2: // 2 1 0 7 6 5 4 3
case 0xC3: // 3 2 1 0 7 6 5 4
case 0xC4: // 4 3 2 1 0 7 6 5
case 0xC5: // 5 4 3 2 1 0 7 6
case 0xC6: // 6 5 4 3 2 1 0 7
case 0xC7: // 7 6 5 4 3 2 1 0
BX_INFO(("IRQ lowest command 0x%x", value));
BX_PIC_THIS s.slave_pic.lowest_priority = value - 0xC0;
break;
case 0xE0: // specific EOI and rotate 0
case 0xE1: // specific EOI and rotate 1
case 0xE2: // specific EOI and rotate 2
case 0xE3: // specific EOI and rotate 3
case 0xE4: // specific EOI and rotate 4
case 0xE5: // specific EOI and rotate 5
case 0xE6: // specific EOI and rotate 6
case 0xE7: // specific EOI and rotate 7
BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0xE0));
BX_PIC_THIS s.slave_pic.lowest_priority = (value - 0xE0);
service_slave_pic();
break;
case 0x02: // single mode bit: 1 = single, 0 = cascade
// ignore. 386BSD writes this value but works with it ignored.
break;
default:
BX_PANIC(("write to port A0h = %02x", value));
} /* switch (value) */
break;
case 0xA1:
/* initialization mode operation */
if (BX_PIC_THIS s.slave_pic.init.in_init) {
switch (BX_PIC_THIS s.slave_pic.init.byte_expected) {
case 2:
BX_PIC_THIS s.slave_pic.interrupt_offset = value & 0xf8;
BX_PIC_THIS s.slave_pic.init.byte_expected = 3;
BX_DEBUG(("slave: init command 2 = %02x", (unsigned) value));
BX_DEBUG((" offset = INT %02x",
BX_PIC_THIS s.slave_pic.interrupt_offset));
return;
case 3:
BX_DEBUG(("slave: init command 3 = %02x", (unsigned) value));
if (BX_PIC_THIS s.slave_pic.init.requires_4) {
BX_PIC_THIS s.slave_pic.init.byte_expected = 4;
} else {
BX_PIC_THIS s.slave_pic.init.in_init = 0;
}
return;
case 4:
BX_DEBUG(("slave: init command 4 = %02x", (unsigned) value));
if (value & 0x02) {
BX_DEBUG((" auto EOI"));
BX_PIC_THIS s.slave_pic.auto_eoi = 1;
}
else {
BX_DEBUG(("normal EOI interrupt"));
BX_PIC_THIS s.slave_pic.auto_eoi = 0;
}
if (value & 0x01) {
BX_DEBUG((" 80x86 mode"));
} else
BX_PANIC((" not 80x86 mode"));
BX_PIC_THIS s.slave_pic.init.in_init = 0;
return;
default:
BX_PANIC(("slave: expecting bad init command"));
}
}
/* normal operation */
BX_DEBUG(("setting slave pic IMR to %02x", value));
BX_PIC_THIS s.slave_pic.imr = value;
service_slave_pic();
return;
} /* switch (address) */
}
// new IRQ signal handling routines
void bx_pic_c::lower_irq(unsigned irq_no)
{
#if BX_SUPPORT_APIC
// forward this function call to the ioapic too
if (DEV_ioapic_present() && (irq_no != 2)) {
DEV_ioapic_set_irq_level(irq_no, 0);
}
#endif
Bit8u mask = (1 << (irq_no & 7));
if ((irq_no <= 7) && (BX_PIC_THIS s.master_pic.IRQ_in & mask)) {
BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
BX_PIC_THIS s.master_pic.IRQ_in &= ~(mask);
BX_PIC_THIS s.master_pic.irr &= ~(mask);
} else if ((irq_no > 7) && (irq_no <= 15) &&
(BX_PIC_THIS s.slave_pic.IRQ_in & mask)) {
BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
BX_PIC_THIS s.slave_pic.IRQ_in &= ~(mask);
BX_PIC_THIS s.slave_pic.irr &= ~(mask);
}
}
void bx_pic_c::raise_irq(unsigned irq_no)
{
#if BX_SUPPORT_APIC
// forward this function call to the ioapic too
if (DEV_ioapic_present() && (irq_no != 2)) {
DEV_ioapic_set_irq_level(irq_no, 1);
}
#endif
Bit8u mask = (1 << (irq_no & 7));
if ((irq_no <= 7) && !(BX_PIC_THIS s.master_pic.IRQ_in & mask)) {
BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
BX_PIC_THIS s.master_pic.IRQ_in |= mask;
BX_PIC_THIS s.master_pic.irr |= mask;
service_master_pic();
} else if ((irq_no > 7) && (irq_no <= 15) &&
!(BX_PIC_THIS s.slave_pic.IRQ_in & mask)) {
BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
BX_PIC_THIS s.slave_pic.IRQ_in |= mask;
BX_PIC_THIS s.slave_pic.irr |= mask;
service_slave_pic();
}
}
void bx_pic_c::set_mode(bx_bool ma_sl, Bit8u mode)
{
if (ma_sl) {
BX_PIC_THIS s.master_pic.edge_level = mode;
} else {
BX_PIC_THIS s.slave_pic.edge_level = mode;
}
}
void bx_pic_c::clear_highest_interrupt(bx_pic_t *pic)
{
int irq;
int lowest_priority;
int highest_priority;
/* clear highest current in service bit */
lowest_priority = pic->lowest_priority;
highest_priority = lowest_priority + 1;
if(highest_priority > 7)
highest_priority = 0;
irq = highest_priority;
do {
if (pic->isr & (1 << irq)) {
pic->isr &= ~(1 << irq);
break; /* Return mask of bit cleared. */
}
irq ++;
if(irq > 7)
irq = 0;
} while(irq != highest_priority);
}
void bx_pic_c::service_master_pic(void)
{
Bit8u unmasked_requests;
int irq;
Bit8u isr, max_irq;
Bit8u highest_priority = BX_PIC_THIS s.master_pic.lowest_priority + 1;
if(highest_priority > 7)
highest_priority = 0;
if (BX_PIC_THIS s.master_pic.INT) { /* last interrupt still not acknowleged */
return;
}
if (BX_PIC_THIS s.master_pic.special_mask) {
/* all priorities may be enabled. check all IRR bits except ones
* which have corresponding ISR bits set
*/
max_irq = highest_priority;
}
else { /* normal mode */
/* Find the highest priority IRQ that is enabled due to current ISR */
isr = BX_PIC_THIS s.master_pic.isr;
if (isr) {
max_irq = highest_priority;
while ((isr & (1 << max_irq)) == 0) {
max_irq++;
if(max_irq > 7)
max_irq = 0;
}
if (max_irq == highest_priority) return; /* Highest priority interrupt in-service,
* no other priorities allowed */
if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
}
else
max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
}
/* now, see if there are any higher priority requests */
if ((unmasked_requests = (BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr))) {
irq = highest_priority;
do {
/* for special mode, since we're looking at all IRQ's, skip if
* current IRQ is already in-service
*/
if (! (BX_PIC_THIS s.master_pic.special_mask && ((BX_PIC_THIS s.master_pic.isr >> irq) & 0x01))) {
if (unmasked_requests & (1 << irq)) {
BX_DEBUG(("signalling IRQ(%u)", (unsigned) irq));
BX_PIC_THIS s.master_pic.INT = 1;
BX_PIC_THIS s.master_pic.irq = irq;
BX_SET_INTR(1);
return;
} /* if (unmasked_requests & ... */
}
irq ++;
if(irq > 7)
irq = 0;
} while(irq != max_irq); /* do ... */
} /* if (unmasked_requests = ... */
}
void bx_pic_c::service_slave_pic(void)
{
Bit8u unmasked_requests;
int irq;
Bit8u isr, max_irq;
Bit8u highest_priority = BX_PIC_THIS s.slave_pic.lowest_priority + 1;
if(highest_priority > 7)
highest_priority = 0;
if (BX_PIC_THIS s.slave_pic.INT) { /* last interrupt still not acknowleged */
return;
}
if (BX_PIC_THIS s.slave_pic.special_mask) {
/* all priorities may be enabled. check all IRR bits except ones
* which have corresponding ISR bits set
*/
max_irq = highest_priority;
}
else { /* normal mode */
/* Find the highest priority IRQ that is enabled due to current ISR */
isr = BX_PIC_THIS s.slave_pic.isr;
if (isr) {
max_irq = highest_priority;
while ((isr & (1 << max_irq)) == 0) {
max_irq++;
if(max_irq > 7)
max_irq = 0;
}
if (max_irq == highest_priority) return; /* Highest priority interrupt in-service,
* no other priorities allowed */
if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
}
else
max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
}
/* now, see if there are any higher priority requests */
if ((unmasked_requests = (BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr))) {
irq = highest_priority;
do {
/* for special mode, since we're looking at all IRQ's, skip if
* current IRQ is already in-service
*/
if (! (BX_PIC_THIS s.slave_pic.special_mask && ((BX_PIC_THIS s.slave_pic.isr >> irq) & 0x01))) {
if (unmasked_requests & (1 << irq)) {
BX_DEBUG(("slave: signalling IRQ(%u)", (unsigned) 8 + irq));
BX_PIC_THIS s.slave_pic.INT = 1;
BX_PIC_THIS s.slave_pic.irq = irq;
BX_PIC_THIS raise_irq(2); /* request IRQ 2 on master pic */
return;
} /* if (unmasked_requests & ... */
}
irq ++;
if(irq > 7)
irq = 0;
} while(irq != max_irq); /* do ... */
} /* if (unmasked_requests = ... */
}
/* CPU handshakes with PIC after acknowledging interrupt */
Bit8u bx_pic_c::IAC(void)
{
Bit8u vector;
Bit8u irq;
BX_SET_INTR(0);
BX_PIC_THIS s.master_pic.INT = 0;
// Check for spurious interrupt
if (BX_PIC_THIS s.master_pic.irr == 0) {
return (BX_PIC_THIS s.master_pic.interrupt_offset + 7);
}
// In level sensitive mode don't clear the irr bit.
if (!(BX_PIC_THIS s.master_pic.edge_level & (1 << BX_PIC_THIS s.master_pic.irq)))
BX_PIC_THIS s.master_pic.irr &= ~(1 << BX_PIC_THIS s.master_pic.irq);
// In autoeoi mode don't set the isr bit.
if (!BX_PIC_THIS s.master_pic.auto_eoi)
BX_PIC_THIS s.master_pic.isr |= (1 << BX_PIC_THIS s.master_pic.irq);
else if (BX_PIC_THIS s.master_pic.rotate_on_autoeoi)
BX_PIC_THIS s.master_pic.lowest_priority = BX_PIC_THIS s.master_pic.irq;
if (BX_PIC_THIS s.master_pic.irq != 2) {
irq = BX_PIC_THIS s.master_pic.irq;
vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
} else { /* IRQ2 = slave pic IRQ8..15 */
BX_PIC_THIS s.slave_pic.INT = 0;
BX_PIC_THIS s.master_pic.IRQ_in &= ~(1 << 2);
// Check for spurious interrupt
if (BX_PIC_THIS s.slave_pic.irr == 0) {
return (BX_PIC_THIS s.slave_pic.interrupt_offset + 7);
}
irq = BX_PIC_THIS s.slave_pic.irq;
vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
// In level sensitive mode don't clear the irr bit.
if (!(BX_PIC_THIS s.slave_pic.edge_level & (1 << BX_PIC_THIS s.slave_pic.irq)))
BX_PIC_THIS s.slave_pic.irr &= ~(1 << BX_PIC_THIS s.slave_pic.irq);
// In autoeoi mode don't set the isr bit.
if (!BX_PIC_THIS s.slave_pic.auto_eoi)
BX_PIC_THIS s.slave_pic.isr |= (1 << BX_PIC_THIS s.slave_pic.irq);
else if (BX_PIC_THIS s.slave_pic.rotate_on_autoeoi)
BX_PIC_THIS s.slave_pic.lowest_priority = BX_PIC_THIS s.slave_pic.irq;
service_slave_pic();
irq += 8; // for debug printing purposes
}
service_master_pic();
BX_DBG_IAC_REPORT(vector, irq);
return(vector);
}
#if BX_DEBUGGER
void bx_pic_c::debug_dump(void)
{
dbg_printf("s.master_pic.imr = %02x\n", BX_PIC_THIS s.master_pic.imr);
dbg_printf("s.master_pic.isr = %02x\n", BX_PIC_THIS s.master_pic.isr);
dbg_printf("s.master_pic.irr = %02x\n", BX_PIC_THIS s.master_pic.irr);
dbg_printf("s.master_pic.irq = %02x\n", BX_PIC_THIS s.master_pic.irq);
dbg_printf("s.slave_pic.imr = %02x\n", BX_PIC_THIS s.slave_pic.imr);
dbg_printf("s.slave_pic.isr = %02x\n", BX_PIC_THIS s.slave_pic.isr);
dbg_printf("s.slave_pic.irr = %02x\n", BX_PIC_THIS s.slave_pic.irr);
dbg_printf("s.slave_pic.irq = %02x\n", BX_PIC_THIS s.slave_pic.irq);
}
#endif

97
bochs/iodev/pic.h Normal file
View File

@ -0,0 +1,97 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_IODEV_PIC_H
#define BX_IODEV_PIC_H
#if BX_USE_PIC_SMF
# define BX_PIC_SMF static
# define BX_PIC_THIS thePic->
#else
# define BX_PIC_SMF
# define BX_PIC_THIS this->
#endif
typedef struct {
Bit8u single_PIC; /* 0=cascaded PIC, 1=master only */
Bit8u interrupt_offset; /* programmable interrupt vector offset */
union {
Bit8u slave_connect_mask; /* for master, a bit for each interrupt line
0=not connect to a slave, 1=connected */
Bit8u slave_id; /* for slave, id number of slave PIC */
} u;
Bit8u sfnm; /* specially fully nested mode: 0=no, 1=yes*/
Bit8u buffered_mode; /* 0=no buffered mode, 1=buffered mode */
Bit8u master_slave; /* master/slave: 0=slave PIC, 1=master PIC */
Bit8u auto_eoi; /* 0=manual EOI, 1=automatic EOI */
Bit8u imr; /* interrupt mask register, 1=masked */
Bit8u isr; /* in service register */
Bit8u irr; /* interrupt request register */
Bit8u read_reg_select; /* 0=IRR, 1=ISR */
Bit8u irq; /* current IRQ number */
Bit8u lowest_priority; /* current lowest priority irq */
bx_bool INT; /* INT request pin of PIC */
Bit8u IRQ_in; /* IRQ pins of PIC */
struct {
bx_bool in_init;
bx_bool requires_4;
Bit8u byte_expected;
} init;
bx_bool special_mask;
bx_bool polled; /* Set when poll command is issued. */
bx_bool rotate_on_autoeoi; /* Set when should rotate in auto-eoi mode. */
Bit8u edge_level; /* bitmap for irq mode (0=edge, 1=level) */
} bx_pic_t;
class bx_pic_c : public bx_pic_stub_c {
public:
bx_pic_c();
virtual ~bx_pic_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void lower_irq(unsigned irq_no);
virtual void raise_irq(unsigned irq_no);
virtual void set_mode(bx_bool ma_sl, Bit8u mode);
virtual Bit8u IAC(void);
#if BX_DEBUGGER
virtual void debug_dump(void);
#endif
virtual void register_state(void);
private:
struct {
bx_pic_t master_pic;
bx_pic_t slave_pic;
} s;
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PIC_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
BX_PIC_SMF void service_master_pic(void);
BX_PIC_SMF void service_slave_pic(void);
BX_PIC_SMF void clear_highest_interrupt(bx_pic_t *pic);
};
#endif

972
bochs/iodev/pit82c54.cc Normal file
View File

@ -0,0 +1,972 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/*
* Emulator of an Intel 8254/82C54 Programmable Interval Timer.
* Greg Alexander <yakovlev@usa.com>
*
*
* Things I am unclear on (greg):
* 1.)What happens if both the status and count registers are latched,
* but the first of the two count registers has already been read?
* I.E.:
* latch count 0 (16-bit)
* Read count 0 (read LSByte)
* READ_BACK status of count 0
* Read count 0 - do you get MSByte or status?
* This will be flagged as an error.
* 2.)What happens when we latch the output in the middle of a 2-part
* unlatched read?
* 3.)I assumed that programming a counter removes a latched status.
* 4.)I implemented the 8254 description of mode 0, not the 82C54 one.
* 5.)clock() calls represent a rising clock edge followed by a falling
* clock edge.
* 6.)What happens when we trigger mode 1 in the middle of a 2-part
* write?
*/
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "pit82c54.h"
#define LOG_THIS this->
void pit_82C54::print_counter(counter_type &thisctr)
{
BX_INFO(("Printing Counter"));
BX_INFO(("count: %d",thisctr.count));
BX_INFO(("count_binary: %x",thisctr.count_binary));
BX_INFO(("counter gate: %x",thisctr.GATE));
BX_INFO(("counter OUT: %x",thisctr.OUTpin));
BX_INFO(("next_change_time: %d",thisctr.next_change_time));
BX_INFO(("End Counter Printout"));
}
void pit_82C54::print_cnum(Bit8u cnum)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Bad counter index to print_cnum"));
} else {
print_counter(counter[cnum]);
}
}
void pit_82C54::latch_counter(counter_type &thisctr)
{
if (thisctr.count_LSB_latched || thisctr.count_MSB_latched) {
//Do nothing because previous latch has not been read.;
} else {
switch(thisctr.read_state) {
case MSByte:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_MSB_latched=1;
break;
case LSByte:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
break;
case LSByte_multiple:
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
thisctr.count_MSB_latched=1;
break;
case MSByte_multiple:
if (!(seen_problems & UNL_2P_READ)) {
// seen_problems|=UNL_2P_READ;
BX_ERROR(("Unknown behavior when latching during 2-part read."));
BX_ERROR((" This message will not be repeated."));
}
//I guess latching and resetting to LSB first makes sense;
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
thisctr.outlatch=thisctr.count & 0xFFFF;
thisctr.count_LSB_latched=1;
thisctr.count_MSB_latched=1;
break;
default:
BX_ERROR(("Unknown read mode found during latch command."));
break;
}
}
}
void pit_82C54::set_OUT(counter_type &thisctr, bx_bool data)
{
if (thisctr.OUTpin != data) {
thisctr.OUTpin = data;
if (thisctr.out_handler != NULL) {
thisctr.out_handler(data);
}
}
}
void BX_CPP_AttrRegparmN(2) pit_82C54::set_count(counter_type &thisctr, Bit32u data)
{
thisctr.count=data & 0xFFFF;
set_binary_to_count(thisctr);
}
void BX_CPP_AttrRegparmN(1) pit_82C54::set_count_to_binary(counter_type &thisctr)
{
if (thisctr.bcd_mode) {
thisctr.count=
(((thisctr.count_binary/1)%10)<<0) |
(((thisctr.count_binary/10)%10)<<4) |
(((thisctr.count_binary/100)%10)<<8) |
(((thisctr.count_binary/1000)%10)<<12);
} else {
thisctr.count=thisctr.count_binary;
}
}
void BX_CPP_AttrRegparmN(1) pit_82C54::set_binary_to_count(counter_type &thisctr)
{
if (thisctr.bcd_mode) {
thisctr.count_binary=
(1*((thisctr.count>>0)&0xF)) +
(10*((thisctr.count>>4)&0xF)) +
(100*((thisctr.count>>8)&0xF)) +
(1000*((thisctr.count>>12)&0xF));
} else {
thisctr.count_binary=thisctr.count;
}
}
void BX_CPP_AttrRegparmN(1) pit_82C54::decrement (counter_type &thisctr)
{
if (!thisctr.count) {
if (thisctr.bcd_mode) {
thisctr.count=0x9999;
thisctr.count_binary=9999;
} else {
thisctr.count=0xFFFF;
thisctr.count_binary=0xFFFF;
}
} else {
thisctr.count_binary--;
set_count_to_binary(thisctr);
}
}
void pit_82C54::init(void)
{
put("PIT81");
for(int i=0;i<3;i++) {
BX_DEBUG(("Setting read_state to LSB"));
counter[i].read_state=LSByte;
counter[i].write_state=LSByte;
counter[i].GATE=1;
counter[i].OUTpin=1;
counter[i].triggerGATE=0;
counter[i].mode=4;
counter[i].first_pass=0;
counter[i].bcd_mode=0;
counter[i].count=0;
counter[i].count_binary=0;
counter[i].state_bit_1=0;
counter[i].state_bit_2=0;
counter[i].null_count=0;
counter[i].rw_mode=1;
counter[i].count_written=1;
counter[i].count_LSB_latched=0;
counter[i].count_MSB_latched=0;
counter[i].status_latched=0;
counter[i].next_change_time=0;
counter[i].out_handler=NULL;
}
seen_problems=0;
}
pit_82C54::pit_82C54(void)
{
init();
}
void pit_82C54::reset(unsigned type) {}
void pit_82C54::register_state(bx_param_c *parent)
{
char name[4];
for (unsigned i=0; i<3; i++) {
sprintf(name, "%d", i);
bx_list_c *tim = new bx_list_c(parent, name, 22);
new bx_shadow_bool_c(tim, "GATE", &counter[i].GATE);
new bx_shadow_bool_c(tim, "OUTpin", &counter[i].OUTpin);
new bx_shadow_num_c(tim, "count", &counter[i].count);
new bx_shadow_num_c(tim, "outlatch", &counter[i].outlatch);
new bx_shadow_num_c(tim, "inlatch", &counter[i].inlatch);
new bx_shadow_num_c(tim, "status_latch", &counter[i].status_latch);
new bx_shadow_num_c(tim, "rw_mode", &counter[i].rw_mode);
new bx_shadow_num_c(tim, "mode", &counter[i].mode);
new bx_shadow_bool_c(tim, "bcd_mode", &counter[i].bcd_mode);
new bx_shadow_bool_c(tim, "null_count", &counter[i].null_count);
new bx_shadow_bool_c(tim, "count_LSB_latched", &counter[i].count_LSB_latched);
new bx_shadow_bool_c(tim, "count_MSB_latched", &counter[i].count_MSB_latched);
new bx_shadow_bool_c(tim, "status_latched", &counter[i].status_latched);
new bx_shadow_num_c(tim, "count_binary", &counter[i].count_binary);
new bx_shadow_bool_c(tim, "triggerGATE", &counter[i].triggerGATE);
new bx_shadow_num_c(tim, "write_state", (Bit8u*)&counter[i].write_state);
new bx_shadow_num_c(tim, "read_state", (Bit8u*)&counter[i].read_state);
new bx_shadow_bool_c(tim, "count_written", &counter[i].count_written);
new bx_shadow_bool_c(tim, "first_pass", &counter[i].first_pass);
new bx_shadow_bool_c(tim, "state_bit_1", &counter[i].state_bit_1);
new bx_shadow_bool_c(tim, "state_bit_2", &counter[i].state_bit_2);
new bx_shadow_num_c(tim, "next_change_time", &counter[i].next_change_time);
}
}
void BX_CPP_AttrRegparmN(2) pit_82C54::decrement_multiple(counter_type &thisctr, Bit32u cycles)
{
while(cycles>0) {
if (cycles<=thisctr.count_binary) {
thisctr.count_binary-=cycles;
cycles-=cycles;
set_count_to_binary(thisctr);
} else {
cycles-=(thisctr.count_binary+1);
thisctr.count_binary-=thisctr.count_binary;
set_count_to_binary(thisctr);
decrement(thisctr);
}
}
}
void pit_82C54::clock_multiple(Bit8u cnum, Bit32u cycles)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number too high in clock"));
} else {
counter_type &thisctr = counter[cnum];
while(cycles>0) {
if (thisctr.next_change_time==0) {
if (thisctr.count_written) {
switch(thisctr.mode) {
case 0:
if (thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
decrement_multiple(thisctr, cycles);
}
break;
case 1:
decrement_multiple(thisctr, cycles);
break;
case 2:
if (!thisctr.first_pass && thisctr.GATE) {
decrement_multiple(thisctr, cycles);
}
break;
case 3:
if (!thisctr.first_pass && thisctr.GATE) {
decrement_multiple(thisctr, 2*cycles);
}
break;
case 4:
if (thisctr.GATE) {
decrement_multiple(thisctr, cycles);
}
break;
case 5:
decrement_multiple(thisctr, cycles);
break;
default:
break;
}
}
cycles-=cycles;
} else {
switch(thisctr.mode) {
case 0:
case 1:
case 2:
case 4:
case 5:
if (thisctr.next_change_time > cycles) {
decrement_multiple(thisctr,cycles);
thisctr.next_change_time-=cycles;
cycles-=cycles;
} else {
decrement_multiple(thisctr,(thisctr.next_change_time-1));
cycles-=thisctr.next_change_time;
clock(cnum);
}
break;
case 3:
if (thisctr.next_change_time > cycles) {
decrement_multiple(thisctr,cycles*2);
thisctr.next_change_time-=cycles;
cycles-=cycles;
} else {
decrement_multiple(thisctr,(thisctr.next_change_time-1)*2);
cycles-=thisctr.next_change_time;
clock(cnum);
}
break;
default:
cycles-=cycles;
break;
}
}
}
#if 0
print_counter(thisctr);
#endif
}
}
void BX_CPP_AttrRegparmN(1) pit_82C54::clock(Bit8u cnum)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number too high in clock"));
} else {
counter_type &thisctr = counter[cnum];
switch(thisctr.mode) {
case 0:
if (thisctr.count_written) {
if (thisctr.null_count) {
set_count(thisctr, thisctr.inlatch);
if (thisctr.GATE) {
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
thisctr.null_count=0;
} else {
if (thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
decrement(thisctr);
if (!thisctr.OUTpin) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if (!thisctr.count) {
set_OUT(thisctr,1);
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0; //if the clock isn't moving.
}
}
} else {
thisctr.next_change_time=0; //default to 0.
}
thisctr.triggerGATE=0;
break;
case 1:
if (thisctr.count_written) {
if (thisctr.triggerGATE) {
set_count(thisctr, thisctr.inlatch);
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
thisctr.null_count=0;
set_OUT(thisctr,0);
if (thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
} else {
decrement(thisctr);
if (!thisctr.OUTpin) {
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
if (thisctr.count==0) {
set_OUT(thisctr,1);
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0; //default to 0.
}
thisctr.triggerGATE=0;
break;
case 2:
if (thisctr.count_written) {
if (thisctr.triggerGATE || thisctr.first_pass) {
set_count(thisctr, thisctr.inlatch);
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
thisctr.null_count=0;
if (thisctr.inlatch==1) {
BX_ERROR(("ERROR: count of 1 is invalid in pit mode 2."));
}
if (!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if (thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=0;
} else {
if (thisctr.GATE) {
decrement(thisctr);
thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
if (thisctr.count==1) {
thisctr.next_change_time=1;
set_OUT(thisctr,0);
thisctr.first_pass=1;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 3:
if (thisctr.count_written) {
if ((thisctr.triggerGATE || thisctr.first_pass
|| thisctr.state_bit_2) && thisctr.GATE) {
set_count(thisctr, thisctr.inlatch & 0xFFFE);
thisctr.state_bit_1=thisctr.inlatch & 0x1;
if (!thisctr.OUTpin || !thisctr.state_bit_1) {
if (((thisctr.count_binary/2)-1)==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
}
} else {
if ((thisctr.count_binary/2)==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
}
}
thisctr.null_count=0;
if (thisctr.inlatch==1) {
BX_ERROR(("Count of 1 is invalid in pit mode 3."));
}
if (!thisctr.OUTpin) {
set_OUT(thisctr,1);
} else if (thisctr.OUTpin && !thisctr.first_pass) {
set_OUT(thisctr,0);
}
if (thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.state_bit_2=0;
thisctr.first_pass=0;
} else {
if (thisctr.GATE) {
decrement(thisctr);
decrement(thisctr);
if (!thisctr.OUTpin || !thisctr.state_bit_1) {
thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
} else {
thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
}
if (thisctr.count==0) {
thisctr.state_bit_2=1;
thisctr.next_change_time=1;
}
if ((thisctr.count==2) &&
(!thisctr.OUTpin || !thisctr.state_bit_1))
{
thisctr.state_bit_2=1;
thisctr.next_change_time=1;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 4:
if (thisctr.count_written) {
if (!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if (thisctr.null_count) {
set_count(thisctr, thisctr.inlatch);
if (thisctr.GATE) {
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
thisctr.null_count=0;
if (thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=1;
} else {
if (thisctr.GATE) {
decrement(thisctr);
if (thisctr.first_pass) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if (!thisctr.count) {
set_OUT(thisctr,0);
thisctr.next_change_time=1;
thisctr.first_pass=0;
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
case 5:
if (thisctr.count_written) {
if (!thisctr.OUTpin) {
set_OUT(thisctr,1);
}
if (thisctr.triggerGATE) {
set_count(thisctr, thisctr.inlatch);
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
thisctr.null_count=0;
if (thisctr.write_state==MSByte_multiple) {
BX_ERROR(("Undefined behavior when loading a half loaded count."));
}
thisctr.first_pass=1;
} else {
decrement(thisctr);
if (thisctr.first_pass) {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
if (!thisctr.count) {
set_OUT(thisctr,0);
thisctr.next_change_time=1;
thisctr.first_pass=0;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
thisctr.next_change_time=0;
}
thisctr.triggerGATE=0;
break;
default:
BX_ERROR(("Mode not implemented."));
thisctr.next_change_time=0;
thisctr.triggerGATE=0;
break;
}
}
}
void pit_82C54::clock_all(Bit32u cycles)
{
BX_DEBUG(("clock_all: cycles=%d",cycles));
clock_multiple(0,cycles);
clock_multiple(1,cycles);
clock_multiple(2,cycles);
}
Bit8u pit_82C54::read(Bit8u address)
{
if (address>MAX_ADDRESS) {
BX_ERROR(("Counter address incorrect in data read."));
} else if (address==CONTROL_ADDRESS) {
BX_DEBUG(("PIT Read: Control Word Register."));
//Read from control word register;
/* This might be okay. If so, 0 seems the most logical
* return value from looking at the docs.
*/
BX_ERROR(("Read from control word register not defined."));
return 0;
} else {
//Read from a counter;
BX_DEBUG(("PIT Read: Counter %d.",address));
counter_type &thisctr=counter[address];
if (thisctr.status_latched) {
//Latched Status Read;
if (thisctr.count_MSB_latched &&
(thisctr.read_state==MSByte_multiple)) {
BX_ERROR(("Undefined output when status latched and count half read."));
} else {
thisctr.status_latched=0;
return thisctr.status_latch;
}
} else {
//Latched Count Read;
if (thisctr.count_LSB_latched) {
//Read Least Significant Byte;
if (thisctr.read_state==LSByte_multiple) {
BX_DEBUG(("Setting read_state to MSB_mult"));
thisctr.read_state=MSByte_multiple;
}
thisctr.count_LSB_latched=0;
return (thisctr.outlatch & 0xFF);
} else if (thisctr.count_MSB_latched) {
//Read Most Significant Byte;
if (thisctr.read_state==MSByte_multiple) {
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
}
thisctr.count_MSB_latched=0;
return ((thisctr.outlatch>>8) & 0xFF);
} else {
//Unlatched Count Read;
if (!(thisctr.read_state & 0x1)) {
//Read Least Significant Byte;
if (thisctr.read_state==LSByte_multiple) {
thisctr.read_state=MSByte_multiple;
BX_DEBUG(("Setting read_state to MSB_mult"));
}
return (thisctr.count & 0xFF);
} else {
//Read Most Significant Byte;
if (thisctr.read_state==MSByte_multiple) {
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
}
return ((thisctr.count>>8) & 0xFF);
}
}
}
}
//Should only get here on errors;
return 0;
}
void pit_82C54::write(Bit8u address, Bit8u data)
{
if (address>MAX_ADDRESS) {
BX_ERROR(("Counter address incorrect in data write."));
} else if (address==CONTROL_ADDRESS) {
Bit8u SC, RW, M, BCD;
controlword=data;
BX_DEBUG(("Control Word Write."));
SC = (controlword>>6) & 0x3;
RW = (controlword>>4) & 0x3;
M = (controlword>>1) & 0x7;
BCD = controlword & 0x1;
if (SC == 3) {
//READ_BACK command;
int i;
BX_DEBUG(("READ_BACK command."));
for(i=0;i<=MAX_COUNTER;i++) {
if ((M>>i) & 0x1) {
//If we are using this counter;
counter_type &thisctr=counter[i];
if (!((controlword>>5) & 1)) {
//Latch Count;
latch_counter(thisctr);
}
if (!((controlword>>4) & 1)) {
//Latch Status;
if (thisctr.status_latched) {
//Do nothing because latched status has not been read.;
} else {
thisctr.status_latch=
((thisctr.OUTpin & 0x1) << 7) |
((thisctr.null_count & 0x1) << 6) |
((thisctr.rw_mode & 0x3) << 4) |
((thisctr.mode & 0x7) << 1) |
(thisctr.bcd_mode&0x1);
thisctr.status_latched=1;
}
}
}
}
} else {
counter_type &thisctr = counter[SC];
if (!RW) {
//Counter Latch command;
BX_DEBUG(("Counter Latch command. SC=%d",SC));
latch_counter(thisctr);
} else {
//Counter Program Command;
BX_DEBUG(("Counter Program command. SC=%d, RW=%d, M=%d, BCD=%d",SC,RW,M,BCD));
thisctr.null_count=1;
thisctr.count_LSB_latched=0;
thisctr.count_MSB_latched=0;
thisctr.status_latched=0;
thisctr.inlatch=0;
thisctr.count_written=0;
thisctr.first_pass=1;
thisctr.rw_mode=RW;
thisctr.bcd_mode=(BCD > 0);
thisctr.mode=M;
switch(RW) {
case 0x1:
BX_DEBUG(("Setting read_state to LSB"));
thisctr.read_state=LSByte;
thisctr.write_state=LSByte;
break;
case 0x2:
BX_DEBUG(("Setting read_state to MSB"));
thisctr.read_state=MSByte;
thisctr.write_state=MSByte;
break;
case 0x3:
BX_DEBUG(("Setting read_state to LSB_mult"));
thisctr.read_state=LSByte_multiple;
thisctr.write_state=LSByte_multiple;
break;
default:
BX_ERROR(("RW field invalid in control word write."));
break;
}
//All modes except mode 0 have initial output of 1.;
if (M) {
set_OUT(thisctr, 1);
} else {
set_OUT(thisctr, 0);
}
thisctr.next_change_time=0;
}
}
} else {
//Write to counter initial value.
counter_type &thisctr = counter[address];
BX_DEBUG(("Write Initial Count: counter=%d, count=%d",address,data));
switch(thisctr.write_state) {
case LSByte_multiple:
thisctr.inlatch = data;
thisctr.write_state = MSByte_multiple;
break;
case LSByte:
thisctr.inlatch = data;
thisctr.count_written = 1;
break;
case MSByte_multiple:
thisctr.write_state = LSByte_multiple;
thisctr.inlatch |= (data << 8);
thisctr.count_written = 1;
break;
case MSByte:
thisctr.inlatch = (data << 8);
thisctr.count_written = 1;
break;
default:
BX_ERROR(("write counter in invalid write state."));
break;
}
if (thisctr.count_written && thisctr.write_state != MSByte_multiple) {
thisctr.null_count = 1;
set_count(thisctr, thisctr.inlatch);
}
switch(thisctr.mode) {
case 0:
if (thisctr.write_state==MSByte_multiple) {
set_OUT(thisctr,0);
}
thisctr.next_change_time=1;
break;
case 1:
if (thisctr.triggerGATE) { //for initial writes, if already saw trigger.
thisctr.next_change_time=1;
} //Otherwise, no change.
break;
case 6:
case 2:
thisctr.next_change_time=1; //FIXME: this could be loosened.
break;
case 7:
case 3:
thisctr.next_change_time=1; //FIXME: this could be loosened.
break;
case 4:
thisctr.next_change_time=1;
break;
case 5:
if (thisctr.triggerGATE) { //for initial writes, if already saw trigger.
thisctr.next_change_time=1;
} //Otherwise, no change.
break;
}
}
}
void pit_82C54::set_GATE(Bit8u cnum, bx_bool data)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 set_GATE"));
} else {
counter_type &thisctr = counter[cnum];
if (!((thisctr.GATE&&data) || (!(thisctr.GATE||data)))) {
BX_INFO(("Changing GATE %d to: %d",cnum,data));
thisctr.GATE=data;
if (thisctr.GATE) {
thisctr.triggerGATE=1;
}
switch(thisctr.mode) {
case 0:
if (data && thisctr.count_written) {
if (thisctr.null_count) {
thisctr.next_change_time=1;
} else {
if ((!thisctr.OUTpin) &&
(thisctr.write_state!=MSByte_multiple))
{
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
}
} else {
if (thisctr.null_count) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 1:
if (data && thisctr.count_written) { //only triggers cause a change.
thisctr.next_change_time=1;
}
break;
case 2:
if (!data) {
set_OUT(thisctr,1);
thisctr.next_change_time=0;
} else {
if (thisctr.count_written) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 3:
if (!data) {
set_OUT(thisctr,1);
thisctr.first_pass=1;
thisctr.next_change_time=0;
} else {
if (thisctr.count_written) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=0;
}
}
break;
case 4:
if (!thisctr.OUTpin || thisctr.null_count) {
thisctr.next_change_time=1;
} else {
if (data && thisctr.count_written) {
if (thisctr.first_pass) {
if (thisctr.count_binary==0) {
thisctr.next_change_time=1;
} else {
thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
}
} else {
thisctr.next_change_time=0;
}
} else {
thisctr.next_change_time=0;
}
}
break;
case 5:
if (data && thisctr.count_written) { //only triggers cause a change.
thisctr.next_change_time=1;
}
break;
default:
break;
}
}
}
}
bx_bool pit_82C54::read_OUT(Bit8u cnum)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
return 0;
}
return counter[cnum].OUTpin;
}
bx_bool pit_82C54::read_GATE(Bit8u cnum)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
return 0;
}
return counter[cnum].GATE;
}
Bit32u pit_82C54::get_clock_event_time(Bit8u cnum)
{
if (cnum>MAX_COUNTER) {
BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
return 0;
}
return counter[cnum].next_change_time;
}
Bit32u pit_82C54::get_next_event_time(void)
{
Bit32u time0=get_clock_event_time(0);
Bit32u time1=get_clock_event_time(1);
Bit32u time2=get_clock_event_time(2);
Bit32u out=time0;
if (time1 && (time1<out))
out=time1;
if (time2 && (time2<out))
out=time2;
return out;
}
Bit16u pit_82C54::get_inlatch(int counternum)
{
return counter[counternum].inlatch;
}
void pit_82C54::set_OUT_handler(Bit8u counternum, out_handler_t outh)
{
counter[counternum].out_handler = outh;
}

148
bochs/iodev/pit82c54.h Normal file
View File

@ -0,0 +1,148 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/*
* Emulator of an Intel 8254/82C54 Programmable Interval Timer.
* Greg Alexander <yakovlev@usa.com>
*/
#ifndef _PIT_82C54_H_
#define _PIT_82C54_H_ 1
typedef void (*out_handler_t)(bx_bool value);
class pit_82C54 : public logfunctions {
public:
//Please do not use these. They are public because they have to be
// to compile on some platforms. They are not to be used by other
// classes.
enum rw_status {
LSByte=0,
MSByte=1,
LSByte_multiple=2,
MSByte_multiple=3
};
private:
enum {
MAX_COUNTER=2,
MAX_ADDRESS=3,
CONTROL_ADDRESS=3,
MAX_MODE=5
};
enum real_RW_status {
LSB_real=1,
MSB_real=2,
BOTH_real=3
};
enum problem_type {
UNL_2P_READ=1
};
struct counter_type {
//Chip IOs;
bx_bool GATE; //GATE Input value at end of cycle
bx_bool OUTpin; //OUT output this cycle
//Architected state;
Bit32u count; //Counter value this cycle
Bit16u outlatch; //Output latch this cycle
Bit16u inlatch; //Input latch this cycle
Bit8u status_latch;
//Status Register data;
Bit8u rw_mode; //2-bit R/W mode from command word register.
Bit8u mode; //3-bit mode from command word register.
bx_bool bcd_mode; //1-bit BCD vs. Binary setting.
bx_bool null_count; //Null count bit of status register.
//Latch status data;
bx_bool count_LSB_latched;
bx_bool count_MSB_latched;
bx_bool status_latched;
//Miscelaneous State;
Bit32u count_binary; //Value of the count in binary.
bx_bool triggerGATE; //Whether we saw GATE rise this cycle.
rw_status write_state; //Read state this cycle
rw_status read_state; //Read state this cycle
bx_bool count_written; //Whether a count written since programmed
bx_bool first_pass; //Whether or not this is the first loaded count.
bx_bool state_bit_1; //Miscelaneous state bits.
bx_bool state_bit_2;
Bit32u next_change_time; //Next time something besides count changes.
//0 means never.
out_handler_t out_handler; // OUT pin callback (for IRQ0)
};
counter_type counter[3];
Bit8u controlword;
int seen_problems;
void latch_counter(counter_type & thisctr);
void set_OUT (counter_type & thisctr, bx_bool data);
void set_count (counter_type & thisctr, Bit32u data) BX_CPP_AttrRegparmN(2);
void set_count_to_binary (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
void set_binary_to_count (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
void decrement (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
void decrement_multiple(counter_type & thisctr, Bit32u cycles) BX_CPP_AttrRegparmN(2);
void clock(Bit8u cnum) BX_CPP_AttrRegparmN(1);
void print_counter(counter_type & thisctr);
public:
pit_82C54 (void);
void init (void);
void reset (unsigned type);
void register_state(bx_param_c *parent);
void clock_all(Bit32u cycles);
void clock_multiple(Bit8u cnum, Bit32u cycles);
Bit8u read(Bit8u address);
void write(Bit8u address, Bit8u data);
void set_GATE(Bit8u cnum, bx_bool data);
bx_bool read_GATE(Bit8u cnum);
bx_bool read_OUT(Bit8u cnum);
void set_OUT_handler(Bit8u cnum, out_handler_t outh);
Bit32u get_clock_event_time(Bit8u cnum);
Bit32u get_next_event_time(void);
Bit16u get_inlatch(int countnum);
void print_cnum(Bit8u cnum);
};
#endif

372
bochs/iodev/pit_wrap.cc Normal file
View File

@ -0,0 +1,372 @@
///////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#include "pit_wrap.h"
#include "virt_timer.h"
#include "speaker.h"
#define LOG_THIS thePit->
bx_pit_c *thePit = NULL;
int libpit_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
thePit = new bx_pit_c();
bx_devices.pluginPitDevice = thePit;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePit, BX_PLUGIN_PIT);
return(0); // Success
}
void libpit_LTX_plugin_fini(void)
{
delete thePit;
}
//Important constant #defines:
#define USEC_PER_SECOND (1000000)
//1.193181MHz Clock
#define TICKS_PER_SECOND (1193181)
// define a macro to convert floating point numbers into 64-bit integers.
// In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
// but it will not convert a 64-bit float into a 64-bit unsigned integer.
// This macro works around that.
#define F2I(x) ((Bit64u)(Bit64s) (x))
#define I2F(x) ((double)(Bit64s) (x))
//Generic MAX and MIN Functions
#define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
//USEC_ALPHA is multiplier for the past.
//USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
#define USEC_ALPHA ((double)(.8))
#define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
#define USEC_ALPHA2 ((double)(.5))
#define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
#define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
//PIT tick to usec conversion functions:
//Direct conversions:
#define TICKS_TO_USEC(a) (((a)*USEC_PER_SECOND)/TICKS_PER_SECOND)
#define USEC_TO_TICKS(a) (((a)*TICKS_PER_SECOND)/USEC_PER_SECOND)
bx_pit_c::bx_pit_c()
{
put("PIT");
s.speaker_data_on=0;
/* 8254 PIT (Programmable Interval Timer) */
s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
s.timer_handle[0] = BX_NULL_TIMER_HANDLE;
}
void bx_pit_c::init(void)
{
DEV_register_irq(0, "8254 PIT");
DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1);
DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1);
DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1);
BX_DEBUG(("starting init"));
BX_PIT_THIS s.speaker_data_on = 0;
BX_PIT_THIS s.refresh_clock_div2 = 0;
BX_PIT_THIS s.timer.init();
BX_PIT_THIS s.timer.set_OUT_handler(0, irq_handler);
Bit64u my_time_usec = bx_virt_timer.time_usec();
if (BX_PIT_THIS s.timer_handle[0] == BX_NULL_TIMER_HANDLE) {
BX_PIT_THIS s.timer_handle[0] = bx_virt_timer.register_timer(this, timer_handler, (unsigned) 100 , 1, 1, "pit_wrap");
}
BX_DEBUG(("RESETting timer."));
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
BX_DEBUG(("deactivated timer."));
if (BX_PIT_THIS s.timer.get_next_event_time()) {
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
0);
BX_DEBUG(("activated timer."));
}
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
BX_PIT_THIS s.last_usec=my_time_usec;
BX_PIT_THIS s.total_ticks=0;
BX_PIT_THIS s.total_usec=0;
BX_DEBUG(("finished init"));
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
BX_DEBUG(("s.timer.get_next_event_time=%d",BX_PIT_THIS s.timer.get_next_event_time()));
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
}
void bx_pit_c::reset(unsigned type)
{
BX_PIT_THIS s.timer.reset(type);
}
void bx_pit_c::register_state(void)
{
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pit", "8254 PIT State", 7);
new bx_shadow_num_c(list, "speaker_data_on", &BX_PIT_THIS s.speaker_data_on, BASE_HEX);
new bx_shadow_bool_c(list, "refresh_clock_div2", &BX_PIT_THIS s.refresh_clock_div2);
new bx_shadow_num_c(list, "last_usec", &BX_PIT_THIS s.last_usec);
new bx_shadow_num_c(list, "last_next_event_time", &BX_PIT_THIS s.last_next_event_time);
new bx_shadow_num_c(list, "total_ticks", &BX_PIT_THIS s.total_ticks);
new bx_shadow_num_c(list, "total_usec", &BX_PIT_THIS s.total_usec);
bx_list_c *counter = new bx_list_c(list, "counter", 4);
BX_PIT_THIS s.timer.register_state(counter);
}
void bx_pit_c::timer_handler(void *this_ptr)
{
bx_pit_c * class_ptr = (bx_pit_c *) this_ptr;
class_ptr->handle_timer();
}
void bx_pit_c::handle_timer()
{
Bit64u my_time_usec = bx_virt_timer.time_usec();
Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
Bit32u time_passed32 = (Bit32u)time_passed;
BX_DEBUG(("entering timer handler"));
if(time_passed32) {
periodic(time_passed32);
}
BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
if(time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time()))
{
BX_DEBUG(("RESETting timer"));
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
BX_DEBUG(("deactivated timer"));
if(BX_PIT_THIS s.timer.get_next_event_time()) {
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
0);
BX_DEBUG(("activated timer"));
}
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
}
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
}
// static IO port read callback handler
// redirects to non-static class handler to avoid virtual functions
Bit32u bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
{
#if !BX_USE_PIT_SMF
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
return class_ptr->read(address, io_len);
}
Bit32u bx_pit_c::read(Bit32u address, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIT_SMF
Bit8u value = 0;
handle_timer();
Bit64u my_time_usec = bx_virt_timer.time_usec();
switch (address) {
case 0x40: /* timer 0 - system ticks */
value = BX_PIT_THIS s.timer.read(0);
break;
case 0x41: /* timer 1 read */
value = BX_PIT_THIS s.timer.read(1);
break;
case 0x42: /* timer 2 read */
value = BX_PIT_THIS s.timer.read(2);
break;
case 0x43: /* timer 1 read */
value = BX_PIT_THIS s.timer.read(3);
break;
case 0x61:
/* AT, port 61h */
BX_PIT_THIS s.refresh_clock_div2 = (bx_bool)((my_time_usec / 15) & 1);
value = (BX_PIT_THIS s.timer.read_OUT(2)<<5) |
(BX_PIT_THIS s.refresh_clock_div2<<4) |
(BX_PIT_THIS s.speaker_data_on<<1) |
(BX_PIT_THIS s.timer.read_GATE(2)?1:0);
break;
default:
BX_PANIC(("unsupported io read from port 0x%04x", address));
}
BX_DEBUG(("read from port 0x%04x, value = 0x%02x", address, value));
return value;
}
// static IO port write callback handler
// redirects to non-static class handler to avoid virtual functions
void bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
{
#if !BX_USE_PIT_SMF
bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
class_ptr->write(address, dvalue, io_len);
}
void bx_pit_c::write(Bit32u address, Bit32u dvalue, unsigned io_len)
{
#else
UNUSED(this_ptr);
#endif // !BX_USE_PIT_SMF
Bit8u value;
Bit64u my_time_usec = bx_virt_timer.time_usec();
Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
Bit32u time_passed32 = (Bit32u)time_passed;
if(time_passed32) {
periodic(time_passed32);
}
BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
value = (Bit8u) dvalue;
BX_DEBUG(("write to port 0x%04x, value = 0x%02x", address, value));
switch (address) {
case 0x40: /* timer 0: write count register */
BX_PIT_THIS s.timer.write(0, value);
break;
case 0x41: /* timer 1: write count register */
BX_PIT_THIS s.timer.write(1, value);
break;
case 0x42: /* timer 2: write count register */
BX_PIT_THIS s.timer.write(2, value);
break;
case 0x43: /* timer 0-2 mode control */
BX_PIT_THIS s.timer.write(3, value);
break;
case 0x61:
BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
if (BX_PIT_THIS s.speaker_data_on) {
DEV_speaker_beep_on((float)(1193180.0 / BX_PIT_THIS get_timer(2)));
} else {
DEV_speaker_beep_off();
}
/* ??? only on AT+ */
BX_PIT_THIS s.timer.set_GATE(2, value & 0x01);
break;
default:
BX_PANIC(("unsupported io write to port 0x%04x = 0x%02x", address, value));
}
if(time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time()))
{
BX_DEBUG(("RESETting timer"));
bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
BX_DEBUG(("deactivated timer"));
if(BX_PIT_THIS s.timer.get_next_event_time()) {
bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0],
(Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
0);
BX_DEBUG(("activated timer"));
}
BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
}
BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
}
bx_bool bx_pit_c::periodic(Bit32u usec_delta)
{
Bit32u ticks_delta = 0;
BX_PIT_THIS s.total_usec += usec_delta;
ticks_delta=(Bit32u)((USEC_TO_TICKS((Bit64u)(BX_PIT_THIS s.total_usec)))-BX_PIT_THIS s.total_ticks);
BX_PIT_THIS s.total_ticks += ticks_delta;
while ((BX_PIT_THIS s.total_ticks >= TICKS_PER_SECOND) && (BX_PIT_THIS s.total_usec >= USEC_PER_SECOND)) {
BX_PIT_THIS s.total_ticks -= TICKS_PER_SECOND;
BX_PIT_THIS s.total_usec -= USEC_PER_SECOND;
}
while(ticks_delta>0) {
Bit32u maxchange=BX_PIT_THIS s.timer.get_next_event_time();
Bit32u timedelta=maxchange;
if((maxchange==0) || (maxchange>ticks_delta)) {
timedelta=ticks_delta;
}
BX_PIT_THIS s.timer.clock_all(timedelta);
ticks_delta-=timedelta;
}
return 0;
}
void bx_pit_c::irq_handler(bx_bool value)
{
if (value == 1) {
DEV_pic_raise_irq(0);
} else {
DEV_pic_lower_irq(0);
}
}
Bit16u bx_pit_c::get_timer(int Timer) {
return BX_PIT_THIS s.timer.get_inlatch(Timer);
}

71
bochs/iodev/pit_wrap.h Normal file
View File

@ -0,0 +1,71 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef _BX_PIT_WRAP_H
#define _BX_PIT_WRAP_H
#include "bochs.h"
#include "pit82c54.h"
#if BX_USE_PIT_SMF
# define BX_PIT_SMF static
# define BX_PIT_THIS thePit->
#else
# define BX_PIT_SMF
# define BX_PIT_THIS this->
#endif
class bx_pit_c : public bx_devmodel_c {
public:
bx_pit_c();
virtual ~bx_pit_c() {}
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
private:
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_PIT_SMF
Bit32u read(Bit32u addr, unsigned len);
void write(Bit32u addr, Bit32u Value, unsigned len);
#endif
struct s_type {
pit_82C54 timer;
Bit8u speaker_data_on;
bx_bool refresh_clock_div2;
Bit64u last_usec;
Bit32u last_next_event_time;
Bit64u total_ticks;
Bit64u total_usec;
int timer_handle[3];
} s;
static void timer_handler(void *this_ptr);
BX_PIT_SMF void handle_timer();
BX_PIT_SMF bx_bool periodic(Bit32u usec_delta);
BX_PIT_SMF void irq_handler(bx_bool value);
BX_PIT_SMF Bit16u get_timer(int Timer);
};
#endif // #ifndef _BX_PIT_WRAP_H

59
bochs/iodev/pnic_api.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Constants etc. for the Bochs/Etherboot pseudo-NIC
*
* This header file must be valid C and C++.
*
* Operation of the pseudo-NIC (PNIC) is pretty simple. To write a
* command plus data, first write the length of the data to
* PNIC_REG_LEN, then write the data a byte at a type to
* PNIC_REG_DATA, then write the command code to PNIC_REG_CMD. The
* status will be available from PNIC_REG_STAT. The length of any
* data returned will be in PNIC_REG_LEN and can be read a byte at a
* time from PNIC_REG_DATA.
*/
/*
* PCI parameters
*/
#define PNIC_PCI_VENDOR 0xfefe /* Hopefully these won't clash with */
#define PNIC_PCI_DEVICE 0xefef /* any real PCI device IDs. */
/*
* 'Hardware' register addresses, offset from io_base
*/
#define PNIC_REG_CMD 0x00 /* Command register, 2 bytes, write only */
#define PNIC_REG_STAT 0x00 /* Status register, 2 bytes, read only */
#define PNIC_REG_LEN 0x02 /* Length register, 2 bytes, read-write */
#define PNIC_REG_DATA 0x04 /* Data port, 1 byte, read-write */
/*
* PNIC_MAX_REG used in Bochs to claim i/o space
*/
#define PNIC_MAX_REG 0x04
/*
* Command code definitions: write these into PNIC_REG_CMD
*/
#define PNIC_CMD_NOOP 0x0000
#define PNIC_CMD_API_VER 0x0001
#define PNIC_CMD_READ_MAC 0x0002
#define PNIC_CMD_RESET 0x0003
#define PNIC_CMD_XMIT 0x0004
#define PNIC_CMD_RECV 0x0005
#define PNIC_CMD_RECV_QLEN 0x0006
#define PNIC_CMD_MASK_IRQ 0x0007
#define PNIC_CMD_FORCE_IRQ 0x0008
/*
* Status code definitions: read these from PNIC_REG_STAT
*
* We avoid using status codes that might be confused with
* randomly-read data (e.g. 0x0000, 0xffff etc.)
*/
#define PNIC_STATUS_OK 0x4f4b /* 'OK' */
#define PNIC_STATUS_UNKNOWN_CMD 0x3f3f /* '??' */
/*
* Other miscellaneous information
*/
#define PNIC_API_VERSION 0x0101 /* 1.1 */

3688
bochs/iodev/sb16.cc Normal file

File diff suppressed because it is too large Load Diff

378
bochs/iodev/sb16.h Normal file
View File

@ -0,0 +1,378 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// The original version of the SB16 support written and donated by Josef Drexler
#ifndef BX_IODEV_SB16_H
#define BX_IODEV_SB16_H
#if BX_USE_SB16_SMF
# define BX_SB16_SMF static
# define BX_SB16_THIS theSB16Device->
# define BX_SB16_THISP (theSB16Device)
#else
# define BX_SB16_SMF
# define BX_SB16_THIS this->
# define BX_SB16_THISP (this)
#endif
// If the buffer commands are to be inlined:
#define BX_SB16_BUFINL BX_CPP_INLINE
// BX_CPP_INLINE is defined to the inline keyword for the C++ compiler.
// maximum number of patch translations
#define BX_SB16_PATCHTABLESIZE 1024
// the resources. Of these, IRQ and DMA's can be changed via a DSP command
#define BX_SB16_IO 0x220 // IO base address of DSP, mixer & FM part
#define BX_SB16_IOLEN 16 // number of addresses covered
#define BX_SB16_IOMPU 0x330 // IO base address of MPU402 part
#define BX_SB16_IOMPULEN 4 // number of addresses covered
#define BX_SB16_IOADLIB 0x388 // equivalent to 0x220..0x223 and 0x228..0x229
#define BX_SB16_IOADLIBLEN 4 // number of addresses covered
#define BX_SB16_IRQ theSB16Device->currentirq
#define BX_SB16_IRQMPU BX_SB16_IRQ // IRQ for the MPU401 part - same value
#define BX_SB16_DMAL theSB16Device->currentdma8
#define BX_SB16_DMAH theSB16Device->currentdma16
/*
A few notes:
IRQ, DMA8bit and DMA16bit are for the DSP part. These
are changeable at runtime in mixer registers 0x80 and 0x81.
The defaults after a mixer initialization are IRQ 5, DMA8 1, no DMA16
Any of the address lengths can be zero to disable that particular
subdevice. Turning off the DSP still leaves FM music enabled on the
BX_SB16_IOADLIB ports, unless those are disabled as well.
BX_SB16_IOMPULEN should be 4 or 2. In the latter case, the emulator
is completely invisible, and runtime changes are not possible
BX_SB16_IOADLIBLEN should be 2 or 4. If 0, Ports 0x388.. don't
get used, but the OPL2 can still be accessed at 0x228..0x229.
If 2, the usual Adlib emulation is enabled. If 4, an OPL3 is
emulated at adresses 0x388..0x38b, or two separate OPL2's.
*/
#define BX_SB16_MIX_REG 0x100 // total number of mixer registers
// The array containing an instrument/bank remapping
struct bx_sb16_ins_map {
Bit8u oldbankmsb, oldbanklsb, oldprogch;
Bit8u newbankmsb, newbanklsb, newprogch;
};
// One operator of the FM emulation
#define BX_SB16_FM_NOP 36 // OPL3 has 36 operators
#define BX_SB16_FM_OPB 6 // one operator has 6 bytes
typedef Bit8u bx_sb16_fm_operator[BX_SB16_FM_OPB];
/* Explanation of the values:
(note [xx] is one bit for xx; [5 xx] is five bits for xx,
all bits listed MSB to LSB)
[0] = [Tremolo][Vibrato][Sustain][KSR][4 Frequency Multiply]
[1] = [2 Key Scale Level][6 Output Level for modulators, reserved for others]
[2] = [4 Attack Rate][4 Decay Rate]
[3] = [4 Sustain Level][4 Release Rate]
[4] = [2 reserved][Right][Left][3 Feedback Factor][SynthType]
[5] = [5 reserved][3 Waveform Select]
Frequency and Output Level are really properties of the channel,
so they get stored there. However, Output Level of the modulator
in FM synthesis varies the instrument.
[4] is only set for the first operator, and zeroed for the others.
All reserved bits are zeroed.
*/
// One channel (1 to 4 operators)
#define BX_SB16_FM_NCH 18 // OPL3 has at most 18 channels
typedef struct {
int nop; // number of operators used: 0=disabled, 1=percussion, 2 or 4=melodic
int ncarr; // how many carriers this channel has (1..3)
int opnum[4]; // operator numbers
Bit16u freq; // frequency (in a special code)
Bit32u afreq; // actual frequency in milli-Hertz (10^-3 Hz)
Bit8u midichan; // assigned midi channel
bx_bool needprogch; // has the instrument changed
Bit8u midinote; // currently playing midi note
bx_bool midion; // is the note on
Bit16u midibend; // current value of the pitch bender
Bit8u outputlevel[4];// 6-bit output level attenuations
Bit8u midivol; // current midi volume (velocity)
} bx_sb16_fm_channel;
// This is the class for the input and
// output FIFO buffers of the SB16
class bx_sb16_buffer {
public:
BX_SB16_BUFINL bx_sb16_buffer(void);
BX_SB16_BUFINL ~bx_sb16_buffer();
BX_SB16_BUFINL void init(int bufferlen);
BX_SB16_BUFINL void reset();
/* These functions return 1 on success and 0 on error */
BX_SB16_BUFINL bx_bool put(Bit8u data); // write one byte in the buffer
BX_SB16_BUFINL bx_bool puts(const char *data, ...); // write a formatted string to the buffer
BX_SB16_BUFINL bx_bool get(Bit8u *data); // read the next available byte
BX_SB16_BUFINL bx_bool getw(Bit16u *data); // get word, in order lo/hi
BX_SB16_BUFINL bx_bool getw1(Bit16u *data);// get word, in order hi/lo
BX_SB16_BUFINL bx_bool full(void); // is the buffer full?
BX_SB16_BUFINL bx_bool empty(void); // is it empty?
BX_SB16_BUFINL void flush(void); // empty the buffer
BX_SB16_BUFINL int bytes(void); // return number of bytes in the buffer
BX_SB16_BUFINL Bit8u peek(int ahead); // peek ahead number of bytes
/* These are for caching the command number */
BX_SB16_BUFINL void newcommand(Bit8u newcmd, int bytes); // start a new command with length bytes
BX_SB16_BUFINL Bit8u currentcommand(void); // return the current command
BX_SB16_BUFINL void clearcommand(void); // clear the command
BX_SB16_BUFINL bx_bool commanddone(void); // return if all bytes have arrived
BX_SB16_BUFINL bx_bool hascommand(void); // return if there is a pending command
BX_SB16_BUFINL int commandbytes(void); // return the length of the command
private:
Bit8u *buffer;
int head,tail,length;
Bit8u command;
bx_bool havecommand;
int bytesneeded;
};
// forward definition
class bx_sound_output_c;
// The actual emulator class, emulating the sound blaster ports
class bx_sb16_c : public bx_devmodel_c {
public:
bx_sb16_c();
virtual ~bx_sb16_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
virtual void after_restore_state(void);
/* Make writelog available to output functions */
BX_SB16_SMF void writelog(int loglev, const char *str, ...);
// return midimode and wavemode setting (for lowlevel output class)
int get_midimode() const {return midimode;}
int get_wavemode() const {return wavemode;}
// runtimer parameter handler
static Bit64s sb16_param_handler(bx_param_c *param, int set, Bit64s val);
private:
int midimode, wavemode, loglevel;
Bit32u dmatimer;
FILE *logfile, *midifile, *wavefile; // the output files or devices
bx_sound_output_c *soundmod;// the output class
int currentirq;
int currentdma8;
int currentdma16;
// the MPU 401 relevant variables
struct bx_sb16_mpu_struct {
bx_sb16_buffer datain, dataout, cmd, midicmd;
bx_bool uartmode, irqpending, forceuartmode, singlecommand;
int banklsb[BX_SB16_PATCHTABLESIZE];
int bankmsb[BX_SB16_PATCHTABLESIZE]; // current patch lists
int program[BX_SB16_PATCHTABLESIZE];
int timer_handle, current_timer; // no. of delta times passed
Bit32u last_delta_time; // timer value at last command
bx_bool outputinit;
} mpu401;
// the DSP variables
struct bx_sb16_dsp_struct {
bx_sb16_buffer datain, dataout;
Bit8u resetport; // last value written to the reset port
Bit8u speaker,prostereo; // properties of the sound input/output
bx_bool irqpending; // Is an IRQ pending (not ack'd)
bx_bool midiuartmode; // Is the DSP in MIDI UART mode
Bit8u testreg;
struct bx_sb16_dsp_dma_struct {
// Properties of the current DMA transfer:
// mode= 0: no transfer, 1: single-cycle transfer, 2: auto-init DMA
// bits= 8 or 16
// fifo= ?? Bit used in DMA command, no idea what it means...
// output= 0: input, 1: output
// bps= bytes per sample; =(dmabits/8)*(dmastereo+1)
// stereo= 0: mono, 1: stereo
// issigned= 0: unsigned data, 1: signed data
// highspeed= 0: normal mode, 1: highspeed mode (only SBPro)
// timer= so many us between data bytes
int mode, bits, bps, format, timer;
bx_bool fifo, output, stereo, issigned, highspeed;
Bit16u count; // bytes remaining in this transfer
Bit8u *chunk; // buffers up to BX_SOUND_OUTPUT_WAVEPACKETSIZE bytes
int chunkindex; // index into the buffer
int chunkcount; // for input: size of the recorded input
Bit16u timeconstant;
Bit16u blocklength, samplerate;
} dma;
int timer_handle; // handle for the DMA timer
bx_bool outputinit; // have the output functions been initialized
} dsp;
// the ASP/CSP registers
Bit8u csp_reg[256];
enum bx_sb16_fm_mode {single, adlib, dual, opl3, fminit};
// the variables common to all FM emulations
struct bx_sb16_opl_struct;
friend struct bx_sb16_opl_struct;
struct bx_sb16_opl_struct {
bx_sb16_fm_mode mode;
// modes: single: one OPL2 (OPL3 disabled),
// adlib: one OPL2 (no OPL3),
// dual: two seperate OPL2
// opl3: one OPL3 (enabled)
int timer_handle;
int timer_running;
Bit16u midichannels; // bitmask: unused midichannels
int drumchannel; // midi channel for percussion (10)
int index[2]; // index register for the two chips
int wsenable[2]; // wave form select enable
Bit16u timer[4]; // two timers on each chip
Bit16u timerinit[4]; // initial timer counts
int tmask[2]; // the timer masking byte for both chips
int tflag[2]; // shows if the timer overflow has occured
int percmode[2]; // percussion mode enabled
int cyhhnote[2]; // cymbal and high hat midi notes
int cyhhon[2]; // cymbal and high hat notes on
bx_sb16_fm_operator oper[BX_SB16_FM_NOP];
bx_sb16_fm_channel chan[BX_SB16_FM_NCH];
} opl;
struct bx_sb16_mixer_struct {
Bit8u regindex;
Bit8u reg[BX_SB16_MIX_REG];
} mixer;
struct bx_sb16_emul_struct {
bx_sb16_buffer datain, dataout;
bx_sb16_ins_map remaplist[256];
Bit16u remaps;
} emuldata;
/* DMA input and output, 8 and 16 bit */
BX_SB16_SMF void dma_write8(Bit8u *data_byte);
BX_SB16_SMF void dma_read8(Bit8u *data_byte);
BX_SB16_SMF void dma_write16(Bit16u *data_word);
BX_SB16_SMF void dma_read16(Bit16u *data_word);
/* the MPU 401 part of the emulator */
BX_SB16_SMF Bit32u mpu_status(); // read status port 3x1
BX_SB16_SMF void mpu_command(Bit32u value); // write command port 3x1
BX_SB16_SMF Bit32u mpu_dataread(); // read data port 3x0
BX_SB16_SMF void mpu_datawrite(Bit32u value); // write data port 3x0
BX_SB16_SMF void mpu_mididata(Bit32u value); // get a midi byte
static void mpu_timer (void *);
/* The DSP part */
BX_SB16_SMF void dsp_reset(Bit32u value); // write to reset port 2x6
BX_SB16_SMF Bit32u dsp_dataread(); // read from data port 2xa
BX_SB16_SMF void dsp_datawrite(Bit32u value); // write to data port 2xa
BX_SB16_SMF Bit32u dsp_bufferstatus(); // read buffer status 2xc
BX_SB16_SMF Bit32u dsp_status(); // read dsp status 2xe
BX_SB16_SMF void dsp_getsamplebyte(Bit8u value);
BX_SB16_SMF Bit8u dsp_putsamplebyte();
BX_SB16_SMF void dsp_sendwavepacket();
BX_SB16_SMF void dsp_getwavepacket();
BX_SB16_SMF Bit32u dsp_irq16ack(); // ack 16 bit IRQ 2xf
BX_SB16_SMF void dsp_dma(Bit8u command, Bit8u mode, Bit16u length, Bit8u comp);
// initiate a DMA transfer
BX_SB16_SMF void dsp_dmadone(); // stop a DMA transfer
BX_SB16_SMF void dsp_enabledma(); // enable the transfer
BX_SB16_SMF void dsp_disabledma(); // temporarily disable DMA
static void dsp_dmatimer (void *);
/* The mixer part */
BX_SB16_SMF Bit32u mixer_readdata(void);
BX_SB16_SMF void mixer_writedata(Bit32u value);
BX_SB16_SMF void mixer_writeregister(Bit32u value);
BX_SB16_SMF void set_irq_dma();
/* The emulator ports to change emulator properties */
BX_SB16_SMF Bit32u emul_read (void); // read emulator port
BX_SB16_SMF void emul_write(Bit32u value); // write emulator port
/* The FM emulation part */
BX_SB16_SMF void opl_entermode(bx_sb16_fm_mode newmode);
BX_SB16_SMF Bit32u opl_status(int chipid);
BX_SB16_SMF void opl_index(Bit32u value, int chipid);
BX_SB16_SMF void opl_data(Bit32u value, int chipid);
static void opl_timer(void *);
BX_SB16_SMF void opl_timerevent(void);
BX_SB16_SMF void opl_changeop(int channum, int opernum, int byte, int value);
BX_SB16_SMF void opl_settimermask(int value, int chipid);
BX_SB16_SMF void opl_set4opmode(int new4opmode);
BX_SB16_SMF void opl_setmodulation(int channel);
BX_SB16_SMF void opl_setpercussion(Bit8u value, int chipid);
BX_SB16_SMF void opl_setvolume(int channel, int opnum, int outlevel);
BX_SB16_SMF void opl_setfreq(int channel);
BX_SB16_SMF void opl_keyonoff(int channel, bx_bool onoff);
BX_SB16_SMF void opl_midichannelinit(int channel);
/* several high level sound handlers */
BX_SB16_SMF int currentdeltatime();
BX_SB16_SMF void processmidicommand(bx_bool force);
BX_SB16_SMF void midiremapprogram(int channel); // remap program change
BX_SB16_SMF int converttodeltatime(Bit32u deltatime, Bit8u value[4]);
BX_SB16_SMF void writemidicommand(int command, int length, Bit8u data[]);
BX_SB16_SMF void writedeltatime(Bit32u deltatime);
// write in delta time coding
BX_SB16_SMF void initmidifile(); // Write midi file header
BX_SB16_SMF void finishmidifile(); // write track length etc.
BX_SB16_SMF void initvocfile(); // Write voc file header
BX_SB16_SMF void writevocblock(int block, Bit32u headerlen, Bit8u header[],
Bit32u datalen, Bit8u data[]);
BX_SB16_SMF void finishvocfile(); // close voc file
/* The port IO multiplexer functions */
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_SB16_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#define BOTHLOG(x) (x)
#define WRITELOG (BX_SB16_THIS writelog)
#define MIDILOG(x) ((BX_SB16_THIS midimode>0?x:0x7f))
#define WAVELOG(x) ((BX_SB16_THIS wavemode>0?x:0x7f))
#endif

772
bochs/iodev/scancodes.cc Normal file
View File

@ -0,0 +1,772 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "bochs.h"
#include "scancodes.h"
unsigned char translation8042[256] = {
0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54,
0x80,0x81,0x82,0x41,0x54,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};
// Definition of scancodes make and break,
// for each set (mf1/xt , mf2/at , mf3/ps2)
// The table must be in BX_KEY order
//
scancode scancodes[BX_KEY_NBKEYS][3] =
{
{ // BX_KEY_CTRL_L ( ibm 58)
{ "\x1D" , "\x9D" },
{ "\x14" , "\xF0\x14" },
{ "\x11" , "\xF0\x11" },
},
{ // BX_KEY_SHIFT_L ( ibm 44)
{ "\x2A" , "\xAA" },
{ "\x12" , "\xF0\x12" },
{ "\x12" , "\xF0\x12" },
},
{ // BX_KEY_F1 ( ibm 112 )
{ "\x3B" , "\xBB" },
{ "\x05" , "\xF0\x05" },
{ "\x07" , "\xF0\x07" },
},
{ // BX_KEY_F2 ( ibm 113 )
{ "\x3C" , "\xBC" },
{ "\x06" , "\xF0\x06" },
{ "\x0F" , "\xF0\x0F" },
},
{ // BX_KEY_F3 ( ibm 114 )
{ "\x3D" , "\xBD" },
{ "\x04" , "\xF0\x04" },
{ "\x17" , "\xF0\x17" },
},
{ // BX_KEY_F4 ( ibm 115 )
{ "\x3E" , "\xBE" },
{ "\x0C" , "\xF0\x0C" },
{ "\x1F" , "\xF0\x1F" },
},
{ // BX_KEY_F5 ( ibm 116 )
{ "\x3F" , "\xBF" },
{ "\x03" , "\xF0\x03" },
{ "\x27" , "\xF0\x27" },
},
{ // BX_KEY_F6 ( ibm 117 )
{ "\x40" , "\xC0" },
{ "\x0B" , "\xF0\x0B" },
{ "\x2F" , "\xF0\x2F" },
},
{ // BX_KEY_F7 ( ibm 118 )
{ "\x41" , "\xC1" },
{ "\x83" , "\xF0\x83" },
{ "\x37" , "\xF0\x37" },
},
{ // BX_KEY_F8 ( ibm 119 )
{ "\x42" , "\xC2" },
{ "\x0A" , "\xF0\x0A" },
{ "\x3F" , "\xF0\x3F" },
},
{ // BX_KEY_F9 ( ibm 120 )
{ "\x43" , "\xC3" },
{ "\x01" , "\xF0\x01" },
{ "\x47" , "\xF0\x47" },
},
{ // BX_KEY_F10 ( ibm 121 )
{ "\x44" , "\xC4" },
{ "\x09" , "\xF0\x09" },
{ "\x4F" , "\xF0\x4F" },
},
{ // BX_KEY_F11 ( ibm 122 )
{ "\x57" , "\xD7" },
{ "\x78" , "\xF0\x78" },
{ "\x56" , "\xF0\x56" },
},
{ // BX_KEY_F12 ( ibm 123 )
{ "\x58" , "\xD8" },
{ "\x07" , "\xF0\x07" },
{ "\x5E" , "\xF0\x5E" },
},
{ // BX_KEY_CTRL_R ( ibm 64 )
{ "\xE0\x1D" , "\xE0\x9D" },
{ "\xE0\x14" , "\xE0\xF0\x14" },
{ "\x58" , "\xF0\x58" },
},
{ // BX_KEY_SHIFT_R ( ibm 57 )
{ "\x36" , "\xB6" },
{ "\x59" , "\xF0\x59" },
{ "\x59" , "\xF0\x59" },
},
{ // BX_KEY_CAPS_LOCK ( ibm 30 )
{ "\x3A" , "\xBA" },
{ "\x58" , "\xF0\x58" },
{ "\x14" , "\xF0\x14" },
},
{ // BX_KEY_NUM_LOCK ( ibm 90 )
{ "\x45" , "\xC5" },
{ "\x77" , "\xF0\x77" },
{ "\x76" , "\xF0\x76" },
},
{ // BX_KEY_ALT_L ( ibm 60 )
{ "\x38" , "\xB8" },
{ "\x11" , "\xF0\x11" },
{ "\x19" , "\xF0\x19" },
},
{ // BX_KEY_ALT_R ( ibm 62 )
{ "\xE0\x38" , "\xE0\xB8" },
{ "\xE0\x11" , "\xE0\xF0\x11" },
{ "\x39" , "\xF0\x39" },
},
{ // BX_KEY_A ( ibm 31 )
{ "\x1E" , "\x9E" },
{ "\x1C" , "\xF0\x1C" },
{ "\x1C" , "\xF0\x1C" },
},
{ // BX_KEY_B ( ibm 50 )
{ "\x30" , "\xB0" },
{ "\x32" , "\xF0\x32" },
{ "\x32" , "\xF0\x32" },
},
{ // BX_KEY_C ( ibm 48 )
{ "\x2E" , "\xAE" },
{ "\x21" , "\xF0\x21" },
{ "\x21" , "\xF0\x21" },
},
{ // BX_KEY_D ( ibm 33 )
{ "\x20" , "\xA0" },
{ "\x23" , "\xF0\x23" },
{ "\x23" , "\xF0\x23" },
},
{ // BX_KEY_E ( ibm 19 )
{ "\x12" , "\x92" },
{ "\x24" , "\xF0\x24" },
{ "\x24" , "\xF0\x24" },
},
{ // BX_KEY_F ( ibm 34 )
{ "\x21" , "\xA1" },
{ "\x2B" , "\xF0\x2B" },
{ "\x2B" , "\xF0\x2B" },
},
{ // BX_KEY_G ( ibm 35 )
{ "\x22" , "\xA2" },
{ "\x34" , "\xF0\x34" },
{ "\x34" , "\xF0\x34" },
},
{ // BX_KEY_H ( ibm 36 )
{ "\x23" , "\xA3" },
{ "\x33" , "\xF0\x33" },
{ "\x33" , "\xF0\x33" },
},
{ // BX_KEY_I ( ibm 24 )
{ "\x17" , "\x97" },
{ "\x43" , "\xF0\x43" },
{ "\x43" , "\xF0\x43" },
},
{ // BX_KEY_J ( ibm 37 )
{ "\x24" , "\xA4" },
{ "\x3B" , "\xF0\x3B" },
{ "\x3B" , "\xF0\x3B" },
},
{ // BX_KEY_K ( ibm 38 )
{ "\x25" , "\xA5" },
{ "\x42" , "\xF0\x42" },
{ "\x42" , "\xF0\x42" },
},
{ // BX_KEY_L ( ibm 39 )
{ "\x26" , "\xA6" },
{ "\x4B" , "\xF0\x4B" },
{ "\x4B" , "\xF0\x4B" },
},
{ // BX_KEY_M ( ibm 52 )
{ "\x32" , "\xB2" },
{ "\x3A" , "\xF0\x3A" },
{ "\x3A" , "\xF0\x3A" },
},
{ // BX_KEY_N ( ibm 51 )
{ "\x31" , "\xB1" },
{ "\x31" , "\xF0\x31" },
{ "\x31" , "\xF0\x31" },
},
{ // BX_KEY_O ( ibm 25 )
{ "\x18" , "\x98" },
{ "\x44" , "\xF0\x44" },
{ "\x44" , "\xF0\x44" },
},
{ // BX_KEY_P ( ibm 26 )
{ "\x19" , "\x99" },
{ "\x4D" , "\xF0\x4D" },
{ "\x4D" , "\xF0\x4D" },
},
{ // BX_KEY_Q ( ibm 17 )
{ "\x10" , "\x90" },
{ "\x15" , "\xF0\x15" },
{ "\x15" , "\xF0\x15" },
},
{ // BX_KEY_R ( ibm 20 )
{ "\x13" , "\x93" },
{ "\x2D" , "\xF0\x2D" },
{ "\x2D" , "\xF0\x2D" },
},
{ // BX_KEY_S ( ibm 32 )
{ "\x1F" , "\x9F" },
{ "\x1B" , "\xF0\x1B" },
{ "\x1B" , "\xF0\x1B" },
},
{ // BX_KEY_T ( ibm 21 )
{ "\x14" , "\x94" },
{ "\x2C" , "\xF0\x2C" },
{ "\x2C" , "\xF0\x2C" },
},
{ // BX_KEY_U ( ibm 23 )
{ "\x16" , "\x96" },
{ "\x3C" , "\xF0\x3C" },
{ "\x3C" , "\xF0\x3C" },
},
{ // BX_KEY_V ( ibm 49 )
{ "\x2F" , "\xAF" },
{ "\x2A" , "\xF0\x2A" },
{ "\x2A" , "\xF0\x2A" },
},
{ // BX_KEY_W ( ibm 18 )
{ "\x11" , "\x91" },
{ "\x1D" , "\xF0\x1D" },
{ "\x1D" , "\xF0\x1D" },
},
{ // BX_KEY_X ( ibm 47 )
{ "\x2D" , "\xAD" },
{ "\x22" , "\xF0\x22" },
{ "\x22" , "\xF0\x22" },
},
{ // BX_KEY_Y ( ibm 22 )
{ "\x15" , "\x95" },
{ "\x35" , "\xF0\x35" },
{ "\x35" , "\xF0\x35" },
},
{ // BX_KEY_Z ( ibm 46 )
{ "\x2C" , "\xAC" },
{ "\x1A" , "\xF0\x1A" },
{ "\x1A" , "\xF0\x1A" },
},
{ // BX_KEY_0 ( ibm 11 )
{ "\x0B" , "\x8B" },
{ "\x45" , "\xF0\x45" },
{ "\x45" , "\xF0\x45" },
},
{ // BX_KEY_1 ( ibm 2 )
{ "\x02" , "\x82" },
{ "\x16" , "\xF0\x16" },
{ "\x16" , "\xF0\x16" },
},
{ // BX_KEY_2 ( ibm 3 )
{ "\x03" , "\x83" },
{ "\x1E" , "\xF0\x1E" },
{ "\x1E" , "\xF0\x1E" },
},
{ // BX_KEY_3 ( ibm 4 )
{ "\x04" , "\x84" },
{ "\x26" , "\xF0\x26" },
{ "\x26" , "\xF0\x26" },
},
{ // BX_KEY_4 ( ibm 5 )
{ "\x05" , "\x85" },
{ "\x25" , "\xF0\x25" },
{ "\x25" , "\xF0\x25" },
},
{ // BX_KEY_5 ( ibm 6 )
{ "\x06" , "\x86" },
{ "\x2E" , "\xF0\x2E" },
{ "\x2E" , "\xF0\x2E" },
},
{ // BX_KEY_6 ( ibm 7 )
{ "\x07" , "\x87" },
{ "\x36" , "\xF0\x36" },
{ "\x36" , "\xF0\x36" },
},
{ // BX_KEY_7 ( ibm 8 )
{ "\x08" , "\x88" },
{ "\x3D" , "\xF0\x3D" },
{ "\x3D" , "\xF0\x3D" },
},
{ // BX_KEY_8 ( ibm 9 )
{ "\x09" , "\x89" },
{ "\x3E" , "\xF0\x3E" },
{ "\x3E" , "\xF0\x3E" },
},
{ // BX_KEY_9 ( ibm 10 )
{ "\x0A" , "\x8A" },
{ "\x46" , "\xF0\x46" },
{ "\x46" , "\xF0\x46" },
},
{ // BX_KEY_ESC ( ibm 110 )
{ "\x01" , "\x81" },
{ "\x76" , "\xF0\x76" },
{ "\x08" , "\xF0\x08" },
},
{ // BX_KEY_SPACE ( ibm 61 )
{ "\x39" , "\xB9" },
{ "\x29" , "\xF0\x29" },
{ "\x29" , "\xF0\x29" },
},
{ // BX_KEY_SINGLE_QUOTE ( ibm 41 )
{ "\x28" , "\xA8" },
{ "\x52" , "\xF0\x52" },
{ "\x52" , "\xF0\x52" },
},
{ // BX_KEY_COMMA ( ibm 53 )
{ "\x33" , "\xB3" },
{ "\x41" , "\xF0\x41" },
{ "\x41" , "\xF0\x41" },
},
{ // BX_KEY_PERIOD ( ibm 54 )
{ "\x34" , "\xB4" },
{ "\x49" , "\xF0\x49" },
{ "\x49" , "\xF0\x49" },
},
{ // BX_KEY_SLASH ( ibm 55 )
{ "\x35" , "\xB5" },
{ "\x4A" , "\xF0\x4A" },
{ "\x4A" , "\xF0\x4A" },
},
{ // BX_KEY_SEMICOLON ( ibm 40 )
{ "\x27" , "\xA7" },
{ "\x4C" , "\xF0\x4C" },
{ "\x4C" , "\xF0\x4C" },
},
{ // BX_KEY_EQUALS ( ibm 13 )
{ "\x0D" , "\x8D" },
{ "\x55" , "\xF0\x55" },
{ "\x55" , "\xF0\x55" },
},
{ // BX_KEY_LEFT_BRACKET ( ibm 27 )
{ "\x1A" , "\x9A" },
{ "\x54" , "\xF0\x54" },
{ "\x54" , "\xF0\x54" },
},
{ // BX_KEY_BACKSLASH ( ibm 42, 29)
{ "\x2B" , "\xAB" },
{ "\x5D" , "\xF0\x5D" },
{ "\x53" , "\xF0\x53" },
},
{ // BX_KEY_RIGHT_BRACKET ( ibm 28 )
{ "\x1B" , "\x9B" },
{ "\x5B" , "\xF0\x5B" },
{ "\x5B" , "\xF0\x5B" },
},
{ // BX_KEY_MINUS ( ibm 12 )
{ "\x0C" , "\x8C" },
{ "\x4E" , "\xF0\x4E" },
{ "\x4E" , "\xF0\x4E" },
},
{ // BX_KEY_GRAVE ( ibm 1 )
{ "\x29" , "\xA9" },
{ "\x0E" , "\xF0\x0E" },
{ "\x0E" , "\xF0\x0E" },
},
{ // BX_KEY_BACKSPACE ( ibm 15 )
{ "\x0E" , "\x8E" },
{ "\x66" , "\xF0\x66" },
{ "\x66" , "\xF0\x66" },
},
{ // BX_KEY_ENTER ( ibm 43 )
{ "\x1C" , "\x9C" },
{ "\x5A" , "\xF0\x5A" },
{ "\x5A" , "\xF0\x5A" },
},
{ // BX_KEY_TAB ( ibm 16 )
{ "\x0F" , "\x8F" },
{ "\x0D" , "\xF0\x0D" },
{ "\x0D" , "\xF0\x0D" },
},
{ // BX_KEY_LEFT_BACKSLASH ( ibm 45 )
{ "\x56" , "\xD6" },
{ "\x61" , "\xF0\x61" },
{ "\x13" , "\xF0\x13" },
},
{ // BX_KEY_PRINT ( ibm 124 )
{ "\xE0\x2A\xE0\x37" , "\xE0\xB7\xE0\xAA" },
{ "\xE0\x12\xE0\x7C" , "\xE0\xF0\x7C\xE0\xF0\x12" },
{ "\x57" , "\xF0\x57" },
},
{ // BX_KEY_SCRL_LOCK ( ibm 125 )
{ "\x46" , "\xC6" },
{ "\x7E" , "\xF0\x7E" },
{ "\x5F" , "\xF0\x5F" },
},
{ // BX_KEY_PAUSE ( ibm 126 )
{ "\xE1\x1D\x45\xE1\x9D\xC5" , "" },
{ "\xE1\x14\x77\xE1\xF0\x14\xF0\x77" , "" },
{ "\x62" , "\xF0\x62" },
},
{ // BX_KEY_INSERT ( ibm 75 )
{ "\xE0\x52" , "\xE0\xD2" },
{ "\xE0\x70" , "\xE0\xF0\x70" },
{ "\x67" , "\xF0\x67" },
},
{ // BX_KEY_DELETE ( ibm 76 )
{ "\xE0\x53" , "\xE0\xD3" },
{ "\xE0\x71" , "\xE0\xF0\x71" },
{ "\x64" , "\xF0\x64" },
},
{ // BX_KEY_HOME ( ibm 80 )
{ "\xE0\x47" , "\xE0\xC7" },
{ "\xE0\x6C" , "\xE0\xF0\x6C" },
{ "\x6E" , "\xF0\x6E" },
},
{ // BX_KEY_END ( ibm 81 )
{ "\xE0\x4F" , "\xE0\xCF" },
{ "\xE0\x69" , "\xE0\xF0\x69" },
{ "\x65" , "\xF0\x65" },
},
{ // BX_KEY_PAGE_UP ( ibm 85 )
{ "\xE0\x49" , "\xE0\xC9" },
{ "\xE0\x7D" , "\xE0\xF0\x7D" },
{ "\x6F" , "\xF0\x6F" },
},
{ // BX_KEY_PAGE_DOWN ( ibm 86 )
{ "\xE0\x51" , "\xE0\xD1" },
{ "\xE0\x7A" , "\xE0\xF0\x7A" },
{ "\x6D" , "\xF0\x6D" },
},
{ // BX_KEY_KP_ADD ( ibm 106 )
{ "\x4E" , "\xCE" },
{ "\x79" , "\xF0\x79" },
{ "\x7C" , "\xF0\x7C" },
},
{ // BX_KEY_KP_SUBTRACT ( ibm 105 )
{ "\x4A" , "\xCA" },
{ "\x7B" , "\xF0\x7B" },
{ "\x84" , "\xF0\x84" },
},
{ // BX_KEY_KP_END ( ibm 93 )
{ "\x4F" , "\xCF" },
{ "\x69" , "\xF0\x69" },
{ "\x69" , "\xF0\x69" },
},
{ // BX_KEY_KP_DOWN ( ibm 98 )
{ "\x50" , "\xD0" },
{ "\x72" , "\xF0\x72" },
{ "\x72" , "\xF0\x72" },
},
{ // BX_KEY_KP_PAGE_DOWN ( ibm 103 )
{ "\x51" , "\xD1" },
{ "\x7A" , "\xF0\x7A" },
{ "\x7A" , "\xF0\x7A" },
},
{ // BX_KEY_KP_LEFT ( ibm 92 )
{ "\x4B" , "\xCB" },
{ "\x6B" , "\xF0\x6B" },
{ "\x6B" , "\xF0\x6B" },
},
{ // BX_KEY_KP_RIGHT ( ibm 102 )
{ "\x4D" , "\xCD" },
{ "\x74" , "\xF0\x74" },
{ "\x74" , "\xF0\x74" },
},
{ // BX_KEY_KP_HOME ( ibm 91 )
{ "\x47" , "\xC7" },
{ "\x6C" , "\xF0\x6C" },
{ "\x6C" , "\xF0\x6C" },
},
{ // BX_KEY_KP_UP ( ibm 96 )
{ "\x48" , "\xC8" },
{ "\x75" , "\xF0\x75" },
{ "\x75" , "\xF0\x75" },
},
{ // BX_KEY_KP_PAGE_UP ( ibm 101 )
{ "\x49" , "\xC9" },
{ "\x7D" , "\xF0\x7D" },
{ "\x7D" , "\xF0\x7D" },
},
{ // BX_KEY_KP_INSERT ( ibm 99 )
{ "\x52" , "\xD2" },
{ "\x70" , "\xF0\x70" },
{ "\x70" , "\xF0\x70" },
},
{ // BX_KEY_KP_DELETE ( ibm 104 )
{ "\x53" , "\xD3" },
{ "\x71" , "\xF0\x71" },
{ "\x71" , "\xF0\x71" },
},
{ // BX_KEY_KP_5 ( ibm 97 )
{ "\x4C" , "\xCC" },
{ "\x73" , "\xF0\x73" },
{ "\x73" , "\xF0\x73" },
},
{ // BX_KEY_UP ( ibm 83 )
{ "\xE0\x48" , "\xE0\xC8" },
{ "\xE0\x75" , "\xE0\xF0\x75" },
{ "\x63" , "\xF0\x63" },
},
{ // BX_KEY_DOWN ( ibm 84 )
{ "\xE0\x50" , "\xE0\xD0" },
{ "\xE0\x72" , "\xE0\xF0\x72" },
{ "\x60" , "\xF0\x60" },
},
{ // BX_KEY_LEFT ( ibm 79 )
{ "\xE0\x4B" , "\xE0\xCB" },
{ "\xE0\x6B" , "\xE0\xF0\x6B" },
{ "\x61" , "\xF0\x61" },
},
{ // BX_KEY_RIGHT ( ibm 89 )
{ "\xE0\x4D" , "\xE0\xCD" },
{ "\xE0\x74" , "\xE0\xF0\x74" },
{ "\x6A" , "\xF0\x6A" },
},
{ // BX_KEY_KP_ENTER ( ibm 108 )
{ "\xE0\x1C" , "\xE0\x9C" },
{ "\xE0\x5A" , "\xE0\xF0\x5A" },
{ "\x79" , "\xF0\x79" },
},
{ // BX_KEY_KP_MULTIPLY ( ibm 100 )
{ "\x37" , "\xB7" },
{ "\x7C" , "\xF0\x7C" },
{ "\x7E" , "\xF0\x7E" },
},
{ // BX_KEY_KP_DIVIDE ( ibm 95 )
{ "\xE0\x35" , "\xE0\xB5" },
{ "\xE0\x4A" , "\xE0\xF0\x4A" },
{ "\x77" , "\xF0\x77" },
},
{ // BX_KEY_WIN_L
{ "\xE0\x5B" , "\xE0\xDB" },
{ "\xE0\x1F" , "\xE0\xF0\x1F" },
{ "\x8B" , "\xF0\x8B" },
},
{ // BX_KEY_WIN_R
{ "\xE0\x5C" , "\xE0\xDC" },
{ "\xE0\x27" , "\xE0\xF0\x27" },
{ "\x8C" , "\xF0\x8C" },
},
{ // BX_KEY_MENU
{ "\xE0\x5D" , "\xE0\xDD" },
{ "\xE0\x2F" , "\xE0\xF0\x2F" },
{ "\x8D" , "\xF0\x8D" },
},
{ // BX_KEY_ALT_SYSREQ
{ "\x54" , "\xD4" },
{ "\x84" , "\xF0\x84" },
{ "\x57" , "\xF0\x57" },
},
{ // BX_KEY_CTRL_BREAK
{ "\xE0\x46" , "\xE0\xC6" },
{ "\xE0\x7E" , "\xE0\xF0\x7E" },
{ "\x62" , "\xF0\x62" },
},
{ // BX_KEY_INT_BACK
{ "\xE0\x6A" , "\xE0\xEA" },
{ "\xE0\x38" , "\xE0\xF0\x38" },
{ "\x38" , "\xF0\x38" },
},
{ // BX_KEY_INT_FORWARD
{ "\xE0\x69" , "\xE0\xE9" },
{ "\xE0\x30" , "\xE0\xF0\x30" },
{ "\x30" , "\xF0\x30" },
},
{ // BX_KEY_INT_STOP
{ "\xE0\x68" , "\xE0\xE8" },
{ "\xE0\x28" , "\xE0\xF0\x28" },
{ "\x28" , "\xF0\x28" },
},
{ // BX_KEY_INT_MAIL
{ "\xE0\x6C" , "\xE0\xEC" },
{ "\xE0\x48" , "\xE0\xF0\x48" },
{ "\x48" , "\xF0\x48" },
},
{ // BX_KEY_INT_SEARCH
{ "\xE0\x65" , "\xE0\xE5" },
{ "\xE0\x10" , "\xE0\xF0\x10" },
{ "\x10" , "\xF0\x10" },
},
{ // BX_KEY_INT_FAV
{ "\xE0\x66" , "\xE0\xE6" },
{ "\xE0\x18" , "\xE0\xF0\x18" },
{ "\x18" , "\xF0\x18" },
},
{ // BX_KEY_INT_HOME
{ "\xE0\x32" , "\xE0\xB2" },
{ "\xE0\x3A" , "\xE0\xF0\x3A" },
{ "\x97" , "\xF0\x97" },
},
{ // BX_KEY_POWER_MYCOMP
{ "\xE0\x6B" , "\xE0\xEB" },
{ "\xE0\x40" , "\xE0\xF0\x40" },
{ "\x40" , "\xF0\x40" },
},
{ // BX_KEY_POWER_CALC
{ "\xE0\x21" , "\xE0\xA1" },
{ "\xE0\x2B" , "\xE0\xF0\x2B" },
{ "\x99" , "\xF0\x99" },
},
{ // BX_KEY_POWER_SLEEP
{ "\xE0\x5F" , "\xE0\xDF" },
{ "\xE0\x3F" , "\xE0\xF0\x3F" },
{ "\x7F" , "\xF0\x7F" },
},
{ // BX_KEY_POWER_POWER
{ "\xE0\x5E" , "\xE0\xDE" },
{ "\xE0\x37" , "\xE0\xF0\x37" },
{ "" , "" },
},
{ // BX_KEY_POWER_WAKE
{ "\xE0\x63" , "\xE0\xE3" },
{ "\xE0\x5E" , "\xE0\xF0\x5E" },
{ "" , "" },
},
};

35
bochs/iodev/scancodes.h Normal file
View File

@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef BX_SCANCODES_H
#define BX_SCANCODES_H
// Translation table of the 8042
extern unsigned char translation8042[256];
typedef struct {
const char *make;
const char *brek;
} scancode;
// Scancodes table
extern scancode scancodes[BX_KEY_NBKEYS][3];
#endif

416
bochs/iodev/scsi_commands.h Normal file
View File

@ -0,0 +1,416 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
/* scsi/commands.h
Used only in cdrom_amigaos.cc.
Operation codes for SCSI-2 commands
30 Nov 94 Peter Urbanec Created file
10 Jan 95 Peter Urbanec Added SCSI_ prefix to all commands
31 Jan 95 Peter Urbanec Released to public
*/
/* All device types */
#define SCSI_CHANGE_DEFINITION 0x40
#define SCSI_COMPARE 0x39
#define SCSI_COPY 0x18
#define SCSI_COPY_AND_VERIFY 0x3a
#define SCSI_INQUIRY 0x12
#define SCSI_LOG_SELECT 0x4c
#define SCSI_LOG_SENSE 0x4d
#define SCSI_MODE_SELECT_6 0x15
#define SCSI_MODE_SELECT_10 0x55
#define SCSI_MODE_SENSE_6 0x1a
#define SCSI_MODE_SENSE_10 0x5a
#define SCSI_READ_BUFFER 0x3c
#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_SEND_DIAGNOSTIC 0x1d
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_WRITE_BUFFER 0x3b
/* Direct Access devices */
#define SCSI_DA_CHANGE_DEFINITION 0x40
#define SCSI_DA_COMPARE 0x39
#define SCSI_DA_COPY 0x18
#define SCSI_DA_COPY_AND_VERIFY 0x3a
#define SCSI_DA_FORMAT_UNIT 0x04
#define SCSI_DA_INQUIRY 0x12
#define SCSI_DA_LOCK_UNLOCK_CACHE 0x36
#define SCSI_DA_LOG_SELECT 0x4c
#define SCSI_DA_LOG_SENSE 0x4d
#define SCSI_DA_MODE_SELECT_6 0x15
#define SCSI_DA_MODE_SELECT_10 0x55
#define SCSI_DA_MODE_SENSE_6 0x1a
#define SCSI_DA_MODE_SENSE_10 0x5a
#define SCSI_DA_PRE_FETCH 0x34
#define SCSI_DA_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_DA_READ_6 0x08
#define SCSI_DA_READ_10 0x28
#define SCSI_DA_READ_BUFFER 0x3c
#define SCSI_DA_READ_CAPACITY 0x25
#define SCSI_DA_READ_DEFECT_DATA 0x37
#define SCSI_DA_READ_LONG 0x3e
#define SCSI_DA_REASSIGN_BLOCKS 0x07
#define SCSI_DA_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_DA_RELEASE 0x17
#define SCSI_DA_REQUEST_SENSE 0x03
#define SCSI_DA_RESERVE 0x16
#define SCSI_DA_REZERO_UNIT 0x01
#define SCSI_DA_SEARCH_DATA_EQUAL 0x31
#define SCSI_DA_SEARCH_DATA_HIGH 0x30
#define SCSI_DA_SEARCH_DATA_LOW 0x32
#define SCSI_DA_SEEK_6 0x0b
#define SCSI_DA_SEEK_10 0x2b
#define SCSI_DA_SEND_DIAGNOSTIC 0x1d
#define SCSI_DA_SET_LIMITS 0x33
#define SCSI_DA_START_STOP_UNIT 0x1b
#define SCSI_DA_SYNCHRONIZE_CACHE 0x35
#define SCSI_DA_TEST_UNIT_READY 0x00
#define SCSI_DA_VERIFY 0x2f
/* Sequential access devices */
#define SCSI_SA_CHANGE_DEFINITION 0x40
#define SCSI_SA_COMPARE 0x39
#define SCSI_SA_COPY 0x18
#define SCSI_SA_COPY_AND_VERIFY 0x3a
#define SCSI_SA_ERASE 0x19
#define SCSI_SA_INQUIRY 0x12
#define SCSI_SA_LOAD_UNLOAD 0x1b
#define SCSI_SA_LOCATE 0x2b
#define SCSI_SA_LOG_SELECT 0x4c
#define SCSI_SA_LOG_SENSE 0x4d
#define SCSI_SA_MODE_SELECT_6 0x15
#define SCSI_SA_MODE_SELECT_10 0x55
#define SCSI_SA_MODE_SENSE_6 0x1a
#define SCSI_SA_MODE_SENSE_10 0x5a
#define SCSI_SA_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_SA_READ 0x08
#define SCSI_SA_READ_BLOCK_LIMITS 0x05
#define SCSI_SA_READ_BUFFER 0x3c
#define SCSI_SA_READ_POSITION 0x34
#define SCSI_SA_READ_REVERSE 0x0f
#define SCSI_SA_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_SA_RECOVER_BUFFERED_DATA 0x14
#define SCSI_SA_RELEASE_UNIT 0x17
#define SCSI_SA_REQUEST_SENSE 0x03
#define SCSI_SA_RESERVE_UNIT 0x16
#define SCSI_SA_REWIND 0x01
#define SCSI_SA_SEND_DIAGNOSTIC 0x1d
#define SCSI_SA_SPACE 0x11
#define SCSI_SA_TEST_UNIT_READY 0x00
#define SCSI_SA_VERIFY 0x13
#define SCSI_SA_WRITE 0x0a
#define SCSI_SA_WRITE_BUFFER 0x3b
#define SCSI_SA_WRITE_FILEMARKS 0x10
/* Printer devices */
#define SCSI_PRT_CHANGE_DEFINITION 0x40
#define SCSI_PRT_COMPARE 0x39
#define SCSI_PRT_COPY 0x18
#define SCSI_PRT_COPY_AND_VERIFY 0x3a
#define SCSI_PRT_FORMAT 0x04
#define SCSI_PRT_INQUIRY 0x12
#define SCSI_PRT_LOG_SELECT 0x4c
#define SCSI_PRT_LOG_SENSE 0x4d
#define SCSI_PRT_MODE_SELECT_6 0x15
#define SCSI_PRT_MODE_SELECT_10 0x55
#define SCSI_PRT_MODE_SENSE_6 0x1a
#define SCSI_PRT_MODE_SENSE_10 0x5a
#define SCSI_PRT_PRINT 0x0a
#define SCSI_PRT_READ_BUFFER 0x3c
#define SCSI_PRT_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_PRT_RECOVER_BUFFERED_DATA 0x14
#define SCSI_PRT_RELEASE_UNIT 0x17
#define SCSI_PRT_REQUEST_SENSE 0x03
#define SCSI_PRT_RESERVE_UNIT 0x16
#define SCSI_PRT_SEND_DIAGNOSTIC 0x1d
#define SCSI_PRT_SLEW_AND_PRINT 0x0b
#define SCSI_PRT_STOP_PRINT 0x1b
#define SCSI_PRT_SYNCHRONIZE_BUFFER 0x10
#define SCSI_PRT_TEST_UNIT_READY 0x00
#define SCSI_PRT_WRITE_BUFFER 0x3b
/* Processor devices */
#define SCSI_CPU_CHANGE_DEFINITION 0x40
#define SCSI_CPU_COMPARE 0x39
#define SCSI_CPU_COPY 0x18
#define SCSI_CPU_COPY_AND_VERIFY 0x3a
#define SCSI_CPU_INQUIRY 0x12
#define SCSI_CPU_LOG_SELECT 0x4c
#define SCSI_CPU_LOG_SENSE 0x4d
#define SCSI_CPU_READ_BUFFER 0x3c
#define SCSI_CPU_RECEIVE 0x08
#define SCSI_CPU_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_CPU_REQUEST_SENSE 0x03
#define SCSI_CPU_SEND 0x0a
#define SCSI_CPU_SEND_DIAGNOSTIC 0x1d
#define SCSI_CPU_TEST_UNIT_READY 0x00
#define SCSI_CPU_WRITE_BUFFER 0x3b
/* Write Once devices */
#define SCSI_WO_CHANGE_DEFINITION 0x40
#define SCSI_WO_COMPARE 0x39
#define SCSI_WO_COPY 0x18
#define SCSI_WO_COPY_AND_VERIFY 0x3a
#define SCSI_WO_INQUIRY 0x12
#define SCSI_WO_LOCK_UNLOCK_CACHE 0x36
#define SCSI_WO_LOG_SELECT 0x4c
#define SCSI_WO_LOG_SENSE 0x4d
#define SCSI_WO_MEDIUM_SCAN 0x38
#define SCSI_WO_MODE_SELECT_6 0x15
#define SCSI_WO_MODE_SELECT_10 0x55
#define SCSI_WO_MODE_SENSE_6 0x1a
#define SCSI_WO_MODE_SENSE_10 0x5a
#define SCSI_WO_PRE_FETCH 0x34
#define SCSI_WO_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_WO_READ_6 0x08
#define SCSI_WO_READ_10 0x28
#define SCSI_WO_READ_12 0xa8
#define SCSI_WO_READ_BUFFER 0x3c
#define SCSI_WO_READ_CAPACITY 0x25
#define SCSI_WO_READ_LONG 0x3e
#define SCSI_WO_REASSIGN_BLOCKS 0x07
#define SCSI_WO_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_WO_RELEASE 0x17
#define SCSI_WO_REQUEST_SENSE 0x03
#define SCSI_WO_RESERVE 0x16
#define SCSI_WO_REZERO_UNIT 0x01
#define SCSI_WO_SEARCH_DATA_EQUAL_10 0x31
#define SCSI_WO_SEARCH_DATA_EQUAL_12 0xb1
#define SCSI_WO_SEARCH_DATA_HIGH_10 0x30
#define SCSI_WO_SEARCH_DATA_HIGH_12 0xb0
#define SCSI_WO_SEARCH_DATA_LOW_10 0x32
#define SCSI_WO_SEARCH_DATA_LOW_12 0xb2
#define SCSI_WO_SEEK_6 0x0b
#define SCSI_WO_SEEK_10 0x2b
#define SCSI_WO_SEND_DIAGNOSTIC 0x1d
#define SCSI_WO_SET_LIMITS_10 0x33
#define SCSI_WO_SET_LIMITS_12 0xb3
#define SCSI_WO_START_STOP_UNIT 0x1b
#define SCSI_WO_SYNCHRONIZE_CACHE 0x35
#define SCSI_WO_TEST_UNIT_READY 0x00
#define SCSI_WO_VERIFY_10 0x2f
#define SCSI_WO_VERIFY_12 0xaf
#define SCSI_WO_WRITE_6 0x0a
#define SCSI_WO_WRITE_10 0x2a
#define SCSI_WO_WRITE_12 0xaa
#define SCSI_WO_WRITE_AND_VERIFY_10 0x2e
#define SCSI_WO_WRITE_AND_VERIFY_12 0xae
#define SCSI_WO_WRITE_BUFFER 0x3b
#define SCSI_WO_WRITE_LONG 0x3f
/* CD-ROM devices */
#define SCSI_CD_CHANGE_DEFINITION 0x40
#define SCSI_CD_COMPARE 0x39
#define SCSI_CD_COPY 0x18
#define SCSI_CD_COPY_AND_VERIFY 0x3a
#define SCSI_CD_INQUIRY 0x12
#define SCSI_CD_LOCK_UNLOCK_CACHE 0x36
#define SCSI_CD_LOG_SELECT 0x4c
#define SCSI_CD_LOG_SENSE 0x4d
#define SCSI_CD_MODE_SELECT_6 0x15
#define SCSI_CD_MODE_SELECT_10 0x55
#define SCSI_CD_MODE_SENSE_6 0x1a
#define SCSI_CD_MODE_SENSE_10 0x5a
#define SCSI_CD_PAUSE_RESUME 0x4b
#define SCSI_CD_PLAY_AUDIO_10 0x45
#define SCSI_CD_PLAY_AUDIO_12 0xa5
#define SCSI_CD_PLAY_AUDIO_MSF 0x47
#define SCSI_CD_PLAY_AUDIO_TRACK_INDEX 0x48
#define SCSI_CD_PLAY_TRACK_RELATIVE_10 0x49
#define SCSI_CD_PLAY_TRACK_RELATIVE_12 0xa9
#define SCSI_CD_PRE_FETCH 0x34
#define SCSI_CD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_CD_READ_6 0x08
#define SCSI_CD_READ_10 0x28
#define SCSI_CD_READ_12 0xa8
#define SCSI_CD_READ_BUFFER 0x3c
#define SCSI_CD_READ_CD_ROM_CAPACITY 0x25
#define SCSI_CD_READ_HEADER 0x44
#define SCSI_CD_READ_LONG 0x3e
#define SCSI_CD_READ_SUB_CHANNEL 0x42
#define SCSI_CD_READ_TOC 0x43
#define SCSI_CD_RECEIVE_DIAGNOSTIC_RESULT 0x1c
#define SCSI_CD_RELEASE 0x17
#define SCSI_CD_REQUEST_SENSE 0x03
#define SCSI_CD_RESERVE 0x16
#define SCSI_CD_REZERO_UNIT 0x01
#define SCSI_CD_SEARCH_DATA_EQUAL_10 0x31
#define SCSI_CD_SEARCH_DATA_EQUAL_12 0xb1
#define SCSI_CD_SEARCH_DATA_HIGH_10 0x30
#define SCSI_CD_SEARCH_DATA_HIGH_12 0xb0
#define SCSI_CD_SEARCH_DATA_LOW_10 0x32
#define SCSI_CD_SEARCH_DATA_LOW_12 0xb2
#define SCSI_CD_SEEK_6 0x0b
#define SCSI_CD_SEEK_10 0x2b
#define SCSI_CD_SEND_DIAGNOSTIC 0x1d
#define SCSI_CD_SET_LIMITS_10 0x33
#define SCSI_CD_SET_LIMITS_12 0xb3
#define SCSI_CD_START_STOP_UNIT 0x1b
#define SCSI_CD_SYNCHRONIZE_CACHE 0x35
#define SCSI_CD_TEST_UNIT_READY 0x00
#define SCSI_CD_VERIFY_10 0x2f
#define SCSI_CD_VERIFY_12 0xaf
#define SCSI_CD_WRITE_BUFFER 0x3b
/* Scanner devices */
#define SCSI_SC_CHANGE_DEFINITION 0x40
#define SCSI_SC_COMPARE 0x39
#define SCSI_SC_COPY 0x18
#define SCSI_SC_COPY_AND_VERIFY 0x3a
#define SCSI_SC_GET_DATA_BUFFER_STATUS 0x34
#define SCSI_SC_GET_WINDOW 0x25
#define SCSI_SC_INQUIRY 0x12
#define SCSI_SC_LOG_SELECT 0x4c
#define SCSI_SC_LOG_SENSE 0x4d
#define SCSI_SC_MODE_SELECT_6 0x15
#define SCSI_SC_MODE_SELECT_10 0x55
#define SCSI_SC_MODE_SENSE_6 0x1a
#define SCSI_SC_MODE_SENSE_10 0x5a
#define SCSI_SC_OBJECT_POSITION 0x31
#define SCSI_SC_READ 0x28
#define SCSI_SC_READ_BUFFER 0x3c
#define SCSI_SC_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_SC_RELEASE_UNIT 0x17
#define SCSI_SC_REQUEST_SENSE 0x03
#define SCSI_SC_RESERVE_UNIT 0x16
#define SCSI_SC_SCAN 0x1b
#define SCSI_SC_SET_WINDOW 0x24
#define SCSI_SC_SEND 0x2a
#define SCSI_SC_SEND_DIAGNOSTIC 0x1d
#define SCSI_SC_TEST_UNIT_READY 0x00
#define SCSI_SC_WRITE_BUFFER 0x3b
/* Optical memory devices */
#define SCSI_OM_CHANGE_DEFINITION 0x40
#define SCSI_OM_COMPARE 0x39
#define SCSI_OM_COPY 0x18
#define SCSI_OM_COPY_AND_VERIFY 0x3a
#define SCSI_OM_ERASE_10 0x2c
#define SCSI_OM_ERASE_12 0xac
#define SCSI_OM_FORMAT_UNIT 0x04
#define SCSI_OM_INQUIRY 0x12
#define SCSI_OM_LOCK_UNLOCK_CACHE 0x36
#define SCSI_OM_LOG_SELECT 0x4c
#define SCSI_OM_LOG_SENSE 0x4d
#define SCSI_OM_MEDIUM_SCAN 0x38
#define SCSI_OM_MODE_SELECT_6 0x15
#define SCSI_OM_MODE_SELECT_10 0x55
#define SCSI_OM_MODE_SENSE_6 0x1a
#define SCSI_OM_MODE_SENSE_10 0x5a
#define SCSI_OM_PRE_FETCH 0x34
#define SCSI_OM_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_OM_READ_6 0x08
#define SCSI_OM_READ_10 0x28
#define SCSI_OM_READ_12 0xa8
#define SCSI_OM_READ_BUFFER 0x3c
#define SCSI_OM_READ_CAPACITY 0x25
#define SCSI_OM_READ_DEFECT_DATA_10 0x37
#define SCSI_OM_READ_DEFECT_DATA_12 0xb7
#define SCSI_OM_READ_GENERATION 0x29
#define SCSI_OM_READ_LONG 0x3e
#define SCSI_OM_READ_UPDATED_BLOCK 0x2d
#define SCSI_OM_REASSIGN_BLOCKS 0x07
#define SCSI_OM_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_OM_RELEASE 0x17
#define SCSI_OM_REQUEST_SENSE 0x03
#define SCSI_OM_RESERVE 0x16
#define SCSI_OM_REZERO_UNIT 0x01
#define SCSI_OM_SEARCH_DATA_EQUAL_10 0x31
#define SCSI_OM_SEARCH_DATA_EQUAL_12 0xb1
#define SCSI_OM_SEARCH_DATA_HIGH_10 0x30
#define SCSI_OM_SEARCH_DATA_HIGH_12 0xb0
#define SCSI_OM_SEARCH_DATA_LOW_10 0x32
#define SCSI_OM_SEARCH_DATA_LOW_12 0xb2
#define SCSI_OM_SEEK_6 0x0b
#define SCSI_OM_SEEK_10 0x2b
#define SCSI_OM_SEND_DIAGNOSTIC 0x1d
#define SCSI_OM_SET_LIMITS_10 0x33
#define SCSI_OM_SET_LIMITS_12 0xb3
#define SCSI_OM_START_STOP_UNIT 0x1b
#define SCSI_OM_SYNCHRONIZE_CACHE 0x35
#define SCSI_OM_TEST_UNIT_READY 0x00
#define SCSI_OM_UPDATE_BLOCK 0x3d
#define SCSI_OM_VERIFY_10 0x2f
#define SCSI_OM_VERIFY_12 0xaf
#define SCSI_OM_WRITE_6 0x0a
#define SCSI_OM_WRITE_10 0x2a
#define SCSI_OM_WRITE_12 0xaa
#define SCSI_OM_WRITE_AND_VERIFY_10 0x2e
#define SCSI_OM_WRITE_AND_VERIFY_12 0xae
#define SCSI_OM_WRITE_BUFFER 0x3b
#define SCSI_OM_WRITE_LONG 0x3f
/* Medium changer devices */
#define SCSI_MC_CHANGE_DEFINITION 0x40
#define SCSI_MC_EXCHANGE_MEDIUM 0xa6
#define SCSI_MC_INITIALIZE_ELEMENT_STATUS 0x07
#define SCSI_MC_INQUIRY 0x12
#define SCSI_MC_LOG_SELECT 0x4c
#define SCSI_MC_LOG_SENSE 0x4d
#define SCSI_MC_MODE_SELECT_6 0x15
#define SCSI_MC_MODE_SELECT_10 0x55
#define SCSI_MC_MODE_SENSE_6 0x1a
#define SCSI_MC_MODE_SENSE_10 0x5a
#define SCSI_MC_MOVE_MEDIUM 0xa5
#define SCSI_MC_POSITION_TO_ELEMENT 0x2b
#define SCSI_MC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
#define SCSI_MC_READ_BUFFER 0x3c
#define SCSI_MC_READ_ELEMENT_STATUS 0xb8
#define SCSI_MC_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_MC_RELEASE 0x17
#define SCSI_MC_REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5
#define SCSI_MC_REQUEST_SENSE 0x03
#define SCSI_MC_RESERVE 0x16
#define SCSI_MC_REZERO_UNIT 0x01
#define SCSI_MC_SEND_DIAGNOSTIC 0x1d
#define SCSI_MC_SEND_VOLUME_TAG 0xb6
#define SCSI_MC_TEST_UNIT_READY 0x00
#define SCSI_MC_WRITE_BUFFER 0x3b
/* Communications devices */
#define SCSI_COM_CHANGE_DEFINITION 0x40
#define SCSI_COM_GET_MESSAGE_6 0x08
#define SCSI_COM_GET_MESSAGE_10 0x28
#define SCSI_COM_GET_MESSAGE_12 0xa8
#define SCSI_COM_INQUIRY 0x12
#define SCSI_COM_LOG_SELECT 0x4c
#define SCSI_COM_LOG_SENSE 0x4d
#define SCSI_COM_MODE_SELECT_6 0x15
#define SCSI_COM_MODE_SELECT_10 0x55
#define SCSI_COM_MODE_SENSE_6 0x1a
#define SCSI_COM_MODE_SENSE_10 0x5a
#define SCSI_COM_READ_BUFFER 0x3c
#define SCSI_COM_RECEIVE_DIAGNOSTIC_RESULTS 0x1c
#define SCSI_COM_REQUEST_SENSE 0x03
#define SCSI_COM_SEND_DIAGNOSTIC 0x1d
#define SCSI_COM_SEND_MESSAGE_6 0x0a
#define SCSI_COM_SEND_MESSAGE_10 0x2a
#define SCSI_COM_SEND_MESSAGE_12 0xaa
#define SCSI_COM_TEST_UNIT_READY 0x00
#define SCSI_COM_WRITE_BUFFER 0x3b

792
bochs/iodev/scsi_device.cc Normal file
View File

@ -0,0 +1,792 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// SCSI emulation layer ported from the Qemu project
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
#include "hdimage.h"
#include "cdrom.h"
#include "scsi_device.h"
#define LOG_THIS
#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
#define DEVICE_NAME "SCSI drive"
static SCSIRequest *free_requests = NULL;
static Bit32u serial_number = 12345678;
scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
scsi_completionfn _completion, void *_dev)
{
type = SCSIDEV_TYPE_DISK;
cdrom = NULL;
hdimage = _hdimage;
requests = NULL;
sense = 0;
tcq = _tcq;
completion = _completion;
dev = _dev;
cluster_size = 1;
locked = 0;
inserted = 1;
max_lba = (hdimage->hd_size / 512) - 1;
sprintf(drive_serial_str, "%d", serial_number++);
put("SCSID");
}
scsi_device_t::scsi_device_t(LOWLEVEL_CDROM *_cdrom, int _tcq,
scsi_completionfn _completion, void *_dev)
{
type = SCSIDEV_TYPE_CDROM;
cdrom = _cdrom;
hdimage = NULL;
requests = NULL;
sense = 0;
tcq = _tcq;
completion = _completion;
dev = _dev;
cluster_size = 4;
locked = 0;
inserted = 1;
max_lba = cdrom->capacity() - 1;
sprintf(drive_serial_str, "%d", serial_number++);
put("SCSIC");
}
scsi_device_t::~scsi_device_t(void)
{
SCSIRequest *r, *next;
if (requests) {
r = requests;
while (r != NULL) {
next = r->next;
delete r;
r = next;
}
}
if (free_requests) {
r = free_requests;
while (r != NULL) {
next = r->next;
delete r;
r = next;
}
free_requests = NULL;
}
}
void scsi_device_t::register_state(bx_list_c *parent, const char *name)
{
bx_list_c *list = new bx_list_c(parent, name, "", 1);
new bx_shadow_num_c(list, "sense", &sense);
// TODO: save/restore for SCSI requests
}
SCSIRequest* scsi_device_t::scsi_new_request(Bit32u tag)
{
SCSIRequest *r;
if (free_requests) {
r = free_requests;
free_requests = r->next;
} else {
r = new SCSIRequest;
}
r->dev = this;
r->tag = tag;
r->sector_count = 0;
r->buf_len = 0;
r->status = 0;
r->next = requests;
requests = r;
return r;
}
void scsi_device_t::scsi_remove_request(SCSIRequest *r)
{
SCSIRequest *last;
if (requests == r) {
requests = r->next;
} else {
last = requests;
while (last != NULL) {
if (last->next != r)
last = last->next;
else
break;
}
if (last) {
last->next = r->next;
} else {
BX_ERROR(("orphaned request"));
}
}
r->next = free_requests;
free_requests = r;
}
SCSIRequest* scsi_device_t::scsi_find_request(Bit32u tag)
{
SCSIRequest *r = requests;
while (r != NULL) {
if (r->tag != tag)
r = r->next;
else
break;
}
return r;
}
void scsi_device_t::scsi_command_complete(SCSIRequest *r, int status, int _sense)
{
Bit32u tag;
BX_DEBUG(("command complete tag=0x%x status=%d sense=%d", r->tag, status, sense));
sense = _sense;
tag = r->tag;
scsi_remove_request(r);
completion(dev, SCSI_REASON_DONE, tag, status);
}
void scsi_device_t::scsi_cancel_io(Bit32u tag)
{
BX_DEBUG(("cancel tag=0x%x", tag));
SCSIRequest *r = scsi_find_request(tag);
if (r) {
scsi_remove_request(r);
}
}
void scsi_device_t::scsi_read_complete(void *req, int ret)
{
SCSIRequest *r = (SCSIRequest *)req;
if (ret) {
BX_ERROR(("IO error"));
completion(r, SCSI_REASON_DATA, r->tag, 0);
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
return;
}
BX_DEBUG(("data ready tag=0x%x len=%d", r->tag, r->buf_len));
completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
}
void scsi_device_t::scsi_read_data(Bit32u tag)
{
Bit32u n;
int ret;
SCSIRequest *r = scsi_find_request(tag);
if (!r) {
BX_ERROR(("bad read tag 0x%x", tag));
// ??? This is the wrong error.
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
return;
}
if (r->sector_count == (Bit32u)-1) {
BX_DEBUG(("read buf_len=%d", r->buf_len));
r->sector_count = 0;
completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
return;
}
BX_DEBUG(("read sector_count=%d", r->sector_count));
if (r->sector_count == 0) {
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
return;
}
n = r->sector_count;
if (n > (Bit32u)(SCSI_DMA_BUF_SIZE / (512 * cluster_size)))
n = SCSI_DMA_BUF_SIZE / (512 * cluster_size);
r->buf_len = n * 512 * cluster_size;
if (type == SCSIDEV_TYPE_CDROM) {
if (!cdrom->read_block(r->dma_buf, (Bit32u)r->sector, 2048)) {
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
} else {
scsi_read_complete((void*)r, 0);
}
} else {
ret = (int)hdimage->lseek(r->sector * 512, SEEK_SET);
if (ret < 0) {
BX_ERROR(("could not lseek() hard drive image file"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
}
ret = hdimage->read((bx_ptr_t)r->dma_buf, r->buf_len);
if (ret < r->buf_len) {
BX_ERROR(("could not read() hard drive image file"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
} else {
scsi_read_complete((void*)r, 0);
}
}
r->sector += n;
r->sector_count -= n;
}
void scsi_device_t::scsi_write_complete(void *req, int ret)
{
SCSIRequest *r = (SCSIRequest *)req;
Bit32u len;
if (ret) {
BX_ERROR(("IO error"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
return;
}
if (r->sector_count == 0) {
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
} else {
len = r->sector_count * 512;
if (len > SCSI_DMA_BUF_SIZE) {
len = SCSI_DMA_BUF_SIZE;
}
r->buf_len = len;
BX_DEBUG(("write complete tag=0x%x more=%d", r->tag, len));
completion(dev, SCSI_REASON_DATA, r->tag, len);
}
}
int scsi_device_t::scsi_write_data(Bit32u tag)
{
SCSIRequest *r;
Bit32u n;
int ret;
BX_DEBUG(("write data tag=0x%x", tag));
r = scsi_find_request(tag);
if (!r) {
BX_ERROR(("bad write tag 0x%x", tag));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
return 1;
}
if (type == SCSIDEV_TYPE_DISK) {
n = r->buf_len / 512;
if (n) {
ret = (int)hdimage->lseek(r->sector * 512, SEEK_SET);
if (ret < 0) {
BX_ERROR(("could not lseek() hard drive image file"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
}
ret = hdimage->write((bx_ptr_t)r->dma_buf, r->buf_len);
r->sector += n;
r->sector_count -= n;
if (ret < r->buf_len) {
BX_ERROR(("could not write() hard drive image file"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
} else {
scsi_write_complete((void*)r, 0);
}
} else {
scsi_write_complete(r, 0);
}
} else {
BX_ERROR(("CD-ROM: write not supported"));
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
}
return 0;
}
Bit8u* scsi_device_t::scsi_get_buf(Bit32u tag)
{
SCSIRequest *r = scsi_find_request(tag);
if (!r) {
BX_ERROR(("bad buffer tag 0x%x", tag));
return NULL;
}
return r->dma_buf;
}
Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
{
Bit64u nb_sectors;
Bit64u lba;
Bit32s len;
int cmdlen;
int is_write;
Bit8u command;
Bit8u *outbuf;
SCSIRequest *r;
command = buf[0];
r = scsi_find_request(tag);
if (r) {
BX_ERROR(("tag 0x%x already in use", tag));
scsi_cancel_io(tag);
}
r = scsi_new_request(tag);
outbuf = r->dma_buf;
is_write = 0;
BX_DEBUG(("command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]));
switch (command >> 5) {
case 0:
lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
len = buf[4];
cmdlen = 6;
break;
case 1:
case 2:
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
len = buf[8] | (buf[7] << 8);
cmdlen = 10;
break;
case 4:
lba = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24) |
((Bit64u)buf[5] << 32) | ((Bit64u)buf[4] << 40) |
((Bit64u)buf[3] << 48) | ((Bit64u)buf[2] << 56);
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
cmdlen = 16;
break;
case 5:
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
cmdlen = 12;
break;
default:
BX_ERROR(("Unsupported command length, command %x", command));
goto fail;
}
if (lun || buf[1] >> 5) {
BX_ERROR(("unimplemented LUN %d", lun ? lun : buf[1] >> 5));
if ((command != 0x03) && (command != 0x12)) // REQUEST SENSE and INQUIRY
goto fail;
}
switch (command) {
case 0x0:
BX_DEBUG(("Test Unit Ready"));
if (!inserted)
goto notready;
break;
case 0x03:
BX_DEBUG(("request Sense (len %d)", len));
if (len < 4)
goto fail;
memset(outbuf, 0, 4);
r->buf_len = 4;
if ((sense == SENSE_NOT_READY) && (len >= 18)) {
memset(outbuf, 0, 18);
r->buf_len = 18;
outbuf[7] = 10;
/* asc 0x3a, ascq 0: Medium not present */
outbuf[12] = 0x3a;
outbuf[13] = 0;
}
outbuf[0] = 0xf0;
outbuf[1] = 0;
outbuf[2] = sense;
break;
case 0x12:
BX_DEBUG(("inquiry (len %d)", len));
if (buf[1] & 0x2) {
// Command support data - optional, not implemented
BX_ERROR(("optional INQUIRY command support request not implemented"));
goto fail;
} else if (buf[1] & 0x1) {
// Vital product data
Bit8u page_code = buf[2];
if (len < 4) {
BX_ERROR(("Error: Inquiry (EVPD[%02X]) buffer size %d is less than 4", page_code, len));
goto fail;
}
switch (page_code) {
case 0x00:
// Supported page codes, mandatory
BX_DEBUG(("Inquiry EVPD[Supported pages] buffer size %d", len));
r->buf_len = 0;
if (type == SCSIDEV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x00; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = 3; // number of pages
outbuf[r->buf_len++] = 0x00; // list of supported pages (this page)
outbuf[r->buf_len++] = 0x80; // unit serial number
outbuf[r->buf_len++] = 0x83; // device identification
break;
case 0x80:
{
int l;
// Device serial number, optional
if (len < 4) {
BX_ERROR(("Error: EVPD[Serial number] Inquiry buffer size %d too small, %d needed", len, 4));
goto fail;
}
BX_DEBUG(("Inquiry EVPD[Serial number] buffer size %d\n", len));
l = BX_MIN(len, (int)strlen(drive_serial_str));
r->buf_len = 0;
// Supported page codes
if (type == SCSIDEV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x80; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = l;
memcpy(&outbuf[r->buf_len], drive_serial_str, l);
r->buf_len += l;
}
break;
case 0x83:
{
// Device identification page, mandatory
int max_len = 255 - 8;
int id_len = strlen(DEVICE_NAME);
if (id_len > max_len)
id_len = max_len;
BX_DEBUG(("Inquiry EVPD[Device identification] buffer size %d", len));
r->buf_len = 0;
if (type == SCSIDEV_TYPE_CDROM) {
outbuf[r->buf_len++] = 5;
} else {
outbuf[r->buf_len++] = 0;
}
outbuf[r->buf_len++] = 0x83; // this page
outbuf[r->buf_len++] = 0x00;
outbuf[r->buf_len++] = 3 + id_len;
outbuf[r->buf_len++] = 0x2; // ASCII
outbuf[r->buf_len++] = 0; // not officially assigned
outbuf[r->buf_len++] = 0; // reserved
outbuf[r->buf_len++] = id_len; // length of data following
memcpy(&outbuf[r->buf_len], DEVICE_NAME, id_len);
r->buf_len += id_len;
}
break;
default:
BX_ERROR(("Error: unsupported Inquiry (EVPD[%02X]) buffer size %d", page_code, len));
goto fail;
}
// done with EVPD
break;
} else {
// Standard INQUIRY data
if (buf[2] != 0) {
BX_ERROR(("Error: Inquiry (STANDARD) page or code is non-zero [%02X]", buf[2]));
goto fail;
}
// PAGE CODE == 0
if (len < 5) {
BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 5", len));
goto fail;
}
if (len < 36) {
BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 36 (TODO: only 5 required)", len));
}
}
if(len > SCSI_MAX_INQUIRY_LEN)
len = SCSI_MAX_INQUIRY_LEN;
memset(outbuf, 0, len);
if (lun || buf[1] >> 5) {
outbuf[0] = 0x7f; // LUN not supported
} else if (type == SCSIDEV_TYPE_CDROM) {
outbuf[0] = 5;
outbuf[1] = 0x80;
memcpy(&outbuf[16], "BOCHS CD-ROM ", 16);
} else {
outbuf[0] = 0;
memcpy(&outbuf[16], "BOCHS HARDDISK ", 16);
}
memcpy(&outbuf[8], "BOCHS ", 8);
memcpy(&outbuf[32], "1.0", 4);
// Identify device as SCSI-3 rev 1.
// Some later commands are also implemented.
outbuf[2] = 3;
outbuf[3] = 2; // Format 2
outbuf[4] = len - 5; // Additional Length = (Len - 1) - 4
// Sync data transfer and TCQ.
outbuf[7] = 0x10 | (tcq ? 0x02 : 0);
r->buf_len = len;
break;
case 0x16:
BX_INFO(("Reserve(6)"));
if (buf[1] & 1)
goto fail;
break;
case 0x17:
BX_INFO(("Release(6)"));
if (buf[1] & 1)
goto fail;
break;
case 0x1a:
case 0x5a:
{
Bit8u *p;
int page;
page = buf[2] & 0x3f;
BX_DEBUG(("mode sense (page %d, len %d)", page, len));
p = outbuf;
memset(p, 0, 4);
outbuf[1] = 0; /* Default media type. */
outbuf[3] = 0; /* Block descriptor length. */
if (type == SCSIDEV_TYPE_CDROM) {
outbuf[2] = 0x80; /* Readonly. */
}
p += 4;
if ((page == 4) || (page == 5)) {
BX_ERROR(("mode sense: page %d not implemented", page));
}
if ((page == 8 || page == 0x3f)) {
/* Caching page. */
memset(p, 0, 20);
p[0] = 8;
p[1] = 0x12;
p[2] = 4; /* WCE */
p += 20;
}
if ((page == 0x3f || page == 0x2a)
&& (type == SCSIDEV_TYPE_CDROM)) {
/* CD Capabilities and Mechanical Status page. */
p[0] = 0x2a;
p[1] = 0x14;
p[2] = 3; // CD-R & CD-RW read
p[3] = 0; // Writing not supported
p[4] = 0x7f; /* Audio, composite, digital out,
mode 2 form 1&2, multi session */
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
RW corrected, C2 errors, ISRC,
UPC, Bar code */
p[6] = 0x2d | (locked ? 2 : 0);
/* Locking supported, jumper present, eject, tray */
p[7] = 0; /* no volume & mute control, no changer */
p[8] = (50 * 176) >> 8; // 50x read speed
p[9] = (50 * 176) & 0xff;
p[10] = 0 >> 8; // No volume
p[11] = 0 & 0xff;
p[12] = 2048 >> 8; // 2M buffer
p[13] = 2048 & 0xff;
p[14] = (16 * 176) >> 8; // 16x read speed current
p[15] = (16 * 176) & 0xff;
p[18] = (16 * 176) >> 8; // 16x write speed
p[19] = (16 * 176) & 0xff;
p[20] = (16 * 176) >> 8; // 16x write speed current
p[21] = (16 * 176) & 0xff;
p += 22;
}
r->buf_len = p - outbuf;
outbuf[0] = r->buf_len - 4;
if (r->buf_len > (int)len)
r->buf_len = len;
}
break;
case 0x1b:
BX_INFO(("Start Stop Unit"));
if (type == SCSIDEV_TYPE_CDROM && (buf[4] & 2)) {
if (!(buf[4] & 1)) {
// eject medium
cdrom->eject_cdrom();
inserted = 0;
}
}
break;
case 0x1e:
BX_INFO(("Prevent Allow Medium Removal (prevent = %d)", buf[4] & 3));
locked = buf[4] & 1;
break;
case 0x25:
BX_DEBUG(("Read Capacity"));
// The normal LEN field for this command is zero
memset(outbuf, 0, 8);
if (type == SCSIDEV_TYPE_CDROM) {
nb_sectors = cdrom->capacity();
} else {
nb_sectors = hdimage->hd_size / 512;
}
/* Returned value is the address of the last sector. */
if (nb_sectors) {
nb_sectors--;
outbuf[0] = (Bit8u)((nb_sectors >> 24) & 0xff);
outbuf[1] = (Bit8u)((nb_sectors >> 16) & 0xff);
outbuf[2] = (Bit8u)((nb_sectors >> 8) & 0xff);
outbuf[3] = (Bit8u)(nb_sectors & 0xff);
outbuf[4] = 0;
outbuf[5] = 0;
outbuf[6] = cluster_size * 2;
outbuf[7] = 0;
r->buf_len = 8;
} else {
notready:
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
return 0;
}
break;
case 0x08:
case 0x28:
case 0x88:
BX_DEBUG(("Read (sector "FMT_LL"d, count %d)", lba, len));
if (lba > max_lba)
goto illegal_lba;
r->sector = lba;
r->sector_count = len;
break;
case 0x0a:
case 0x2a:
case 0x8a:
BX_DEBUG(("Write (sector "FMT_LL"d, count %d)", lba, len));
if (lba > max_lba)
goto illegal_lba;
r->sector = lba;
r->sector_count = len;
is_write = 1;
break;
case 0x35:
BX_DEBUG(("Syncronise cache (sector "FMT_LL"d, count %d)", lba, len));
// TODO: flush cache
break;
case 0x43:
{
int start_track, format, msf, toclen;
if (type == SCSIDEV_TYPE_CDROM) {
msf = buf[1] & 2;
format = buf[2] & 0xf;
start_track = buf[6];
BX_DEBUG(("Read TOC (track %d format %d msf %d)", start_track, format, msf >> 1));
cdrom->read_toc(outbuf, &toclen, msf, start_track, format);
if (toclen > 0) {
if (len > toclen)
len = toclen;
r->buf_len = len;
break;
}
BX_ERROR(("Read TOC error"));
goto fail;
} else {
goto fail;
}
}
case 0x46:
BX_DEBUG(("Get Configuration (rt %d, maxlen %d)", buf[1] & 3, len));
memset(outbuf, 0, 8);
/* ??? This shoud probably return much more information. For now
just return the basic header indicating the CD-ROM profile. */
outbuf[7] = 8; // CD-ROM
r->buf_len = 8;
break;
case 0x56:
BX_INFO(("Reserve(10)"));
if (buf[1] & 3)
goto fail;
break;
case 0x57:
BX_INFO(("Release(10)"));
if (buf[1] & 3)
goto fail;
break;
case 0xa0:
BX_INFO(("Report LUNs (len %d)", len));
if (len < 16)
goto fail;
memset(outbuf, 0, 16);
outbuf[3] = 8;
r->buf_len = 16;
break;
case 0x2f:
BX_INFO(("Verify"));
break;
case 0x23: {
// USBMASS-UFI10.pdf  rev 1.0  Section 4.10
BX_INFO(("READ FORMAT CAPACITIES (MMC)"));
unsigned len = (buf[7]<<8) | buf[8];
#define OUR_LEN 12
// Cap List Header
outbuf[0] = 0;
outbuf[1] = 0;
outbuf[2] = 0;
outbuf[3] = OUR_LEN;
// Current/Max Cap Header
if (type == SCSIDEV_TYPE_CDROM) {
nb_sectors = cdrom->capacity();
} else {
nb_sectors = (hdimage->hd_size / 512);
}
/* Returned value is the address of the last sector.  */
outbuf[4] = (Bit8u)((nb_sectors >> 24) & 0xff);
outbuf[5] = (Bit8u)((nb_sectors >> 16) & 0xff);
outbuf[6] = (Bit8u)((nb_sectors >> 8) & 0xff);
outbuf[7] = (Bit8u)(nb_sectors & 0xff);
outbuf[8] = 2; // formatted (1 = unformatted)
outbuf[9] = 0;
outbuf[10] = cluster_size * 2;
outbuf[11] = 0;
r->buf_len = (len < OUR_LEN) ? len : OUR_LEN;
}
break;
default:
BX_ERROR(("Unknown SCSI command (%2.2x)", buf[0]));
fail:
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
return 0;
illegal_lba:
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
return 0;
}
if (r->sector_count == 0 && r->buf_len == 0) {
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
}
len = r->sector_count * 512 * cluster_size + r->buf_len;
if (is_write) {
return -len;
} else {
if (!r->sector_count)
r->sector_count = (Bit32u) -1;
return len;
}
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB

106
bochs/iodev/scsi_device.h Normal file
View File

@ -0,0 +1,106 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// SCSI emulation layer ported from the Qemu project
#ifndef BX_IODEV_SCSI_DEVICE_H
#define BX_IODEV_SCSI_DEVICE_H
typedef void (*scsi_completionfn)(void *opaque, int reason, Bit32u tag,
Bit32u arg);
class scsi_device_t;
class LOWLEVEL_CDROM;
enum scsidev_type {
SCSIDEV_TYPE_DISK,
SCSIDEV_TYPE_CDROM
};
enum scsi_reason {
SCSI_REASON_DONE,
SCSI_REASON_DATA
};
#define SENSE_NO_SENSE 0
#define SENSE_NOT_READY 2
#define SENSE_HARDWARE_ERROR 4
#define SENSE_ILLEGAL_REQUEST 5
#define STATUS_GOOD 0
#define STATUS_CHECK_CONDITION 2
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
typedef struct SCSIRequest {
scsi_device_t *dev;
Bit32u tag;
Bit64u sector;
Bit32u sector_count;
int buf_len;
Bit8u dma_buf[SCSI_DMA_BUF_SIZE];
Bit32u status;
struct SCSIRequest *next;
} SCSIRequest;
class scsi_device_t : public logfunctions {
public:
scsi_device_t(device_image_t *_hdimage, int _tcq,
scsi_completionfn _completion, void *_dev);
scsi_device_t(LOWLEVEL_CDROM *_cdrom, int _tcq,
scsi_completionfn _completion, void *_dev);
virtual ~scsi_device_t(void);
void register_state(bx_list_c *parent, const char *name);
Bit32s scsi_send_command(Bit32u tag, Bit8u *buf, int lun);
void scsi_command_complete(SCSIRequest *r, int status, int sense);
void scsi_cancel_io(Bit32u tag);
void scsi_read_complete(void *req, int ret);
void scsi_read_data(Bit32u tag);
void scsi_write_complete(void *req, int ret);
int scsi_write_data(Bit32u tag);
Bit8u* scsi_get_buf(Bit32u tag);
const char *get_serial_number() {return drive_serial_str;}
void set_inserted(bx_bool value) {inserted = value;}
bx_bool get_inserted() {return inserted;}
protected:
SCSIRequest* scsi_new_request(Bit32u tag);
void scsi_remove_request(SCSIRequest *r);
SCSIRequest *scsi_find_request(Bit32u tag);
private:
enum scsidev_type type;
device_image_t *hdimage;
LOWLEVEL_CDROM *cdrom;
SCSIRequest *requests;
int cluster_size;
Bit64u max_lba;
int sense;
int tcq;
scsi_completionfn completion;
void *dev;
bx_bool locked;
bx_bool inserted;
char drive_serial_str[21];
};
#endif

283
bochs/iodev/scsidefs.h Normal file
View File

@ -0,0 +1,283 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// iodev/scsidefs.h
//
// This file was copied from ... ?
//
//***************************************************************************
// Name: SCSIDEFS.H
//
// Description: SCSI definitions ('C' Language)
//***************************************************************************
//***************************************************************************
// %%% TARGET STATUS VALUES %%%
//***************************************************************************
#define STATUS_GOOD 0x00 // Status Good
#define STATUS_CHKCOND 0x02 // Check Condition
#define STATUS_CONDMET 0x04 // Condition Met
#define STATUS_BUSY 0x08 // Busy
#define STATUS_INTERM 0x10 // Intermediate
#define STATUS_INTCDMET 0x14 // Intermediate-condition met
#define STATUS_RESCONF 0x18 // Reservation conflict
#define STATUS_COMTERM 0x22 // Command Terminated
#define STATUS_QFULL 0x28 // Queue full
//***************************************************************************
// %%% SCSI MISCELLANEOUS EQUATES %%%
//***************************************************************************
#define MAXLUN 7 // Maximum Logical Unit Id
#define MAXTARG 7 // Maximum Target Id
#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs
#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//
// %%% SCSI COMMAND OPCODES %%%
//
///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//***************************************************************************
// %%% Commands for all Device Types %%%
//***************************************************************************
#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional)
#define SCSI_COMPARE 0x39 // Compare (O)
#define SCSI_COPY 0x18 // Copy (O)
#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O)
#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY)
#define SCSI_LOG_SELECT 0x4C // Log Select (O)
#define SCSI_LOG_SENSE 0x4D // Log Sense (O)
#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific)
#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific)
#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific)
#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific)
#define SCSI_READ_BUFF 0x3C // Read Buffer (O)
#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY)
#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O)
#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY)
#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O)
//***************************************************************************
// %%% Commands Unique to Direct Access Devices %%%
//***************************************************************************
#define SCSI_COMPARE 0x39 // Compare (O)
#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY)
#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O)
#define SCSI_PREFETCH 0x34 // Prefetch (O)
#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O)
#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY)
#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY)
#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY)
#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O)
#define SCSI_READ_LONG 0x3E // Read Long (O)
#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O)
#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O)
#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY)
#define SCSI_REZERO 0x01 // Rezero Unit (O)
#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O)
#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O)
#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O)
#define SCSI_SEEK6 0x0B // Seek 6-Byte (O)
#define SCSI_SEEK10 0x2B // Seek 10-Byte (O)
#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY)
#define SCSI_SET_LIMIT 0x33 // Set Limits (O)
#define SCSI_START_STP 0x1B // Start/Stop Unit (O)
#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O)
#define SCSI_VERIFY 0x2F // Verify (O)
#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY)
#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY)
#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O)
#define SCSI_WRITE_LONG 0x3F // Write Long (O)
#define SCSI_WRITE_SAME 0x41 // Write Same (O)
//***************************************************************************
// %%% Commands Unique to Sequential Access Devices %%%
//***************************************************************************
#define SCSI_ERASE 0x19 // Erase (MANDATORY)
#define SCSI_LOAD_UN 0x1B // Load/Unload (O)
#define SCSI_LOCATE 0x2B // Locate (O)
#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY)
#define SCSI_READ_POS 0x34 // Read Position (O)
#define SCSI_READ_REV 0x0F // Read Reverse (O)
#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O)
#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY)
#define SCSI_REWIND 0x01 // Rewind (MANDATORY)
#define SCSI_SPACE 0x11 // Space (MANDATORY)
#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O)
#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY)
//***************************************************************************
// %%% Commands Unique to Printer Devices %%%
//***************************************************************************
#define SCSI_PRINT 0x0A // Print (MANDATORY)
#define SCSI_SLEW_PNT 0x0B // Slew and Print (O)
#define SCSI_STOP_PNT 0x1B // Stop Print (O)
#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O)
//***************************************************************************
// %%% Commands Unique to Processor Devices %%%
//***************************************************************************
#define SCSI_RECEIVE 0x08 // Receive (O)
#define SCSI_SEND 0x0A // Send (O)
//***************************************************************************
// %%% Commands Unique to Write-Once Devices %%%
//***************************************************************************
#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O)
#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O)
#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O)
#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O)
#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O)
#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O)
#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O)
#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O)
#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O)
#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O)
#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O)
#define SCSI_WRITE12 0xAA // Write 12-Byte (O)
#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O)
#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O)
//***************************************************************************
// %%% Commands Unique to CD-ROM Devices %%%
//***************************************************************************
#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O)
#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O)
#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O)
#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O)
#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O)
#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O)
#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY)
#define SCSI_READHEADER 0x44 // Read Header (O)
#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O)
#define SCSI_READ_TOC 0x43 // Read TOC (O)
//***************************************************************************
// %%% Commands Unique to Scanner Devices %%%
//***************************************************************************
#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O)
#define SCSI_GETWINDOW 0x25 // Get Window (O)
#define SCSI_OBJECTPOS 0x31 // Object Postion (O)
#define SCSI_SCAN 0x1B // Scan (O)
#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY)
//***************************************************************************
// %%% Commands Unique to Optical Memory Devices %%%
//***************************************************************************
#define SCSI_UpdateBlk 0x3D // Update Block (O)
//***************************************************************************
// %%% Commands Unique to Medium Changer Devices %%%
//***************************************************************************
#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O)
#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O)
#define SCSI_POSTOELEM 0x2B // Position to Element (O)
#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O)
#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O)
//***************************************************************************
// %%% Commands Unique to Communication Devices %%%
//***************************************************************************
#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY)
#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O)
#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O)
#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY)
#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O)
#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O)
//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//
// %%% END OF SCSI COMMAND OPCODES %%%
//
///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
//***************************************************************************
// %%% Request Sense Data Format %%%
//***************************************************************************
typedef struct {
BYTE ErrorCode; // Error Code (70H or 71H)
BYTE SegmentNum; // Number of current segment descriptor
BYTE SenseKey; // Sense Key(See bit definitions too)
BYTE InfoByte0; // Information MSB
BYTE InfoByte1; // Information MID
BYTE InfoByte2; // Information MID
BYTE InfoByte3; // Information LSB
BYTE AddSenLen; // Additional Sense Length
BYTE ComSpecInf0; // Command Specific Information MSB
BYTE ComSpecInf1; // Command Specific Information MID
BYTE ComSpecInf2; // Command Specific Information MID
BYTE ComSpecInf3; // Command Specific Information LSB
BYTE AddSenseCode; // Additional Sense Code
BYTE AddSenQual; // Additional Sense Code Qualifier
BYTE FieldRepUCode; // Field Replaceable Unit Code
BYTE SenKeySpec15; // Sense Key Specific 15th byte
BYTE SenKeySpec16; // Sense Key Specific 16th byte
BYTE SenKeySpec17; // Sense Key Specific 17th byte
BYTE AddSenseBytes; // Additional Sense Bytes
} SENSE_DATA_FMT;
//***************************************************************************
// %%% REQUEST SENSE ERROR CODE %%%
//***************************************************************************
#define SERROR_CURRENT 0x70 // Current Errors
#define SERROR_DEFERED 0x71 // Deferred Errors
//***************************************************************************
// %%% REQUEST SENSE BIT DEFINITIONS %%%
//***************************************************************************
#define SENSE_VALID 0x80 // Byte 0 Bit 7
#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7
#define SENSE_EOM 0x40 // Byte 2 Bit 6
#define SENSE_ILI 0x20 // Byte 2 Bit 5
//***************************************************************************
// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%%
//***************************************************************************
#define KEY_NOSENSE 0x00 // No Sense
#define KEY_RECERROR 0x01 // Recovered Error
#define KEY_NOTREADY 0x02 // Not Ready
#define KEY_MEDIUMERR 0x03 // Medium Error
#define KEY_HARDERROR 0x04 // Hardware Error
#define KEY_ILLGLREQ 0x05 // Illegal Request
#define KEY_UNITATT 0x06 // Unit Attention
#define KEY_DATAPROT 0x07 // Data Protect
#define KEY_BLANKCHK 0x08 // Blank Check
#define KEY_VENDSPEC 0x09 // Vendor Specific
#define KEY_COPYABORT 0x0A // Copy Abort
#define KEY_EQUAL 0x0C // Equal (Search)
#define KEY_VOLOVRFLW 0x0D // Volume Overflow
#define KEY_MISCOMP 0x0E // Miscompare (Search)
#define KEY_RESERVED 0x0F // Reserved
//***************************************************************************
// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%%
//***************************************************************************
#define DTYPE_DASD 0x00 // Disk Device
#define DTYPE_SEQD 0x01 // Tape Device
#define DTYPE_PRNT 0x02 // Printer
#define DTYPE_PROC 0x03 // Processor
#define DTYPE_WORM 0x04 // Write-once read-multiple
#define DTYPE_CROM 0x05 // CD-ROM device
#define DTYPE_CDROM 0x05 // CD-ROM device
#define DTYPE_SCAN 0x06 // Scanner device
#define DTYPE_OPTI 0x07 // Optical memory device
#define DTYPE_JUKE 0x08 // Medium Changer device
#define DTYPE_COMM 0x09 // Communications device
#define DTYPE_RESL 0x0A // Reserved (low)
#define DTYPE_RESH 0x1E // Reserved (high)
#define DTYPE_UNKNOWN 0x1F // Unknown or no device type
//***************************************************************************
// %%% ANSI APPROVED VERSION DEFINITIONS %%%
//***************************************************************************
#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand
#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1)
#define ANSI_SCSI2 0x2 // Device complies to SCSI-2
#define ANSI_RESLO 0x3 // Reserved (low)
#define ANSI_RESHI 0x7 // Reserved (high)

142
bochs/iodev/scsipt.h Normal file
View File

@ -0,0 +1,142 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// iodev/scsipt.h
// This file was copied from ... ?
//
// distilled information from various header files from Microsoft's
// DDK for Windows NT 4.0
//
#ifndef _SCSIPT_H_INC
#define _SCSIPT_H_INC
#include <windows.h>
typedef struct {
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
ULONG DataBufferOffset;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
typedef struct {
USHORT Length;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR CdbLength;
UCHAR SenseInfoLength;
UCHAR DataIn;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
ULONG SenseInfoOffset;
UCHAR Cdb[16];
} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
typedef struct {
SCSI_PASS_THROUGH spt;
ULONG Filler;
UCHAR ucSenseBuf[32];
UCHAR ucDataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
typedef struct {
SCSI_PASS_THROUGH_DIRECT spt;
ULONG Filler;
UCHAR ucSenseBuf[32];
} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
typedef struct {
UCHAR NumberOfLogicalUnits;
UCHAR InitiatorBusId;
ULONG InquiryDataOffset;
} SCSI_BUS_DATA, *PSCSI_BUS_DATA;
typedef struct {
UCHAR NumberOfBusses;
SCSI_BUS_DATA BusData[1];
} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;
typedef struct {
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
BOOLEAN DeviceClaimed;
ULONG InquiryDataLength;
ULONG NextInquiryDataOffset;
UCHAR InquiryData[1];
} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;
typedef struct {
ULONG Length;
UCHAR PortNumber;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
} SCSI_ADDRESS, *PSCSI_ADDRESS;
/*
* method codes
*/
#define METHOD_BUFFERED 0
#define METHOD_IN_DIRECT 1
#define METHOD_OUT_DIRECT 2
#define METHOD_NEITHER 3
/*
* file access values
*/
#define FILE_ANY_ACCESS 0
#define FILE_READ_ACCESS (0x0001)
#define FILE_WRITE_ACCESS (0x0002)
#define IOCTL_SCSI_BASE 0x00000004
/*
* constants for DataIn member of SCSI_PASS_THROUGH* structures
*/
#define SCSI_IOCTL_DATA_OUT 0
#define SCSI_IOCTL_DATA_IN 1
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
/*
* Standard IOCTL define
*/
#define CTL_CODE(DevType, Function, Method, Access) ( \
((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )
#endif

1627
bochs/iodev/serial.cc Normal file

File diff suppressed because it is too large Load Diff

249
bochs/iodev/serial.h Normal file
View File

@ -0,0 +1,249 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_SERIAL_H
#define BX_IODEV_SERIAL_H
// Peter Grehan (grehan@iprg.nokia.com) coded most of this
// serial emulation.
#if BX_USE_SER_SMF
# define BX_SER_SMF static
# define BX_SER_THIS theSerialDevice->
#else
# define BX_SER_SMF
# define BX_SER_THIS this->
#endif
#if defined(WIN32)
#define SERIAL_ENABLE
#endif
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || defined(__APPLE__) || defined(__sun__)
#define SERIAL_ENABLE
extern "C" {
#include <termios.h>
};
#endif
#define BX_SERIAL_MAXDEV 4
#define BX_PC_CLOCK_XTL 1843200.0
#define BX_SER_RXIDLE 0
#define BX_SER_RXPOLL 1
#define BX_SER_RXWAIT 2
#define BX_SER_THR 0
#define BX_SER_RBR 0
#define BX_SER_IER 1
#define BX_SER_IIR 2
#define BX_SER_FCR 2
#define BX_SER_LCR 3
#define BX_SER_MCR 4
#define BX_SER_LSR 5
#define BX_SER_MSR 6
#define BX_SER_SCR 7
#define BX_SER_MODE_NULL 0
#define BX_SER_MODE_FILE 1
#define BX_SER_MODE_TERM 2
#define BX_SER_MODE_RAW 3
#define BX_SER_MODE_MOUSE 4
#define BX_SER_MODE_SOCKET 5
#define BX_SER_MODE_PIPE 6
enum {
BX_SER_INT_IER,
BX_SER_INT_RXDATA,
BX_SER_INT_TXHOLD,
BX_SER_INT_RXLSTAT,
BX_SER_INT_MODSTAT,
BX_SER_INT_FIFO
};
#if USE_RAW_SERIAL
class serial_raw;
#endif
typedef struct {
/*
* UART internal state
*/
bx_bool ls_interrupt;
bx_bool ms_interrupt;
bx_bool rx_interrupt;
bx_bool tx_interrupt;
bx_bool fifo_interrupt;
bx_bool ls_ipending;
bx_bool ms_ipending;
bx_bool rx_ipending;
bx_bool fifo_ipending;
Bit8u IRQ;
Bit8u rx_fifo_end;
Bit8u tx_fifo_end;
int baudrate;
int tx_timer_index;
int rx_pollstate;
int rx_timer_index;
int fifo_timer_index;
int io_mode;
int tty_id;
SOCKET socket_id;
FILE *output;
#ifdef WIN32
HANDLE pipe;
#endif
#if USE_RAW_SERIAL
serial_raw* raw;
#endif
#if defined(SERIAL_ENABLE) && !defined(WIN32)
struct termios term_orig, term_new;
#endif
/*
* Register definitions
*/
Bit8u rxbuffer; /* receiver buffer register (r/o) */
Bit8u thrbuffer; /* transmit holding register (w/o) */
/* Interrupt Enable Register */
struct {
bx_bool rxdata_enable; /* 1=enable receive data interrupts */
bx_bool txhold_enable; /* 1=enable tx. holding reg. empty ints */
bx_bool rxlstat_enable; /* 1=enable rx line status interrupts */
bx_bool modstat_enable; /* 1=enable modem status interrupts */
} int_enable;
/* Interrupt Identification Register (r/o) */
struct {
bx_bool ipending; /* 0=interrupt pending */
Bit8u int_ID; /* 3-bit interrupt ID */
} int_ident;
/* FIFO Control Register (w/o) */
struct {
bx_bool enable; /* 1=enable tx and rx FIFOs */
Bit8u rxtrigger; /* 2-bit code for rx fifo trigger level */
} fifo_cntl;
/* Line Control Register (r/w) */
struct {
Bit8u wordlen_sel; /* 2-bit code for char length */
bx_bool stopbits; /* select stop bit len */
bx_bool parity_enable; /* ... */
bx_bool evenparity_sel; /* ... */
bx_bool stick_parity; /* ... */
bx_bool break_cntl; /* 1=send break signal */
bx_bool dlab; /* divisor latch access bit */
} line_cntl;
/* MODEM Control Register (r/w) */
struct {
bx_bool dtr; /* DTR output value */
bx_bool rts; /* RTS output value */
bx_bool out1; /* OUTPUT1 value */
bx_bool out2; /* OUTPUT2 value */
bx_bool local_loopback; /* 1=loopback mode */
} modem_cntl;
/* Line Status Register (r/w) */
struct {
bx_bool rxdata_ready; /* 1=receiver data ready */
bx_bool overrun_error; /* 1=receive overrun detected */
bx_bool parity_error; /* 1=rx char has a bad parity bit */
bx_bool framing_error; /* 1=no stop bit detected for rx char */
bx_bool break_int; /* 1=break signal detected */
bx_bool thr_empty; /* 1=tx hold register (or fifo) is empty */
bx_bool tsr_empty; /* 1=shift reg and hold reg empty */
bx_bool fifo_error; /* 1=at least 1 err condition in fifo */
} line_status;
/* Modem Status Register (r/w) */
struct {
bx_bool delta_cts; /* 1=CTS changed since last read */
bx_bool delta_dsr; /* 1=DSR changed since last read */
bx_bool ri_trailedge; /* 1=RI moved from low->high */
bx_bool delta_dcd; /* 1=CD changed since last read */
bx_bool cts; /* CTS input value */
bx_bool dsr; /* DSR input value */
bx_bool ri; /* RI input value */
bx_bool dcd; /* DCD input value */
} modem_status;
Bit8u scratch; /* Scratch Register (r/w) */
Bit8u tsrbuffer; /* transmit shift register (internal) */
Bit8u rx_fifo[16]; /* receive FIFO (internal) */
Bit8u tx_fifo[16]; /* transmit FIFO (internal) */
Bit8u divisor_lsb; /* Divisor latch, least-sig. byte */
Bit8u divisor_msb; /* Divisor latch, most-sig. byte */
} bx_serial_t;
class bx_serial_c : public bx_devmodel_c {
public:
bx_serial_c();
virtual ~bx_serial_c();
virtual void init(void);
virtual void reset(unsigned type);
virtual void register_state(void);
private:
bx_serial_t s[BX_SERIAL_MAXDEV];
int detect_mouse;
int mouse_port;
int mouse_type;
int mouse_delayed_dx;
int mouse_delayed_dy;
int mouse_delayed_dz;
struct {
int num_elements;
Bit8u buffer[BX_MOUSE_BUFF_SIZE];
int head;
} mouse_internal_buffer;
static void lower_interrupt(Bit8u port);
static void raise_interrupt(Bit8u port, int type);
static void rx_fifo_enq(Bit8u port, Bit8u data);
static void tx_timer_handler(void *);
BX_SER_SMF void tx_timer(void);
static void rx_timer_handler(void *);
BX_SER_SMF void rx_timer(void);
static void fifo_timer_handler(void *);
BX_SER_SMF void fifo_timer(void);
static void mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state);
void mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state);
static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
#if !BX_USE_SER_SMF
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
};
#endif

477
bochs/iodev/serial_raw.cc Normal file
View File

@ -0,0 +1,477 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if USE_RAW_SERIAL
#include "serial_raw.h"
#define LOG_THIS
#ifdef WIN32_RECEIVE_RAW
DWORD WINAPI RawSerialThread(VOID *this_ptr);
#endif
serial_raw::serial_raw(const char *devname)
{
#ifdef WIN32
char portstr[MAX_PATH];
#ifdef WIN32_RECEIVE_RAW
DWORD threadID;
#endif
#endif
put ("SERR");
#ifdef WIN32
memset(&dcb, 0, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
dcb.fBinary = 1;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.Parity = NOPARITY;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = CBR_115200;
DCBchanged = FALSE;
if (lstrlen(devname) > 0) {
wsprintf(portstr, "\\\\.\\%s", devname);
hCOM = CreateFile(portstr, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hCOM != INVALID_HANDLE_VALUE) {
present = 1;
GetCommModemStatus(hCOM, &MSR_value);
SetupComm(hCOM, 8192, 2048);
PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR);
#ifdef WIN32_RECEIVE_RAW
SetCommMask(hCOM, EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR);
memset(&rx_ovl, 0, sizeof(OVERLAPPED));
rx_ovl.hEvent = CreateEvent(NULL,TRUE,FALSE,"receive");
hRawSerialThread = CreateThread(NULL, 0, RawSerialThread, this, 0, &threadID);
#endif
} else {
present = 0;
BX_ERROR(("Raw device '%s' not present", devname));
}
} else {
present = 0;
}
#else
present = 0;
#endif
set_modem_control(0x00);
set_break(0);
rxdata_count = 0;
}
serial_raw::~serial_raw(void)
{
if (present) {
#ifdef WIN32
#ifdef WIN32_RECEIVE_RAW
thread_quit = TRUE;
SetCommMask(hCOM, 0);
while (thread_active) Sleep(10);
CloseHandle(thread_ovl.hEvent);
CloseHandle(rx_ovl.hEvent);
CloseHandle(hRawSerialThread);
#endif
CloseHandle(hCOM);
#endif
}
}
void serial_raw::set_baudrate(int rate)
{
BX_DEBUG (("set_baudrate %d", rate));
#ifdef WIN32
switch (rate) {
case 110: dcb.BaudRate = CBR_110; break;
case 300: dcb.BaudRate = CBR_300; break;
case 600: dcb.BaudRate = CBR_600; break;
case 1200: dcb.BaudRate = CBR_1200; break;
case 2400: dcb.BaudRate = CBR_2400; break;
case 4800: dcb.BaudRate = CBR_4800; break;
case 9600: dcb.BaudRate = CBR_9600; break;
case 19200: dcb.BaudRate = CBR_19200; break;
case 38400: dcb.BaudRate = CBR_38400; break;
case 57600: dcb.BaudRate = CBR_57600; break;
case 115200: dcb.BaudRate = CBR_115200; break;
default: BX_ERROR(("set_baudrate(): unsupported value %d", rate));
}
DCBchanged = TRUE;
#endif
}
void serial_raw::set_data_bits(int val)
{
BX_DEBUG (("set data bits (%d)", val));
#ifdef WIN32
dcb.ByteSize = val;
DCBchanged = TRUE;
#endif
}
void serial_raw::set_stop_bits(int val)
{
BX_DEBUG (("set stop bits (%d)", val));
#ifdef WIN32
if (val == 1) {
dcb.StopBits = ONESTOPBIT;
} if (dcb.ByteSize == 5) {
dcb.StopBits = ONE5STOPBITS;
} else {
dcb.StopBits = TWOSTOPBITS;
}
DCBchanged = TRUE;
#endif
}
void serial_raw::set_parity_mode(int mode)
{
BX_DEBUG (("set parity mode %d", mode));
#ifdef WIN32
switch (mode) {
case 0:
dcb.fParity = FALSE;
dcb.Parity = NOPARITY;
break;
case 1:
dcb.fParity = TRUE;
dcb.Parity = ODDPARITY;
break;
case 2:
dcb.fParity = TRUE;
dcb.Parity = EVENPARITY;
break;
case 3:
dcb.fParity = TRUE;
dcb.Parity = MARKPARITY;
break;
case 4:
dcb.fParity = TRUE;
dcb.Parity = SPACEPARITY;
break;
}
DCBchanged = TRUE;
#endif
}
void serial_raw::set_break(int mode)
{
BX_DEBUG (("set break %s", mode?"on":"off"));
#ifdef WIN32
if (mode) {
SetCommBreak(hCOM);
} else {
ClearCommBreak(hCOM);
}
#endif
}
void serial_raw::set_modem_control(int ctrl)
{
BX_DEBUG (("set modem control 0x%02x", ctrl));
#ifdef WIN32
EscapeCommFunction(hCOM, (ctrl & 0x01)?SETDTR:CLRDTR);
EscapeCommFunction(hCOM, (ctrl & 0x02)?SETRTS:CLRRTS);
#endif
}
int serial_raw::get_modem_status()
{
int status = 0;
#ifdef WIN32
status = MSR_value;
#endif
BX_DEBUG (("get modem status returns 0x%02x", status));
return status;
}
void serial_raw::setup_port()
{
#ifdef WIN32
DWORD DErr;
COMMTIMEOUTS ctmo;
ClearCommError(hCOM, &DErr, NULL);
PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR);
memset(&ctmo, 0, sizeof(ctmo));
SetCommTimeouts(hCOM, &ctmo);
SetCommState(hCOM, &dcb);
rxdata_count = 0;
#ifdef WIN32_RECEIVE_RAW
thread_rxdata_count = 0;
#endif
#endif
}
void serial_raw::transmit(Bit8u byte)
{
#ifdef WIN32
DWORD DErr, Len2;
OVERLAPPED tx_ovl;
#endif
BX_DEBUG (("transmit %d", byte));
if (present) {
#ifdef WIN32
if (DCBchanged) {
setup_port();
} else {
ClearCommError(hCOM, &DErr, NULL);
}
memset(&tx_ovl, 0, sizeof(OVERLAPPED));
tx_ovl.hEvent = CreateEvent(NULL,TRUE,TRUE,"transmit");
if (!WriteFile(hCOM, &byte, 1, &Len2, &tx_ovl)) {
if (GetLastError() == ERROR_IO_PENDING) {
if (WaitForSingleObject(tx_ovl.hEvent, 100) == WAIT_OBJECT_0) {
GetOverlappedResult(hCOM, &tx_ovl, &Len2, FALSE);
}
}
}
if (Len2 != 1) BX_ERROR(("transmit failed: len = %d", Len2));
ClearCommError(hCOM, &DErr, NULL);
CloseHandle(tx_ovl.hEvent);
#endif
}
}
bx_bool serial_raw::ready_transmit()
{
BX_DEBUG (("ready_transmit returning %d", present));
return present;
}
bx_bool serial_raw::ready_receive()
{
#ifdef WIN32_RECEIVE_RAW
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
SetEvent(thread_ovl.hEvent);
SetEvent(rx_ovl.hEvent);
}
#endif
BX_DEBUG (("ready_receive returning %d", (rxdata_count > 0)));
return (rxdata_count > 0);
}
int serial_raw::receive()
{
#ifdef WIN32
int data;
#endif
if (present) {
#ifdef WIN32
if (DCBchanged) {
setup_port();
}
data = rxdata_buffer[0];
if (rxdata_count > 0) {
memcpy(&rxdata_buffer[0], &rxdata_buffer[1], sizeof(Bit16s)*(RX_BUFSIZE-1));
rxdata_count--;
}
if (data < 0) {
switch (data) {
case RAW_EVENT_CTS_ON:
MSR_value |= 0x10;
break;
case RAW_EVENT_CTS_OFF:
MSR_value &= ~0x10;
break;
case RAW_EVENT_DSR_ON:
MSR_value |= 0x20;
break;
case RAW_EVENT_DSR_OFF:
MSR_value &= ~0x20;
break;
case RAW_EVENT_RING_ON:
MSR_value |= 0x40;
break;
case RAW_EVENT_RING_OFF:
MSR_value &= ~0x40;
break;
case RAW_EVENT_RLSD_ON:
MSR_value |= 0x80;
break;
case RAW_EVENT_RLSD_OFF:
MSR_value &= ~0x80;
break;
}
}
return data;
#else
BX_DEBUG (("receive returning 'A'"));
return (int)'A';
#endif
} else {
BX_DEBUG (("receive returning 'A'"));
return (int)'A';
}
}
#ifdef WIN32_RECEIVE_RAW
DWORD WINAPI RawSerialThread(VOID *this_ptr)
{
serial_raw *class_ptr = (serial_raw *) this_ptr;
class_ptr->serial_thread();
return 0;
}
void serial_raw::serial_thread()
{
DWORD DErr, Len2;
DWORD EvtMask, MSR, Temp;
char s1[2];
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
thread_active = TRUE;
thread_quit = FALSE;
memset(&thread_ovl, 0, sizeof(OVERLAPPED));
thread_ovl.hEvent = CreateEvent(NULL,TRUE,TRUE,"thread");
thread_rxdata_count = 0;
while (!thread_quit) {
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
if (thread_rxdata_count > RX_BUFSIZE) {
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE);
memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE));
rxdata_count = RX_BUFSIZE;
thread_rxdata_count -= RX_BUFSIZE;
} else {
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count);
rxdata_count = thread_rxdata_count;
thread_rxdata_count = 0;
}
}
ClearCommError(hCOM, &DErr, NULL);
EvtMask = 0;
if (!WaitCommEvent(hCOM, &EvtMask, &thread_ovl)) {
if (GetLastError() == ERROR_IO_PENDING) {
if (WaitForSingleObject(thread_ovl.hEvent, INFINITE) == WAIT_OBJECT_0) {
GetOverlappedResult(hCOM, &thread_ovl, &Temp, FALSE);
}
}
}
if (EvtMask & EV_RXCHAR) {
if (thread_rxdata_count < THREAD_RX_BUFSIZE) {
do {
ClearCommError(hCOM, &DErr, NULL);
if (!ReadFile(hCOM, s1, 1, &Len2, &rx_ovl)) {
if (GetLastError() == ERROR_IO_PENDING) {
if (WaitForSingleObject(rx_ovl.hEvent, INFINITE) != WAIT_OBJECT_0) {
Len2 = 0;
} else {
GetOverlappedResult(hCOM, &rx_ovl, &Len2, FALSE);
}
} else {
Len2 = 0;
}
}
if (Len2 > 0) {
enq_event(s1[0]);
}
if ((rxdata_count == 0) && (thread_rxdata_count > 0)) {
if (thread_rxdata_count > RX_BUFSIZE) {
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE);
memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE));
rxdata_count = RX_BUFSIZE;
thread_rxdata_count -= RX_BUFSIZE;
} else {
memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count);
rxdata_count = thread_rxdata_count;
thread_rxdata_count = 0;
}
}
} while ((Len2 != 0) && (thread_rxdata_count < THREAD_RX_BUFSIZE));
ClearCommError(hCOM, &DErr, NULL);
}
}
if (EvtMask & EV_BREAK) {
enq_event(RAW_EVENT_BREAK);
}
if (EvtMask & EV_ERR) {
ClearCommError(hCOM, &DErr, NULL);
if (DErr & CE_FRAME) {
enq_event(RAW_EVENT_FRAME);
}
if (DErr & CE_OVERRUN) {
enq_event(RAW_EVENT_OVERRUN);
}
if (DErr & CE_RXPARITY) {
enq_event(RAW_EVENT_PARITY);
}
}
if (EvtMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
GetCommModemStatus(hCOM, &MSR);
}
if (EvtMask & EV_CTS) {
if (MSR & MS_CTS_ON) {
enq_event(RAW_EVENT_CTS_ON);
} else {
enq_event(RAW_EVENT_CTS_OFF);
}
}
if (EvtMask & EV_DSR) {
if (MSR & MS_DSR_ON) {
enq_event(RAW_EVENT_DSR_ON);
} else {
enq_event(RAW_EVENT_DSR_OFF);
}
}
if (EvtMask & EV_RING) {
if (MSR & MS_RING_ON) {
enq_event(RAW_EVENT_RING_ON);
} else {
enq_event(RAW_EVENT_RING_OFF);
}
}
if (EvtMask & EV_RLSD) {
if (MSR & MS_RLSD_ON) {
enq_event(RAW_EVENT_RLSD_ON);
} else {
enq_event(RAW_EVENT_RLSD_OFF);
}
}
}
CloseHandle(thread_ovl.hEvent);
thread_active = FALSE;
}
void serial_raw::enq_event(Bit16s event)
{
if (thread_rxdata_count < THREAD_RX_BUFSIZE) {
thread_rxdata_buffer[thread_rxdata_count++] = event;
} else {
fprintf(stderr, "receive buffer overflow\n");
}
}
#endif
#endif

97
bochs/iodev/serial_raw.h Normal file
View File

@ -0,0 +1,97 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#if USE_RAW_SERIAL
#ifdef __linux__
#include <linux/serial.h>
#endif
#ifdef WIN32
// experimental raw serial receive support on win32
//#define WIN32_RECEIVE_RAW
#endif
#define P_NONE 0
#define P_ODD 1
#define P_EVEN 2
#define P_HIGH 3
#define P_LOW 4
#define RAW_EVENT_BREAK -1
#define RAW_EVENT_CTS_ON -2
#define RAW_EVENT_CTS_OFF -3
#define RAW_EVENT_DSR_ON -4
#define RAW_EVENT_DSR_OFF -5
#define RAW_EVENT_RING_ON -6
#define RAW_EVENT_RING_OFF -7
#define RAW_EVENT_RLSD_ON -8
#define RAW_EVENT_RLSD_OFF -9
#define RAW_EVENT_FRAME -10
#define RAW_EVENT_OVERRUN -11
#define RAW_EVENT_PARITY -12
#define THREAD_RX_BUFSIZE 8192
#define RX_BUFSIZE 256
class serial_raw : public logfunctions {
public:
serial_raw(const char *devname);
virtual ~serial_raw();
void set_baudrate(int rate);
void set_data_bits(int);
void set_stop_bits(int);
void set_parity_mode(int mode);
void set_break(int mode);
void set_modem_control(int ctrl);
int get_modem_status();
void transmit(Bit8u byte);
bx_bool ready_transmit();
bx_bool ready_receive();
int receive ();
#ifdef WIN32_RECEIVE_RAW
void serial_thread();
#endif
private:
void setup_port();
#ifdef WIN32_RECEIVE_RAW
void enq_event(Bit16s event);
#endif
bx_bool present;
unsigned rxdata_count;
#ifdef WIN32
HANDLE hCOM;
DCB dcb;
BOOL DCBchanged;
DWORD MSR_value;
Bit16s rxdata_buffer[RX_BUFSIZE];
#ifdef WIN32_RECEIVE_RAW
HANDLE hRawSerialThread;
BOOL thread_active;
BOOL thread_quit;
OVERLAPPED rx_ovl;
OVERLAPPED thread_ovl;
unsigned thread_rxdata_count;
Bit16s thread_rxdata_buffer[THREAD_RX_BUFSIZE];
#endif
#endif
};
#endif

View File

@ -0,0 +1,179 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#include "bochs.h"
#include "param_names.h"
#include "slowdown_timer.h"
#include <errno.h>
#if !defined(_MSC_VER)
#include <unistd.h>
#endif
//These need to stay printfs because they are useless in the log file.
#define BX_SLOWDOWN_PRINTF_FEEDBACK 0
#define SECINUSEC 1000000
#define usectosec(a) ((a)/SECINUSEC)
#define sectousec(a) ((a)*SECINUSEC)
#define nsectousec(a) ((a)/1000)
#define MSECINUSEC 1000
#define usectomsec(a) ((a)/MSECINUSEC)
#define Qval 1000
#define MAXMULT 1.5
#define REALTIME_Q SECINUSEC
#define LOG_THIS bx_slowdown_timer.
bx_slowdown_timer_c bx_slowdown_timer;
bx_slowdown_timer_c::bx_slowdown_timer_c()
{
put("STIME");
s.start_time=0;
s.start_emulated_time=0;
s.timer_handle=BX_NULL_TIMER_HANDLE;
}
void bx_slowdown_timer_c::init(void)
{
// Return early if slowdown timer not selected
if ((SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_SLOWDOWN) &&
(SIM->get_param_enum(BXPN_CLOCK_SYNC)->get() != BX_CLOCK_SYNC_BOTH))
return;
BX_INFO(("using 'slowdown' timer synchronization method"));
s.MAXmultiplier=MAXMULT;
s.Q=Qval;
if(s.MAXmultiplier<1)
s.MAXmultiplier=1;
s.start_time=sectousec(time(NULL));
s.start_emulated_time = bx_pc_system.time_usec();
s.lasttime=0;
if (s.timer_handle == BX_NULL_TIMER_HANDLE) {
s.timer_handle=bx_pc_system.register_timer(this, timer_handler, 100 , 1, 1,
"slowdown_timer");
}
bx_pc_system.deactivate_timer(s.timer_handle);
bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
}
void bx_slowdown_timer_c::exit(void)
{
s.timer_handle = BX_NULL_TIMER_HANDLE;
}
void bx_slowdown_timer_c::after_restore_state(void)
{
s.start_emulated_time = bx_pc_system.time_usec();
}
void bx_slowdown_timer_c::timer_handler(void * this_ptr)
{
bx_slowdown_timer_c * class_ptr = (bx_slowdown_timer_c *) this_ptr;
class_ptr->handle_timer();
}
void bx_slowdown_timer_c::handle_timer()
{
Bit64u total_emu_time = (bx_pc_system.time_usec()) - s.start_emulated_time;
Bit64u wanttime = s.lasttime+s.Q;
Bit64u totaltime = sectousec(time(NULL)) - s.start_time;
Bit64u thistime=(wanttime>totaltime)?wanttime:totaltime;
#if BX_SLOWDOWN_PRINTF_FEEDBACK
printf("Entering slowdown timer handler.\n");
#endif
/* Decide if we're behind.
* Set interrupt interval accordingly. */
if(totaltime > total_emu_time) {
bx_pc_system.deactivate_timer(s.timer_handle);
bx_pc_system.activate_timer(s.timer_handle,
(Bit32u)(s.MAXmultiplier * (float)((Bit64s)s.Q)), 0);
#if BX_SLOWDOWN_PRINTF_FEEDBACK
printf("running at MAX speed\n");
#endif
} else {
bx_pc_system.deactivate_timer(s.timer_handle);
bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
#if BX_SLOWDOWN_PRINTF_FEEDBACK
printf("running at NORMAL speed\n");
#endif
}
/* Make sure we took at least one time quantum. */
/* This is a little strange. I'll try to explain.
* We're running bochs one second ahead of real time.
* this gives us a very precise division on whether
* we're ahead or behind the second line.
* Basically, here's how it works:
* *****|******************|***********...
* Time Time+1sec
* <^Bochs doesn't delay.
* ^>Bochs delays.
* <^Bochs runs at MAX speed.
* ^>Bochs runs at normal
*/
if(wanttime > (totaltime+REALTIME_Q)) {
#if BX_HAVE_USLEEP
usleep(s.Q);
#elif BX_HAVE_MSLEEP
msleep(usectomsec((Bit32u)s.Q));
#elif BX_HAVE_SLEEP
sleep(usectosec(s.Q));
#else
#error do not know have to sleep
#endif //delay(wanttime-totaltime);
/* alternatively: delay(Q);
* This works okay because we share the delay between
* two time quantums.
*/
#if BX_SLOWDOWN_PRINTF_FEEDBACK
printf("DELAYING for a quantum\n");
#endif
}
s.lasttime=thistime;
//Diagnostic info:
#if 0
if(wanttime > (totaltime+REALTIME_Q)) {
if(totaltime > total_emu_time) {
printf("Solving OpenBSD problem.\n");
} else {
printf("too fast.\n");
}
} else {
if(totaltime > total_emu_time) {
printf("too slow.\n");
} else {
printf("sometimes invalid state, normally okay.\n");
}
}
#endif // Diagnostic info
}

View File

@ -0,0 +1,53 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002-2009 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef BX_IODEV_SLOWDOWN_TIMER_H
#define BX_IODEV_SLOWDOWN_TIMER_H
class bx_slowdown_timer_c : public logfunctions {
private:
struct {
Bit64u start_time;
Bit64u start_emulated_time;
Bit64u lasttime;
int timer_handle;
float MAXmultiplier;
Bit64u Q; // sleep rate in usec
} s;
public:
bx_slowdown_timer_c();
void init(void);
void exit(void);
void after_restore_state(void);
static void timer_handler(void * this_ptr);
void handle_timer();
};
extern bx_slowdown_timer_c bx_slowdown_timer;
#endif

530
bochs/iodev/soundlnx.cc Normal file
View File

@ -0,0 +1,530 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// Josef Drexler coded the original version of the lowlevel sound support
// for Linux using OSS. The current version also supports OSS on FreeBSD and
// ALSA PCM output on Linux.
#include "iodev.h"
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && BX_SUPPORT_SB16
#define LOG_THIS device->
#include "soundmod.h"
#include "soundlnx.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
bx_sound_linux_c::bx_sound_linux_c(logfunctions *dev)
:bx_sound_output_c(dev)
{
#if BX_HAVE_ALSASOUND
alsa_seq.handle = NULL;
alsa_pcm.handle = NULL;
alsa_buffer = NULL;
#endif
midi = NULL;
wavedevice = NULL;
wave = -1;
BX_INFO(("Sound output module 'linux' initialized"));
}
bx_sound_linux_c::~bx_sound_linux_c()
{
// nothing for now
}
int bx_sound_linux_c::waveready()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_linux_c::midiready()
{
return BX_SOUND_OUTPUT_OK;
}
#if BX_HAVE_ALSASOUND
int bx_sound_linux_c::alsa_seq_open(const char *alsadev)
{
char *mididev, *ptr;
int client, port, ret = 0;
int length = strlen(alsadev) + 1;
mididev = new char[length];
if (mididev == NULL)
return BX_SOUND_OUTPUT_ERR;
strcpy(mididev, alsadev);
ptr = strtok(mididev, ":");
if (ptr == NULL) {
BX_ERROR(("ALSA sequencer setup: missing client parameters"));
return BX_SOUND_OUTPUT_ERR;
}
client = atoi(ptr);
ptr = strtok(NULL, ":");
if (ptr == NULL) {
BX_ERROR(("ALSA sequencer setup: missing port parameter"));
return BX_SOUND_OUTPUT_ERR;
}
port = atoi(ptr);
delete(mididev);
if (snd_seq_open(&alsa_seq.handle, "default", SND_SEQ_OPEN_OUTPUT, 0) < 0) {
BX_ERROR(("Couldn't open ALSA sequencer for midi output"));
return BX_SOUND_OUTPUT_ERR;
}
ret = snd_seq_create_simple_port(alsa_seq.handle, NULL,
SND_SEQ_PORT_CAP_WRITE |
SND_SEQ_PORT_CAP_SUBS_WRITE |
SND_SEQ_PORT_CAP_READ,
SND_SEQ_PORT_TYPE_MIDI_GENERIC);
if (ret < 0) {
BX_ERROR(("ALSA sequencer: error creating port %s", snd_strerror(errno)));
} else {
alsa_seq.source_port = ret;
ret = snd_seq_connect_to(alsa_seq.handle, alsa_seq.source_port, client, port);
if (ret < 0) {
BX_ERROR(("ALSA sequencer: could not connect to port %d:%d", client, port));
}
}
if (ret < 0) {
snd_seq_close(alsa_seq.handle);
return BX_SOUND_OUTPUT_ERR;
} else {
return BX_SOUND_OUTPUT_OK;
}
}
#endif
int bx_sound_linux_c::openmidioutput(const char *mididev)
{
if ((mididev == NULL) || (strlen(mididev) < 1))
return BX_SOUND_OUTPUT_ERR;
#if BX_HAVE_ALSASOUND
use_alsa_seq = !strncmp(mididev, "alsa:", 5);
if (use_alsa_seq) {
return alsa_seq_open(mididev+5);
}
#endif
midi = fopen(mididev,"w");
if (midi == NULL) {
BX_ERROR(("Couldn't open midi output device %s: %s",
mididev, strerror(errno)));
return BX_SOUND_OUTPUT_ERR;
}
return BX_SOUND_OUTPUT_OK;
}
#if BX_HAVE_ALSASOUND
int bx_sound_linux_c::alsa_seq_output(int delta, int command, int length, Bit8u data[])
{
int cmd, chan, value;
snd_seq_event_t ev;
snd_seq_ev_clear(&ev);
snd_seq_ev_set_source(&ev, alsa_seq.source_port);
snd_seq_ev_set_subs(&ev);
snd_seq_ev_set_direct(&ev);
cmd = command & 0xf0;
chan = command & 0x0f;
switch (cmd) {
case 0x80:
ev.type = SND_SEQ_EVENT_NOTEOFF;
ev.data.note.channel = chan;
ev.data.note.note = data[0];
ev.data.note.velocity = data[1];
ev.data.note.duration = delta;
break;
case 0x90:
ev.type = SND_SEQ_EVENT_NOTEON;
ev.data.note.channel = chan;
ev.data.note.note = data[0];
ev.data.note.velocity = data[1];
ev.data.note.duration = 0;
break;
case 0xa0:
ev.type = SND_SEQ_EVENT_KEYPRESS;
ev.data.control.channel = chan;
ev.data.control.param = data[0];
ev.data.control.value = data[1];
break;
case 0xb0:
ev.type = SND_SEQ_EVENT_CONTROLLER;
ev.data.control.channel = chan;
ev.data.control.param = data[0];
ev.data.control.value = data[1];
break;
case 0xc0:
ev.type = SND_SEQ_EVENT_PGMCHANGE;
ev.data.control.channel = chan;
ev.data.control.value = data[0];
break;
case 0xd0:
ev.type = SND_SEQ_EVENT_CHANPRESS;
ev.data.control.channel = chan;
ev.data.control.value = data[0];
break;
case 0xe0:
ev.type = SND_SEQ_EVENT_PITCHBEND;
ev.data.control.channel = chan;
value = data[0] | (data[1] << 7);
value -= 0x2000;
ev.data.control.value = value;
break;
case 0xf0:
BX_ERROR(("alsa_seq_output(): SYSEX not implemented, length=%d", length));
return BX_SOUND_OUTPUT_ERR;
default:
BX_ERROR(("alsa_seq_output(): unknown command 0x%02x, length=%d", command, length));
return BX_SOUND_OUTPUT_ERR;
}
snd_seq_event_output(alsa_seq.handle, &ev);
snd_seq_drain_output(alsa_seq.handle);
return BX_SOUND_OUTPUT_OK;
}
#endif
int bx_sound_linux_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
{
#if BX_HAVE_ALSASOUND
if ((use_alsa_seq) && (alsa_seq.handle != NULL)) {
return alsa_seq_output(delta, command, length, data);
}
#endif
UNUSED(delta);
fputc(command, midi);
fwrite(data, 1, length, midi);
fflush(midi); // to start playing immediately
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_linux_c::closemidioutput()
{
#if BX_HAVE_ALSASOUND
if ((use_alsa_seq) && (alsa_seq.handle != NULL)) {
snd_seq_close(alsa_seq.handle);
return BX_SOUND_OUTPUT_OK;
}
#endif
fclose(midi);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_linux_c::openwaveoutput(const char *wavedev)
{
#if BX_HAVE_ALSASOUND
use_alsa_pcm = !strcmp(wavedev, "alsa");
if (use_alsa_pcm) {
return BX_SOUND_OUTPUT_OK;
}
#endif
int length = strlen(wavedev) + 1;
if (wavedevice != NULL)
delete(wavedevice);
wavedevice = new char[length];
if (wavedevice == NULL)
return BX_SOUND_OUTPUT_ERR;
strncpy(wavedevice, wavedev, length);
return BX_SOUND_OUTPUT_OK;
}
#if BX_HAVE_ALSASOUND
int bx_sound_linux_c::alsa_pcm_open(int frequency, int bits, int stereo, int format)
{
int ret;
snd_pcm_format_t fmt;
snd_pcm_hw_params_t *params;
unsigned int size, freq;
int signeddata = format & 1;
audio_bufsize = 0;
if (alsa_pcm.handle == NULL) {
ret = snd_pcm_open(&alsa_pcm.handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (ret < 0) {
return BX_SOUND_OUTPUT_ERR;
}
BX_INFO(("ALSA: opened default PCM output device"));
}
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(alsa_pcm.handle, params);
snd_pcm_hw_params_set_access(alsa_pcm.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if ((frequency == oldfreq) &&
(bits == oldbits) &&
(stereo == oldstereo) &&
(format == oldformat))
return BX_SOUND_OUTPUT_OK; // nothing to do
oldfreq = frequency;
oldbits = bits;
oldstereo = stereo;
oldformat = format;
freq = (unsigned int)frequency;
if (bits == 16) {
if (signeddata == 1)
fmt = SND_PCM_FORMAT_S16_LE;
else
fmt = SND_PCM_FORMAT_U16_LE;
size = 2;
} else if (bits == 8) {
if (signeddata == 1)
fmt = SND_PCM_FORMAT_S8;
else
fmt = SND_PCM_FORMAT_U8;
size = 1;
} else
return BX_SOUND_OUTPUT_ERR;
if (stereo) size *= 2;
snd_pcm_hw_params_set_format(alsa_pcm.handle, params, fmt);
snd_pcm_hw_params_set_channels(alsa_pcm.handle, params, (stereo != 0) ? 2 : 1);
snd_pcm_hw_params_set_rate_near(alsa_pcm.handle, params, &freq, &dir);
alsa_pcm.frames = 32;
snd_pcm_hw_params_set_period_size_near(alsa_pcm.handle, params, &alsa_pcm.frames, &dir);
ret = snd_pcm_hw_params(alsa_pcm.handle, params);
if (ret < 0) {
return BX_SOUND_OUTPUT_ERR;
}
snd_pcm_hw_params_get_period_size(params, &alsa_pcm.frames, &dir);
alsa_bufsize = alsa_pcm.frames * size;
BX_DEBUG(("ALSA: buffer size set to %d", alsa_bufsize));
if (alsa_buffer != NULL) {
free(alsa_buffer);
alsa_buffer = NULL;
}
return BX_SOUND_OUTPUT_OK;
}
#endif
int bx_sound_linux_c::startwaveplayback(int frequency, int bits, int stereo, int format)
{
int fmt, ret;
int signeddata = format & 1;
#if BX_HAVE_ALSASOUND
if (use_alsa_pcm) {
return alsa_pcm_open(frequency, bits, stereo, format);
}
#endif
if ((wavedevice == NULL) || (strlen(wavedevice) < 1))
return BX_SOUND_OUTPUT_ERR;
if (wave == -1) {
wave = open(wavedevice, O_WRONLY);
if (wave == -1) {
return BX_SOUND_OUTPUT_ERR;
} else {
BX_INFO(("OSS: opened output device %s", wavedevice));
}
} else {
if ((frequency == oldfreq) &&
(bits == oldbits) &&
(stereo == oldstereo) &&
(format == oldformat))
return BX_SOUND_OUTPUT_OK; // nothing to do
}
oldfreq = frequency;
oldbits = bits;
oldstereo = stereo;
oldformat = format;
if (bits == 16)
if (signeddata == 1)
fmt = AFMT_S16_LE;
else
fmt = AFMT_U16_LE;
else if (bits == 8)
if (signeddata == 1)
fmt = AFMT_S8;
else
fmt = AFMT_U8;
else
return BX_SOUND_OUTPUT_ERR;
// set frequency etc.
ret = ioctl(wave, SNDCTL_DSP_RESET);
if (ret != 0)
BX_DEBUG(("ioctl(SNDCTL_DSP_RESET): %s", strerror(errno)));
/*
ret = ioctl(wave, SNDCTL_DSP_SETFRAGMENT, &fragment);
if (ret != 0)
WRITELOG(WAVELOG(4), "ioctl(SNDCTL_DSP_SETFRAGMENT, %d): %s",
fragment, strerror(errno));
*/
ret = ioctl(wave, SNDCTL_DSP_SETFMT, &fmt);
if (ret != 0) // abort if the format is unknown, to avoid playing noise
{
BX_DEBUG(("ioctl(SNDCTL_DSP_SETFMT, %d): %s",
fmt, strerror(errno)));
return BX_SOUND_OUTPUT_ERR;
}
ret = ioctl(wave, SNDCTL_DSP_STEREO, &stereo);
if (ret != 0)
BX_DEBUG(("ioctl(SNDCTL_DSP_STEREO, %d): %s",
stereo, strerror(errno)));
ret = ioctl(wave, SNDCTL_DSP_SPEED, &frequency);
if (ret != 0)
BX_DEBUG(("ioctl(SNDCTL_DSP_SPEED, %d): %s",
frequency, strerror(errno)));
// ioctl(wave, SNDCTL_DSP_GETBLKSIZE, &fragment);
// BX_DEBUG(("current output block size is %d", fragment));
return BX_SOUND_OUTPUT_OK;
}
#if BX_HAVE_ALSASOUND
int bx_sound_linux_c::alsa_pcm_write()
{
int ret;
if (alsa_buffer == NULL) {
alsa_buffer = (char *)malloc(alsa_bufsize);
}
while (audio_bufsize >= alsa_bufsize) {
memcpy(alsa_buffer, audio_buffer, alsa_bufsize);
ret = snd_pcm_writei(alsa_pcm.handle, alsa_buffer, alsa_pcm.frames);
if (ret == -EAGAIN)
continue;
if (ret == -EPIPE) {
/* EPIPE means underrun */
BX_ERROR(("ALSA: underrun occurred"));
snd_pcm_prepare(alsa_pcm.handle);
} else if (ret < 0) {
BX_ERROR(("ALSA: error from writei: %s", snd_strerror(ret)));
} else if (ret != (int)alsa_pcm.frames) {
BX_ERROR(("ALSA: short write, write %d frames", ret));
}
audio_bufsize -= alsa_bufsize;
memcpy(audio_buffer, audio_buffer+alsa_bufsize, audio_bufsize);
}
if ((audio_bufsize == 0) && (alsa_buffer != NULL)) {
free(alsa_buffer);
alsa_buffer = NULL;
}
return BX_SOUND_OUTPUT_OK;
}
#endif
int bx_sound_linux_c::sendwavepacket(int length, Bit8u data[])
{
#if BX_HAVE_ALSASOUND
if (use_alsa_pcm) {
if ((audio_bufsize+length) <= BX_SOUND_LINUX_BUFSIZE) {
memcpy(audio_buffer+audio_bufsize, data, length);
audio_bufsize += length;
} else {
BX_ERROR(("ALSA: audio buffer overflow"));
return BX_SOUND_OUTPUT_ERR;
}
if (audio_bufsize < alsa_bufsize) {
return BX_SOUND_OUTPUT_OK;
} else {
return alsa_pcm_write();
}
}
#endif
int ret = write(wave, data, length);
if (ret == length) {
return BX_SOUND_OUTPUT_OK;
} else {
BX_ERROR(("OSS: write error"));
return BX_SOUND_OUTPUT_ERR;
}
}
int bx_sound_linux_c::stopwaveplayback()
{
#if BX_HAVE_ALSASOUND
if (use_alsa_pcm && (audio_bufsize > 0)) {
if (audio_bufsize < alsa_bufsize) {
memset(audio_buffer+audio_bufsize, 0, alsa_bufsize-audio_bufsize);
audio_bufsize = alsa_bufsize;
}
alsa_pcm_write();
}
#endif
// ioctl(wave, SNDCTL_DSP_SYNC);
// close(wave);
// wave = -1;
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_linux_c::closewaveoutput()
{
#if BX_HAVE_ALSASOUND
if (use_alsa_pcm && (alsa_pcm.handle != NULL)) {
snd_pcm_drain(alsa_pcm.handle);
snd_pcm_close(alsa_pcm.handle);
alsa_pcm.handle = NULL;
}
#endif
if (wavedevice != NULL)
delete(wavedevice);
if (wave != -1)
{
close(wave);
wave = -1;
}
wavedevice = NULL;
return BX_SOUND_OUTPUT_OK;
}
#endif

81
bochs/iodev/soundlnx.h Normal file
View File

@ -0,0 +1,81 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
// Josef Drexler coded the original version of the lowlevel sound support
// for Linux using OSS. The current version also supports OSS on FreeBSD and
// ALSA PCM output on Linux.
#if (defined(linux) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
#define BX_SOUND_LINUX_BUFSIZE BX_SOUND_OUTPUT_WAVEPACKETSIZE * 2
#if BX_HAVE_ALSASOUND
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#endif
class bx_sound_linux_c : public bx_sound_output_c {
public:
bx_sound_linux_c(logfunctions *dev);
virtual ~bx_sound_linux_c();
virtual int waveready();
virtual int midiready();
virtual int openmidioutput(const char *mididev);
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
virtual int closemidioutput();
virtual int openwaveoutput(const char *wavedev);
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
virtual int sendwavepacket(int length, Bit8u data[]);
virtual int stopwaveplayback();
virtual int closewaveoutput();
private:
#if BX_HAVE_ALSASOUND
int alsa_seq_open(const char *alsadev);
int alsa_seq_output(int delta, int command, int length, Bit8u data[]);
int alsa_pcm_open(int frequency, int bits, int stereo, int format);
int alsa_pcm_write();
bx_bool use_alsa_seq;
bx_bool use_alsa_pcm;
struct {
snd_seq_t *handle;
int source_port;
} alsa_seq;
struct {
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
} alsa_pcm;
int dir, alsa_bufsize, audio_bufsize;
char *alsa_buffer;
#endif
FILE *midi;
char *wavedevice;
int wave;
Bit8u audio_buffer[BX_SOUND_LINUX_BUFSIZE];
int oldfreq,oldbits,oldstereo,oldformat;
};
#endif

140
bochs/iodev/soundmod.cc Normal file
View File

@ -0,0 +1,140 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Common sound module code and dummy sound output functions
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_SB16
#include "soundmod.h"
#include "soundlnx.h"
#include "soundosx.h"
#include "soundwin.h"
#define LOG_THIS dev->
bx_soundmod_ctl_c* theSoundModCtl = NULL;
int libsoundmod_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theSoundModCtl = new bx_soundmod_ctl_c;
bx_devices.pluginSoundModCtl = theSoundModCtl;
return(0); // Success
}
void libsoundmod_LTX_plugin_fini(void)
{
delete theSoundModCtl;
}
int bx_soundmod_ctl_c::init_module(const char *type, void **module, logfunctions *dev)
{
bx_sound_output_c **soundmod = (bx_sound_output_c**)module;
if (!strcmp(type, "default")) {
*soundmod = new BX_SOUND_OUTPUT_C(dev);
} else if (!strcmp(type, "dummy")) {
*soundmod = new bx_sound_output_c(dev);
} else {
BX_PANIC(("unknown sound module type '%s'", type));
*soundmod = NULL;
}
return 0;
}
// The dummy sound output functions. They don't do anything.
bx_sound_output_c::bx_sound_output_c(logfunctions *dev)
{
device = dev;
}
bx_sound_output_c::~bx_sound_output_c()
{
}
int bx_sound_output_c::waveready()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::midiready()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::openmidioutput(const char *mididev)
{
UNUSED(mididev);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
{
UNUSED(delta);
UNUSED(command);
UNUSED(length);
UNUSED(data);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::closemidioutput()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::openwaveoutput(const char *wavedev)
{
UNUSED(wavedev);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::startwaveplayback(int frequency, int bits, int stereo, int format)
{
UNUSED(frequency);
UNUSED(bits);
UNUSED(stereo);
UNUSED(format);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::sendwavepacket(int length, Bit8u data[])
{
UNUSED(length);
UNUSED(data);
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::stopwaveplayback()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_output_c::closewaveoutput()
{
return BX_SOUND_OUTPUT_OK;
}
#endif

68
bochs/iodev/soundmod.h Normal file
View File

@ -0,0 +1,68 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// Common code for sound output modules
// this is the size of a DMA chunk sent to output
// it should not be too large to avoid lag, and not too
// small to avoid unnecessary overhead.
#define BX_SOUND_OUTPUT_WAVEPACKETSIZE 8192
// Definitions for the output functions
#define BX_SOUND_OUTPUT_OK 0
#define BX_SOUND_OUTPUT_ERR 1
// Pseudo device that loads the lowlevel sound module
class bx_soundmod_ctl_c : public bx_soundmod_ctl_stub_c {
public:
bx_soundmod_ctl_c() {}
virtual ~bx_soundmod_ctl_c() {}
virtual int init_module(const char *type, void **module, logfunctions *dev);
};
// The class with the output functions
class bx_sound_output_c : public logfunctions {
public:
/*
These functions are the sound output functions, sending
the music/sound to the OS specific driver.
They are in a different file (soundxxx.cc) because they are
non-portable, while everything in sb16.cc is portable
*/
bx_sound_output_c(logfunctions *dev);
virtual ~bx_sound_output_c();
virtual int waveready();
virtual int midiready();
virtual int openmidioutput(const char *mididev);
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
virtual int closemidioutput();
virtual int openwaveoutput(const char *wavedev);
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
virtual int sendwavepacket(int length, Bit8u data[]);
virtual int stopwaveplayback();
virtual int closewaveoutput();
protected:
logfunctions *device;
};

409
bochs/iodev/soundosx.cc Normal file
View File

@ -0,0 +1,409 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// This file (SOUNDOSX.CC) written and donated by Brian Huffman
#ifdef PARANOID
#include <MacTypes.h>
#endif
#include "iodev.h"
#if defined(macintosh) && BX_SUPPORT_SB16
#define LOG_THIS device->
#include "soundmod.h"
#include "soundosx.h"
#if BX_WITH_MACOS
#include <QuickTimeMusic.h>
#else
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/DefaultAudioOutput.h>
#include <AudioToolbox/AudioConverter.h>
#include <AudioToolbox/AUGraph.h>
#include <QuickTime/QuickTimeMusic.h>
#endif
#include <string.h>
#ifdef BX_SOUND_OSX_use_converter
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData);
OSStatus MyACInputProc (AudioConverterRef inAudioConverter, UInt32* outDataSize,
void** outData, void* inUserData);
#endif
// Global variables
#ifdef BX_SOUND_OSX_use_converter
AUGraph MidiGraph;
AudioUnit synthUnit;
#endif
#ifdef BX_SOUND_OSX_use_quicktime
SndChannelPtr WaveChannel;
ExtSoundHeader WaveInfo;
ExtSoundHeader WaveHeader[BX_SOUND_OSX_NBUF];
#endif
#ifdef BX_SOUND_OSX_use_converter
AudioUnit WaveOutputUnit = NULL;
AudioConverterRef WaveConverter = NULL;
#endif
bx_sound_osx_c::bx_sound_osx_c(logfunctions *dev)
:bx_sound_output_c(dev)
{
MidiOpen = 0;
WaveOpen = 0;
head = 0;
tail = 0;
for (int i=0; i<BX_SOUND_OSX_NBUF; i++)
WaveLength[i] = 0;
BX_INFO(("Sound output module 'osx' initialized"));
}
bx_sound_osx_c::~bx_sound_osx_c()
{
// nothing for now
}
int bx_sound_osx_c::midiready()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::openmidioutput(const char *mididev)
{
#ifdef BX_SOUND_OSX_use_converter
ComponentDescription description;
AUNode synthNode, outputNode;
// Create the graph
NewAUGraph (&MidiGraph);
// Open the DLS Synth
description.componentType = kAudioUnitComponentType;
description.componentSubType = kAudioUnitSubType_MusicDevice;
description.componentManufacturer = kAudioUnitID_DLSSynth;
description.componentFlags = 0;
description.componentFlagsMask = 0;
AUGraphNewNode (MidiGraph, &description, 0, NULL, &synthNode);
// Open the output device
description.componentType = kAudioUnitComponentType;
description.componentSubType = kAudioUnitSubType_Output;
description.componentManufacturer = kAudioUnitID_DefaultOutput;
description.componentFlags = 0;
description.componentFlagsMask = 0;
AUGraphNewNode (MidiGraph, &description, 0, NULL, &outputNode);
// Connect the devices up
AUGraphConnectNodeInput (MidiGraph, synthNode, 1, outputNode, 0);
AUGraphUpdate (MidiGraph, NULL);
// Open and initialize the audio units
AUGraphOpen (MidiGraph);
AUGraphInitialize (MidiGraph);
// Turn off the reverb on the synth
AUGraphGetNodeInfo (MidiGraph, synthNode, NULL, NULL, NULL, &synthUnit);
UInt32 usesReverb = 0;
AudioUnitSetProperty (synthUnit, kMusicDeviceProperty_UsesInternalReverb,
kAudioUnitScope_Global, 0, &usesReverb, sizeof (usesReverb));
// Start playing
AUGraphStart (MidiGraph);
#endif
BX_DEBUG(("openmidioutput(%s)", mididev));
MidiOpen = 1;
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
{
BX_DEBUG(("sendmidicommand(%i,%02x,%i)", delta, command, length));
if (!MidiOpen) return BX_SOUND_OUTPUT_ERR;
#ifdef BX_SOUND_OSX_use_converter
if (length <= 2) {
Bit8u arg1 = (length >=1) ? data[0] : 0;
Bit8u arg2 = (length >=2) ? data[1] : 0;
MusicDeviceMIDIEvent (synthUnit, command, arg1, arg2, delta);
}
else {
MusicDeviceSysEx (synthUnit, data, length);
}
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::closemidioutput()
{
BX_DEBUG(("closemidioutput()"));
MidiOpen = 0;
#ifdef BX_SOUND_OSX_use_converter
AUGraphStop (MidiGraph);
AUGraphClose (MidiGraph);
#endif
return BX_SOUND_OUTPUT_OK;
}
#ifdef BX_SOUND_OSX_use_quicktime
#if BX_WITH_MACOS
pascal
#endif
void WaveCallbackProc (SndChannelPtr chan, SndCommand *cmd)
{
// a new buffer is available, so increment tail pointer
int *tail = (int *) (cmd->param2);
(*tail)++;
}
#endif
int bx_sound_osx_c::openwaveoutput(const char *wavedev)
{
OSStatus err;
BX_DEBUG(("openwaveoutput(%s)", wavedev));
// open the default output unit
#ifdef BX_SOUND_OSX_use_quicktime
err = SndNewChannel (&WaveChannel, sampledSynth, 0, NewSndCallBackUPP(WaveCallbackProc));
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
#endif
#ifdef BX_SOUND_OSX_use_converter
err = OpenDefaultAudioOutput (&WaveOutputUnit);
if (err != noErr) return BX_SOUND_OUTPUT_ERR;
AudioUnitInitialize (WaveOutputUnit);
// Set up a callback function to generate output to the output unit
AudioUnitInputCallback input;
input.inputProc = MyRenderer;
input.inputProcRefCon = (void *) this;
AudioUnitSetProperty (WaveOutputUnit, kAudioUnitProperty_SetInputCallback,
kAudioUnitScope_Global, 0, &input, sizeof(input));
#endif
WaveOpen = 1;
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::startwaveplayback(int frequency, int bits, int stereo, int format)
{
#ifdef BX_SOUND_OSX_use_converter
static int oldfreq, oldbits, oldstereo, oldformat;
AudioStreamBasicDescription srcFormat, dstFormat;
UInt32 formatSize = sizeof(AudioStreamBasicDescription);
#endif
BX_DEBUG(("startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format));
#ifdef BX_SOUND_OSX_use_quicktime
WaveInfo.samplePtr = NULL;
WaveInfo.numChannels = stereo ? 2 : 1;
WaveInfo.sampleRate = frequency << 16; // sampleRate is a 16.16 fixed-point value
WaveInfo.loopStart = 0;
WaveInfo.loopEnd = 0;
WaveInfo.encode = extSH; // WaveInfo has type ExtSoundHeader
WaveInfo.baseFrequency = 1; // not sure what means. It's only a Uint8.
WaveInfo.numFrames = 0;
//WaveInfo.AIFFSampleRate = frequency; // frequency as float80
WaveInfo.markerChunk = NULL;
WaveInfo.instrumentChunks = NULL;
WaveInfo.AESRecording = NULL;
WaveInfo.sampleSize = bits * WaveInfo.numChannels;
#endif
#ifdef BX_SOUND_OSX_use_converter
if ((frequency == oldfreq) &&
(bits == oldbits) &&
(stereo == oldstereo) &&
(format == oldformat))
return BX_SOUND_OUTPUT_OK; // nothing to do
oldfreq = frequency;
oldbits = bits;
oldstereo = stereo;
oldformat = format;
// update the source audio format
UInt32 bytes = bits / 8;
UInt32 channels = stereo ? 2 : 1;
srcFormat.mSampleRate = (Float64) frequency;
srcFormat.mFormatID = kAudioFormatLinearPCM;
srcFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
if (format & 1) srcFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
srcFormat.mBytesPerPacket = channels * bytes;
srcFormat.mFramesPerPacket = 1;
srcFormat.mBytesPerFrame = channels * bytes;
srcFormat.mChannelsPerFrame = channels;
srcFormat.mBitsPerChannel = bytes * 8;
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
if (WaveConverter) AudioConverterDispose (WaveConverter);
AudioUnitGetProperty (WaveOutputUnit, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0, &dstFormat, &formatSize);
AudioConverterNew (&srcFormat, &dstFormat, &WaveConverter);
if (srcFormat.mChannelsPerFrame == 1 && dstFormat.mChannelsPerFrame == 2) {
// map single-channel input to both output channels
SInt32 map[2] = {0,0};
AudioConverterSetProperty (WaveConverter, kAudioConverterChannelMap,
sizeof(map), (void*) map);
}
if (WavePlaying) AudioOutputUnitStart (WaveOutputUnit);
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::waveready()
{
// HACK: the -4 is to keep from overwriting buffers that
// have been sent, but possibly not yet played. There
// should be a better way of doing this.
if (WaveOpen && (head - tail < BX_SOUND_OSX_NBUF-4)) {
return BX_SOUND_OUTPUT_OK;
}
else {
#ifdef BX_SOUND_OSX_use_converter
// If buffer is full, make sure sound is playing
if (WaveOutputUnit && !WavePlaying) {
AudioOutputUnitStart (WaveOutputUnit);
WavePlaying = 1;
}
#endif
return BX_SOUND_OUTPUT_ERR;
}
}
int bx_sound_osx_c::sendwavepacket(int length, Bit8u data[])
{
#ifdef BX_SOUND_OSX_use_quicktime
SndCommand mySndCommand;
#endif
BX_DEBUG(("sendwavepacket(%d, %p), head=%u", length, data, head));
// sanity check
if ((!WaveOpen) || (head - tail >= BX_SOUND_OSX_NBUF))
return BX_SOUND_OUTPUT_ERR;
// find next available buffer
int n = head++ % BX_SOUND_OSX_NBUF;
// put data in buffer
memcpy(WaveData[n], data, length);
WaveLength[n] = length;
#ifdef BX_SOUND_OSX_use_quicktime
memcpy(&WaveHeader[n], &WaveInfo, sizeof(WaveInfo));
WaveHeader[n].samplePtr = (char *) (WaveData[n]);
WaveHeader[n].numFrames = length * 8 / WaveInfo.sampleSize;
#endif
#ifdef BX_SOUND_OSX_use_converter
// make sure that the sound is playing
if (!WavePlaying) {
AudioOutputUnitStart (WaveOutputUnit);
WavePlaying = 1;
}
#endif
#ifdef BX_SOUND_OSX_use_quicktime
// queue buffer to play
mySndCommand.cmd = bufferCmd;
mySndCommand.param1 = 0;
mySndCommand.param2 = (long)(&WaveHeader[n]);
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
// queue callback for when buffer finishes
mySndCommand.cmd = callBackCmd;
mySndCommand.param1 = 0;
mySndCommand.param2 = (long)(&tail);
SndDoCommand(WaveChannel, &mySndCommand, TRUE);
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::stopwaveplayback()
{
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_osx_c::closewaveoutput()
{
#ifdef BX_SOUND_OSX_use_converter
if (WavePlaying) AudioOutputUnitStop (WaveOutputUnit);
if (WaveConverter) AudioConverterDispose (WaveConverter);
if (WaveOutputUnit) CloseComponent (WaveOutputUnit);
WavePlaying = 0;
WaveOpen = 0;
WaveConverter = NULL;
WaveOutputUnit = NULL;
#endif
return BX_SOUND_OUTPUT_OK;
}
#ifdef BX_SOUND_OSX_use_converter
OSStatus MyRenderer (void *inRefCon, AudioUnitRenderActionFlags inActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, AudioBuffer *ioData)
{
UInt32 size = ioData->mDataByteSize;
AudioConverterFillBuffer (WaveConverter, MyACInputProc, inRefCon, &size, ioData->mData);
return noErr;
}
OSStatus MyACInputProc (AudioConverterRef inAudioConverter,
UInt32* outDataSize, void** outData, void* inUserData)
{
bx_sound_osx_c *self = (bx_sound_osx_c*) inUserData;
self->nextbuffer ((int*) outDataSize, outData);
return noErr;
}
void bx_sound_osx_c::nextbuffer (int *outDataSize, void **outData)
{
BX_DEBUG(("nextbuffer(), tail=%u", tail));
if (head - tail <= 0) {
*outData = NULL;
*outDataSize = 0;
// We are getting behind, so stop the output for now
AudioOutputUnitStop (WaveOutputUnit);
WavePlaying = 0;
}
else {
int n = tail % BX_SOUND_OSX_NBUF;
*outData = (void *) (WaveData[n]);
*outDataSize = WaveLength[n];
tail++;
}
}
#endif
#endif // defined(macintosh)

72
bochs/iodev/soundosx.h Normal file
View File

@ -0,0 +1,72 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// This file (SOUNDOSX.H) written and donated by Brian Huffman
#ifdef macintosh
#include "bochs.h"
// uncomment one of these two:
#if BX_WITH_MACOS
#define BX_SOUND_OSX_use_quicktime
#else
#define BX_SOUND_OSX_use_converter
//#define BX_SOUND_OSX_use_quicktime
#endif
#define BX_SOUND_OSX_NBUF 8 // number of buffers for digital output
class bx_sound_osx_c : public bx_sound_output_c {
public:
bx_sound_osx_c(logfunctions *dev);
virtual ~bx_sound_osx_c();
virtual int waveready();
virtual int midiready();
virtual int openmidioutput(const char *mididev);
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
virtual int closemidioutput();
virtual int openwaveoutput(const char *wavedev);
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
virtual int sendwavepacket(int length, Bit8u data[]);
virtual int stopwaveplayback();
virtual int closewaveoutput();
#ifdef BX_SOUND_OSX_use_converter
void nextbuffer(int *outDataSize, void **outData);
#endif
private:
int MidiOpen;
int WaveOpen;
Bit8u WaveData[BX_SOUND_OSX_NBUF][BX_SOUND_OUTPUT_WAVEPACKETSIZE];
int WaveLength[BX_SOUND_OSX_NBUF];
int head, tail; // buffer pointers
#ifdef BX_SOUND_OSX_use_converter
int WavePlaying;
#endif
};
#endif // macintosh

511
bochs/iodev/soundwin.cc Normal file
View File

@ -0,0 +1,511 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// This file (SOUNDWIN.CC) written and donated by Josef Drexler
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if defined(WIN32) && BX_SUPPORT_SB16
#include "soundmod.h"
#include "soundwin.h"
#define LOG_THIS device->
bx_sound_windows_c::bx_sound_windows_c(logfunctions *dev)
:bx_sound_output_c(dev)
{
MidiOpen = 0;
WaveOpen = 0;
ismidiready = 1;
iswaveready = 1;
// size is the total size of the midi header and buffer and the
// BX_SOUND_WINDOWS_NBUF wave header and buffers, all aligned
// on a 16-byte boundary
#define ALIGN(size) ((size + 15) & ~15)
#define size ALIGN(sizeof(MIDIHDR)) \
+ ALIGN(sizeof(WAVEHDR)) \
+ ALIGN(BX_SOUND_WINDOWS_MAXSYSEXLEN) * BX_SOUND_WINDOWS_NBUF \
+ ALIGN(BX_SOUND_OUTPUT_WAVEPACKETSIZE) * BX_SOUND_WINDOWS_NBUF
DataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
DataPointer = (Bit8u*) GlobalLock(DataHandle);
if (DataPointer == NULL)
BX_PANIC(("GlobalLock returned NULL-pointer"));
#define NEWBUFFER(size) &(DataPointer[offset]); offset += ALIGN(size)
unsigned offset = 0;
MidiHeader = (LPMIDIHDR) NEWBUFFER(sizeof(MIDIHDR));
MidiData = (LPSTR) NEWBUFFER(BX_SOUND_WINDOWS_MAXSYSEXLEN);
for (int bufnum=0; bufnum<BX_SOUND_WINDOWS_NBUF; bufnum++)
{
WaveHeader[bufnum] = (LPWAVEHDR) NEWBUFFER(sizeof(WAVEHDR));
WaveData[bufnum] = (LPSTR) NEWBUFFER(BX_SOUND_OUTPUT_WAVEPACKETSIZE+64);
}
if (offset > size)
BX_PANIC(("Allocated memory was too small!"));
#undef size
#undef ALIGN
#undef NEWBUFFER
BX_INFO(("Sound output module 'win' initialized"));
}
bx_sound_windows_c::~bx_sound_windows_c()
{
GlobalUnlock(DataHandle);
GlobalFree(DataHandle);
}
int bx_sound_windows_c::waveready()
{
if (iswaveready == 0)
checkwaveready();
if (iswaveready == 1)
return BX_SOUND_OUTPUT_OK;
else
return BX_SOUND_OUTPUT_ERR;
}
int bx_sound_windows_c::midiready()
{
if (ismidiready == 0)
checkmidiready();
if (ismidiready == 1)
return BX_SOUND_OUTPUT_OK;
else
return BX_SOUND_OUTPUT_ERR;
}
int bx_sound_windows_c::openmidioutput(const char *mididev)
{
// could make the output device selectable,
// but currently only the midi mapper is supported
UNUSED(mididev);
UINT deviceid = (UINT) MIDIMAPPER;
MidiOpen = 0;
UINT ret = midiOutOpen(&MidiOut, deviceid, 0, 0, CALLBACK_NULL);
if (ret == 0)
MidiOpen = 1;
BX_DEBUG(("midiOutOpen() = %d, MidiOpen: %d", ret, MidiOpen));
return (MidiOpen == 1) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
}
int bx_sound_windows_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
{
UINT ret;
if (MidiOpen != 1)
return BX_SOUND_OUTPUT_ERR;
if ((command == 0xf0) || (command == 0xf7) || (length > 3))
{
BX_DEBUG(("SYSEX started, length %d", length));
ismidiready = 0; // until the buffer is done
memcpy(MidiData, data, length);
MidiHeader->lpData = MidiData;
MidiHeader->dwBufferLength = BX_SOUND_WINDOWS_MAXSYSEXLEN;
MidiHeader->dwBytesRecorded = 0;
MidiHeader->dwUser = 0;
MidiHeader->dwFlags = 0;
ret = midiOutPrepareHeader(MidiOut, MidiHeader, sizeof(*MidiHeader));
if (ret != 0)
BX_ERROR(("midiOutPrepareHeader() = %d", ret));
ret = midiOutLongMsg(MidiOut, MidiHeader, sizeof(*MidiHeader));
if (ret != 0)
BX_ERROR(("midiOutLongMsg() = %d", ret));
}
else
{
DWORD msg = command;
for (int i = 0; i<length; i++)
msg |= (data[i] << (8 * (i + 1)));
ret = midiOutShortMsg(MidiOut, msg);
BX_DEBUG(("midiOutShortMsg(%x) = %d", msg, ret));
}
return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
}
int bx_sound_windows_c::closemidioutput()
{
UINT ret;
if (MidiOpen != 1)
return BX_SOUND_OUTPUT_ERR;
ret = midiOutReset(MidiOut);
if (ismidiready == 0)
checkmidiready(); // to clear any pending SYSEX
ret = midiOutClose(MidiOut);
BX_DEBUG(("midiOutClose() = %d", ret));
MidiOpen = 0;
return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
}
int bx_sound_windows_c::openwaveoutput(const char *wavedev)
{
// could make the output device selectable,
// but currently only the wave mapper is supported
UNUSED(wavedev);
BX_DEBUG(("openwaveoutput(%s)", wavedev));
#ifdef usewaveOut
WaveDevice = (UINT) WAVEMAPPER;
for (int i=0; i<BX_SOUND_WINDOWS_NBUF; i++)
WaveHeader[i]->dwFlags = WHDR_DONE;
head = 0;
tailfull = 0;
tailplay = 0;
needreopen = 0;
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_windows_c::playnextbuffer()
{
UINT ret;
PCMWAVEFORMAT waveformat;
int bufnum;
// if the format is different, we have to reopen the device,
// so reset it first
if (needreopen != 0)
if (WaveOpen != 0)
ret = waveOutReset(WaveOut);
// clean up the buffers and mark if output is ready
checkwaveready();
// do we have to play anything?
if (tailplay == head)
return BX_SOUND_OUTPUT_OK;
// if the format is different, we have to close and reopen the device
// or, just open the device if it's not open yet
if ((needreopen != 0) || (WaveOpen == 0))
{
if (WaveOpen != 0)
{
ret = waveOutClose(WaveOut);
WaveOpen = 0;
}
// try three times to find a suitable format
for (int tries = 0; tries < 3; tries++)
{
int frequency = WaveInfo.frequency;
int stereo = WaveInfo.stereo;
int bits = WaveInfo.bits;
// int format = WaveInfo.format;
int bps = (bits / 8) * (stereo + 1);
waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
waveformat.wf.nChannels = stereo + 1;
waveformat.wf.nSamplesPerSec = frequency;
waveformat.wf.nAvgBytesPerSec = frequency * bps;
waveformat.wf.nBlockAlign = bps;
waveformat.wBitsPerSample = bits;
ret = waveOutOpen(&(WaveOut), WaveDevice, (LPWAVEFORMATEX)&(waveformat.wf), 0, 0, CALLBACK_NULL);
if (ret != 0)
{
char errormsg[4*MAXERRORLENGTH+1];
waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
BX_DEBUG(("waveOutOpen: %s", errormsg));
switch (tries) {
case 0: // maybe try a different frequency
if (frequency < 15600)
frequency = 11025;
else if (frequency < 31200)
frequency = 22050;
else
frequency = 44100;
BX_DEBUG(("Couldn't open wave device (error %d), trying frequency %d", ret, frequency));
break;
case 1: // or something else
frequency = 11025;
stereo = 0;
bits = 8;
bps = 1;
BX_DEBUG(("Couldn't open wave device again (error %d), trying 11KHz, mono, 8bit", ret));
break;
case 2: // nope, doesn't work
BX_ERROR(("Couldn't open wave device (error %d)!", ret));
return BX_SOUND_OUTPUT_ERR;
}
BX_DEBUG(("The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,",
waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec));
BX_DEBUG((" nAvgBytesPerSec=%d, nBlockAlign=%d, wBitsPerSample=%d",
waveformat.wf.nAvgBytesPerSec, waveformat.wf.nBlockAlign, waveformat.wBitsPerSample));
}
else
{
WaveOpen = 1;
needreopen = 0;
break;
}
}
}
for (bufnum=tailplay; bufnum != head;
bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK, tailplay=bufnum)
{
BX_DEBUG(("Playing buffer %d", bufnum));
// prepare the wave header
WaveHeader[bufnum]->lpData = WaveData[bufnum];
WaveHeader[bufnum]->dwBufferLength = length[bufnum];
WaveHeader[bufnum]->dwBytesRecorded = length[bufnum];
WaveHeader[bufnum]->dwUser = 0;
WaveHeader[bufnum]->dwFlags = 0;
WaveHeader[bufnum]->dwLoops = 1;
ret = waveOutPrepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
if (ret != 0)
{
BX_ERROR(("waveOutPrepareHeader = %d", ret));
return BX_SOUND_OUTPUT_ERR;
}
ret = waveOutWrite(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
if (ret != 0)
{
char errormsg[4*MAXERRORLENGTH+1];
waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
BX_DEBUG(("waveOutWrite: %s", errormsg));
}
}
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_windows_c::startwaveplayback(int frequency, int bits, int stereo, int format)
{
BX_DEBUG(("startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format));
#ifdef usewaveOut
// check if any of the properties have changed
if ((WaveInfo.frequency != frequency) ||
(WaveInfo.bits != bits) ||
(WaveInfo.stereo != stereo) ||
(WaveInfo.format != format))
{
needreopen = 1;
// store the current settings to be used by sendwavepacket()
WaveInfo.frequency = frequency;
WaveInfo.bits = bits;
WaveInfo.stereo = stereo;
WaveInfo.format = format;
}
#endif
#ifdef usesndPlaySnd
int bps = (bits / 8) * (stereo + 1);
LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0];
memcpy(header->RIFF, "RIFF", 4);
memcpy(header->TYPE, "WAVE", 4);
memcpy(header->chnk, "fmt ", 4);
header->chnklen = 16;
header->waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
header->waveformat.wf.nChannels = stereo + 1;
header->waveformat.wf.nSamplesPerSec = frequency;
header->waveformat.wf.nAvgBytesPerSec = frequency * bps;
header->waveformat.wf.nBlockAlign = bps;
header->waveformat.wBitsPerSample = bits;
memcpy(header->chnk2, "data", 4);
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_windows_c::sendwavepacket(int length, Bit8u data[])
{
#ifdef usewaveOut
int bufnum;
#endif
#ifdef usesndPlaySnd
UINT ret;
#endif
BX_DEBUG(("sendwavepacket(%d, %p)", length, data));
#ifdef usewaveOut
bufnum = head;
memcpy(WaveData[bufnum], data, length);
this->length[bufnum] = length;
// select next buffer to write to
bufnum++;
bufnum &= BX_SOUND_WINDOWS_NMASK;
if (((bufnum + 1) & BX_SOUND_WINDOWS_NMASK) == tailfull)
{ // this should not actually happen!
BX_ERROR(("Output buffer overflow! Not played. Iswaveready was %d", iswaveready));
iswaveready = 0; // stop the output for a while
return BX_SOUND_OUTPUT_ERR;
}
head = bufnum;
// check if more buffers are available, otherwise stall the emulator
if (((bufnum + 2) & BX_SOUND_WINDOWS_NMASK) == tailfull)
{
BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Stall.",
head, tailfull, tailplay));
iswaveready = 0;
}
playnextbuffer();
#endif
#ifdef usesndPlaySnd
LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0];
header->length = length + 36;
header->chnk2len = length;
memcpy(&(header->data), data, length);
ret = sndPlaySoundA((LPCSTR) header, SND_SYNC | SND_MEMORY);
if (ret != 0)
{
BX_DEBUG(("sndPlaySoundA: %d", ret));
}
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_windows_c::stopwaveplayback()
{
BX_DEBUG(("stopwaveplayback()"));
#ifdef usewaveOut
// this is handled by checkwaveready() when closing
#endif
#ifdef usesndPlaySnd
sndPlaySoundA(NULL, SND_ASYNC | SND_MEMORY);
WaveOpen = 0;
#endif
return BX_SOUND_OUTPUT_OK;
}
int bx_sound_windows_c::closewaveoutput()
{
BX_DEBUG(("closewaveoutput"));
#ifdef usewaveOut
if (WaveOpen == 1)
{
waveOutReset(WaveOut);
// let checkwaveready() clean up the buffers
checkwaveready();
waveOutClose(WaveOut);
head = 0;
tailfull = 0;
tailplay = 0;
needreopen = 0;
}
#endif
return BX_SOUND_OUTPUT_OK;
}
void bx_sound_windows_c::checkmidiready()
{
UINT ret;
if ((MidiHeader->dwFlags & MHDR_DONE) != 0)
{
BX_DEBUG(("SYSEX message done, midi ready again"));
ret = midiOutUnprepareHeader(MidiOut, MidiHeader, sizeof(*MidiHeader));
ismidiready = 1;
}
}
void bx_sound_windows_c::checkwaveready()
{
int bufnum;
UINT ret;
// clean up all finished buffers and mark them as available
for (bufnum=tailfull; (bufnum != tailplay) &&
((WaveHeader[bufnum]->dwFlags & WHDR_DONE) != 0);
bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK)
{
BX_DEBUG(("Buffer %d done.", bufnum));
ret = waveOutUnprepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
}
tailfull = bufnum;
// enable gathering data if a buffer is available
if (((head + 2) & BX_SOUND_WINDOWS_NMASK) != tailfull)
{
BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Ready.",
head, tailfull, tailplay));
iswaveready = 1;
}
}
#endif // defined(WIN32)

222
bochs/iodev/soundwin.h Normal file
View File

@ -0,0 +1,222 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2011 The Bochs Project
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
/////////////////////////////////////////////////////////////////////////
// This file (SOUNDWIN.H) written and donated by Josef Drexler
#if defined(WIN32)
#include <windows.h>
// uncomment one of the following two #defines
//#define usesndPlaySnd
#define usewaveOut
#define BX_SOUND_WINDOWS_MAXSYSEXLEN 256 // maximum supported length of a sysex message
#define BX_SOUND_WINDOWS_NBUF 64 // number of buffers for the output, must be power of 2 and >= 4
#define BX_SOUND_WINDOWS_NMASK (BX_SOUND_WINDOWS_NBUF - 1)
#ifndef WAVEMAPPER
#define WAVEMAPPER -1
#endif
// Definitions for WINMM.DLL, if not defined already
#ifndef MMSYSERR_NOERROR
#pragma pack(1)
typedef UINT HMIDIOUT;
typedef HMIDIOUT *LPHMIDIOUT;
typedef struct midihdr_tag {
LPSTR lpData;
DWORD dwBufferLength;
DWORD dwBytesRecorded;
DWORD dwUser;
DWORD dwFlags;
struct midihdr_tag *lpNext;
DWORD reserved;
} MIDIHDR, *LPMIDIHDR;
typedef UINT HWAVEOUT;
typedef HWAVEOUT *LPHWAVEOUT;
typedef struct wavehdr_tag {
LPSTR lpData;
DWORD dwBufferLength;
DWORD dwBytesRecorded;
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops;
struct wavehdr_tag *lpNext;
DWORD reserved;
} WAVEHDR, *LPWAVEHDR;
#define WHDR_DONE 0x00000001
#define WHDR_PREPARED 0x00000002
#define WHDR_BEGINLOOP 0x00000004
#define WHDR_ENDLOOP 0x00000008
#define WHDR_INQUEUE 0x00000010
typedef struct waveformat_tag {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
} WAVEFORMAT, *LPWAVEFORMAT;
#define WAVE_FORMAT_PCM 1
typedef struct pcmwaveformat_tag {
WAVEFORMAT wf;
WORD wBitsPerSample;
} PCMWAVEFORMAT, *LPPCMWAVEFORMAT;
#define MIDIMAPPER -1
#define CALLBACK_NULL 0x00000000
#define CALLBACK_WINDOW 0x00010000
#define CALLBACK_TASK 0x00020000
#define CALLBACK_FUNCTION 0x00030000
#define MMSYSERR_NOERROR 0
#define MMSYSERR_ERROR 1
#define MMSYSERR_BADDEVICEID 2
#define MMSYSERR_NOTENABLED 3
#define MMSYSERR_ALLOCATED 4
#define MMSYSERR_INVALHANDLE 5
#define MMSYSERR_NODRIVER 6
#define MMSYSERR_NOMEM 7
#define MMSYSERR_NOTSUPPORTED 8
#define MMSYSERR_NOMAP 7
#define MIDIERR_UNPREPARED 64
#define MIDIERR_STILLPLAYING 65
#define MIDIERR_NOTREADY 66
#define MIDIERR_NODEVICE 67
#define WAVERR_BADFORMAT 32
#define WAVERR_STILLPLAYING 33
#define WAVERR_UNPREPARED 34
#define WAVERR_SYNC 35
#define MAXERRORLENGTH 128
extern "C" {
UINT STDCALL midiOutOpen(LPHMIDIOUT, UINT, DWORD, DWORD, DWORD);
UINT STDCALL midiOutShortMsg(HMIDIOUT, DWORD);
UINT STDCALL midiOutLongMsg(HMIDIOUT, LPMIDIHDR, UINT);
UINT STDCALL midiOutPrepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
UINT STDCALL midiOutUnprepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
UINT STDCALL midiOutReset(HMIDIOUT);
UINT STDCALL midiOutClose(HMIDIOUT);
UINT STDCALL waveOutOpen(LPHWAVEOUT, UINT, LPWAVEFORMAT, DWORD, DWORD, DWORD);
UINT STDCALL waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT);
UINT STDCALL waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
UINT STDCALL waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
UINT STDCALL waveOutReset(HWAVEOUT);
UINT STDCALL waveOutClose(HWAVEOUT);
UINT STDCALL waveOutGetErrorTextA(UINT, LPSTR, UINT);
BOOL STDCALL sndPlaySoundA(LPCSTR, UINT);
}
#pragma pack(0)
#endif // MMSYSERR_NOERROR defined
#ifndef WAVEFILEHEADER
#pragma pack(push, 1)
typedef struct {
char RIFF[4];
Bit32u length;
char TYPE[4];
char chnk[4];
Bit32u chnklen;
PCMWAVEFORMAT waveformat;
char chnk2[4];
Bit32u chnk2len;
char data[1];
} WAVEFILEHEADER, *LPWAVEFILEHEADER;
#pragma pack(pop)
#endif
class bx_sound_windows_c : public bx_sound_output_c {
public:
bx_sound_windows_c(logfunctions *dev);
virtual ~bx_sound_windows_c();
virtual int waveready();
virtual int midiready();
virtual int openmidioutput(const char *mididev);
virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]);
virtual int closemidioutput();
virtual int openwaveoutput(const char *wavedev);
virtual int startwaveplayback(int frequency, int bits, int stereo, int format);
virtual int sendwavepacket(int length, Bit8u data[]);
virtual int stopwaveplayback();
virtual int closewaveoutput();
private:
struct bx_sb16_waveinfo_struct {
int frequency;
int bits;
int stereo;
int format;
};
HMIDIOUT MidiOut; // Midi output device
int MidiOpen; // is it open?
HWAVEOUT WaveOut; // Wave output device
int WaveOpen; // is it open?
UINT WaveDevice; // Wave device ID, for waveOutOpen
// some data for the wave buffers
HANDLE DataHandle; // returned by GlobalAlloc()
Bit8u *DataPointer; // returned by GlobalLock()
LPWAVEHDR WaveHeader[BX_SOUND_WINDOWS_NBUF];
LPSTR WaveData[BX_SOUND_WINDOWS_NBUF];
int length[BX_SOUND_WINDOWS_NBUF]; // length of the data in the buffer
int needreopen; // if the format has changed
int head,tailfull,tailplay; // These are for three states of the buffers: empty, full, played
bx_sb16_waveinfo_struct WaveInfo; // format for the next buffer to be played
int iswaveready;
// and the midi buffer for the SYSEX messages
LPMIDIHDR MidiHeader;
LPSTR MidiData;
int ismidiready;
int playnextbuffer();
void checkmidiready();
void checkwaveready();
};
#endif // defined(WIN32)

152
bochs/iodev/speaker.cc Normal file
View File

@ -0,0 +1,152 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright 2003 by David N. Welton <davidw@dedasys.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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define BX_PLUGGABLE
#include "iodev.h"
#include "speaker.h"
#ifdef __linux__
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/kd.h>
#endif
#define LOG_THIS theSpeaker->
bx_speaker_c *theSpeaker= NULL;
int libspeaker_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theSpeaker = new bx_speaker_c();
bx_devices.pluginSpeaker = theSpeaker;
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSpeaker, BX_PLUGIN_SPEAKER);
return(0); // Success
}
void libspeaker_LTX_plugin_fini(void)
{
delete theSpeaker;
}
bx_speaker_c::bx_speaker_c()
{
put("SPEAK");
beep_frequency = 0.0; // Off
#ifdef __linux__
consolefd = open("/dev/console", O_WRONLY);
#endif
}
bx_speaker_c::~bx_speaker_c()
{
#ifdef __linux__
if (consolefd >= 0) {
ioctl(consolefd, KIOCSOUND, 0);
close(consolefd);
}
#endif
BX_DEBUG(("Exit"));
}
void bx_speaker_c::init(void)
{
#ifdef __linux__
if (consolefd != -1) {
BX_INFO(("Open /dev/console successfully"));
} else {
BX_INFO(("Failed to open /dev/console: %s", strerror(errno)));
BX_INFO(("Deactivating beep on console"));
}
#endif
this->beep_off();
}
void bx_speaker_c::reset(unsigned type)
{
beep_off();
}
void bx_speaker_c::beep_on(float frequency)
{
beep_frequency = frequency;
#ifdef __linux__
if (consolefd != -1) {
this->info("pc speaker on with frequency %f", frequency);
ioctl(consolefd, KIOCSOUND, (int)(clock_tick_rate/frequency));
}
#elif defined(WIN32)
usec_start = bx_pc_system.time_usec();
#endif
// give the gui a chance to signal beep off
bx_gui->beep_on(frequency);
}
#if defined(WIN32)
static struct {
DWORD frequency;
DWORD msec;
} beep_info;
DWORD WINAPI BeepThread(LPVOID)
{
static BOOL threadActive = FALSE;
while (threadActive) Sleep(10);
threadActive = TRUE;
Beep(beep_info.frequency, beep_info.msec);
threadActive = FALSE;
return 0;
}
#endif
void bx_speaker_c::beep_off()
{
if (beep_frequency != 0.0) {
#ifdef __linux__
if (consolefd != -1) {
ioctl(consolefd, KIOCSOUND, 0);
}
#elif defined(WIN32)
// FIXME: sound should start at beep_on() and end here
DWORD threadID;
beep_info.msec = (DWORD)((bx_pc_system.time_usec() - usec_start) / 1000);
beep_info.frequency = (DWORD)beep_frequency;
CreateThread(NULL, 0, BeepThread, NULL, 0, &threadID);
#endif
// give the gui a chance to signal beep off
bx_gui->beep_off();
beep_frequency = 0.0;
}
}

Some files were not shown because too many files have changed in this diff Show More