aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ioemu
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ioemu')
-rw-r--r--tools/ioemu/Makefile19
-rw-r--r--tools/ioemu/font/vga.bitmap.h288
-rw-r--r--tools/ioemu/gui/Makefile12
-rw-r--r--tools/ioemu/gui/Makefile.in561
-rw-r--r--tools/ioemu/gui/bitmaps/cdromd.h34
-rw-r--r--tools/ioemu/gui/bitmaps/cdromd.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/configbutton.h16
-rw-r--r--tools/ioemu/gui/bitmaps/configbutton.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/copy.h18
-rw-r--r--tools/ioemu/gui/bitmaps/copy.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/floppya.h34
-rw-r--r--tools/ioemu/gui/bitmaps/floppya.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/floppyb.h34
-rw-r--r--tools/ioemu/gui/bitmaps/floppyb.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/mouse.h34
-rw-r--r--tools/ioemu/gui/bitmaps/mouse.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/paste.h18
-rw-r--r--tools/ioemu/gui/bitmaps/paste.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/power.h20
-rw-r--r--tools/ioemu/gui/bitmaps/power.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/reset.h20
-rw-r--r--tools/ioemu/gui/bitmaps/reset.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/snapshot.h20
-rw-r--r--tools/ioemu/gui/bitmaps/snapshot.xpm41
-rw-r--r--tools/ioemu/gui/bitmaps/userbutton.h19
-rw-r--r--tools/ioemu/gui/bitmaps/userbutton.xpm40
-rw-r--r--tools/ioemu/gui/gui.cc592
-rw-r--r--tools/ioemu/gui/gui.h352
-rw-r--r--tools/ioemu/gui/icon_bochs.h40
-rw-r--r--tools/ioemu/gui/icon_bochs.xpm45
-rw-r--r--tools/ioemu/gui/keymap.cc330
-rw-r--r--tools/ioemu/gui/keymap.h77
-rw-r--r--tools/ioemu/gui/keymaps/convertmap.pl14
-rw-r--r--tools/ioemu/gui/keymaps/sdl-pc-de.map222
-rw-r--r--tools/ioemu/gui/keymaps/sdl-pc-us.map211
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-be.map220
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-da.map247
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-de.map247
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-es.map217
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-fr.map218
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-it.map207
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-se.map278
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-uk.map209
-rw-r--r--tools/ioemu/gui/keymaps/x11-pc-us.map205
-rw-r--r--tools/ioemu/gui/nogui.cc336
-rw-r--r--tools/ioemu/gui/rfb.cc1508
-rw-r--r--tools/ioemu/gui/rfb.h35
-rw-r--r--tools/ioemu/gui/rfbproto.h675
-rw-r--r--tools/ioemu/gui/sdl.h1038
-rw-r--r--tools/ioemu/gui/sdlkeys.h257
-rw-r--r--tools/ioemu/gui/siminterface.cc1411
-rw-r--r--tools/ioemu/gui/siminterface.h1460
-rw-r--r--tools/ioemu/gui/svga.cc514
-rw-r--r--tools/ioemu/gui/term.cc843
-rw-r--r--tools/ioemu/gui/textconfig.cc995
-rw-r--r--tools/ioemu/gui/textconfig.h19
-rw-r--r--tools/ioemu/gui/x.cc1848
-rw-r--r--tools/ioemu/include/bochs.h771
-rw-r--r--tools/ioemu/include/bxversion.h7
-rw-r--r--tools/ioemu/include/config.h919
-rw-r--r--tools/ioemu/include/cpu/cpu.h116
-rw-r--r--tools/ioemu/include/extplugin.h51
-rw-r--r--tools/ioemu/include/instrument.h256
-rw-r--r--tools/ioemu/include/ltdl.h398
-rw-r--r--tools/ioemu/include/ltdlconf.h161
-rw-r--r--tools/ioemu/include/osdep.h176
-rw-r--r--tools/ioemu/include/pc_system.h226
-rw-r--r--tools/ioemu/include/plugin.h323
-rw-r--r--tools/ioemu/include/state_file.h61
-rw-r--r--tools/ioemu/iodev/Makefile15
-rw-r--r--tools/ioemu/iodev/aspi-win32.h210
-rw-r--r--tools/ioemu/iodev/biosdev.cc212
-rw-r--r--tools/ioemu/iodev/biosdev.h63
-rw-r--r--tools/ioemu/iodev/cdrom.cc1338
-rw-r--r--tools/ioemu/iodev/cdrom.h67
-rw-r--r--tools/ioemu/iodev/cdrom_beos.h10
-rw-r--r--tools/ioemu/iodev/cmos.cc824
-rw-r--r--tools/ioemu/iodev/cmos.h90
-rw-r--r--tools/ioemu/iodev/cpu.cc334
-rw-r--r--tools/ioemu/iodev/crc32.cc49
-rw-r--r--tools/ioemu/iodev/crc32.h25
-rw-r--r--tools/ioemu/iodev/devices.cc685
-rw-r--r--tools/ioemu/iodev/dma.cc825
-rw-r--r--tools/ioemu/iodev/dma.h114
-rw-r--r--tools/ioemu/iodev/eth.cc194
-rw-r--r--tools/ioemu/iodev/eth.h76
-rw-r--r--tools/ioemu/iodev/eth_arpback.cc214
-rw-r--r--tools/ioemu/iodev/eth_fbsd.cc385
-rw-r--r--tools/ioemu/iodev/eth_linux.cc286
-rw-r--r--tools/ioemu/iodev/eth_null.cc164
-rw-r--r--tools/ioemu/iodev/eth_packetmaker.cc184
-rw-r--r--tools/ioemu/iodev/eth_packetmaker.h135
-rw-r--r--tools/ioemu/iodev/eth_tap.cc370
-rw-r--r--tools/ioemu/iodev/eth_tuntap.cc401
-rw-r--r--tools/ioemu/iodev/extfpuirq.cc107
-rw-r--r--tools/ioemu/iodev/extfpuirq.h51
-rw-r--r--tools/ioemu/iodev/floppy.cc1633
-rw-r--r--tools/ioemu/iodev/floppy.h138
-rw-r--r--tools/ioemu/iodev/gameport.cc242
-rw-r--r--tools/ioemu/iodev/gameport.h63
-rw-r--r--tools/ioemu/iodev/guest2host.h77
-rw-r--r--tools/ioemu/iodev/harddrv.cc4880
-rw-r--r--tools/ioemu/iodev/harddrv.h765
-rw-r--r--tools/ioemu/iodev/ioapic.cc175
-rw-r--r--tools/ioemu/iodev/ioapic.h54
-rw-r--r--tools/ioemu/iodev/iodebug.cc354
-rw-r--r--tools/ioemu/iodev/iodebug.h35
-rw-r--r--tools/ioemu/iodev/iodev.h422
-rw-r--r--tools/ioemu/iodev/keyboard.cc1611
-rw-r--r--tools/ioemu/iodev/keyboard.h234
-rw-r--r--tools/ioemu/iodev/load32bitOShack.cc322
-rw-r--r--tools/ioemu/iodev/logio.cc631
-rw-r--r--tools/ioemu/iodev/main.cc4067
-rw-r--r--tools/ioemu/iodev/ne2k.cc1608
-rw-r--r--tools/ioemu/iodev/ne2k.h239
-rw-r--r--tools/ioemu/iodev/osdep.cc340
-rw-r--r--tools/ioemu/iodev/parallel.cc300
-rw-r--r--tools/ioemu/iodev/parallel.h78
-rw-r--r--tools/ioemu/iodev/pc_system.cc570
-rw-r--r--tools/ioemu/iodev/pci.cc467
-rw-r--r--tools/ioemu/iodev/pci.h90
-rw-r--r--tools/ioemu/iodev/pci2isa.cc294
-rw-r--r--tools/ioemu/iodev/pci2isa.h63
-rw-r--r--tools/ioemu/iodev/pciusb.cc668
-rw-r--r--tools/ioemu/iodev/pciusb.h195
-rw-r--r--tools/ioemu/iodev/pcivga.cc248
-rw-r--r--tools/ioemu/iodev/pcivga.h48
-rw-r--r--tools/ioemu/iodev/pic.cc887
-rw-r--r--tools/ioemu/iodev/pic.h97
-rw-r--r--tools/ioemu/iodev/pit.cc856
-rw-r--r--tools/ioemu/iodev/pit.h103
-rw-r--r--tools/ioemu/iodev/pit82c54.cc930
-rw-r--r--tools/ioemu/iodev/pit82c54.h143
-rw-r--r--tools/ioemu/iodev/pit_wrap.cc444
-rw-r--r--tools/ioemu/iodev/pit_wrap.h104
-rw-r--r--tools/ioemu/iodev/plugin.cc554
-rw-r--r--tools/ioemu/iodev/scancodes.cc770
-rw-r--r--tools/ioemu/iodev/scancodes.h31
-rw-r--r--tools/ioemu/iodev/scsi_commands.h418
-rw-r--r--tools/ioemu/iodev/scsidefs.h286
-rw-r--r--tools/ioemu/iodev/scsipt.h144
-rw-r--r--tools/ioemu/iodev/serial.cc1001
-rw-r--r--tools/ioemu/iodev/serial.h193
-rw-r--r--tools/ioemu/iodev/serial_raw.h23
-rw-r--r--tools/ioemu/iodev/slowdown_timer.cc182
-rw-r--r--tools/ioemu/iodev/slowdown_timer.h33
-rw-r--r--tools/ioemu/iodev/soundlnx.cc227
-rw-r--r--tools/ioemu/iodev/soundlnx.h69
-rw-r--r--tools/ioemu/iodev/soundwin.cc521
-rw-r--r--tools/ioemu/iodev/soundwin.h229
-rw-r--r--tools/ioemu/iodev/state_file.cc136
-rw-r--r--tools/ioemu/iodev/unmapped.cc305
-rw-r--r--tools/ioemu/iodev/unmapped.h64
-rw-r--r--tools/ioemu/iodev/vga.cc3116
-rw-r--r--tools/ioemu/iodev/vga.h300
-rw-r--r--tools/ioemu/iodev/virt_timer.cc552
-rw-r--r--tools/ioemu/iodev/virt_timer.h131
-rw-r--r--tools/ioemu/memory/Makefile12
-rw-r--r--tools/ioemu/memory/memory.cc450
-rw-r--r--tools/ioemu/memory/memory.h98
-rw-r--r--tools/ioemu/memory/misc_mem.cc440
-rw-r--r--tools/ioemu/mk/helix.mk6
162 files changed, 62126 insertions, 0 deletions
diff --git a/tools/ioemu/Makefile b/tools/ioemu/Makefile
new file mode 100644
index 0000000000..24215c5a6f
--- /dev/null
+++ b/tools/ioemu/Makefile
@@ -0,0 +1,19 @@
+# Order is important!
+SUBDIRS=gui memory iodev
+
+.PHONY: all clean install
+
+all:
+ @for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $(MAKEDEFS) $@ || exit -1; \
+ done
+
+clean:
+ @for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $(MAKEDEFS) $@ || exit -1; \
+ done
+
+install:
+ @for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $(MAKEDEFS) $@ || exit -1; \
+ done
diff --git a/tools/ioemu/font/vga.bitmap.h b/tools/ioemu/font/vga.bitmap.h
new file mode 100644
index 0000000000..e82dd629e6
--- /dev/null
+++ b/tools/ioemu/font/vga.bitmap.h
@@ -0,0 +1,288 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.bitmap.h,v 1.4 2002/05/25 14:22:53 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+typedef struct {
+ unsigned char data[16];
+ } bx_fontcharbitmap_t;
+
+static const bx_fontcharbitmap_t bx_vgafont[256] = {
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xa5, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x78, 0x60, 0x70, 0x58, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfc, 0xcc, 0xfc, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xe7, 0x67, 0x03, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7f, 0x7c, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfe, 0xdb, 0xdb, 0xdb, 0xde, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x36, 0x63, 0x63, 0x36, 0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x36, 0x7f, 0x36, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x3e, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x18, 0x18, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x63, 0x61, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0c, 0x0c, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7b, 0x7b, 0x7b, 0x3b, 0x03, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x7b, 0x3e, 0x30, 0x70, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x1c, 0x3e, 0x36, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x61, 0x30, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 }},
+{{ 0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0x78, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1f, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x30, 0x60, 0x3e, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x33, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x33, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x1c, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06, 0x66, 0x3c, 0x30, 0x60, 0x3c, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x1c, 0x36, 0x1c, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x0c, 0x06, 0x00, 0x7f, 0x66, 0x06, 0x3e, 0x06, 0x06, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x6e, 0x6c, 0x7e, 0x1b, 0x1b, 0x76, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33, 0x33, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0c, 0x1e, 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1e, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x67, 0x3f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1f, 0x33, 0x33, 0x1f, 0x23, 0x33, 0x7b, 0x33, 0x33, 0x33, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x70, 0xd8, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6e, 0x3b, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x3c, 0x36, 0x36, 0x7c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x06, 0x03, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x30, 0x18, 0x7c, 0x00, 0x00 }},
+{{ 0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x73, 0x79, 0x7c, 0x60, 0x60, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 }},
+{{ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }},
+{{ 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f }},
+{{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x1b, 0x1b, 0x3b, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x1b, 0x33, 0x63, 0x63, 0x63, 0x33, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x63, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x7f, 0x63, 0x06, 0x0c, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x03, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x36, 0x36, 0x36, 0x36, 0x77, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0xc0, 0x60, 0x7e, 0xdb, 0xdb, 0xcf, 0x7e, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x38, 0x0c, 0x06, 0x06, 0x3e, 0x06, 0x06, 0x06, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x70, 0xd8, 0xd8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37, 0x36, 0x36, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1b, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0e, 0x1b, 0x0c, 0x06, 0x13, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+};
diff --git a/tools/ioemu/gui/Makefile b/tools/ioemu/gui/Makefile
new file mode 100644
index 0000000000..52ce67bd20
--- /dev/null
+++ b/tools/ioemu/gui/Makefile
@@ -0,0 +1,12 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS= gui.o keymap.o siminterface.o textconfig.o x.o
+
+all: libgui.a
+
+libgui.a: $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(TOPDIR)/mk/helix.mk
+
+install:: all
diff --git a/tools/ioemu/gui/Makefile.in b/tools/ioemu/gui/Makefile.in
new file mode 100644
index 0000000000..c9fd86558a
--- /dev/null
+++ b/tools/ioemu/gui/Makefile.in
@@ -0,0 +1,561 @@
+# Copyright (C) 2002 MandrakeSoft S.A.
+#
+# MandrakeSoft S.A.
+# 43, rue d'Aboukir
+# 75002 Paris - France
+# http://www.linux-mandrake.com/
+# http://www.mandrakesoft.com/
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Makefile for the gui component of bochs
+
+
+@SUFFIX_LINE@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+srcdir = @srcdir@
+VPATH = @srcdir@
+bindir = @bindir@
+libdir = @libdir@
+mandir = @mandir@
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+docdir = $(prefix)/share/doc/bochs
+sharedir = $(prefix)/share/bochs
+top_builddir = ..
+top_srcdir = @top_srcdir@
+
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+CXX = @CXX@
+CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@ @GUI_CXXFLAGS@
+LOCAL_CXXFLAGS =
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+RANLIB = @RANLIB@
+PLUGIN_PATH=@libdir@
+top_builddir = ..
+LIBTOOL=@LIBTOOL@
+WIN32_DLL_IMPORT_LIBRARY=../dllexports.a
+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
+
+GUI_OBJS_X11 = x.o
+GUI_OBJS_SDL = sdl.o
+GUI_OBJS_SVGA = svga.o
+GUI_OBJS_BEOS = beos.o
+GUI_OBJS_WIN32 = win32.o
+GUI_OBJS_MACOS = macintosh.o
+GUI_OBJS_CARBON = carbon.o
+GUI_OBJS_NOGUI = nogui.o
+GUI_OBJS_TERM = term.o
+GUI_OBJS_RFB = rfb.o
+GUI_OBJS_AMIGAOS = amigaos.o
+GUI_OBJS_WX = wx.o
+GUI_OBJS_WX_SUPPORT = wxmain.o wxdialog.o
+OBJS_THAT_CANNOT_BE_PLUGINS = keymap.o gui.o siminterface.o textconfig.o @DIALOG_OBJS@
+OBJS_THAT_CAN_BE_PLUGINS = @GUI_OBJS@
+
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+GUI_LINK_OPTS_X = $(X_LIBS) $(X_PRE_LIBS) -lX11 -lXpm
+GUI_LINK_OPTS_SDL = `sdl-config --cflags --libs`
+GUI_LINK_OPTS_SVGA = -lvga -lvgagl
+GUI_LINK_OPTS_BEOS = -lbe
+GUI_LINK_OPTS_RFB = @RFB_LIBS@
+GUI_LINK_OPTS_AMIGAOS =
+GUI_LINK_OPTS_WIN32 = -luser32 -lgdi32 -lcomdlg32 -lcomctl32
+GUI_LINK_OPTS_WIN32_VCPP = user32.lib gdi32.lib winmm.lib \
+ comdlg32.lib comctl32.lib wsock32.lib
+GUI_LINK_OPTS_MACOS =
+GUI_LINK_OPTS_CARBON = -framework Carbon
+GUI_LINK_OPTS_NOGUI =
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_LINK_OPTS_WX = @GUI_LINK_OPTS_WX@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@ @DEVICE_LINK_OPTS@
+
+NONPLUGIN_OBJS = @GUI_NON_PLUGIN_OBJS@
+PLUGIN_OBJS = @GUI_PLUGIN_OBJS@
+
+#
+# -------- end configurable options --------------------------
+#
+
+all: libgui.a
+
+plugins: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@)
+
+libgui.a: $(NONPLUGIN_OBJS)
+ @RMCOMMAND@ libgui.a
+ @MAKELIB@ $(NONPLUGIN_OBJS)
+ @RANLIB@ libgui.a
+
+# standard compile rule for C++ files
+.@CPP_SUFFIX@.o:
+ $(CXX) @DASH@c $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
+
+##### building plugins with libtool
+%.lo: %.@CPP_SUFFIX@
+ $(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
+
+libbx_%.la: %.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH)
+
+libbx_x.la: x.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_X)
+
+libbx_sdl.la: sdl.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SDL)
+
+libbx_svga.la: svga.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SVGA)
+
+libbx_beos.la: beos.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_BEOS)
+
+libbx_rfb.la: rfb.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_RFB)
+
+libbx_amigaos.la: amigaos.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_AMIGAOS)
+
+libbx_win32.la: win32.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_WIN32)
+
+libbx_macos.la: macos.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_MACOS)
+
+libbx_carbon.la: carbon.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_CARBON)
+
+libbx_nogui.la: nogui.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_NOGUI)
+
+libbx_term.la: term.lo
+ $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_TERM)
+
+# special link rules for plugins that require more than one object file
+libbx_wx.la: $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo)
+ $(LIBTOOL) --mode=link $(CXX) -module $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo) -o libbx_wx.la -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_WX)
+
+#### building DLLs for win32 (tested on cygwin only)
+bx_%.dll: %.o
+ $(CXX) $(CXXFLAGS) -shared -o $@ $< $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_WIN32)
+
+bx_wx.dll: $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT)
+ $(CXX) $(CXXFLAGS) -shared -o bx_wx.dll $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT) $(WIN32_DLL_IMPORT_LIBRARY) `wx-config --libs` -luser32 -lgdi32 -lcomdlg32 -lcomctl32
+
+bx_sdl.dll: $(GUI_OBJS_SDL)
+ $(CXX) $(CXXFLAGS) -shared -o bx_sdl.dll $(GUI_OBJS_SDL) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_SDL)
+
+bx_rfb.dll: $(GUI_OBJS_RFB)
+ $(CXX) $(CXXFLAGS) -shared -o bx_rfb.dll $(GUI_OBJS_RFB) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_RFB)
+
+# no need to build DLLs for beos.o
+# no need to build DLLs for x.o
+
+##### end DLL section
+
+clean:
+ @RMCOMMAND@ -rf .libs *.la *.a *.lo *.o *.dll
+
+dist-clean: clean
+ @RMCOMMAND@ Makefile
+
+###########################################
+# all other dependencies generated by
+# gcc -MM -I.. -I../instrument/stubs `wx-config --cxxflags` *.cc |
+# sed -e 's/\.cc/.@CPP_SUFFIX@/g'
+# gcc -MM -I.. -I../instrument/stubs `wx-config --cxxflags` *.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.
+###########################################
+amigaos.o: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h amigagui.h
+beos.o: beos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../font/vga.bitmap.h
+carbon.o: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+gui.o: gui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/bitmaps/floppya.h \
+ ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h \
+ ../gui/bitmaps/reset.h ../gui/bitmaps/power.h \
+ ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \
+ ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \
+ ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h
+keymap.o: keymap.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h
+macintosh.o: macintosh.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h ../font/vga.bitmap.h
+nogui.o: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+rfb.o: rfb.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h \
+ rfbproto.h
+sdl.o: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h sdl.h sdlkeys.h
+siminterface.o: siminterface.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h
+svga.o: svga.@CPP_SUFFIX@ ../font/vga.bitmap.h ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h
+term.o: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+textconfig.o: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h textconfig.h \
+ siminterface.h ../extplugin.h ../ltdl.h
+win32.o: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+wx.o: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/icon_bochs.h \
+ ../font/vga.bitmap.h wxmain.h
+wxdialog.o: wxdialog.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h
+wxmain.o: wxmain.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h ../extplugin.h ../ltdl.h \
+ bitmaps/cdromd.xpm bitmaps/copy.xpm bitmaps/floppya.xpm \
+ bitmaps/floppyb.xpm bitmaps/paste.xpm bitmaps/power.xpm \
+ bitmaps/reset.xpm bitmaps/snapshot.xpm bitmaps/mouse.xpm \
+ bitmaps/userbutton.xpm
+x.o: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+amigaos.lo: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h amigagui.h
+beos.lo: beos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../font/vga.bitmap.h
+carbon.lo: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+gui.lo: gui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/bitmaps/floppya.h \
+ ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h \
+ ../gui/bitmaps/reset.h ../gui/bitmaps/power.h \
+ ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \
+ ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \
+ ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h
+keymap.lo: keymap.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h
+macintosh.lo: macintosh.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h ../font/vga.bitmap.h
+nogui.lo: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+rfb.lo: rfb.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h \
+ rfbproto.h
+sdl.lo: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h sdl.h sdlkeys.h
+siminterface.lo: siminterface.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h
+svga.lo: svga.@CPP_SUFFIX@ ../font/vga.bitmap.h ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h
+term.lo: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+textconfig.lo: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h textconfig.h \
+ siminterface.h ../extplugin.h ../ltdl.h
+win32.lo: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+wx.lo: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/icon_bochs.h \
+ ../font/vga.bitmap.h wxdialog.h wxmain.h
+wxdialog.lo: wxdialog.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h
+wxmain.lo: wxmain.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h ../extplugin.h ../ltdl.h \
+ bitmaps/cdromd.xpm bitmaps/copy.xpm bitmaps/floppya.xpm \
+ bitmaps/floppyb.xpm bitmaps/paste.xpm bitmaps/power.xpm \
+ bitmaps/reset.xpm bitmaps/snapshot.xpm bitmaps/mouse.xpm \
+ bitmaps/userbutton.xpm
+x.lo: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
diff --git a/tools/ioemu/gui/bitmaps/cdromd.h b/tools/ioemu/gui/bitmaps/cdromd.h
new file mode 100644
index 0000000000..49d78e122c
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/cdromd.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdromd.h,v 1.1 2002/01/31 21:16:52 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_CDROMD_BMAP_X 32
+#define BX_CDROMD_BMAP_Y 32
+
+static const unsigned char bx_cdromd_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0e, 0x00, 0x00, 0x10, 0x12, 0x00,
+ 0x00, 0x10, 0x12, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x60, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x0c, 0x30, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0x19, 0x98, 0x00, 0x80, 0xe6, 0x67, 0x01,
+ 0x40, 0x19, 0x98, 0x02, 0x20, 0xe5, 0xa7, 0x04, 0xa0, 0x12, 0x48, 0x05,
+ 0x90, 0xca, 0x53, 0x09, 0x50, 0x25, 0xa4, 0x0a, 0x50, 0x15, 0xa8, 0x0a,
+ 0x50, 0x15, 0xa8, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 0x50, 0x15, 0xa8, 0x0a,
+ 0x50, 0x25, 0xa4, 0x0a, 0x90, 0xca, 0x53, 0x09, 0xa0, 0x12, 0x48, 0x05,
+ 0x20, 0xe5, 0xa7, 0x04, 0x40, 0x19, 0x98, 0x02, 0x80, 0xe6, 0x67, 0x01,
+ 0x00, 0x19, 0x98, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0x0c, 0x30, 0x00,
+ 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+static const unsigned char bx_cdromd_eject_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+ 0x01, 0x00, 0x00, 0x80, 0x02, 0x60, 0x0e, 0x40, 0x04, 0x10, 0x12, 0x20,
+ 0x08, 0x10, 0x12, 0x10, 0x10, 0x10, 0x12, 0x08, 0x20, 0x60, 0x0e, 0x04,
+ 0x40, 0x00, 0x00, 0x02, 0x80, 0xf0, 0x0f, 0x01, 0x00, 0x0d, 0xb0, 0x00,
+ 0x00, 0xe2, 0x47, 0x00, 0x00, 0x1d, 0xb8, 0x00, 0x80, 0xee, 0x77, 0x01,
+ 0x40, 0x19, 0x98, 0x02, 0x20, 0xe5, 0xa7, 0x04, 0xa0, 0x52, 0x4a, 0x05,
+ 0x90, 0xca, 0x53, 0x09, 0x50, 0xa5, 0xa5, 0x0a, 0x50, 0x55, 0xaa, 0x0a,
+ 0x50, 0x35, 0xac, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 0x50, 0x1d, 0xb8, 0x0a,
+ 0x50, 0x25, 0xa4, 0x0a, 0x90, 0xca, 0x53, 0x09, 0xa0, 0x13, 0xc8, 0x05,
+ 0xa0, 0xe5, 0xa7, 0x05, 0x40, 0x19, 0x98, 0x02, 0xa0, 0xe6, 0x67, 0x05,
+ 0x10, 0x19, 0x98, 0x08, 0x08, 0xe2, 0x47, 0x10, 0x04, 0x0c, 0x30, 0x20,
+ 0x02, 0xf0, 0x0f, 0x40, 0x01, 0x00, 0x00, 0x80
+ };
diff --git a/tools/ioemu/gui/bitmaps/cdromd.xpm b/tools/ioemu/gui/bitmaps/cdromd.xpm
new file mode 100644
index 0000000000..7a216b0bfe
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/cdromd.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *cdromd_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............##..###............",
+"............#....#..#...........",
+"............#....#..#...........",
+"............#....#..#...........",
+".............##..###............",
+"................................",
+"............########............",
+"..........##........##..........",
+".........#...######...#.........",
+"........#..##......##..#........",
+".......#.##..######..##.#.......",
+"......#.#..##......##..#.#......",
+".....#..#.#..######..#.#..#.....",
+".....#.#.#..#......#..#.#.#.....",
+"....#..#.#.#..####..#.#.#..#....",
+"....#.#.#.#..#....#..#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#..#....#..#.#.#.#....",
+"....#..#.#.#..####..#.#.#..#....",
+".....#.#.#..#......#..#.#.#.....",
+".....#..#.#..######..#.#..#.....",
+"......#.#..##......##..#.#......",
+".......#.##..######..##.#.......",
+"........#..##......##..#........",
+".........#...######...#.........",
+"..........##........##..........",
+"............########............",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/configbutton.h b/tools/ioemu/gui/bitmaps/configbutton.h
new file mode 100644
index 0000000000..7c51ff9b69
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/configbutton.h
@@ -0,0 +1,16 @@
+#define BX_CONFIG_BMAP_X 32
+#define BX_CONFIG_BMAP_Y 32
+
+static const unsigned char bx_config_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x01, 0xfc, 0x7f, 0xc0, 0x03,
+ 0xfc, 0xff, 0xc1, 0x03, 0xfc, 0xff, 0xc1, 0x03, 0xfc, 0x7f, 0xc0, 0x03,
+ 0x84, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03,
+ 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03,
+ 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03,
+ 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03,
+ 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xe0, 0x07, 0x80, 0x07, 0xf0, 0x0f,
+ 0x80, 0x07, 0x70, 0x0e, 0x80, 0x07, 0x30, 0x0c, 0x80, 0x07, 0x30, 0x0c,
+ 0x80, 0x07, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x27, 0xba, 0x1c,
+ 0x84, 0x68, 0x8a, 0x02, 0x84, 0xa8, 0xba, 0x32, 0x84, 0x28, 0x8b, 0x22,
+ 0x38, 0x27, 0x8a, 0x1c, 0x00, 0x00, 0x00, 0x00
+ };
diff --git a/tools/ioemu/gui/bitmaps/configbutton.xpm b/tools/ioemu/gui/bitmaps/configbutton.xpm
new file mode 100644
index 0000000000..ef2f933828
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/configbutton.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *configbutton_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"..#....................##.......",
+"..#############.......####......",
+"..###############.....####......",
+"..###############.....####......",
+"..#############.......####......",
+"..#....####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####..........######.....",
+".......####.........########....",
+".......####.........###..###....",
+".......####.........##....##....",
+".......####.........##....##....",
+".......####..........#....#.....",
+"................................",
+"...###..###..#...#.###.#..###...",
+"..#....#...#.##..#.#...#.#......",
+"..#....#...#.#.#.#.###.#.#..##..",
+"..#....#...#.#..##.#...#.#...#..",
+"...###..###..#...#.#...#..###...",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/copy.h b/tools/ioemu/gui/bitmaps/copy.h
new file mode 100644
index 0000000000..78546c979f
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/copy.h
@@ -0,0 +1,18 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: copy.h,v 1.1 2002/03/11 15:04:58 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_COPY_BMAP_X 32
+#define BX_COPY_BMAP_Y 32
+
+static unsigned char bx_copy_bmap[(BX_COPY_BMAP_X*BX_COPY_BMAP_Y)] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x80, 0x60, 0x4e, 0x02, 0x80, 0x90, 0x52, 0x02, 0x80, 0x90, 0x52, 0x02,
+ 0x00, 0x6f, 0x8e, 0x03, 0x00, 0x00, 0x02, 0x02, 0xf8, 0x3f, 0x02, 0x02,
+ 0x08, 0x20, 0xc0, 0x01, 0xe8, 0x2b, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00,
+ 0xe8, 0x2e, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0xe8, 0x39, 0x00, 0x00,
+ 0x08, 0x24, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0xe8, 0xaf, 0xff, 0x03,
+ 0x08, 0xa0, 0x00, 0x02, 0xf8, 0xbf, 0xbe, 0x02, 0x00, 0x80, 0x00, 0x02,
+ 0x80, 0x88, 0xee, 0x02, 0x80, 0x90, 0x00, 0x02, 0x00, 0xbf, 0x9e, 0x03,
+ 0x00, 0x90, 0x40, 0x02, 0x00, 0x88, 0x08, 0x02, 0x00, 0x80, 0xfe, 0x02,
+ 0x00, 0x80, 0x00, 0x02, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/bitmaps/copy.xpm b/tools/ioemu/gui/bitmaps/copy.xpm
new file mode 100644
index 0000000000..5e0138e87a
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/copy.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *copy_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"........####....................",
+".......#........................",
+".......#.....##..###..#..#......",
+".......#....#..#.#..#.#..#......",
+".......#....#..#.#..#.#..#......",
+"........####.##..###...###......",
+".................#.......#......",
+"...###########...#.......#......",
+"...#.........#........###.......",
+"...#.#####.#.#..................",
+"...#.........#..................",
+"...#.###.###.#..................",
+"...#.........#..................",
+"...#.####..###..................",
+"...#......#..#..................",
+"...#...#.....#..................",
+"...#.#######.#.###########......",
+"...#.........#.#.........#......",
+"...###########.#.#####.#.#......",
+"...............#.........#......",
+".......#...#...#.###.###.#......",
+".......#....#..#.........#......",
+"........######.#.####..###......",
+"............#..#......#..#......",
+"...........#...#...#.....#......",
+"...............#.#######.#......",
+"...............#.........#......",
+"...............###########......",
+"................................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/floppya.h b/tools/ioemu/gui/bitmaps/floppya.h
new file mode 100644
index 0000000000..86ba90f6f6
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/floppya.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppya.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_FLOPPYA_BMAP_X 32
+#define BX_FLOPPYA_BMAP_Y 32
+
+static const unsigned char bx_floppya_bmap[(BX_FLOPPYA_BMAP_X * BX_FLOPPYA_BMAP_Y)/8] = {
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x11, 0x00,
+ 0x00, 0xc0, 0x01, 0x00, 0x00, 0x60, 0x13, 0x00, 0x00, 0x60, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0x20, 0xfd, 0xbf, 0x04, 0x20, 0x01, 0x80, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+ 0xe0, 0xef, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07, 0xc0, 0xef, 0xea, 0x07,
+ 0x80, 0x57, 0xd5, 0x07, 0x00, 0xaf, 0xea, 0x07
+ };
+
+static const unsigned char bx_floppya_eject_bmap[(BX_FLOPPYA_BMAP_X * BX_FLOPPYA_BMAP_Y)/8] = {
+ 0x01, 0x80, 0x00, 0x80, 0x02, 0x40, 0x01, 0x40, 0x04, 0x40, 0x11, 0x20,
+ 0x08, 0xc0, 0x01, 0x10, 0x10, 0x60, 0x13, 0x08, 0x20, 0x60, 0x03, 0x04,
+ 0x40, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0x20, 0xff, 0xff, 0x04, 0x20, 0x05, 0xa0, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x11, 0x88, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x41, 0x82, 0x07,
+ 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x81, 0x81, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x21, 0x84, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x09, 0x90, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+ 0xf0, 0xef, 0xea, 0x0f, 0xe8, 0xf7, 0xd5, 0x17, 0xc4, 0xef, 0xea, 0x27,
+ 0x82, 0x57, 0xd5, 0x47, 0x01, 0xaf, 0xea, 0x87
+ };
diff --git a/tools/ioemu/gui/bitmaps/floppya.xpm b/tools/ioemu/gui/bitmaps/floppya.xpm
new file mode 100644
index 0000000000..637f198b9b
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/floppya.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *floppya_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"...............#................",
+"..............#.#...............",
+"..............#.#...#...........",
+"..............###...............",
+".............##.##..#...........",
+".............##.##..............",
+"................................",
+".....######################.....",
+".....####..............####.....",
+".....#..#.############.#..#.....",
+".....#..#..............#..#.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....#######.#.#.#.#.######.....",
+".....######.#####.#.#.#####.....",
+".....#######.###.#.#.######.....",
+".....######.#####.#.#.#####.....",
+"......######.###.#.#.######.....",
+".......####.#.#.#.#.#.#####.....",
+"........####.#.#.#.#.######....."
+};
diff --git a/tools/ioemu/gui/bitmaps/floppyb.h b/tools/ioemu/gui/bitmaps/floppyb.h
new file mode 100644
index 0000000000..70c7597201
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/floppyb.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppyb.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_FLOPPYB_BMAP_X 32
+#define BX_FLOPPYB_BMAP_Y 32
+
+static const unsigned char bx_floppyb_bmap[(BX_FLOPPYB_BMAP_X * BX_FLOPPYB_BMAP_Y)/8] = {
+ 0x00, 0xe0, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xe0, 0x08, 0x00,
+ 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0x20, 0xfd, 0xbf, 0x04, 0x20, 0x01, 0x80, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+ 0xe0, 0xef, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07, 0xc0, 0xef, 0xea, 0x07,
+ 0x80, 0x57, 0xd5, 0x07, 0x00, 0xaf, 0xea, 0x07
+ };
+
+static const unsigned char bx_floppyb_eject_bmap[(BX_FLOPPYB_BMAP_X * BX_FLOPPYB_BMAP_Y)/8] = {
+ 0x01, 0xe0, 0x00, 0x80, 0x02, 0x20, 0x01, 0x40, 0x04, 0xe0, 0x08, 0x20,
+ 0x08, 0x20, 0x01, 0x10, 0x10, 0x20, 0x09, 0x08, 0x20, 0xe0, 0x00, 0x04,
+ 0x40, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+ 0x20, 0xff, 0xff, 0x04, 0x20, 0x05, 0xa0, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x11, 0x88, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x41, 0x82, 0x07,
+ 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x81, 0x81, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+ 0xe0, 0x21, 0x84, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x09, 0x90, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+ 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+ 0xf0, 0xef, 0xea, 0x0f, 0xe8, 0xf7, 0xd5, 0x17, 0xc4, 0xef, 0xea, 0x27,
+ 0x82, 0x57, 0xd5, 0x47, 0x01, 0xaf, 0xea, 0x87
+ };
diff --git a/tools/ioemu/gui/bitmaps/floppyb.xpm b/tools/ioemu/gui/bitmaps/floppyb.xpm
new file mode 100644
index 0000000000..f4e20e5dcb
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/floppyb.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *floppyb_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+".............###................",
+".............#..#...............",
+".............###...#............",
+".............#..#...............",
+".............#..#..#............",
+".............###................",
+"................................",
+".....######################.....",
+".....####..............####.....",
+".....#..#.############.#..#.....",
+".....#..#..............#..#.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....#######.#.#.#.#.######.....",
+".....######.#####.#.#.#####.....",
+".....#######.###.#.#.######.....",
+".....######.#####.#.#.#####.....",
+"......######.###.#.#.######.....",
+".......####.#.#.#.#.#.#####.....",
+"........####.#.#.#.#.######....."
+};
diff --git a/tools/ioemu/gui/bitmaps/mouse.h b/tools/ioemu/gui/bitmaps/mouse.h
new file mode 100644
index 0000000000..cc8f364125
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/mouse.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: mouse.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_MOUSE_BMAP_X 32
+#define BX_MOUSE_BMAP_Y 32
+
+static unsigned char bx_mouse_bmap[(BX_MOUSE_BMAP_X * BX_MOUSE_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+ 0x00, 0x0c, 0x30, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x40, 0x00,
+ 0xf8, 0xff, 0xc0, 0x00, 0x0c, 0x80, 0xc1, 0x00, 0x24, 0x22, 0xc1, 0x00,
+ 0x74, 0x77, 0x81, 0x00, 0x74, 0x77, 0x81, 0x01, 0x74, 0x77, 0x81, 0x01,
+ 0x74, 0x77, 0x01, 0x01, 0x74, 0x77, 0x01, 0x03, 0x74, 0x77, 0x01, 0x06,
+ 0x24, 0x22, 0x01, 0x0c, 0x0c, 0x80, 0x01, 0x38, 0x04, 0x00, 0x01, 0x00,
+ 0x0c, 0x80, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x80, 0x01, 0x00,
+ 0x04, 0x00, 0x01, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+ 0x0c, 0x80, 0x01, 0x00, 0x14, 0x40, 0x01, 0x00, 0x2c, 0xa0, 0x01, 0x00,
+ 0x54, 0x55, 0x01, 0x00, 0xac, 0xaa, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+static unsigned char bx_nomouse_bmap[(BX_MOUSE_BMAP_X * BX_MOUSE_BMAP_Y)/8] = {
+ 0x01, 0x00, 0x00, 0x80, 0x02, 0xe0, 0x07, 0x40, 0x04, 0xf8, 0x1f, 0x20,
+ 0x08, 0x0c, 0x30, 0x10, 0x10, 0x06, 0x60, 0x08, 0x20, 0x06, 0x40, 0x04,
+ 0xf8, 0xff, 0xc0, 0x02, 0x8c, 0x80, 0xc1, 0x01, 0x24, 0x23, 0xc1, 0x00,
+ 0x74, 0x77, 0xc1, 0x00, 0x74, 0x77, 0xa1, 0x01, 0x74, 0x7f, 0x91, 0x01,
+ 0x74, 0x77, 0x09, 0x01, 0x74, 0x77, 0x05, 0x03, 0x74, 0x77, 0x03, 0x06,
+ 0x24, 0xa2, 0x01, 0x0c, 0x0c, 0x80, 0x01, 0x38, 0x04, 0x40, 0x03, 0x00,
+ 0x0c, 0xa0, 0x05, 0x00, 0x04, 0x10, 0x09, 0x00, 0x0c, 0x88, 0x11, 0x00,
+ 0x04, 0x04, 0x21, 0x00, 0x0c, 0x82, 0x41, 0x00, 0x04, 0x01, 0x81, 0x00,
+ 0x8c, 0x80, 0x01, 0x01, 0x54, 0x40, 0x01, 0x02, 0x2c, 0xa0, 0x01, 0x04,
+ 0x54, 0x55, 0x01, 0x08, 0xac, 0xaa, 0x01, 0x10, 0xfc, 0xff, 0x00, 0x20,
+ 0x02, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x80
+ };
diff --git a/tools/ioemu/gui/bitmaps/mouse.xpm b/tools/ioemu/gui/bitmaps/mouse.xpm
new file mode 100644
index 0000000000..dea33275a2
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/mouse.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *mouse_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............######.............",
+"...........##########...........",
+"..........##........##..........",
+".........##..........##.........",
+".........##...........#.........",
+"...#############......##........",
+"..##...........##.....##........",
+"..#..#...#...#..#.....##........",
+"..#.###.###.###.#......#........",
+"..#.###.###.###.#......##.......",
+"..#.###.###.###.#......##.......",
+"..#.###.###.###.#.......#.......",
+"..#.###.###.###.#.......##......",
+"..#.###.###.###.#........##.....",
+"..#..#...#...#..#.........##....",
+"..##...........##..........###..",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.#.........#.#...............",
+"..##.#.......#.##...............",
+"..#.#.#.#.#.#.#.#...............",
+"..##.#.#.#.#.#.##...............",
+"...#############................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/paste.h b/tools/ioemu/gui/bitmaps/paste.h
new file mode 100644
index 0000000000..f574dad3dc
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/paste.h
@@ -0,0 +1,18 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: paste.h,v 1.1 2002/03/11 15:04:58 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_PASTE_BMAP_X 32
+#define BX_PASTE_BMAP_Y 32
+
+static unsigned char bx_paste_bmap[(BX_PASTE_BMAP_X*BX_PASTE_BMAP_Y)] = {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x10, 0x00, 0x20, 0x9a, 0x93, 0x03,
+ 0x20, 0x66, 0x78, 0x04, 0xe0, 0xa5, 0xd3, 0x07, 0x20, 0x24, 0x54, 0x00,
+ 0x20, 0xd8, 0x93, 0x03, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x02, 0x00,
+ 0x00, 0x7c, 0x3f, 0x00, 0xc0, 0x83, 0xc1, 0x03, 0x20, 0x02, 0x40, 0x04,
+ 0x20, 0x01, 0x80, 0x04, 0x20, 0x01, 0x80, 0x04, 0xa0, 0xff, 0xff, 0x05,
+ 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x20, 0xf8, 0x3f, 0x04,
+ 0x20, 0x08, 0x20, 0x04, 0x20, 0xe8, 0x2b, 0x04, 0x20, 0x08, 0x20, 0x04,
+ 0x20, 0xe8, 0x2e, 0x04, 0x20, 0x08, 0x20, 0x04, 0x20, 0xe8, 0x39, 0x04,
+ 0x20, 0x08, 0x24, 0x04, 0x20, 0x88, 0x20, 0x04, 0x20, 0xe8, 0x2f, 0x04,
+ 0x20, 0x08, 0x20, 0x04, 0x20, 0xf8, 0x3f, 0x04, 0x20, 0x00, 0x00, 0x04,
+ 0xc0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/bitmaps/paste.xpm b/tools/ioemu/gui/bitmaps/paste.xpm
new file mode 100644
index 0000000000..5c83b01dc7
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/paste.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *paste_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".....####...........#...........",
+".....#...#.##..###..#..###......",
+".....#...##..##....####...#.....",
+".....####.#..#.###..#.#####.....",
+".....#....#..#....#.#.#.........",
+".....#.....##.####..#..###......",
+"...............##...............",
+"..............##.#..............",
+"..........#####.######..........",
+"......####.....##.....####......",
+".....#...#............#...#.....",
+".....#..#..............#..#.....",
+".....#..#..............#..#.....",
+".....#.##################.#.....",
+".....#....................#.....",
+".....#....................#.....",
+".....#.....###########....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.#####.#.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.###.###.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.####..###....#.....",
+".....#.....#......#..#....#.....",
+".....#.....#...#.....#....#.....",
+".....#.....#.#######.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....###########....#.....",
+".....#....................#.....",
+"......####################......",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/power.h b/tools/ioemu/gui/bitmaps/power.h
new file mode 100644
index 0000000000..ba72d6a31b
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/power.h
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: power.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_POWER_BMAP_X 32
+#define BX_POWER_BMAP_Y 32
+
+static const unsigned char bx_power_bmap[(BX_POWER_BMAP_X * BX_POWER_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+ 0x24, 0x67, 0x66, 0x34, 0xa4, 0x28, 0x92, 0x48, 0x9a, 0xa8, 0xfa, 0x04,
+ 0x82, 0x64, 0x09, 0x04, 0x07, 0xa3, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0x03, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x0f, 0x1e, 0x00,
+ 0x80, 0x03, 0x38, 0x00, 0xc0, 0x00, 0x60, 0x00, 0xe0, 0xe0, 0xe0, 0x00,
+ 0x60, 0xe0, 0xc0, 0x00, 0x70, 0xe0, 0xc0, 0x01, 0x30, 0xe0, 0x80, 0x01,
+ 0x30, 0xe0, 0x80, 0x01, 0x30, 0xe0, 0x80, 0x01, 0x30, 0xe0, 0x80, 0x01,
+ 0x30, 0xe0, 0x80, 0x01, 0x70, 0xe0, 0xc0, 0x01, 0x60, 0xe0, 0xc0, 0x00,
+ 0xe0, 0xe0, 0xe0, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x80, 0x03, 0x38, 0x00,
+ 0x00, 0x0f, 0x1e, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xf8, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
diff --git a/tools/ioemu/gui/bitmaps/power.xpm b/tools/ioemu/gui/bitmaps/power.xpm
new file mode 100644
index 0000000000..ff7e9e8367
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/power.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *power_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"................................",
+".####...........................",
+"..#..#..###..##..##..##...#.##..",
+"..#..#.#...#.#...#..#..#...#..#.",
+".#.##..#...#.#.#.#.#####..#.....",
+".#.....#..#..##.#..#......#.....",
+"###.....##...#.#....###..###....",
+"................................",
+"...........#######..............",
+".........###########............",
+"........####.....####...........",
+".......###.........###..........",
+"......##.............##.........",
+".....###.....###.....###........",
+".....##......###......##........",
+"....###......###......###.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....###......###......###.......",
+".....##......###......##........",
+".....###.....###.....###........",
+"......##.............##.........",
+".......###.........###..........",
+"........####.....####...........",
+".........###########............",
+"...........#######..............",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/reset.h b/tools/ioemu/gui/bitmaps/reset.h
new file mode 100644
index 0000000000..046f80aeb8
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/reset.h
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: reset.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_RESET_BMAP_X 32
+#define BX_RESET_BMAP_Y 32
+
+static const unsigned char bx_reset_bmap[(BX_RESET_BMAP_X * BX_RESET_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3c, 0x00, 0x00, 0x10,
+ 0x48, 0x0c, 0xc7, 0x7c, 0x48, 0x92, 0x20, 0x11, 0x34, 0x1f, 0xf3, 0x09,
+ 0x24, 0x41, 0x12, 0x48, 0x6e, 0xce, 0xe1, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+ 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+ 0x00, 0xc7, 0x38, 0x00, 0x00, 0x87, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00,
+ 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00,
+ 0x00, 0x07, 0x38, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00,
+ 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
diff --git a/tools/ioemu/gui/bitmaps/reset.xpm b/tools/ioemu/gui/bitmaps/reset.xpm
new file mode 100644
index 0000000000..d47ea6cbfd
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/reset.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *reset_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............................#..",
+"..####......................#...",
+"...#..#...##....###...##..#####.",
+"...#..#..#..#..#.....#..#...#...",
+"..#.##..#####...##..#####..#....",
+"..#..#..#.....#..#..#......#..#.",
+".###.##..###..###....###....##..",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"...............#................",
+"..............##................",
+".............#######............",
+"............#########...........",
+".............#########..........",
+"........###...##...###..........",
+"........###....#...###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........##############..........",
+".........############...........",
+"..........##########............",
+"................................",
+"................................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/snapshot.h b/tools/ioemu/gui/bitmaps/snapshot.h
new file mode 100644
index 0000000000..cced8ff9e7
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/snapshot.h
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: snapshot.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_SNAPSHOT_BMAP_X 32
+#define BX_SNAPSHOT_BMAP_Y 32
+
+static const unsigned char bx_snapshot_bmap[(BX_SNAPSHOT_BMAP_X * BX_SNAPSHOT_BMAP_Y)/8] = {
+ 0x00, 0x00, 0x20, 0x40, 0x77, 0xe6, 0xee, 0xec, 0x91, 0xa8, 0xa2, 0x52,
+ 0x96, 0xac, 0xac, 0x52, 0x94, 0xaa, 0xa8, 0x52, 0xb7, 0xee, 0xae, 0xcc,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x7c, 0x0f, 0x10, 0x1f, 0xfa, 0x07, 0xa0, 0x2e, 0x42, 0x07, 0xa0, 0x50,
+ 0xa3, 0x03, 0xc0, 0xe0, 0xff, 0xee, 0x77, 0xbf, 0x01, 0xf9, 0x9f, 0x40,
+ 0x01, 0x1d, 0xb8, 0xa0, 0xff, 0xe5, 0xa7, 0xff, 0xff, 0xba, 0x5a, 0xff,
+ 0xff, 0x55, 0xb5, 0xff, 0xff, 0x8d, 0xaa, 0xff, 0xff, 0x16, 0x55, 0xff,
+ 0xff, 0xa2, 0x6a, 0xff, 0xff, 0x46, 0x55, 0xff, 0xff, 0xaa, 0x6a, 0xff,
+ 0xff, 0x56, 0x55, 0xff, 0xfe, 0xae, 0x6a, 0x7f, 0x00, 0x55, 0xb5, 0x00,
+ 0x00, 0xbd, 0xba, 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0xe4, 0x27, 0x00,
+ 0x00, 0x18, 0x18, 0x00, 0x00, 0xe0, 0x07, 0x00
+ };
diff --git a/tools/ioemu/gui/bitmaps/snapshot.xpm b/tools/ioemu/gui/bitmaps/snapshot.xpm
new file mode 100644
index 0000000000..c17305beb5
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/snapshot.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char *snapshot_xpm[] = {
+/* width height num_colors chars_per_pixel */
+" 32 32 2 1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+".....................#........#.",
+"###.###..##..###.###.###..##.###",
+"#...#..#...#.#.#.#...#.#.#..#.#.",
+".##.#..#..##.#.#..##.#.#.#..#.#.",
+"..#.#..#.#.#.#.#...#.#.#.#..#.#.",
+"###.##.#.###.###.###.#.#..##..##",
+".............#..................",
+"............########............",
+"...........#........#...........",
+"..#####.####........#...#####...",
+".#.########..........#.#.###.#..",
+".#....#.###..........#.#....#.#.",
+"##...#.###............##.....###",
+"########.###.######.###.######.#",
+"#.......#..##########..#......#.",
+"#.......#.###......###.#.....#.#",
+"#########.#..######..#.#########",
+"########.#.###.#.#.##.#.########",
+"#########.#.#.#.#.#.##.#########",
+"#########.##...#.#.#.#.#########",
+"########.##.#...#.#.#.#.########",
+"########.#...#.#.#.#.##.########",
+"########.##...#.#.#.#.#.########",
+"########.#.#.#.#.#.#.##.########",
+"########.##.#.#.#.#.#.#.########",
+".#######.###.#.#.#.#.##.#######.",
+"........#.#.#.#.#.#.##.#........",
+"........#.####.#.#.###.#........",
+".........#.##########.#.........",
+"..........#..######..#..........",
+"...........##......##...........",
+".............######............."
+};
diff --git a/tools/ioemu/gui/bitmaps/userbutton.h b/tools/ioemu/gui/bitmaps/userbutton.h
new file mode 100644
index 0000000000..c93f50664b
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/userbutton.h
@@ -0,0 +1,19 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: userbutton.h,v 1.1 2002/08/09 06:16:43 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_USER_BMAP_X 32
+#define BX_USER_BMAP_Y 32
+
+static const unsigned char bx_user_bmap[BX_USER_BMAP_X*BX_USER_BMAP_Y/8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x84, 0x78, 0x9e, 0x07, 0x84, 0x04, 0x82, 0x08,
+ 0x84, 0x04, 0x82, 0x08, 0x84, 0x38, 0x9e, 0x07, 0x84, 0x40, 0x82, 0x01,
+ 0x84, 0x40, 0x82, 0x06, 0x78, 0x3c, 0x9e, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1c,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x02, 0x00, 0x00, 0x20,
+ 0xaa, 0xaa, 0x2a, 0x2a, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20,
+ 0xaa, 0xaa, 0xaa, 0x2a, 0x52, 0x55, 0x11, 0x25, 0xaa, 0xaa, 0xaa, 0x2a,
+ 0x52, 0x55, 0x01, 0x25, 0xaa, 0xaa, 0x82, 0x2a, 0x52, 0x55, 0x11, 0x25,
+ 0xaa, 0xbf, 0xaa, 0x2a, 0x02, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
diff --git a/tools/ioemu/gui/bitmaps/userbutton.xpm b/tools/ioemu/gui/bitmaps/userbutton.xpm
new file mode 100644
index 0000000000..a5d1f99eec
--- /dev/null
+++ b/tools/ioemu/gui/bitmaps/userbutton.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char *userbutton_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 2 1",
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"..#....#...####..####..####.....",
+"..#....#..#......#.....#...#....",
+"..#....#..#......#.....#...#....",
+"..#....#...###...####..####.....",
+"..#....#......#..#.....##.......",
+"..#....#......#..#.....#.##.....",
+"...####...####...####..#...#....",
+"................................",
+"................................",
+".............................#..",
+"..........................###...",
+".........................#......",
+"........................#.......",
+".......................#........",
+".......................#........",
+".#############################..",
+".#...........................#..",
+".#.#.#.#.#.#.#.#.#.#.#...#.#.#..",
+".#...........................#..",
+".#...........................#..",
+".#.#.#.#.#.#.#.#.#.#.#.#.#.#.#..",
+".#..#.#.#.#.#.#.#...#...#.#..#..",
+".#.#.#.#.#.#.#.#.#.#.#.#.#.#.#..",
+".#..#.#.#.#.#.#.#.......#.#..#..",
+".#.#.#.#.#.#.#.#.#.....#.#.#.#..",
+".#..#.#.#.#.#.#.#...#...#.#..#..",
+".#.#.#.#######.#.#.#.#.#.#.#.#..",
+".#...........................#..",
+".#############################..",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/gui.cc b/tools/ioemu/gui/gui.cc
new file mode 100644
index 0000000000..a6cd30732a
--- /dev/null
+++ b/tools/ioemu/gui/gui.cc
@@ -0,0 +1,592 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gui.cc,v 1.73 2003/12/18 20:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#include <signal.h>
+#include "bochs.h"
+#include "gui/bitmaps/floppya.h"
+#include "gui/bitmaps/floppyb.h"
+#include "gui/bitmaps/mouse.h"
+#include "gui/bitmaps/reset.h"
+#include "gui/bitmaps/power.h"
+#include "gui/bitmaps/snapshot.h"
+#include "gui/bitmaps/copy.h"
+#include "gui/bitmaps/paste.h"
+#include "gui/bitmaps/configbutton.h"
+#include "gui/bitmaps/cdromd.h"
+#include "gui/bitmaps/userbutton.h"
+#if BX_WITH_MACOS
+# include <Disks.h>
+#endif
+
+bx_gui_c *bx_gui = NULL;
+
+#define BX_GUI_THIS bx_gui->
+#define LOG_THIS BX_GUI_THIS
+
+bx_gui_c::bx_gui_c(void)
+{
+ put("GUI"); // Init in specific_init
+ settype(GUILOG);
+}
+
+bx_gui_c::~bx_gui_c()
+{
+}
+
+ void
+bx_gui_c::init(int argc, char **argv, unsigned tilewidth, unsigned tileheight)
+{
+ specific_init(argc, argv, tilewidth, tileheight, BX_HEADER_BAR_Y);
+
+ // Define some bitmaps to use in the headerbar
+ BX_GUI_THIS floppyA_bmap_id = create_bitmap(bx_floppya_bmap,
+ BX_FLOPPYA_BMAP_X, BX_FLOPPYA_BMAP_Y);
+ BX_GUI_THIS floppyA_eject_bmap_id = create_bitmap(bx_floppya_eject_bmap,
+ BX_FLOPPYA_BMAP_X, BX_FLOPPYA_BMAP_Y);
+ BX_GUI_THIS floppyB_bmap_id = create_bitmap(bx_floppyb_bmap,
+ BX_FLOPPYB_BMAP_X, BX_FLOPPYB_BMAP_Y);
+ BX_GUI_THIS floppyB_eject_bmap_id = create_bitmap(bx_floppyb_eject_bmap,
+ BX_FLOPPYB_BMAP_X, BX_FLOPPYB_BMAP_Y);
+ BX_GUI_THIS cdromD_bmap_id = create_bitmap(bx_cdromd_bmap,
+ BX_CDROMD_BMAP_X, BX_CDROMD_BMAP_Y);
+ BX_GUI_THIS cdromD_eject_bmap_id = create_bitmap(bx_cdromd_eject_bmap,
+ BX_CDROMD_BMAP_X, BX_CDROMD_BMAP_Y);
+ BX_GUI_THIS mouse_bmap_id = create_bitmap(bx_mouse_bmap,
+ BX_MOUSE_BMAP_X, BX_MOUSE_BMAP_Y);
+ BX_GUI_THIS nomouse_bmap_id = create_bitmap(bx_nomouse_bmap,
+ BX_MOUSE_BMAP_X, BX_MOUSE_BMAP_Y);
+
+
+ BX_GUI_THIS power_bmap_id = create_bitmap(bx_power_bmap, BX_POWER_BMAP_X, BX_POWER_BMAP_Y);
+ BX_GUI_THIS reset_bmap_id = create_bitmap(bx_reset_bmap, BX_RESET_BMAP_X, BX_RESET_BMAP_Y);
+ BX_GUI_THIS snapshot_bmap_id = create_bitmap(bx_snapshot_bmap, BX_SNAPSHOT_BMAP_X, BX_SNAPSHOT_BMAP_Y);
+ BX_GUI_THIS copy_bmap_id = create_bitmap(bx_copy_bmap, BX_COPY_BMAP_X, BX_COPY_BMAP_Y);
+ BX_GUI_THIS paste_bmap_id = create_bitmap(bx_paste_bmap, BX_PASTE_BMAP_X, BX_PASTE_BMAP_Y);
+ BX_GUI_THIS config_bmap_id = create_bitmap(bx_config_bmap, BX_CONFIG_BMAP_X, BX_CONFIG_BMAP_Y);
+ BX_GUI_THIS user_bmap_id = create_bitmap(bx_user_bmap, BX_USER_BMAP_X, BX_USER_BMAP_Y);
+
+
+ // Add the initial bitmaps to the headerbar, and enable callback routine, for use
+ // when that bitmap is clicked on
+
+ // Floppy A:
+ BX_GUI_THIS floppyA_status = DEV_floppy_get_media_status(0);
+ if (BX_GUI_THIS floppyA_status)
+ BX_GUI_THIS floppyA_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyA_bmap_id,
+ BX_GRAVITY_LEFT, floppyA_handler);
+ else
+ BX_GUI_THIS floppyA_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyA_eject_bmap_id,
+ BX_GRAVITY_LEFT, floppyA_handler);
+
+ // Floppy B:
+ BX_GUI_THIS floppyB_status = DEV_floppy_get_media_status(1);
+ if (BX_GUI_THIS floppyB_status)
+ BX_GUI_THIS floppyB_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyB_bmap_id,
+ BX_GRAVITY_LEFT, floppyB_handler);
+ else
+ BX_GUI_THIS floppyB_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyB_eject_bmap_id,
+ BX_GRAVITY_LEFT, floppyB_handler);
+
+ // CDROM,
+ // valgrinds says that the harddrive object is not be initialised yet,
+ // so we just set the bitmap to ejected for now
+#if 0
+ if (DEV_hd_present()) {
+ Bit32u handle = DEV_hd_get_first_cd_handle();
+ BX_GUI_THIS cdromD_status = DEV_hd_get_cd_media_status(handle);
+ }
+
+ if (BX_GUI_THIS cdromD_status)
+ BX_GUI_THIS cdromD_hbar_id = headerbar_bitmap(BX_GUI_THIS cdromD_bmap_id,
+ BX_GRAVITY_LEFT, cdromD_handler);
+ else
+#endif
+ BX_GUI_THIS cdromD_hbar_id = headerbar_bitmap(BX_GUI_THIS cdromD_eject_bmap_id,
+ BX_GRAVITY_LEFT, cdromD_handler);
+
+ // Mouse button
+ if (bx_options.Omouse_enabled->get ())
+ BX_GUI_THIS mouse_hbar_id = headerbar_bitmap(BX_GUI_THIS mouse_bmap_id,
+ BX_GRAVITY_LEFT, toggle_mouse_enable);
+ else
+ BX_GUI_THIS mouse_hbar_id = headerbar_bitmap(BX_GUI_THIS nomouse_bmap_id,
+ BX_GRAVITY_LEFT, toggle_mouse_enable);
+
+ // These are the buttons on the right side. They are created in order
+ // of right to left.
+
+ // Power button
+ BX_GUI_THIS power_hbar_id = headerbar_bitmap(BX_GUI_THIS power_bmap_id,
+ BX_GRAVITY_RIGHT, power_handler);
+ // Reset button
+ BX_GUI_THIS reset_hbar_id = headerbar_bitmap(BX_GUI_THIS reset_bmap_id,
+ BX_GRAVITY_RIGHT, reset_handler);
+ // Configure button
+ BX_GUI_THIS config_hbar_id = headerbar_bitmap(BX_GUI_THIS config_bmap_id,
+ BX_GRAVITY_RIGHT, config_handler);
+ // Snapshot button
+ BX_GUI_THIS snapshot_hbar_id = headerbar_bitmap(BX_GUI_THIS snapshot_bmap_id,
+ BX_GRAVITY_RIGHT, snapshot_handler);
+ // Paste button
+ BX_GUI_THIS paste_hbar_id = headerbar_bitmap(BX_GUI_THIS paste_bmap_id,
+ BX_GRAVITY_RIGHT, paste_handler);
+ // Copy button
+ BX_GUI_THIS copy_hbar_id = headerbar_bitmap(BX_GUI_THIS copy_bmap_id,
+ BX_GRAVITY_RIGHT, copy_handler);
+ // User button
+ BX_GUI_THIS user_hbar_id = headerbar_bitmap(BX_GUI_THIS user_bmap_id,
+ BX_GRAVITY_RIGHT, userbutton_handler);
+
+ if(bx_options.Otext_snapshot_check->get()) {
+ bx_pc_system.register_timer(this, bx_gui_c::snapshot_checker, (unsigned) 1000000, 1, 1, "snap_chk");
+ }
+
+ BX_GUI_THIS charmap_updated = 0;
+
+ show_headerbar();
+}
+
+void
+bx_gui_c::update_drive_status_buttons (void) {
+ BX_GUI_THIS floppyA_status =
+ DEV_floppy_get_media_status(0)
+ && bx_options.floppya.Ostatus->get ();
+ BX_GUI_THIS floppyB_status =
+ DEV_floppy_get_media_status(1)
+ && bx_options.floppyb.Ostatus->get ();
+ Bit32u handle = DEV_hd_get_first_cd_handle();
+ BX_GUI_THIS cdromD_status = DEV_hd_get_cd_media_status(handle);
+ if (BX_GUI_THIS floppyA_status)
+ replace_bitmap(BX_GUI_THIS floppyA_hbar_id, BX_GUI_THIS floppyA_bmap_id);
+ else {
+#if BX_WITH_MACOS
+ // If we are using the Mac floppy driver, eject the disk
+ // from the floppy drive. This doesn't work in MacOS X.
+ if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+ DiskEject(1);
+#endif
+ replace_bitmap(BX_GUI_THIS floppyA_hbar_id, BX_GUI_THIS floppyA_eject_bmap_id);
+ }
+ if (BX_GUI_THIS floppyB_status)
+ replace_bitmap(BX_GUI_THIS floppyB_hbar_id, BX_GUI_THIS floppyB_bmap_id);
+ else {
+#if BX_WITH_MACOS
+ // If we are using the Mac floppy driver, eject the disk
+ // from the floppy drive. This doesn't work in MacOS X.
+ if (!strcmp(bx_options.floppyb.Opath->getptr (), SuperDrive))
+ DiskEject(1);
+#endif
+ replace_bitmap(BX_GUI_THIS floppyB_hbar_id, BX_GUI_THIS floppyB_eject_bmap_id);
+ }
+ if (BX_GUI_THIS cdromD_status)
+ replace_bitmap(BX_GUI_THIS cdromD_hbar_id, BX_GUI_THIS cdromD_bmap_id);
+ else {
+ replace_bitmap(BX_GUI_THIS cdromD_hbar_id, BX_GUI_THIS cdromD_eject_bmap_id);
+ }
+}
+
+ void
+bx_gui_c::floppyA_handler(void)
+{
+ if (bx_options.floppya.Odevtype->get() == BX_FLOPPY_NONE)
+ return; // no primary floppy device present
+#ifdef WIN32
+ if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+ "rfb")) {
+ // instead of just toggling the status, call win32dialog to bring up
+ // a dialog asking what disk image you want to switch to.
+ int ret = SIM->ask_param (BXP_FLOPPYA_PATH);
+ if (ret > 0) {
+ BX_GUI_THIS update_drive_status_buttons ();
+ }
+ return;
+ }
+#endif
+ BX_GUI_THIS floppyA_status = !BX_GUI_THIS floppyA_status;
+ DEV_floppy_set_media_status(0, BX_GUI_THIS floppyA_status);
+ BX_GUI_THIS update_drive_status_buttons ();
+}
+
+ void
+bx_gui_c::floppyB_handler(void)
+{
+ if (bx_options.floppyb.Odevtype->get() == BX_FLOPPY_NONE)
+ return; // no secondary floppy device present
+#ifdef WIN32
+ if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+ "rfb")) {
+ // instead of just toggling the status, call win32dialog to bring up
+ // a dialog asking what disk image you want to switch to.
+ int ret = SIM->ask_param (BXP_FLOPPYB_PATH);
+ if (ret > 0) {
+ BX_GUI_THIS update_drive_status_buttons ();
+ }
+ return;
+ }
+#endif
+ BX_GUI_THIS floppyB_status = !BX_GUI_THIS floppyB_status;
+ DEV_floppy_set_media_status(1, BX_GUI_THIS floppyB_status);
+ BX_GUI_THIS update_drive_status_buttons ();
+}
+
+ void
+bx_gui_c::cdromD_handler(void)
+{
+ Bit32u handle = DEV_hd_get_first_cd_handle();
+ if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+ "wx")) {
+ // instead of just toggling the status, call wxWindows to bring up
+ // a dialog asking what disk image you want to switch to.
+ // BBD: for now, find the first cdrom and call ask_param on that.
+ // Since we could have multiple cdroms now, maybe we should be adding
+ // one cdrom button for each?
+ bx_param_c *cdrom = SIM->get_first_cdrom ();
+ if (cdrom == NULL)
+ return; // no cdrom found
+ int ret = SIM->ask_param (cdrom->get_id ());
+ if (ret < 0) return; // cancelled
+ // eject and then insert the disk. If the new path is invalid,
+ // the status will return 0.
+ unsigned status = DEV_hd_set_cd_media_status(handle, 0);
+ printf ("eject disk, new_status is %d\n", status);
+ status = DEV_hd_set_cd_media_status(handle, 1);
+ printf ("insert disk, new_status is %d\n", status);
+ fflush (stdout);
+ BX_GUI_THIS cdromD_status = status;
+ } else {
+ BX_GUI_THIS cdromD_status =
+ DEV_hd_set_cd_media_status(handle, !BX_GUI_THIS cdromD_status);
+ }
+ BX_GUI_THIS update_drive_status_buttons ();
+}
+
+ void
+bx_gui_c::reset_handler(void)
+{
+ BX_INFO(( "system RESET callback." ));
+ bx_pc_system.ResetSignal( PCS_SET ); /* XXX is this right? */
+ for (int i=0; i<BX_SMP_PROCESSORS; i++)
+ BX_CPU(i)->reset(BX_RESET_HARDWARE);
+}
+
+ void
+bx_gui_c::power_handler(void)
+{
+ // the user pressed power button, so there's no doubt they want bochs
+ // to quit. Change panics to fatal for the GUI and then do a panic.
+ bx_user_quit = 1;
+ LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+ BX_PANIC (("POWER button turned off."));
+ // shouldn't reach this point, but if you do, QUIT!!!
+ fprintf (stderr, "Bochs is exiting because you pressed the power button.\n");
+ BX_EXIT (1);
+}
+
+Bit32s
+bx_gui_c::make_text_snapshot (char **snapshot, Bit32u *length)
+{
+ Bit8u* raw_snap = NULL;
+ char *clean_snap;
+ unsigned line_addr, txt_addr, txHeight, txWidth;
+
+ DEV_vga_get_text_snapshot(&raw_snap, &txHeight, &txWidth);
+ if (txHeight <= 0) return -1;
+ clean_snap = (char*) malloc(txHeight*(txWidth+2)+1);
+ txt_addr = 0;
+ for (unsigned i=0; i<txHeight; i++) {
+ line_addr = i * txWidth * 2;
+ for (unsigned j=0; j<(txWidth*2); j+=2) {
+ clean_snap[txt_addr++] = raw_snap[line_addr+j];
+ }
+ while ((txt_addr > 0) && (clean_snap[txt_addr-1] == ' ')) txt_addr--;
+#ifdef WIN32
+ if(!(bx_options.Otext_snapshot_check->get())) {
+ clean_snap[txt_addr++] = 13;
+ }
+#endif
+ clean_snap[txt_addr++] = 10;
+ }
+ clean_snap[txt_addr] = 0;
+ *snapshot = clean_snap;
+ *length = txt_addr;
+ return 0;
+}
+
+// create a text snapshot and copy to the system clipboard. On guis that
+// we haven't figured out how to support yet, dump to a file instead.
+ void
+bx_gui_c::copy_handler(void)
+{
+ Bit32u len;
+ char *text_snapshot;
+ if (make_text_snapshot (&text_snapshot, &len) < 0) {
+ BX_INFO(( "copy button failed, mode not implemented"));
+ return;
+ }
+ if (!BX_GUI_THIS set_clipboard_text(text_snapshot, len)) {
+ // platform specific code failed, use portable code instead
+ FILE *fp = fopen("copy.txt", "w");
+ fwrite(text_snapshot, 1, len, fp);
+ fclose(fp);
+ }
+ free(text_snapshot);
+}
+
+// Check the current text snapshot against file snapchk.txt.
+ void
+bx_gui_c::snapshot_checker(void * this_ptr)
+{
+ char filename[BX_PATHNAME_LEN];
+ strcpy(filename,"snapchk.txt");
+ FILE *fp = fopen(filename, "rb");
+ if(fp) {
+ char *text_snapshot;
+ Bit32u len;
+ if (make_text_snapshot (&text_snapshot, &len) < 0) {
+ return;
+ }
+ char *compare_snapshot = (char *) malloc((len+1) * sizeof(char));
+ fread(compare_snapshot, 1, len, fp);
+ fclose(fp);
+ strcpy(filename,"snapmask.txt");
+ fp=fopen(filename, "rb");
+ if(fp) {
+ char *mask_snapshot = (char *) malloc((len+1) * sizeof(char));
+ unsigned i;
+ bx_bool flag = 1;
+ fread(mask_snapshot, 1, len, fp);
+ fclose(fp);
+ for(i=0;i<len;i++) {
+ if((text_snapshot[i] != compare_snapshot[i]) &&
+ (compare_snapshot[i] == mask_snapshot[i])) {
+ flag = 0;
+ break;
+ }
+ }
+ if(flag) {
+ if(!memcmp(text_snapshot,compare_snapshot,len)) {
+ BX_PASS(("Test Passed."));
+ } else {
+ BX_PASS(("Test Passed with Mask."));
+ }
+ }
+ } else {
+ if(!memcmp(text_snapshot,compare_snapshot,len)) {
+ BX_PASS(("Test Passed."));
+ }
+ }
+ free(compare_snapshot);
+ free(text_snapshot);
+ }
+}
+
+// create a text snapshot and dump it to a file
+ void
+bx_gui_c::snapshot_handler(void)
+{
+ char *text_snapshot;
+ Bit32u len;
+ if (make_text_snapshot (&text_snapshot, &len) < 0) {
+ BX_ERROR(( "snapshot button failed, mode not implemented"));
+ return;
+ }
+ //FIXME
+ char filename[BX_PATHNAME_LEN];
+#ifdef WIN32
+ if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+ "rfb")) {
+#else
+ if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+ "wx")) {
+#endif
+ int ret = SIM->ask_filename (filename, sizeof(filename),
+ "Save snapshot as...", "snapshot.txt",
+ bx_param_string_c::SAVE_FILE_DIALOG);
+ if (ret < 0) { // cancelled
+ free(text_snapshot);
+ return;
+ }
+ } else {
+ strcpy (filename, "snapshot.txt");
+ }
+ FILE *fp = fopen(filename, "wb");
+ fwrite(text_snapshot, 1, len, fp);
+ fclose(fp);
+ free(text_snapshot);
+}
+
+// Read ASCII chars from the system clipboard and paste them into bochs.
+// Note that paste cannot work with the key mapping tables loaded.
+ void
+bx_gui_c::paste_handler(void)
+{
+ Bit32s nbytes;
+ Bit8u *bytes;
+ if (!bx_keymap.isKeymapLoaded ()) {
+ BX_ERROR (("keyboard_mapping disabled, so paste cannot work"));
+ return;
+ }
+ if (!BX_GUI_THIS get_clipboard_text(&bytes, &nbytes)) {
+ BX_ERROR (("paste not implemented on this platform"));
+ return;
+ }
+ BX_INFO (("pasting %d bytes", nbytes));
+ DEV_kbd_paste_bytes (bytes, nbytes);
+}
+
+
+ void
+bx_gui_c::config_handler(void)
+{
+ if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+ "rfb")) {
+ SIM->configuration_interface (NULL, CI_RUNTIME_CONFIG);
+ }
+}
+
+ void
+bx_gui_c::toggle_mouse_enable(void)
+{
+ int old = bx_options.Omouse_enabled->get ();
+ BX_DEBUG (("toggle mouse_enabled, now %d", !old));
+ bx_options.Omouse_enabled->set (!old);
+}
+
+ void
+bx_gui_c::userbutton_handler(void)
+{
+ unsigned shortcut[4];
+ unsigned p;
+ char *user_shortcut;
+ int i, len, ret = 1;
+
+ len = 0;
+#ifdef WIN32
+ if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+ "rfb")) {
+#else
+ if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+ "wx")) {
+#endif
+ ret = SIM->ask_param (BXP_USER_SHORTCUT);
+ }
+ user_shortcut = bx_options.Ouser_shortcut->getptr();
+ if ((ret > 0) && user_shortcut[0] && (strcmp(user_shortcut, "none"))) {
+ len = 0;
+ p = 0;
+ while ((p < strlen(user_shortcut)) && (len < 3)) {
+ if (!strncmp(user_shortcut+p, "alt", 3)) {
+ shortcut[len++] = BX_KEY_ALT_L;
+ p += 3;
+ } else if (!strncmp(user_shortcut+p, "ctrl", 4)) {
+ shortcut[len++] = BX_KEY_CTRL_L;
+ p += 4;
+ } else if (!strncmp(user_shortcut+p, "del", 3)) {
+ shortcut[len++] = BX_KEY_DELETE;
+ p += 3;
+ } else if (!strncmp(user_shortcut+p, "esc", 3)) {
+ shortcut[len++] = BX_KEY_ESC;
+ p += 3;
+ } else if (!strncmp(user_shortcut+p, "f1", 2)) {
+ shortcut[len++] = BX_KEY_F1;
+ p += 2;
+ } else if (!strncmp(user_shortcut+p, "f4", 2)) {
+ shortcut[len++] = BX_KEY_F4;
+ p += 2;
+ } else if (!strncmp(user_shortcut+p, "tab", 3)) {
+ shortcut[len++] = BX_KEY_TAB;
+ p += 3;
+ } else if (!strncmp(user_shortcut+p, "win", 3)) {
+ shortcut[len++] = BX_KEY_WIN_L;
+ p += 3;
+ } else if (!strncmp(user_shortcut+p, "bksp", 4)) {
+ shortcut[len++] = BX_KEY_BACKSPACE;
+ p += 4;
+ } else {
+ BX_ERROR(("Unknown shortcut %s ignored", user_shortcut));
+ return;
+ }
+ }
+ i = 0;
+ while (i < len) {
+ DEV_kbd_gen_scancode(shortcut[i++]);
+ }
+ i--;
+ while (i >= 0) {
+ DEV_kbd_gen_scancode(shortcut[i--] | BX_KEY_RELEASED);
+ }
+ }
+}
+
+ void
+bx_gui_c::mouse_enabled_changed (bx_bool val)
+{
+ // This is only called when SIM->get_init_done is 1. Note that VAL
+ // is the new value of mouse_enabled, which may not match the old
+ // value which is still in bx_options.Omouse_enabled->get ().
+ BX_DEBUG (("replacing the mouse bitmaps"));
+ if (val)
+ BX_GUI_THIS replace_bitmap(BX_GUI_THIS mouse_hbar_id, BX_GUI_THIS mouse_bmap_id);
+ else
+ BX_GUI_THIS replace_bitmap(BX_GUI_THIS mouse_hbar_id, BX_GUI_THIS nomouse_bmap_id);
+ // give the GUI a chance to respond to the event. Most guis will hide
+ // the native mouse cursor and do something to trap the mouse inside the
+ // bochs VGA display window.
+ BX_GUI_THIS mouse_enabled_changed_specific (val);
+}
+
+void
+bx_gui_c::init_signal_handlers ()
+{
+#if BX_GUI_SIGHANDLER
+ if (bx_gui_sighandler)
+ {
+ Bit32u mask = bx_gui->get_sighandler_mask ();
+ for (Bit32u sig=0; sig<32; sig++)
+ {
+ if (mask & (1<<sig))
+ signal (sig, bx_signal_handler);
+ }
+ }
+#endif
+}
+
+ void
+bx_gui_c::set_text_charmap(Bit8u *fbuffer)
+{
+ memcpy(& BX_GUI_THIS vga_charmap, fbuffer, 0x2000);
+ for (unsigned i=0; i<256; i++) BX_GUI_THIS char_changed[i] = 1;
+ BX_GUI_THIS charmap_updated = 1;
+}
+
+ void
+bx_gui_c::set_text_charbyte(Bit16u address, Bit8u data)
+{
+ BX_GUI_THIS vga_charmap[address] = data;
+ BX_GUI_THIS char_changed[address >> 5] = 1;
+ BX_GUI_THIS charmap_updated = 1;
+}
diff --git a/tools/ioemu/gui/gui.h b/tools/ioemu/gui/gui.h
new file mode 100644
index 0000000000..14a44caa71
--- /dev/null
+++ b/tools/ioemu/gui/gui.h
@@ -0,0 +1,352 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gui.h,v 1.40 2003/06/28 08:04:31 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+typedef struct {
+ Bit8u cs_start;
+ Bit8u cs_end;
+ Bit16u line_offset;
+ Bit16u line_compare;
+ Bit8u h_panning;
+ Bit8u v_panning;
+ bx_bool line_graphics;
+} bx_vga_tminfo_t;
+
+
+BOCHSAPI extern class bx_gui_c *bx_gui;
+
+
+// The bx_gui_c class provides data and behavior that is common to
+// all guis. Each gui implementation will override the abstract methods.
+class BOCHSAPI bx_gui_c : public logfunctions {
+public:
+ bx_gui_c (void);
+ virtual ~bx_gui_c ();
+ // Define the following functions in the module for your particular GUI
+ // (x.cc, beos.cc, ...)
+ virtual void specific_init(int argc, char **argv,
+ unsigned x_tilesize, unsigned y_tilesize, unsigned header_bar_y) = 0;
+ virtual void text_update(Bit8u *old_text, Bit8u *new_text,
+ unsigned long cursor_x, unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info, unsigned rows) = 0;
+ virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y) = 0;
+ virtual void handle_events(void) = 0;
+ virtual void flush(void) = 0;
+ virtual void clear_screen(void) = 0;
+ virtual bx_bool palette_change(unsigned index, unsigned red, unsigned green, unsigned blue) = 0;
+ virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0, unsigned fwidth=0, unsigned bpp=8) = 0;
+ virtual unsigned create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) = 0;
+ virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) = 0;
+ virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id) = 0;
+ virtual void show_headerbar(void) = 0;
+ virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes) = 0;
+ virtual int set_clipboard_text(char *snapshot, Bit32u len) = 0;
+ virtual void mouse_enabled_changed_specific (bx_bool val) = 0;
+ virtual void exit(void) = 0;
+ // set_display_mode() changes the mode between the configuration interface
+ // and the simulation. This is primarily intended for display libraries
+ // which have a full-screen mode such as SDL, term, and svgalib. The display
+ // mode is set to DISP_MODE_CONFIG before displaying any configuration menus,
+ // for panics that requires user input, when entering the debugger, etc. It
+ // is set to DISP_MODE_SIM when the Bochs simulation resumes. The
+ // enum is defined in gui/siminterface.h.
+ virtual void set_display_mode (disp_mode_t newmode) { /* default=no action*/ }
+ // These are only needed for the term gui. For all other guis they will
+ // have no effect.
+ // returns 32-bit bitmask in which 1 means the GUI should handle that signal
+ virtual Bit32u get_sighandler_mask () {return 0;}
+ // called when registered signal arrives
+ virtual void sighandler (int sig) {}
+#if BX_USE_IDLE_HACK
+ // this is called from the CPU model when the HLT instruction is executed.
+ virtual void sim_is_idle(void) {}
+#endif
+
+ // The following function(s) are defined already, and your
+ // GUI code calls them
+ static void key_event(Bit32u key);
+ static void set_text_charmap(Bit8u *fbuffer);
+ static void set_text_charbyte(Bit16u address, Bit8u data);
+
+ void init(int argc, char **argv,
+ unsigned x_tilesize, unsigned y_tilesize);
+ void update_drive_status_buttons (void);
+ static void mouse_enabled_changed (bx_bool val);
+ static void init_signal_handlers ();
+
+
+protected:
+ // And these are defined and used privately in gui.cc
+ static void floppyA_handler(void);
+ static void floppyB_handler(void);
+ static void cdromD_handler(void);
+ static void reset_handler(void);
+ static void power_handler(void);
+ static void copy_handler(void);
+ static void paste_handler(void);
+ static void snapshot_handler(void);
+ static void snapshot_checker(void *);
+ static void config_handler(void);
+ static void toggle_mouse_enable(void);
+ static void userbutton_handler(void);
+ static Bit32s make_text_snapshot (char **snapshot, Bit32u *length);
+
+ bx_bool floppyA_status;
+ bx_bool floppyB_status;
+ bx_bool cdromD_status;
+ unsigned floppyA_bmap_id, floppyA_eject_bmap_id, floppyA_hbar_id;
+ unsigned floppyB_bmap_id, floppyB_eject_bmap_id, floppyB_hbar_id;
+ unsigned cdromD_bmap_id, cdromD_eject_bmap_id, cdromD_hbar_id;
+ unsigned power_bmap_id, power_hbar_id;
+ unsigned reset_bmap_id, reset_hbar_id;
+ unsigned copy_bmap_id, copy_hbar_id;
+ unsigned paste_bmap_id, paste_hbar_id;
+ unsigned snapshot_bmap_id, snapshot_hbar_id;
+ unsigned config_bmap_id, config_hbar_id;
+ unsigned mouse_bmap_id, nomouse_bmap_id, mouse_hbar_id;
+ unsigned user_bmap_id, user_hbar_id;
+
+ unsigned char vga_charmap[0x2000];
+ bx_bool charmap_updated;
+ bx_bool char_changed[256];
+ disp_mode_t disp_mode;
+ };
+
+
+// Add this macro in the class declaration of each GUI, to define all the
+// required virtual methods. Example:
+//
+// class bx_rfb_gui_c : public bx_gui_c {
+// public:
+// bx_rfb_gui_c (void) {}
+// DECLARE_GUI_VIRTUAL_METHODS()
+// };
+// Then, each method must be defined later in the file.
+#define DECLARE_GUI_VIRTUAL_METHODS() \
+ virtual void specific_init(int argc, char **argv, \
+ unsigned x_tilesize, unsigned y_tilesize, \
+ unsigned header_bar_y); \
+ virtual void text_update(Bit8u *old_text, Bit8u *new_text, \
+ unsigned long cursor_x, unsigned long cursor_y, \
+ bx_vga_tminfo_t tm_info, unsigned rows); \
+ virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y); \
+ virtual void handle_events(void); \
+ virtual void flush(void); \
+ virtual void clear_screen(void); \
+ virtual bx_bool palette_change(unsigned index, \
+ unsigned red, unsigned green, unsigned blue); \
+ virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0, \
+ unsigned fwidth=0, unsigned bpp=8); \
+ virtual unsigned create_bitmap(const unsigned char *bmap, \
+ unsigned xdim, unsigned ydim); \
+ virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment, \
+ void (*f)(void)); \
+ virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id); \
+ virtual void show_headerbar(void); \
+ virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes); \
+ virtual int set_clipboard_text(char *snapshot, Bit32u len); \
+ virtual void mouse_enabled_changed_specific (bx_bool val); \
+ virtual void exit(void); \
+ /* end of DECLARE_GUI_VIRTUAL_METHODS */
+
+#define BX_MAX_PIXMAPS 16
+#define BX_MAX_HEADERBAR_ENTRIES 11
+#define BX_HEADER_BAR_Y 32
+
+// align pixmaps towards left or right side of header bar
+#define BX_GRAVITY_LEFT 10
+#define BX_GRAVITY_RIGHT 11
+
+#define BX_KEY_PRESSED 0x00000000
+#define BX_KEY_RELEASED 0x80000000
+
+#define BX_KEY_UNHANDLED 0x10000000
+
+#define BX_KEY_CTRL_L 0
+#define BX_KEY_SHIFT_L 1
+
+#define BX_KEY_F1 2
+#define BX_KEY_F2 3
+#define BX_KEY_F3 4
+#define BX_KEY_F4 5
+#define BX_KEY_F5 6
+#define BX_KEY_F6 7
+#define BX_KEY_F7 8
+#define BX_KEY_F8 9
+#define BX_KEY_F9 10
+#define BX_KEY_F10 11
+#define BX_KEY_F11 12
+#define BX_KEY_F12 13
+
+#define BX_KEY_CTRL_R 14
+#define BX_KEY_SHIFT_R 15
+#define BX_KEY_CAPS_LOCK 16
+#define BX_KEY_NUM_LOCK 17
+#define BX_KEY_ALT_L 18
+#define BX_KEY_ALT_R 19
+
+#define BX_KEY_A 20
+#define BX_KEY_B 21
+#define BX_KEY_C 22
+#define BX_KEY_D 23
+#define BX_KEY_E 24
+#define BX_KEY_F 25
+#define BX_KEY_G 26
+#define BX_KEY_H 27
+#define BX_KEY_I 28
+#define BX_KEY_J 29
+#define BX_KEY_K 30
+#define BX_KEY_L 31
+#define BX_KEY_M 32
+#define BX_KEY_N 33
+#define BX_KEY_O 34
+#define BX_KEY_P 35
+#define BX_KEY_Q 36
+#define BX_KEY_R 37
+#define BX_KEY_S 38
+#define BX_KEY_T 39
+#define BX_KEY_U 40
+#define BX_KEY_V 41
+#define BX_KEY_W 42
+#define BX_KEY_X 43
+#define BX_KEY_Y 44
+#define BX_KEY_Z 45
+
+#define BX_KEY_0 46
+#define BX_KEY_1 47
+#define BX_KEY_2 48
+#define BX_KEY_3 49
+#define BX_KEY_4 50
+#define BX_KEY_5 51
+#define BX_KEY_6 52
+#define BX_KEY_7 53
+#define BX_KEY_8 54
+#define BX_KEY_9 55
+
+#define BX_KEY_ESC 56
+
+#define BX_KEY_SPACE 57
+#define BX_KEY_SINGLE_QUOTE 58
+#define BX_KEY_COMMA 59
+#define BX_KEY_PERIOD 60
+#define BX_KEY_SLASH 61
+
+#define BX_KEY_SEMICOLON 62
+#define BX_KEY_EQUALS 63
+
+#define BX_KEY_LEFT_BRACKET 64
+#define BX_KEY_BACKSLASH 65
+#define BX_KEY_RIGHT_BRACKET 66
+#define BX_KEY_MINUS 67
+#define BX_KEY_GRAVE 68
+
+#define BX_KEY_BACKSPACE 69
+#define BX_KEY_ENTER 70
+#define BX_KEY_TAB 71
+
+#define BX_KEY_LEFT_BACKSLASH 72
+#define BX_KEY_PRINT 73
+#define BX_KEY_SCRL_LOCK 74
+#define BX_KEY_PAUSE 75
+
+#define BX_KEY_INSERT 76
+#define BX_KEY_DELETE 77
+#define BX_KEY_HOME 78
+#define BX_KEY_END 79
+#define BX_KEY_PAGE_UP 80
+#define BX_KEY_PAGE_DOWN 81
+
+#define BX_KEY_KP_ADD 82
+#define BX_KEY_KP_SUBTRACT 83
+#define BX_KEY_KP_END 84
+#define BX_KEY_KP_DOWN 85
+#define BX_KEY_KP_PAGE_DOWN 86
+#define BX_KEY_KP_LEFT 87
+#define BX_KEY_KP_RIGHT 88
+#define BX_KEY_KP_HOME 89
+#define BX_KEY_KP_UP 90
+#define BX_KEY_KP_PAGE_UP 91
+#define BX_KEY_KP_INSERT 92
+#define BX_KEY_KP_DELETE 93
+#define BX_KEY_KP_5 94
+
+#define BX_KEY_UP 95
+#define BX_KEY_DOWN 96
+#define BX_KEY_LEFT 97
+#define BX_KEY_RIGHT 98
+
+#define BX_KEY_KP_ENTER 99
+#define BX_KEY_KP_MULTIPLY 100
+#define BX_KEY_KP_DIVIDE 101
+
+#define BX_KEY_WIN_L 102
+#define BX_KEY_WIN_R 103
+#define BX_KEY_MENU 104
+
+#define BX_KEY_ALT_SYSREQ 105
+#define BX_KEY_CTRL_BREAK 106
+
+#define BX_KEY_INT_BACK 107
+#define BX_KEY_INT_FORWARD 108
+#define BX_KEY_INT_STOP 109
+#define BX_KEY_INT_MAIL 110
+#define BX_KEY_INT_SEARCH 111
+#define BX_KEY_INT_FAV 112
+#define BX_KEY_INT_HOME 113
+
+#define BX_KEY_POWER_MYCOMP 114
+#define BX_KEY_POWER_CALC 115
+#define BX_KEY_POWER_SLEEP 116
+#define BX_KEY_POWER_POWER 117
+#define BX_KEY_POWER_WAKE 118
+
+#define BX_KEY_NBKEYS 119
+// If you add BX_KEYs Please update
+// - BX_KEY_NBKEYS
+// - the scancodes table in the file iodev/scancodes.cc
+// - the bx_key_symbol table in the file gui/keymap.cc
+
+
+/////////////// GUI plugin support
+
+// Define macro to supply gui plugin code. This macro is called once in GUI to
+// supply the plugin initialization methods. Since it is nearly identical for
+// each gui module, the macro is easier to maintain than pasting the same code
+// in each one.
+//
+// Each gui should declare a class pointer called "theGui" which is derived
+// from bx_gui_c, before calling this macro. For example, the SDL port
+// says:
+// static bx_sdl_gui_c *theGui;
+
+#define IMPLEMENT_GUI_PLUGIN_CODE(gui_name) \
+ int lib##gui_name##_LTX_plugin_init(plugin_t *plugin, \
+ plugintype_t type, int argc, char *argv[]) { \
+ genlog->info("installing %s module as the Bochs GUI", #gui_name); \
+ theGui = new bx_##gui_name##_gui_c (); \
+ bx_gui = theGui; \
+ return(0); /* Success */ \
+ } \
+ void lib##gui_name##_LTX_plugin_fini(void) { }
diff --git a/tools/ioemu/gui/icon_bochs.h b/tools/ioemu/gui/icon_bochs.h
new file mode 100644
index 0000000000..36669fec53
--- /dev/null
+++ b/tools/ioemu/gui/icon_bochs.h
@@ -0,0 +1,40 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: icon_bochs.h,v 1.3 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#define bochs_icon_width 32
+#define bochs_icon_height 32
+static unsigned char bochs_icon_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0xe0, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f,
+ 0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f,
+ 0xfc, 0xc3, 0xc3, 0x3f, 0xf8, 0xc1, 0x83, 0x1f, 0xf0, 0xc0, 0x03, 0x0f,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xf0, 0xc0, 0x03, 0x0f,
+ 0xf8, 0xc1, 0x83, 0x1f, 0xfc, 0xc3, 0xc3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f,
+ 0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc7, 0xe3, 0x3f, 0xf8, 0xff, 0xff, 0x1f,
+ 0xf8, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/icon_bochs.xpm b/tools/ioemu/gui/icon_bochs.xpm
new file mode 100644
index 0000000000..f895743fcf
--- /dev/null
+++ b/tools/ioemu/gui/icon_bochs.xpm
@@ -0,0 +1,45 @@
+/* XPM */
+static char *icon_bochs_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 7 1",
+" c black",
+". c #800000",
+"X c #808000",
+"o c yellow",
+"O c #808080",
+"+ c #c0c0c0",
+"@ c None",
+/* pixels */
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@. +@@@+ +@@@@@@@@@",
+"@@@@@@@@ Oo @+ .@@@@@@@@",
+"@@@@@@ ooooo ooo. @@@@@@@",
+"@@@@ oooooo. oooooX @@@@@",
+"@+ XoooooO XX ooooooo O@@@",
+"+ oooooO XXXX X ooooooo @@",
+"@ ooo XXXXXX XX ooooooX ",
+"@@. XXXXXXXX XXX Xooooo. ",
+"@@@@ OXXXXXXXXX XXXXXO oO .@",
+"@@@@ .XXXXXXX XXXXXXX. @@@",
+"@+ oo XXXX XXXXXXXX @@@",
+"@ ooooo XXXXXX O",
+"@@O oooooo OXXXX. XX Oooo ",
+"@@@@ .ooooo. XXXXX oooo O@",
+"@@@@ Oooooo XX. .ooo @@@",
+"@@@@ XX oooooo .oooo. @@@@",
+"@@@@ ooXX . ooO o @@@@",
+"@@@@ oooXX. .Xo XX XXo @@@@",
+"@@@@ ooooXXXXXXXo XXXX.XXoo @@@@",
+"@@@+ oooooooooooo XooXXXooo @@@@",
+"@@@. oooooooooooo Xooooooo @@@@",
+"@@@+ oooooooooo XoooooX .@@@@@",
+"@@@@@O XoooooooX ooooo +@@@@@@",
+"@@@@@@@ ooooooX oooX @@@@@@@@",
+"@@@@@@@@@ ooooX oo @@@@@@@@@",
+"@@@@@@@@@@. Ooo. O@@@@@@@@@@",
+"@@@@@@@@@@@@ @@@@@@@@@@@@",
+"@@@@@@@@@@@@@@O O@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@+@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+};
diff --git a/tools/ioemu/gui/keymap.cc b/tools/ioemu/gui/keymap.cc
new file mode 100644
index 0000000000..8013693c8a
--- /dev/null
+++ b/tools/ioemu/gui/keymap.cc
@@ -0,0 +1,330 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keymap.cc,v 1.16 2003/10/11 10:43:24 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Todo
+// . Currently supported by sdl, wxGTK and x11. Check if other guis need mapping.
+// . Tables look-up should be optimised.
+//
+
+#include "bochs.h"
+
+// Table of bochs "BX_KEY_*" symbols
+// the table must be in BX_KEY_* order
+char *bx_key_symbol[BX_KEY_NBKEYS] = {
+ "BX_KEY_CTRL_L", "BX_KEY_SHIFT_L", "BX_KEY_F1",
+ "BX_KEY_F2", "BX_KEY_F3", "BX_KEY_F4",
+ "BX_KEY_F5", "BX_KEY_F6", "BX_KEY_F7",
+ "BX_KEY_F8", "BX_KEY_F9", "BX_KEY_F10",
+ "BX_KEY_F11", "BX_KEY_F12", "BX_KEY_CTRL_R",
+ "BX_KEY_SHIFT_R", "BX_KEY_CAPS_LOCK", "BX_KEY_NUM_LOCK",
+ "BX_KEY_ALT_L", "BX_KEY_ALT_R", "BX_KEY_A",
+ "BX_KEY_B", "BX_KEY_C", "BX_KEY_D",
+ "BX_KEY_E", "BX_KEY_F", "BX_KEY_G",
+ "BX_KEY_H", "BX_KEY_I", "BX_KEY_J",
+ "BX_KEY_K", "BX_KEY_L", "BX_KEY_M",
+ "BX_KEY_N", "BX_KEY_O", "BX_KEY_P",
+ "BX_KEY_Q", "BX_KEY_R", "BX_KEY_S",
+ "BX_KEY_T", "BX_KEY_U", "BX_KEY_V",
+ "BX_KEY_W", "BX_KEY_X", "BX_KEY_Y",
+ "BX_KEY_Z", "BX_KEY_0", "BX_KEY_1",
+ "BX_KEY_2", "BX_KEY_3", "BX_KEY_4",
+ "BX_KEY_5", "BX_KEY_6", "BX_KEY_7",
+ "BX_KEY_8", "BX_KEY_9", "BX_KEY_ESC",
+ "BX_KEY_SPACE", "BX_KEY_SINGLE_QUOTE", "BX_KEY_COMMA",
+ "BX_KEY_PERIOD", "BX_KEY_SLASH", "BX_KEY_SEMICOLON",
+ "BX_KEY_EQUALS", "BX_KEY_LEFT_BRACKET", "BX_KEY_BACKSLASH",
+ "BX_KEY_RIGHT_BRACKET", "BX_KEY_MINUS", "BX_KEY_GRAVE",
+ "BX_KEY_BACKSPACE", "BX_KEY_ENTER", "BX_KEY_TAB",
+ "BX_KEY_LEFT_BACKSLASH", "BX_KEY_PRINT", "BX_KEY_SCRL_LOCK",
+ "BX_KEY_PAUSE", "BX_KEY_INSERT", "BX_KEY_DELETE",
+ "BX_KEY_HOME", "BX_KEY_END", "BX_KEY_PAGE_UP",
+ "BX_KEY_PAGE_DOWN", "BX_KEY_KP_ADD", "BX_KEY_KP_SUBTRACT",
+ "BX_KEY_KP_END", "BX_KEY_KP_DOWN", "BX_KEY_KP_PAGE_DOWN",
+ "BX_KEY_KP_LEFT", "BX_KEY_KP_RIGHT", "BX_KEY_KP_HOME",
+ "BX_KEY_KP_UP", "BX_KEY_KP_PAGE_UP", "BX_KEY_KP_INSERT",
+ "BX_KEY_KP_DELETE", "BX_KEY_KP_5", "BX_KEY_UP",
+ "BX_KEY_DOWN", "BX_KEY_LEFT", "BX_KEY_RIGHT",
+ "BX_KEY_KP_ENTER", "BX_KEY_KP_MULTIPLY", "BX_KEY_KP_DIVIDE",
+ "BX_KEY_WIN_L", "BX_KEY_WIN_R", "BX_KEY_MENU",
+ "BX_KEY_ALT_SYSREQ", "BX_KEY_CTRL_BREAK", "BX_KEY_INT_BACK",
+ "BX_KEY_INT_FORWARD", "BX_KEY_INT_STOP", "BX_KEY_INT_MAIL",
+ "BX_KEY_INT_SEARCH", "BX_KEY_INT_FAV", "BX_KEY_INT_HOME",
+ "BX_KEY_POWER_MYCOMP", "BX_KEY_POWER_CALC", "BX_KEY_POWER_SLEEP",
+ "BX_KEY_POWER_POWER", "BX_KEY_POWER_WAKE",
+ };
+
+bx_keymap_c bx_keymap;
+
+#define LOG_THIS bx_keymap.
+
+bx_keymap_c::bx_keymap_c(void)
+{
+ put("KMAP");
+
+ keymapCount = 0;
+ keymapTable = (BXKeyEntry *)NULL;
+
+}
+
+bx_keymap_c::~bx_keymap_c(void)
+{
+ if(keymapTable != NULL) {
+ free(keymapTable);
+ keymapTable = (BXKeyEntry *)NULL;
+ }
+ keymapCount = 0;
+}
+
+ void
+bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*))
+{
+ if(bx_options.keyboard.OuseMapping->get()) {
+ loadKeymap(stringToSymbol,bx_options.keyboard.Okeymap->getptr());
+ }
+}
+
+
+bx_bool
+bx_keymap_c::isKeymapLoaded ()
+{
+ return (keymapCount > 0);
+}
+
+
+///////////////////
+// I'll add these to the keymap object in a minute.
+static unsigned char *lineptr = NULL;
+static int lineCount;
+
+static void
+init_parse ()
+{
+ lineCount = 0;
+}
+
+static void
+init_parse_line (char *line_to_parse)
+{
+ // chop off newline
+ lineptr = (unsigned char *)line_to_parse;
+ char *nl;
+ if( (nl = strchr(line_to_parse,'\n')) != NULL) {
+ *nl = 0;
+ }
+}
+
+static Bit32s
+get_next_word (char *output)
+{
+ char *copyp = output;
+ // find first nonspace
+ while (*lineptr && isspace (*lineptr))
+ lineptr++;
+ if (!*lineptr)
+ return -1; // nothing but spaces until end of line
+ if (*lineptr == '#')
+ return -1; // nothing but a comment
+ // copy nonspaces into the output
+ while (*lineptr && !isspace (*lineptr))
+ *copyp++ = *lineptr++;
+ *copyp=0; // null terminate the copy
+ // there must be at least one nonspace, since that's why we stopped the
+ // first loop!
+ BX_ASSERT (copyp != output);
+ return 0;
+}
+
+static Bit32s
+get_next_keymap_line (FILE *fp, char *bxsym, char *modsym, Bit32s *ascii, char *hostsym)
+{
+ char line[256];
+ char buf[256];
+ line[0] = 0;
+ while (1) {
+ lineCount++;
+ if (!fgets(line, sizeof(line)-1, fp)) return -1; // EOF
+ init_parse_line (line);
+ if (get_next_word (bxsym) >= 0) {
+ modsym[0] = 0;
+ char *p;
+ if ((p = strchr (bxsym, '+')) != NULL) {
+ *p = 0; // truncate bxsym.
+ p++; // move one char beyond the +
+ strcpy (modsym, p); // copy the rest to modsym
+ }
+ if (get_next_word (buf) < 0) {
+ BX_PANIC (("keymap line %d: expected 3 columns", lineCount));
+ return -1;
+ }
+ if (buf[0] == '\'' && buf[2] == '\'' && buf[3]==0) {
+ *ascii = (Bit8u) buf[1];
+ } else if (!strcmp(buf, "space")) {
+ *ascii = ' ';
+ } else if (!strcmp(buf, "return")) {
+ *ascii = '\n';
+ } else if (!strcmp(buf, "tab")) {
+ *ascii = '\t';
+ } else if (!strcmp(buf, "backslash")) {
+ *ascii = '\\';
+ } else if (!strcmp(buf, "apostrophe")) {
+ *ascii = '\'';
+ } else if (!strcmp(buf, "none")) {
+ *ascii = -1;
+ } else {
+ BX_PANIC (("keymap line %d: ascii equivalent is \"%s\" but it must be char constant like 'x', or one of space,tab,return,none", lineCount, buf));
+ }
+ if (get_next_word (hostsym) < 0) {
+ BX_PANIC (("keymap line %d: expected 3 columns", lineCount));
+ return -1;
+ }
+ return 0;
+ }
+ // no words on this line, keep reading.
+ }
+}
+
+ void
+bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*), const char* filename)
+{
+ FILE *keymapFile;
+ char baseSym[256], modSym[256], hostSym[256];
+ Bit32s ascii;
+ Bit32u baseKey, modKey, hostKey;
+ struct stat status;
+
+ if (stat(filename, &status)) {
+ BX_PANIC(("Can not stat keymap file '%s'.",filename));
+ }
+
+ if (!(S_ISREG(status.st_mode))) {
+ BX_PANIC(("Keymap file '%s' is not a file",filename));
+ }
+
+ if((keymapFile = fopen(filename,"r"))==NULL) {
+ BX_PANIC(("Can not open keymap file '%s'.",filename));
+ }
+
+ BX_INFO(("Loading keymap from '%s'",filename));
+ init_parse ();
+
+ // Read keymap file one line at a time
+ while(1) {
+ if (get_next_keymap_line (keymapFile,
+ baseSym, modSym, &ascii, hostSym) < 0) { break; }
+
+
+ // convert X_KEY_* symbols to values
+ baseKey = convertStringToBXKey(baseSym);
+ modKey = convertStringToBXKey(modSym);
+ hostKey = 0;
+ if (stringToSymbol != NULL)
+ hostKey = stringToSymbol(hostSym);
+
+ BX_DEBUG (("baseKey='%s' (%d), modSym='%s' (%d), ascii=%d, guisym='%s' (%d)", baseSym, baseKey, modSym, modKey, ascii, hostSym, hostKey));
+
+ // Check if data is valid
+ if( baseKey==BX_KEYMAP_UNKNOWN ) {
+ BX_PANIC (("line %d: unknown BX_KEY constant '%s'",lineCount,baseSym));
+ continue;
+ }
+
+ if( hostKey==BX_KEYMAP_UNKNOWN ) {
+ BX_PANIC (("line %d: unknown host key name '%s'",lineCount,hostSym));
+ continue;
+ }
+
+ keymapTable=(BXKeyEntry*)realloc(keymapTable,(keymapCount+1) * sizeof(BXKeyEntry));
+
+ if(keymapTable==NULL)
+ BX_PANIC(("Can not allocate memory for keymap table."));
+
+ keymapTable[keymapCount].baseKey=baseKey;
+ keymapTable[keymapCount].modKey=modKey;
+ keymapTable[keymapCount].ascii=ascii;
+ keymapTable[keymapCount].hostKey=hostKey;
+
+ keymapCount++;
+ }
+
+ BX_INFO(("Loaded %d symbols",keymapCount));
+
+ fclose(keymapFile);
+}
+
+ Bit32u
+bx_keymap_c::convertStringToBXKey(const char* string)
+{
+ Bit16u i;
+
+ // We look through the bx_key_symbol table to find the searched string
+ for (i=0; i<BX_KEY_NBKEYS; i++) {
+ if (strcmp(string,bx_key_symbol[i])==0) {
+ return i;
+ }
+ }
+
+ // Key is not known
+ return BX_KEYMAP_UNKNOWN;
+}
+
+ BXKeyEntry *
+bx_keymap_c::findHostKey(Bit32u key)
+{
+ Bit16u i;
+
+ // We look through the keymap table to find the searched key
+ for (i=0; i<keymapCount; i++) {
+ if (keymapTable[i].hostKey == key) {
+ BX_DEBUG (("key 0x%02x matches hostKey for entry #%d", key, i));
+ return &keymapTable[i];
+ }
+ }
+ BX_DEBUG (("key %02x matches no entries", key));
+
+ // Return default
+ return NULL;
+}
+
+ BXKeyEntry *
+bx_keymap_c::findAsciiChar(Bit8u ch)
+{
+ Bit16u i;
+ BX_DEBUG (("findAsciiChar (0x%02x)", ch));
+
+ // We look through the keymap table to find the searched key
+ for (i=0; i<keymapCount; i++) {
+ if (keymapTable[i].ascii == ch) {
+ BX_DEBUG (("key %02x matches ascii for entry #%d", ch, i));
+ return &keymapTable[i];
+ }
+ }
+ BX_DEBUG (("key 0x%02x matches no entries", ch));
+
+ // Return default
+ return NULL;
+}
+
+ char *
+bx_keymap_c::getBXKeyName(Bit32u key)
+{
+ return bx_key_symbol[key & 0x7fffffff];
+}
diff --git a/tools/ioemu/gui/keymap.h b/tools/ioemu/gui/keymap.h
new file mode 100644
index 0000000000..945729bd17
--- /dev/null
+++ b/tools/ioemu/gui/keymap.h
@@ -0,0 +1,77 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keymap.h,v 1.9 2003/07/12 08:17:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Methods of bx_keymap_c :
+//
+// - loadKeymap(Bit32u convertStringToSymbol(const char*));
+// loads the configuration specified keymap file if keymapping is enabled
+// using convertStringToSymbol to convert strings to client constants
+//
+// - loadKeymap(Bit32u convertStringToSymbol(const char*), const char* filename);
+// loads the specified keymap file
+// using convertStringToSymbol to convert strings to client constants
+//
+// - isKeymapLoaded () returns true if the keymap contains any valid key
+// entries.
+//
+// - convertStringToBXKey
+// convert a null-terminate string to a BX_KEY code
+//
+// - findHostKey(Bit32u key)
+// - findAsciiChar(Bit8u ch)
+// Each of these methods returns a pointer to a BXKeyEntry structure
+// corresponding to a key. findHostKey() finds an entry whose hostKey
+// value matches the target value, and findAsciiChar() finds an entry
+// whose ASCII code matches the search value.
+
+// In case of unknown symbol
+#define BX_KEYMAP_UNKNOWN 0xFFFFFFFF
+
+// Structure of an element of the keymap table
+typedef struct BOCHSAPI {
+ Bit32u baseKey; // base key
+ Bit32u modKey; // modifier key that must be held down
+ Bit32s ascii; // ascii equivalent, if any
+ Bit32u hostKey; // value that the host's OS or library recognizes
+ } BXKeyEntry;
+
+class BOCHSAPI bx_keymap_c : public logfunctions {
+public:
+ bx_keymap_c(void);
+ ~bx_keymap_c(void);
+
+ void loadKeymap(Bit32u(*)(const char*));
+ void loadKeymap(Bit32u(*)(const char*),const char *filename);
+ bx_bool isKeymapLoaded ();
+
+ BXKeyEntry *findHostKey(Bit32u hostkeynum);
+ BXKeyEntry *findAsciiChar(Bit8u ascii);
+ char *getBXKeyName(Bit32u key);
+
+private:
+ Bit32u convertStringToBXKey(const char *);
+
+ BXKeyEntry *keymapTable;
+ Bit16u keymapCount;
+ };
+
+BOCHSAPI extern bx_keymap_c bx_keymap;
diff --git a/tools/ioemu/gui/keymaps/convertmap.pl b/tools/ioemu/gui/keymaps/convertmap.pl
new file mode 100644
index 0000000000..18c47bea93
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/convertmap.pl
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+# little utility script that I used to convert key map files from
+# the pre-March 11 format to the post-March 11 format. It doesn't
+# do anything smart with the ascii equivalents and modifiers, so ATM those must
+# be added by hand.
+
+while (<STDIN>)
+{
+ chop;
+ s/^ *//;
+ if (/^#/ || /^ *$/) { print "$_\n"; next;}
+ ($key, $equals, $xksym) = split (/ +/);
+ printf ("%-45s %-10s %s\n", $key, 'none', "XK_$xksym");
+}
diff --git a/tools/ioemu/gui/keymaps/sdl-pc-de.map b/tools/ioemu/gui/keymaps/sdl-pc-de.map
new file mode 100644
index 0000000000..de4fd59cd8
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/sdl-pc-de.map
@@ -0,0 +1,222 @@
+# Bochs Keymap file
+# $Id: sdl-pc-de.map,v 1.2 2002/10/24 21:06:55 bdenney Exp $
+# Target: PC(x86) keyboard, DE keymap, SDL gui on X11
+# Author: Volker Ruppert
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Host_key_name
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Host_key_name
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Host_key_name is the name of the key combination according to the gui library
+# (X windows, SDL, etc). Each GUI module must provide a function that converts
+# these host key names into numbers. A pointer to the conversion function is
+# passed to loadKeymap(), and it is used when parsing the keymap file. As the
+# keymap file is parsed, the conversion function is called for each host key
+# name, to convert it into a number. Only the number is stored. If the host
+# key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and
+# the keymap code will panic, like this:
+#
+# [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT'
+#
+# If this happens, you must edit the keymap file, and either correct the host
+# key name or comment out that line.
+#
+
+BX_KEY_0 '0' SDLK_0
+BX_KEY_0+BX_KEY_SHIFT_L '=' SDLK_EQUALS
+BX_KEY_1 '1' SDLK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' SDLK_EXCLAIM
+BX_KEY_2 '2' SDLK_2
+BX_KEY_2+BX_KEY_ALT_R '²' SDLK_2
+BX_KEY_2+BX_KEY_SHIFT_L '"' SDLK_QUOTEDBL
+BX_KEY_3 '3' SDLK_3
+BX_KEY_3+BX_KEY_SHIFT_L '§' SDLK_3
+BX_KEY_4 '4' SDLK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' SDLK_DOLLAR
+BX_KEY_4+BX_KEY_ALT_R '¼' SDLK_4
+BX_KEY_5 '5' SDLK_5
+BX_KEY_5+BX_KEY_ALT_R '½' SDLK_5
+BX_KEY_5+BX_KEY_SHIFT_L '%' SDLK_5
+BX_KEY_6 '6' SDLK_6
+BX_KEY_6+BX_KEY_SHIFT_L '&' SDLK_AMPERSAND
+BX_KEY_7 '7' SDLK_7
+BX_KEY_7+BX_KEY_ALT_R '{' SDLK_7
+BX_KEY_7+BX_KEY_SHIFT_L '/' SDLK_SLASH
+BX_KEY_8 '8' SDLK_8
+BX_KEY_8+BX_KEY_ALT_R '[' SDLK_LEFTBRACKET
+BX_KEY_8+BX_KEY_SHIFT_L '(' SDLK_LEFTPAREN
+BX_KEY_9 '9' SDLK_9
+BX_KEY_9+BX_KEY_ALT_R ']' SDLK_RIGHTBRACKET
+BX_KEY_9+BX_KEY_SHIFT_L ')' SDLK_RIGHTPAREN
+BX_KEY_A+BX_KEY_SHIFT_L 'A' SDLK_a
+BX_KEY_A 'a' SDLK_a
+BX_KEY_A+BX_KEY_ALT_R 'æ' SDLK_a
+BX_KEY_B+BX_KEY_SHIFT_L 'B' SDLK_b
+BX_KEY_B 'b' SDLK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' SDLK_c
+BX_KEY_C 'c' SDLK_c
+BX_KEY_C+BX_KEY_ALT_R '¢' SDLK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' SDLK_d
+BX_KEY_D 'd' SDLK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' SDLK_e
+BX_KEY_E+BX_KEY_ALT_R none SDLK_EURO
+BX_KEY_E 'e' SDLK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' SDLK_f
+BX_KEY_F 'f' SDLK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' SDLK_g
+BX_KEY_G 'g' SDLK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' SDLK_h
+BX_KEY_H 'h' SDLK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' SDLK_i
+BX_KEY_I 'i' SDLK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' SDLK_j
+BX_KEY_J 'j' SDLK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' SDLK_k
+BX_KEY_K 'k' SDLK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' SDLK_l
+BX_KEY_L 'l' SDLK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' SDLK_m
+BX_KEY_M 'm' SDLK_m
+BX_KEY_M+BX_KEY_ALT_R 'µ' SDLK_m
+BX_KEY_N+BX_KEY_SHIFT_L 'N' SDLK_n
+BX_KEY_N 'n' SDLK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' SDLK_o
+BX_KEY_O 'o' SDLK_o
+BX_KEY_O+BX_KEY_ALT_R 'ø' SDLK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' SDLK_p
+BX_KEY_P 'p' SDLK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' SDLK_q
+BX_KEY_Q+BX_KEY_ALT_R '@' SDLK_AT
+BX_KEY_Q 'q' SDLK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' SDLK_r
+BX_KEY_R+BX_KEY_ALT_R '¶' SDLK_r
+BX_KEY_R 'r' SDLK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' SDLK_s
+BX_KEY_S 's' SDLK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' SDLK_t
+BX_KEY_T 't' SDLK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' SDLK_u
+BX_KEY_U 'u' SDLK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' SDLK_v
+BX_KEY_V 'v' SDLK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' SDLK_w
+BX_KEY_W 'w' SDLK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' SDLK_x
+BX_KEY_X+BX_KEY_ALT_R '»' SDLK_x
+BX_KEY_X 'x' SDLK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Z' SDLK_z
+BX_KEY_Y 'z' SDLK_z
+BX_KEY_Z+BX_KEY_SHIFT_L 'Y' SDLK_y
+BX_KEY_Z+BX_KEY_ALT_R '«' SDLK_y
+BX_KEY_Z 'y' SDLK_y
+BX_KEY_F1 none SDLK_F1
+BX_KEY_F2 none SDLK_F2
+BX_KEY_F3 none SDLK_F3
+BX_KEY_F4 none SDLK_F4
+BX_KEY_F5 none SDLK_F5
+BX_KEY_F6 none SDLK_F6
+BX_KEY_F7 none SDLK_F7
+BX_KEY_F8 none SDLK_F8
+BX_KEY_F9 none SDLK_F9
+BX_KEY_F10 none SDLK_F10
+BX_KEY_F11 none SDLK_F11
+BX_KEY_F12 none SDLK_F12
+BX_KEY_ALT_L none SDLK_LALT
+BX_KEY_ALT_L none SDLK_LMETA
+BX_KEY_ALT_R none SDLK_RALT
+BX_KEY_ALT_R none SDLK_MODE
+BX_KEY_BACKSLASH apostrophe SDLK_QUOTE
+BX_KEY_BACKSLASH '#' SDLK_HASH
+BX_KEY_BACKSPACE none SDLK_BACKSPACE
+BX_KEY_CAPS_LOCK none SDLK_CAPSLOCK
+BX_KEY_COMMA ',' SDLK_COMMA
+BX_KEY_COMMA+BX_KEY_SHIFT_L ';' SDLK_SEMICOLON
+BX_KEY_CTRL_L none SDLK_LCTRL
+BX_KEY_CTRL_R none SDLK_RCTRL
+BX_KEY_DELETE none SDLK_DELETE
+BX_KEY_DOWN none SDLK_DOWN
+BX_KEY_END none SDLK_END
+BX_KEY_ENTER return SDLK_RETURN
+BX_KEY_EQUALS none SDLK_WORLD_20
+BX_KEY_EQUALS+BX_KEY_ALT_R '¸' SDLK_WORLD_20
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '`' SDLK_WORLD_20
+BX_KEY_ESC none SDLK_ESCAPE
+BX_KEY_GRAVE '^' SDLK_CARET
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '°' SDLK_CARET
+BX_KEY_GRAVE+BX_KEY_ALT_R '¬' SDLK_CARET
+BX_KEY_HOME none SDLK_HOME
+BX_KEY_INSERT none SDLK_INSERT
+BX_KEY_KP_5 none SDLK_KP5
+BX_KEY_KP_ADD none SDLK_KP_PLUS
+BX_KEY_KP_DELETE none SDLK_KP_PERIOD
+BX_KEY_KP_DIVIDE none SDLK_KP_DIVIDE
+BX_KEY_KP_DOWN none SDLK_KP2
+BX_KEY_KP_END none SDLK_KP1
+BX_KEY_KP_ENTER none SDLK_KP_ENTER
+BX_KEY_KP_HOME none SDLK_KP7
+BX_KEY_KP_INSERT none SDLK_KP0
+BX_KEY_KP_LEFT none SDLK_KP4
+BX_KEY_KP_MULTIPLY none SDLK_KP_MULTIPLY
+BX_KEY_KP_PAGE_DOWN none SDLK_KP3
+BX_KEY_KP_PAGE_UP none SDLK_KP9
+BX_KEY_KP_RIGHT none SDLK_KP6
+BX_KEY_KP_SUBTRACT none SDLK_KP_MINUS
+BX_KEY_KP_UP none SDLK_KP8
+BX_KEY_LEFT none SDLK_LEFT
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R '|' SDLK_LESS
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' SDLK_GREATER
+BX_KEY_LEFT_BACKSLASH '<' SDLK_LESS
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L 'Ü' SDLK_WORLD_92
+BX_KEY_LEFT_BRACKET 'ü' SDLK_WORLD_92
+BX_KEY_MENU none SDLK_MENU
+BX_KEY_MINUS+BX_KEY_ALT_L backslash SDLK_BACKSLASH
+BX_KEY_MINUS+BX_KEY_SHIFT_L '?' SDLK_QUESTION
+BX_KEY_MINUS 'ß' SDLK_WORLD_63
+BX_KEY_NUM_LOCK none SDLK_NUMLOCK
+BX_KEY_PAGE_DOWN none SDLK_PAGEDOWN
+BX_KEY_PAGE_UP none SDLK_PAGEUP
+BX_KEY_PAUSE none SDLK_BREAK
+BX_KEY_PAUSE none SDLK_PAUSE
+BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' SDLK_COLON
+BX_KEY_PERIOD '.' SDLK_PERIOD
+BX_KEY_PERIOD+BX_KEY_ALT_L '·' SDLK_PERIOD
+BX_KEY_PRINT none SDLK_PRINT
+BX_KEY_PRINT none SDLK_SYSREQ
+BX_KEY_RIGHT none SDLK_RIGHT
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R '~' SDLK_PLUS
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '*' SDLK_PLUS
+BX_KEY_RIGHT_BRACKET '+' SDLK_PLUS
+BX_KEY_SCRL_LOCK none SDLK_SCROLLOCK
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'Ö' SDLK_WORLD_86
+BX_KEY_SEMICOLON 'ö' SDLK_WORLD_86
+BX_KEY_SHIFT_L none SDLK_LSHIFT
+BX_KEY_SHIFT_R none SDLK_RSHIFT
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L 'Ä' SDLK_WORLD_68
+BX_KEY_SINGLE_QUOTE 'ä' SDLK_WORLD_68
+BX_KEY_SLASH '-' SDLK_MINUS
+BX_KEY_SLASH+BX_KEY_SHIFT_L '_' SDLK_UNDERSCORE
+BX_KEY_SPACE space SDLK_SPACE
+BX_KEY_TAB tab SDLK_TAB
+BX_KEY_UP none SDLK_UP
+BX_KEY_WIN_L none SDLK_LSUPER
+BX_KEY_WIN_R none SDLK_RSUPER
diff --git a/tools/ioemu/gui/keymaps/sdl-pc-us.map b/tools/ioemu/gui/keymaps/sdl-pc-us.map
new file mode 100644
index 0000000000..3440992b50
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/sdl-pc-us.map
@@ -0,0 +1,211 @@
+# Bochs Keymap file
+# $Id: sdl-pc-us.map,v 1.2 2002/10/24 21:06:55 bdenney Exp $
+# Target: PC(x86) keyboard, US keymap, SDL gui
+# Author: Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Host_key_name
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Host_key_name
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Host_key_name is the name of the key combination according to the gui library
+# (X windows, SDL, etc). Each GUI module must provide a function that converts
+# these host key names into numbers. A pointer to the conversion function is
+# passed to loadKeymap(), and it is used when parsing the keymap file. As the
+# keymap file is parsed, the conversion function is called for each host key
+# name, to convert it into a number. Only the number is stored. If the host
+# key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and
+# the keymap code will panic, like this:
+#
+# [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT'
+#
+# If this happens, you must edit the keymap file, and either correct the host
+# key name or comment out that line.
+#
+
+BX_KEY_0 '0' SDLK_0
+BX_KEY_0+BX_KEY_SHIFT_L ')' SDLK_RIGHTPAREN
+BX_KEY_1 '1' SDLK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' SDLK_EXCLAIM
+BX_KEY_2 '2' SDLK_2
+BX_KEY_2+BX_KEY_SHIFT_L '@' SDLK_AT
+BX_KEY_3 '3' SDLK_3
+BX_KEY_3+BX_KEY_SHIFT_L '#' SDLK_HASH
+BX_KEY_4 '4' SDLK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' SDLK_DOLLAR
+BX_KEY_5 '5' SDLK_5
+#BX_KEY_5+BX_KEY_SHIFT_L '%' SDLK_PERCENT
+BX_KEY_6 '6' SDLK_6
+BX_KEY_6+BX_KEY_SHIFT_L '^' SDLK_CARET
+BX_KEY_7 '7' SDLK_7
+BX_KEY_7+BX_KEY_SHIFT_L '&' SDLK_AMPERSAND
+BX_KEY_8 '8' SDLK_8
+BX_KEY_8+BX_KEY_SHIFT_L '*' SDLK_ASTERISK
+BX_KEY_9 '9' SDLK_9
+BX_KEY_9+BX_KEY_SHIFT_L '(' SDLK_LEFTPAREN
+BX_KEY_A+BX_KEY_SHIFT_L 'A' SDLK_a
+BX_KEY_A 'a' SDLK_a
+BX_KEY_B+BX_KEY_SHIFT_L 'B' SDLK_b
+BX_KEY_B 'b' SDLK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' SDLK_c
+BX_KEY_C 'c' SDLK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' SDLK_d
+BX_KEY_D 'd' SDLK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' SDLK_e
+BX_KEY_E 'e' SDLK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' SDLK_f
+BX_KEY_F 'f' SDLK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' SDLK_g
+BX_KEY_G 'g' SDLK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' SDLK_h
+BX_KEY_H 'h' SDLK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' SDLK_i
+BX_KEY_I 'i' SDLK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' SDLK_j
+BX_KEY_J 'j' SDLK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' SDLK_k
+BX_KEY_K 'k' SDLK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' SDLK_l
+BX_KEY_L 'l' SDLK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' SDLK_m
+BX_KEY_M 'm' SDLK_m
+BX_KEY_N+BX_KEY_SHIFT_L 'N' SDLK_n
+BX_KEY_N 'n' SDLK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' SDLK_o
+BX_KEY_O 'o' SDLK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' SDLK_p
+BX_KEY_P 'p' SDLK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' SDLK_q
+BX_KEY_Q 'q' SDLK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' SDLK_r
+BX_KEY_R 'r' SDLK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' SDLK_s
+BX_KEY_S 's' SDLK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' SDLK_t
+BX_KEY_T 't' SDLK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' SDLK_u
+BX_KEY_U 'u' SDLK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' SDLK_v
+BX_KEY_V 'v' SDLK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' SDLK_w
+BX_KEY_W 'w' SDLK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' SDLK_x
+BX_KEY_X 'x' SDLK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' SDLK_y
+BX_KEY_Y 'y' SDLK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' SDLK_z
+BX_KEY_Z 'z' SDLK_z
+BX_KEY_F1 none SDLK_F1
+BX_KEY_F2 none SDLK_F2
+BX_KEY_F3 none SDLK_F3
+BX_KEY_F4 none SDLK_F4
+BX_KEY_F5 none SDLK_F5
+BX_KEY_F6 none SDLK_F6
+BX_KEY_F7 none SDLK_F7
+BX_KEY_F8 none SDLK_F8
+BX_KEY_F9 none SDLK_F9
+BX_KEY_F10 none SDLK_F10
+BX_KEY_F11 none SDLK_F11
+BX_KEY_F12 none SDLK_F12
+BX_KEY_ALT_L none SDLK_LALT
+BX_KEY_ALT_L none SDLK_LMETA
+BX_KEY_ALT_R none SDLK_MODE
+#BX_KEY_ALT_R none SDLK_Multi_key
+BX_KEY_BACKSLASH backslash SDLK_BACKSLASH
+#BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '|' SDLK_bar
+BX_KEY_BACKSPACE none SDLK_BACKSPACE
+BX_KEY_CAPS_LOCK none SDLK_CAPSLOCK
+BX_KEY_COMMA ',' SDLK_COMMA
+BX_KEY_COMMA+BX_KEY_SHIFT_L '<' SDLK_LESS
+BX_KEY_CTRL_L none SDLK_LCTRL
+BX_KEY_CTRL_R none SDLK_RCTRL
+BX_KEY_DELETE none SDLK_DELETE
+BX_KEY_DOWN none SDLK_DOWN
+BX_KEY_END none SDLK_END
+BX_KEY_ENTER return SDLK_RETURN
+BX_KEY_EQUALS '=' SDLK_EQUALS
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' SDLK_PLUS
+BX_KEY_ESC none SDLK_ESCAPE
+#BX_KEY_GRAVE+BX_KEY_SHIFT_L '~' SDLK_asciitilde
+BX_KEY_GRAVE '`' SDLK_BACKQUOTE
+BX_KEY_HOME none SDLK_HOME
+BX_KEY_INSERT none SDLK_INSERT
+BX_KEY_KP_5 none SDLK_KP5
+#BX_KEY_KP_5 none SDLK_KP_BEGIN
+BX_KEY_KP_ADD none SDLK_KP_PLUS
+BX_KEY_KP_DELETE none SDLK_KP_PERIOD
+#BX_KEY_KP_DELETE none SDLK_KP_DELETE
+BX_KEY_KP_DIVIDE none SDLK_KP_DIVIDE
+BX_KEY_KP_DOWN none SDLK_KP2
+#BX_KEY_KP_DOWN none SDLK_KP_DOWN
+BX_KEY_KP_END none SDLK_KP1
+#BX_KEY_KP_END none SDLK_KP_END
+BX_KEY_KP_ENTER none SDLK_KP_ENTER
+BX_KEY_KP_HOME none SDLK_KP7
+#BX_KEY_KP_HOME none SDLK_KP_HOME
+BX_KEY_KP_INSERT none SDLK_KP0
+#BX_KEY_KP_INSERT none SDLK_KP_INSERT
+BX_KEY_KP_LEFT none SDLK_KP4
+#BX_KEY_KP_LEFT none SDLK_KP_LEFT
+BX_KEY_KP_MULTIPLY none SDLK_KP_MULTIPLY
+BX_KEY_KP_PAGE_DOWN none SDLK_KP3
+#BX_KEY_KP_PAGE_DOWN none SDLK_KP_PAGE_DOWN
+BX_KEY_KP_PAGE_UP none SDLK_KP9
+#BX_KEY_KP_PAGE_UP none SDLK_KP_PAGE_UP
+BX_KEY_KP_RIGHT none SDLK_KP6
+#BX_KEY_KP_RIGHT none SDLK_KP_Right
+BX_KEY_KP_SUBTRACT none SDLK_KP_MINUS
+BX_KEY_KP_UP none SDLK_KP8
+#BX_KEY_KP_UP none SDLK_KP_Up
+BX_KEY_LEFT none SDLK_LEFT
+#BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' SDLK_BRACELEFT
+BX_KEY_LEFT_BRACKET '[' SDLK_LEFTBRACKET
+BX_KEY_MENU none SDLK_MENU
+BX_KEY_MINUS '-' SDLK_MINUS
+BX_KEY_MINUS+BX_KEY_SHIFT_L '_' SDLK_UNDERSCORE
+BX_KEY_NUM_LOCK none SDLK_NUMLOCK
+BX_KEY_PAGE_DOWN none SDLK_PAGEDOWN
+BX_KEY_PAGE_UP none SDLK_PAGEUP
+BX_KEY_PAUSE none SDLK_BREAK
+BX_KEY_PAUSE none SDLK_PAUSE
+BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' SDLK_GREATER
+BX_KEY_PERIOD '.' SDLK_PERIOD
+BX_KEY_PRINT none SDLK_PRINT
+BX_KEY_PRINT none SDLK_SYSREQ
+BX_KEY_RIGHT none SDLK_RIGHT
+#BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' SDLK_BRACERIGHT
+BX_KEY_RIGHT_BRACKET ']' SDLK_RIGHTBRACKET
+BX_KEY_SCRL_LOCK none SDLK_SCROLLOCK
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' SDLK_COLON
+BX_KEY_SEMICOLON ';' SDLK_SEMICOLON
+BX_KEY_SHIFT_L none SDLK_LSHIFT
+BX_KEY_SHIFT_R none SDLK_RSHIFT
+BX_KEY_SINGLE_QUOTE apostrophe SDLK_QUOTE
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' SDLK_QUOTEDBL
+BX_KEY_SLASH+BX_KEY_SHIFT_L '?' SDLK_QUESTION
+BX_KEY_SLASH '/' SDLK_SLASH
+BX_KEY_SPACE space SDLK_SPACE
+#BX_KEY_TAB none SDLK_ISO_LEFT_TAB
+BX_KEY_TAB tab SDLK_TAB
+BX_KEY_UP none SDLK_UP
+BX_KEY_WIN_L none SDLK_LSUPER
+BX_KEY_WIN_R none SDLK_LSUPER
diff --git a/tools/ioemu/gui/keymaps/x11-pc-be.map b/tools/ioemu/gui/keymaps/x11-pc-be.map
new file mode 100644
index 0000000000..0a607e00c5
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-be.map
@@ -0,0 +1,220 @@
+# Bochs Keymap file
+# $Id: x11-pc-be.map,v 1.2 2003/07/29 13:31:11 bdenney Exp $
+# Target: PC(x86) keyboard, BE keymap
+# Author: Wouter Verhelst,
+# based on FR keymap by Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0+BX_KEY_SHIFT_L '0' XK_0
+BX_KEY_0 'à' XK_agrave
+BX_KEY_0+BX_KEY_ALT_R '}' XK_braceright
+BX_KEY_1+BX_KEY_SHIFT_L '1' XK_1
+BX_KEY_1 '&' XK_ampersand
+BX_KEY_1+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_2+BX_KEY_SHIFT_L '2' XK_2
+BX_KEY_2+BX_KEY_ALT_R '@' XK_at
+BX_KEY_2 'é' XK_eacute
+BX_KEY_3+BX_KEY_SHIFT_L '3' XK_3
+BX_KEY_3+BX_KEY_ALT_R '#' XK_numbersign
+BX_KEY_3 '"' XK_quotedbl
+BX_KEY_4+BX_KEY_SHIFT_L '4' XK_4
+BX_KEY_4 apostrophe XK_apostrophe
+BX_KEY_5+BX_KEY_SHIFT_L '5' XK_5
+BX_KEY_5 '(' XK_parenleft
+BX_KEY_6+BX_KEY_SHIFT_L '6' XK_6
+BX_KEY_6+BX_KEY_ALT_R '^' XK_asciicircum
+BX_KEY_6 '§' XK_section
+BX_KEY_7+BX_KEY_SHIFT_L '7' XK_7
+BX_KEY_7 'è' XK_egrave
+BX_KEY_8+BX_KEY_SHIFT_L '8' XK_8
+BX_KEY_8 '!' XK_exclam
+BX_KEY_9+BX_KEY_SHIFT_L '9' XK_9
+BX_KEY_9+BX_KEY_ALT_R '{' XK_braceleft
+BX_KEY_9 'ç' XK_ccedilla
+BX_KEY_A+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_A 'q' XK_q
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E 'e' XK_e
+BX_KEY_E+BX_KEY_ALT_R none XK_EuroSign
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_M ',' XK_comma
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_Q 'a' XK_a
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_W 'z' XK_z
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_Z 'w' XK_w
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH 'µ' XK_mu
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '£' XK_sterling
+BX_KEY_BACKSLASH+BX_KEY_ALT_R '`' XK_dead_grave
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA+BX_KEY_SHIFT_L '.' XK_period
+BX_KEY_COMMA ';' XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS '-' XK_minus
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE '²' XK_twosuperior
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '³' XK_threesuperior
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R backslash XK_backslash
+BX_KEY_LEFT_BRACKET none XK_dead_circumflex
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L none XK_dead_diaeresis
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_R '[' XK_bracketleft
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS+BX_KEY_SHIFT_L '°' XK_degree
+BX_KEY_MINUS ')' XK_parenright
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD ':' XK_colon
+BX_KEY_PERIOD+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET '$' XK_dollar
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R ']' XK_bracketright
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_SEMICOLON 'm' XK_m
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_SINGLE_QUOTE+BX_KEY_ALT_R none XK_dead_acute
+BX_KEY_SINGLE_QUOTE 'ù' XK_ugrave
+BX_KEY_SLASH '=' XK_equal
+BX_KEY_SLASH+BX_KEY_SHIFT_L '+' XK_plus
+BX_KEY_SLASH+BX_KEY_ALT_R none XK_dead_tilde
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-da.map b/tools/ioemu/gui/keymaps/x11-pc-da.map
new file mode 100644
index 0000000000..41ead2b63d
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-da.map
@@ -0,0 +1,247 @@
+# Bochs Keymap file
+# $Id: x11-pc-da.map,v 0.9 2002/09/02
+# Target: PC(x86) keyboard, DA keymap
+# Author: Andreas Ott
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_ALT_R '}' XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L '=' XK_equal
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_1+BX_KEY_ALT_R '¡' XK_exclamdown
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '=' XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R '@' XK_at # XK_twosuperior
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '#' XK_numbersign
+BX_KEY_3+BX_KEY_ALT_R '£' XK_sterling
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '¤' XK_currency
+BX_KEY_4+BX_KEY_ALT_R '$' XK_dollar
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_ALT_R '½' XK_onehalf
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R '¥' XK_yen
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_ALT_R '{' XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_ALT_R '[' XK_bracketleft
+BX_KEY_8+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_ALT_R ']' XK_bracketright
+BX_KEY_9+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A 'a' XK_a
+BX_KEY_A+BX_KEY_ALT_R 'ª' XK_ordfeminine
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_B+BX_KEY_ALT_R none XK_rightdoublequotemark
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_C+BX_KEY_ALT_R '©' XK_copyright
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_D+BX_KEY_ALT_R 'ð' XK_eth
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E+BX_KEY_ALT_R '?' XK_EuroSign
+BX_KEY_E 'e' XK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F+BX_KEY_ALT_R '?' XK_dstroke
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G+BX_KEY_ALT_R '?' XK_eng
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_H+BX_KEY_ALT_R '?' XK_hstroke
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_I+BX_KEY_ALT_R none XK_rightarrow
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_K+BX_KEY_ALT_R none XK_kra
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M 'm' XK_m
+BX_KEY_M+BX_KEY_ALT_R 'µ' XK_mu
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_O+BX_KEY_ALT_R none XK_oslash
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_P+BX_KEY_ALT_R 'þ' XK_thorn
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_Q+BX_KEY_ALT_R '@' XK_at
+BX_KEY_Q 'q' XK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R+BX_KEY_ALT_R '®' XK_registered
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_S+BX_KEY_ALT_R 'ß' XK_ssharp
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_T+BX_KEY_ALT_R 'þ' XK_thorn
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U+BX_KEY_ALT_R none XK_downarrow
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V+BX_KEY_ALT_R none XK_leftdoublequotemark
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_W+BX_KEY_ALT_R '?' XK_lstroke
+BX_KEY_W 'w' XK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X+BX_KEY_ALT_R '»' XK_guillemotright
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y+BX_KEY_ALT_R none XK_leftarrow
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Z+BX_KEY_ALT_R '«' XK_guillemotleft
+BX_KEY_Z 'z' XK_z
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH apostrophe XK_apostrophe
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_ALT_R none XK_horizconnector
+BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS none XK_acute
+BX_KEY_EQUALS+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '`' XK_grave
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE '½' XK_onehalf
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '§' XK_section
+BX_KEY_GRAVE+BX_KEY_ALT_R '¾' XK_threequarters
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R backslash XK_backslash
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L 'Å' XK_Aring
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_L none XK_diaeresis
+BX_KEY_LEFT_BRACKET 'å' XK_aring
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_R '±' XK_plusminus
+BX_KEY_MINUS+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_MINUS '+' XK_plus
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PERIOD+BX_KEY_ALT_R '·' XK_periodcentered
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R '~' XK_asciitilde
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '^' XK_asciicircum
+BX_KEY_RIGHT_BRACKET '"' XK_diaeresis
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'Æ' XK_AE
+BX_KEY_SEMICOLON 'æ' XK_ae
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE 'ø' XK_oslash
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L 'Ø' XK_Ooblique
+BX_KEY_SLASH+BX_KEY_ALT_R '­' XK_hyphen
+BX_KEY_SLASH '-' XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-de.map b/tools/ioemu/gui/keymaps/x11-pc-de.map
new file mode 100644
index 0000000000..929ad0625e
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-de.map
@@ -0,0 +1,247 @@
+# Bochs Keymap file
+# $Id: x11-pc-de.map,v 1.7 2002/10/24 21:06:56 bdenney Exp $
+# Target: PC(x86) keyboard, DE keymap
+# Author: Volker Ruppert
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_ALT_R '}' XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L '=' XK_equal
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_1+BX_KEY_ALT_R '¹' XK_onesuperior
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '"' XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R '²' XK_twosuperior
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '§' XK_section
+BX_KEY_3+BX_KEY_ALT_R '³' XK_threesuperior
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar
+BX_KEY_4+BX_KEY_ALT_R '¼' XK_onequarter
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_ALT_R '½' XK_onehalf
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R '¾' XK_threequarters
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_ALT_R '{' XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_ALT_R '[' XK_bracketleft
+BX_KEY_8+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_ALT_R ']' XK_bracketright
+BX_KEY_9+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A 'a' XK_a
+BX_KEY_A+BX_KEY_ALT_R 'æ' XK_ae
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_B+BX_KEY_ALT_R none XK_rightdoublequotemark
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_C+BX_KEY_ALT_R '¢' XK_cent
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_D+BX_KEY_ALT_R 'ð' XK_eth
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E+BX_KEY_ALT_R none XK_EuroSign
+BX_KEY_E 'e' XK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F+BX_KEY_ALT_R none XK_dstroke
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G+BX_KEY_ALT_R none XK_eng
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_H+BX_KEY_ALT_R none XK_hstroke
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_I+BX_KEY_ALT_R none XK_rightarrow
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_K+BX_KEY_ALT_R none XK_kra
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M 'm' XK_m
+BX_KEY_M+BX_KEY_ALT_R 'µ' XK_mu
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_O+BX_KEY_ALT_R 'ø' XK_oslash
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_P+BX_KEY_ALT_R 'þ' XK_thorn
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_Q+BX_KEY_ALT_R '@' XK_at
+BX_KEY_Q 'q' XK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R+BX_KEY_ALT_R '¶' XK_paragraph
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_T+BX_KEY_ALT_R none XK_tslash
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U+BX_KEY_ALT_R none XK_downarrow
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V+BX_KEY_ALT_R none XK_leftdoublequotemark
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_W+BX_KEY_ALT_R none XK_lstroke
+BX_KEY_W 'w' XK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X+BX_KEY_ALT_R '»' XK_guillemotright
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Y+BX_KEY_ALT_R none XK_leftarrow
+BX_KEY_Y 'z' XK_z
+BX_KEY_Z+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Z+BX_KEY_ALT_R '«' XK_guillemotleft
+BX_KEY_Z 'y' XK_y
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH apostrophe XK_apostrophe
+BX_KEY_BACKSLASH '#' XK_numbersign
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_ALT_R none XK_horizconnector
+BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS none XK_acute
+BX_KEY_EQUALS+BX_KEY_ALT_R '¸' XK_cedilla
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '`' XK_grave
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE '^' XK_asciicircum
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '°' XK_degree
+BX_KEY_GRAVE+BX_KEY_ALT_R '¬' XK_notsign
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L 'Ü' XK_Udiaeresis
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_L none XK_diaeresis
+BX_KEY_LEFT_BRACKET 'ü' XK_udiaeresis
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_L backslash XK_backslash
+BX_KEY_MINUS+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_MINUS 'ß' XK_ssharp
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PERIOD+BX_KEY_ALT_L '·' XK_periodcentered
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R '~' XK_asciitilde
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_RIGHT_BRACKET '+' XK_plus
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'Ö' XK_Odiaeresis
+BX_KEY_SEMICOLON 'ö' XK_odiaeresis
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L 'Ä' XK_Adiaeresis
+BX_KEY_SINGLE_QUOTE 'ä' XK_adiaeresis
+BX_KEY_SLASH none XK_dead_belowdot
+BX_KEY_SLASH '-' XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-es.map b/tools/ioemu/gui/keymaps/x11-pc-es.map
new file mode 100644
index 0000000000..3856044ac0
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-es.map
@@ -0,0 +1,217 @@
+# Bochs Keymap file
+# $Id: x11-pc-es.map,v 1.4 2002/09/25 08:00:24 bdenney Exp $
+# Target: PC(x86) keyboard, ES keymap
+# Author: Vicente Hernando Ara
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+BX_KEY_0 none XK_0
+BX_KEY_0 none XK_equal
+BX_KEY_1 none XK_1
+BX_KEY_1 none XK_bar
+BX_KEY_1 none XK_exclam
+BX_KEY_2 none XK_2
+BX_KEY_2 none XK_at
+BX_KEY_2 none XK_quotedbl
+BX_KEY_3 none XK_3
+BX_KEY_3 none XK_numbersign
+BX_KEY_3 none XK_periodcentered
+BX_KEY_4 none XK_4
+BX_KEY_4 none XK_dollar
+BX_KEY_5 none XK_5
+BX_KEY_5 none XK_percent
+BX_KEY_6 none XK_6
+BX_KEY_6 none XK_ampersand
+BX_KEY_7 none XK_7
+BX_KEY_7 none XK_slash
+BX_KEY_8 none XK_8
+BX_KEY_8 none XK_parenleft
+BX_KEY_9 none XK_9
+BX_KEY_9 none XK_parenright
+BX_KEY_A none XK_A
+BX_KEY_A none XK_a
+BX_KEY_B none XK_B
+BX_KEY_B none XK_b
+BX_KEY_C none XK_C
+BX_KEY_C none XK_c
+BX_KEY_D none XK_D
+BX_KEY_D none XK_d
+BX_KEY_E none XK_E
+BX_KEY_E none XK_EuroSign
+BX_KEY_E none XK_e
+BX_KEY_F none XK_F
+BX_KEY_F none XK_f
+BX_KEY_G none XK_G
+BX_KEY_G none XK_g
+BX_KEY_H none XK_H
+BX_KEY_H none XK_h
+BX_KEY_I none XK_I
+BX_KEY_I none XK_i
+BX_KEY_J none XK_J
+BX_KEY_J none XK_j
+BX_KEY_K none XK_K
+BX_KEY_K none XK_k
+BX_KEY_L none XK_L
+BX_KEY_L none XK_l
+BX_KEY_M none XK_M
+BX_KEY_M none XK_m
+BX_KEY_N none XK_N
+BX_KEY_N none XK_n
+BX_KEY_O none XK_O
+BX_KEY_O none XK_o
+BX_KEY_P none XK_P
+BX_KEY_P none XK_p
+BX_KEY_Q none XK_Q
+BX_KEY_Q none XK_q
+BX_KEY_R none XK_R
+BX_KEY_R none XK_r
+BX_KEY_S none XK_S
+BX_KEY_S none XK_s
+BX_KEY_T none XK_T
+BX_KEY_T none XK_t
+BX_KEY_U none XK_U
+BX_KEY_U none XK_u
+BX_KEY_V none XK_V
+BX_KEY_V none XK_v
+BX_KEY_W none XK_W
+BX_KEY_W none XK_w
+BX_KEY_X none XK_X
+BX_KEY_X none XK_x
+BX_KEY_Y none XK_Y
+BX_KEY_Y none XK_y
+BX_KEY_Z none XK_Z
+BX_KEY_Z none XK_z
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH none XK_Ccedilla
+BX_KEY_BACKSLASH none XK_ccedilla
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA none XK_comma
+BX_KEY_COMMA none XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER none XK_Return
+BX_KEY_EQUALS none XK_exclamdown
+BX_KEY_EQUALS none XK_questiondown
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE none XK_asciitilde
+BX_KEY_GRAVE none XK_backslash
+BX_KEY_GRAVE none XK_grave
+BX_KEY_GRAVE none XK_masculine
+BX_KEY_GRAVE none XK_ordfeminine
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BACKSLASH none XK_greater
+BX_KEY_LEFT_BACKSLASH none XK_less
+BX_KEY_LEFT_BRACKET none XK_braceleft
+BX_KEY_LEFT_BRACKET none XK_bracketleft
+BX_KEY_LEFT_BRACKET none XK_dead_circumflex
+BX_KEY_LEFT_BRACKET none XK_dead_grave
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS none XK_apostrophe
+BX_KEY_MINUS none XK_question
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD none XK_colon
+BX_KEY_PERIOD none XK_period
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET none XK_asterisk
+BX_KEY_RIGHT_BRACKET none XK_braceright
+BX_KEY_RIGHT_BRACKET none XK_bracketright
+BX_KEY_RIGHT_BRACKET none XK_plus
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON none XK_Ntilde
+BX_KEY_SEMICOLON none XK_ntilde
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE none XK_dead_acute
+BX_KEY_SINGLE_QUOTE none XK_dead_diaeresis
+BX_KEY_SLASH none XK_minus
+BX_KEY_SLASH none XK_underscore
+BX_KEY_SPACE none XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB none XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-fr.map b/tools/ioemu/gui/keymaps/x11-pc-fr.map
new file mode 100644
index 0000000000..869b328552
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-fr.map
@@ -0,0 +1,218 @@
+# Bochs Keymap file
+# $Id: x11-pc-fr.map,v 1.5 2002/09/25 08:00:24 bdenney Exp $
+# Target: PC(x86) keyboard, FR keymap
+# Author: Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0+BX_KEY_SHIFT_L '0' XK_0
+BX_KEY_0 'à' XK_agrave
+BX_KEY_0+BX_KEY_ALT_R '@' XK_at
+BX_KEY_1+BX_KEY_SHIFT_L '1' XK_1
+BX_KEY_1 '&' XK_ampersand
+BX_KEY_2+BX_KEY_SHIFT_L '2' XK_2
+BX_KEY_2+BX_KEY_ALT_R '~' XK_asciitilde
+BX_KEY_2 'é' XK_eacute
+BX_KEY_3+BX_KEY_SHIFT_L '3' XK_3
+BX_KEY_3+BX_KEY_ALT_R '#' XK_numbersign
+BX_KEY_3 '"' XK_quotedbl
+BX_KEY_4+BX_KEY_SHIFT_L '4' XK_4
+BX_KEY_4 apostrophe XK_apostrophe
+BX_KEY_4+BX_KEY_ALT_R '{' XK_braceleft
+BX_KEY_5+BX_KEY_SHIFT_L '5' XK_5
+BX_KEY_5+BX_KEY_ALT_R '[' XK_bracketleft
+BX_KEY_5 '(' XK_parenleft
+BX_KEY_6+BX_KEY_SHIFT_L '6' XK_6
+BX_KEY_6+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_6 '-' XK_minus
+BX_KEY_7+BX_KEY_SHIFT_L '7' XK_7
+BX_KEY_7 'è' XK_egrave
+BX_KEY_7+BX_KEY_ALT_R '`' XK_grave
+BX_KEY_8+BX_KEY_SHIFT_L '8' XK_8
+BX_KEY_8+BX_KEY_ALT_R backslash XK_backslash
+BX_KEY_8 '_' XK_underscore
+BX_KEY_9+BX_KEY_SHIFT_L '9' XK_9
+BX_KEY_9+BX_KEY_ALT_R '^' XK_asciicircum
+BX_KEY_9 'ç' XK_ccedilla
+BX_KEY_A+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_A 'q' XK_q
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E 'e' XK_e
+BX_KEY_E+BX_KEY_ALT_R none XK_EuroSign
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_M ',' XK_comma
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_Q 'a' XK_a
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_W 'z' XK_z
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_Z 'w' XK_w
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH '*' XK_asterisk
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L 'µ' XK_mu
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA+BX_KEY_SHIFT_L '.' XK_period
+BX_KEY_COMMA ';' XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS+BX_KEY_ALT_R '}' XK_braceright
+BX_KEY_EQUALS '=' XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' XK_plus
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE '²' XK_twosuperior
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_LEFT_BRACKET '^' XK_dead_circumflex
+BX_KEY_LEFT_BRACKET none XK_dead_diaeresis
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_R ']' XK_bracketright
+BX_KEY_MINUS+BX_KEY_SHIFT_L '°' XK_degree
+BX_KEY_MINUS ')' XK_parenright
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD ':' XK_colon
+BX_KEY_PERIOD+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R '¤' XK_currency
+BX_KEY_RIGHT_BRACKET '$' XK_dollar
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '£' XK_sterling
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_SEMICOLON 'm' XK_m
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_SINGLE_QUOTE 'ù' XK_ugrave
+BX_KEY_SLASH '!' XK_exclam
+BX_KEY_SLASH+BX_KEY_SHIFT_L '§' XK_section
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-it.map b/tools/ioemu/gui/keymaps/x11-pc-it.map
new file mode 100644
index 0000000000..fac365e0ba
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-it.map
@@ -0,0 +1,207 @@
+# Bochs Keymap file
+# $Id: x11-pc-it.map,v 1.2 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, IT keymap
+# Author: Emanuele Goldoni
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_SHIFT_L '=' XK_equal
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '"' XK_quotedbl
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '£' XK_sterling
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A 'a' XK_a
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E 'e' XK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M 'm' XK_m
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_Q 'q' XK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_W 'w' XK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Z 'z' XK_z
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH 'ù' XK_ugrave
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '§' XK_section
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS 'ì' XK_igrave
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '^' XK_asciicircum
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '|' XK_bar
+BX_KEY_GRAVE backslash XK_backslash
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L 'é' XK_eacute
+BX_KEY_LEFT_BRACKET 'è' XK_egrave
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS apostrophe XK_apostrophe
+BX_KEY_MINUS+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_RIGHT_BRACKET '+' XK_plus
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'ç' XK_ccedilla
+BX_KEY_SEMICOLON 'ò' XK_ograve
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE 'à' XK_agrave
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '°' XK_degree
+BX_KEY_SLASH+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_SLASH '-' XK_minus
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-se.map b/tools/ioemu/gui/keymaps/x11-pc-se.map
new file mode 100644
index 0000000000..c564ca83c6
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-se.map
@@ -0,0 +1,278 @@
+# Bochs Keymap file
+# $Id: x11-pc-se.map,v 1.2 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, SE keymap
+# Author: Magnus 'Moggen' Öberg
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+# Upper key groups
+BX_KEY_ESC none XK_Escape
+
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+
+# Main key group
+# Row 1
+BX_KEY_GRAVE '§' XK_section
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '½' XK_onehalf
+BX_KEY_GRAVE+BX_KEY_ALT_R '¶' XK_paragraph
+BX_KEY_GRAVE+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¾' XK_threequarters
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_1+BX_KEY_ALT_R '¡' XK_exclamdown
+BX_KEY_1+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¹' XK_onesuperior
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '"' XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R '@' XK_at
+BX_KEY_2+BX_KEY_SHIFT_L+BX_KEY_ALT_R '²' XK_twosuperior
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '#' XK_numbersign
+BX_KEY_3+BX_KEY_ALT_R '£' XK_sterling
+BX_KEY_3+BX_KEY_SHIFT_L+BX_KEY_ALT_R '³' XK_threesuperior
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '¤' XK_currency
+BX_KEY_4+BX_KEY_ALT_R '$' XK_dollar
+BX_KEY_4+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¼' XK_onequarter
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_5+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¢' XK_cent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R '¥' XK_yen
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_SHIFT_L '/' XK_slash
+BX_KEY_7+BX_KEY_ALT_R '{' XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L+BX_KEY_ALT_R '÷' XK_division
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_8+BX_KEY_ALT_R '[' XK_bracketleft
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_9+BX_KEY_ALT_R ']' XK_bracketright
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_SHIFT_L '=' XK_equal
+BX_KEY_0+BX_KEY_ALT_R '}' XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L+BX_KEY_ALT_R '°' XK_degree
+BX_KEY_MINUS '+' XK_plus
+BX_KEY_MINUS+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_MINUS+BX_KEY_ALT_L backslash XK_backslash
+BX_KEY_MINUS+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¿' XK_questiondown
+BX_KEY_EQUALS none XK_dead_acute
+BX_KEY_EQUALS+BX_KEY_SHIFT_L none XK_dead_grave
+BX_KEY_EQUALS+BX_KEY_ALT_L '±' XK_plusminus
+BX_KEY_EQUALS+BX_KEY_ALT_L+BX_KEY_ALT_R '¬' XK_notsign
+BX_KEY_BACKSPACE none XK_BackSpace
+
+# Row 2
+BX_KEY_TAB tab XK_Tab
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_Q 'q' XK_q
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_W 'w' XK_w
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_E 'e' XK_e
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E+BX_KEY_SHIFT_L+BX_KEY_ALT_R none XK_EuroSign
+BX_KEY_R 'r' XK_r
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R+BX_KEY_ALT_R '®' XK_registered
+BX_KEY_T 't' XK_t
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T+BX_KEY_ALT_R 'þ' XK_thorn
+BX_KEY_T+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'Þ' XK_THORN
+BX_KEY_Y 'y' XK_y
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_U 'u' XK_u
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_I 'i' XK_i
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_O 'o' XK_o
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_P 'p' XK_p
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_LEFT_BRACKET 'å' XK_aring
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L 'Å' XK_Aring
+BX_KEY_RIGHT_BRACKET none XK_dead_diaeresis
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L none XK_dead_circumflex
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R none XK_dead_tilde
+BX_KEY_ENTER return XK_Return
+
+# Row 3
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_A 'a' XK_a
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A+BX_KEY_ALT_R 'ª' XK_ordfeminine
+BX_KEY_A+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'º' XK_masculine
+BX_KEY_S 's' XK_s
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S+BX_KEY_ALT_R 'ß' XK_ssharp
+BX_KEY_D 'd' XK_d
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D+BX_KEY_ALT_R 'ð' XK_eth
+BX_KEY_D+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'Ð' XK_ETH
+BX_KEY_F 'f' XK_f
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_G 'g' XK_g
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_H 'h' XK_h
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_J 'j' XK_j
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_K 'k' XK_k
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_L 'l' XK_l
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_SEMICOLON 'ö' XK_odiaeresis
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L 'Ö' XK_Odiaeresis
+BX_KEY_SEMICOLON+BX_KEY_ALT_R 'ø' XK_oslash
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'Ø' XK_Ooblique
+BX_KEY_SINGLE_QUOTE 'ä' XK_adiaeresis
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L 'Ä' XK_Adiaeresis
+BX_KEY_SINGLE_QUOTE+BX_KEY_ALT_R 'æ' XK_ae
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'Æ' XK_AE
+BX_KEY_BACKSLASH apostrophe XK_apostrophe
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_BACKSLASH+BX_KEY_ALT_R '´' XK_acute
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L+BX_KEY_ALT_R '×' XK_multiply
+
+# Row 4
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_LEFT_BACKSLASH '<' XK_less
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¦' XK_brokenbar
+BX_KEY_Z 'z' XK_z
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Z+BX_KEY_ALT_R '«' XK_guillemotleft
+BX_KEY_X 'x' XK_x
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X+BX_KEY_ALT_R '»' XK_guillemotright
+BX_KEY_C 'c' XK_c
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C+BX_KEY_ALT_R '©' XK_copyright
+BX_KEY_V 'v' XK_v
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V+BX_KEY_SHIFT_L+BX_KEY_ALT_R '`' XK_grave
+BX_KEY_B 'b' XK_b
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_N 'n' XK_n
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_M 'm' XK_m
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M+BX_KEY_ALT_R 'µ' XK_mu
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L ';' XK_semicolon
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PERIOD+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_PERIOD+BX_KEY_ALT_R '·' XK_periodcentered
+BX_KEY_SLASH '-' XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT '_' XK_underscore
+BX_KEY_SLASH+BX_KEY_ALT_R '­' XK_hyphen
+BX_KEY_SLASH+BX_KEY_SHIFT+BX_KEY_ALT_R '­' XK_macron
+BX_KEY_SHIFT_R none XK_Shift_R
+
+# Row 5
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_SPACE space XK_space
+BX_KEY_SPACE+BX_KEY_ALT_R none XK_nobreakspace
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_WIN_R none XK_Super_R
+BX_KEY_MENU none XK_Menu
+BX_KEY_CTRL_R none XK_Control_R
+
+# Ins/Del/Home/End/PgUp/PgDn
+BX_KEY_INSERT none XK_Insert
+BX_KEY_DELETE none XK_Delete
+BX_KEY_HOME none XK_Home
+BX_KEY_END none XK_End
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAGE_DOWN none XK_Page_Down
+
+# Arrow keys
+BX_KEY_LEFT none XK_Left
+BX_KEY_RIGHT none XK_Right
+BX_KEY_UP none XK_Up
+BX_KEY_DOWN none XK_Down
+
+# Numerical keypad
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
diff --git a/tools/ioemu/gui/keymaps/x11-pc-uk.map b/tools/ioemu/gui/keymaps/x11-pc-uk.map
new file mode 100644
index 0000000000..05abbe4f83
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-uk.map
@@ -0,0 +1,209 @@
+# Bochs Keymap file
+# $Id: x11-pc-uk.map,v 1.1 2002/12/11 21:35:50 bdenney Exp $
+# Target: PC(x86) keyboard, UK keymap
+# Author: Denis Lenihan
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '"' XK_quotedbl
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '£' XK_sterling
+BX_KEY_3+BX_KEY_ALT_R '|' XK_EuroSign
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '^' XK_asciicircum
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A 'a' XK_a
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E 'e' XK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M 'm' XK_m
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_Q 'q' XK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_W 'w' XK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Z 'z' XK_z
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_LEFT_BACKSLASH '\' XK_backslash
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L '|' XK_bar
+BX_KEY_BACKSLASH '~' XK_asciitilde
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '#' XK_numbersign
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L '<' XK_less
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS '=' XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' XK_plus
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '¬' XK_notsign
+BX_KEY_GRAVE '`' XK_grave
+BX_KEY_GRAVE+BX_KEY_ALT_R '|' XK_bar
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' XK_braceleft
+BX_KEY_LEFT_BRACKET '[' XK_bracketleft
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS '-' XK_minus
+BX_KEY_MINUS+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' XK_braceright
+BX_KEY_RIGHT_BRACKET ']' XK_bracketright
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_SEMICOLON ';' XK_semicolon
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE apostrophe XK_apostrophe
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '@' XK_at
+BX_KEY_SLASH+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_SLASH '/' XK_slash
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-us.map b/tools/ioemu/gui/keymaps/x11-pc-us.map
new file mode 100644
index 0000000000..8cda7a8a13
--- /dev/null
+++ b/tools/ioemu/gui/keymaps/x11-pc-us.map
@@ -0,0 +1,205 @@
+# Bochs Keymap file
+# $Id: x11-pc-us.map,v 1.3 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, US keymap
+# Author: Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+# BX_Keysym ASCII_equivalent Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+# BX_Keysym+BX_Modifier ASCII_equivalent Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc. The BX_Modifier is usually a shift key press, but it
+# could be any key. Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser. There's no concept of backslash being an escape char. The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination. These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes. If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0 '0' XK_0
+BX_KEY_0+BX_KEY_SHIFT_L ')' XK_parenright
+BX_KEY_1 '1' XK_1
+BX_KEY_1+BX_KEY_SHIFT_L '!' XK_exclam
+BX_KEY_2 '2' XK_2
+BX_KEY_2+BX_KEY_SHIFT_L '@' XK_at
+BX_KEY_3 '3' XK_3
+BX_KEY_3+BX_KEY_SHIFT_L '#' XK_numbersign
+BX_KEY_4 '4' XK_4
+BX_KEY_4+BX_KEY_SHIFT_L '$' XK_dollar
+BX_KEY_5 '5' XK_5
+BX_KEY_5+BX_KEY_SHIFT_L '%' XK_percent
+BX_KEY_6 '6' XK_6
+BX_KEY_6+BX_KEY_SHIFT_L '^' XK_asciicircum
+BX_KEY_7 '7' XK_7
+BX_KEY_7+BX_KEY_SHIFT_L '&' XK_ampersand
+BX_KEY_8 '8' XK_8
+BX_KEY_8+BX_KEY_SHIFT_L '*' XK_asterisk
+BX_KEY_9 '9' XK_9
+BX_KEY_9+BX_KEY_SHIFT_L '(' XK_parenleft
+BX_KEY_A+BX_KEY_SHIFT_L 'A' XK_A
+BX_KEY_A 'a' XK_a
+BX_KEY_B+BX_KEY_SHIFT_L 'B' XK_B
+BX_KEY_B 'b' XK_b
+BX_KEY_C+BX_KEY_SHIFT_L 'C' XK_C
+BX_KEY_C 'c' XK_c
+BX_KEY_D+BX_KEY_SHIFT_L 'D' XK_D
+BX_KEY_D 'd' XK_d
+BX_KEY_E+BX_KEY_SHIFT_L 'E' XK_E
+BX_KEY_E 'e' XK_e
+BX_KEY_F+BX_KEY_SHIFT_L 'F' XK_F
+BX_KEY_F 'f' XK_f
+BX_KEY_G+BX_KEY_SHIFT_L 'G' XK_G
+BX_KEY_G 'g' XK_g
+BX_KEY_H+BX_KEY_SHIFT_L 'H' XK_H
+BX_KEY_H 'h' XK_h
+BX_KEY_I+BX_KEY_SHIFT_L 'I' XK_I
+BX_KEY_I 'i' XK_i
+BX_KEY_J+BX_KEY_SHIFT_L 'J' XK_J
+BX_KEY_J 'j' XK_j
+BX_KEY_K+BX_KEY_SHIFT_L 'K' XK_K
+BX_KEY_K 'k' XK_k
+BX_KEY_L+BX_KEY_SHIFT_L 'L' XK_L
+BX_KEY_L 'l' XK_l
+BX_KEY_M+BX_KEY_SHIFT_L 'M' XK_M
+BX_KEY_M 'm' XK_m
+BX_KEY_N+BX_KEY_SHIFT_L 'N' XK_N
+BX_KEY_N 'n' XK_n
+BX_KEY_O+BX_KEY_SHIFT_L 'O' XK_O
+BX_KEY_O 'o' XK_o
+BX_KEY_P+BX_KEY_SHIFT_L 'P' XK_P
+BX_KEY_P 'p' XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L 'Q' XK_Q
+BX_KEY_Q 'q' XK_q
+BX_KEY_R+BX_KEY_SHIFT_L 'R' XK_R
+BX_KEY_R 'r' XK_r
+BX_KEY_S+BX_KEY_SHIFT_L 'S' XK_S
+BX_KEY_S 's' XK_s
+BX_KEY_T+BX_KEY_SHIFT_L 'T' XK_T
+BX_KEY_T 't' XK_t
+BX_KEY_U+BX_KEY_SHIFT_L 'U' XK_U
+BX_KEY_U 'u' XK_u
+BX_KEY_V+BX_KEY_SHIFT_L 'V' XK_V
+BX_KEY_V 'v' XK_v
+BX_KEY_W+BX_KEY_SHIFT_L 'W' XK_W
+BX_KEY_W 'w' XK_w
+BX_KEY_X+BX_KEY_SHIFT_L 'X' XK_X
+BX_KEY_X 'x' XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L 'Y' XK_Y
+BX_KEY_Y 'y' XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L 'Z' XK_Z
+BX_KEY_Z 'z' XK_z
+BX_KEY_F1 none XK_F1
+BX_KEY_F2 none XK_F2
+BX_KEY_F3 none XK_F3
+BX_KEY_F4 none XK_F4
+BX_KEY_F5 none XK_F5
+BX_KEY_F6 none XK_F6
+BX_KEY_F7 none XK_F7
+BX_KEY_F8 none XK_F8
+BX_KEY_F9 none XK_F9
+BX_KEY_F10 none XK_F10
+BX_KEY_F11 none XK_F11
+BX_KEY_F12 none XK_F12
+BX_KEY_ALT_L none XK_Alt_L
+BX_KEY_ALT_L none XK_Meta_L
+BX_KEY_ALT_R none XK_Alt_R
+BX_KEY_ALT_R none XK_Mode_switch
+BX_KEY_ALT_R none XK_Multi_key
+BX_KEY_BACKSLASH backslash XK_backslash
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L '|' XK_bar
+BX_KEY_BACKSPACE none XK_BackSpace
+BX_KEY_CAPS_LOCK none XK_Caps_Lock
+BX_KEY_COMMA ',' XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L '<' XK_less
+BX_KEY_CTRL_L none XK_Control_L
+BX_KEY_CTRL_R none XK_Control_R
+BX_KEY_DELETE none XK_Delete
+BX_KEY_DOWN none XK_Down
+BX_KEY_END none XK_End
+BX_KEY_ENTER return XK_Return
+BX_KEY_EQUALS '=' XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L '+' XK_plus
+BX_KEY_ESC none XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L '~' XK_asciitilde
+BX_KEY_GRAVE '`' XK_grave
+BX_KEY_HOME none XK_Home
+BX_KEY_INSERT none XK_Insert
+BX_KEY_KP_5 none XK_KP_5
+BX_KEY_KP_5 none XK_KP_Begin
+BX_KEY_KP_ADD none XK_KP_Add
+BX_KEY_KP_DELETE none XK_KP_Decimal
+BX_KEY_KP_DELETE none XK_KP_Delete
+BX_KEY_KP_DIVIDE none XK_KP_Divide
+BX_KEY_KP_DOWN none XK_KP_2
+BX_KEY_KP_DOWN none XK_KP_Down
+BX_KEY_KP_END none XK_KP_1
+BX_KEY_KP_END none XK_KP_End
+BX_KEY_KP_ENTER none XK_KP_Enter
+BX_KEY_KP_HOME none XK_KP_7
+BX_KEY_KP_HOME none XK_KP_Home
+BX_KEY_KP_INSERT none XK_KP_0
+BX_KEY_KP_INSERT none XK_KP_Insert
+BX_KEY_KP_LEFT none XK_KP_4
+BX_KEY_KP_LEFT none XK_KP_Left
+BX_KEY_KP_MULTIPLY none XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN none XK_KP_3
+BX_KEY_KP_PAGE_DOWN none XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP none XK_KP_9
+BX_KEY_KP_PAGE_UP none XK_KP_Page_Up
+BX_KEY_KP_RIGHT none XK_KP_6
+BX_KEY_KP_RIGHT none XK_KP_Right
+BX_KEY_KP_SUBTRACT none XK_KP_Subtract
+BX_KEY_KP_UP none XK_KP_8
+BX_KEY_KP_UP none XK_KP_Up
+BX_KEY_LEFT none XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L '{' XK_braceleft
+BX_KEY_LEFT_BRACKET '[' XK_bracketleft
+BX_KEY_MENU none XK_Menu
+BX_KEY_MINUS '-' XK_minus
+BX_KEY_MINUS+BX_KEY_SHIFT_L '_' XK_underscore
+BX_KEY_NUM_LOCK none XK_Num_Lock
+BX_KEY_PAGE_DOWN none XK_Page_Down
+BX_KEY_PAGE_UP none XK_Page_Up
+BX_KEY_PAUSE none XK_Break
+BX_KEY_PAUSE none XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L '>' XK_greater
+BX_KEY_PERIOD '.' XK_period
+BX_KEY_PRINT none XK_Print
+BX_KEY_PRINT none XK_Sys_Req
+BX_KEY_RIGHT none XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L '}' XK_braceright
+BX_KEY_RIGHT_BRACKET ']' XK_bracketright
+BX_KEY_SCRL_LOCK none XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L ':' XK_colon
+BX_KEY_SEMICOLON ';' XK_semicolon
+BX_KEY_SHIFT_L none XK_Shift_L
+BX_KEY_SHIFT_R none XK_Shift_R
+BX_KEY_SINGLE_QUOTE apostrophe XK_apostrophe
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L '"' XK_quotedbl
+BX_KEY_SLASH+BX_KEY_SHIFT_L '?' XK_question
+BX_KEY_SLASH '/' XK_slash
+BX_KEY_SPACE space XK_space
+BX_KEY_TAB none XK_ISO_Left_Tab
+BX_KEY_TAB tab XK_Tab
+BX_KEY_UP none XK_Up
+BX_KEY_WIN_L none XK_Super_L
+BX_KEY_WIN_R none XK_Super_R
diff --git a/tools/ioemu/gui/nogui.cc b/tools/ioemu/gui/nogui.cc
new file mode 100644
index 0000000000..dd56d9d854
--- /dev/null
+++ b/tools/ioemu/gui/nogui.cc
@@ -0,0 +1,336 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: nogui.cc,v 1.21 2003/06/28 08:04:31 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// 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 "icon_bochs.h"
+
+class bx_nogui_gui_c : public bx_gui_c {
+public:
+ bx_nogui_gui_c (void) {}
+ DECLARE_GUI_VIRTUAL_METHODS()
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_nogui_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(nogui)
+
+#define LOG_THIS theGui->
+
+// This file defines stubs for the GUI interface, which is a
+// place to start if you want to port bochs to a platform, for
+// which there is no support for your native GUI, or if you want to compile
+// bochs without any native GUI support (no output window or
+// keyboard input will be possible).
+// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific
+// implementations of this interface. -Kevin
+
+
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+// specific options from the command line. (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+// only updated regions of the screen to the gui code to be redrawn.
+// These define the dimensions of a region (tile).
+// headerbar_y: A headerbar (toolbar) is display on the top of the
+// VGA window, showing floppy status, and other information. It
+// always assumes the width of the current VGA mode width, but
+// it's height is defined by this parameter.
+
+ void
+bx_nogui_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+ unsigned headerbar_y)
+{
+ put("NGUI");
+ UNUSED(argc);
+ UNUSED(argv);
+ UNUSED(tilewidth);
+ UNUSED(tileheight);
+ UNUSED(headerbar_y);
+
+ UNUSED(bochs_icon_bits); // global variable
+
+ if (bx_options.Oprivate_colormap->get ()) {
+ BX_INFO(("private_colormap option ignored."));
+ }
+}
+
+
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+ void
+bx_nogui_gui_c::handle_events(void)
+{
+}
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+ void
+bx_nogui_gui_c::flush(void)
+{
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared. Don't
+// clear the area that defines the headerbar.
+
+ void
+bx_nogui_gui_c::clear_screen(void)
+{
+}
+
+
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+// of the screen from the last call. See below
+// new_text: array of character/attributes making up the current
+// contents, which should now be displayed. See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+// This represents 80 characters wide by 25 high, with
+// each character being 2 bytes. The first by is the
+// character value, the second is the attribute byte.
+// I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+ void
+bx_nogui_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+ unsigned long cursor_x, unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+ UNUSED(old_text);
+ UNUSED(new_text);
+ UNUSED(cursor_x);
+ UNUSED(cursor_y);
+ UNUSED(tm_info);
+ UNUSED(nrows);
+}
+
+ int
+bx_nogui_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ UNUSED(bytes);
+ UNUSED(nbytes);
+ return 0;
+}
+
+ int
+bx_nogui_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ UNUSED(text_snapshot);
+ UNUSED(len);
+ return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+// 1=screen updated needed (redraw using current colormap)
+
+ bx_bool
+bx_nogui_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+ UNUSED(index);
+ UNUSED(red);
+ UNUSED(green);
+ UNUSED(blue);
+ return(0);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+// dimension equal to the 'tilewidth' & 'tileheight' parameters to
+// ::specific_init(). Each value specifies an index into the
+// array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+// left of the window.
+
+ void
+bx_nogui_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+ UNUSED(tile);
+ UNUSED(x0);
+ UNUSED(y0);
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+ void
+bx_nogui_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+ UNUSED(x);
+ UNUSED(y);
+ UNUSED(fheight);
+ UNUSED(fwidth);
+ UNUSED(bpp);
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar. Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
+// bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+ unsigned
+bx_nogui_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+ UNUSED(bmap);
+ UNUSED(xdim);
+ UNUSED(ydim);
+ return(0);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+// ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
+// or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+// meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+// the boundaries of this bitmap.
+
+ unsigned
+bx_nogui_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+ UNUSED(bmap_id);
+ UNUSED(alignment);
+ UNUSED(f);
+ return(0);
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+ void
+bx_nogui_gui_c::show_headerbar(void)
+{
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'. 'bmap_id' will have
+// been generated by ::create_bitmap(). The old and new bitmap
+// must be of the same size. This allows the bitmap the user
+// sees to change, when some action occurs. For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+ void
+bx_nogui_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+ UNUSED(hbar_id);
+ UNUSED(bmap_id);
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+
+ void
+bx_nogui_gui_c::exit(void)
+{
+ BX_INFO(("bx_nogui_gui_c::exit() not implemented yet."));
+}
+
+ void
+bx_nogui_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
diff --git a/tools/ioemu/gui/rfb.cc b/tools/ioemu/gui/rfb.cc
new file mode 100644
index 0000000000..f67f80e895
--- /dev/null
+++ b/tools/ioemu/gui/rfb.cc
@@ -0,0 +1,1508 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfb.cc,v 1.26.2.1 2004/02/02 22:35:30 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2000 Psyon.Org!
+//
+// Donald Becker
+// http://www.psyon.org
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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"
+#if BX_WITH_RFB
+
+#include "icon_bochs.h"
+#include "font/vga.bitmap.h"
+
+class bx_rfb_gui_c : public bx_gui_c {
+public:
+ bx_rfb_gui_c (void) {}
+ DECLARE_GUI_VIRTUAL_METHODS()
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_rfb_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(rfb)
+
+#define LOG_THIS theGui->
+
+#ifdef WIN32
+
+#include <winsock.h>
+#include <process.h>
+#include "rfb.h"
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <pthread.h>
+typedef unsigned long CARD32;
+typedef unsigned short CARD16;
+typedef short INT16;
+typedef unsigned char CARD8;
+typedef int SOCKET;
+
+#endif
+
+#include "rfbproto.h"
+
+static bool keep_alive;
+static bool client_connected;
+
+#define BX_RFB_PORT_MIN 5900
+#define BX_RFB_PORT_MAX 5949
+static unsigned short rfbPort;
+
+// Headerbar stuff
+unsigned rfbBitmapCount = 0;
+struct {
+ char *bmap;
+ unsigned xdim;
+ unsigned ydim;
+} rfbBitmaps[BX_MAX_PIXMAPS];
+
+unsigned rfbHeaderbarBitmapCount = 0;
+struct {
+ unsigned int index;
+ unsigned int xorigin;
+ unsigned int yorigin;
+ unsigned int alignment;
+ void (*f)(void);
+} rfbHeaderbarBitmaps[BX_MAX_HEADERBAR_ENTRIES];
+
+//Keyboard stuff
+#define KEYBOARD true
+#define MOUSE false
+#define MAX_KEY_EVENTS 512
+struct {
+ bool type;
+ int key;
+ int down;
+ int x;
+ int y;
+} rfbKeyboardEvent[MAX_KEY_EVENTS];
+static unsigned long rfbKeyboardEvents = 0;
+static bool bKeyboardInUse = false;
+
+// Misc Stuff
+struct {
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int height;
+ bool updated;
+} rfbUpdateRegion;
+
+static char *rfbScreen;
+static char rfbPallet[256];
+
+static long rfbDimensionX, rfbDimensionY;
+static long rfbStretchedX, rfbStretchedY;
+static long rfbHeaderbarY;
+static long rfbTileX = 0;
+static long rfbTileY = 0;
+static unsigned long rfbCursorX = 0;
+static unsigned long rfbCursorY = 0;
+static unsigned long rfbOriginLeft = 0;
+static unsigned long rfbOriginRight = 0;
+
+static unsigned int text_rows=25, text_cols=80;
+static unsigned int font_height=16, font_width=8;
+
+//static unsigned long ServerThread = 0;
+//static unsigned long ServerThreadID = 0;
+
+static SOCKET sGlobal;
+
+void ServerThreadInit(void *indata);
+void HandleRfbClient(SOCKET sClient);
+int ReadExact(int sock, char *buf, int len);
+int WriteExact(int sock, char *buf, int len);
+void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client);
+void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color);
+void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client);
+void SendUpdate(int x, int y, int width, int height);
+void StartThread();
+void rfbKeyPressed(Bit32u key, int press_release);
+void rfbMouseMove(int x, int y, int bmask);
+void DrawColorPallet();
+
+static const rfbPixelFormat BGR233Format = {
+ 8, 8, 1, 1, 7, 7, 3, 0, 3, 6
+};
+
+// Set this for the endian of your machine. 0 = big, 1 = little
+static const int rfbEndianTest = 1;
+
+#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
+#define Swap32(l) (((l) >> 24) | (((l) & 0x00ff0000) >> 8) | (((l) & 0x0000ff00) << 8) | ((l) << 24))
+#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s))
+#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l))
+#define PF_EQ(x,y) ((x.bitsPerPixel == y.bitsPerPixel) && (x.depth == y.depth) && (x.trueColour == y.trueColour) && ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && (!x.trueColour || ((x.redMax == y.redMax) && (x.greenMax == y.greenMax) && (x.blueMax == y.blueMax) && (x.redShift == y.redShift) && (x.greenShift == y.greenShift) && (x.blueShift == y.blueShift))))
+
+// This file defines stubs for the GUI interface, which is a
+// place to start if you want to port bochs to a platform, for
+// which there is no support for your native GUI, or if you want to compile
+// bochs without any native GUI support (no output window or
+// keyboard input will be possible).
+// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific
+// implementations of this interface. -Kevin
+
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+// specific options from the command line. (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+// only updated regions of the screen to the gui code to be redrawn.
+// These define the dimensions of a region (tile).
+// headerbar_y: A headerbar (toolbar) is display on the top of the
+// VGA window, showing floppy status, and other information. It
+// always assumes the width of the current VGA mode width, but
+// it's height is defined by this parameter.
+
+void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y)
+{
+ unsigned char fc, vc;
+
+ put("RFB");
+ UNUSED(bochs_icon_bits);
+
+ // the ask menu doesn't work on the client side
+ io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
+
+ rfbHeaderbarY = headerbar_y;
+ rfbDimensionX = 640;
+ rfbDimensionY = 480 + rfbHeaderbarY;
+ rfbStretchedX = rfbDimensionX;
+ rfbStretchedY = rfbDimensionY;
+ rfbTileX = tilewidth;
+ rfbTileY = tileheight;
+
+ for(int i = 0; i < 256; i++) {
+ for(int j = 0; j < 16; j++) {
+ vc = bx_vgafont[i].data[j];
+ fc = 0;
+ for (int b = 0; b < 8; b++) {
+ fc |= (vc & 0x01) << (7 - b);
+ vc >>= 1;
+ }
+ vga_charmap[i*32+j] = fc;
+ }
+ }
+
+ rfbScreen = (char *)malloc(rfbDimensionX * rfbDimensionY);
+ memset(&rfbPallet, 0, sizeof(rfbPallet));
+ rfbPallet[63] = (char)0xFF;
+
+ rfbUpdateRegion.x = rfbDimensionX;
+ rfbUpdateRegion.y = rfbDimensionY;
+ rfbUpdateRegion.width = 0;
+ rfbUpdateRegion.height = 0;
+ rfbUpdateRegion.updated = false;
+
+ keep_alive = true;
+ client_connected = false;
+ StartThread();
+
+#ifdef WIN32
+ Sleep(1000);
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+#endif
+ if (bx_options.Oprivate_colormap->get ()) {
+ BX_ERROR(( "private_colormap option ignored." ));
+ }
+ int counter = 30;
+ while ((!client_connected) && (counter--)) {
+#ifdef WIN32
+ Sleep(1000);
+#else
+ sleep(1);
+#endif
+ }
+ if (counter < 0) BX_PANIC(("timeout! no client present"));
+}
+
+bool InitWinsock()
+{
+#ifdef WIN32
+ WSADATA wsaData;
+ if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false;
+#endif
+ return true;
+}
+
+bool StopWinsock()
+{
+#ifdef WIN32
+ WSACleanup();
+#endif
+ return true;
+}
+
+void ServerThreadInit(void *indata)
+{
+ SOCKET sServer;
+ SOCKET sClient;
+ struct sockaddr_in sai;
+ unsigned int sai_size;
+ int port_ok = 0;
+
+#ifdef WIN32
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
+#endif
+ if(!InitWinsock()) {
+ BX_PANIC(( "could not initialize winsock."));
+ goto end_of_thread;
+ }
+
+ sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(sServer == -1) {
+ BX_PANIC(( "could not create socket." ));
+ goto end_of_thread;
+ }
+ for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) {
+ sai.sin_addr.s_addr = INADDR_ANY;
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(rfbPort);
+ BX_INFO (("Trying port %d", rfbPort));
+ if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) {
+ BX_INFO(( "Could not bind socket."));
+ continue;
+ }
+ if(listen(sServer, SOMAXCONN) == -1) {
+ BX_INFO(( "Could not listen on socket."));
+ continue;
+ }
+ // success
+ port_ok = 1;
+ break;
+ }
+ if (!port_ok) {
+ BX_PANIC (("RFB could not bind any port between %d and %d\n",
+ BX_RFB_PORT_MIN,
+ BX_RFB_PORT_MAX));
+ goto end_of_thread;
+ }
+ BX_INFO (("listening for connections on port %i", rfbPort));
+ fprintf (stderr, "RFB: listening for connections on port %i\n", rfbPort);
+ sai_size = sizeof(sai);
+ while(keep_alive) {
+ sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size);
+ if(sClient != -1) {
+ HandleRfbClient(sClient);
+ sGlobal = -1;
+ close(sClient);
+ } else {
+ close(sClient);
+ }
+ }
+
+end_of_thread:
+ StopWinsock();
+}
+
+void HandleRfbClient(SOCKET sClient)
+{
+ char rfbName[] = "Bochs-RFB";
+ rfbProtocolVersionMsg pv;
+ int one = 1;
+ CARD32 auth;
+ rfbClientInitMsg cim;
+ rfbServerInitMsg sim;
+
+ client_connected = true;
+ setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
+ fprintf(stderr, "# RFB: accepted client connection.\n");
+ sprintf(pv, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+ if(WriteExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could not send protocol version.\n");
+ return;
+ }
+ if(ReadExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could not recieve client protocol version.\n");
+ return;
+ }
+
+ auth = Swap32IfLE(rfbNoAuth);
+ if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could not send authorization method.\n");
+ return;
+ }
+
+ if(ReadExact(sClient, (char *)&cim, sz_rfbClientInitMsg) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could not recieve client initialization message.\n");
+ return;
+ }
+
+ sim.framebufferWidth = Swap16IfLE((short)rfbDimensionX);
+ sim.framebufferHeight = Swap16IfLE((short)rfbDimensionY);
+ sim.format = BGR233Format;
+ sim.format.redMax = Swap16IfLE(sim.format.redMax);
+ sim.format.greenMax = Swap16IfLE(sim.format.greenMax);
+ sim.format.blueMax = Swap16IfLE(sim.format.blueMax);
+ sim.nameLength = strlen(rfbName);
+ sim.nameLength = Swap32IfLE(sim.nameLength);
+ if(WriteExact(sClient, (char *)&sim, sz_rfbServerInitMsg) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could send server initialization message.\n");
+ return;
+ }
+ if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) {
+ fprintf(stderr, "# ERROR: RFB: could not send server name.\n");
+ return;
+ }
+
+ sGlobal = sClient;
+ while(keep_alive) {
+ CARD8 msgType;
+ int n;
+
+ if((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) {
+ if(n == 0) {
+ fprintf(stderr, "# RFB: client closed connection.\n");
+ } else {
+ fprintf(stderr, "# RFB: error recieving data.\n");
+ }
+ return;
+ }
+
+ switch(msgType) {
+ case rfbSetPixelFormat:
+ {
+ rfbSetPixelFormatMsg spf;
+ ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMsg));
+
+ spf.format.bitsPerPixel = spf.format.bitsPerPixel;
+ spf.format.depth = spf.format.depth;
+ spf.format.trueColour = (spf.format.trueColour ? 1 : 0);
+ spf.format.bigEndian = (spf.format.bigEndian ? 1 : 0);
+ spf.format.redMax = Swap16IfLE(spf.format.redMax);
+ spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
+ spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
+ spf.format.redShift = spf.format.redShift;
+ spf.format.greenShift = spf.format.greenShift;
+ spf.format.blueShift = spf.format.blueShift;
+
+ if (!PF_EQ(spf.format, BGR233Format)) {
+ fprintf(stderr,"# ERROR: RFB: client has wrong pixel format\n");
+ //return;
+ }
+ break;
+ }
+ case rfbFixColourMapEntries:
+ {
+ rfbFixColourMapEntriesMsg fcme;
+ ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMsg));
+ break;
+ }
+ case rfbSetEncodings:
+ {
+ rfbSetEncodingsMsg se;
+ int i;
+ CARD32 enc;
+ ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMsg));
+ se.nEncodings = Swap16IfLE(se.nEncodings);
+ for(i = 0; i < se.nEncodings; i++) {
+ if((n = ReadExact(sClient, (char *)&enc, sizeof(CARD32))) <= 0) {
+ if(n == 0) {
+ fprintf(stderr, "# RFB: client closed connection.\n");
+ } else {
+ fprintf(stderr, "# RFB: error recieving data.\n");
+ }
+ return;
+ }
+ }
+ break;
+ }
+ case rfbFramebufferUpdateRequest:
+ {
+ rfbFramebufferUpdateRequestMsg fur;
+
+ ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMsg));
+ if(!fur.incremental) {
+ rfbUpdateRegion.x = 0;
+ rfbUpdateRegion.y = 0;
+ rfbUpdateRegion.width = rfbDimensionX;
+ rfbUpdateRegion.height = rfbDimensionY;
+ rfbUpdateRegion.updated = true;
+ } //else {
+ // if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x;
+ // if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y;
+ // if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x);
+ // if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y);
+ //}
+ //rfbUpdateRegion.updated = true;
+ break;
+ }
+ case rfbKeyEvent:
+ {
+ rfbKeyEventMsg ke;
+ ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMsg));
+ ke.key = Swap32IfLE(ke.key);
+ while(bKeyboardInUse);
+ bKeyboardInUse = true;
+ if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
+ rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD;
+ rfbKeyboardEvent[rfbKeyboardEvents].key = ke.key;
+ rfbKeyboardEvent[rfbKeyboardEvents].down = ke.down;
+ rfbKeyboardEvents++;
+ bKeyboardInUse = false;
+ break;
+ }
+ case rfbPointerEvent:
+ {
+ rfbPointerEventMsg pe;
+ ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMsg));
+ while(bKeyboardInUse);
+ bKeyboardInUse = true;
+ if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
+ rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE;
+ rfbKeyboardEvent[rfbKeyboardEvents].x = Swap16IfLE(pe.x);
+ rfbKeyboardEvent[rfbKeyboardEvents].y = Swap16IfLE(pe.y);
+ rfbKeyboardEvent[rfbKeyboardEvents].down = pe.buttonMask;
+ rfbKeyboardEvents++;
+ bKeyboardInUse = false;
+ break;
+ }
+ case rfbClientCutText:
+ {
+ rfbClientCutTextMsg cct;
+ ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMsg));
+ break;
+ }
+ }
+ }
+}
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+void bx_rfb_gui_c::handle_events(void)
+{
+ unsigned int i = 0;
+ while(bKeyboardInUse);
+ bKeyboardInUse = true;
+ if(rfbKeyboardEvents > 0) {
+ for(i = 0; i < rfbKeyboardEvents; i++) {
+ if(rfbKeyboardEvent[i].type == KEYBOARD) {
+ rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down);
+ } else { //type == MOUSE;
+ rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].down);
+ }
+ }
+ rfbKeyboardEvents = 0;
+ }
+ bKeyboardInUse = false;
+
+ if(rfbUpdateRegion.updated) {
+ SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width, rfbUpdateRegion.height);
+ rfbUpdateRegion.x = rfbDimensionX;
+ rfbUpdateRegion.y = rfbDimensionY;
+ rfbUpdateRegion.width = 0;
+ rfbUpdateRegion.height = 0;
+ }
+ rfbUpdateRegion.updated = false;
+}
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+void bx_rfb_gui_c::flush(void)
+{
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared. Don't
+// clear the area that defines the headerbar.
+void bx_rfb_gui_c::clear_screen(void)
+{
+ memset(&rfbScreen[rfbDimensionX * rfbHeaderbarY], 0, rfbDimensionX * (rfbDimensionY - rfbHeaderbarY));
+}
+
+
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+// of the screen from the last call. See below
+// new_text: array of character/attributes making up the current
+// contents, which should now be displayed. See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+// This represents 80 characters wide by 25 high, with
+// each character being 2 bytes. The first by is the
+// character value, the second is the attribute byte.
+// I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+void bx_rfb_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+ unsigned char *old_line, *new_line;
+ unsigned char cAttr, cChar;
+ unsigned int curs, hchars, offset, rows, x, y, xc, yc;
+ bx_bool force_update=0;
+
+ UNUSED(nrows);
+
+ if(charmap_updated) {
+ force_update = 1;
+ charmap_updated = 0;
+ }
+
+ // first invalidate character at previous and new cursor location
+ if ( (rfbCursorY < text_rows) && (rfbCursorX < text_cols) ) {
+ curs = rfbCursorY * tm_info.line_offset + rfbCursorX * 2;
+ old_text[curs] = ~new_text[curs];
+ }
+ if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
+ (cursor_y < text_rows) && (cursor_x < text_cols)) {
+ curs = cursor_y * tm_info.line_offset + cursor_x * 2;
+ old_text[curs] = ~new_text[curs];
+ } else {
+ curs = 0xffff;
+ }
+
+ rows = text_rows;
+ y = 0;
+ do {
+ hchars = text_cols;
+ new_line = new_text;
+ old_line = old_text;
+ offset = y * tm_info.line_offset;
+ yc = y * font_height + rfbHeaderbarY;
+ x = 0;
+ do {
+ if (force_update || (old_text[0] != new_text[0])
+ || (old_text[1] != new_text[1])) {
+ cChar = new_text[0];
+ cAttr = new_text[1];
+ xc = x * 8;
+ DrawChar(xc, yc, 8, font_height, 0, (char *)&vga_charmap[cChar<<5], cAttr);
+ if(yc < rfbUpdateRegion.y) rfbUpdateRegion.y = yc;
+ if((yc + font_height - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = (yc + font_height - rfbUpdateRegion.y);
+ if(xc < rfbUpdateRegion.x) rfbUpdateRegion.x = xc;
+ if((xc + 8 - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = (xc + 8 - rfbUpdateRegion.x);
+ rfbUpdateRegion.updated = true;
+ if (offset == curs) {
+ cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
+ DrawChar(xc, yc + tm_info.cs_start, 8, tm_info.cs_end - tm_info.cs_start + 1,
+ tm_info.cs_start, (char *)&vga_charmap[cChar<<5], cAttr);
+ }
+ }
+ x++;
+ new_text+=2;
+ old_text+=2;
+ offset+=2;
+ } while (--hchars);
+ y++;
+ new_text = new_line + tm_info.line_offset;
+ old_text = old_line + tm_info.line_offset;
+ } while (--rows);
+
+ rfbCursorX = cursor_x;
+ rfbCursorY = cursor_y;
+}
+
+ int
+bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ return 0;
+}
+
+ int
+bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+// 1=screen updated needed (redraw using current colormap)
+
+bx_bool bx_rfb_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+ rfbPallet[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6);
+ return(1);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+// dimension equal to the 'tilewidth' & 'tileheight' parameters to
+// ::specific_init(). Each value specifies an index into the
+// array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+// left of the window.
+void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+ UpdateScreen(tile, x0, y0 + rfbHeaderbarY, rfbTileX, rfbTileY, false);
+ if(x0 < rfbUpdateRegion.x) rfbUpdateRegion.x = x0;
+ if((y0 + rfbHeaderbarY) < rfbUpdateRegion.y) rfbUpdateRegion.y = y0 + rfbHeaderbarY;
+ if(((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y);
+ if(((x0 + rfbTileX) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((x0 + rfbTileX) - rfbUpdateRegion.x);
+ rfbUpdateRegion.updated = true;
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+ void
+bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+ if (bpp > 8) {
+ BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
+ }
+ if (fheight > 0) {
+ font_height = fheight;
+ font_width = fwidth;
+ text_cols = x / fwidth;
+ text_rows = y / fheight;
+ } else {
+ if ((x > 640) || (y > 480)) {
+ BX_PANIC(("dimension_update(): RFB doesn't support graphics modes > 640x480 (%dx%d)", x, y));
+ }
+ }
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar. Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
+// bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+ if(rfbBitmapCount >= BX_MAX_PIXMAPS) {
+ fprintf(stderr, "# RFB: too many pixmaps.\n");
+ return 0;
+ }
+ rfbBitmaps[rfbBitmapCount].bmap = (char *)malloc((xdim * ydim) / 8);
+ rfbBitmaps[rfbBitmapCount].xdim = xdim;
+ rfbBitmaps[rfbBitmapCount].ydim = ydim;
+ memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8);
+
+ rfbBitmapCount++;
+ return(rfbBitmapCount - 1);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+// ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
+// or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+// meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+// the boundaries of this bitmap.
+
+unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+ int hb_index;
+
+ if((rfbHeaderbarBitmapCount + 1) > BX_MAX_HEADERBAR_ENTRIES) {
+ return 0;
+ }
+
+ rfbHeaderbarBitmapCount++;
+ hb_index = rfbHeaderbarBitmapCount - 1;
+ rfbHeaderbarBitmaps[hb_index].index = bmap_id;
+ rfbHeaderbarBitmaps[hb_index].alignment = alignment;
+ rfbHeaderbarBitmaps[hb_index].f = f;
+ if (alignment == BX_GRAVITY_LEFT) {
+ rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginLeft;
+ rfbHeaderbarBitmaps[hb_index].yorigin = 0;
+ rfbOriginLeft += rfbBitmaps[bmap_id].xdim;
+ } else { // BX_GRAVITY_RIGHT
+ rfbOriginRight += rfbBitmaps[bmap_id].xdim;
+ rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginRight;
+ rfbHeaderbarBitmaps[hb_index].yorigin = 0;
+ }
+ return hb_index;
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+void bx_rfb_gui_c::show_headerbar(void)
+{
+ char *newBits;
+ unsigned int i, xorigin;
+
+ newBits = (char *)malloc(rfbDimensionX * rfbHeaderbarY);
+ memset(newBits, 0, (rfbDimensionX * rfbHeaderbarY));
+ DrawBitmap(0, 0, rfbDimensionX, rfbHeaderbarY, newBits, (char)0xf0, false);
+ for(i = 0; i < rfbHeaderbarBitmapCount; i++) {
+ if(rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT) {
+ xorigin = rfbHeaderbarBitmaps[i].xorigin;
+ } else {
+ xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin;
+ }
+ DrawBitmap(xorigin, 0, rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].ydim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].bmap, (char)0xf0, false);
+ }
+ free(newBits);
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'. 'bmap_id' will have
+// been generated by ::create_bitmap(). The old and new bitmap
+// must be of the same size. This allows the bitmap the user
+// sees to change, when some action occurs. For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+ rfbHeaderbarBitmaps[hbar_id].index = bmap_id;
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+void bx_rfb_gui_c::exit(void)
+{
+ unsigned int i;
+ keep_alive = false;
+ StopWinsock();
+ free(rfbScreen);
+ for(i = 0; i < rfbBitmapCount; i++) {
+ free(rfbBitmaps[i].bmap);
+ }
+ fprintf(stderr, "# RFB: bx_rfb_gui_c::exit()\n");
+}
+
+/*
+* ReadExact reads an exact number of bytes on a TCP socket. Returns 1 if
+* those bytes have been read, 0 if the other end has closed, or -1 if an error
+* occurred (errno is set to ETIMEDOUT if it timed out).
+*/
+
+int ReadExact(int sock, char *buf, int len)
+{
+ int n;
+
+ while (len > 0) {
+ n = recv(sock, buf, len, 0);
+ if (n > 0) {
+ buf += n;
+ len -= n;
+ } else {
+ return n;
+ }
+ }
+ return 1;
+}
+
+/*
+* WriteExact writes an exact number of bytes on a TCP socket. Returns 1 if
+* those bytes have been written, or -1 if an error occurred (errno is set to
+* ETIMEDOUT if it timed out).
+*/
+
+int WriteExact(int sock, char *buf, int len)
+{
+ int n;
+
+ while (len > 0) {
+ n = send(sock, buf, len,0);
+
+ if (n > 0) {
+ buf += n;
+ len -= n;
+ } else if (n == 0) {
+ fprintf(stderr,"WriteExact: write returned 0?\n");
+ return n;
+ } else {
+ return n;
+ }
+ }
+ return 1;
+}
+
+void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client)
+{
+ int i;
+ unsigned char *newBits;
+ char fgcolor, bgcolor;
+ char vgaPallet[] = { (char)0x00, //Black
+ (char)0x01, //Dark Blue
+ (char)0x02, //Dark Green
+ (char)0x03, //Dark Cyan
+ (char)0x04, //Dark Red
+ (char)0x05, //Dark Magenta
+ (char)0x06, //Brown
+ (char)0x07, //Light Gray
+ (char)0x38, //Dark Gray
+ (char)0x09, //Light Blue
+ (char)0x12, //Green
+ (char)0x1B, //Cyan
+ (char)0x24, //Light Red
+ (char)0x2D, //Magenta
+ (char)0x36, //Yellow
+ (char)0x3F //White
+ };
+
+ bgcolor = vgaPallet[(color >> 4) & 0xF];
+ fgcolor = vgaPallet[color & 0xF];
+ newBits = (unsigned char *)malloc(width * height);
+ memset(newBits, 0, (width * height));
+ for(i = 0; i < (width * height) / 8; i++) {
+ newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor;
+ newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor;
+ newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor;
+ newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor;
+ newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor;
+ newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor;
+ newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor;
+ newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor;
+ }
+ UpdateScreen(newBits, x, y, width, height, update_client);
+ //DrawColorPallet();
+ free(newBits);
+}
+
+void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color)
+{
+ static unsigned char newBits[8 * 32];
+ unsigned char mask;
+ int bytes = width * height;
+ char fgcolor, bgcolor;
+ char vgaPallet[] = { (char)0x00, //Black
+ (char)0x01, //Dark Blue
+ (char)0x02, //Dark Green
+ (char)0x03, //Dark Cyan
+ (char)0x04, //Dark Red
+ (char)0x05, //Dark Magenta
+ (char)0x06, //Brown
+ (char)0x07, //Light Gray
+ (char)0x38, //Dark Gray
+ (char)0x09, //Light Blue
+ (char)0x12, //Green
+ (char)0x1B, //Cyan
+ (char)0x24, //Light Red
+ (char)0x2D, //Magenta
+ (char)0x36, //Yellow
+ (char)0x3F //White
+ };
+
+ bgcolor = vgaPallet[(color >> 4) & 0xF];
+ fgcolor = vgaPallet[color & 0xF];
+
+ for(int i = 0; i < bytes; i+=width) {
+ mask = 0x80;
+ for(int j = 0; j < width; j++) {
+ newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
+ mask >>= 1;
+ }
+ fonty++;
+ }
+ UpdateScreen(newBits, x, y, width, height, false);
+ //DrawColorPallet();
+}
+
+void DrawColorPallet()
+{
+ unsigned char bits[100];
+ int x = 0, y = 0, c;
+ for(c = 0; c < 256; c++) {
+ memset(&bits, rfbPallet[c], 100);
+ UpdateScreen(bits, x, y, 10, 10, false);
+ x += 10;
+ if(x > 70) {
+ y += 10;
+ x = 0;
+ }
+ }
+}
+
+void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client)
+{
+ int i, c;
+ for(i = 0; i < height; i++) {
+ for(c = 0; c < width; c++) {
+ newBits[(i * width) + c] = rfbPallet[newBits[(i * width) + c]];
+ }
+ memcpy(&rfbScreen[y * rfbDimensionX + x], &newBits[i * width], width);
+ y++;
+ }
+ if(update_client) {
+ if(sGlobal == -1) return;
+ rfbFramebufferUpdateMsg fum;
+ rfbFramebufferUpdateRectHeader furh;
+ fum.type = rfbFramebufferUpdate;
+ fum.nRects = Swap16IfLE(1);
+ WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg);
+ furh.r.x = Swap16IfLE(x);
+ furh.r.y = Swap16IfLE((y - i));
+ furh.r.w = Swap16IfLE((short)width);
+ furh.r.h = Swap16IfLE((short)height);
+ furh.encoding = Swap32IfLE(rfbEncodingRaw);
+ WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader);
+ WriteExact(sGlobal, (char *)newBits, width * height);
+ }
+}
+
+void SendUpdate(int x, int y, int width, int height)
+{
+ char *newBits;
+ int i;
+
+ if(x < 0 || y < 0 || (x + width) > rfbDimensionX || (y + height) > rfbDimensionY) {
+ fprintf(stderr, "# RFB: Dimensions out of bounds. x=%i y=%i w=%i h=%i\n", x, y, width, height);
+ }
+ if(sGlobal != -1) {
+ rfbFramebufferUpdateMsg fum;
+ rfbFramebufferUpdateRectHeader furh;
+
+ fum.type = rfbFramebufferUpdate;
+ fum.nRects = Swap16IfLE(1);
+
+ furh.r.x = Swap16IfLE(x);
+ furh.r.y = Swap16IfLE(y);
+ furh.r.w = Swap16IfLE((short)width);
+ furh.r.h = Swap16IfLE((short)height);
+ furh.encoding = Swap32IfLE(rfbEncodingRaw);
+
+ newBits = (char *)malloc(width * height);
+ for(i = 0; i < height; i++) {
+ memcpy(&newBits[i * width], &rfbScreen[y * rfbDimensionX + x], width);
+ y++;
+ }
+
+ WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg);
+ WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader);
+ WriteExact(sGlobal, (char *)newBits, width * height);
+
+ free(newBits);
+ }
+}
+
+void StartThread()
+{
+#ifdef WIN32
+ _beginthread(ServerThreadInit, 0, NULL);
+#else
+ pthread_t thread;
+ pthread_create(&thread, NULL, (void *(*)(void *))&ServerThreadInit, NULL);
+#endif
+}
+
+/***********************/
+/* Keyboard Definitons */
+/* And */
+/* Functions */
+/***********************/
+
+#define XK_space 0x020
+#define XK_asciitilde 0x07e
+
+#define XK_dead_grave 0xFE50
+#define XK_dead_acute 0xFE51
+#define XK_dead_circumflex 0xFE52
+#define XK_dead_tilde 0xFE53
+
+#define XK_BackSpace 0xFF08
+#define XK_Tab 0xFF09
+#define XK_Linefeed 0xFF0A
+#define XK_Clear 0xFF0B
+#define XK_Return 0xFF0D
+#define XK_Pause 0xFF13
+#define XK_Scroll_Lock 0xFF14
+#define XK_Sys_Req 0xFF15
+#define XK_Escape 0xFF1B
+
+#define XK_Delete 0xFFFF
+
+#define XK_Home 0xFF50
+#define XK_Left 0xFF51
+#define XK_Up 0xFF52
+#define XK_Right 0xFF53
+#define XK_Down 0xFF54
+#define XK_Page_Up 0xFF55
+#define XK_Page_Down 0xFF56
+#define XK_End 0xFF57
+#define XK_Begin 0xFF58
+
+#define XK_Select 0xFF60
+#define XK_Print 0xFF61
+#define XK_Execute 0xFF62
+#define XK_Insert 0xFF63
+
+#define XK_Cancel 0xFF69
+#define XK_Help 0xFF6A
+#define XK_Break 0xFF6B
+#define XK_Num_Lock 0xFF7F
+
+#define XK_KP_Space 0xFF80
+#define XK_KP_Tab 0xFF89
+#define XK_KP_Enter 0xFF8D
+
+#define XK_KP_Home 0xFF95
+#define XK_KP_Left 0xFF96
+#define XK_KP_Up 0xFF97
+#define XK_KP_Right 0xFF98
+#define XK_KP_Down 0xFF99
+#define XK_KP_Prior 0xFF9A
+#define XK_KP_Page_Up 0xFF9A
+#define XK_KP_Next 0xFF9B
+#define XK_KP_Page_Down 0xFF9B
+#define XK_KP_End 0xFF9C
+#define XK_KP_Begin 0xFF9D
+#define XK_KP_Insert 0xFF9E
+#define XK_KP_Delete 0xFF9F
+#define XK_KP_Equal 0xFFBD
+#define XK_KP_Multiply 0xFFAA
+#define XK_KP_Add 0xFFAB
+#define XK_KP_Separator 0xFFAC
+#define XK_KP_Subtract 0xFFAD
+#define XK_KP_Decimal 0xFFAE
+#define XK_KP_Divide 0xFFAF
+
+#define XK_KP_F1 0xFF91
+#define XK_KP_F2 0xFF92
+#define XK_KP_F3 0xFF93
+#define XK_KP_F4 0xFF94
+
+#define XK_KP_0 0xFFB0
+#define XK_KP_1 0xFFB1
+#define XK_KP_2 0xFFB2
+#define XK_KP_3 0xFFB3
+#define XK_KP_4 0xFFB4
+#define XK_KP_5 0xFFB5
+#define XK_KP_6 0xFFB6
+#define XK_KP_7 0xFFB7
+#define XK_KP_8 0xFFB8
+#define XK_KP_9 0xFFB9
+
+#define XK_F1 0xFFBE
+#define XK_F2 0xFFBF
+#define XK_F3 0xFFC0
+#define XK_F4 0xFFC1
+#define XK_F5 0xFFC2
+#define XK_F6 0xFFC3
+#define XK_F7 0xFFC4
+#define XK_F8 0xFFC5
+#define XK_F9 0xFFC6
+#define XK_F10 0xFFC7
+#define XK_F11 0xFFC8
+#define XK_F12 0xFFC9
+#define XK_F13 0xFFCA
+#define XK_F14 0xFFCB
+#define XK_F15 0xFFCC
+#define XK_F16 0xFFCD
+#define XK_F17 0xFFCE
+#define XK_F18 0xFFCF
+#define XK_F19 0xFFD0
+#define XK_F20 0xFFD1
+#define XK_F21 0xFFD2
+#define XK_F22 0xFFD3
+#define XK_F23 0xFFD4
+#define XK_F24 0xFFD5
+
+
+#define XK_Shift_L 0xFFE1
+#define XK_Shift_R 0xFFE2
+#define XK_Control_L 0xFFE3
+#define XK_Control_R 0xFFE4
+#define XK_Caps_Lock 0xFFE5
+#define XK_Shift_Lock 0xFFE6
+#define XK_Meta_L 0xFFE7
+#define XK_Meta_R 0xFFE8
+#define XK_Alt_L 0xFFE9
+#define XK_Alt_R 0xFFEA
+
+Bit32u rfb_ascii_to_key_event[0x5f] = {
+ // !"#$%&'
+ BX_KEY_SPACE,
+ BX_KEY_1,
+ BX_KEY_SINGLE_QUOTE,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_7,
+ BX_KEY_SINGLE_QUOTE,
+
+ // ()*+,-./
+ BX_KEY_9,
+ BX_KEY_0,
+ BX_KEY_8,
+ BX_KEY_EQUALS,
+ BX_KEY_COMMA,
+ BX_KEY_MINUS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // 01234567
+ BX_KEY_0,
+ BX_KEY_1,
+ BX_KEY_2,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_6,
+ BX_KEY_7,
+
+ // 89:;<=>?
+ BX_KEY_8,
+ BX_KEY_9,
+ BX_KEY_SEMICOLON,
+ BX_KEY_SEMICOLON,
+ BX_KEY_COMMA,
+ BX_KEY_EQUALS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // @ABCDEFG
+ BX_KEY_2,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+
+ // HIJKLMNO
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+
+ // PQRSTUVW
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // XYZ[\]^_
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_6,
+ BX_KEY_MINUS,
+
+ // `abcdefg
+ BX_KEY_GRAVE,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+ // hijklmno
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+ // pqrstuvw
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // xyz{|}~
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_GRAVE
+ };
+
+void rfbKeyPressed(Bit32u key, int press_release)
+{
+ Bit32u key_event;
+
+ if((key >= XK_space) && (key <= XK_asciitilde)) {
+ key_event = rfb_ascii_to_key_event[key - XK_space];
+ } else {
+ switch (key) {
+ case XK_KP_1:
+#ifdef XK_KP_End
+ case XK_KP_End:
+#endif
+ key_event = BX_KEY_KP_END; break;
+
+ case XK_KP_2:
+#ifdef XK_KP_Down
+ case XK_KP_Down:
+#endif
+ key_event = BX_KEY_KP_DOWN; break;
+
+ case XK_KP_3:
+#ifdef XK_KP_Page_Down
+ case XK_KP_Page_Down:
+#endif
+ key_event = BX_KEY_KP_PAGE_DOWN; break;
+
+ case XK_KP_4:
+#ifdef XK_KP_Left
+ case XK_KP_Left:
+#endif
+ key_event = BX_KEY_KP_LEFT; break;
+
+ case XK_KP_5:
+#ifdef XK_KP_Begin
+ case XK_KP_Begin:
+#endif
+ key_event = BX_KEY_KP_5; break;
+
+ case XK_KP_6:
+#ifdef XK_KP_Right
+ case XK_KP_Right:
+#endif
+ key_event = BX_KEY_KP_RIGHT; break;
+
+ case XK_KP_7:
+#ifdef XK_KP_Home
+ case XK_KP_Home:
+#endif
+ key_event = BX_KEY_KP_HOME; break;
+
+ case XK_KP_8:
+#ifdef XK_KP_Up
+ case XK_KP_Up:
+#endif
+ key_event = BX_KEY_KP_UP; break;
+
+ case XK_KP_9:
+#ifdef XK_KP_Page_Up
+ case XK_KP_Page_Up:
+#endif
+ key_event = BX_KEY_KP_PAGE_UP; break;
+
+ case XK_KP_0:
+#ifdef XK_KP_Insert
+ case XK_KP_Insert:
+#endif
+ key_event = BX_KEY_KP_INSERT; break;
+
+ case XK_KP_Decimal:
+#ifdef XK_KP_Delete
+ case XK_KP_Delete:
+#endif
+ key_event = BX_KEY_KP_DELETE; break;
+
+#ifdef XK_KP_Enter
+ case XK_KP_Enter: key_event = BX_KEY_KP_ENTER; break;
+#endif
+
+ case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
+ case XK_KP_Add: key_event = BX_KEY_KP_ADD; break;
+
+ case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
+ case XK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break;
+
+
+ case XK_Up: key_event = BX_KEY_UP; break;
+ case XK_Down: key_event = BX_KEY_DOWN; break;
+ case XK_Left: key_event = BX_KEY_LEFT; break;
+ case XK_Right: key_event = BX_KEY_RIGHT; break;
+
+
+ case XK_Delete: key_event = BX_KEY_DELETE; break;
+ case XK_BackSpace: key_event = BX_KEY_BACKSPACE; break;
+ case XK_Tab: key_event = BX_KEY_TAB; break;
+#ifdef XK_ISO_Left_Tab
+ case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
+#endif
+ case XK_Return: key_event = BX_KEY_ENTER; break;
+ case XK_Escape: key_event = BX_KEY_ESC; break;
+ case XK_F1: key_event = BX_KEY_F1; break;
+ case XK_F2: key_event = BX_KEY_F2; break;
+ case XK_F3: key_event = BX_KEY_F3; break;
+ case XK_F4: key_event = BX_KEY_F4; break;
+ case XK_F5: key_event = BX_KEY_F5; break;
+ case XK_F6: key_event = BX_KEY_F6; break;
+ case XK_F7: key_event = BX_KEY_F7; break;
+ case XK_F8: key_event = BX_KEY_F8; break;
+ case XK_F9: key_event = BX_KEY_F9; break;
+ case XK_F10: key_event = BX_KEY_F10; break;
+ case XK_F11: key_event = BX_KEY_F11; break;
+ case XK_F12: key_event = BX_KEY_F12; break;
+ case XK_Control_L: key_event = BX_KEY_CTRL_L; break;
+#ifdef XK_Control_R
+ case XK_Control_R: key_event = BX_KEY_CTRL_R; break;
+#endif
+ case XK_Shift_L: key_event = BX_KEY_SHIFT_L; break;
+ case XK_Shift_R: key_event = BX_KEY_SHIFT_R; break;
+ case XK_Alt_L: key_event = BX_KEY_ALT_L; break;
+#ifdef XK_Alt_R
+ case XK_Alt_R: key_event = BX_KEY_ALT_R; break;
+#endif
+ case XK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break;
+ case XK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break;
+#ifdef XK_Scroll_Lock
+ case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
+#endif
+#ifdef XK_Print
+ case XK_Print: key_event = BX_KEY_PRINT; break;
+#endif
+#ifdef XK_Pause
+ case XK_Pause: key_event = BX_KEY_PAUSE; break;
+#endif
+
+ case XK_Insert: key_event = BX_KEY_INSERT; break;
+ case XK_Home: key_event = BX_KEY_HOME; break;
+ case XK_End: key_event = BX_KEY_END; break;
+ case XK_Page_Up: key_event = BX_KEY_PAGE_UP; break;
+ case XK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break;
+
+ default:
+ BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key));
+ fprintf(stderr, "RFB: rfbKeyPress(): key %04x unhandled!\n", key);
+ return;
+ break;
+ }
+ }
+
+ if (press_release) key_event |= BX_KEY_RELEASED;
+ DEV_kbd_gen_scancode(key_event);
+}
+
+void rfbMouseMove(int x, int y, int bmask)
+{
+ static int oldx = -1;
+ static int oldy = -1;
+ int xorigin;
+
+ if (oldx == oldy == -1) {
+ oldx = x;
+ oldy = y;
+ return;
+ }
+ if(y > rfbHeaderbarY) {
+ //DEV_mouse_motion(x, y - rfbHeaderbarY, buttons);
+ DEV_mouse_motion(x - oldx, oldy - y, bmask);
+ oldx = x;
+ oldy = y;
+ } else {
+ if (bmask == 1) {
+ for (unsigned i=0; i<rfbHeaderbarBitmapCount; i++) {
+ if (rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT)
+ xorigin = rfbHeaderbarBitmaps[i].xorigin;
+ else
+ xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin;
+ if ( (x>=xorigin) && (x<(xorigin+int(rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim))) ) {
+ rfbHeaderbarBitmaps[i].f();
+ return;
+ }
+ }
+ }
+ }
+}
+
+ void
+bx_rfb_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+
+#endif /* if BX_WITH_RFB */
diff --git a/tools/ioemu/gui/rfb.h b/tools/ioemu/gui/rfb.h
new file mode 100644
index 0000000000..948ac8252f
--- /dev/null
+++ b/tools/ioemu/gui/rfb.h
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfb.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// rfb.h
+// This includes the rfb spec header, the port numbers,
+// the CARD type definitions and various useful macros.
+//
+
+#ifndef RFB_H__
+#define RFB_H__
+
+// Define the CARD* types as used in X11/Xmd.h
+
+typedef unsigned long CARD32;
+typedef unsigned short CARD16;
+typedef short INT16;
+typedef unsigned char CARD8;
+
+// Define the port number offsets
+#define FLASH_PORT_OFFSET 5400
+#define INCOMING_PORT_OFFSET 5500
+#define HTTP_PORT_OFFSET 5800 // we don't use this in Venice
+#define RFB_PORT_OFFSET 5900
+
+#define _SIZEOF(x) sz_##x
+#define SIZEOF(x) _SIZEOF(x)
+
+#define PORT_TO_DISPLAY(p) ( (p) - RFB_PORT_OFFSET )
+#define DISPLAY_TO_PORT(d) ( (d) + RFB_PORT_OFFSET )
+
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ETIMEDOUT WSAETIMEDOUT
+
+#endif
diff --git a/tools/ioemu/gui/rfbproto.h b/tools/ioemu/gui/rfbproto.h
new file mode 100644
index 0000000000..a2be5f83c9
--- /dev/null
+++ b/tools/ioemu/gui/rfbproto.h
@@ -0,0 +1,675 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfbproto.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ * Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol version 3.3
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first). Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data. The order of definitions in
+ * this file is as follows:
+ *
+ * (1) Structures used in several types of message.
+ * (2) Structures used in the initial handshaking.
+ * (3) Message types.
+ * (4) Encoding types.
+ * (5) For each message type, the form of the data following the type byte.
+ * Sometimes this is defined by a single structure but the more complex
+ * messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle. This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct {
+ CARD16 x;
+ CARD16 y;
+ CARD16 w;
+ CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct {
+
+ CARD8 bitsPerPixel; /* 8,16,32 only */
+
+ CARD8 depth; /* 8 to 32 */
+
+ CARD8 bigEndian; /* True if multi-byte pixels are interpreted
+ as big endian, or if single-bit-per-pixel
+ has most significant bit of the byte
+ corresponding to first (leftmost) pixel. Of
+ course this is meaningless for 8 bits/pix */
+
+ CARD8 trueColour; /* If false then we need a "colour map" to
+ convert pixels to RGB. If true, xxxMax and
+ xxxShift specify bits used for red, green
+ and blue */
+
+ /* the following fields are only meaningful if trueColour is true */
+
+ CARD16 redMax; /* maximum red value (= 2^n - 1 where n is the
+ number of bits used for red). Note this
+ value is always in big endian order. */
+
+ CARD16 greenMax; /* similar for green */
+
+ CARD16 blueMax; /* and blue */
+
+ CARD8 redShift; /* number of shifts needed to get the red
+ value in a pixel to the least significant
+ bit. To find the red value from a given
+ pixel, do the following:
+ 1) Swap pixel value according to bigEndian
+ (e.g. if bigEndian is false and host byte
+ order is big endian, then swap).
+ 2) Shift right by redShift.
+ 3) AND with redMax (in host byte order).
+ 4) You now have the red value between 0 and
+ redMax. */
+
+ CARD8 greenShift; /* similar for green */
+
+ CARD8 blueShift; /* and blue */
+
+ CARD8 pad1;
+ CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports. These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.3
+ * this is "RFB 003.003\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism. Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent. For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK. This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * Authentication
+ *
+ * Once the protocol version has been decided, the server then sends a 32-bit
+ * word indicating whether any authentication is needed on the connection.
+ * The value of this word determines the authentication scheme in use. For
+ * version 3.0 of the protocol this may have one of the following values:
+ */
+
+#define rfbConnFailed 0
+#define rfbNoAuth 1
+#define rfbVncAuth 2
+
+/*
+ * rfbConnFailed: For some reason the connection failed (e.g. the server
+ * cannot support the desired protocol version). This is
+ * followed by a string describing the reason (where a
+ * string is specified as a 32-bit length followed by that
+ * many ASCII characters).
+ *
+ * rfbNoAuth: No authentication is needed.
+ *
+ * rfbVncAuth: The VNC authentication scheme is to be used. A 16-byte
+ * challenge follows, which the client encrypts as
+ * appropriate using the password and sends the resulting
+ * 16-byte response. If the response is correct, the
+ * server sends the 32-bit word rfbVncAuthOK. If a simple
+ * failure happens, the server sends rfbVncAuthFailed and
+ * closes the connection. If the server decides that too
+ * many failures have occurred, it sends rfbVncAuthTooMany
+ * and closes the connection. In the latter case, the
+ * server should not allow an immediate reconnection by
+ * the client.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message. At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct {
+ CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct {
+ CARD16 framebufferWidth;
+ CARD16 framebufferHeight;
+ rfbPixelFormat format; /* the server's preferred pixel format */
+ CARD32 nameLength;
+ /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants. Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest. From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages. The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1 /* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+
+
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw 0
+#define rfbEncodingCopyRect 1
+#define rfbEncodingRRE 2
+#define rfbEncodingCoRRE 4
+#define rfbEncodingHextile 5
+
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves. The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbFramebufferUpdate */
+ CARD8 pad;
+ CARD16 nRects;
+ /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data. Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct {
+ rfbRectangle r;
+ CARD32 encoding; /* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding. Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding. The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct {
+ CARD16 srcX;
+ CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure
+ * giving the number of subrectangles following. Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct {
+ CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding. We have an rfbRREHeader structure giving
+ * the number of subrectangles following. Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>]. This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct {
+ CARD8 x;
+ CARD8 y;
+ CARD8 w;
+ CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding. The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order. If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller. Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller. Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits. If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile). Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes. The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ * the background colour for this tile. The first non-raw tile in a
+ * rectangle must have this bit set. If this bit isn't set then the
+ * background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ * the foreground colour to be used for all subrectangles in this tile.
+ * If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ * subrectangles following. If not set, there are no subrectangles (i.e.
+ * the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ * value giving the colour of that subrectangle. If not set, all
+ * subrectangles are the same colour, the foreground colour; if the
+ * ForegroundSpecified bit wasn't set then the foreground is the same as
+ * the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes. The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw (1 << 0)
+#define rfbHextileBackgroundSpecified (1 << 1)
+#define rfbHextileForegroundSpecified (1 << 2)
+#define rfbHextileAnySubrects (1 << 3)
+#define rfbHextileSubrectsColoured (1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries. In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest. So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbSetColourMapEntries */
+ CARD8 pad;
+ CARD16 firstColour;
+ CARD16 nColours;
+
+ /* Followed by nColours * 3 * CARD16
+ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbServerCutText */
+ CARD8 pad1;
+ CARD16 pad2;
+ CARD32 length;
+ /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union {
+ CARD8 type;
+ rfbFramebufferUpdateMsg fu;
+ rfbSetColourMapEntriesMsg scme;
+ rfbBellMsg b;
+ rfbServerCutTextMsg sct;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbSetPixelFormat */
+ CARD8 pad1;
+ CARD16 pad2;
+ rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ * ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbFixColourMapEntries */
+ CARD8 pad;
+ CARD16 firstColour;
+ CARD16 nColours;
+
+ /* Followed by nColours * 3 * CARD16
+ r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept. Put them
+ * in order of preference, if we have any. We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbSetEncodings */
+ CARD8 pad;
+ CARD16 nEncodings;
+ /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update. If incremental
+ * is true then the client just wants the changes since the last update. If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbFramebufferUpdateRequest */
+ CARD8 incremental;
+ CARD16 x;
+ CARD16 y;
+ CARD16 w;
+ CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value. Other common keys are:
+ *
+ * BackSpace 0xff08
+ * Tab 0xff09
+ * Return or Enter 0xff0d
+ * Escape 0xff1b
+ * Insert 0xff63
+ * Delete 0xffff
+ * Home 0xff50
+ * End 0xff57
+ * Page Up 0xff55
+ * Page Down 0xff56
+ * Left 0xff51
+ * Up 0xff52
+ * Right 0xff53
+ * Down 0xff54
+ * F1 0xffbe
+ * F2 0xffbf
+ * ... ...
+ * F12 0xffc9
+ * Shift 0xffe1
+ * Control 0xffe3
+ * Meta 0xffe7
+ * Alt 0xffe9
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbKeyEvent */
+ CARD8 down; /* true if down (press), false if up */
+ CARD16 pad;
+ CARD32 key; /* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbPointerEvent */
+ CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */
+ CARD16 x;
+ CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct {
+ CARD8 type; /* always rfbClientCutText */
+ CARD8 pad1;
+ CARD16 pad2;
+ CARD32 length;
+ /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union {
+ CARD8 type;
+ rfbSetPixelFormatMsg spf;
+ rfbFixColourMapEntriesMsg fcme;
+ rfbSetEncodingsMsg se;
+ rfbFramebufferUpdateRequestMsg fur;
+ rfbKeyEventMsg ke;
+ rfbPointerEventMsg pe;
+ rfbClientCutTextMsg cct;
+} rfbClientToServerMsg;
diff --git a/tools/ioemu/gui/sdl.h b/tools/ioemu/gui/sdl.h
new file mode 100644
index 0000000000..c8df029f05
--- /dev/null
+++ b/tools/ioemu/gui/sdl.h
@@ -0,0 +1,1038 @@
+#define BX_HEADERBAR_FG_RED 0x10
+#define BX_HEADERBAR_FG_GREEN 0x10
+#define BX_HEADERBAR_FG_BLUE 0x10
+#define BX_HEADERBAR_BG_RED 0xD0
+#define BX_HEADERBAR_BG_GREEN 0xD0
+#define BX_HEADERBAR_BG_BLUE 0xD0
+
+unsigned char sdl_font8x16[256][16] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 0
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 126, 129, 165, 129, 129, 189, // 1
+ 153, 129, 129, 126, 0, 0, 0, 0 },
+ { 0, 0, 126, 255, 219, 255, 255, 195, // 2
+ 231, 255, 255, 126, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 108, 254, 254, 254, // 3
+ 254, 124, 56, 16, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 16, 56, 124, 254, // 4
+ 124, 56, 16, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 24, 60, 60, 231, 231, // 5
+ 231, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 0, 24, 60, 126, 255, 255, // 6
+ 126, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 24, 60, // 7
+ 60, 24, 0, 0, 0, 0, 0, 0 },
+ { 255, 255, 255, 255, 255, 255, 231, 195, // 8
+ 195, 231, 255, 255, 255, 255, 255, 255 },
+ { 0, 0, 0, 0, 0, 60, 102, 66, // 9
+ 66, 102, 60, 0, 0, 0, 0, 0 },
+ { 255, 255, 255, 255, 255, 195, 153, 189, // 10
+ 189, 153, 195, 255, 255, 255, 255, 255 },
+ { 0, 0, 30, 14, 26, 50, 120, 204, // 11
+ 204, 204, 204, 120, 0, 0, 0, 0 },
+ { 0, 0, 60, 102, 102, 102, 102, 60, // 12
+ 24, 126, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 63, 51, 63, 48, 48, 48, // 13
+ 48, 112, 240, 224, 0, 0, 0, 0 },
+ { 0, 0, 127, 99, 127, 99, 99, 99, // 14
+ 99, 103, 231, 230, 192, 0, 0, 0 },
+ { 0, 0, 0, 24, 24, 219, 60, 231, // 15
+ 60, 219, 24, 24, 0, 0, 0, 0 },
+ { 0, 128, 192, 224, 240, 248, 254, 248, // 16
+ 240, 224, 192, 128, 0, 0, 0, 0 },
+ { 0, 2, 6, 14, 30, 62, 254, 62, // 17
+ 30, 14, 6, 2, 0, 0, 0, 0 },
+ { 0, 0, 24, 60, 126, 24, 24, 24, // 18
+ 126, 60, 24, 0, 0, 0, 0, 0 },
+ { 0, 0, 102, 102, 102, 102, 102, 102, // 19
+ 102, 0, 102, 102, 0, 0, 0, 0 },
+ { 0, 0, 127, 219, 219, 219, 123, 27, // 20
+ 27, 27, 27, 27, 0, 0, 0, 0 },
+ { 0, 124, 198, 96, 56, 108, 198, 198, // 21
+ 108, 56, 12, 198, 124, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 22
+ 254, 254, 254, 254, 0, 0, 0, 0 },
+ { 0, 0, 24, 60, 126, 24, 24, 24, // 23
+ 126, 60, 24, 126, 0, 0, 0, 0 },
+ { 0, 0, 24, 60, 126, 24, 24, 24, // 24
+ 24, 24, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 24, 24, 24, 24, 24, 24, // 25
+ 24, 126, 60, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 24, 12, 254, // 26
+ 12, 24, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 48, 96, 254, // 27
+ 96, 48, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 192, 192, // 28
+ 192, 254, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 40, 108, 254, // 29
+ 108, 40, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 16, 56, 56, 124, // 30
+ 124, 254, 254, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 254, 254, 124, 124, // 31
+ 56, 56, 16, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 32
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 24, 60, 60, 60, 24, 24, // 33
+ 24, 0, 24, 24, 0, 0, 0, 0 },
+ { 0, 102, 102, 102, 36, 0, 0, 0, // 34
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 108, 108, 254, 108, 108, // 35
+ 108, 254, 108, 108, 0, 0, 0, 0 },
+ { 24, 24, 124, 198, 194, 192, 124, 6, // 36
+ 6, 134, 198, 124, 24, 24, 0, 0 },
+ { 0, 0, 0, 0, 194, 198, 12, 24, // 37
+ 48, 96, 198, 134, 0, 0, 0, 0 },
+ { 0, 0, 56, 108, 108, 56, 118, 220, // 38
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 48, 48, 48, 96, 0, 0, 0, // 39
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 12, 24, 48, 48, 48, 48, // 40
+ 48, 48, 24, 12, 0, 0, 0, 0 },
+ { 0, 0, 48, 24, 12, 12, 12, 12, // 41
+ 12, 12, 24, 48, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 102, 60, 255, // 42
+ 60, 102, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 24, 24, 126, // 43
+ 24, 24, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 44
+ 0, 24, 24, 24, 48, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 254, // 45
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 46
+ 0, 0, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 2, 6, 12, 24, // 47
+ 48, 96, 192, 128, 0, 0, 0, 0 },
+ { 0, 0, 56, 108, 198, 198, 214, 214, // 48
+ 198, 198, 108, 56, 0, 0, 0, 0 },
+ { 0, 0, 24, 56, 120, 24, 24, 24, // 49
+ 24, 24, 24, 126, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 6, 12, 24, 48, // 50
+ 96, 192, 198, 254, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 6, 6, 60, 6, // 51
+ 6, 6, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 12, 28, 60, 108, 204, 254, // 52
+ 12, 12, 12, 30, 0, 0, 0, 0 },
+ { 0, 0, 254, 192, 192, 192, 252, 6, // 53
+ 6, 6, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 56, 96, 192, 192, 252, 198, // 54
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 254, 198, 6, 6, 12, 24, // 55
+ 48, 48, 48, 48, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 198, 124, 198, // 56
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 198, 126, 6, // 57
+ 6, 6, 12, 120, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 24, 24, 0, 0, // 58
+ 0, 24, 24, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 24, 24, 0, 0, // 59
+ 0, 24, 24, 48, 0, 0, 0, 0 },
+ { 0, 0, 0, 6, 12, 24, 48, 96, // 60
+ 48, 24, 12, 6, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 126, 0, 0, // 61
+ 126, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 96, 48, 24, 12, 6, // 62
+ 12, 24, 48, 96, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 12, 24, 24, // 63
+ 24, 0, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 124, 198, 198, 222, 222, // 64
+ 222, 220, 192, 124, 0, 0, 0, 0 },
+ { 0, 0, 16, 56, 108, 198, 198, 254, // 65
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 252, 102, 102, 102, 124, 102, // 66
+ 102, 102, 102, 252, 0, 0, 0, 0 },
+ { 0, 0, 60, 102, 194, 192, 192, 192, // 67
+ 192, 194, 102, 60, 0, 0, 0, 0 },
+ { 0, 0, 248, 108, 102, 102, 102, 102, // 68
+ 102, 102, 108, 248, 0, 0, 0, 0 },
+ { 0, 0, 254, 102, 98, 104, 120, 104, // 69
+ 96, 98, 102, 254, 0, 0, 0, 0 },
+ { 0, 0, 254, 102, 98, 104, 120, 104, // 70
+ 96, 96, 96, 240, 0, 0, 0, 0 },
+ { 0, 0, 60, 102, 194, 192, 192, 222, // 71
+ 198, 198, 102, 58, 0, 0, 0, 0 },
+ { 0, 0, 198, 198, 198, 198, 254, 198, // 72
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 60, 24, 24, 24, 24, 24, // 73
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 30, 12, 12, 12, 12, 12, // 74
+ 204, 204, 204, 120, 0, 0, 0, 0 },
+ { 0, 0, 230, 102, 102, 108, 120, 120, // 75
+ 108, 102, 102, 230, 0, 0, 0, 0 },
+ { 0, 0, 240, 96, 96, 96, 96, 96, // 76
+ 96, 98, 102, 254, 0, 0, 0, 0 },
+ { 0, 0, 198, 238, 254, 254, 214, 198, // 77
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 198, 230, 246, 254, 222, 206, // 78
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 198, 198, 198, // 79
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 252, 102, 102, 102, 124, 96, // 80
+ 96, 96, 96, 240, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 198, 198, 198, // 81
+ 198, 214, 222, 124, 12, 14, 0, 0 },
+ { 0, 0, 252, 102, 102, 102, 124, 108, // 82
+ 102, 102, 102, 230, 0, 0, 0, 0 },
+ { 0, 0, 124, 198, 198, 96, 56, 12, // 83
+ 6, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 126, 126, 90, 24, 24, 24, // 84
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 198, 198, 198, 198, 198, 198, // 85
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 198, 198, 198, 198, 198, 198, // 86
+ 198, 108, 56, 16, 0, 0, 0, 0 },
+ { 0, 0, 198, 198, 198, 198, 214, 214, // 87
+ 214, 254, 238, 108, 0, 0, 0, 0 },
+ { 0, 0, 198, 198, 108, 124, 56, 56, // 88
+ 124, 108, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 102, 102, 102, 102, 60, 24, // 89
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 254, 198, 134, 12, 24, 48, // 90
+ 96, 194, 198, 254, 0, 0, 0, 0 },
+ { 0, 0, 60, 48, 48, 48, 48, 48, // 91
+ 48, 48, 48, 60, 0, 0, 0, 0 },
+ { 0, 0, 0, 128, 192, 224, 112, 56, // 92
+ 28, 14, 6, 2, 0, 0, 0, 0 },
+ { 0, 0, 60, 12, 12, 12, 12, 12, // 93
+ 12, 12, 12, 60, 0, 0, 0, 0 },
+ { 16, 56, 108, 198, 0, 0, 0, 0, // 94
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 95
+ 0, 0, 0, 0, 0, 255, 0, 0 },
+ { 0, 48, 24, 12, 0, 0, 0, 0, // 96
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 120, 12, 124, // 97
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 224, 96, 96, 120, 108, 102, // 98
+ 102, 102, 102, 124, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 198, 192, // 99
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 28, 12, 12, 60, 108, 204, // 100
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 198, 254, // 101
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 28, 54, 50, 48, 120, 48, // 102
+ 48, 48, 48, 120, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 118, 204, 204, // 103
+ 204, 204, 204, 124, 12, 204, 120, 0 },
+ { 0, 0, 224, 96, 96, 108, 118, 102, // 104
+ 102, 102, 102, 230, 0, 0, 0, 0 },
+ { 0, 0, 24, 24, 0, 56, 24, 24, // 105
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 6, 6, 0, 14, 6, 6, // 106
+ 6, 6, 6, 6, 102, 102, 60, 0 },
+ { 0, 0, 224, 96, 96, 102, 108, 120, // 107
+ 120, 108, 102, 230, 0, 0, 0, 0 },
+ { 0, 0, 56, 24, 24, 24, 24, 24, // 108
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 236, 254, 214, // 109
+ 214, 214, 214, 198, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 220, 102, 102, // 110
+ 102, 102, 102, 102, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 198, 198, // 111
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 220, 102, 102, // 112
+ 102, 102, 102, 124, 96, 96, 240, 0 },
+ { 0, 0, 0, 0, 0, 118, 204, 204, // 113
+ 204, 204, 204, 124, 12, 12, 30, 0 },
+ { 0, 0, 0, 0, 0, 220, 118, 102, // 114
+ 96, 96, 96, 240, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 198, 96, // 115
+ 56, 12, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 16, 48, 48, 252, 48, 48, // 116
+ 48, 48, 54, 28, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 204, 204, 204, // 117
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 198, 198, 198, // 118
+ 198, 198, 108, 56, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 198, 198, 214, // 119
+ 214, 214, 254, 108, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 198, 108, 56, // 120
+ 56, 56, 108, 198, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 198, 198, 198, // 121
+ 198, 198, 198, 126, 6, 12, 248, 0 },
+ { 0, 0, 0, 0, 0, 254, 204, 24, // 122
+ 48, 96, 198, 254, 0, 0, 0, 0 },
+ { 0, 0, 14, 24, 24, 24, 112, 24, // 123
+ 24, 24, 24, 14, 0, 0, 0, 0 },
+ { 0, 0, 24, 24, 24, 24, 24, 24, // 124
+ 24, 24, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 112, 24, 24, 24, 14, 24, // 125
+ 24, 24, 24, 112, 0, 0, 0, 0 },
+ { 0, 118, 220, 0, 0, 0, 0, 0, // 126
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 16, 56, 108, 198, // 127
+ 198, 198, 254, 0, 0, 0, 0, 0 },
+ { 0, 0, 60, 102, 194, 192, 192, 192, // 128
+ 192, 194, 102, 60, 24, 112, 0, 0 },
+ { 0, 0, 204, 0, 0, 204, 204, 204, // 129
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 12, 24, 48, 0, 124, 198, 254, // 130
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 16, 56, 108, 0, 120, 12, 124, // 131
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 204, 0, 0, 120, 12, 124, // 132
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 96, 48, 24, 0, 120, 12, 124, // 133
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 56, 108, 56, 0, 120, 12, 124, // 134
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 198, 192, // 135
+ 192, 192, 198, 124, 24, 112, 0, 0 },
+ { 0, 16, 56, 108, 0, 124, 198, 254, // 136
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 198, 0, 0, 124, 198, 254, // 137
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 96, 48, 24, 0, 124, 198, 254, // 138
+ 192, 192, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 102, 0, 0, 56, 24, 24, // 139
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 24, 60, 102, 0, 56, 24, 24, // 140
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 96, 48, 24, 0, 56, 24, 24, // 141
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 198, 0, 16, 56, 108, 198, 198, // 142
+ 254, 198, 198, 198, 0, 0, 0, 0 },
+ { 56, 108, 56, 16, 56, 108, 198, 198, // 143
+ 254, 198, 198, 198, 0, 0, 0, 0 },
+ { 12, 24, 0, 254, 102, 98, 104, 120, // 144
+ 104, 98, 102, 254, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 236, 54, 54, // 145
+ 126, 216, 216, 110, 0, 0, 0, 0 },
+ { 0, 0, 62, 108, 204, 204, 254, 204, // 146
+ 204, 204, 204, 206, 0, 0, 0, 0 },
+ { 0, 16, 56, 108, 0, 124, 198, 198, // 147
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 198, 0, 0, 124, 198, 198, // 148
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 96, 48, 24, 0, 124, 198, 198, // 149
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 48, 120, 204, 0, 204, 204, 204, // 150
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 96, 48, 24, 0, 204, 204, 204, // 151
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 198, 0, 0, 198, 198, 198, // 152
+ 198, 198, 198, 126, 6, 12, 120, 0 },
+ { 0, 198, 0, 124, 198, 198, 198, 198, // 153
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 198, 0, 198, 198, 198, 198, 198, // 154
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 124, 206, 222, // 155
+ 246, 230, 198, 124, 0, 0, 0, 0 },
+ { 0, 56, 108, 100, 96, 240, 96, 96, // 156
+ 96, 96, 230, 252, 0, 0, 0, 0 },
+ { 0, 4, 124, 206, 206, 214, 214, 214, // 157
+ 214, 230, 230, 124, 64, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 198, 108, 56, // 158
+ 56, 108, 198, 0, 0, 0, 0, 0 },
+ { 0, 14, 27, 24, 24, 24, 126, 24, // 159
+ 24, 24, 216, 112, 0, 0, 0, 0 },
+ { 0, 24, 48, 96, 0, 120, 12, 124, // 160
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 12, 24, 48, 0, 56, 24, 24, // 161
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 24, 48, 96, 0, 124, 198, 198, // 162
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 24, 48, 96, 0, 204, 204, 204, // 163
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 0, 0, 118, 220, 0, 220, 102, 102, // 164
+ 102, 102, 102, 102, 0, 0, 0, 0 },
+ { 118, 220, 0, 198, 230, 246, 254, 222, // 165
+ 206, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 60, 108, 108, 62, 0, 126, // 166
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 56, 108, 108, 56, 0, 124, // 167
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 48, 48, 0, 48, 48, 96, // 168
+ 192, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 124, 130, 178, 170, 178, 170, // 169
+ 170, 130, 124, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 254, 6, // 170
+ 6, 6, 6, 0, 0, 0, 0, 0 },
+ { 0, 96, 224, 98, 102, 108, 24, 48, // 171
+ 96, 220, 134, 12, 24, 62, 0, 0 },
+ { 0, 96, 224, 98, 102, 108, 24, 48, // 172
+ 102, 206, 154, 63, 6, 6, 0, 0 },
+ { 0, 0, 24, 24, 0, 24, 24, 24, // 173
+ 60, 60, 60, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 54, 108, 216, // 174
+ 108, 54, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 216, 108, 54, // 175
+ 108, 216, 0, 0, 0, 0, 0, 0 },
+ { 17, 68, 17, 68, 17, 68, 17, 68, // 176
+ 17, 68, 17, 68, 17, 68, 17, 68 },
+ { 85, 170, 85, 170, 85, 170, 85, 170, // 177
+ 85, 170, 85, 170, 85, 170, 85, 170 },
+ { 221, 119, 221, 119, 221, 119, 221, 119, // 178
+ 221, 119, 221, 119, 221, 119, 221, 119 },
+ { 24, 24, 24, 24, 24, 24, 24, 24, // 179
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 24, 24, 24, 24, 24, 24, 24, 248, // 180
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 96, 192, 16, 56, 108, 198, 198, 254, // 181
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 124, 198, 16, 56, 108, 198, 198, 254, // 182
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 12, 6, 16, 56, 108, 198, 198, 254, // 183
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 0, 0, 124, 130, 154, 162, 162, 162, // 184
+ 154, 130, 124, 0, 0, 0, 0, 0 },
+ { 54, 54, 54, 54, 54, 246, 6, 246, // 185
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 54, 54, 54, 54, 54, 54, 54, 54, // 186
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 0, 0, 0, 0, 0, 254, 6, 246, // 187
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 54, 54, 54, 54, 54, 246, 6, 254, // 188
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 24, 24, 124, 198, 192, 192, // 189
+ 198, 124, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 102, 102, 60, 24, 126, // 190
+ 24, 126, 24, 24, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 248, // 191
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 24, 24, 24, 24, 24, 24, 24, 31, // 192
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 24, 24, 24, 24, 24, 24, 24, 255, // 193
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 255, // 194
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 24, 24, 24, 24, 24, 24, 24, 31, // 195
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 0, 0, 0, 0, 0, 0, 0, 255, // 196
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 24, 24, 24, 24, 24, 24, 24, 255, // 197
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 0, 0, 118, 220, 0, 120, 12, 124, // 198
+ 204, 204, 204, 118, 0, 0, 0, 0 },
+ { 118, 220, 0, 56, 108, 198, 198, 254, // 199
+ 198, 198, 198, 198, 0, 0, 0, 0 },
+ { 54, 54, 54, 54, 54, 55, 48, 63, // 200
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 63, 48, 55, // 201
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 54, 54, 54, 54, 54, 247, 0, 255, // 202
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 255, 0, 247, // 203
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 54, 54, 54, 54, 54, 55, 48, 55, // 204
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 0, 0, 0, 0, 0, 255, 0, 255, // 205
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 54, 54, 54, 54, 54, 247, 0, 247, // 206
+ 54, 54, 54, 54, 54, 54, 54, 54 },
+ { 0, 0, 0, 0, 198, 124, 198, 198, // 207
+ 198, 198, 124, 198, 0, 0, 0, 0 },
+ { 0, 0, 52, 24, 44, 6, 62, 102, // 208
+ 102, 102, 102, 60, 0, 0, 0, 0 },
+ { 0, 0, 248, 108, 102, 102, 246, 102, // 209
+ 102, 102, 108, 248, 0, 0, 0, 0 },
+ { 56, 108, 0, 254, 102, 98, 104, 120, // 210
+ 104, 98, 102, 254, 0, 0, 0, 0 },
+ { 0, 198, 0, 254, 102, 98, 104, 120, // 211
+ 104, 98, 102, 254, 0, 0, 0, 0 },
+ { 48, 24, 0, 254, 102, 98, 104, 120, // 212
+ 104, 98, 102, 254, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 56, 24, 24, // 213
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 12, 24, 0, 60, 24, 24, 24, 24, // 214
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 60, 102, 0, 60, 24, 24, 24, 24, // 215
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 102, 0, 60, 24, 24, 24, 24, // 216
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 24, 24, 24, 24, 24, 24, 24, 248, // 217
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 31, // 218
+ 24, 24, 24, 24, 24, 24, 24, 24 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, // 219
+ 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 0, 0, 0, 0, 0, 0, 0, 255, // 220
+ 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 0, 24, 24, 24, 24, 24, 0, 0, // 221
+ 24, 24, 24, 24, 24, 0, 0, 0 },
+ { 48, 24, 0, 60, 24, 24, 24, 24, // 222
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 255, 255, 255, 255, 255, 255, 255, 0, // 223
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 24, 48, 0, 124, 198, 198, 198, 198, // 224
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 120, 204, 204, 204, 216, 204, // 225
+ 198, 198, 198, 204, 0, 0, 0, 0 },
+ { 56, 108, 0, 124, 198, 198, 198, 198, // 226
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 48, 24, 0, 124, 198, 198, 198, 198, // 227
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 118, 220, 0, 124, 198, 198, // 228
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 118, 220, 0, 124, 198, 198, 198, 198, // 229
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 102, 102, 102, // 230
+ 102, 102, 102, 124, 96, 96, 192, 0 },
+ { 0, 0, 224, 96, 96, 124, 102, 102, // 231
+ 102, 102, 102, 124, 96, 96, 240, 0 },
+ { 0, 0, 240, 96, 124, 102, 102, 102, // 232
+ 102, 124, 96, 240, 0, 0, 0, 0 },
+ { 24, 48, 0, 198, 198, 198, 198, 198, // 233
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 56, 108, 0, 198, 198, 198, 198, 198, // 234
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 48, 24, 0, 198, 198, 198, 198, 198, // 235
+ 198, 198, 198, 124, 0, 0, 0, 0 },
+ { 0, 12, 24, 48, 0, 198, 198, 198, // 236
+ 198, 198, 198, 126, 6, 12, 248, 0 },
+ { 12, 24, 0, 102, 102, 102, 102, 60, // 237
+ 24, 24, 24, 60, 0, 0, 0, 0 },
+ { 0, 255, 0, 0, 0, 0, 0, 0, // 238
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 12, 24, 48, 0, 0, 0, 0, // 239
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 254, // 240
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 24, 24, 126, 24, // 241
+ 24, 0, 0, 126, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 242
+ 0, 0, 0, 0, 255, 0, 255, 0 },
+ { 0, 224, 48, 98, 54, 236, 24, 48, // 243
+ 102, 206, 154, 63, 6, 6, 0, 0 },
+ { 0, 0, 127, 219, 219, 219, 123, 27, // 244
+ 27, 27, 27, 27, 0, 0, 0, 0 },
+ { 0, 124, 198, 96, 56, 108, 198, 198, // 245
+ 108, 56, 12, 198, 124, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 24, 0, 126, // 246
+ 0, 24, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 247
+ 0, 0, 0, 24, 12, 120, 0, 0 },
+ { 0, 56, 108, 108, 56, 0, 0, 0, // 248
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 198, 0, 0, 0, 0, 0, 0, // 249
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 24, // 250
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 24, 56, 24, 24, 24, 60, 0, // 251
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 124, 6, 60, 6, 6, 124, 0, // 252
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 60, 102, 12, 24, 50, 126, 0, // 253
+ 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 126, 126, 126, 126, // 254
+ 126, 126, 126, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, // 255
+ 0, 0, 0, 0, 0, 0, 0, 0 }};
+
+unsigned char sdl_font8x8[256][8] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 126, 129, 165, 129, 189, 153, 129, 126 }, // 1
+ { 126, 255, 219, 255, 195, 231, 255, 126 }, // 2
+ { 108, 254, 254, 254, 124, 56, 16, 0 }, // 3
+ { 16, 56, 124, 254, 124, 56, 16, 0 }, // 4
+ { 56, 124, 56, 254, 254, 214, 16, 56 }, // 5
+ { 16, 56, 124, 254, 254, 124, 16, 56 }, // 6
+ { 0, 0, 24, 60, 60, 24, 0, 0 }, // 7
+ { 255, 255, 231, 195, 195, 231, 255, 255 }, // 8
+ { 0, 60, 102, 66, 66, 102, 60, 0 }, // 9
+ { 255, 195, 153, 189, 189, 153, 195, 255 }, // 10
+ { 15, 7, 15, 125, 204, 204, 204, 120 }, // 11
+ { 60, 102, 102, 102, 60, 24, 126, 24 }, // 12
+ { 63, 51, 63, 48, 48, 112, 240, 224 }, // 13
+ { 127, 99, 127, 99, 99, 103, 230, 192 }, // 14
+ { 24, 219, 60, 231, 231, 60, 219, 24 }, // 15
+ { 128, 224, 248, 254, 248, 224, 128, 0 }, // 16
+ { 2, 14, 62, 254, 62, 14, 2, 0 }, // 17
+ { 24, 60, 126, 24, 24, 126, 60, 24 }, // 18
+ { 102, 102, 102, 102, 102, 0, 102, 0 }, // 19
+ { 127, 219, 219, 123, 27, 27, 27, 0 }, // 20
+ { 62, 97, 60, 102, 102, 60, 134, 124 }, // 21
+ { 0, 0, 0, 0, 126, 126, 126, 0 }, // 22
+ { 24, 60, 126, 24, 126, 60, 24, 255 }, // 23
+ { 24, 60, 126, 24, 24, 24, 24, 0 }, // 24
+ { 24, 24, 24, 24, 126, 60, 24, 0 }, // 25
+ { 0, 24, 12, 254, 12, 24, 0, 0 }, // 26
+ { 0, 48, 96, 254, 96, 48, 0, 0 }, // 27
+ { 0, 0, 192, 192, 192, 254, 0, 0 }, // 28
+ { 0, 36, 102, 255, 102, 36, 0, 0 }, // 29
+ { 0, 24, 60, 126, 255, 255, 0, 0 }, // 30
+ { 0, 255, 255, 126, 60, 24, 0, 0 }, // 31
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 32
+ { 24, 60, 60, 24, 24, 0, 24, 0 }, // 33
+ { 102, 102, 36, 0, 0, 0, 0, 0 }, // 34
+ { 108, 108, 254, 108, 254, 108, 108, 0 }, // 35
+ { 24, 62, 96, 60, 6, 124, 24, 0 }, // 36
+ { 0, 198, 204, 24, 48, 102, 198, 0 }, // 37
+ { 56, 108, 56, 118, 220, 204, 118, 0 }, // 38
+ { 24, 24, 48, 0, 0, 0, 0, 0 }, // 39
+ { 12, 24, 48, 48, 48, 24, 12, 0 }, // 40
+ { 48, 24, 12, 12, 12, 24, 48, 0 }, // 41
+ { 0, 102, 60, 231, 60, 102, 0, 0 }, // 42
+ { 0, 24, 24, 126, 24, 24, 0, 0 }, // 43
+ { 0, 0, 0, 0, 0, 24, 24, 48 }, // 44
+ { 0, 0, 0, 126, 0, 0, 0, 0 }, // 45
+ { 0, 0, 0, 0, 0, 24, 24, 0 }, // 46
+ { 6, 12, 24, 48, 96, 192, 128, 0 }, // 47
+ { 124, 198, 206, 222, 246, 230, 124, 0 }, // 48
+ { 24, 56, 24, 24, 24, 24, 126, 0 }, // 49
+ { 124, 198, 6, 28, 48, 102, 254, 0 }, // 50
+ { 124, 198, 6, 60, 6, 198, 124, 0 }, // 51
+ { 28, 60, 108, 204, 254, 12, 30, 0 }, // 52
+ { 254, 192, 192, 252, 6, 198, 124, 0 }, // 53
+ { 56, 96, 192, 252, 198, 198, 124, 0 }, // 54
+ { 254, 198, 12, 24, 48, 48, 48, 0 }, // 55
+ { 124, 198, 198, 124, 198, 198, 124, 0 }, // 56
+ { 124, 198, 198, 126, 6, 12, 120, 0 }, // 57
+ { 0, 24, 24, 0, 0, 24, 24, 0 }, // 58
+ { 0, 24, 24, 0, 0, 24, 24, 48 }, // 59
+ { 6, 12, 24, 48, 24, 12, 6, 0 }, // 60
+ { 0, 0, 126, 0, 0, 126, 0, 0 }, // 61
+ { 96, 48, 24, 12, 24, 48, 96, 0 }, // 62
+ { 124, 198, 12, 24, 24, 0, 24, 0 }, // 63
+ { 124, 198, 222, 222, 222, 192, 120, 0 }, // 64
+ { 56, 108, 198, 254, 198, 198, 198, 0 }, // 65
+ { 252, 102, 102, 124, 102, 102, 252, 0 }, // 66
+ { 60, 102, 192, 192, 192, 102, 60, 0 }, // 67
+ { 248, 108, 102, 102, 102, 108, 248, 0 }, // 68
+ { 254, 98, 104, 120, 104, 98, 254, 0 }, // 69
+ { 254, 98, 104, 120, 104, 96, 240, 0 }, // 70
+ { 60, 102, 192, 192, 206, 102, 58, 0 }, // 71
+ { 198, 198, 198, 254, 198, 198, 198, 0 }, // 72
+ { 60, 24, 24, 24, 24, 24, 60, 0 }, // 73
+ { 30, 12, 12, 12, 204, 204, 120, 0 }, // 74
+ { 230, 102, 108, 120, 108, 102, 230, 0 }, // 75
+ { 240, 96, 96, 96, 98, 102, 254, 0 }, // 76
+ { 198, 238, 254, 254, 214, 198, 198, 0 }, // 77
+ { 198, 230, 246, 222, 206, 198, 198, 0 }, // 78
+ { 124, 198, 198, 198, 198, 198, 124, 0 }, // 79
+ { 252, 102, 102, 124, 96, 96, 240, 0 }, // 80
+ { 124, 198, 198, 198, 198, 206, 124, 14 }, // 81
+ { 252, 102, 102, 124, 108, 102, 230, 0 }, // 82
+ { 60, 102, 48, 24, 12, 102, 60, 0 }, // 83
+ { 126, 126, 90, 24, 24, 24, 60, 0 }, // 84
+ { 198, 198, 198, 198, 198, 198, 124, 0 }, // 85
+ { 198, 198, 198, 198, 198, 108, 56, 0 }, // 86
+ { 198, 198, 198, 214, 214, 254, 108, 0 }, // 87
+ { 198, 198, 108, 56, 108, 198, 198, 0 }, // 88
+ { 102, 102, 102, 60, 24, 24, 60, 0 }, // 89
+ { 254, 198, 140, 24, 50, 102, 254, 0 }, // 90
+ { 60, 48, 48, 48, 48, 48, 60, 0 }, // 91
+ { 192, 96, 48, 24, 12, 6, 2, 0 }, // 92
+ { 60, 12, 12, 12, 12, 12, 60, 0 }, // 93
+ { 16, 56, 108, 198, 0, 0, 0, 0 }, // 94
+ { 0, 0, 0, 0, 0, 0, 0, 255 }, // 95
+ { 48, 24, 12, 0, 0, 0, 0, 0 }, // 96
+ { 0, 0, 120, 12, 124, 204, 118, 0 }, // 97
+ { 224, 96, 124, 102, 102, 102, 220, 0 }, // 98
+ { 0, 0, 124, 198, 192, 198, 124, 0 }, // 99
+ { 28, 12, 124, 204, 204, 204, 118, 0 }, // 100
+ { 0, 0, 124, 198, 254, 192, 124, 0 }, // 101
+ { 60, 102, 96, 248, 96, 96, 240, 0 }, // 102
+ { 0, 0, 118, 204, 204, 124, 12, 248 }, // 103
+ { 224, 96, 108, 118, 102, 102, 230, 0 }, // 104
+ { 24, 0, 56, 24, 24, 24, 60, 0 }, // 105
+ { 6, 0, 6, 6, 6, 102, 102, 60 }, // 106
+ { 224, 96, 102, 108, 120, 108, 230, 0 }, // 107
+ { 56, 24, 24, 24, 24, 24, 60, 0 }, // 108
+ { 0, 0, 236, 254, 214, 214, 214, 0 }, // 109
+ { 0, 0, 220, 102, 102, 102, 102, 0 }, // 110
+ { 0, 0, 124, 198, 198, 198, 124, 0 }, // 111
+ { 0, 0, 220, 102, 102, 124, 96, 240 }, // 112
+ { 0, 0, 118, 204, 204, 124, 12, 30 }, // 113
+ { 0, 0, 220, 118, 96, 96, 240, 0 }, // 114
+ { 0, 0, 126, 192, 124, 6, 252, 0 }, // 115
+ { 48, 48, 252, 48, 48, 54, 28, 0 }, // 116
+ { 0, 0, 204, 204, 204, 204, 118, 0 }, // 117
+ { 0, 0, 198, 198, 198, 108, 56, 0 }, // 118
+ { 0, 0, 198, 214, 214, 254, 108, 0 }, // 119
+ { 0, 0, 198, 108, 56, 108, 198, 0 }, // 120
+ { 0, 0, 198, 198, 198, 126, 6, 252 }, // 121
+ { 0, 0, 126, 76, 24, 50, 126, 0 }, // 122
+ { 14, 24, 24, 112, 24, 24, 14, 0 }, // 123
+ { 24, 24, 24, 24, 24, 24, 24, 0 }, // 124
+ { 112, 24, 24, 14, 24, 24, 112, 0 }, // 125
+ { 118, 220, 0, 0, 0, 0, 0, 0 }, // 126
+ { 0, 16, 56, 108, 198, 198, 254, 0 }, // 127
+ { 124, 198, 192, 192, 198, 124, 12, 120 }, // 128
+ { 204, 0, 204, 204, 204, 204, 118, 0 }, // 129
+ { 12, 24, 124, 198, 254, 192, 124, 0 }, // 130
+ { 124, 130, 120, 12, 124, 204, 118, 0 }, // 131
+ { 198, 0, 120, 12, 124, 204, 118, 0 }, // 132
+ { 48, 24, 120, 12, 124, 204, 118, 0 }, // 133
+ { 48, 48, 120, 12, 124, 204, 118, 0 }, // 134
+ { 0, 0, 126, 192, 192, 126, 12, 56 }, // 135
+ { 124, 130, 124, 198, 254, 192, 124, 0 }, // 136
+ { 198, 0, 124, 198, 254, 192, 124, 0 }, // 137
+ { 48, 24, 124, 198, 254, 192, 124, 0 }, // 138
+ { 102, 0, 56, 24, 24, 24, 60, 0 }, // 139
+ { 124, 130, 56, 24, 24, 24, 60, 0 }, // 140
+ { 48, 24, 0, 56, 24, 24, 60, 0 }, // 141
+ { 198, 56, 108, 198, 254, 198, 198, 0 }, // 142
+ { 56, 108, 124, 198, 254, 198, 198, 0 }, // 143
+ { 24, 48, 254, 192, 248, 192, 254, 0 }, // 144
+ { 0, 0, 126, 18, 254, 144, 254, 0 }, // 145
+ { 62, 108, 204, 254, 204, 204, 206, 0 }, // 146
+ { 124, 130, 124, 198, 198, 198, 124, 0 }, // 147
+ { 198, 0, 124, 198, 198, 198, 124, 0 }, // 148
+ { 48, 24, 124, 198, 198, 198, 124, 0 }, // 149
+ { 120, 132, 0, 204, 204, 204, 118, 0 }, // 150
+ { 96, 48, 204, 204, 204, 204, 118, 0 }, // 151
+ { 198, 0, 198, 198, 198, 126, 6, 252 }, // 152
+ { 198, 56, 108, 198, 198, 108, 56, 0 }, // 153
+ { 198, 0, 198, 198, 198, 198, 124, 0 }, // 154
+ { 0, 2, 124, 206, 214, 230, 124, 128 }, // 155
+ { 56, 108, 100, 240, 96, 102, 252, 0 }, // 156
+ { 58, 108, 206, 214, 230, 108, 184, 0 }, // 157
+ { 0, 198, 108, 56, 108, 198, 0, 0 }, // 158
+ { 14, 27, 24, 60, 24, 216, 112, 0 }, // 159
+ { 24, 48, 120, 12, 124, 204, 118, 0 }, // 160
+ { 12, 24, 0, 56, 24, 24, 60, 0 }, // 161
+ { 12, 24, 124, 198, 198, 198, 124, 0 }, // 162
+ { 24, 48, 204, 204, 204, 204, 118, 0 }, // 163
+ { 118, 220, 0, 220, 102, 102, 102, 0 }, // 164
+ { 118, 220, 0, 230, 246, 222, 206, 0 }, // 165
+ { 60, 108, 108, 62, 0, 126, 0, 0 }, // 166
+ { 56, 108, 108, 56, 0, 124, 0, 0 }, // 167
+ { 24, 0, 24, 24, 48, 99, 62, 0 }, // 168
+ { 126, 129, 185, 165, 185, 165, 129, 126 }, // 169
+ { 0, 0, 0, 254, 6, 6, 0, 0 }, // 170
+ { 99, 230, 108, 126, 51, 102, 204, 15 }, // 171
+ { 99, 230, 108, 122, 54, 106, 223, 6 }, // 172
+ { 24, 0, 24, 24, 60, 60, 24, 0 }, // 173
+ { 0, 51, 102, 204, 102, 51, 0, 0 }, // 174
+ { 0, 204, 102, 51, 102, 204, 0, 0 }, // 175
+ { 34, 136, 34, 136, 34, 136, 34, 136 }, // 176
+ { 85, 170, 85, 170, 85, 170, 85, 170 }, // 177
+ { 119, 221, 119, 221, 119, 221, 119, 221 }, // 178
+ { 24, 24, 24, 24, 24, 24, 24, 24 }, // 179
+ { 24, 24, 56, 248, 56, 24, 24, 24 }, // 180
+ { 48, 96, 56, 108, 198, 254, 198, 0 }, // 181
+ { 124, 130, 56, 108, 198, 254, 198, 0 }, // 182
+ { 24, 12, 56, 108, 198, 254, 198, 0 }, // 183
+ { 126, 129, 157, 161, 161, 157, 129, 126 }, // 184
+ { 54, 54, 246, 6, 246, 54, 54, 54 }, // 185
+ { 54, 54, 54, 54, 54, 54, 54, 54 }, // 186
+ { 0, 0, 254, 6, 246, 54, 54, 54 }, // 187
+ { 54, 54, 246, 6, 254, 0, 0, 0 }, // 188
+ { 24, 24, 126, 192, 192, 126, 24, 24 }, // 189
+ { 102, 102, 60, 126, 24, 126, 24, 24 }, // 190
+ { 0, 0, 0, 240, 56, 24, 24, 24 }, // 191
+ { 24, 24, 28, 15, 0, 0, 0, 0 }, // 192
+ { 24, 24, 60, 255, 0, 0, 0, 0 }, // 193
+ { 0, 0, 0, 255, 60, 24, 24, 24 }, // 194
+ { 48, 48, 56, 63, 56, 48, 48, 48 }, // 195
+ { 0, 0, 0, 255, 0, 0, 0, 0 }, // 196
+ { 24, 24, 24, 60, 231, 60, 24, 24 }, // 197
+ { 240, 120, 120, 120, 60, 60, 60, 28 }, // 198
+ { 30, 60, 60, 60, 120, 120, 120, 112 }, // 199
+ { 15, 63, 63, 120, 120, 0, 1, 3 }, // 200
+ { 192, 224, 240, 240, 240, 240, 240, 224 }, // 201
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 202
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 203
+ { 30, 30, 14, 15, 15, 7, 7, 0 }, // 204
+ { 240, 240, 224, 224, 192, 192, 192, 0 }, // 205
+ { 6, 13, 27, 55, 47, 127, 126, 30 }, // 206
+ { 0, 252, 255, 255, 143, 119, 243, 3 }, // 207
+ { 0, 1, 7, 143, 143, 207, 207, 199 }, // 208
+ { 0, 248, 254, 254, 31, 15, 192, 248 }, // 209
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 210
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 211
+ { 30, 30, 30, 31, 15, 7, 7, 1 }, // 212
+ { 3, 3, 3, 7, 143, 255, 254, 252 }, // 213
+ { 195, 192, 192, 207, 143, 7, 7, 1 }, // 214
+ { 254, 255, 31, 15, 143, 254, 254, 248 }, // 215
+ { 102, 0, 60, 24, 24, 24, 60, 0 }, // 216
+ { 24, 24, 56, 240, 0, 0, 0, 0 }, // 217
+ { 0, 0, 0, 15, 28, 24, 24, 24 }, // 218
+ { 255, 255, 255, 255, 255, 255, 255, 255 }, // 219
+ { 0, 0, 0, 0, 255, 255, 255, 255 }, // 220
+ { 24, 24, 24, 0, 0, 24, 24, 24 }, // 221
+ { 48, 24, 60, 24, 24, 24, 60, 0 }, // 222
+ { 255, 255, 255, 255, 0, 0, 0, 0 }, // 223
+ { 0, 0, 0, 0, 0, 0, 0, 255 }, // 224
+ { 0, 0, 0, 0, 0, 255, 0, 255 }, // 225
+ { 0, 0, 0, 255, 0, 255, 0, 255 }, // 226
+ { 0, 255, 0, 255, 0, 255, 0, 255 }, // 227
+ { 0, 255, 0, 255, 0, 255, 0, 0 }, // 228
+ { 0, 255, 0, 255, 0, 0, 0, 0 }, // 229
+ { 0, 255, 0, 0, 0, 0, 0, 0 }, // 230
+ { 224, 128, 0, 0, 0, 0, 128, 224 }, // 231
+ { 248, 254, 255, 255, 255, 255, 254, 248 }, // 232
+ { 24, 48, 198, 198, 198, 198, 124, 0 }, // 233
+ { 124, 130, 0, 198, 198, 198, 124, 0 }, // 234
+ { 96, 48, 198, 198, 198, 198, 124, 0 }, // 235
+ { 24, 48, 198, 198, 198, 126, 6, 252 }, // 236
+ { 12, 24, 102, 102, 60, 24, 60, 0 }, // 237
+ { 255, 0, 0, 0, 0, 0, 0, 0 }, // 238
+ { 12, 24, 48, 0, 0, 0, 0, 0 }, // 239
+ { 0, 0, 0, 126, 0, 0, 0, 0 }, // 240
+ { 24, 24, 126, 24, 24, 0, 126, 0 }, // 241
+ { 0, 0, 0, 0, 0, 255, 0, 255 }, // 242
+ { 225, 50, 228, 58, 246, 42, 95, 134 }, // 243
+ { 127, 219, 219, 123, 27, 27, 27, 0 }, // 244
+ { 62, 97, 60, 102, 102, 60, 134, 124 }, // 245
+ { 0, 24, 0, 126, 0, 24, 0, 0 }, // 246
+ { 0, 0, 0, 0, 0, 24, 12, 56 }, // 247
+ { 56, 108, 108, 56, 0, 0, 0, 0 }, // 248
+ { 0, 198, 0, 0, 0, 0, 0, 0 }, // 249
+ { 0, 0, 0, 24, 0, 0, 0, 0 }, // 250
+ { 24, 56, 24, 24, 60, 0, 0, 0 }, // 251
+ { 120, 12, 56, 12, 120, 0, 0, 0 }, // 252
+ { 120, 12, 24, 48, 124, 0, 0, 0 }, // 253
+ { 0, 0, 60, 60, 60, 60, 0, 0 }, // 254
+ { 0, 0, 0, 0, 0, 0, 0, 0 }}; // 255
+
+/*
+unsigned char sdl_palette[256][3] = {
+ { 0, 0, 0 }, // 0
+ { 0, 0, 168 }, // 1
+ { 0, 168, 0 }, // 2
+ { 0, 168, 168 }, // 3
+ { 168, 0, 0 }, // 4
+ { 168, 0, 168 }, // 5
+ { 168, 84, 0 }, // 6
+ { 168, 168, 168 }, // 7
+ { 84, 84, 84 }, // 8
+ { 84, 84, 252 }, // 9
+ { 84, 252, 84 }, // 10
+ { 84, 252, 252 }, // 11
+ { 252, 84, 84 }, // 12
+ { 252, 84, 252 }, // 13
+ { 252, 252, 84 }, // 14
+ { 252, 252, 252 }, // 15
+ { 0, 0, 0 }, // 16
+ { 20, 20, 20 }, // 17
+ { 32, 32, 32 }, // 18
+ { 44, 44, 44 }, // 19
+ { 56, 56, 56 }, // 20
+ { 68, 68, 68 }, // 21
+ { 80, 80, 80 }, // 22
+ { 96, 96, 96 }, // 23
+ { 112, 112, 112 }, // 24
+ { 128, 128, 128 }, // 25
+ { 144, 144, 144 }, // 26
+ { 160, 160, 160 }, // 27
+ { 180, 180, 180 }, // 28
+ { 200, 200, 200 }, // 29
+ { 224, 224, 224 }, // 30
+ { 252, 252, 252 }, // 31
+ { 0, 0, 252 }, // 32
+ { 64, 0, 252 }, // 33
+ { 124, 0, 252 }, // 34
+ { 188, 0, 252 }, // 35
+ { 252, 0, 252 }, // 36
+ { 252, 0, 188 }, // 37
+ { 252, 0, 124 }, // 38
+ { 252, 0, 64 }, // 39
+ { 252, 0, 0 }, // 40
+ { 252, 64, 0 }, // 41
+ { 252, 124, 0 }, // 42
+ { 252, 188, 0 }, // 43
+ { 252, 252, 0 }, // 44
+ { 188, 252, 0 }, // 45
+ { 124, 252, 0 }, // 46
+ { 64, 252, 0 }, // 47
+ { 0, 252, 0 }, // 48
+ { 0, 252, 64 }, // 49
+ { 0, 252, 124 }, // 50
+ { 0, 252, 188 }, // 51
+ { 0, 252, 252 }, // 52
+ { 0, 188, 252 }, // 53
+ { 0, 124, 252 }, // 54
+ { 0, 64, 252 }, // 55
+ { 124, 124, 252 }, // 56
+ { 156, 124, 252 }, // 57
+ { 188, 124, 252 }, // 58
+ { 220, 124, 252 }, // 59
+ { 252, 124, 252 }, // 60
+ { 252, 124, 220 }, // 61
+ { 252, 124, 188 }, // 62
+ { 252, 124, 156 }, // 63
+ { 252, 124, 124 }, // 64
+ { 252, 156, 124 }, // 65
+ { 252, 188, 124 }, // 66
+ { 252, 220, 124 }, // 67
+ { 252, 252, 124 }, // 68
+ { 220, 252, 124 }, // 69
+ { 188, 252, 124 }, // 70
+ { 156, 252, 124 }, // 71
+ { 124, 252, 124 }, // 72
+ { 124, 252, 156 }, // 73
+ { 124, 252, 188 }, // 74
+ { 124, 252, 220 }, // 75
+ { 124, 252, 252 }, // 76
+ { 124, 220, 252 }, // 77
+ { 124, 188, 252 }, // 78
+ { 124, 156, 252 }, // 79
+ { 180, 180, 252 }, // 80
+ { 196, 180, 252 }, // 81
+ { 216, 180, 252 }, // 82
+ { 232, 180, 252 }, // 83
+ { 252, 180, 252 }, // 84
+ { 252, 180, 232 }, // 85
+ { 252, 180, 216 }, // 86
+ { 252, 180, 196 }, // 87
+ { 252, 180, 180 }, // 88
+ { 252, 196, 180 }, // 89
+ { 252, 216, 180 }, // 90
+ { 252, 232, 180 }, // 91
+ { 252, 252, 180 }, // 92
+ { 232, 252, 180 }, // 93
+ { 216, 252, 180 }, // 94
+ { 196, 252, 180 }, // 95
+ { 180, 252, 180 }, // 96
+ { 180, 252, 196 }, // 97
+ { 180, 252, 216 }, // 98
+ { 180, 252, 232 }, // 99
+ { 180, 252, 252 }, // 100
+ { 180, 232, 252 }, // 101
+ { 180, 216, 252 }, // 102
+ { 180, 196, 252 }, // 103
+ { 0, 0, 112 }, // 104
+ { 28, 0, 112 }, // 105
+ { 56, 0, 112 }, // 106
+ { 84, 0, 112 }, // 107
+ { 112, 0, 112 }, // 108
+ { 112, 0, 84 }, // 109
+ { 112, 0, 56 }, // 110
+ { 112, 0, 28 }, // 111
+ { 112, 0, 0 }, // 112
+ { 112, 28, 0 }, // 113
+ { 112, 56, 0 }, // 114
+ { 112, 84, 0 }, // 115
+ { 112, 112, 0 }, // 116
+ { 84, 112, 0 }, // 117
+ { 56, 112, 0 }, // 118
+ { 28, 112, 0 }, // 119
+ { 0, 112, 0 }, // 120
+ { 0, 112, 28 }, // 121
+ { 0, 112, 56 }, // 122
+ { 0, 112, 84 }, // 123
+ { 0, 112, 112 }, // 124
+ { 0, 84, 112 }, // 125
+ { 0, 56, 112 }, // 126
+ { 0, 28, 112 }, // 127
+ { 56, 56, 112 }, // 128
+ { 68, 56, 112 }, // 129
+ { 84, 56, 112 }, // 130
+ { 96, 56, 112 }, // 131
+ { 112, 56, 112 }, // 132
+ { 112, 56, 96 }, // 133
+ { 112, 56, 84 }, // 134
+ { 112, 56, 68 }, // 135
+ { 112, 56, 56 }, // 136
+ { 112, 68, 56 }, // 137
+ { 112, 84, 56 }, // 138
+ { 112, 96, 56 }, // 139
+ { 112, 112, 56 }, // 140
+ { 96, 112, 56 }, // 141
+ { 84, 112, 56 }, // 142
+ { 68, 112, 56 }, // 143
+ { 56, 112, 56 }, // 144
+ { 56, 112, 68 }, // 145
+ { 56, 112, 84 }, // 146
+ { 56, 112, 96 }, // 147
+ { 56, 112, 112 }, // 148
+ { 56, 96, 112 }, // 149
+ { 56, 84, 112 }, // 150
+ { 56, 68, 112 }, // 151
+ { 80, 80, 112 }, // 152
+ { 88, 80, 112 }, // 153
+ { 96, 80, 112 }, // 154
+ { 104, 80, 112 }, // 155
+ { 112, 80, 112 }, // 156
+ { 112, 80, 104 }, // 157
+ { 112, 80, 96 }, // 158
+ { 112, 80, 88 }, // 159
+ { 112, 80, 80 }, // 160
+ { 112, 88, 80 }, // 161
+ { 112, 96, 80 }, // 162
+ { 112, 104, 80 }, // 163
+ { 112, 112, 80 }, // 164
+ { 104, 112, 80 }, // 165
+ { 96, 112, 80 }, // 166
+ { 88, 112, 80 }, // 167
+ { 80, 112, 80 }, // 168
+ { 80, 112, 88 }, // 169
+ { 80, 112, 96 }, // 170
+ { 80, 112, 104 }, // 171
+ { 80, 112, 112 }, // 172
+ { 80, 104, 112 }, // 173
+ { 80, 96, 112 }, // 174
+ { 80, 88, 112 }, // 175
+ { 0, 0, 64 }, // 176
+ { 16, 0, 64 }, // 177
+ { 32, 0, 64 }, // 178
+ { 48, 0, 64 }, // 179
+ { 64, 0, 64 }, // 180
+ { 64, 0, 48 }, // 181
+ { 64, 0, 32 }, // 182
+ { 64, 0, 16 }, // 183
+ { 64, 0, 0 }, // 184
+ { 64, 16, 0 }, // 185
+ { 64, 32, 0 }, // 186
+ { 64, 48, 0 }, // 187
+ { 64, 64, 0 }, // 188
+ { 48, 64, 0 }, // 189
+ { 32, 64, 0 }, // 190
+ { 16, 64, 0 }, // 191
+ { 0, 64, 0 }, // 192
+ { 0, 64, 16 }, // 193
+ { 0, 64, 32 }, // 194
+ { 0, 64, 48 }, // 195
+ { 0, 64, 64 }, // 196
+ { 0, 48, 64 }, // 197
+ { 0, 32, 64 }, // 198
+ { 0, 16, 64 }, // 199
+ { 32, 32, 64 }, // 200
+ { 40, 32, 64 }, // 201
+ { 48, 32, 64 }, // 202
+ { 56, 32, 64 }, // 203
+ { 64, 32, 64 }, // 204
+ { 64, 32, 56 }, // 205
+ { 64, 32, 48 }, // 206
+ { 64, 32, 40 }, // 207
+ { 64, 32, 32 }, // 208
+ { 64, 40, 32 }, // 209
+ { 64, 48, 32 }, // 210
+ { 64, 56, 32 }, // 211
+ { 64, 64, 32 }, // 212
+ { 56, 64, 32 }, // 213
+ { 48, 64, 32 }, // 214
+ { 40, 64, 32 }, // 215
+ { 32, 64, 32 }, // 216
+ { 32, 64, 40 }, // 217
+ { 32, 64, 48 }, // 218
+ { 32, 64, 56 }, // 219
+ { 32, 64, 64 }, // 220
+ { 32, 56, 64 }, // 221
+ { 32, 48, 64 }, // 222
+ { 32, 40, 64 }, // 223
+ { 44, 44, 64 }, // 224
+ { 48, 44, 64 }, // 225
+ { 52, 44, 64 }, // 226
+ { 60, 44, 64 }, // 227
+ { 64, 44, 64 }, // 228
+ { 64, 44, 60 }, // 229
+ { 64, 44, 52 }, // 230
+ { 64, 44, 48 }, // 231
+ { 64, 44, 44 }, // 232
+ { 64, 48, 44 }, // 233
+ { 64, 52, 44 }, // 234
+ { 64, 60, 44 }, // 235
+ { 64, 64, 44 }, // 236
+ { 60, 64, 44 }, // 237
+ { 52, 64, 44 }, // 238
+ { 48, 64, 44 }, // 239
+ { 44, 64, 44 }, // 240
+ { 44, 64, 48 }, // 241
+ { 44, 64, 52 }, // 242
+ { 44, 64, 60 }, // 243
+ { 44, 64, 64 }, // 244
+ { 44, 60, 64 }, // 245
+ { 44, 52, 64 }, // 246
+ { 44, 48, 64 }, // 247
+ { 0, 0, 0 }, // 248
+ { 0, 0, 0 }, // 249
+ { 0, 0, 0 }, // 250
+ { 0, 0, 0 }, // 251
+ { 0, 0, 0 }, // 252
+ { 0, 0, 0 }, // 253
+ { 0, 0, 0 }, // 254
+ { 112, 97, 108 }}; // 255
+*/
diff --git a/tools/ioemu/gui/sdlkeys.h b/tools/ioemu/gui/sdlkeys.h
new file mode 100644
index 0000000000..fd1197a5f1
--- /dev/null
+++ b/tools/ioemu/gui/sdlkeys.h
@@ -0,0 +1,257 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: sdlkeys.h,v 1.2 2002/10/24 21:06:32 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file is simply a list of SDL key symbols taken from <SDL/SDL_keysym.h>.
+// The order in this file is not important. In sdl.cc, DEF_SDL_KEY() is
+// defined as a macro and then it includes this file to fill in all the data in
+// its key mapping table.
+//
+// The symbols, such as SDLK_RETURN, are used for two purposes. They
+// are converted into a string (by the # operator in processor), which is
+// compared to the host key name in the keymap file. Also, the value of
+// the symbol is inserted into the key mapping table. Then the value is
+// compared with the keysym field of each key up/down event as it arrives.
+//
+// If you get undefined symbol errors in this file, it must mean that
+// your SDL library version doesn't define those same SDLK_* symbols in
+// <SDL/SDL_keysym.h>. You can't fix it with #ifdef SDLK_SYM because
+// they are enums, so you'll just have to comment out the offending line.
+// The list was generated using symbols from SDL 1.2.3.
+
+DEF_SDL_KEY( SDLK_UNKNOWN )
+DEF_SDL_KEY( SDLK_FIRST )
+DEF_SDL_KEY( SDLK_BACKSPACE )
+DEF_SDL_KEY( SDLK_TAB )
+DEF_SDL_KEY( SDLK_CLEAR )
+DEF_SDL_KEY( SDLK_RETURN )
+DEF_SDL_KEY( SDLK_PAUSE )
+DEF_SDL_KEY( SDLK_ESCAPE )
+DEF_SDL_KEY( SDLK_SPACE )
+DEF_SDL_KEY( SDLK_EXCLAIM )
+DEF_SDL_KEY( SDLK_QUOTEDBL )
+DEF_SDL_KEY( SDLK_HASH )
+DEF_SDL_KEY( SDLK_DOLLAR )
+DEF_SDL_KEY( SDLK_AMPERSAND )
+DEF_SDL_KEY( SDLK_QUOTE )
+DEF_SDL_KEY( SDLK_LEFTPAREN )
+DEF_SDL_KEY( SDLK_RIGHTPAREN )
+DEF_SDL_KEY( SDLK_ASTERISK )
+DEF_SDL_KEY( SDLK_PLUS )
+DEF_SDL_KEY( SDLK_COMMA )
+DEF_SDL_KEY( SDLK_MINUS )
+DEF_SDL_KEY( SDLK_PERIOD )
+DEF_SDL_KEY( SDLK_SLASH )
+DEF_SDL_KEY( SDLK_0 )
+DEF_SDL_KEY( SDLK_1 )
+DEF_SDL_KEY( SDLK_2 )
+DEF_SDL_KEY( SDLK_3 )
+DEF_SDL_KEY( SDLK_4 )
+DEF_SDL_KEY( SDLK_5 )
+DEF_SDL_KEY( SDLK_6 )
+DEF_SDL_KEY( SDLK_7 )
+DEF_SDL_KEY( SDLK_8 )
+DEF_SDL_KEY( SDLK_9 )
+DEF_SDL_KEY( SDLK_COLON )
+DEF_SDL_KEY( SDLK_SEMICOLON )
+DEF_SDL_KEY( SDLK_LESS )
+DEF_SDL_KEY( SDLK_EQUALS )
+DEF_SDL_KEY( SDLK_GREATER )
+DEF_SDL_KEY( SDLK_QUESTION )
+DEF_SDL_KEY( SDLK_AT )
+DEF_SDL_KEY( /* )
+DEF_SDL_KEY( Skip uppercase letters )
+DEF_SDL_KEY( */ )
+DEF_SDL_KEY( SDLK_LEFTBRACKET )
+DEF_SDL_KEY( SDLK_BACKSLASH )
+DEF_SDL_KEY( SDLK_RIGHTBRACKET )
+DEF_SDL_KEY( SDLK_CARET )
+DEF_SDL_KEY( SDLK_UNDERSCORE )
+DEF_SDL_KEY( SDLK_BACKQUOTE )
+DEF_SDL_KEY( SDLK_a )
+DEF_SDL_KEY( SDLK_b )
+DEF_SDL_KEY( SDLK_c )
+DEF_SDL_KEY( SDLK_d )
+DEF_SDL_KEY( SDLK_e )
+DEF_SDL_KEY( SDLK_f )
+DEF_SDL_KEY( SDLK_g )
+DEF_SDL_KEY( SDLK_h )
+DEF_SDL_KEY( SDLK_i )
+DEF_SDL_KEY( SDLK_j )
+DEF_SDL_KEY( SDLK_k )
+DEF_SDL_KEY( SDLK_l )
+DEF_SDL_KEY( SDLK_m )
+DEF_SDL_KEY( SDLK_n )
+DEF_SDL_KEY( SDLK_o )
+DEF_SDL_KEY( SDLK_p )
+DEF_SDL_KEY( SDLK_q )
+DEF_SDL_KEY( SDLK_r )
+DEF_SDL_KEY( SDLK_s )
+DEF_SDL_KEY( SDLK_t )
+DEF_SDL_KEY( SDLK_u )
+DEF_SDL_KEY( SDLK_v )
+DEF_SDL_KEY( SDLK_w )
+DEF_SDL_KEY( SDLK_x )
+DEF_SDL_KEY( SDLK_y )
+DEF_SDL_KEY( SDLK_z )
+DEF_SDL_KEY( SDLK_DELETE )
+DEF_SDL_KEY( SDLK_WORLD_0 )
+DEF_SDL_KEY( SDLK_WORLD_1 )
+DEF_SDL_KEY( SDLK_WORLD_2 )
+DEF_SDL_KEY( SDLK_WORLD_3 )
+DEF_SDL_KEY( SDLK_WORLD_4 )
+DEF_SDL_KEY( SDLK_WORLD_5 )
+DEF_SDL_KEY( SDLK_WORLD_6 )
+DEF_SDL_KEY( SDLK_WORLD_7 )
+DEF_SDL_KEY( SDLK_WORLD_8 )
+DEF_SDL_KEY( SDLK_WORLD_9 )
+DEF_SDL_KEY( SDLK_WORLD_10 )
+DEF_SDL_KEY( SDLK_WORLD_11 )
+DEF_SDL_KEY( SDLK_WORLD_12 )
+DEF_SDL_KEY( SDLK_WORLD_13 )
+DEF_SDL_KEY( SDLK_WORLD_14 )
+DEF_SDL_KEY( SDLK_WORLD_15 )
+DEF_SDL_KEY( SDLK_WORLD_16 )
+DEF_SDL_KEY( SDLK_WORLD_17 )
+DEF_SDL_KEY( SDLK_WORLD_18 )
+DEF_SDL_KEY( SDLK_WORLD_19 )
+DEF_SDL_KEY( SDLK_WORLD_20 )
+DEF_SDL_KEY( SDLK_WORLD_21 )
+DEF_SDL_KEY( SDLK_WORLD_22 )
+DEF_SDL_KEY( SDLK_WORLD_23 )
+DEF_SDL_KEY( SDLK_WORLD_24 )
+DEF_SDL_KEY( SDLK_WORLD_25 )
+DEF_SDL_KEY( SDLK_WORLD_26 )
+DEF_SDL_KEY( SDLK_WORLD_27 )
+DEF_SDL_KEY( SDLK_WORLD_28 )
+DEF_SDL_KEY( SDLK_WORLD_29 )
+DEF_SDL_KEY( SDLK_WORLD_30 )
+DEF_SDL_KEY( SDLK_WORLD_31 )
+DEF_SDL_KEY( SDLK_WORLD_32 )
+DEF_SDL_KEY( SDLK_WORLD_33 )
+DEF_SDL_KEY( SDLK_WORLD_34 )
+DEF_SDL_KEY( SDLK_WORLD_35 )
+DEF_SDL_KEY( SDLK_WORLD_36 )
+DEF_SDL_KEY( SDLK_WORLD_37 )
+DEF_SDL_KEY( SDLK_WORLD_38 )
+DEF_SDL_KEY( SDLK_WORLD_39 )
+DEF_SDL_KEY( SDLK_WORLD_40 )
+DEF_SDL_KEY( SDLK_WORLD_41 )
+DEF_SDL_KEY( SDLK_WORLD_42 )
+DEF_SDL_KEY( SDLK_WORLD_43 )
+DEF_SDL_KEY( SDLK_WORLD_44 )
+DEF_SDL_KEY( SDLK_WORLD_45 )
+DEF_SDL_KEY( SDLK_WORLD_46 )
+DEF_SDL_KEY( SDLK_WORLD_47 )
+DEF_SDL_KEY( SDLK_WORLD_48 )
+DEF_SDL_KEY( SDLK_WORLD_49 )
+DEF_SDL_KEY( SDLK_WORLD_50 )
+DEF_SDL_KEY( SDLK_WORLD_51 )
+DEF_SDL_KEY( SDLK_WORLD_52 )
+DEF_SDL_KEY( SDLK_WORLD_53 )
+DEF_SDL_KEY( SDLK_WORLD_54 )
+DEF_SDL_KEY( SDLK_WORLD_55 )
+DEF_SDL_KEY( SDLK_WORLD_56 )
+DEF_SDL_KEY( SDLK_WORLD_57 )
+DEF_SDL_KEY( SDLK_WORLD_58 )
+DEF_SDL_KEY( SDLK_WORLD_59 )
+DEF_SDL_KEY( SDLK_WORLD_60 )
+DEF_SDL_KEY( SDLK_WORLD_61 )
+DEF_SDL_KEY( SDLK_WORLD_62 )
+DEF_SDL_KEY( SDLK_WORLD_63 )
+DEF_SDL_KEY( SDLK_WORLD_64 )
+DEF_SDL_KEY( SDLK_WORLD_65 )
+DEF_SDL_KEY( SDLK_WORLD_66 )
+DEF_SDL_KEY( SDLK_WORLD_67 )
+DEF_SDL_KEY( SDLK_WORLD_68 )
+DEF_SDL_KEY( SDLK_WORLD_69 )
+DEF_SDL_KEY( SDLK_WORLD_70 )
+DEF_SDL_KEY( SDLK_WORLD_71 )
+DEF_SDL_KEY( SDLK_WORLD_72 )
+DEF_SDL_KEY( SDLK_WORLD_73 )
+DEF_SDL_KEY( SDLK_WORLD_74 )
+DEF_SDL_KEY( SDLK_WORLD_75 )
+DEF_SDL_KEY( SDLK_WORLD_76 )
+DEF_SDL_KEY( SDLK_WORLD_77 )
+DEF_SDL_KEY( SDLK_WORLD_78 )
+DEF_SDL_KEY( SDLK_WORLD_79 )
+DEF_SDL_KEY( SDLK_WORLD_80 )
+DEF_SDL_KEY( SDLK_WORLD_81 )
+DEF_SDL_KEY( SDLK_WORLD_82 )
+DEF_SDL_KEY( SDLK_WORLD_83 )
+DEF_SDL_KEY( SDLK_WORLD_84 )
+DEF_SDL_KEY( SDLK_WORLD_85 )
+DEF_SDL_KEY( SDLK_WORLD_86 )
+DEF_SDL_KEY( SDLK_WORLD_87 )
+DEF_SDL_KEY( SDLK_WORLD_88 )
+DEF_SDL_KEY( SDLK_WORLD_89 )
+DEF_SDL_KEY( SDLK_WORLD_90 )
+DEF_SDL_KEY( SDLK_WORLD_91 )
+DEF_SDL_KEY( SDLK_WORLD_92 )
+DEF_SDL_KEY( SDLK_WORLD_93 )
+DEF_SDL_KEY( SDLK_WORLD_94 )
+DEF_SDL_KEY( SDLK_WORLD_95 )
+DEF_SDL_KEY( SDLK_KP0 )
+DEF_SDL_KEY( SDLK_KP1 )
+DEF_SDL_KEY( SDLK_KP2 )
+DEF_SDL_KEY( SDLK_KP3 )
+DEF_SDL_KEY( SDLK_KP4 )
+DEF_SDL_KEY( SDLK_KP5 )
+DEF_SDL_KEY( SDLK_KP6 )
+DEF_SDL_KEY( SDLK_KP7 )
+DEF_SDL_KEY( SDLK_KP8 )
+DEF_SDL_KEY( SDLK_KP9 )
+DEF_SDL_KEY( SDLK_KP_PERIOD )
+DEF_SDL_KEY( SDLK_KP_DIVIDE )
+DEF_SDL_KEY( SDLK_KP_MULTIPLY )
+DEF_SDL_KEY( SDLK_KP_MINUS )
+DEF_SDL_KEY( SDLK_KP_PLUS )
+DEF_SDL_KEY( SDLK_KP_ENTER )
+DEF_SDL_KEY( SDLK_KP_EQUALS )
+DEF_SDL_KEY( SDLK_UP )
+DEF_SDL_KEY( SDLK_DOWN )
+DEF_SDL_KEY( SDLK_RIGHT )
+DEF_SDL_KEY( SDLK_LEFT )
+DEF_SDL_KEY( SDLK_INSERT )
+DEF_SDL_KEY( SDLK_HOME )
+DEF_SDL_KEY( SDLK_END )
+DEF_SDL_KEY( SDLK_PAGEUP )
+DEF_SDL_KEY( SDLK_PAGEDOWN )
+DEF_SDL_KEY( SDLK_F1 )
+DEF_SDL_KEY( SDLK_F2 )
+DEF_SDL_KEY( SDLK_F3 )
+DEF_SDL_KEY( SDLK_F4 )
+DEF_SDL_KEY( SDLK_F5 )
+DEF_SDL_KEY( SDLK_F6 )
+DEF_SDL_KEY( SDLK_F7 )
+DEF_SDL_KEY( SDLK_F8 )
+DEF_SDL_KEY( SDLK_F9 )
+DEF_SDL_KEY( SDLK_F10 )
+DEF_SDL_KEY( SDLK_F11 )
+DEF_SDL_KEY( SDLK_F12 )
+DEF_SDL_KEY( SDLK_F13 )
+DEF_SDL_KEY( SDLK_F14 )
+DEF_SDL_KEY( SDLK_F15 )
+DEF_SDL_KEY( SDLK_NUMLOCK )
+DEF_SDL_KEY( SDLK_CAPSLOCK )
+DEF_SDL_KEY( SDLK_SCROLLOCK )
+DEF_SDL_KEY( SDLK_RSHIFT )
+DEF_SDL_KEY( SDLK_LSHIFT )
+DEF_SDL_KEY( SDLK_RCTRL )
+DEF_SDL_KEY( SDLK_LCTRL )
+DEF_SDL_KEY( SDLK_RALT )
+DEF_SDL_KEY( SDLK_LALT )
+DEF_SDL_KEY( SDLK_RMETA )
+DEF_SDL_KEY( SDLK_LMETA )
+DEF_SDL_KEY( SDLK_LSUPER )
+DEF_SDL_KEY( SDLK_RSUPER )
+DEF_SDL_KEY( SDLK_MODE )
+DEF_SDL_KEY( SDLK_COMPOSE )
+DEF_SDL_KEY( SDLK_HELP )
+DEF_SDL_KEY( SDLK_PRINT )
+DEF_SDL_KEY( SDLK_SYSREQ )
+DEF_SDL_KEY( SDLK_BREAK )
+DEF_SDL_KEY( SDLK_MENU )
+DEF_SDL_KEY( SDLK_POWER )
+DEF_SDL_KEY( SDLK_EURO )
+DEF_SDL_KEY( SDLK_UNDO )
diff --git a/tools/ioemu/gui/siminterface.cc b/tools/ioemu/gui/siminterface.cc
new file mode 100644
index 0000000000..0284e6b1d7
--- /dev/null
+++ b/tools/ioemu/gui/siminterface.cc
@@ -0,0 +1,1411 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: siminterface.cc,v 1.105 2004/01/05 22:18:01 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// See siminterface.h for description of the siminterface concept.
+// Basically, the siminterface is visible from both the simulator and
+// the configuration user interface, and allows them to talk to each other.
+
+#include "bochs.h"
+
+bx_simulator_interface_c *SIM = NULL;
+logfunctions *siminterface_log = NULL;
+#define LOG_THIS siminterface_log->
+
+// bx_simulator_interface just defines the interface that the Bochs simulator
+// and the gui will use to talk to each other. None of the methods of
+// bx_simulator_interface are implemented; they are all virtual. The
+// bx_real_sim_c class is a child of bx_simulator_interface_c, and it
+// implements all the methods. The idea is that a gui needs to know only
+// definition of bx_simulator_interface to talk to Bochs. The gui should
+// not need to include bochs.h.
+//
+// I made this separation to ensure that all guis use the siminterface to do
+// access bochs internals, instead of accessing things like
+// bx_keyboard.s.internal_buffer[4] (or whatever) directly. -Bryce
+//
+
+class bx_real_sim_c : public bx_simulator_interface_c {
+ bxevent_handler bxevent_callback;
+ void *bxevent_callback_data;
+ const char *registered_ci_name;
+ config_interface_callback_t ci_callback;
+ void *ci_callback_data;
+ int init_done;
+ bx_param_c **param_registry;
+ int registry_alloc_size;
+ int enabled;
+ // save context to jump to if we must quit unexpectedly
+ jmp_buf *quit_context;
+ int exit_code;
+public:
+ bx_real_sim_c ();
+ virtual ~bx_real_sim_c ();
+ virtual void set_quit_context (jmp_buf *context) { quit_context = context; }
+ virtual int get_init_done () { return init_done; }
+ virtual int set_init_done (int n) { init_done = n; return 0;}
+ virtual void get_param_id_range (int *min, int *max) {
+ *min = BXP_NULL;
+ *max = BXP_THIS_IS_THE_LAST-1;
+ }
+ virtual int register_param (bx_id id, bx_param_c *it);
+ virtual void reset_all_param ();
+ virtual bx_param_c *get_param (bx_id id);
+ virtual bx_param_num_c *get_param_num (bx_id id);
+ virtual bx_param_string_c *get_param_string (bx_id id);
+ virtual bx_param_bool_c *get_param_bool (bx_id id);
+ virtual bx_param_enum_c *get_param_enum (bx_id id);
+ virtual int get_n_log_modules ();
+ virtual char *get_prefix (int mod);
+ virtual int get_log_action (int mod, int level);
+ virtual void set_log_action (int mod, int level, int action);
+ virtual char *get_action_name (int action);
+ virtual int get_default_log_action (int level) {
+ return logfunctions::get_default_action (level);
+ }
+ virtual void set_default_log_action (int level, int action) {
+ logfunctions::set_default_action (level, action);
+ }
+ virtual const char *get_log_level_name (int level);
+ virtual int get_max_log_level ();
+ virtual void quit_sim (int code);
+ virtual int get_exit_code () { return exit_code; }
+ virtual int get_default_rc (char *path, int len);
+ virtual int read_rc (char *path);
+ virtual int write_rc (char *path, int overwrite);
+ virtual int get_log_file (char *path, int len);
+ virtual int set_log_file (char *path);
+ virtual int get_log_prefix (char *prefix, int len);
+ virtual int set_log_prefix (char *prefix);
+ virtual int get_debugger_log_file (char *path, int len);
+ virtual int set_debugger_log_file (char *path);
+ virtual int get_floppy_options (int drive, bx_floppy_options *out);
+ virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *device = NULL);
+ virtual char *get_floppy_type_name (int type);
+ virtual void set_notify_callback (bxevent_handler func, void *arg);
+ virtual void get_notify_callback (bxevent_handler *func, void **arg);
+ virtual BxEvent* sim_to_ci_event (BxEvent *event);
+ virtual int log_msg (const char *prefix, int level, const char *msg);
+ virtual int ask_param (bx_id which);
+ // ask the user for a pathname
+ virtual int ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags);
+ // called at a regular interval, currently by the keyboard handler.
+ virtual void periodic ();
+ virtual int create_disk_image (const char *filename, int sectors, bx_bool overwrite);
+ virtual void refresh_ci ();
+ virtual void refresh_vga () {
+ // maybe need to check if something has been initialized yet?
+ DEV_vga_refresh();
+ }
+ virtual void handle_events () {
+ // maybe need to check if something has been initialized yet?
+ bx_gui->handle_events ();
+ }
+ // find first hard drive or cdrom
+ bx_param_c *get_first_atadevice (Bit32u search_type);
+ bx_param_c *get_first_cdrom () {
+ return get_first_atadevice (BX_ATA_DEVICE_CDROM);
+ }
+ bx_param_c *get_first_hd () {
+ return get_first_atadevice (BX_ATA_DEVICE_DISK);
+ }
+#if BX_DEBUGGER
+ virtual void debug_break ();
+ virtual void debug_interpret_cmd (char *cmd);
+ virtual char *debug_get_next_command ();
+ virtual void debug_puts (const char *cmd);
+#endif
+ virtual void register_configuration_interface (
+ const char* name,
+ config_interface_callback_t callback,
+ void *userdata);
+ virtual int configuration_interface(const char* name, ci_command_t command);
+ virtual int begin_simulation (int argc, char *argv[]);
+ virtual void set_sim_thread_func (is_sim_thread_func_t func) {}
+ virtual bool is_sim_thread ();
+ bool wxsel;
+ virtual bool is_wx_selected () { return wxsel; }
+ // provide interface to bx_gui->set_display_mode() method for config
+ // interfaces to use.
+ virtual void set_display_mode (disp_mode_t newmode) {
+ if (bx_gui != NULL)
+ bx_gui->set_display_mode (newmode);
+ }
+ virtual bool test_for_text_console ();
+};
+
+bx_param_c *
+bx_real_sim_c::get_param (bx_id id)
+{
+ BX_ASSERT (id >= BXP_NULL && id < BXP_THIS_IS_THE_LAST);
+ int index = (int)id - BXP_NULL;
+ bx_param_c *retval = param_registry[index];
+ if (!retval)
+ BX_INFO (("get_param can't find id %u", id));
+ return retval;
+}
+
+bx_param_num_c *
+bx_real_sim_c::get_param_num (bx_id id) {
+ bx_param_c *generic = get_param(id);
+ if (generic==NULL) {
+ BX_PANIC (("get_param_num(%u) could not find a parameter", id));
+ return NULL;
+ }
+ int type = generic->get_type ();
+ if (type == BXT_PARAM_NUM || type == BXT_PARAM_BOOL || type == BXT_PARAM_ENUM)
+ return (bx_param_num_c *)generic;
+ BX_PANIC (("get_param_num %u could not find an integer parameter with that id", id));
+ return NULL;
+}
+
+bx_param_string_c *
+bx_real_sim_c::get_param_string (bx_id id) {
+ bx_param_c *generic = get_param(id);
+ if (generic==NULL) {
+ BX_PANIC (("get_param_string(%u) could not find a parameter", id));
+ return NULL;
+ }
+ if (generic->get_type () == BXT_PARAM_STRING)
+ return (bx_param_string_c *)generic;
+ BX_PANIC (("get_param_string %u could not find an integer parameter with that id", id));
+ return NULL;
+}
+
+bx_param_bool_c *
+bx_real_sim_c::get_param_bool (bx_id id) {
+ bx_param_c *generic = get_param(id);
+ if (generic==NULL) {
+ BX_PANIC (("get_param_bool(%u) could not find a parameter", id));
+ return NULL;
+ }
+ if (generic->get_type () == BXT_PARAM_BOOL)
+ return (bx_param_bool_c *)generic;
+ BX_PANIC (("get_param_bool %u could not find a bool parameter with that id", id));
+ return NULL;
+}
+
+bx_param_enum_c *
+bx_real_sim_c::get_param_enum (bx_id id) {
+ bx_param_c *generic = get_param(id);
+ if (generic==NULL) {
+ BX_PANIC (("get_param_enum(%u) could not find a parameter", id));
+ return NULL;
+ }
+ if (generic->get_type () == BXT_PARAM_ENUM)
+ return (bx_param_enum_c *)generic;
+ BX_PANIC (("get_param_enum %u could not find a enum parameter with that id", id));
+ return NULL;
+}
+
+void bx_init_siminterface ()
+{
+ siminterface_log = new logfunctions ();
+ siminterface_log->put ("CTRL");
+ siminterface_log->settype(CTRLLOG);
+ if (SIM == NULL)
+ SIM = new bx_real_sim_c();
+}
+
+bx_simulator_interface_c::bx_simulator_interface_c ()
+{
+}
+
+bx_real_sim_c::bx_real_sim_c ()
+{
+ bxevent_callback = NULL;
+ bxevent_callback_data = NULL;
+ ci_callback = NULL;
+ ci_callback_data = NULL;
+ is_sim_thread_func = NULL;
+ wxsel = false;
+
+ enabled = 1;
+ int i;
+ init_done = 0;
+ registry_alloc_size = BXP_THIS_IS_THE_LAST - BXP_NULL;
+ param_registry = new bx_param_c* [registry_alloc_size];
+ for (i=0; i<registry_alloc_size; i++)
+ param_registry[i] = NULL;
+ quit_context = NULL;
+ exit_code = 0;
+}
+
+// called by constructor of bx_param_c, so that every parameter that is
+// initialized gets registered. This builds a list of all parameters
+// which can be used to look them up by number (get_param).
+bx_real_sim_c::~bx_real_sim_c ()
+{
+ if ( param_registry != NULL )
+ {
+ delete [] param_registry;
+ param_registry = NULL;
+ }
+}
+
+int
+bx_real_sim_c::register_param (bx_id id, bx_param_c *it)
+{
+ if (id == BXP_NULL) return 0;
+ BX_ASSERT (id >= BXP_NULL && id < BXP_THIS_IS_THE_LAST);
+ int index = (int)id - BXP_NULL;
+ if (this->param_registry[index] != NULL) {
+ BX_INFO (("register_param is overwriting parameter id %d", id));
+ }
+ this->param_registry[index] = it;
+ return 0;
+}
+
+void
+bx_real_sim_c::reset_all_param ()
+{
+ bx_reset_options ();
+}
+
+int
+bx_real_sim_c::get_n_log_modules ()
+{
+ return io->get_n_logfns ();
+}
+
+char *
+bx_real_sim_c::get_prefix (int mod)
+{
+ logfunc_t *logfn = io->get_logfn (mod);
+ return logfn->getprefix ();
+}
+
+int
+bx_real_sim_c::get_log_action (int mod, int level)
+{
+ logfunc_t *logfn = io->get_logfn (mod);
+ return logfn->getonoff (level);
+}
+
+void
+bx_real_sim_c::set_log_action (int mod, int level, int action)
+{
+ // normal
+ if (mod >= 0) {
+ logfunc_t *logfn = io->get_logfn (mod);
+ logfn->setonoff (level, action);
+ return;
+ }
+ // if called with mod<0 loop over all
+ int nmod = get_n_log_modules ();
+ for (mod=0; mod<nmod; mod++)
+ set_log_action (mod, level, action);
+}
+
+char *
+bx_real_sim_c::get_action_name (int action)
+{
+ return io->getaction (action);
+}
+
+const char *
+bx_real_sim_c::get_log_level_name (int level)
+{
+ return io->getlevel (level);
+}
+
+int
+bx_real_sim_c::get_max_log_level ()
+{
+ return N_LOGLEV;
+}
+
+void
+bx_real_sim_c::quit_sim (int code) {
+ BX_INFO (("quit_sim called with exit code %d", code));
+ exit_code = code;
+ // use longjmp to quit cleanly, no matter where in the stack we are.
+ //fprintf (stderr, "using longjmp() to jump directly to the quit context!\n");
+ if (quit_context != NULL) {
+ longjmp (*quit_context, 1);
+ BX_PANIC (("in bx_real_sim_c::quit_sim, longjmp should never return"));
+ }
+ if (SIM->is_wx_selected ()) {
+ // in wxWindows, the whole simulator is running in a separate thread.
+ // our only job is to end the thread as soon as possible, NOT to shut
+ // down the whole application with an exit.
+ BX_CPU(0)->async_event = 1;
+ BX_CPU(0)->kill_bochs_request = 1;
+ // the cpu loop will exit very soon after this condition is set.
+ } else {
+ // just a single thread. Use exit() to stop the application.
+ if (!code)
+ BX_PANIC (("Quit simulation command"));
+ ::exit (exit_code);
+ }
+}
+
+int
+bx_real_sim_c::get_default_rc (char *path, int len)
+{
+ char *rc = bx_find_bochsrc ();
+ if (rc == NULL) return -1;
+ strncpy (path, rc, len);
+ path[len-1] = 0;
+ return 0;
+}
+
+int
+bx_real_sim_c::read_rc (char *rc)
+{
+ return bx_read_configuration (rc);
+}
+
+// return values:
+// 0: written ok
+// -1: failed
+// -2: already exists, and overwrite was off
+int
+bx_real_sim_c::write_rc (char *rc, int overwrite)
+{
+ return bx_write_configuration (rc, overwrite);
+}
+
+int
+bx_real_sim_c::get_log_file (char *path, int len)
+{
+ strncpy (path, bx_options.log.Ofilename->getptr (), len);
+ return 0;
+}
+
+int
+bx_real_sim_c::set_log_file (char *path)
+{
+ bx_options.log.Ofilename->set (path);
+ return 0;
+}
+
+int
+bx_real_sim_c::get_log_prefix (char *prefix, int len)
+{
+ strncpy (prefix, bx_options.log.Oprefix->getptr (), len);
+ return 0;
+}
+
+int
+bx_real_sim_c::set_log_prefix (char *prefix)
+{
+ bx_options.log.Oprefix->set (prefix);
+ return 0;
+}
+
+int
+bx_real_sim_c::get_debugger_log_file (char *path, int len)
+{
+ strncpy (path, bx_options.log.Odebugger_filename->getptr (), len);
+ return 0;
+}
+
+int
+bx_real_sim_c::set_debugger_log_file (char *path)
+{
+ bx_options.log.Odebugger_filename->set (path);
+ return 0;
+}
+
+int
+bx_real_sim_c::get_floppy_options (int drive, bx_floppy_options *out)
+{
+ *out = (drive==0)? bx_options.floppya : bx_options.floppyb;
+ return 0;
+}
+
+int
+bx_real_sim_c::get_cdrom_options (int level, bx_atadevice_options *out, int *where)
+{
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ for (Bit8u device=0; device<2; device++) {
+ if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_CDROM) {
+ if (level==0) {
+ *out = bx_options.atadevice[channel][device];
+ if (where != NULL) *where=(channel*2)+device;
+ return 1;
+ }
+ else level--;
+ }
+ }
+ }
+ return 0;
+}
+
+char *bochs_start_names[] = { "quick", "load", "edit", "run" };
+int n_bochs_start_names = 3;
+
+char *floppy_type_names[] = { "none", "1.2M", "1.44M", "2.88M", "720K", "360K", "160K", "180K", "320K", NULL };
+int floppy_type_n_sectors[] = { -1, 80*2*15, 80*2*18, 80*2*36, 80*2*9, 40*2*9, 40*1*8, 40*1*9, 40*2*8 };
+int n_floppy_type_names = 9;
+
+char *floppy_status_names[] = { "ejected", "inserted", NULL };
+int n_floppy_status_names = 2;
+char *floppy_bootdisk_names[] = { "floppy", "disk","cdrom", NULL };
+int n_floppy_bootdisk_names = 3;
+char *loader_os_names[] = { "none", "linux", "nullkernel", NULL };
+int n_loader_os_names = 3;
+char *keyboard_type_names[] = { "xt", "at", "mf", NULL };
+int n_keyboard_type_names = 3;
+
+char *atadevice_type_names[] = { "disk", "cdrom", NULL };
+int n_atadevice_type_names = 2;
+//char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "split", "undoable", "growing", "volatile", "z-undoable", "z-volatile", NULL };
+char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "undoable", "growing", "volatile", NULL };
+int n_atadevice_mode_names = 9;
+char *atadevice_status_names[] = { "ejected", "inserted", NULL };
+int n_atadevice_status_names = 2;
+char *atadevice_biosdetect_names[] = { "none", "auto", "cmos", NULL };
+int n_atadevice_biosdetect_names = 3;
+char *atadevice_translation_names[] = { "none", "lba", "large", "rechs", "auto", NULL };
+int n_atadevice_translation_names = 5;
+char *clock_sync_names[] = { "none", "realtime", "slowdown", "both", NULL };
+int clock_sync_n_names=4;
+
+
+
+char *
+bx_real_sim_c::get_floppy_type_name (int type)
+{
+ BX_ASSERT (type >= BX_FLOPPY_NONE && type <= BX_FLOPPY_LAST);
+ type -= BX_FLOPPY_NONE;
+ return floppy_type_names[type];
+}
+
+void
+bx_real_sim_c::set_notify_callback (bxevent_handler func, void *arg)
+{
+ bxevent_callback = func;
+ bxevent_callback_data = arg;
+}
+
+void bx_real_sim_c::get_notify_callback (
+ bxevent_handler *func,
+ void **arg)
+{
+ *func = bxevent_callback;
+ *arg = bxevent_callback_data;
+}
+
+BxEvent *
+bx_real_sim_c::sim_to_ci_event (BxEvent *event)
+{
+ if (bxevent_callback == NULL) {
+ BX_ERROR (("notify called, but no bxevent_callback function is registered"));
+ return NULL;
+ } else {
+ return (*bxevent_callback)(bxevent_callback_data, event);
+ }
+}
+
+// returns 0 for continue, 1 for alwayscontinue, 2 for die.
+int
+bx_real_sim_c::log_msg (const char *prefix, int level, const char *msg)
+{
+ BxEvent be;
+ be.type = BX_SYNC_EVT_LOG_ASK;
+ be.u.logmsg.prefix = prefix;
+ be.u.logmsg.level = level;
+ be.u.logmsg.msg = msg;
+ // default return value in case something goes wrong.
+ be.retcode = BX_LOG_ASK_CHOICE_DIE;
+ //fprintf (stderr, "calling notify.\n");
+ sim_to_ci_event (&be);
+ return be.retcode;
+}
+
+// Called by simulator whenever it needs the user to choose a new value
+// for a registered parameter. Create a synchronous ASK_PARAM event,
+// send it to the CI, and wait for the response. The CI will call the
+// set() method on the parameter if the user changes the value.
+int
+bx_real_sim_c::ask_param (bx_id param)
+{
+ bx_param_c *paramptr = SIM->get_param(param);
+ BX_ASSERT (paramptr != NULL);
+ // create appropriate event
+ BxEvent event;
+ event.type = BX_SYNC_EVT_ASK_PARAM;
+ event.u.param.param = paramptr;
+ sim_to_ci_event (&event);
+ return event.retcode;
+}
+
+int
+bx_real_sim_c::ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags)
+{
+ // implement using ASK_PARAM on a newly created param. I can't use
+ // ask_param because I don't intend to register this param.
+ BxEvent event;
+ bx_param_string_c param (BXP_NULL, prompt, "filename", the_default, maxlen);
+ flags |= param.IS_FILENAME;
+ param.get_options()->set (flags);
+ event.type = BX_SYNC_EVT_ASK_PARAM;
+ event.u.param.param = &param;
+ sim_to_ci_event (&event);
+ if (event.retcode >= 0)
+ memcpy (filename, param.getptr(), maxlen);
+ return event.retcode;
+}
+
+void
+bx_real_sim_c::periodic ()
+{
+ // give the GUI a chance to do periodic things on the bochs thread. in
+ // particular, notice if the thread has been asked to die.
+ BxEvent tick;
+ tick.type = BX_SYNC_EVT_TICK;
+ sim_to_ci_event (&tick);
+ if (tick.retcode < 0) {
+ BX_INFO (("Bochs thread has been asked to quit."));
+ bx_atexit ();
+ quit_sim (0);
+ }
+ static int refresh_counter = 0;
+ if (++refresh_counter == 50) {
+ // only ask the CI to refresh every 50 times periodic() is called.
+ // This should obviously be configurable because system speeds and
+ // user preferences vary.
+ refresh_ci ();
+ refresh_counter = 0;
+ }
+#if 0
+ // watch for memory leaks. Allocate a small block of memory, print the
+ // pointer that is returned, then free.
+ BxEvent *memcheck = new BxEvent ();
+ BX_INFO(("memory allocation at %p", memcheck));
+ delete memcheck;
+#endif
+}
+
+// create a disk image file called filename, size=512 bytes * sectors.
+// If overwrite is true and the file exists, returns -1 without changing it.
+// Otherwise, opens up the image and starts writing. Returns -2 if
+// the image could not be opened, or -3 if there are failures during
+// write, e.g. disk full.
+//
+// wxWindows: This may be called from the gui thread.
+int
+bx_real_sim_c::create_disk_image (
+ const char *filename,
+ int sectors,
+ bx_bool overwrite)
+{
+ FILE *fp;
+ if (!overwrite) {
+ // check for existence first
+ fp = fopen (filename, "r");
+ if (fp) {
+ // yes it exists
+ fclose (fp);
+ return -1;
+ }
+ }
+ fp = fopen (filename, "w");
+ if (fp == NULL) {
+#ifdef HAVE_PERROR
+ char buffer[1024];
+ sprintf (buffer, "while opening '%s' for writing", filename);
+ perror (buffer);
+ // not sure how to get this back into the CI
+#endif
+ return -2;
+ }
+ int sec = sectors;
+ /*
+ * seek to sec*512-1 and write a single character.
+ * can't just do: fseek(fp, 512*sec-1, SEEK_SET)
+ * because 512*sec may be too large for signed int.
+ */
+ while (sec > 0)
+ {
+ /* temp <-- min(sec, 4194303)
+ * 4194303 is (int)(0x7FFFFFFF/512)
+ */
+ int temp = ((sec < 4194303) ? sec : 4194303);
+ fseek(fp, 512*temp, SEEK_CUR);
+ sec -= temp;
+ }
+
+ fseek(fp, -1, SEEK_CUR);
+ if (fputc('\0', fp) == EOF)
+ {
+ fclose (fp);
+ return -3;
+ }
+ fclose (fp);
+ return 0;
+}
+
+void bx_real_sim_c::refresh_ci () {
+ if (SIM->is_wx_selected ()) {
+ // presently, only wxWindows interface uses these events
+ // It's an async event, so allocate a pointer and send it.
+ // The event will be freed by the recipient.
+ BxEvent *event = new BxEvent ();
+ event->type = BX_ASYNC_EVT_REFRESH;
+ sim_to_ci_event (event);
+ }
+}
+
+bx_param_c *
+bx_real_sim_c::get_first_atadevice (Bit32u search_type) {
+ for (int channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if (!bx_options.ata[channel].Opresent->get ())
+ continue;
+ for (int slave=0; slave<2; slave++) {
+ Bit32u present = bx_options.atadevice[channel][slave].Opresent->get ();
+ Bit32u type = bx_options.atadevice[channel][slave].Otype->get ();
+ if (present && (type == search_type)) {
+ return bx_options.atadevice[channel][slave].Omenu;
+ }
+ }
+ }
+ return NULL;
+}
+
+#if BX_DEBUGGER
+
+// this can be safely called from either thread.
+void bx_real_sim_c::debug_break () {
+ bx_debug_break ();
+}
+
+// this should only be called from the sim_thread.
+void bx_real_sim_c::debug_interpret_cmd (char *cmd) {
+ if (!is_sim_thread ()) {
+ fprintf (stderr, "ERROR: debug_interpret_cmd called but not from sim_thread\n");
+ return;
+ }
+ bx_dbg_interpret_line (cmd);
+}
+
+char *bx_real_sim_c::debug_get_next_command ()
+{
+ fprintf (stderr, "begin debug_get_next_command\n");
+ BxEvent event;
+ event.type = BX_SYNC_EVT_GET_DBG_COMMAND;
+ BX_INFO (("asking for next debug command"));
+ sim_to_ci_event (&event);
+ BX_INFO (("received next debug command: '%s'", event.u.debugcmd.command));
+ if (event.retcode >= 0)
+ return event.u.debugcmd.command;
+ return NULL;
+}
+
+void bx_real_sim_c::debug_puts (const char *text)
+{
+ if (SIM->is_wx_selected ()) {
+ // send message to the wxWindows debugger
+ BxEvent *event = new BxEvent ();
+ event->type = BX_ASYNC_EVT_DBG_MSG;
+ event->u.logmsg.msg = text;
+ sim_to_ci_event (event);
+ // the event will be freed by the recipient
+ } else {
+ // text mode debugger: just write to console
+ fputs (text, stderr);
+ delete [] (char *)text;
+ }
+}
+#endif
+
+void
+bx_real_sim_c::register_configuration_interface (
+ const char* name,
+ config_interface_callback_t callback,
+ void *userdata)
+{
+ ci_callback = callback;
+ ci_callback_data = userdata;
+ registered_ci_name = name;
+}
+
+int
+bx_real_sim_c::configuration_interface(const char *ignore, ci_command_t command)
+{
+ bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+ char *name = ci_param->get_choice (ci_param->get ());
+ if (!ci_callback) {
+ BX_PANIC (("no configuration interface was loaded"));
+ return -1;
+ }
+ if (strcmp (name, registered_ci_name) != 0) {
+ BX_PANIC (("siminterface does not support loading one configuration interface and then calling another"));
+ return -1;
+ }
+ if (!strcmp (name, "wx"))
+ wxsel = true;
+ else
+ wxsel = false;
+ // enter configuration mode, just while running the configuration interface
+ set_display_mode (DISP_MODE_CONFIG);
+ int retval = (*ci_callback)(ci_callback_data, command);
+ set_display_mode (DISP_MODE_SIM);
+ return retval;
+}
+
+int
+bx_real_sim_c::begin_simulation (int argc, char *argv[])
+{
+ return bx_begin_simulation (argc, argv);
+}
+
+bool bx_real_sim_c::is_sim_thread ()
+{
+ if (is_sim_thread_func == NULL) return true;
+ return (*is_sim_thread_func)();
+}
+
+// check if the text console exists. On some platforms, if Bochs is
+// started from the "Start Menu" or by double clicking on it on a Mac,
+// there may be nothing attached to stdin/stdout/stderr. This function
+// tests if stdin/stdout/stderr are usable and returns false if not.
+bool
+bx_real_sim_c::test_for_text_console ()
+{
+#if BX_WITH_CARBON
+ // In a Carbon application, you have a text console if you run the app from
+ // the command line, but if you start it from the finder you don't.
+ if(!isatty(STDIN_FILENO)) return false;
+#endif
+ // default: yes
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// define methods of bx_param_* and family
+/////////////////////////////////////////////////////////////////////////
+
+bx_object_c::bx_object_c (bx_id id)
+{
+ this->id = id;
+ this->type = BXT_OBJECT;
+}
+
+void
+bx_object_c::set_type (bx_objtype type)
+{
+ this->type = type;
+}
+
+const char* bx_param_c::default_text_format = NULL;
+
+bx_param_c::bx_param_c (bx_id id, char *name, char *description)
+ : bx_object_c (id)
+{
+ set_type (BXT_PARAM);
+ this->name = name;
+ this->description = description;
+ this->text_format = default_text_format;
+ this->ask_format = NULL;
+ this->label = NULL;
+ this->runtime_param = 0;
+ this->enabled = 1;
+ SIM->register_param (id, this);
+}
+
+const char* bx_param_c::set_default_format (const char *f) {
+ const char *old = default_text_format;
+ default_text_format = f;
+ return old;
+}
+
+bx_param_num_c::bx_param_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s min, Bit64s max, Bit64s initial_val)
+ : bx_param_c (id, name, description)
+{
+ set_type (BXT_PARAM_NUM);
+ this->min = min;
+ this->max = max;
+ this->initial_val = initial_val;
+ this->val.number = initial_val;
+ this->handler = NULL;
+ this->enable_handler = NULL;
+ this->base = default_base;
+ // dependent_list must be initialized before the set(),
+ // because set calls update_dependents().
+ dependent_list = NULL;
+ set (initial_val);
+}
+
+Bit32u bx_param_num_c::default_base = 10;
+
+Bit32u bx_param_num_c::set_default_base (Bit32u val) {
+ Bit32u old = default_base;
+ default_base = val;
+ return old;
+}
+
+void
+bx_param_num_c::reset ()
+{
+ this->val.number = initial_val;
+}
+
+void
+bx_param_num_c::set_handler (param_event_handler handler)
+{
+ this->handler = handler;
+ // now that there's a handler, call set once to run the handler immediately
+ //set (get ());
+}
+
+void
+bx_param_num_c::set_enable_handler (param_enable_handler handler)
+{
+ this->enable_handler = handler;
+}
+
+void bx_param_num_c::set_dependent_list (bx_list_c *l) {
+ dependent_list = l;
+ update_dependents ();
+}
+
+Bit64s
+bx_param_num_c::get64 ()
+{
+ if (handler) {
+ // the handler can decide what value to return and/or do some side effect
+ return (*handler)(this, 0, val.number);
+ } else {
+ // just return the value
+ return val.number;
+ }
+}
+
+void
+bx_param_num_c::set (Bit64s newval)
+{
+ if (handler) {
+ // the handler can override the new value and/or perform some side effect
+ val.number = newval;
+ (*handler)(this, 1, newval);
+ } else {
+ // just set the value. This code does not check max/min.
+ val.number = newval;
+ }
+ if ((val.number < min || val.number > max) && (Bit64u)max != BX_MAX_BIT64U)
+ BX_PANIC (("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), val.number, min, max));
+ if (dependent_list != NULL) update_dependents ();
+}
+
+void bx_param_num_c::set_range (Bit64u min, Bit64u max)
+{
+ this->min = min;
+ this->max = max;
+}
+
+void bx_param_num_c::set_initial_val (Bit64s initial_val) {
+ this->val.number = this->initial_val = initial_val;
+}
+
+void bx_param_num_c::update_dependents ()
+{
+ if (dependent_list) {
+ int en = val.number && enabled;
+ for (int i=0; i<dependent_list->get_size (); i++) {
+ bx_param_c *param = dependent_list->get (i);
+ if (param != this)
+ param->set_enabled (en);
+ }
+ }
+}
+
+void
+bx_param_num_c::set_enabled (int en)
+{
+ // The enable handler may wish to allow/disallow the action
+ if (enable_handler) {
+ en = (*enable_handler) (this, en);
+ }
+ bx_param_c::set_enabled (en);
+ update_dependents ();
+}
+
+// Signed 64 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT64S, BX_MAX_BIT64S, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p64bit = ptr_to_real_val;
+}
+
+// Unsigned 64 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64u *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT64U, BX_MAX_BIT64U, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p64bit = (Bit64s*) ptr_to_real_val;
+}
+
+// Signed 32 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit32s *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT32S, BX_MAX_BIT32S, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p32bit = ptr_to_real_val;
+}
+
+// Unsigned 32 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit32u *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT32U, BX_MAX_BIT32U, *ptr_to_real_val)
+{
+ this->varsize = 32;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p32bit = (Bit32s*) ptr_to_real_val;
+}
+
+// Signed 16 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit16s *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT16S, BX_MAX_BIT16S, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p16bit = ptr_to_real_val;
+}
+
+// Unsigned 16 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit16u *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT16U, BX_MAX_BIT16U, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p16bit = (Bit16s*) ptr_to_real_val;
+}
+
+// Signed 8 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit8s *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT8S, BX_MAX_BIT8S, *ptr_to_real_val)
+{
+ this->varsize = 16;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p8bit = ptr_to_real_val;
+}
+
+// Unsigned 8 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit8u *ptr_to_real_val,
+ Bit8u highbit,
+ Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT8U, BX_MAX_BIT8U, *ptr_to_real_val)
+{
+ this->varsize = 8;
+ this->lowbit = lowbit;
+ this->mask = (1 << (highbit - lowbit)) - 1;
+ val.p8bit = (Bit8s*) ptr_to_real_val;
+}
+
+Bit64s
+bx_shadow_num_c::get64 () {
+ Bit64u current = 0;
+ switch (varsize) {
+ case 8: current = *(val.p8bit); break;
+ case 16: current = *(val.p16bit); break;
+ case 32: current = *(val.p32bit); break;
+ case 64: current = *(val.p64bit); break;
+ default: BX_PANIC(("unsupported varsize %d", varsize));
+ }
+ current = (current >> lowbit) & mask;
+ if (handler) {
+ // the handler can decide what value to return and/or do some side effect
+ return (*handler)(this, 0, current) & mask;
+ } else {
+ // just return the value
+ return current;
+ }
+}
+
+void
+bx_shadow_num_c::set (Bit64s newval)
+{
+ Bit64u tmp = 0;
+ if ((newval < min || newval > max) && (Bit64u)max != BX_MAX_BIT64U)
+ BX_PANIC (("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), newval, min, max));
+ switch (varsize) {
+ case 8:
+ tmp = (*(val.p8bit) >> lowbit) & mask;
+ tmp |= (newval & mask) << lowbit;
+ *(val.p8bit) = (Bit8s)tmp;
+ break;
+ case 16:
+ tmp = (*(val.p16bit) >> lowbit) & mask;
+ tmp |= (newval & mask) << lowbit;
+ *(val.p16bit) = (Bit16s)tmp;
+ break;
+ case 32:
+ tmp = (*(val.p32bit) >> lowbit) & mask;
+ tmp |= (newval & mask) << lowbit;
+ *(val.p32bit) = (Bit32s)tmp;
+ break;
+ case 64:
+ tmp = (*(val.p64bit) >> lowbit) & mask;
+ tmp |= (newval & mask) << lowbit;
+ *(val.p64bit) = tmp;
+ break;
+ default:
+ BX_PANIC(("unsupported varsize %d", varsize));
+ }
+ if (handler) {
+ // the handler can override the new value and/or perform some side effect
+ (*handler)(this, 1, tmp);
+ }
+}
+
+bx_param_bool_c::bx_param_bool_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s initial_val)
+ : bx_param_num_c (id, name, description, 0, 1, initial_val)
+{
+ set_type (BXT_PARAM_BOOL);
+ set (initial_val);
+}
+
+bx_shadow_bool_c::bx_shadow_bool_c (bx_id id,
+ char *name,
+ char *description,
+ bx_bool *ptr_to_real_val,
+ Bit8u bitnum)
+ : bx_param_bool_c (id, name, description, (Bit64s) *ptr_to_real_val)
+{
+ val.pbool = ptr_to_real_val;
+ this->bitnum = bitnum;
+}
+
+Bit64s
+bx_shadow_bool_c::get64 () {
+ if (handler) {
+ // the handler can decide what value to return and/or do some side effect
+ Bit64s ret = (*handler)(this, 0, (Bit64s) *(val.pbool));
+ return (ret>>bitnum) & 1;
+ } else {
+ // just return the value
+ return (*(val.pbool)) & 1;
+ }
+}
+
+void
+bx_shadow_bool_c::set (Bit64s newval)
+{
+ // only change the bitnum bit
+ Bit64s tmp = (newval&1) << bitnum;
+ *(val.pbool) &= ~tmp;
+ *(val.pbool) |= tmp;
+ if (handler) {
+ // the handler can override the new value and/or perform some side effect
+ (*handler)(this, 1, newval&1);
+ }
+}
+
+bx_param_enum_c::bx_param_enum_c (bx_id id,
+ char *name,
+ char *description,
+ char **choices,
+ Bit64s initial_val,
+ Bit64s value_base)
+ : bx_param_num_c (id, name, description, value_base, BX_MAX_BIT64S, initial_val)
+{
+ set_type (BXT_PARAM_ENUM);
+ this->choices = choices;
+ // count number of choices, set max
+ char **p = choices;
+ while (*p != NULL) p++;
+ this->min = value_base;
+ // now that the max is known, replace the BX_MAX_BIT64S sent to the parent
+ // class constructor with the real max.
+ this->max = value_base + (p - choices - 1);
+ set (initial_val);
+}
+
+int
+bx_param_enum_c::find_by_name (const char *string)
+{
+ char **p;
+ for (p=&choices[0]; *p; p++) {
+ if (!strcmp (string, *p))
+ return p-choices;
+ }
+ return -1;
+}
+
+bool
+bx_param_enum_c::set_by_name (const char *string)
+{
+ int n = find_by_name (string);
+ if (n<0) return false;
+ set (n);
+ return true;
+}
+
+bx_param_string_c::bx_param_string_c (bx_id id,
+ char *name,
+ char *description,
+ char *initial_val,
+ int maxsize)
+ : bx_param_c (id, name, description)
+{
+ set_type (BXT_PARAM_STRING);
+ if (maxsize < 0)
+ maxsize = strlen(initial_val) + 1;
+ this->val = new char[maxsize];
+ this->initial_val = new char[maxsize];
+ this->handler = NULL;
+ this->enable_handler = NULL;
+ this->maxsize = maxsize;
+ strncpy (this->val, initial_val, maxsize);
+ strncpy (this->initial_val, initial_val, maxsize);
+ this->options = new bx_param_num_c (BXP_NULL,
+ "stringoptions", NULL, 0, BX_MAX_BIT64S, 0);
+ set (initial_val);
+}
+
+bx_param_filename_c::bx_param_filename_c (bx_id id,
+ char *name,
+ char *description,
+ char *initial_val,
+ int maxsize)
+ : bx_param_string_c (id, name, description, initial_val, maxsize)
+{
+ get_options()->set (IS_FILENAME);
+}
+
+bx_param_string_c::~bx_param_string_c ()
+{
+ if ( this->val != NULL )
+ {
+ delete [] this->val;
+ this->val = NULL;
+ }
+ if ( this->initial_val != NULL )
+ {
+ delete [] this->initial_val;
+ this->initial_val = NULL;
+ }
+
+ if ( this->options != NULL )
+ {
+ delete [] this->options;
+ this->options = NULL;
+ }
+}
+
+void
+bx_param_string_c::reset () {
+ strncpy (this->val, this->initial_val, maxsize);
+}
+
+void
+bx_param_string_c::set_handler (param_string_event_handler handler)
+{
+ this->handler = handler;
+ // now that there's a handler, call set once to run the handler immediately
+ //set (getptr ());
+}
+
+void
+bx_param_string_c::set_enable_handler (param_enable_handler handler)
+{
+ this->enable_handler = handler;
+}
+
+void
+bx_param_string_c::set_enabled (int en)
+{
+ // The enable handler may wish to allow/disallow the action
+ if (enable_handler) {
+ en = (*enable_handler) (this, en);
+ }
+ bx_param_c::set_enabled (en);
+}
+
+Bit32s
+bx_param_string_c::get (char *buf, int len)
+{
+ if (options->get () & RAW_BYTES)
+ memcpy (buf, val, len);
+ else
+ strncpy (buf, val, len);
+ if (handler) {
+ // the handler can choose to replace the value in val/len. Also its
+ // return value is passed back as the return value of get.
+ (*handler)(this, 0, buf, len);
+ }
+ return 0;
+}
+
+void
+bx_param_string_c::set (char *buf)
+{
+ if (options->get () & RAW_BYTES)
+ memcpy (val, buf, maxsize);
+ else
+ strncpy (val, buf, maxsize);
+ if (handler) {
+ // the handler can return a different char* to be copied into the value
+ buf = (*handler)(this, 1, buf, -1);
+ }
+}
+
+bx_bool
+bx_param_string_c::equals (const char *buf)
+{
+ if (options->get () & RAW_BYTES)
+ return (memcmp (val, buf, maxsize) == 0);
+ else
+ return (strncmp (val, buf, maxsize) == 0);
+}
+
+bx_list_c::bx_list_c (bx_id id, int maxsize)
+ : bx_param_c (id, "list", "")
+{
+ set_type (BXT_LIST);
+ this->size = 0;
+ this->maxsize = maxsize;
+ this->list = new bx_param_c* [maxsize];
+ init ();
+}
+
+bx_list_c::bx_list_c (bx_id id, char *name, char *description, int maxsize)
+ : bx_param_c (id, name, description)
+{
+ set_type (BXT_LIST);
+ this->size = 0;
+ this->maxsize = maxsize;
+ this->list = new bx_param_c* [maxsize];
+ init ();
+}
+
+bx_list_c::bx_list_c (bx_id id, char *name, char *description, bx_param_c **init_list)
+ : bx_param_c (id, name, description)
+{
+ set_type (BXT_LIST);
+ this->size = 0;
+ while (init_list[this->size] != NULL)
+ this->size++;
+ this->maxsize = this->size;
+ this->list = new bx_param_c* [maxsize];
+ for (int i=0; i<this->size; i++)
+ this->list[i] = init_list[i];
+ init ();
+}
+
+bx_list_c::~bx_list_c()
+{
+ if (this->list)
+ {
+ delete [] this->list;
+ this->list = NULL;
+ }
+ if ( this->title != NULL)
+ {
+ delete this->title;
+ this->title = NULL;
+ }
+ if (this->options != NULL)
+ {
+ delete this->options;
+ this->options = NULL;
+ }
+ if ( this->choice != NULL )
+ {
+ delete this->choice;
+ this->choice = NULL;
+ }
+}
+
+void
+bx_list_c::init ()
+{
+ // the title defaults to the name
+ this->title = new bx_param_string_c (BXP_NULL,
+ "title of list",
+ "",
+ get_name (), 80);
+ this->options = new bx_param_num_c (BXP_NULL,
+ "list_option", "", 0, BX_MAX_BIT64S,
+ 0);
+ this->choice = new bx_param_num_c (BXP_NULL,
+ "list_choice", "", 0, BX_MAX_BIT64S,
+ 1);
+ this->parent = NULL;
+}
+
+bx_list_c *
+bx_list_c::clone ()
+{
+ bx_list_c *newlist = new bx_list_c (BXP_NULL, name, description, maxsize);
+ for (int i=0; i<get_size (); i++)
+ newlist->add (get(i));
+ newlist->set_options (get_options ());
+ newlist->set_parent (get_parent ());
+ return newlist;
+}
+
+void
+bx_list_c::add (bx_param_c *param)
+{
+ if (this->size >= this->maxsize)
+ BX_PANIC (("add param %u to bx_list_c id=%u: list capacity exceeded", param->get_id (), get_id ()));
+ list[size] = param;
+ size++;
+}
+
+bx_param_c *
+bx_list_c::get (int index)
+{
+ BX_ASSERT (index >= 0 && index < size);
+ return list[index];
+}
+
diff --git a/tools/ioemu/gui/siminterface.h b/tools/ioemu/gui/siminterface.h
new file mode 100644
index 0000000000..9a028470c8
--- /dev/null
+++ b/tools/ioemu/gui/siminterface.h
@@ -0,0 +1,1460 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: siminterface.h,v 1.113.2.2 2004/02/06 22:14:35 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Before I can describe what this file is for, I have to make the
+// distinction between a configuration interface (CI) and the VGA display
+// window (VGAW). I will try to avoid the term 'GUI' because it is unclear
+// if that means CI or VGAW, and because not all interfaces are graphical
+// anyway.
+//
+// The traditional Bochs screen is a window with a large VGA display panel and
+// a series of buttons (floppy, cdrom, snapshot, power). Over the years, we
+// have collected many implementations of the VGAW for different environments
+// and platforms; each implementation is in a separate file under gui/*:
+// x.cc, win32.cc, beos.cc, macintosh.cc, etc. The files gui.h and gui.cc
+// define the platform independent part of the VGAW, leaving about 15 methods
+// of the bx_gui_c class undefined. The platform dependent file must
+// implement the remaining 15 methods.
+//
+// The configuration interface is relatively new, started by Bryce Denney in
+// June 2001. The CI is intended to allow the user to edit a variety of
+// configuration and runtime options. Some options, such as memory size or
+// enabling the ethernet card, should only be changed before the simulation
+// begins; others, such as floppy disk image, instructions per second, and
+// logging options can be safely changed at runtime. The CI allows the user to
+// make these changes. Before the CI existed, only a few things could be
+// changed at runtime, all linked to clicking on the VGAW buttons.
+//
+// At the time that the CI was conceived, we were still debating what form the
+// user interface part would take: stdin/stdout menus, a graphical application
+// with menus and dialogs running in a separate thread, or even a tiny web
+// server that you can connect to with a web browser. As a result the
+// interface to the CI was designed so that the user interface of the CI
+// could be replaced easily at compile time, or maybe even at runtime via
+// a plugin architecture. To this end, we kept a clear separation between
+// the user interface code and the siminterface, the code that interfaces with
+// the simulator. The same siminterface is used all the time, while
+// different implementations of the CI can be switched in reasonably easily.
+// Only the CI code uses library specific graphics and I/O functions; the
+// siminterface deals in portable abstractions and callback functions.
+// The first CI implementation was a series of text mode menus implemented in
+// control.cc.
+//
+// The configuration interface MUST use the siminterface methods to access the
+// simulator. It should not modify settings in some device with code like
+// bx_floppy.s.media[2].heads = 17. If such access is needed, then a
+// siminterface method should be written to make the change on the CI's behalf.
+// This separation is enforced by the fact that the CI does not even include
+// bochs.h. You'll notice that control.cc include osdep.h, control.h, and
+// siminterface.h, so it doesn't know what bx_floppy or bx_cpu_c are. I'm sure
+// some people will say is overly restrictive and/or annoying. When I set it
+// up this way, we were still talking about making the CI in a seperate
+// process, where direct method calls would be impossible. Also, we have been
+// considering turning devices into plugin modules which are dynamically
+// linked. Any direct references to something like bx_floppy.s.media[2].heads
+// would have to be reworked before a plugin interface was possible as well.
+//
+// The siminterface is the glue between the CI and the simulator. There is
+// just one global instance of the siminterface object, which can be referred
+// to by the global variable bx_simulator_interface_c *SIM; The base class
+// bx_simulator_interface_c, contains only virtual functions and it defines the
+// interface that the CI is allowed to use. In siminterface.cc, a class
+// called bx_real_sim_c is defined with bx_simulator_interface_c as its parent
+// class. Bx_real_sim_c implements each of the functions. The separation into
+// parent class and child class leaves the possibility of making a different
+// child class that talks to the simulator in a different way (networking for
+// example). If you were writing a user interface in a separate process, you
+// could define a subclass of bx_simulator_interface_c called
+// bx_siminterface_proxy_c which opens up a network port and turns all method
+// calls into network sends and receives. Because the interface is defined
+// entirely by the base class, the code that calls the methods would not know
+// the difference.
+//
+// An important part of the siminterface implementation is the use of parameter
+// classes, or bx_param_*. The parameter classes are described below, where
+// they are declared. Search for "parameter classes" below for detals.
+//
+// Also this header file declares data structures for certain events that pass
+// between the siminterface and the CI. Search for "event structures" below.
+
+
+
+//////////////////////////////////////////////////////
+// BX_UI_TEXT should be set to 1 when the text mode configuration interface
+// is compiled in. This gives each type of parameter a text_print and text_ask
+// method (defined in gui/control.cc) so that you can call text_ask() on any
+// kind of parameter to ask the user to edit the value.
+//
+// I have been considering whether to use the same strategy for the
+// wxWindows interface, but I'm not sure if I like it. One problem is
+// that in order to declare member functions that are useful for
+// wxWindows, the wxWindows header files would have to be included
+// before the param object definitions. That means that all the
+// wxwindows headers would have be included when compiling every
+// single bochs file. One of the things I like about the separation
+// between the simulator and CI is that the two parts can be
+// compiled without any knowledge of the other. Bochs doesn't include
+// <wx.h>, and the wxwindows CI (wxmain.cc) doesn't need to include <bochs.h>.
+// Aside from making compiles faster, this enforces the use of the siminterface
+// so it keeps the interface clean (important when we may have multiple UI
+// implementations for example). This argues for keeping UI-specific
+// structures out of the simulator interface. It certainly works ok for the
+// text interface, but that's because FILE* is standard and portable.
+#define BX_UI_TEXT 1
+
+//////////////////////////////////////////////////////
+
+// list of possible types for bx_param_c and descendant objects
+typedef enum {
+ BXT_OBJECT = 201,
+ BXT_PARAM,
+ BXT_PARAM_NUM,
+ BXT_PARAM_BOOL,
+ BXT_PARAM_ENUM,
+ BXT_PARAM_STRING,
+ BXT_LIST
+} bx_objtype;
+
+// list if parameter id values. The actual values are not important;
+// it's only important that they all be different from each other.
+typedef enum {
+ BXP_NULL = 301,
+ BXP_IPS,
+ BXP_REALTIME_PIT,
+ BXP_TEXT_SNAPSHOT_CHECK,
+ BXP_VGA_UPDATE_INTERVAL,
+ BXP_MOUSE_ENABLED,
+ BXP_MEM_SIZE,
+ BXP_ROM_PATH,
+ BXP_ROM_ADDRESS,
+ BXP_VGA_ROM_PATH,
+ BXP_OPTROM1_PATH,
+ BXP_OPTROM2_PATH,
+ BXP_OPTROM3_PATH,
+ BXP_OPTROM4_PATH,
+ BXP_OPTROM1_ADDRESS,
+ BXP_OPTROM2_ADDRESS,
+ BXP_OPTROM3_ADDRESS,
+ BXP_OPTROM4_ADDRESS,
+ BXP_KBD_SERIAL_DELAY,
+ BXP_KBD_PASTE_DELAY,
+ BXP_KBD_TYPE,
+ BXP_FLOPPY_CMD_DELAY,
+ BXP_FLOPPYA_DEVTYPE,
+ BXP_FLOPPYA_PATH,
+ BXP_FLOPPYA_TYPE,
+ BXP_FLOPPYA_STATUS,
+ BXP_FLOPPYA,
+ BXP_FLOPPYB_DEVTYPE,
+ BXP_FLOPPYB_PATH,
+ BXP_FLOPPYB_TYPE,
+ BXP_FLOPPYB_STATUS,
+ BXP_FLOPPYB,
+
+ BXP_ATA0_MENU,
+ BXP_ATA1_MENU,
+ BXP_ATA2_MENU,
+ BXP_ATA3_MENU,
+#define BXP_ATAx_MENU(i) (BXP_ATA0_MENU + (i))
+ BXP_ATA0,
+ BXP_ATA1,
+ BXP_ATA2,
+ BXP_ATA3,
+#define BXP_ATAx(i) (BXP_ATA0 + (i))
+ BXP_ATA0_PRESENT,
+ BXP_ATA1_PRESENT,
+ BXP_ATA2_PRESENT,
+ BXP_ATA3_PRESENT,
+#define BXP_ATAx_PRESENT(i) (BXP_ATA0_PRESENT + (i))
+ BXP_ATA0_IOADDR1,
+ BXP_ATA1_IOADDR1,
+ BXP_ATA2_IOADDR1,
+ BXP_ATA3_IOADDR1,
+#define BXP_ATAx_IOADDR1(i) (BXP_ATA0_IOADDR1 + (i))
+ BXP_ATA0_IOADDR2,
+ BXP_ATA1_IOADDR2,
+ BXP_ATA2_IOADDR2,
+ BXP_ATA3_IOADDR2,
+#define BXP_ATAx_IOADDR2(i) (BXP_ATA0_IOADDR2 + (i))
+ BXP_ATA0_IRQ,
+ BXP_ATA1_IRQ,
+ BXP_ATA2_IRQ,
+ BXP_ATA3_IRQ,
+#define BXP_ATAx_IRQ(i) (BXP_ATA0_IRQ + (i))
+
+ BXP_ATA0_MASTER,
+ BXP_ATA0_SLAVE,
+ BXP_ATA1_MASTER,
+ BXP_ATA1_SLAVE,
+ BXP_ATA2_MASTER,
+ BXP_ATA2_SLAVE,
+ BXP_ATA3_MASTER,
+ BXP_ATA3_SLAVE,
+#define BXP_ATAx_DEVICE(i, s) (BXP_ATA0_MASTER + (2*(i)) + (s))
+
+#define BXP_PARAMS_PER_ATA_DEVICE 12
+
+ BXP_ATA0_MASTER_PRESENT,
+ BXP_ATA0_SLAVE_PRESENT,
+ BXP_ATA1_MASTER_PRESENT,
+ BXP_ATA1_SLAVE_PRESENT,
+ BXP_ATA2_MASTER_PRESENT,
+ BXP_ATA2_SLAVE_PRESENT,
+ BXP_ATA3_MASTER_PRESENT,
+ BXP_ATA3_SLAVE_PRESENT,
+#define BXP_ATAx_DEVICE_PRESENT(i, s) (BXP_ATA0_MASTER_PRESENT + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_TYPE,
+ BXP_ATA0_SLAVE_TYPE,
+ BXP_ATA1_MASTER_TYPE,
+ BXP_ATA1_SLAVE_TYPE,
+ BXP_ATA2_MASTER_TYPE,
+ BXP_ATA2_SLAVE_TYPE,
+ BXP_ATA3_MASTER_TYPE,
+ BXP_ATA3_SLAVE_TYPE,
+#define BXP_ATAx_DEVICE_TYPE(i, s) (BXP_ATA0_MASTER_TYPE + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_MODE,
+ BXP_ATA0_SLAVE_MODE,
+ BXP_ATA1_MASTER_MODE,
+ BXP_ATA1_SLAVE_MODE,
+ BXP_ATA2_MASTER_MODE,
+ BXP_ATA2_SLAVE_MODE,
+ BXP_ATA3_MASTER_MODE,
+ BXP_ATA3_SLAVE_MODE,
+#define BXP_ATAx_DEVICE_MODE(i, s) (BXP_ATA0_MASTER_MODE + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_PATH,
+ BXP_ATA0_SLAVE_PATH,
+ BXP_ATA1_MASTER_PATH,
+ BXP_ATA1_SLAVE_PATH,
+ BXP_ATA2_MASTER_PATH,
+ BXP_ATA2_SLAVE_PATH,
+ BXP_ATA3_MASTER_PATH,
+ BXP_ATA3_SLAVE_PATH,
+#define BXP_ATAx_DEVICE_PATH(i, s) (BXP_ATA0_MASTER_PATH + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_CYLINDERS,
+ BXP_ATA0_SLAVE_CYLINDERS,
+ BXP_ATA1_MASTER_CYLINDERS,
+ BXP_ATA1_SLAVE_CYLINDERS,
+ BXP_ATA2_MASTER_CYLINDERS,
+ BXP_ATA2_SLAVE_CYLINDERS,
+ BXP_ATA3_MASTER_CYLINDERS,
+ BXP_ATA3_SLAVE_CYLINDERS,
+#define BXP_ATAx_DEVICE_CYLINDERS(i, s) (BXP_ATA0_MASTER_CYLINDERS + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_HEADS,
+ BXP_ATA0_SLAVE_HEADS,
+ BXP_ATA1_MASTER_HEADS,
+ BXP_ATA1_SLAVE_HEADS,
+ BXP_ATA2_MASTER_HEADS,
+ BXP_ATA2_SLAVE_HEADS,
+ BXP_ATA3_MASTER_HEADS,
+ BXP_ATA3_SLAVE_HEADS,
+#define BXP_ATAx_DEVICE_HEADS(i, s) (BXP_ATA0_MASTER_HEADS + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_SPT,
+ BXP_ATA0_SLAVE_SPT,
+ BXP_ATA1_MASTER_SPT,
+ BXP_ATA1_SLAVE_SPT,
+ BXP_ATA2_MASTER_SPT,
+ BXP_ATA2_SLAVE_SPT,
+ BXP_ATA3_MASTER_SPT,
+ BXP_ATA3_SLAVE_SPT,
+#define BXP_ATAx_DEVICE_SPT(i, s) (BXP_ATA0_MASTER_SPT + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_STATUS,
+ BXP_ATA0_SLAVE_STATUS,
+ BXP_ATA1_MASTER_STATUS,
+ BXP_ATA1_SLAVE_STATUS,
+ BXP_ATA2_MASTER_STATUS,
+ BXP_ATA2_SLAVE_STATUS,
+ BXP_ATA3_MASTER_STATUS,
+ BXP_ATA3_SLAVE_STATUS,
+#define BXP_ATAx_DEVICE_STATUS(i, s) (BXP_ATA0_MASTER_STATUS + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_MODEL,
+ BXP_ATA0_SLAVE_MODEL,
+ BXP_ATA1_MASTER_MODEL,
+ BXP_ATA1_SLAVE_MODEL,
+ BXP_ATA2_MASTER_MODEL,
+ BXP_ATA2_SLAVE_MODEL,
+ BXP_ATA3_MASTER_MODEL,
+ BXP_ATA3_SLAVE_MODEL,
+#define BXP_ATAx_DEVICE_MODEL(i, s) (BXP_ATA0_MASTER_MODEL + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_BIOSDETECT,
+ BXP_ATA0_SLAVE_BIOSDETECT,
+ BXP_ATA1_MASTER_BIOSDETECT,
+ BXP_ATA1_SLAVE_BIOSDETECT,
+ BXP_ATA2_MASTER_BIOSDETECT,
+ BXP_ATA2_SLAVE_BIOSDETECT,
+ BXP_ATA3_MASTER_BIOSDETECT,
+ BXP_ATA3_SLAVE_BIOSDETECT,
+#define BXP_ATAx_DEVICE_BIOSDETECT(i, s) (BXP_ATA0_MASTER_BIOSDETECT + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_TRANSLATION,
+ BXP_ATA0_SLAVE_TRANSLATION,
+ BXP_ATA1_MASTER_TRANSLATION,
+ BXP_ATA1_SLAVE_TRANSLATION,
+ BXP_ATA2_MASTER_TRANSLATION,
+ BXP_ATA2_SLAVE_TRANSLATION,
+ BXP_ATA3_MASTER_TRANSLATION,
+ BXP_ATA3_SLAVE_TRANSLATION,
+#define BXP_ATAx_DEVICE_TRANSLATION(i, s) (BXP_ATA0_MASTER_TRANSLATION + (2*(i)) + (s))
+
+ BXP_ATA0_MASTER_JOURNAL,
+ BXP_ATA0_SLAVE_JOURNAL,
+ BXP_ATA1_MASTER_JOURNAL,
+ BXP_ATA1_SLAVE_JOURNAL,
+ BXP_ATA2_MASTER_JOURNAL,
+ BXP_ATA2_SLAVE_JOURNAL,
+ BXP_ATA3_MASTER_JOURNAL,
+ BXP_ATA3_SLAVE_JOURNAL,
+#define BXP_ATAx_DEVICE_JOURNAL(i, s) (BXP_ATA0_MASTER_JOURNAL + (2*(i)) + (s))
+
+#define BXP_PARAMS_PER_SERIAL_PORT 2
+ BXP_COM1_ENABLED,
+ BXP_COM1_PATH,
+ BXP_COM2_ENABLED,
+ BXP_COM2_PATH,
+ BXP_COM3_ENABLED,
+ BXP_COM3_PATH,
+ BXP_COM4_ENABLED,
+ BXP_COM4_PATH,
+#define BXP_PARAMS_PER_USB_HUB 3
+ BXP_USB1_ENABLED,
+ BXP_USB1_IOADDR,
+ BXP_USB1_IRQ,
+ BXP_PRIVATE_COLORMAP,
+ BXP_FULLSCREEN,
+ BXP_SCREENMODE,
+ BXP_I440FX_SUPPORT,
+ BXP_NEWHARDDRIVESUPPORT,
+ BXP_LOG_FILENAME,
+ BXP_LOG_PREFIX,
+ BXP_DEBUGGER_LOG_FILENAME,
+ BXP_CMOS_PATH,
+ BXP_CMOS_IMAGE,
+ BXP_CLOCK,
+ BXP_CLOCK_TIME0,
+ BXP_CLOCK_SYNC,
+ BXP_LOAD32BITOS_WHICH,
+ BXP_LOAD32BITOS_PATH,
+ BXP_LOAD32BITOS_IOLOG,
+ BXP_LOAD32BITOS_INITRD,
+ BXP_LOAD32BITOS,
+ BXP_BOOTDRIVE,
+ BXP_FLOPPYSIGCHECK,
+ BXP_MENU_MAIN,
+ BXP_MENU_MEMORY,
+ BXP_MENU_INTERFACE,
+ BXP_MENU_DISK,
+ BXP_MENU_SERIAL_PARALLEL,
+ BXP_MENU_SOUND,
+ BXP_MENU_KEYBOARD,
+ BXP_MENU_MISC,
+ BXP_MENU_MISC_2,
+ BXP_MENU_RUNTIME,
+ BXP_MAX_IPS,
+ BXP_NE2K_PRESENT,
+ BXP_NE2K_IOADDR,
+ BXP_NE2K_IRQ,
+ BXP_NE2K_MACADDR,
+ BXP_NE2K_ETHMOD,
+ BXP_NE2K_ETHDEV,
+ BXP_NE2K_SCRIPT,
+ BXP_NE2K,
+ BXP_SB16_PRESENT,
+ BXP_SB16_MIDIFILE,
+ BXP_SB16_WAVEFILE,
+ BXP_SB16_LOGFILE,
+ BXP_SB16_MIDIMODE,
+ BXP_SB16_WAVEMODE,
+ BXP_SB16_LOGLEVEL,
+ BXP_SB16_DMATIMER,
+ BXP_SB16,
+#define BXP_PARAMS_PER_PARALLEL_PORT 2
+ BXP_PARPORT1_ENABLED,
+ BXP_PARPORT1_OUTFILE,
+ BXP_PARPORT2_ENABLED,
+ BXP_PARPORT2_OUTFILE,
+ BXP_KEYBOARD_USEMAPPING,
+ BXP_KEYBOARD_MAP,
+ BXP_KEYBOARD,
+ BXP_USER_SHORTCUT,
+ BXP_ASK_FOR_PATHNAME, // for general file selection dialog
+ BXP_BOCHS_START, // How Bochs starts
+ // experiment: add params for CPU registers
+ BXP_CPU_PARAMETERS,
+ BXP_CPU_EAX,
+ BXP_CPU_EBX,
+ BXP_CPU_ECX,
+ BXP_CPU_EDX,
+ BXP_CPU_EBP,
+ BXP_CPU_ESI,
+ BXP_CPU_EDI,
+ BXP_CPU_ESP,
+ BXP_CPU_EIP,
+ BXP_CPU_SEG_CS,
+ BXP_CPU_SEG_DS,
+ BXP_CPU_SEG_SS,
+ BXP_CPU_SEG_ES,
+ BXP_CPU_SEG_FS,
+ BXP_CPU_SEG_GS,
+ BXP_CPU_SEG_LDTR,
+ BXP_CPU_SEG_TR,
+ BXP_CPU_GDTR_BASE,
+ BXP_CPU_GDTR_LIMIT,
+ BXP_CPU_IDTR_BASE,
+ BXP_CPU_IDTR_LIMIT,
+ BXP_CPU_EFLAGS,
+ BXP_CPU_EFLAGS_ID,
+ BXP_CPU_EFLAGS_VIP,
+ BXP_CPU_EFLAGS_VIF,
+ BXP_CPU_EFLAGS_AC,
+ BXP_CPU_EFLAGS_VM,
+ BXP_CPU_EFLAGS_RF,
+ BXP_CPU_EFLAGS_NT,
+ BXP_CPU_EFLAGS_IOPL,
+ BXP_CPU_EFLAGS_OF,
+ BXP_CPU_EFLAGS_DF,
+ BXP_CPU_EFLAGS_IF,
+ BXP_CPU_EFLAGS_TF,
+ BXP_CPU_EFLAGS_SF,
+ BXP_CPU_EFLAGS_ZF,
+ BXP_CPU_EFLAGS_AF,
+ BXP_CPU_EFLAGS_PF,
+ BXP_CPU_EFLAGS_CF,
+ BXP_CPU_DR0,
+ BXP_CPU_DR1,
+ BXP_CPU_DR2,
+ BXP_CPU_DR3,
+ BXP_CPU_DR6,
+ BXP_CPU_DR7,
+ BXP_CPU_TR3,
+ BXP_CPU_TR4,
+ BXP_CPU_TR5,
+ BXP_CPU_TR6,
+ BXP_CPU_TR7,
+ BXP_CPU_CR0,
+ BXP_CPU_CR1,
+ BXP_CPU_CR2,
+ BXP_CPU_CR3,
+ BXP_CPU_CR4,
+ // a few parameters for the keyboard
+ BXP_KBD_PARAMETERS,
+ BXP_KBD_PARE,
+ BXP_KBD_TIM ,
+ BXP_KBD_AUXB,
+ BXP_KBD_KEYL,
+ BXP_KBD_C_D,
+ BXP_KBD_SYSF,
+ BXP_KBD_INPB,
+ BXP_KBD_OUTB,
+ BXP_KBD_TIMER_PENDING,
+ BXP_KBD_IRQ1_REQ,
+ BXP_KBD_IRQ12_REQ,
+#if BX_DEBUGGER
+ // in debugger, is the simulation running (continue command) or waiting.
+ // This is only modified by debugger code, not by the user.
+ BXP_DEBUG_RUNNING,
+#endif
+ BXP_SEL_CONFIG_INTERFACE,
+ BXP_SEL_DISPLAY_LIBRARY,
+ BXP_THIS_IS_THE_LAST // used to determine length of list
+} bx_id;
+
+// use x=1,2,3,4
+#define BXP_COMx_ENABLED(x) \
+ (bx_id)(BXP_COM1_ENABLED + (((x)-1)*BXP_PARAMS_PER_SERIAL_PORT))
+#define BXP_COMx_PATH(x) \
+ (bx_id)(BXP_COM1_PATH + (((x)-1)*BXP_PARAMS_PER_SERIAL_PORT))
+
+// use x=1
+#define BXP_USBx_ENABLED(x) \
+ (bx_id)(BXP_USB1_ENABLED + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+#define BXP_USBx_IOADDR(x) \
+ (bx_id)(BXP_USB1_IOADDR + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+#define BXP_USBx_IRQ(x) \
+ (bx_id)(BXP_USB1_IRQ + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+
+// use x=1,2
+#define BXP_PARPORTx_ENABLED(x) \
+ (bx_id)(BXP_PARPORT1_ENABLED + (((x)-1)*BXP_PARAMS_PER_PARALLEL_PORT))
+#define BXP_PARPORTx_OUTFILE(x) \
+ (bx_id)(BXP_PARPORT1_OUTFILE + (((x)-1)*BXP_PARAMS_PER_PARALLEL_PORT))
+
+typedef enum {
+ BX_TOOLBAR_UNDEFINED,
+ BX_TOOLBAR_FLOPPYA,
+ BX_TOOLBAR_FLOPPYB,
+ BX_TOOLBAR_CDROMD,
+ BX_TOOLBAR_RESET,
+ BX_TOOLBAR_POWER,
+ BX_TOOLBAR_COPY,
+ BX_TOOLBAR_PASTE,
+ BX_TOOLBAR_SNAPSHOT,
+ BX_TOOLBAR_CONFIG,
+ BX_TOOLBAR_MOUSE_EN,
+ BX_TOOLBAR_USER
+} bx_toolbar_buttons;
+
+// Log level defines
+typedef enum {
+ LOGLEV_DEBUG = 0,
+ LOGLEV_INFO,
+ LOGLEV_ERROR,
+ LOGLEV_PANIC,
+ LOGLEV_PASS,
+ N_LOGLEV
+} bx_log_levels;
+
+// types of reset
+#define BX_RESET_SOFTWARE 10
+#define BX_RESET_HARDWARE 11
+
+//cdrom
+#define BX_EJECTED 10
+#define BX_INSERTED 11
+
+// boot devices
+#define BX_BOOT_FLOPPYA 0
+#define BX_BOOT_DISKC 1
+#define BX_BOOT_CDROM 2
+
+// loader hack
+#define Load32bitOSNone 0
+#define Load32bitOSLinux 1
+#define Load32bitOSNullKernel 2 // being developed for plex86
+#define Load32bitOSLast 2
+
+///////////////////////////////////////////////////////////////////
+// event structures for communication between simulator and CI
+///////////////////////////////////////////////////////////////////
+// Because the CI (configuration interface) might be in a different
+// thread or even a different process, we pass events encoded in data
+// structures to it instead of just calling functions. Each type of
+// event is declared as a different structure, and then all those
+// structures are squished into a union in BxEvent. (BTW, this is
+// almost exactly how X windows event structs work.)
+//
+// These are simple structs, unblemished by C++ methods and tricks.
+// No matter what event type it is, we allocate a BxEvent for each
+// one, as opposed to trying to save a few bytes on small events by
+// allocating only the bytes necessary for it. This makes it easy and
+// fast to store events in a queue, like this
+// BxEvent event_queue[MAX_EVENTS];
+//
+// Events come in two varieties: synchronous and asynchronous. We
+// have to worry about sync and async events because the CI and the
+// simulation may be running in different threads. An async event is
+// the simplest. Whichever thread originates the event just builds
+// the data structure, sends it, and then continues with its business.
+// Async events can go in either direction. Synchronous events
+// require the other thread to "respond" before the originating thread
+// can continue. It's like a function with a return value; you can't
+// continue until you get the return value back.
+//
+// Examples:
+//
+// async event: In the wxWindows implementation, both the CI and the
+// VGAW operate in the wxWindows GUI thread. When the user presses a
+// key, wxWindows sends a wxKeyEvent to the VGAW event handler code in
+// wx.cc. The VGAW handler then builds a BxEvent with
+// type=BX_ASYNC_EVT_KEY, and fills in the bx_key and raw_scancode
+// fields. The asynchronous event is placed on the event_queue for
+// the simulator, then the VGAW handler returns. (With wxWindows and
+// many other graphical libaries, the event handler must return
+// quickly because the window will not be updated until it's done.)
+// Some time later, the simulator reaches the point where it checks
+// for new events from the user (actually controlled by
+// bx_keyb_c::periodic() in iodev/keyboard.cc) and calls
+// bx_gui.handle_events(). Then all the events in the queue are
+// processed by the simulator. There is no "response" sent back to
+// the originating thread.
+//
+// sync event: Sometimes the simulator reaches a point where it needs
+// to ask the user how to proceed. In this case, the simulator sends
+// a synchronous event because it requires a response before it can
+// continue. It builds an event structure, perhaps with type
+// BX_SYNC_EVT_ASK_PARAM, sends it to the user interface
+// using the event handler function defined by set_notify_callback(),
+// and pauses the simulation. The user interface asks the user the
+// question, and puts the answer into the BxEvent.retcode field. The
+// event handler function returns the modified BxEvent with retcode
+// filled in, and the simulation continues. The details of this
+// transaction can be complicated if the simulation and CI are not
+// in the same thread, but the behavior is as described.
+//
+
+///// types and definitions used in event structures
+
+#define BX_EVT_IS_ASYNC(type) ((type) > __ALL_EVENTS_BELOW_ARE_ASYNC__)
+
+typedef enum {
+ __ALL_EVENTS_BELOW_ARE_SYNCHRONOUS__ = 2000,
+ BX_SYNC_EVT_GET_PARAM, // CI -> simulator -> CI
+ BX_SYNC_EVT_ASK_PARAM, // simulator -> CI -> simulator
+ BX_SYNC_EVT_TICK, // simulator -> CI, wait for response.
+ BX_SYNC_EVT_LOG_ASK, // simulator -> CI, wait for response.
+ BX_SYNC_EVT_GET_DBG_COMMAND, // simulator -> CI, wait for response.
+ __ALL_EVENTS_BELOW_ARE_ASYNC__,
+ BX_ASYNC_EVT_KEY, // vga window -> simulator
+ BX_ASYNC_EVT_MOUSE, // vga window -> simulator
+ BX_ASYNC_EVT_SET_PARAM, // CI -> simulator
+ BX_ASYNC_EVT_LOG_MSG, // simulator -> CI
+ BX_ASYNC_EVT_DBG_MSG, // simulator -> CI
+ BX_ASYNC_EVT_VALUE_CHANGED, // simulator -> CI
+ BX_ASYNC_EVT_TOOLBAR, // CI -> simulator
+ BX_ASYNC_EVT_REFRESH // simulator -> CI
+} BxEventType;
+
+typedef union {
+ Bit32s s32;
+ char *charptr;
+} AnyParamVal;
+
+// Define substructures which make up the interior of BxEvent. The
+// substructures, such as BxKeyEvent or BxMouseEvent, should never be
+// allocated on their own. They are only intended to be used within
+// the union in the BxEvent structure.
+
+// Event type: BX_SYNC_EVT_TICK
+//
+// A tick event is synchronous, sent from the simulator to the GUI. The
+// event doesn't do anything visible. Primarily it gives the GUI a chance
+// to tell the simulator to quit, if necessary. There may be other uses
+// for the tick in the future, such as giving some kind of regular
+// status report or mentioning watched values that changed, but so far
+// it's just for that one thing. There is no data associated with a
+// tick event.
+
+// Event type: BX_ASYNC_EVT_KEY
+//
+// A key event can be sent from the VGA window to the Bochs simulator.
+// It is asynchronous.
+typedef struct {
+ // what was pressed? This is a BX_KEY_* value. For key releases,
+ // BX_KEY_RELEASED is ORed with the base BX_KEY_*.
+ Bit32u bx_key;
+ bx_bool raw_scancode;
+} BxKeyEvent;
+
+// Event type: BX_ASYNC_EVT_MOUSE
+//
+// A mouse event can be sent from the VGA window to the Bochs
+// simulator. It is asynchronous. Currently unused because mouse
+// events aren't implemented in our wxWindows code yet.
+typedef struct {
+ // type is BX_EVT_MOUSE
+ Bit16s dx, dy; // mouse motion delta
+ Bit8u buttons; // which buttons are pressed.
+ // bit 0: 1=left button down, 0=up
+ // bit 1: 1=right button down, 0=up
+} BxMouseEvent;
+
+// Event type: BX_SYNC_EVT_GET_PARAM, BX_ASYNC_EVT_SET_PARAM
+//
+// Parameter set/get events are initiated by the CI, since Bochs can
+// always access the parameters directly. So far, I haven't used
+// these event types. In the CI I just call
+// SIM->get_param(parameter_id) to get a pointer to the bx_param_c
+// object and then call the get/set methods. This is okay for
+// configuration since bochs is not running. However it could be
+// dangerous for the GUI thread to poke around in Bochs structures
+// while the thread is running. For these cases, I may have to be
+// more careful and actually build get/set events and place them on
+// Bochs's event queue to be processed during SIM->periodic() or
+// something.
+typedef struct {
+ // type is BX_EVT_GET_PARAM, BX_EVT_SET_PARAM
+ class bx_param_c *param; // pointer to param structure
+ AnyParamVal val;
+} BxParamEvent;
+
+// Event type: BX_SYNC_EVT_ASK_PARAM
+// Synchronous event sent from the simulator to the CI. This tells the
+// CI to ask the user to choose the value of a parameter. The CI may
+// need to discover the type of parameter so that it can use the right
+// kind of graphical display. The BxParamEvent is used for these events
+// too.
+// FIXME: at the moment the GUI implements the ASK_PARAM event for just
+// a few parameter types. I need to implement the event for all parameter
+// types.
+
+// Event type: BX_ASYNC_EVT_VALUE_CHANGED
+//
+// Asynchronous event sent from the simulator to the CI, telling it that
+// some value that it (hopefully) cares about has changed. This isn't
+// being used yet, but a good example is in a debugger interface, you might
+// want to maintain a reasonably current display of the PC or some other
+// simulation state. The CI would set some kind of event mask (which
+// doesn't exist now of course) and then when certain values change, the
+// simulator would send this event so that the CI can update. We may need
+// some kind of "flow control" since the simulator will be able to produce
+// new events much faster than the gui can accept them.
+
+// Event type: BX_ASYNC_EVT_LOG_MSG (unused)
+//
+// Asynchronous event from the simulator to the CI. When a BX_PANIC,
+// BX_ERROR, BX_INFO, or BX_DEBUG is found in the simulator code, this
+// event type can be used to inform the CI of the condition. There is
+// no point in sending messages to the CI that will not be displayed; these
+// would only slow the simulation. So we will need some mechanism for
+// choosing what kinds of events will be delivered to the CI. Normally,
+// you wouldn't want to look at the log unless something is going wrong.
+// At that point, you might want to open up a window to watch the debug
+// messages from one or two devices only.
+//
+// Idea: Except for panics that require user attention to continue, it
+// might be most efficient to just append log messages to a file.
+// When the user wants to look at the log messages, the gui can reopen
+// the file (read only), skip to the end, and look backward for a
+// reasonable number of lines to display (200?). This allows it to
+// skip over huge bursts of log entries without allocating memory,
+// synchronizing threads, etc. for each.
+typedef struct {
+ Bit8u level;
+ const char *prefix;
+ const char *msg;
+} BxLogMsgEvent;
+
+// Event type: BX_ASYNC_EVT_DBG_MSG (unused)
+//
+// Also uses BxLogMsgEvent, but this is a message to be displayed in
+// the debugger history window.
+
+// Event type: BX_SYNC_EVT_LOG_ASK
+//
+// This is a synchronous version of BX_ASYNC_EVT_LOG_MSG, which is used
+// when the "action=ask" setting is used. If the simulator runs into a
+// panic, it sends a synchronous BX_SYNC_EVT_LOG_ASK to the CI to be
+// displayed. The CI shows a dialog that asks if the user wants to
+// continue, quit, etc. and sends the answer back to the simulator.
+// This event also uses BxLogMsgEvent.
+enum {
+ BX_LOG_ASK_CHOICE_CONTINUE,
+ BX_LOG_ASK_CHOICE_CONTINUE_ALWAYS,
+ BX_LOG_ASK_CHOICE_DIE,
+ BX_LOG_ASK_CHOICE_DUMP_CORE,
+ BX_LOG_ASK_CHOICE_ENTER_DEBUG,
+ BX_LOG_ASK_N_CHOICES
+};
+
+// Event type: BX_SYNC_EVT_GET_DBG_COMMAND
+//
+// This is a synchronous event sent from the simulator to the debugger
+// requesting the next action. In a text mode debugger, this would prompt
+// the user for the next command. When a new command is ready, the
+// synchronous event is sent back with its fields filled in.
+typedef struct {
+ char *command; // null terminated string. allocated by debugger interface
+ // with new operator, freed by simulator with delete.
+} BxDebugCommand;
+
+
+
+// Event type: BX_EVT_TOOLBAR
+// Asynchronous event from the VGAW to the simulator, sent when the user
+// clicks on a toolbar button. This may one day become something more
+// general, like a command event, but at the moment it's only needed for
+// the toolbar events.
+typedef struct {
+ bx_toolbar_buttons button;
+ bool on; // for toggling buttons, on=true means the toolbar button is
+ // pressed. on=false means it is not pressed.
+} BxToolbarEvent;
+
+// The BxEvent structure should be used for all events. Every event has
+// a type and a spot for a return code (only used for synchronous events).
+typedef struct {
+ BxEventType type; // what kind is this?
+ Bit32s retcode; // sucess or failure. only used for synchronous events.
+ union {
+ BxKeyEvent key;
+ BxMouseEvent mouse;
+ BxParamEvent param;
+ BxLogMsgEvent logmsg;
+ BxToolbarEvent toolbar;
+ BxDebugCommand debugcmd;
+ } u;
+} BxEvent;
+
+
+////////////////////////////////////////////////////////////////////
+// parameter classes: bx_param_c and family
+////////////////////////////////////////////////////////////////////
+//
+// All variables that can be configured through the CI are declared as
+// "parameters" or objects of type bx_param_*. There is a bx_param_*
+// class for each type of data that the user would need to see and
+// edit, e.g. integer, boolean, enum, string, filename, or list of
+// other parameters. The purpose of the bx_param_* class, in addition
+// to storing the parameter's value, is to hold the name, description,
+// and constraints on the value. The bx_param_* class should hold
+// everything that the CI would need to display the value and allow
+// the user to modify it. For integer parameters, the minimum and
+// maximum allowed value can be defined, and the base in which it
+// should be displayed and interpreted. For enums, the
+// bx_param_enum_c structure includes the list of values which the
+// parameter can have.
+//
+// Also, some parameter classes support get/set callback functions to
+// allow arbitrary code to be executed when the parameter is get/set.
+// An example of where this is useful: if you disable the NE2K card,
+// the set() handler for that parameter can tell the user interface
+// that the NE2K's irq, I/O address, and mac address should be
+// disabled (greyed out, hidden, or made inaccessible). The get/set
+// methods can also check if the set() value is acceptable using
+// whatever means and override it.
+//
+// The parameter concept is similar to the use of parameters in JavaBeans.
+
+class bx_object_c;
+class bx_param_c;
+class bx_param_num_c;
+class bx_param_enum_c;
+class bx_param_bool_c;
+class bx_param_string_c;
+class bx_param_filename_c;
+class bx_list_c;
+
+class BOCHSAPI bx_object_c {
+private:
+ bx_id id;
+ bx_objtype type;
+protected:
+ void set_type (bx_objtype type);
+public:
+ bx_object_c (bx_id id);
+ bx_id get_id () { return id; }
+ Bit8u get_type () { return type; }
+};
+
+class BOCHSAPI bx_param_c : public bx_object_c {
+ BOCHSAPI_CYGONLY static const char *default_text_format;
+protected:
+ char *name;
+ char *description;
+ char *label; // label string for text menus and gui dialogs
+ const char *text_format; // printf format string. %d for ints, %s for strings, etc.
+ char *ask_format; // format string for asking for a new value
+ int runtime_param;
+ int enabled;
+public:
+ bx_param_c (bx_id id, char *name, char *description);
+ void set_format (const char *format) {text_format = format;}
+ const char *get_format () {return text_format;}
+ void set_ask_format (char *format) {ask_format = format; }
+ char *get_ask_format () {return ask_format;}
+ void set_label (char *text) {label = text;}
+ char *get_label () {return label;}
+ void set_runtime_param (int val) { runtime_param = val; }
+ int get_runtime_param () { return runtime_param; }
+ char *get_name () { return name; }
+ char *get_description () { return description; }
+ int get_enabled () { return enabled; }
+ virtual void set_enabled (int enabled) { this->enabled = enabled; }
+ void reset () {}
+ int getint () {return -1;}
+ static const char* set_default_format (const char *f);
+ static const char *get_default_format () { return default_text_format; }
+ virtual bx_list_c *get_dependent_list () { return NULL; }
+#if BX_UI_TEXT
+ virtual void text_print (FILE *fp) {}
+ virtual int text_ask (FILE *fpin, FILE *fpout) {return -1;}
+#endif
+};
+
+typedef Bit64s (*param_event_handler)(class bx_param_c *, int set, Bit64s val);
+typedef int (*param_enable_handler)(class bx_param_c *, int en);
+
+class BOCHSAPI bx_param_num_c : public bx_param_c {
+ BOCHSAPI_CYGONLY static Bit32u default_base;
+ // The dependent_list is initialized to NULL. If dependent_list is modified
+ // to point to a bx_list_c of other parameters, the set() method of
+ // bx_param_bool_c will enable those parameters when this bool is true, and
+ // disable them when this bool is false.
+ bx_list_c *dependent_list;
+ void update_dependents ();
+protected:
+ Bit64s min, max, initial_val;
+ union _uval_ {
+ Bit64s number; // used by bx_param_num_c
+ Bit64s *p64bit; // used by bx_shadow_num_c
+ Bit32s *p32bit; // used by bx_shadow_num_c
+ Bit16s *p16bit; // used by bx_shadow_num_c
+ Bit8s *p8bit; // used by bx_shadow_num_c
+ bx_bool *pbool; // used by bx_shadow_bool_c
+ } val;
+ param_event_handler handler;
+ param_enable_handler enable_handler;
+ int base;
+ Bit32u options;
+public:
+ enum {
+ // When a bx_param_num_c is displayed in dialog, USE_SPIN_CONTROL controls
+ // whether a spin control should be used instead of a simple text control.
+ USE_SPIN_CONTROL = (1<<0)
+ } bx_numopt_bits;
+ bx_param_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s min, Bit64s max, Bit64s initial_val);
+ void reset ();
+ void set_handler (param_event_handler handler);
+ void set_enable_handler (param_enable_handler handler);
+ virtual bx_list_c *get_dependent_list () { return dependent_list; }
+ void set_dependent_list (bx_list_c *l);
+ virtual void set_enabled (int enabled);
+ virtual Bit32s get () { return (Bit32s) get64(); }
+ virtual Bit64s get64 ();
+ virtual void set (Bit64s val);
+ void set_base (int base) { this->base = base; }
+ void set_initial_val (Bit64s initial_val);
+ int get_base () { return base; }
+ void set_range (Bit64u min, Bit64u max);
+ Bit64s get_min () { return min; }
+ Bit64s get_max () { return max; }
+ static Bit32u set_default_base (Bit32u val);
+ static Bit32u get_default_base () { return default_base; }
+ void set_options (Bit32u options) { this->options = options; }
+ Bit32u get_options () { return options; }
+#if BX_UI_TEXT
+ virtual void text_print (FILE *fp);
+ virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// a bx_shadow_num_c is like a bx_param_num_c except that it doesn't
+// store the actual value with its data. Instead, it uses val.p32bit
+// to keep a pointer to the actual data. This is used to register
+// existing variables as parameters, without have to access it via
+// set/get methods.
+class BOCHSAPI bx_shadow_num_c : public bx_param_num_c {
+ Bit8u varsize; // must be 64, 32, 16, or 8
+ Bit8u lowbit; // range of bits associated with this param
+ Bit64u mask; // mask is ANDed with value before it is returned from get
+public:
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s *ptr_to_real_val,
+ Bit8u highbit = 63,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64u *ptr_to_real_val,
+ Bit8u highbit = 63,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit32s *ptr_to_real_val,
+ Bit8u highbit = 31,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit32u *ptr_to_real_val,
+ Bit8u highbit = 31,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit16s *ptr_to_real_val,
+ Bit8u highbit = 15,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit16u *ptr_to_real_val,
+ Bit8u highbit = 15,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit8s *ptr_to_real_val,
+ Bit8u highbit = 7,
+ Bit8u lowbit = 0);
+ bx_shadow_num_c (bx_id id,
+ char *name,
+ char *description,
+ Bit8u *ptr_to_real_val,
+ Bit8u highbit = 7,
+ Bit8u lowbit = 0);
+ virtual Bit64s get64 ();
+ virtual void set (Bit64s val);
+};
+
+class BOCHSAPI bx_param_bool_c : public bx_param_num_c {
+ // many boolean variables are used to enable/disable modules. In the
+ // user interface, the enable variable should enable/disable all the
+ // other parameters associated with that module.
+public:
+ bx_param_bool_c (bx_id id,
+ char *name,
+ char *description,
+ Bit64s initial_val);
+#if BX_UI_TEXT
+ virtual void text_print (FILE *fp);
+ virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// a bx_shadow_bool_c is a shadow param based on bx_param_bool_c.
+class BOCHSAPI bx_shadow_bool_c : public bx_param_bool_c {
+ // each bit of a bitfield can be a separate value. bitnum tells which
+ // bit is used. get/set will only modify that bit.
+ Bit8u bitnum;
+public:
+ bx_shadow_bool_c (bx_id id,
+ char *name,
+ char *description,
+ bx_bool *ptr_to_real_val,
+ Bit8u bitnum = 0);
+ virtual Bit64s get64 ();
+ virtual void set (Bit64s val);
+};
+
+
+class BOCHSAPI bx_param_enum_c : public bx_param_num_c {
+ char **choices;
+public:
+ bx_param_enum_c (bx_id id,
+ char *name,
+ char *description,
+ char **choices,
+ Bit64s initial_val,
+ Bit64s value_base = 0);
+ char *get_choice (int n) { return choices[n]; }
+ int find_by_name (const char *string);
+ bool set_by_name (const char *string);
+#if BX_UI_TEXT
+ virtual void text_print (FILE *fp);
+ virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+typedef char* (*param_string_event_handler)(class bx_param_string_c *, int set, char *val, int maxlen);
+
+class BOCHSAPI bx_param_string_c : public bx_param_c {
+ int maxsize;
+ char *val, *initial_val;
+ param_string_event_handler handler;
+ param_enable_handler enable_handler;
+ bx_param_num_c *options;
+ char separator;
+public:
+ enum {
+ RAW_BYTES = 1, // use binary text editor, like MAC addr
+ IS_FILENAME = 2, // 1=yes it's a filename, 0=not a filename.
+ // Some guis have a file browser. This
+ // bit suggests that they use it.
+ SAVE_FILE_DIALOG = 4 // Use save dialog opposed to open file dialog
+ } bx_string_opt_bits;
+ bx_param_string_c (bx_id id,
+ char *name,
+ char *description,
+ char *initial_val,
+ int maxsize=-1);
+ virtual ~bx_param_string_c ();
+ void reset ();
+ void set_handler (param_string_event_handler handler);
+ void set_enable_handler (param_enable_handler handler);
+ virtual void set_enabled (int enabled);
+ Bit32s get (char *buf, int len);
+ char *getptr () {return val; }
+ void set (char *buf);
+ bx_bool equals (const char *buf);
+ bx_param_num_c *get_options () { return options; }
+ void set_separator (char sep) {separator = sep; }
+ char get_separator () {return separator; }
+ int get_maxsize () {return maxsize; }
+#if BX_UI_TEXT
+ virtual void text_print (FILE *fp);
+ virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// Declare a filename class. It is identical to a string, except that
+// it initializes the options differently. This is just a shortcut
+// for declaring a string param and setting the options with IS_FILENAME.
+class BOCHSAPI bx_param_filename_c : public bx_param_string_c {
+public:
+ bx_param_filename_c (bx_id id,
+ char *name,
+ char *description,
+ char *initial_val,
+ int maxsize=-1);
+};
+
+class BOCHSAPI bx_list_c : public bx_param_c {
+private:
+ // just a list of bx_param_c objects. size tells current number of
+ // objects in the list, and maxsize tells how many list items are
+ // allocated in the constructor.
+ bx_param_c **list;
+ int size, maxsize;
+ // options is a bit field whose bits are defined by bx_listopt_bits ORed
+ // together. Options is a bx_param so that if necessary the bx_list could
+ // install a handler to cause get/set of options to have side effects.
+ bx_param_num_c *options;
+ // for a menu, the value of choice before the call to "ask" is default.
+ // After ask, choice holds the value that the user chose. Choice defaults
+ // to 1 in the constructor.
+ bx_param_num_c *choice;
+ // title of the menu or series
+ bx_param_string_c *title;
+ // if the menu shows a "return to previous menu" type of choice,
+ // this controls where that choice will go.
+ bx_param_c *parent;
+ void init ();
+public:
+ enum {
+ // When a bx_list_c is displayed as a menu, SHOW_PARENT controls whether or
+ // not the menu shows a "Return to parent menu" choice or not.
+ SHOW_PARENT = (1<<0),
+ // Some lists are best displayed shown as menus, others as a series of
+ // related questions. This bit suggests to the CI that the series of
+ // questions format is preferred.
+ SERIES_ASK = (1<<1),
+ // When a bx_list_c is displayed in a dialog, USE_TAB_WINDOW suggests
+ // to the CI that each item in the list should be shown as a separate
+ // tab. This would be most appropriate when each item is another list
+ // of parameters.
+ USE_TAB_WINDOW = (1<<2),
+ // When a bx_list_c is displayed in a dialog, the list name is used as the
+ // label of the group box if USE_BOX_TITLE is set. This is only necessary if
+ // more than one list appears in a dialog box.
+ USE_BOX_TITLE = (1<<3)
+ } bx_listopt_bits;
+ bx_list_c (bx_id id, int maxsize);
+ bx_list_c (bx_id id, char *name, char *description, bx_param_c **init_list);
+ bx_list_c (bx_id id, char *name, char *description, int maxsize);
+ virtual ~bx_list_c();
+ bx_list_c *clone ();
+ void add (bx_param_c *param);
+ bx_param_c *get (int index);
+ int get_size () { return size; }
+ bx_param_num_c *get_options () { return options; }
+ void set_options (bx_param_num_c *newopt) { options = newopt; }
+ bx_param_num_c *get_choice () { return choice; }
+ bx_param_string_c *get_title () { return title; }
+ void set_parent (bx_param_c *newparent) { parent = newparent; }
+ bx_param_c *get_parent () { return parent; }
+#if BX_UI_TEXT
+ virtual void text_print (FILE *);
+ virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+////////////////////////////////////////////////////////////////
+
+
+// These are the different start modes.
+enum {
+ // Just start the simulation without running the configuration interface
+ // at all, unless something goes wrong.
+ BX_QUICK_START = 200,
+ // Run the configuration interface. The default action will be to load a
+ // configuration file. This makes sense if a config file could not be
+ // loaded, either because it wasn't found or because it had errors.
+ BX_LOAD_START,
+ // Run the configuration interface. The default action will be to
+ // edit the configuration.
+ BX_EDIT_START,
+ // Run the configuration interface, but make the default action be to
+ // start the simulation.
+ BX_RUN_START
+};
+
+#define BX_FLOPPY_NONE 10 // floppy not present
+#define BX_FLOPPY_1_2 11 // 1.2M 5.25"
+#define BX_FLOPPY_1_44 12 // 1.44M 3.5"
+#define BX_FLOPPY_2_88 13 // 2.88M 3.5"
+#define BX_FLOPPY_720K 14 // 720K 3.5"
+#define BX_FLOPPY_360K 15 // 360K 5.25"
+#define BX_FLOPPY_160K 16 // 160K 5.25"
+#define BX_FLOPPY_180K 17 // 180K 5.25"
+#define BX_FLOPPY_320K 18 // 320K 5.25"
+#define BX_FLOPPY_LAST 18 // last legal value of floppy type
+
+#define BX_FLOPPY_GUESS 20 // decide based on image size
+
+#define BX_ATA_DEVICE_DISK 0
+#define BX_ATA_DEVICE_CDROM 1
+#define BX_ATA_DEVICE_LAST 1
+
+#define BX_ATA_BIOSDETECT_NONE 0
+#define BX_ATA_BIOSDETECT_AUTO 1
+#define BX_ATA_BIOSDETECT_CMOS 2
+
+#define BX_ATA_TRANSLATION_NONE 0
+#define BX_ATA_TRANSLATION_LBA 1
+#define BX_ATA_TRANSLATION_LARGE 2
+#define BX_ATA_TRANSLATION_RECHS 3
+#define BX_ATA_TRANSLATION_AUTO 4
+#define BX_ATA_TRANSLATION_LAST 4
+
+#define BX_ATA_MODE_FLAT 0
+#define BX_ATA_MODE_CONCAT 1
+#define BX_ATA_MODE_EXTDISKSIM 2
+#define BX_ATA_MODE_DLL_HD 3
+#define BX_ATA_MODE_SPARSE 4
+#define BX_ATA_MODE_VMWARE3 5
+#define BX_ATA_MODE_UNDOABLE 6
+#define BX_ATA_MODE_GROWING 7
+#define BX_ATA_MODE_VOLATILE 8
+#define BX_ATA_MODE_LAST 8
+//#define BX_ATA_MODE_Z_UNDOABLE 9
+//#define BX_ATA_MODE_Z_VOLATILE 10
+//#define BX_ATA_MODE_SPLIT 6
+
+#define BX_CLOCK_SYNC_NONE 0
+#define BX_CLOCK_SYNC_REALTIME 1
+#define BX_CLOCK_SYNC_SLOWDOWN 2
+#define BX_CLOCK_SYNC_BOTH 3
+#define BX_CLOCK_SYNC_LAST 3
+
+#define BX_CLOCK_TIME0_LOCAL 1
+#define BX_CLOCK_TIME0_UTC 2
+
+BOCHSAPI extern char *bochs_start_names[];
+BOCHSAPI extern int n_bochs_start_names;
+BOCHSAPI extern char *floppy_type_names[];
+BOCHSAPI extern int floppy_type_n_sectors[];
+BOCHSAPI extern int n_floppy_type_names;
+BOCHSAPI extern char *floppy_status_names[];
+BOCHSAPI extern int n_floppy_status_names;
+BOCHSAPI extern char *floppy_bootdisk_names[];
+BOCHSAPI extern int n_floppy_bootdisk_names;
+BOCHSAPI extern char *loader_os_names[];
+BOCHSAPI extern int n_loader_os_names;
+BOCHSAPI extern char *keyboard_type_names[];
+BOCHSAPI extern int n_keyboard_type_names;
+BOCHSAPI extern char *atadevice_type_names[];
+BOCHSAPI extern int n_atadevice_type_names;
+BOCHSAPI extern char *atadevice_mode_names[];
+BOCHSAPI extern int n_atadevice_mode_names;
+BOCHSAPI extern char *atadevice_status_names[];
+BOCHSAPI extern int n_atadevice_status_names;
+BOCHSAPI extern char *atadevice_biosdetect_names[];
+BOCHSAPI extern int n_atadevice_biosdetect_names;
+BOCHSAPI extern char *atadevice_translation_names[];
+BOCHSAPI extern int n_atadevice_translation_names;
+BOCHSAPI extern char *clock_sync_names[];
+BOCHSAPI extern int clock_sync_n_names;
+
+typedef struct {
+ bx_param_enum_c *Odevtype;
+ bx_param_string_c *Opath;
+ bx_param_enum_c *Otype;
+ bx_param_enum_c *Ostatus;
+ } bx_floppy_options;
+
+typedef struct {
+ bx_list_c *Omenu;
+ bx_param_bool_c *Opresent;
+ bx_param_enum_c *Otype;
+ bx_param_enum_c *Omode;
+ bx_param_string_c *Opath;
+ bx_param_string_c *Ojournal;
+ bx_param_num_c *Ocylinders;
+ bx_param_num_c *Oheads;
+ bx_param_num_c *Ospt;
+ bx_param_enum_c *Ostatus;
+ bx_param_string_c *Omodel;
+ bx_param_enum_c *Obiosdetect;
+ bx_param_enum_c *Otranslation;
+ } bx_atadevice_options;
+
+typedef struct {
+ bx_param_bool_c *Oenabled;
+ bx_param_string_c *Odev;
+ } bx_serial_options;
+
+typedef struct {
+ bx_param_bool_c *Oenabled;
+ bx_param_num_c *Oioaddr;
+ bx_param_num_c *Oirq;
+ } bx_usb_options;
+
+
+////////////////////////////////////////////////////////////////////
+// base class simulator interface, contains just virtual functions.
+// I'm not longer sure that having a base class is going to be of any
+// use... -Bryce
+
+#include <setjmp.h>
+
+enum ci_command_t { CI_START, CI_RUNTIME_CONFIG, CI_SHUTDOWN };
+enum ci_return_t {
+ CI_OK, // normal return value
+ CI_ERR_NO_TEXT_CONSOLE // err: can't work because there's no text console
+ };
+typedef int (*config_interface_callback_t)(void *userdata, ci_command_t command);
+
+// bx_gui->set_display_mode() changes the mode between the configuration
+// interface and the simulation. This is primarily intended for display
+// libraries which have a full-screen mode such as SDL, term, and svgalib. The
+// display mode is set to DISP_MODE_CONFIG before displaying any configuration
+// menus, for panics that requires user input, when entering the debugger, etc.
+// It is set to DISP_MODE_SIM when the Bochs simulation resumes. The constants
+// are defined here so that configuration interfaces can use them with the
+// bx_simulator_interface_c::set_display_mode() method.
+enum disp_mode_t { DISP_MODE_CONFIG=100, DISP_MODE_SIM };
+
+class BOCHSAPI bx_simulator_interface_c {
+public:
+ bx_simulator_interface_c ();
+ virtual void set_quit_context (jmp_buf *context) {}
+ virtual int get_init_done () { return -1; }
+ virtual int set_init_done (int n) {return -1;}
+ virtual void get_param_id_range (int *min, int *max) {}
+ virtual int register_param (bx_id id, bx_param_c *it) {return -1;}
+ virtual void reset_all_param () {}
+ virtual bx_param_c *get_param (bx_id id) {return NULL;}
+ virtual bx_param_num_c *get_param_num (bx_id id) {return NULL;}
+ virtual bx_param_string_c *get_param_string (bx_id id) {return NULL;}
+ virtual bx_param_bool_c *get_param_bool (bx_id id) {return NULL;}
+ virtual bx_param_enum_c *get_param_enum (bx_id id) {return NULL;}
+ virtual int get_n_log_modules () {return -1;}
+ virtual char *get_prefix (int mod) {return 0;}
+ virtual int get_log_action (int mod, int level) {return -1;}
+ virtual void set_log_action (int mod, int level, int action) {}
+ virtual int get_default_log_action (int level) {return -1;}
+ virtual void set_default_log_action (int level, int action) {}
+ virtual char *get_action_name (int action) {return 0;}
+ virtual const char *get_log_level_name (int level) {return 0;}
+ virtual int get_max_log_level () {return -1;}
+
+ // exiting is somewhat complicated! The preferred way to exit bochs is
+ // to call BX_EXIT(exitcode). That is defined to call
+ // SIM->quit_sim(exitcode). The quit_sim function first calls
+ // the cleanup functions in bochs so that it can destroy windows
+ // and free up memory, then sends a notify message to the CI
+ // telling it that bochs has stopped.
+ virtual void quit_sim (int code) {}
+
+ virtual int get_exit_code () { return 0; }
+
+ virtual int get_default_rc (char *path, int len) {return -1;}
+ virtual int read_rc (char *path) {return -1;}
+ virtual int write_rc (char *rc, int overwrite) {return -1;}
+ virtual int get_log_file (char *path, int len) {return -1;}
+ virtual int set_log_file (char *path) {return -1;}
+ virtual int get_log_prefix (char *prefix, int len) {return -1;}
+ virtual int set_log_prefix (char *prefix) {return -1;}
+ virtual int get_debugger_log_file (char *path, int len) {return -1;}
+ virtual int set_debugger_log_file (char *path) {return -1;}
+ virtual int get_floppy_options (int drive, bx_floppy_options *out) {return -1;}
+ virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *where = NULL) {return -1;}
+ virtual char *get_floppy_type_name (int type) {return NULL;}
+
+ // The CI calls set_notify_callback to register its event handler function.
+ // This event handler function is called whenever the simulator needs to
+ // send an event to the CI. For example, if the simulator hits a panic and
+ // wants to ask the user how to proceed, it would call the CI event handler
+ // to ask the CI to display a dialog.
+ //
+ // NOTE: At present, the standard VGAW buttons (floppy, snapshot, power,
+ // etc.) are displayed and handled by gui.cc, not by the CI or siminterface.
+ // gui.cc uses its own callback functions to implement the behavior of
+ // the buttons. Some of these implementations call the siminterface.
+ typedef BxEvent* (*bxevent_handler)(void *theclass, BxEvent *event);
+ virtual void set_notify_callback (bxevent_handler func, void *arg) {}
+ virtual void get_notify_callback (bxevent_handler *func, void **arg) {}
+
+ // send an event from the simulator to the CI.
+ virtual BxEvent* sim_to_ci_event (BxEvent *event) {return NULL;}
+
+ // called from simulator when it hits serious errors, to ask if the user
+ // wants to continue or not
+ virtual int log_msg (const char *prefix, int level, const char *msg) {return -1;}
+
+ // tell the CI to ask the user for the value of a parameter.
+ virtual int ask_param (bx_id param) {return -1;}
+
+ // ask the user for a pathname
+ virtual int ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags) {return -1;}
+ // called at a regular interval, currently by the keyboard handler.
+ virtual void periodic () {}
+ virtual int create_disk_image (const char *filename, int sectors, bx_bool overwrite) {return -3;}
+ // Tell the configuration interface (CI) that some parameter values have
+ // changed. The CI will reread the parameters and change its display if it's
+ // appropriate. Maybe later: mention which params have changed to save time.
+ virtual void refresh_ci () {}
+ // forces a vga update. This was added so that a debugger can force
+ // a vga update when single stepping, without having to wait thousands
+ // of cycles for the normal vga refresh triggered by iodev/keyboard.cc.
+ virtual void refresh_vga () {}
+ // forces a call to bx_gui.handle_events. This was added so that a debugger
+ // can force the gui events to be handled, so that interactive things such
+ // as a toolbar click will be processed.
+ virtual void handle_events () {}
+ // return first hard disk in ATA interface
+ virtual bx_param_c *get_first_cdrom () {return NULL;}
+ // return first cdrom in ATA interface
+ virtual bx_param_c *get_first_hd () {return NULL;}
+#if BX_DEBUGGER
+ // for debugger: same behavior as pressing control-C
+ virtual void debug_break () {}
+ virtual void debug_interpret_cmd (char *cmd) {}
+ virtual char *debug_get_next_command () {return NULL;}
+ virtual void debug_puts (const char *text) {}
+#endif
+ virtual void register_configuration_interface (
+ const char* name,
+ config_interface_callback_t callback,
+ void *userdata) {}
+ virtual int configuration_interface(const char* name, ci_command_t command) {return -1; }
+ virtual int begin_simulation (int argc, char *argv[]) {return -1;}
+ typedef bool (*is_sim_thread_func_t)();
+ is_sim_thread_func_t is_sim_thread_func;
+ virtual void set_sim_thread_func (is_sim_thread_func_t func) {
+ is_sim_thread_func = func;
+ }
+ virtual bool is_sim_thread () {return true;}
+ virtual bool is_wx_selected () {return false;}
+ // provide interface to bx_gui->set_display_mode() method for config
+ // interfaces to use.
+ virtual void set_display_mode (disp_mode_t newmode) {}
+ virtual bool test_for_text_console () { return true; }
+};
+
+BOCHSAPI extern bx_simulator_interface_c *SIM;
+
+BOCHSAPI extern void bx_init_siminterface ();
+BOCHSAPI extern int bx_init_main (int argc, char *argv[]);
+
+#if defined(__WXMSW__) || defined(WIN32)
+// Just to provide HINSTANCE, etc. in files that have not included bochs.h.
+// I don't like this at all, but I don't see a way around it.
+#include <windows.h>
+#endif
+
+// define structure to hold data that is passed into our main function.
+typedef struct BOCHSAPI {
+ // standard argc,argv
+ int argc;
+ char **argv;
+#ifdef WIN32
+ char initial_dir[MAX_PATH];
+#endif
+#ifdef __WXMSW__
+ // these are only used when compiling with wxWindows. This gives us a
+ // place to store the data that was passed to WinMain.
+ HINSTANCE hInstance;
+ HINSTANCE hPrevInstance;
+ LPSTR m_lpCmdLine;
+ int nCmdShow;
+#endif
+} bx_startup_flags_t;
+
+BOCHSAPI extern bx_startup_flags_t bx_startup_flags;
+BOCHSAPI extern bx_bool bx_user_quit;
diff --git a/tools/ioemu/gui/svga.cc b/tools/ioemu/gui/svga.cc
new file mode 100644
index 0000000000..33020fca80
--- /dev/null
+++ b/tools/ioemu/gui/svga.cc
@@ -0,0 +1,514 @@
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#define _MULTI_THREAD
+
+// 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"
+#if BX_WITH_SVGA
+
+#include <stdlib.h>
+#include </usr/include/vga.h>
+#include <vgagl.h>
+#include <vgakeyboard.h>
+#include <vgamouse.h>
+
+#include "font/vga.bitmap.h"
+//#include "icon_bochs.h"
+
+class bx_svga_gui_c : public bx_gui_c {
+public:
+ bx_svga_gui_c (void);
+ DECLARE_GUI_VIRTUAL_METHODS()
+ virtual void set_display_mode (disp_mode_t newmode);
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_svga_gui_c *theGui = NULL;
+
+IMPLEMENT_GUI_PLUGIN_CODE(svga)
+
+#define LOG_THIS theGui->
+
+static unsigned res_x, res_y;
+static int fontwidth = 8, fontheight = 16;
+static unsigned tilewidth, tileheight;
+static unsigned char vgafont[256 * 16];
+static int clut8 = 0;
+GraphicsContext *screen = NULL;
+static int save_vga_mode;
+static int save_vga_pal[256 * 3];
+
+void keyboard_handler(int scancode, int press);
+void mouse_handler(int button, int dx, int dy, int dz,
+ int drx, int dry, int drz);
+
+unsigned char reverse_byteorder(unsigned char b)
+{
+ unsigned char ret = 0;
+
+ for (unsigned i=0;i<8;i++){
+ ret |= (b & 0x01) << (7 - i);
+ b >>= 1;
+ }
+ return ret;
+}
+
+void create_vga_font()
+{
+ memcpy(vgafont, bx_vgafont, sizeof(bx_vgafont));
+
+ for (unsigned i=0;i< sizeof(bx_vgafont);i++) {
+ vgafont[i] = reverse_byteorder(vgafont[i]);
+ }
+}
+
+bx_svga_gui_c::bx_svga_gui_c ()
+{
+ put("SVGA");
+}
+
+void bx_svga_gui_c::specific_init(
+ int argc,
+ char **argv,
+ unsigned x_tilesize,
+ unsigned y_tilesize,
+ unsigned header_bar_y)
+{
+ tilewidth = x_tilesize;
+ tileheight = y_tilesize;
+
+ if(vga_init() != 0 )
+ {
+ LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+ BX_PANIC (("Unable to initialize SVGAlib"));
+ return;
+ }
+
+ screen = gl_allocatecontext();
+
+ dimension_update(640,400);
+ create_vga_font();
+ gl_setfont(8, 16, (void *)vgafont);
+ gl_setwritemode(FONT_COMPRESSED);
+
+ keyboard_init();
+ keyboard_seteventhandler((__keyboard_handler) keyboard_handler);
+
+ vga_setmousesupport(1);
+ mouse_seteventhandler((__mouse_handler) mouse_handler);
+ if (vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_FLAGS) & VGA_CLUT8) {
+ vga_ext_set(VGA_EXT_SET, VGA_CLUT8);
+ clut8 = 1;
+ }
+ // Save settings to prepare for mode transition in set_display_mode.
+ // If DISP_MODE_SIM is called first, these values will be used.
+ save_vga_mode = vga_getcurrentmode();
+ vga_getpalvec(0, 256, save_vga_pal);
+}
+
+void bx_svga_gui_c::text_update(
+ Bit8u *old_text,
+ Bit8u *new_text,
+ unsigned long cursor_x,
+ unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info,
+ unsigned rows)
+{
+ unsigned x, y, i;
+ unsigned chars, cols;
+ char s[] = " ";
+ static unsigned int previ;
+ unsigned int cursori;
+
+ cols = res_x/fontwidth;
+
+ cursori = (cursor_y*cols + cursor_x) * 2;
+
+ chars = cols*rows;
+
+ for (i=0; i<chars*2; i+=2) {
+ if (i == cursori || i == previ || old_text[i] != new_text[i] ||
+ old_text[i+1] != new_text[i+1]) {
+
+ s[0] = new_text[i];
+ x = (i/2) % cols;
+ y = (i/2) / cols;
+
+ if (i == cursori) {
+ gl_setfontcolors(new_text[i+1] & 0x0F, (new_text[i+1] & 0xF0) >> 4);
+ } else {
+ gl_setfontcolors((new_text[i+1] & 0xF0) >> 4, new_text[i+1] & 0x0F);
+ }
+ gl_write(x * fontwidth, y * fontheight, s);
+ }
+ }
+ previ = cursori;
+}
+
+ int
+bx_svga_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ return 0;
+}
+
+ int
+bx_svga_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ return 0;
+}
+
+
+void bx_svga_gui_c::graphics_tile_update(
+ Bit8u *snapshot,
+ unsigned x,
+ unsigned y)
+{
+ gl_putbox(x, y, tilewidth, tileheight, snapshot);
+}
+
+static Bit32u vga_to_bx_key(int key)
+{
+ switch (key) {
+ case SCANCODE_ESCAPE: return BX_KEY_ESC;
+ case SCANCODE_1: return BX_KEY_1;
+ case SCANCODE_2: return BX_KEY_2;
+ case SCANCODE_3: return BX_KEY_3;
+ case SCANCODE_4: return BX_KEY_4;
+ case SCANCODE_5: return BX_KEY_5;
+ case SCANCODE_6: return BX_KEY_6;
+ case SCANCODE_7: return BX_KEY_7;
+ case SCANCODE_8: return BX_KEY_8;
+ case SCANCODE_9: return BX_KEY_9;
+ case SCANCODE_0: return BX_KEY_0;
+
+ case SCANCODE_MINUS: return BX_KEY_MINUS;
+ case SCANCODE_EQUAL: return BX_KEY_EQUALS;
+ case SCANCODE_TAB: return BX_KEY_TAB;
+ case SCANCODE_BACKSPACE: return BX_KEY_BACKSPACE;
+
+ case SCANCODE_Q: return BX_KEY_Q;
+ case SCANCODE_W: return BX_KEY_W;
+ case SCANCODE_E: return BX_KEY_E;
+ case SCANCODE_R: return BX_KEY_R;
+ case SCANCODE_T: return BX_KEY_T;
+ case SCANCODE_Y: return BX_KEY_Y;
+ case SCANCODE_U: return BX_KEY_U;
+ case SCANCODE_I: return BX_KEY_I;
+ case SCANCODE_O: return BX_KEY_O;
+ case SCANCODE_P: return BX_KEY_P;
+
+ case SCANCODE_BRACKET_LEFT: return BX_KEY_LEFT_BRACKET;
+ case SCANCODE_BRACKET_RIGHT: return BX_KEY_RIGHT_BRACKET;
+
+ case SCANCODE_ENTER: return BX_KEY_ENTER;
+ case SCANCODE_LEFTCONTROL: return BX_KEY_CTRL_L;
+
+ case SCANCODE_A: return BX_KEY_A;
+ case SCANCODE_S: return BX_KEY_S;
+ case SCANCODE_D: return BX_KEY_D;
+ case SCANCODE_F: return BX_KEY_F;
+ case SCANCODE_G: return BX_KEY_G;
+ case SCANCODE_H: return BX_KEY_H;
+ case SCANCODE_J: return BX_KEY_J;
+ case SCANCODE_K: return BX_KEY_K;
+ case SCANCODE_L: return BX_KEY_L;
+
+ case SCANCODE_SEMICOLON: return BX_KEY_SEMICOLON;
+ case SCANCODE_APOSTROPHE: return BX_KEY_SINGLE_QUOTE;
+ case SCANCODE_GRAVE: return BX_KEY_GRAVE;
+
+ case SCANCODE_LEFTSHIFT: return BX_KEY_SHIFT_L;
+ case SCANCODE_BACKSLASH: return BX_KEY_BACKSLASH;
+
+ case SCANCODE_Z: return BX_KEY_Z;
+ case SCANCODE_X: return BX_KEY_X;
+ case SCANCODE_C: return BX_KEY_C;
+ case SCANCODE_V: return BX_KEY_V;
+ case SCANCODE_B: return BX_KEY_B;
+ case SCANCODE_N: return BX_KEY_N;
+ case SCANCODE_M: return BX_KEY_M;
+
+ case SCANCODE_COMMA: return BX_KEY_COMMA;
+ case SCANCODE_PERIOD: return BX_KEY_PERIOD;
+ case SCANCODE_SLASH: return BX_KEY_SLASH;
+
+ case SCANCODE_RIGHTSHIFT: return BX_KEY_SHIFT_R;
+ case SCANCODE_KEYPADMULTIPLY: return BX_KEY_KP_MULTIPLY;
+
+ case SCANCODE_LEFTALT: return BX_KEY_ALT_L;
+ case SCANCODE_SPACE: return BX_KEY_SPACE;
+ case SCANCODE_CAPSLOCK: return BX_KEY_CAPS_LOCK;
+
+ case SCANCODE_F1: return BX_KEY_F1;
+ case SCANCODE_F2: return BX_KEY_F2;
+ case SCANCODE_F3: return BX_KEY_F3;
+ case SCANCODE_F4: return BX_KEY_F4;
+ case SCANCODE_F5: return BX_KEY_F5;
+ case SCANCODE_F6: return BX_KEY_F6;
+ case SCANCODE_F7: return BX_KEY_F7;
+ case SCANCODE_F8: return BX_KEY_F8;
+ case SCANCODE_F9: return BX_KEY_F9;
+ case SCANCODE_F10: return BX_KEY_F10;
+
+ case SCANCODE_NUMLOCK: return BX_KEY_NUM_LOCK;
+ case SCANCODE_SCROLLLOCK: return BX_KEY_SCRL_LOCK;
+
+ case SCANCODE_KEYPAD7: return BX_KEY_KP_HOME;
+ case SCANCODE_KEYPAD8: return BX_KEY_KP_UP;
+ case SCANCODE_KEYPAD9: return BX_KEY_KP_PAGE_UP;
+ case SCANCODE_KEYPADMINUS: return BX_KEY_KP_SUBTRACT;
+ case SCANCODE_KEYPAD4: return BX_KEY_KP_LEFT;
+ case SCANCODE_KEYPAD5: return BX_KEY_KP_5;
+ case SCANCODE_KEYPAD6: return BX_KEY_KP_RIGHT;
+ case SCANCODE_KEYPADPLUS: return BX_KEY_KP_ADD;
+ case SCANCODE_KEYPAD1: return BX_KEY_KP_END;
+ case SCANCODE_KEYPAD2: return BX_KEY_KP_DOWN;
+ case SCANCODE_KEYPAD3: return BX_KEY_KP_PAGE_DOWN;
+ case SCANCODE_KEYPAD0: return BX_KEY_KP_INSERT;
+// case SCANCODE_KEYPADPERIOD: return BX_KEY_KP_; /* ??? */
+
+// case SCANCODE_LESS: return BX_KEY_KP_LESS; /* ??? */
+
+ case SCANCODE_F11: return BX_KEY_F11;
+ case SCANCODE_F12: return BX_KEY_F12;
+
+ case SCANCODE_KEYPADENTER: return BX_KEY_KP_ENTER;
+ case SCANCODE_RIGHTCONTROL: return BX_KEY_CTRL_R;
+ case SCANCODE_KEYPADDIVIDE: return BX_KEY_KP_DIVIDE;
+ case SCANCODE_PRINTSCREEN: return BX_KEY_PRINT;
+ case SCANCODE_RIGHTALT: return BX_KEY_ALT_R;
+ case SCANCODE_BREAK: return BX_KEY_PAUSE;
+
+ case SCANCODE_HOME: return BX_KEY_HOME;
+ case SCANCODE_CURSORBLOCKUP: return BX_KEY_UP;
+ case SCANCODE_PAGEUP: return BX_KEY_PAGE_UP;
+ case SCANCODE_CURSORBLOCKLEFT: return BX_KEY_LEFT;
+ case SCANCODE_CURSORBLOCKRIGHT: return BX_KEY_RIGHT;
+ case SCANCODE_END: return BX_KEY_END;
+ case SCANCODE_CURSORBLOCKDOWN: return BX_KEY_DOWN;
+ case SCANCODE_PAGEDOWN: return BX_KEY_PAGE_DOWN;
+ case SCANCODE_INSERT: return BX_KEY_INSERT;
+ case SCANCODE_REMOVE: return BX_KEY_DELETE;
+
+ case SCANCODE_RIGHTWIN: return BX_KEY_WIN_R;
+ case SCANCODE_LEFTWIN: return BX_KEY_WIN_L;
+
+ default: return 0;
+ }
+}
+
+void keyboard_handler(int scancode, int press)
+{
+ if (scancode != SCANCODE_F12) {
+ int bx_key = vga_to_bx_key(scancode);
+ Bit32u key_state;
+
+ if (press) {
+ key_state = BX_KEY_PRESSED;
+ } else {
+ key_state = BX_KEY_RELEASED;
+ }
+
+ DEV_kbd_gen_scancode(bx_key | key_state);
+ } else {
+ BX_INFO(("F12 pressed"));
+ // show runtime options menu, which uses stdin/stdout
+ SIM->configuration_interface (NULL, CI_RUNTIME_CONFIG);
+ }
+}
+
+void mouse_handler(int button, int dx, int dy, int dz,
+ int drx, int dry, int drz)
+{
+ int buttons = 0;
+
+ if (button & MOUSE_LEFTBUTTON) {
+ buttons |= 0x01;
+ }
+
+ if (button & MOUSE_RIGHTBUTTON) {
+ buttons |= 0x02;
+ }
+ DEV_mouse_motion((int) (0.25 * dx), (int) -(0.25 * dy), buttons);
+}
+
+void bx_svga_gui_c::handle_events(void)
+{
+ keyboard_update();
+ keyboard_clearstate();
+ mouse_update();
+}
+
+void bx_svga_gui_c::flush(void)
+{
+ gl_copyscreen(screen);
+}
+
+void bx_svga_gui_c::clear_screen(void)
+{
+ gl_clearscreen(0);
+}
+
+bx_bool bx_svga_gui_c::palette_change(
+ unsigned index,
+ unsigned red,
+ unsigned green,
+ unsigned blue)
+{
+ if( index > 255 ) return 0;
+
+ // without VGA_CLUT8 extension we have only 6 bits for each r,g,b value
+ if (!clut8 && (red > 63 || green > 63 || blue > 63)) {
+ red = red >> 2;
+ green = green >> 2;
+ blue = blue >> 2;
+ }
+
+ vga_setpalette(index, red, green, blue);
+
+ return 1;
+}
+
+
+void bx_svga_gui_c::dimension_update(
+ unsigned x,
+ unsigned y,
+ unsigned fheight,
+ unsigned fwidth,
+ unsigned bpp)
+{
+ int newmode = 0;
+
+ if (bpp > 8) {
+ BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
+ }
+ if( fheight > 0 )
+ {
+ fontheight = fheight;
+ if (fwidth != 8) {
+ x = x * 8 / fwidth;
+ }
+ fontwidth = 8;
+ }
+
+ if( (x == res_x) && (y == res_y )) return;
+
+ if (x == 640 && y == 480) {
+ newmode = G640x480x256;
+ } else if (x == 640 && y == 400) {
+ newmode = G640x400x256;
+ } else if (x == 320 && y == 200) {
+ newmode = G320x200x256;
+ }
+
+ if (!vga_hasmode(newmode)) {
+ newmode = G640x480x256; // trying "default" mode...
+ }
+
+ if (vga_setmode(newmode) != 0)
+ {
+ LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+ BX_PANIC (("Unable to set requested videomode: %ix%i", x, y));
+ }
+
+ gl_setcontextvga(newmode);
+ gl_getcontext(screen);
+ gl_setcontextvgavirtual(newmode);
+ save_vga_mode = newmode;
+
+ res_x = x;
+ res_y = y;
+}
+
+
+unsigned bx_svga_gui_c::create_bitmap(
+ const unsigned char *bmap,
+ unsigned xdim,
+ unsigned ydim)
+{
+ return 0;
+}
+
+
+unsigned bx_svga_gui_c::headerbar_bitmap(
+ unsigned bmap_id,
+ unsigned alignment,
+ void (*f)(void))
+{
+ return 0;
+}
+
+
+void bx_svga_gui_c::replace_bitmap(
+ unsigned hbar_id,
+ unsigned bmap_id)
+{
+}
+
+
+void bx_svga_gui_c::show_headerbar(void)
+{
+}
+
+
+void bx_svga_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+
+
+void headerbar_click(int x)
+{
+}
+
+void bx_svga_gui_c::exit(void)
+{
+ vga_setmode(TEXT);
+ keyboard_close();
+ mouse_close();
+}
+
+void
+bx_svga_gui_c::set_display_mode (disp_mode_t newmode)
+{
+ // if no mode change, do nothing.
+ if (disp_mode == newmode) return;
+ // remember the display mode for next time
+ disp_mode = newmode;
+ switch (newmode) {
+ case DISP_MODE_CONFIG:
+ BX_DEBUG (("switch to configuration mode (back to console)"));
+ // remember old values and switch to text mode
+ save_vga_mode = vga_getcurrentmode();
+ vga_getpalvec(0, 256, save_vga_pal);
+ keyboard_close();
+ vga_setmode(TEXT);
+ break;
+ case DISP_MODE_SIM:
+ BX_DEBUG (("switch to simulation mode (fullscreen)"));
+ keyboard_init();
+ keyboard_seteventhandler((__keyboard_handler) keyboard_handler);
+ vga_setmode(save_vga_mode);
+ vga_setpalvec(0, 256, save_vga_pal);
+ break;
+ }
+}
+
+#endif /* if BX_WITH_SVGA */
diff --git a/tools/ioemu/gui/term.cc b/tools/ioemu/gui/term.cc
new file mode 100644
index 0000000000..37bf9c5936
--- /dev/null
+++ b/tools/ioemu/gui/term.cc
@@ -0,0 +1,843 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: term.cc,v 1.31 2003/08/17 23:40:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2000 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// 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"
+#if BX_WITH_TERM
+
+#include "icon_bochs.h"
+
+extern "C" {
+#include <curses.h>
+#include <signal.h>
+};
+
+class bx_term_gui_c : public bx_gui_c {
+public:
+ bx_term_gui_c (void) {}
+ DECLARE_GUI_VIRTUAL_METHODS()
+
+ virtual Bit32u get_sighandler_mask ();
+ // called when registered signal arrives
+ virtual void sighandler (int sig);
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_term_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(term)
+
+#define LOG_THIS theGui->
+
+bx_bool initialized = 0;
+static unsigned int text_cols = 80, text_rows = 25;
+
+static short curses_color[8] = {
+ /* 0 */ COLOR_BLACK,
+ /* 1 */ COLOR_BLUE,
+ /* 2 */ COLOR_GREEN,
+ /* 3 */ COLOR_CYAN,
+ /* 4 */ COLOR_RED,
+ /* 5 */ COLOR_MAGENTA,
+ /* 6 */ COLOR_YELLOW,
+ /* 7 */ COLOR_WHITE
+};
+
+static chtype vga_to_term[128] = {
+ 0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7,
+ 0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5,
+ 0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9,
+ 0xff, 0xd6, 0xdc, 0xe7, 0xa3, 0xa5, ' ', ' ',
+ 0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba,
+ 0xbf, ' ', 0xac, ' ', ' ', 0xa1, 0xab, 0xbb,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, ' ', ' ', ' ', ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', 0xb5, ' ',
+ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+ ' ', 0xb1, ' ', ' ', ' ', ' ', 0xf7, ' ',
+ 0xb0, ' ', ' ', ' ', ' ', 0xb2, ' ', ' '
+};
+
+static void
+do_scan(int key_event, int shift, int ctrl, int alt)
+{
+ /* XXX At some point, cache alt/ctrl/shift so only when the state
+ changes do we simulate a press or release, to cut down on
+ keyboard input to the simulated machine */
+
+ BX_DEBUG(("key_event %d/0x%x %s%s%s",
+ key_event,key_event,
+ shift?"(shift)":"",
+ ctrl?"(ctrl)":"",
+ alt?"(alt)":""));
+ if(shift)
+ DEV_kbd_gen_scancode(BX_KEY_SHIFT_L);
+ if(ctrl)
+ DEV_kbd_gen_scancode(BX_KEY_CTRL_L);
+ if(alt)
+ DEV_kbd_gen_scancode(BX_KEY_ALT_L);
+ DEV_kbd_gen_scancode(key_event);
+ key_event |= BX_KEY_RELEASED;
+
+ DEV_kbd_gen_scancode(key_event);
+ if(alt)
+ DEV_kbd_gen_scancode(BX_KEY_ALT_L|BX_KEY_RELEASED);
+ if(ctrl)
+ DEV_kbd_gen_scancode(BX_KEY_CTRL_L|BX_KEY_RELEASED);
+ if(shift)
+ DEV_kbd_gen_scancode(BX_KEY_SHIFT_L|BX_KEY_RELEASED);
+}
+
+Bit32u
+bx_term_gui_c::get_sighandler_mask ()
+{
+ return
+ (1<<SIGHUP)
+ | (1<<SIGINT)
+ | (1<<SIGQUIT)
+#ifdef SIGSTOP
+ | (1<<SIGSTOP)
+#endif
+#ifdef SIGTSTP
+ | (1<<SIGTSTP)
+#endif
+ | (1<<SIGTERM);
+}
+
+void
+bx_term_gui_c::sighandler(int signo)
+{
+ switch(signo) {
+ case SIGINT:
+ do_scan(BX_KEY_C,0,1,0);
+ break;
+#ifdef SIGSTOP
+ case SIGSTOP:
+ do_scan(BX_KEY_S,0,1,0);
+ break;
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP:
+ do_scan(BX_KEY_Z,0,1,0);
+ break;
+#endif
+ default:
+ BX_INFO(("sig %d caught",signo));
+ break;
+ }
+}
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+// specific options from the command line. (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+// only updated regions of the screen to the gui code to be redrawn.
+// These define the dimensions of a region (tile).
+// headerbar_y: A headerbar (toolbar) is display on the top of the
+// VGA window, showing floppy status, and other information. It
+// always assumes the width of the current VGA mode width, but
+// it's height is defined by this parameter.
+
+ void
+bx_term_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+ unsigned headerbar_y)
+{
+ put("TGUI");
+ UNUSED(argc);
+ UNUSED(argv);
+ UNUSED(tilewidth);
+ UNUSED(tileheight);
+ UNUSED(headerbar_y);
+
+ UNUSED(bochs_icon_bits); // global variable
+
+ // the ask menu causes trouble
+ io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
+ // logfile should be different from stderr, otherwise terminal mode
+ // really ends up having fun
+ if (!strcmp(bx_options.log.Ofilename->getptr(), "-"))
+ BX_PANIC(("cannot log to stderr in term mode"));
+
+ initscr();
+ start_color();
+ cbreak();
+ curs_set(2);
+ keypad(stdscr,TRUE);
+ nodelay(stdscr, TRUE);
+ noecho();
+
+#if BX_HAVE_COLOR_SET
+ if (has_colors()) {
+ for (int i=0; i<COLORS; i++) {
+ for (int j=0; j<COLORS; j++) {
+ if ((i!=0)||(j!=0)) init_pair(i * COLORS + j, j, i);
+ }
+ }
+ }
+#endif
+
+ if (bx_options.Oprivate_colormap->get ())
+ BX_ERROR(("WARNING: private_colormap option ignored."));
+ initialized = 1;
+}
+
+
+
+void
+do_char(int character,int alt)
+{
+ switch (character) {
+ // control keys
+ case 0x9: do_scan(BX_KEY_TAB,0,0,alt); break;
+ case 0xa: do_scan(BX_KEY_KP_ENTER,0,0,alt); break;
+ case 0xd: do_scan(BX_KEY_KP_DELETE,0,0,alt); break;
+ case 0x1: do_scan(BX_KEY_A,0,1,alt); break;
+ case 0x2: do_scan(BX_KEY_B,0,1,alt); break;
+ case 0x3: do_scan(BX_KEY_C,0,1,alt); break;
+ case 0x4: do_scan(BX_KEY_D,0,1,alt); break;
+ case 0x5: do_scan(BX_KEY_E,0,1,alt); break;
+ case 0x6: do_scan(BX_KEY_F,0,1,alt); break;
+ case 0x7: do_scan(BX_KEY_G,0,1,alt); break;
+ case 0x8: do_scan(BX_KEY_H,0,1,alt); break;
+ case 0xb: do_scan(BX_KEY_K,0,1,alt); break;
+ case 0xc: do_scan(BX_KEY_L,0,1,alt); break;
+ case 0xe: do_scan(BX_KEY_N,0,1,alt); break;
+ case 0xf: do_scan(BX_KEY_O,0,1,alt); break;
+ case 0x10: do_scan(BX_KEY_P,0,1,alt); break;
+ case 0x11: do_scan(BX_KEY_Q,0,1,alt); break;
+ case 0x12: do_scan(BX_KEY_R,0,1,alt); break;
+ case 0x13: do_scan(BX_KEY_S,0,1,alt); break;
+ case 0x14: do_scan(BX_KEY_T,0,1,alt); break;
+ case 0x15: do_scan(BX_KEY_U,0,1,alt); break;
+ case 0x16: do_scan(BX_KEY_V,0,1,alt); break;
+ case 0x17: do_scan(BX_KEY_W,0,1,alt); break;
+ case 0x18: do_scan(BX_KEY_X,0,1,alt); break;
+ case 0x19: do_scan(BX_KEY_Y,0,1,alt); break;
+ case 0x1a: do_scan(BX_KEY_Z,0,1,alt); break;
+ case 0x20: do_scan(BX_KEY_SPACE,0,0,alt); break;
+ case 0x107: do_scan(BX_KEY_BACKSPACE,0,0,alt); break;
+ case 0x102: do_scan(BX_KEY_DOWN,0,0,alt); break;
+ case 0x103: do_scan(BX_KEY_UP,0,0,alt); break;
+ case 0x104: do_scan(BX_KEY_LEFT,0,0,alt); break;
+ case 0x105: do_scan(BX_KEY_RIGHT,0,0,alt); break;
+ case 0x152: do_scan(BX_KEY_PAGE_DOWN,0,0,alt); break;
+ case 0x153: do_scan(BX_KEY_PAGE_UP,0,0,alt); break;
+ case 0x106: do_scan(BX_KEY_HOME,0,0,alt); break;
+ case 0x168: do_scan(BX_KEY_END,0,0,alt); break;
+ case 0x14b: do_scan(BX_KEY_INSERT,0,0,alt); break;
+ case 0x7f: do_scan(BX_KEY_DELETE,0,0,alt); break;
+ case 0x1b: do_scan(BX_KEY_ESC,0,0,alt); break;
+ case '!': do_scan(BX_KEY_1,1,0,alt); break;
+ case '\'': do_scan(BX_KEY_SINGLE_QUOTE,0,0,alt); break;
+ case '#': do_scan(BX_KEY_3,1,0,alt); break;
+ case '$': do_scan(BX_KEY_4,1,0,alt); break;
+ case '%': do_scan(BX_KEY_5,1,0,alt); break;
+ case '^': do_scan(BX_KEY_6,1,0,alt); break;
+ case '&': do_scan(BX_KEY_7,1,0,alt); break;
+ case '"': do_scan(BX_KEY_SINGLE_QUOTE,1,0,alt); break;
+
+ // ()*+,-./
+ case '(': do_scan(BX_KEY_9,1,0,alt); break;
+ case ')': do_scan(BX_KEY_0,1,0,alt); break;
+ case '*': do_scan(BX_KEY_8,1,0,alt); break;
+ case '+': do_scan(BX_KEY_EQUALS,1,0,alt); break;
+ case ',': do_scan(BX_KEY_COMMA,0,0,alt); break;
+ case '-': do_scan(BX_KEY_MINUS,0,0,alt); break;
+ case '.': do_scan(BX_KEY_PERIOD,0,0,alt); break;
+ case '/': do_scan(BX_KEY_SLASH,0,0,alt); break;
+
+ // 01234567
+ case '0': do_scan(BX_KEY_0,0,0,alt); break;
+ case '1': do_scan(BX_KEY_1,0,0,alt); break;
+ case '2': do_scan(BX_KEY_2,0,0,alt); break;
+ case '3': do_scan(BX_KEY_3,0,0,alt); break;
+ case '4': do_scan(BX_KEY_4,0,0,alt); break;
+ case '5': do_scan(BX_KEY_5,0,0,alt); break;
+ case '6': do_scan(BX_KEY_6,0,0,alt); break;
+ case '7': do_scan(BX_KEY_7,0,0,alt); break;
+
+ // 89:;<=>?
+ case '8': do_scan(BX_KEY_8,0,0,alt); break;
+ case '9': do_scan(BX_KEY_9,0,0,alt); break;
+ case ':': do_scan(BX_KEY_SEMICOLON,1,0,alt); break;
+ case ';': do_scan(BX_KEY_SEMICOLON,0,0,alt); break;
+ case '<': do_scan(BX_KEY_COMMA,1,0,alt); break;
+ case '=': do_scan(BX_KEY_EQUALS,0,0,alt); break;
+ case '>': do_scan(BX_KEY_PERIOD,1,0,alt); break;
+ case '?': do_scan(BX_KEY_SLASH,1,0,alt); break;
+
+ // @ABCDEFG
+ case '@': do_scan(BX_KEY_2,1,0,alt); break;
+ case 'A': do_scan(BX_KEY_A,1,0,alt); break;
+ case 'B': do_scan(BX_KEY_B,1,0,alt); break;
+ case 'C': do_scan(BX_KEY_C,1,0,alt); break;
+ case 'D': do_scan(BX_KEY_D,1,0,alt); break;
+ case 'E': do_scan(BX_KEY_E,1,0,alt); break;
+ case 'F': do_scan(BX_KEY_F,1,0,alt); break;
+ case 'G': do_scan(BX_KEY_G,1,0,alt); break;
+
+
+ // HIJKLMNO
+ case 'H': do_scan(BX_KEY_H,1,0,alt); break;
+ case 'I': do_scan(BX_KEY_I,1,0,alt); break;
+ case 'J': do_scan(BX_KEY_J,1,0,alt); break;
+ case 'K': do_scan(BX_KEY_K,1,0,alt); break;
+ case 'L': do_scan(BX_KEY_L,1,0,alt); break;
+ case 'M': do_scan(BX_KEY_M,1,0,alt); break;
+ case 'N': do_scan(BX_KEY_N,1,0,alt); break;
+ case 'O': do_scan(BX_KEY_O,1,0,alt); break;
+
+
+ // PQRSTUVW
+ case 'P': do_scan(BX_KEY_P,1,0,alt); break;
+ case 'Q': do_scan(BX_KEY_Q,1,0,alt); break;
+ case 'R': do_scan(BX_KEY_R,1,0,alt); break;
+ case 'S': do_scan(BX_KEY_S,1,0,alt); break;
+ case 'T': do_scan(BX_KEY_T,1,0,alt); break;
+ case 'U': do_scan(BX_KEY_U,1,0,alt); break;
+ case 'V': do_scan(BX_KEY_V,1,0,alt); break;
+ case 'W': do_scan(BX_KEY_W,1,0,alt); break;
+
+ // XYZ[\]^_
+ case 'X': do_scan(BX_KEY_X,1,0,alt); break;
+ case 'Y': do_scan(BX_KEY_Y,1,0,alt); break;
+ case 'Z': do_scan(BX_KEY_Z,1,0,alt); break;
+ case '{': do_scan(BX_KEY_LEFT_BRACKET,1,0,alt); break;
+ case '|': do_scan(BX_KEY_BACKSLASH,1,0,alt); break;
+ case '}': do_scan(BX_KEY_RIGHT_BRACKET,1,0,alt); break;
+ case '_': do_scan(BX_KEY_MINUS,1,0,alt); break;
+
+ // `abcdefg
+ case '`': do_scan(BX_KEY_GRAVE,0,0,alt); break;
+ case 'a': do_scan(BX_KEY_A,0,0,alt); break;
+ case 'b': do_scan(BX_KEY_B,0,0,alt); break;
+ case 'c': do_scan(BX_KEY_C,0,0,alt); break;
+ case 'd': do_scan(BX_KEY_D,0,0,alt); break;
+ case 'e': do_scan(BX_KEY_E,0,0,alt); break;
+ case 'f': do_scan(BX_KEY_F,0,0,alt); break;
+ case 'g': do_scan(BX_KEY_G,0,0,alt); break;
+
+ // hijklmno
+ case 'h': do_scan(BX_KEY_H,0,0,alt); break;
+ case 'i': do_scan(BX_KEY_I,0,0,alt); break;
+ case 'j': do_scan(BX_KEY_J,0,0,alt); break;
+ case 'k': do_scan(BX_KEY_K,0,0,alt); break;
+ case 'l': do_scan(BX_KEY_L,0,0,alt); break;
+ case 'm': do_scan(BX_KEY_M,0,0,alt); break;
+ case 'n': do_scan(BX_KEY_N,0,0,alt); break;
+ case 'o': do_scan(BX_KEY_O,0,0,alt); break;
+
+ // pqrstuvw
+ case 'p': do_scan(BX_KEY_P,0,0,alt); break;
+ case 'q': do_scan(BX_KEY_Q,0,0,alt); break;
+ case 'r': do_scan(BX_KEY_R,0,0,alt); break;
+ case 's': do_scan(BX_KEY_S,0,0,alt); break;
+ case 't': do_scan(BX_KEY_T,0,0,alt); break;
+ case 'u': do_scan(BX_KEY_U,0,0,alt); break;
+ case 'v': do_scan(BX_KEY_V,0,0,alt); break;
+ case 'w': do_scan(BX_KEY_W,0,0,alt); break;
+
+ // xyz{|}~
+ case 'x': do_scan(BX_KEY_X,0,0,alt); break;
+ case 'y': do_scan(BX_KEY_Y,0,0,alt); break;
+ case 'z': do_scan(BX_KEY_Z,0,0,alt); break;
+ case '[': do_scan(BX_KEY_LEFT_BRACKET,0,0,alt); break;
+ case '\\': do_scan(BX_KEY_BACKSLASH,0,0,alt); break;
+ case ']': do_scan(BX_KEY_RIGHT_BRACKET,0,0,alt); break;
+ case '~': do_scan(BX_KEY_GRAVE,1,0,alt); break;
+
+ // function keys
+ case KEY_F(1): do_scan(BX_KEY_F1,0,0,alt); break;
+ case KEY_F(2): do_scan(BX_KEY_F2,0,0,alt); break;
+ case KEY_F(3): do_scan(BX_KEY_F3,0,0,alt); break;
+ case KEY_F(4): do_scan(BX_KEY_F4,0,0,alt); break;
+ case KEY_F(5): do_scan(BX_KEY_F5,0,0,alt); break;
+ case KEY_F(6): do_scan(BX_KEY_F6,0,0,alt); break;
+ case KEY_F(7): do_scan(BX_KEY_F7,0,0,alt); break;
+ case KEY_F(8): do_scan(BX_KEY_F8,0,0,alt); break;
+ case KEY_F(9): do_scan(BX_KEY_F9,0,0,alt); break;
+ case KEY_F(10): do_scan(BX_KEY_F10,0,0,alt); break;
+ case KEY_F(11): do_scan(BX_KEY_F11,0,0,alt); break;
+ case KEY_F(12): do_scan(BX_KEY_F12,0,0,alt); break;
+
+ // shifted function keys
+ case KEY_F(13): do_scan(BX_KEY_F1,1,0,alt); break;
+ case KEY_F(14): do_scan(BX_KEY_F2,1,0,alt); break;
+ case KEY_F(15): do_scan(BX_KEY_F3,1,0,alt); break;
+ case KEY_F(16): do_scan(BX_KEY_F4,1,0,alt); break;
+ case KEY_F(17): do_scan(BX_KEY_F5,1,0,alt); break;
+ case KEY_F(18): do_scan(BX_KEY_F6,1,0,alt); break;
+ case KEY_F(19): do_scan(BX_KEY_F7,1,0,alt); break;
+ case KEY_F(20): do_scan(BX_KEY_F8,1,0,alt); break;
+
+ default:
+ if(character > 0x79) {
+ do_char(character - 0x80,1);
+ break;
+ }
+
+ BX_INFO(("character unhandled: 0x%x",character));
+ break;
+ }
+}
+
+
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+ void
+bx_term_gui_c::handle_events(void)
+{
+ int character;
+ while((character = getch()) != ERR) {
+ BX_DEBUG(("scancode(0x%x)",character));
+ do_char(character,0);
+ }
+}
+
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+ void
+bx_term_gui_c::flush(void)
+{
+ if (initialized)
+ refresh();
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared. Don't
+// clear the area that defines the headerbar.
+
+ void
+bx_term_gui_c::clear_screen(void)
+{
+ clear();
+#if BX_HAVE_COLOR_SET
+ color_set(7, NULL);
+#endif
+#if BX_HAVE_MVHLINE
+ if (LINES > (int)text_rows) {
+ mvhline(text_rows, 0, ACS_HLINE, text_cols);
+ }
+#endif
+#if BX_HAVE_MVVLINE
+ if (COLS > (int)text_cols) {
+ mvvline(0, text_cols, ACS_VLINE, text_rows);
+ }
+#endif
+ if ((LINES > (int)text_rows) && (COLS > (int)text_cols)) {
+ mvaddch(text_rows, text_cols, ACS_LRCORNER);
+ }
+}
+
+int
+get_color_pair(Bit8u vga_attr)
+{
+ int term_attr;
+
+ term_attr = curses_color[vga_attr & 0x07];
+ term_attr |= (curses_color[(vga_attr & 0x70) >> 4] << 3);
+ return term_attr;
+}
+
+chtype
+get_term_char(Bit8u vga_char[])
+{
+ int term_char;
+
+ if ((vga_char[1] & 0x0f) == ((vga_char[1] >> 4) & 0x0f)) {
+ return ' ';
+ }
+ switch (vga_char[0]) {
+ case 0x04: term_char = ACS_DIAMOND; break;
+ case 0x18: term_char = ACS_UARROW; break;
+ case 0x19: term_char = ACS_DARROW; break;
+ case 0x1a: term_char = ACS_RARROW; break;
+ case 0x1b: term_char = ACS_LARROW; break;
+ case 0xc4:
+ case 0xcd: term_char = ACS_HLINE; break;
+ case 0xb3:
+ case 0xba: term_char = ACS_VLINE; break;
+ case 0xc9:
+ case 0xd5:
+ case 0xd6:
+ case 0xda: term_char = ACS_ULCORNER; break;
+ case 0xb7:
+ case 0xb8:
+ case 0xbb:
+ case 0xbf: term_char = ACS_URCORNER; break;
+ case 0xc0:
+ case 0xc8:
+ case 0xd3:
+ case 0xd4: term_char = ACS_LLCORNER; break;
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xd9: term_char = ACS_LRCORNER; break;
+ case 0xc3:
+ case 0xc6:
+ case 0xc7:
+ case 0xcc: term_char = ACS_LTEE; break;
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb9: term_char = ACS_RTEE; break;
+ case 0xc2:
+ case 0xcb:
+ case 0xd1:
+ case 0xd2: term_char = ACS_TTEE; break;
+ case 0xc1:
+ case 0xca:
+ case 0xcf:
+ case 0xd0: term_char = ACS_BTEE; break;
+ case 0xc5:
+ case 0xce:
+ case 0xd7:
+ case 0xd8: term_char = ACS_PLUS; break;
+ case 0xb0:
+ case 0xb1: term_char = ACS_CKBOARD; break;
+ case 0xb2: term_char = ACS_BOARD; break;
+ case 0xdb: term_char = ACS_BLOCK; break;
+ default:
+ if (vga_char[0] > 0x7f) {
+ term_char = vga_to_term[vga_char[0]-0x80];
+ } else if (vga_char[0] > 0x1f) {
+ term_char = vga_char[0];
+ } else {
+ term_char = ' ';
+ }
+ }
+ return term_char;
+}
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+// of the screen from the last call. See below
+// new_text: array of character/attributes making up the current
+// contents, which should now be displayed. See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+// This represents 80 characters wide by 25 high, with
+// each character being 2 bytes. The first by is the
+// character value, the second is the attribute byte.
+// I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+ void
+bx_term_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+ unsigned long cursor_x, unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+ unsigned char *old_line, *new_line, *new_start;
+ unsigned char cAttr;
+ unsigned int hchars, rows, x, y;
+ chtype ch;
+ bx_bool force_update = 0;
+
+ UNUSED(nrows);
+
+ if(charmap_updated) {
+ force_update = 1;
+ charmap_updated = 0;
+ }
+
+ new_start = new_text;
+ rows = text_rows;
+ y = 0;
+ do {
+ hchars = text_cols;
+ new_line = new_text;
+ old_line = old_text;
+ x = 0;
+ do {
+ if (force_update || (old_text[0] != new_text[0])
+ || (old_text[1] != new_text[1])) {
+#if BX_HAVE_COLOR_SET
+ if (has_colors()) {
+ color_set(get_color_pair(new_text[1]), NULL);
+ }
+#endif
+ ch = get_term_char(&new_text[0]);
+ if ((new_text[1] & 0x08) > 0) ch |= A_BOLD;
+ if ((new_text[1] & 0x80) > 0) ch |= A_BLINK;
+ mvaddch(y, x, ch);
+ }
+ x++;
+ new_text+=2;
+ old_text+=2;
+ } while (--hchars);
+ y++;
+ new_text = new_line + tm_info.line_offset;
+ old_text = old_line + tm_info.line_offset;
+ } while (--rows);
+
+ if ((cursor_x<text_cols) && (cursor_y<text_rows)
+ && (tm_info.cs_start <= tm_info.cs_end)) {
+ if(cursor_x>0)
+ cursor_x--;
+ else {
+ cursor_x=COLS-1;
+ cursor_y--;
+ }
+ cAttr = new_start[cursor_y*tm_info.line_offset+cursor_x*2+1];
+#if BX_HAVE_COLOR_SET
+ if (has_colors()) {
+ color_set(get_color_pair(cAttr), NULL);
+ }
+#endif
+ ch = get_term_char(&new_start[cursor_y*tm_info.line_offset+cursor_x*2]);
+ if ((cAttr & 0x08) > 0) ch |= A_BOLD;
+ if ((cAttr & 0x80) > 0) ch |= A_REVERSE;
+ mvaddch(cursor_y, cursor_x, ch);
+ curs_set(2);
+ } else {
+ curs_set(0);
+ }
+}
+
+ int
+bx_term_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ return 0;
+}
+
+ int
+bx_term_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+// 1=screen updated needed (redraw using current colormap)
+
+ bx_bool
+bx_term_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+ BX_DEBUG(("color pallete request (%d,%d,%d,%d) ignored",
+ index,red,green,blue));
+ return(0);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+// dimension equal to the 'tilewidth' & 'tileheight' parameters to
+// ::specific_init(). Each value specifies an index into the
+// array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+// left of the window.
+
+ void
+bx_term_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+ UNUSED(tile);
+ UNUSED(x0);
+ UNUSED(y0);
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+ void
+bx_term_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+ if (bpp > 8) {
+ BX_PANIC(("%d bpp graphics mode not supported", bpp));
+ }
+ if (fheight > 0) {
+ text_cols = x / fwidth;
+ text_rows = y / fheight;
+#if BX_HAVE_COLOR_SET
+ color_set(7, NULL);
+#endif
+#if BX_HAVE_MVHLINE
+ if (LINES > (int)text_rows) {
+ mvhline(text_rows, 0, ACS_HLINE, text_cols);
+ }
+#endif
+#if BX_HAVE_MVVLINE
+ if (COLS > (int)text_cols) {
+ mvvline(0, text_cols, ACS_VLINE, text_rows);
+ }
+#endif
+ if ((LINES > (int)text_rows) && (COLS > (int)text_cols)) {
+ mvaddch(text_rows, text_cols, ACS_LRCORNER);
+ }
+ }
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar. Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap. The pixel order is:
+// bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+ unsigned
+bx_term_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+ UNUSED(bmap);
+ UNUSED(xdim);
+ UNUSED(ydim);
+ return(0);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+// ::create_bitmap(). 'alignment' is either BX_GRAVITY_LEFT
+// or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+// meaning install the bitmap in the next
+// available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+// the boundaries of this bitmap.
+
+ unsigned
+bx_term_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+ UNUSED(bmap_id);
+ UNUSED(alignment);
+ UNUSED(f);
+ return(0);
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+ void
+bx_term_gui_c::show_headerbar(void)
+{
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'. 'bmap_id' will have
+// been generated by ::create_bitmap(). The old and new bitmap
+// must be of the same size. This allows the bitmap the user
+// sees to change, when some action occurs. For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+ void
+bx_term_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+ UNUSED(hbar_id);
+ UNUSED(bmap_id);
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+
+ void
+bx_term_gui_c::exit(void)
+{
+ if (!initialized) return;
+ clear();
+ flush();
+ endwin();
+ BX_DEBUG(("exiting"));
+}
+
+ void
+bx_term_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+#endif /* if BX_WITH_TERM */
diff --git a/tools/ioemu/gui/textconfig.cc b/tools/ioemu/gui/textconfig.cc
new file mode 100644
index 0000000000..7b5b098453
--- /dev/null
+++ b/tools/ioemu/gui/textconfig.cc
@@ -0,0 +1,995 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: textconfig.cc,v 1.18 2003/10/24 15:39:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This is code for a text-mode configuration interface. Note that this file
+// does NOT include bochs.h. Instead, it does all of its contact with
+// the simulator through an object called SIM, defined in siminterface.cc
+// and siminterface.h. This separation adds an extra layer of method
+// calls before any work can be done, but the benefit is that the compiler
+// enforces the rules. I can guarantee that textconfig.cc doesn't call any
+// I/O device objects directly, for example, because the bx_devices symbol
+// isn't even defined in this context.
+//
+
+#include "config.h"
+
+extern "C" {
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+}
+#include "osdep.h"
+#include "textconfig.h"
+#include "siminterface.h"
+#include "extplugin.h"
+#ifdef WIN32
+#include "win32dialog.h"
+#endif
+
+#define CI_PATH_LENGTH 512
+
+#define BX_INSERTED 11
+
+/* functions for changing particular options */
+void bx_config_interface_init ();
+int bx_read_rc (char *rc);
+int bx_write_rc (char *rc);
+void bx_log_options (int individual);
+
+/******************************************************************/
+/* lots of code stolen from bximage.c */
+/* remove leading spaces, newline junk at end. returns pointer to
+ cleaned string, which is between s0 and the null */
+char *
+clean_string (char *s0)
+{
+ char *s = s0;
+ char *ptr;
+ /* find first nonblank */
+ while (isspace (*s))
+ s++;
+ /* truncate string at first non-alphanumeric */
+ ptr = s;
+ while (isprint (*ptr))
+ ptr++;
+ *ptr = 0;
+ return s;
+}
+
+void
+double_percent (char *s, int max_len)
+{
+ char d[CI_PATH_LENGTH];
+ int i=0,j=0;
+
+ if (max_len>CI_PATH_LENGTH)
+ max_len=CI_PATH_LENGTH;
+
+ max_len--;
+
+ while((s[i]!=0)&&(j<max_len))
+ {
+ d[j++]=s[i];
+ if((s[i]=='%')&&(j<max_len))
+ {
+ d[j++]=s[i];
+ }
+ i++;
+ }
+ d[j]=0;
+ strcpy(s,d);
+}
+
+/* returns 0 on success, -1 on failure. The value goes into out. */
+int
+ask_uint (char *prompt, Bit32u min, Bit32u max, Bit32u the_default, Bit32u *out, int base)
+{
+ Bit32u n = max + 1;
+ char buffer[1024];
+ char *clean;
+ int illegal;
+ assert (base==10 || base==16);
+ while (1) {
+ printf (prompt, the_default);
+ if (!fgets (buffer, sizeof(buffer), stdin))
+ return -1;
+ clean = clean_string (buffer);
+ if (strlen(clean) < 1) {
+ // empty line, use the default
+ *out = the_default;
+ return 0;
+ }
+ const char *format = (base==10) ? "%d" : "%x";
+ illegal = (1 != sscanf (buffer, format, &n));
+ if (illegal || n<min || n>max) {
+ printf ("Your choice (%s) was not an integer between %u and %u.\n\n",
+ clean, min, max);
+ } else {
+ // choice is okay
+ *out = n;
+ return 0;
+ }
+ }
+}
+
+// identical to ask_uint, but uses signed comparisons
+int
+ask_int (char *prompt, Bit32s min, Bit32s max, Bit32s the_default, Bit32s *out)
+{
+ int n = max + 1;
+ char buffer[1024];
+ char *clean;
+ int illegal;
+ while (1) {
+ printf (prompt, the_default);
+ if (!fgets (buffer, sizeof(buffer), stdin))
+ return -1;
+ clean = clean_string (buffer);
+ if (strlen(clean) < 1) {
+ // empty line, use the default
+ *out = the_default;
+ return 0;
+ }
+ illegal = (1 != sscanf (buffer, "%d", &n));
+ if (illegal || n<min || n>max) {
+ printf ("Your choice (%s) was not an integer between %d and %d.\n\n",
+ clean, min, max);
+ } else {
+ // choice is okay
+ *out = n;
+ return 0;
+ }
+ }
+}
+
+int
+ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out)
+{
+ char buffer[1024];
+ char *clean;
+ int i;
+ *out = -1;
+ while (1) {
+ printf (prompt, choice[the_default]);
+ if (!fgets (buffer, sizeof(buffer), stdin))
+ return -1;
+ clean = clean_string (buffer);
+ if (strlen(clean) < 1) {
+ // empty line, use the default
+ *out = the_default;
+ return 0;
+ }
+ for (i=0; i<n_choices; i++) {
+ if (!strcmp (choice[i], clean)) {
+ // matched, return the choice number
+ *out = i;
+ return 0;
+ }
+ }
+ if (clean[0] != '?')
+ printf ("Your choice (%s) did not match any of the choices:\n", clean);
+ for (i=0; i<n_choices; i++) {
+ if (i>0) printf (", ");
+ printf ("%s", choice[i]);
+ }
+ printf ("\n");
+ }
+}
+
+int
+ask_yn (char *prompt, Bit32u the_default, Bit32u *out)
+{
+ char buffer[16];
+ char *clean;
+ *out = 1<<31;
+ while (1) {
+ // if there's a %s field, substitute in the default yes/no.
+ printf (prompt, the_default ? "yes" : "no");
+ if (!fgets (buffer, sizeof(buffer), stdin))
+ return -1;
+ clean = clean_string (buffer);
+ if (strlen(clean) < 1) {
+ // empty line, use the default
+ *out = the_default;
+ return 0;
+ }
+ switch (tolower(clean[0])) {
+ case 'y': *out=1; return 0;
+ case 'n': *out=0; return 0;
+ }
+ printf ("Please type either yes or no.\n");
+ }
+}
+
+// returns -1 on error (stream closed or something)
+// returns 0 if default was taken
+// returns 1 if value changed
+int
+ask_string (char *prompt, char *the_default, char *out)
+{
+ char buffer[1024];
+ char *clean;
+ assert (the_default != out);
+ out[0] = 0;
+ printf (prompt, the_default);
+ if (fgets (buffer, sizeof(buffer), stdin) == NULL)
+ return -1;
+ clean = clean_string (buffer);
+ if (strlen(clean) < 1) {
+ // empty line, use the default
+ strcpy (out, the_default);
+ return 0;
+ }
+ strcpy (out, clean);
+ return 1;
+}
+
+/******************************************************************/
+
+static char *startup_menu_prompt =
+"------------------------------\n"
+"Bochs Configuration: Main Menu\n"
+"------------------------------\n"
+"\n"
+"This is the Bochs Configuration Interface, where you can describe the\n"
+"machine that you want to simulate. Bochs has already searched for a\n"
+"configuration file (typically called bochsrc.txt) and loaded it if it\n"
+"could be found. When you are satisfied with the configuration, go\n"
+"ahead and start the simulation.\n"
+"\n"
+"You can also start bochs with the -q option to skip these menus.\n"
+"\n"
+"1. Restore factory default configuration\n"
+"2. Read options from...\n"
+"3. Edit options\n"
+"4. Save options to...\n"
+"5. Begin simulation\n"
+"6. Quit now\n"
+"\n"
+"Please choose one: [%d] ";
+
+static char *startup_options_prompt =
+"------------------\n"
+"Bochs Options Menu\n"
+"------------------\n"
+"0. Return to previous menu\n"
+"1. Log file: %s\n"
+"2. Log prefix: %s\n"
+"3. Debug log file: %s\n"
+"4. Log options for all devices\n"
+"5. Log options for individual devices\n"
+"6. Memory options\n"
+"7. Interface options\n"
+"8. Disk options\n"
+"9. Serial or Parallel port options\n"
+"10. Sound Blaster 16 options\n"
+"11. NE2000 network card options\n"
+"12. Keyboard options\n"
+"13. Other options\n"
+"\n"
+"Please choose one: [0] ";
+
+static char *runtime_menu_prompt =
+"---------------------\n"
+"Bochs Runtime Options\n"
+"---------------------\n"
+"1. Floppy disk 0: %s\n"
+"2. Floppy disk 1: %s\n"
+"3. 1st CDROM: %s\n"
+"4. 2nd CDROM: %s\n"
+"5. 3rd CDROM: %s\n"
+"6. 4th CDROM: %s\n"
+"7. (not implemented)\n"
+"8. Log options for all devices\n"
+"9. Log options for individual devices\n"
+"10. VGA Update Interval: %d\n"
+"11. Mouse: %s\n"
+"12. Keyboard paste delay: %d\n"
+"13. Userbutton shortcut: %s\n"
+"14. Instruction tracing: off (doesn't exist yet)\n"
+"15. Continue simulation\n"
+"16. Quit now\n"
+"\n"
+"Please choose one: [15] ";
+
+#define NOT_IMPLEMENTED(choice) \
+ fprintf (stderr, "ERROR: choice %d not implemented\n", choice);
+
+#define BAD_OPTION(menu,choice) \
+ do {fprintf (stderr, "ERROR: menu %d has no choice %d\n", menu, choice); \
+ assert (0); } while (0)
+
+void build_runtime_options_prompt (char *format, char *buf, int size)
+{
+ bx_floppy_options floppyop;
+ bx_atadevice_options cdromop;
+/* bx_param_num_c *ips = SIM->get_param_num (BXP_IPS); */
+ char buffer[6][128];
+ for (int i=0; i<2; i++) {
+ SIM->get_floppy_options (i, &floppyop);
+ if (floppyop.Odevtype->get () == BX_FLOPPY_NONE)
+ strcpy (buffer[i], "(not present)");
+ else {
+ sprintf (buffer[i], "%s, size=%s, %s", floppyop.Opath->getptr (),
+ SIM->get_floppy_type_name (floppyop.Otype->get ()),
+ (floppyop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected");
+ if (!floppyop.Opath->getptr ()[0]) strcpy (buffer[i], "none");
+ }
+ }
+
+ // 4 cdroms supported at run time
+ int device;
+ for (Bit8u cdrom=0; cdrom<4; cdrom++) {
+ if (!SIM->get_cdrom_options (cdrom, &cdromop, &device) || !cdromop.Opresent->get ())
+ sprintf (buffer[2+cdrom], "(not present)");
+ else
+ sprintf (buffer[2+cdrom], "(%s on ata%d) %s, %s",
+ device&1?"slave":"master", device/2, cdromop.Opath->getptr (),
+ (cdromop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected");
+ }
+
+ snprintf (buf, size, format, buffer[0], buffer[1], buffer[2],
+ buffer[3], buffer[4], buffer[5],
+ /* ips->get (), */
+ SIM->get_param_num (BXP_VGA_UPDATE_INTERVAL)->get (),
+ SIM->get_param_num (BXP_MOUSE_ENABLED)->get () ? "enabled" : "disabled",
+ SIM->get_param_num (BXP_KBD_PASTE_DELAY)->get (),
+ SIM->get_param_string (BXP_USER_SHORTCUT)->getptr ());
+}
+
+int do_menu (bx_id id) {
+ bx_list_c *menu = (bx_list_c *)SIM->get_param (id);
+ while (1) {
+ menu->get_choice()->set (0);
+ int status = menu->text_ask (stdin, stderr);
+ if (status < 0) return status;
+ bx_param_num_c *choice = menu->get_choice();
+ if (choice->get () < 1)
+ return choice->get ();
+ else {
+ int index = choice->get () - 1; // choosing 1 means list[0]
+ bx_param_c *chosen = menu->get (index);
+ assert (chosen != NULL);
+ chosen->text_ask (stdin, stderr);
+ }
+ }
+}
+
+void askparam (bx_id id)
+{
+ bx_param_c *param = SIM->get_param (id);
+ param->text_ask (stdin, stderr);
+}
+
+int bx_config_interface (int menu)
+{
+ Bit32u choice;
+ while (1) {
+ switch (menu)
+ {
+ case BX_CI_INIT:
+ bx_config_interface_init ();
+ return 0;
+ case BX_CI_START_SIMULATION: {
+ SIM->begin_simulation (bx_startup_flags.argc, bx_startup_flags.argv);
+ // we don't expect it to return, but if it does, quit
+ SIM->quit_sim(1);
+ break;
+ }
+ case BX_CI_START_MENU:
+ {
+ Bit32u default_choice;
+ switch (SIM->get_param_enum(BXP_BOCHS_START)->get ()) {
+ case BX_LOAD_START:
+ default_choice = 2; break;
+ case BX_EDIT_START:
+ default_choice = 3; break;
+ default:
+ default_choice = 5; break;
+ }
+
+ if (ask_uint (startup_menu_prompt, 1, 6, default_choice, &choice, 10) < 0) return -1;
+ switch (choice) {
+ case 1:
+ fprintf (stderr, "I reset all options back to their factory defaults.\n\n");
+ SIM->reset_all_param ();
+ SIM->get_param_enum(BXP_BOCHS_START)->set(BX_EDIT_START);
+ break;
+ case 2:
+ // Before reading a new configuration, reset every option to its
+ // original state.
+ SIM->reset_all_param ();
+ if (bx_read_rc (NULL) >= 0)
+ SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START);
+ break;
+ case 3:
+ bx_config_interface (BX_CI_START_OPTS);
+ SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START);
+ break;
+ case 4: bx_write_rc (NULL); break;
+ case 5: bx_config_interface (BX_CI_START_SIMULATION); break;
+ case 6: SIM->quit_sim (1); return -1;
+ default: BAD_OPTION(menu, choice);
+ }
+ }
+ break;
+ case BX_CI_START_OPTS:
+ {
+ char prompt[CI_PATH_LENGTH];
+ char oldpath[CI_PATH_LENGTH];
+ char olddebuggerpath[CI_PATH_LENGTH];
+ char oldprefix[CI_PATH_LENGTH];
+ int retval;
+
+ retval = SIM->get_log_file (oldpath, CI_PATH_LENGTH);
+ assert (retval >= 0);
+ double_percent(oldpath,CI_PATH_LENGTH);
+ retval = SIM->get_log_prefix (oldprefix, CI_PATH_LENGTH);
+ assert (retval >= 0);
+ double_percent(oldprefix,CI_PATH_LENGTH);
+ retval = SIM->get_debugger_log_file (olddebuggerpath, CI_PATH_LENGTH);
+ assert (retval >= 0);
+ double_percent(olddebuggerpath,CI_PATH_LENGTH);
+
+ sprintf (prompt, startup_options_prompt, oldpath, oldprefix, olddebuggerpath);
+ if (ask_uint (prompt, 0, 13, 0, &choice, 10) < 0) return -1;
+ switch (choice) {
+ case 0: return 0;
+ case 1: askparam (BXP_LOG_FILENAME); break;
+ case 2: askparam (BXP_LOG_PREFIX); break;
+ case 3: askparam (BXP_DEBUGGER_LOG_FILENAME); break;
+ case 4: bx_log_options (0); break;
+ case 5: bx_log_options (1); break;
+ case 6: do_menu (BXP_MENU_MEMORY); break;
+ case 7: do_menu (BXP_MENU_INTERFACE); break;
+ case 8: do_menu (BXP_MENU_DISK); break;
+ case 9: do_menu (BXP_MENU_SERIAL_PARALLEL); break;
+ case 10: do_menu (BXP_SB16); break;
+ case 11: do_menu (BXP_NE2K); break;
+ case 12: do_menu (BXP_MENU_KEYBOARD); break;
+ case 13: do_menu (BXP_MENU_MISC); break;
+ default: BAD_OPTION(menu, choice);
+ }
+ }
+ break;
+ case BX_CI_RUNTIME:
+ char prompt[1024];
+ bx_floppy_options floppyop;
+ bx_atadevice_options cdromop;
+ build_runtime_options_prompt (runtime_menu_prompt, prompt, 1024);
+ if (ask_uint (prompt, 1, 16, 15, &choice, 10) < 0) return -1;
+ switch (choice) {
+ case 1:
+ SIM->get_floppy_options (0, &floppyop);
+ if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYA);
+ break;
+ case 2:
+ SIM->get_floppy_options (1, &floppyop);
+ if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYB);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ int device;
+ if (SIM->get_cdrom_options (choice - 3, &cdromop, &device) && cdromop.Opresent->get ()) {
+ // disable type selection
+ SIM->get_param((bx_id)(BXP_ATA0_MASTER_TYPE + device))->set_enabled(0);
+ SIM->get_param((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled(0);
+ SIM->get_param((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled(0);
+ do_menu ((bx_id)(BXP_ATA0_MASTER + device));
+ }
+ break;
+ case 7: // not implemented yet because I would have to mess with
+ // resetting timers and pits and everything on the fly.
+ // askparam (BXP_IPS);
+ break;
+ case 8: bx_log_options (0); break;
+ case 9: bx_log_options (1); break;
+ case 10: askparam (BXP_VGA_UPDATE_INTERVAL); break;
+ case 11: askparam (BXP_MOUSE_ENABLED); break;
+ case 12: askparam (BXP_KBD_PASTE_DELAY); break;
+ case 13: askparam (BXP_USER_SHORTCUT); break;
+ case 14: NOT_IMPLEMENTED (choice); break;
+ case 15: fprintf (stderr, "Continuing simulation\n"); return 0;
+ case 16:
+ fprintf (stderr, "You chose quit on the configuration interface.\n");
+ SIM->quit_sim (1);
+ return -1;
+ default: fprintf (stderr, "Menu choice %d not implemented.\n", choice);
+ }
+ break;
+ default:
+ fprintf (stderr, "Unknown config interface menu type.\n");
+ assert (menu >=0 && menu < BX_CI_N_MENUS);
+ }
+ }
+}
+
+static void bx_print_log_action_table ()
+{
+ // just try to print all the prefixes first.
+ fprintf (stderr, "Current log settings:\n");
+ fprintf (stderr, " Debug Info Error Panic Pass\n");
+ fprintf (stderr, "ID Device Action Action Action Action Action\n");
+ fprintf (stderr, "---- --------- --------- --------- ---------- ---------- ----------\n");
+ int i, j, imax=SIM->get_n_log_modules ();
+ for (i=0; i<imax; i++) {
+ if (strcmp(SIM->get_prefix(i), "[ ]")) {
+ fprintf (stderr, "%3d. %s ", i, SIM->get_prefix (i));
+ for (j=0; j<SIM->get_max_log_level (); j++) {
+ fprintf (stderr, "%10s ", SIM->get_action_name (SIM->get_log_action (i, j)));
+ }
+ fprintf (stderr, "\n");
+ }
+ }
+}
+
+static char *log_options_prompt1 = "Enter the ID of the device to edit, or -1 to return: [-1] ";
+static char *log_level_choices[] = { "ignore", "report", "ask", "fatal", "no change" };
+static int log_level_n_choices_normal = 4;
+
+void bx_log_options (int individual)
+{
+ if (individual) {
+ int done = 0;
+ while (!done) {
+ bx_print_log_action_table ();
+ Bit32s id, level, action;
+ Bit32s maxid = SIM->get_n_log_modules ();
+ if (ask_int (log_options_prompt1, -1, maxid-1, -1, &id) < 0)
+ return;
+ if (id < 0) return;
+ fprintf (stderr, "Editing log options for the device %s\n", SIM->get_prefix (id));
+ for (level=0; level<SIM->get_max_log_level (); level++) {
+ char prompt[1024];
+ int default_action = SIM->get_log_action (id, level);
+ sprintf (prompt, "Enter action for %s event: [%s] ", SIM->get_log_level_name (level), SIM->get_action_name(default_action));
+ // don't show the no change choice (choices=3)
+ if (ask_menu (prompt, log_level_n_choices_normal, log_level_choices, default_action, &action)<0)
+ return;
+ SIM->set_log_action (id, level, action);
+ }
+ }
+ } else {
+ // provide an easy way to set log options for all devices at once
+ bx_print_log_action_table ();
+ for (int level=0; level<SIM->get_max_log_level (); level++) {
+ char prompt[1024];
+ int action, default_action = 3; // default to no change
+ sprintf (prompt, "Enter action for %s event on all devices: [no change] ", SIM->get_log_level_name (level));
+ // do show the no change choice (choices=4)
+ if (ask_menu (prompt, log_level_n_choices_normal+1, log_level_choices, default_action, &action)<0)
+ return;
+ if (action < 3) {
+ SIM->set_default_log_action (level, action);
+ SIM->set_log_action (-1, level, action);
+ }
+ }
+ }
+}
+
+int bx_read_rc (char *rc)
+{
+ if (rc && SIM->read_rc (rc) >= 0) return 0;
+ char oldrc[CI_PATH_LENGTH];
+ if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0)
+ strcpy (oldrc, "none");
+ char newrc[CI_PATH_LENGTH];
+ while (1) {
+ if (ask_string ("\nWhat is the configuration file name?\nTo cancel, type 'none'. [%s] ", oldrc, newrc) < 0) return -1;
+ if (!strcmp (newrc, "none")) return -1;
+ if (SIM->read_rc (newrc) >= 0) return 0;
+ fprintf (stderr, "The file '%s' could not be found.\n", newrc);
+ }
+}
+
+int bx_write_rc (char *rc)
+{
+ char oldrc[CI_PATH_LENGTH], newrc[CI_PATH_LENGTH];
+ if (rc == NULL) {
+ if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0)
+ strcpy (oldrc, "none");
+ } else {
+ strncpy (oldrc, rc, CI_PATH_LENGTH);
+ }
+ while (1) {
+ if (ask_string ("Save configuration to what file? To cancel, type 'none'.\n[%s] ", oldrc, newrc) < 0) return -1;
+ if (!strcmp (newrc, "none")) return 0;
+ // try with overwrite off first
+ int status = SIM->write_rc (newrc, 0);
+ if (status >= 0) {
+ fprintf (stderr, "Wrote configuration to '%s'.\n", newrc);
+ return 0;
+ } else if (status == -2) {
+ // return code -2 indicates the file already exists, and overwrite
+ // confirmation is required.
+ Bit32u overwrite = 0;
+ char prompt[256];
+ sprintf (prompt, "Configuration file '%s' already exists. Overwrite it? [no] ", newrc);
+ if (ask_yn (prompt, 0, &overwrite) < 0) return -1;
+ if (!overwrite) continue; // if "no", start loop over, asking for a different file
+ // they confirmed, so try again with overwrite bit set
+ if (SIM->write_rc (newrc, 1) >= 0) {
+ fprintf (stderr, "Overwriting existing configuration '%s'.\n", newrc);
+ return 0;
+ } else {
+ fprintf (stderr, "Write failed to '%s'.\n", newrc);
+ }
+ }
+ }
+}
+
+char *log_action_ask_choices[] = { "cont", "alwayscont", "die", "abort", "debug" };
+int log_action_n_choices = 4 + (BX_DEBUGGER?1:0);
+
+BxEvent *
+config_interface_notify_callback (void *unused, BxEvent *event)
+{
+#ifdef WIN32
+ int opts;
+ bx_param_c *param;
+ bx_param_string_c *sparam;
+#endif
+ event->retcode = -1;
+ switch (event->type)
+ {
+ case BX_SYNC_EVT_TICK:
+ event->retcode = 0;
+ return event;
+ case BX_SYNC_EVT_ASK_PARAM:
+#ifdef WIN32
+ param = event->u.param.param;
+ if (param->get_type() == BXT_PARAM_STRING) {
+ sparam = (bx_param_string_c *)param;
+ opts = sparam->get_options()->get();
+ if (opts & sparam->IS_FILENAME) {
+ if (param->get_id() == BXP_NULL) {
+ event->retcode = AskFilename(GetBochsWindow(), (bx_param_filename_c *)sparam);
+ } else {
+ event->retcode = FloppyDialog((bx_param_filename_c *)sparam);
+ }
+ return event;
+ } else {
+ event->retcode = AskString(sparam);
+ return event;
+ }
+ }
+#endif
+ event->u.param.param->text_ask (stdin, stderr);
+ return event;
+ case BX_SYNC_EVT_LOG_ASK:
+ {
+#ifdef WIN32
+ LogAskDialog(event);
+#else
+ int level = event->u.logmsg.level;
+ fprintf (stderr, "========================================================================\n");
+ fprintf (stderr, "Event type: %s\n", SIM->get_log_level_name (level));
+ fprintf (stderr, "Device: %s\n", event->u.logmsg.prefix);
+ fprintf (stderr, "Message: %s\n\n", event->u.logmsg.msg);
+ fprintf (stderr, "A %s has occurred. Do you want to:\n", SIM->get_log_level_name (level));
+ fprintf (stderr, " cont - continue execution\n");
+ fprintf (stderr, " alwayscont - continue execution, and don't ask again.\n");
+ fprintf (stderr, " This affects only %s events from device %s\n", SIM->get_log_level_name (level), event->u.logmsg.prefix);
+ fprintf (stderr, " die - stop execution now\n");
+ fprintf (stderr, " abort - dump core %s\n",
+ BX_HAVE_ABORT ? "" : "(Disabled)");
+#if BX_DEBUGGER
+ fprintf (stderr, " debug - continue and return to bochs debugger\n");
+#endif
+ int choice;
+ask:
+ if (ask_menu ("Choose one of the actions above: [%s] ",
+ log_action_n_choices, log_action_ask_choices, 2, &choice) < 0)
+ event->retcode = -1;
+ // return 0 for continue, 1 for alwayscontinue, 2 for die, 3 for debug.
+ if (!BX_HAVE_ABORT && choice==BX_LOG_ASK_CHOICE_DUMP_CORE) goto ask;
+ fflush(stdout);
+ fflush(stderr);
+ event->retcode = choice;
+#endif
+ }
+ return event;
+ case BX_ASYNC_EVT_REFRESH:
+ case BX_ASYNC_EVT_DBG_MSG:
+ // The text mode interface does not use these events, so just ignore
+ // them.
+ return event;
+ default:
+ fprintf (stderr, "Control panel: notify callback called with event type %04x\n", event->type);
+ return event;
+ }
+ assert (0); // switch statement should return
+}
+
+void bx_config_interface_init () {
+ //fprintf (stderr, "bx_config_interface_init()\n");
+ SIM->set_notify_callback (config_interface_notify_callback, NULL);
+}
+
+/////////////////////////////////////////////////////////////////////
+// implement the text_* methods for bx_param types.
+
+void
+bx_param_num_c::text_print (FILE *fp)
+{
+ //fprintf (fp, "number parameter, id=%u, name=%s\n", get_id (), get_name ());
+ //fprintf (fp, "value=%u\n", get ());
+ if (get_format ()) {
+ fprintf (fp, get_format (), get ());
+ } else {
+ char *format = "%s: %d";
+ assert (base==10 || base==16);
+ if (base==16) format = "%s: 0x%x";
+ fprintf (fp, format, get_name (), get ());
+ }
+}
+
+void
+bx_param_bool_c::text_print (FILE *fp)
+{
+ if (get_format ()) {
+ fprintf (fp, get_format (), get () ? "yes" : "no");
+ } else {
+ char *format = "%s: %s";
+ fprintf (fp, format, get_name (), get () ? "yes" : "no");
+ }
+}
+
+void
+bx_param_enum_c::text_print (FILE *fp)
+{
+ int n = get ();
+ assert (n >= min && n <= max);
+ char *choice = choices[n - min];
+ if (get_format ()) {
+ fprintf (fp, get_format (), choice);
+ } else {
+ char *format = "%s: %s";
+ fprintf (fp, format, get_name (), choice);
+ }
+}
+
+void
+bx_param_string_c::text_print (FILE *fp)
+{
+ char *value = getptr ();
+ int opts = options->get ();
+ if (opts & RAW_BYTES) {
+ char buffer[1024];
+ buffer[0] = 0;
+ char sep_string[2];
+ sep_string[0] = separator;
+ sep_string[1] = 0;
+ for (int i=0; i<maxsize; i++) {
+ char eachbyte[16];
+ sprintf (eachbyte, "%s%02x", (i>0)?sep_string : "", (unsigned int)0xff&val[i]);
+ strncat (buffer, eachbyte, sizeof(buffer));
+ }
+ if (strlen (buffer) > sizeof(buffer)-4) {
+ assert (0); // raw byte print buffer is probably overflowing. increase the max or make it dynamic
+ }
+ value = buffer;
+ }
+ if (get_format ()) {
+ fprintf (fp, get_format (), value);
+ } else {
+ fprintf (fp, "%s: %s", get_name (), value);
+ }
+}
+
+void
+bx_list_c::text_print (FILE *fp)
+{
+ //fprintf (fp, "This is a list.\n");
+ //fprintf (fp, "title=%s\n", title->getptr ());
+ fprintf (fp, "%s: ", get_name ());
+ /*
+ fprintf (fp, "options=%s%s%s\n",
+ (options->get () == 0) ? "none" : "",
+ (options->get () & SHOW_PARENT) ? "SHOW_PARENT " : "",
+ (options->get () & SERIES_ASK) ? "SERIES_ASK " : "");
+ */
+ for (int i=0; i<size; i++) {
+ //fprintf (fp, "param[%d] = %p\n", i, list[i]);
+ assert (list[i] != NULL);
+ if (list[i]->get_enabled ()) {
+ if ((i>0) && (options->get () & SERIES_ASK))
+ fprintf (fp, ", ");
+ list[i]->text_print (fp);
+ if (!(options->get () & SERIES_ASK))
+ fprintf (fp, "\n");
+ }
+ }
+}
+
+int
+bx_param_num_c::text_ask (FILE *fpin, FILE *fpout)
+{
+ fprintf (fpout, "\n");
+ int status;
+ char *prompt = get_ask_format ();
+ if (prompt == NULL) {
+ // default prompt, if they didn't set an ask format string
+ text_print (fpout);
+ fprintf (fpout, "\n");
+ prompt = "Enter new value: [%d] ";
+ if (base==16)
+ prompt = "Enter new value in hex: [%x] ";
+ }
+ Bit32u n = get ();
+ status = ask_uint (prompt, min, max, n, &n, base);
+ if (status < 0) return status;
+ set (n);
+ return 0;
+}
+
+int
+bx_param_bool_c::text_ask (FILE *fpin, FILE *fpout)
+{
+ fprintf (fpout, "\n");
+ int status;
+ char *prompt = get_ask_format ();
+ char buffer[512];
+ if (prompt == NULL) {
+ // default prompt, if they didn't set an ask format string
+ sprintf (buffer, "%s? [%%s] ", get_name ());
+ prompt = buffer;
+ }
+ Bit32u n = get ();
+ status = ask_yn (prompt, n, &n);
+ if (status < 0) return status;
+ set (n);
+ return 0;
+}
+
+int
+bx_param_enum_c::text_ask (FILE *fpin, FILE *fpout)
+{
+ fprintf (fpout, "\n");
+ char *prompt = get_ask_format ();
+ if (prompt == NULL) {
+ // default prompt, if they didn't set an ask format string
+ fprintf (fpout, "%s = ", get_name ());
+ text_print (fpout);
+ fprintf (fpout, "\n");
+ prompt = "Enter new value: [%s] ";
+ }
+ Bit32s n = (Bit32s)(get () - min);
+ int status = ask_menu (prompt, (max-min+1), choices, n, &n);
+ if (status < 0) return status;
+ n += (Bit32s)min;
+ set (n);
+ return 0;
+}
+
+int parse_raw_bytes (char *dest, char *src, int destsize, char separator)
+{
+ //printf ("parsing src='%s'\n", src);
+ int i;
+ unsigned int n;
+ for (i=0; i<destsize; i++)
+ dest[i] = 0;
+ for (i=0; i<destsize; i++) {
+ while (*src == separator)
+ src++;
+ if (*src == 0) break;
+ // try to read a byte of hex
+ if (sscanf (src, "%02x", &n) == 1) {
+ //printf ("found a byte %02x\n", n);
+ dest[i] = n;
+ src+=2;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+bx_param_string_c::text_ask (FILE *fpin, FILE *fpout)
+{
+ fprintf (fpout, "\n");
+ int status;
+ char *prompt = get_ask_format ();
+ if (prompt == NULL) {
+ // default prompt, if they didn't set an ask format string
+ text_print (fpout);
+ fprintf (fpout, "\n");
+ prompt = "Enter a new value, or press return for no change.\n";
+ }
+ while (1) {
+ char buffer[1024];
+ status = ask_string (prompt, getptr(), buffer);
+ if (status < 0) return status;
+ int opts = options->get ();
+ char buffer2[1024];
+ strcpy (buffer2, buffer);
+ if (status == 1 && opts & RAW_BYTES) {
+ // copy raw hex into buffer
+ status = parse_raw_bytes (buffer, buffer2, maxsize, separator);
+ if (status < 0) {
+ fprintf (fpout, "Illegal raw byte format. I expected something like 3A%c03%c12%c...\n", separator, separator, separator);
+ continue;
+ }
+ }
+ if (!equals (buffer))
+ set (buffer);
+ return 0;
+ }
+}
+
+int
+bx_list_c::text_ask (FILE *fpin, FILE *fpout)
+{
+ char *my_title = title->getptr ();
+ fprintf (fpout, "\n");
+ int i, imax = strlen (my_title);
+ for (i=0; i<imax; i++) fprintf (fpout, "-");
+ fprintf (fpout, "\n%s\n", my_title);
+ for (i=0; i<imax; i++) fprintf (fpout, "-");
+ fprintf (fpout, "\n"); //fprintf (fp, "options=%s\n", options->get ());
+ if (options->get () & SERIES_ASK) {
+ for (int i=0; i<size; i++) {
+ if (list[i]->get_enabled ())
+ list[i]->text_ask (fpin, fpout);
+ }
+ } else {
+ if (options->get () & SHOW_PARENT)
+ fprintf (fpout, "0. Return to previous menu\n");
+ for (int i=0; i<size; i++) {
+ assert (list[i] != NULL);
+ fprintf (fpout, "%d. ", i+1);
+ if (list[i]->get_enabled ()) {
+ list[i]->text_print (fpout);
+ fprintf (fpout, "\n");
+ } else
+ fprintf (fpout, "(disabled)\n");
+ }
+ fprintf (fpout, "\n");
+ Bit32u n = choice->get ();
+ int min = (options->get () & SHOW_PARENT) ? 0 : 1;
+ int max = size;
+ int status = ask_uint ("Please choose one: [%d] ", min, max, n, &n, 10);
+ if (status < 0) return status;
+ choice->set (n);
+ }
+ return 0;
+}
+
+static int ci_callback (void *userdata, ci_command_t command)
+{
+ switch (command)
+ {
+ case CI_START:
+ //fprintf (stderr, "textconfig.cc: start\n");
+ bx_config_interface_init ();
+ if (SIM->get_param_enum(BXP_BOCHS_START)->get () == BX_QUICK_START)
+ bx_config_interface (BX_CI_START_SIMULATION);
+ else {
+ if (!SIM->test_for_text_console ())
+ return CI_ERR_NO_TEXT_CONSOLE;
+ bx_config_interface (BX_CI_START_MENU);
+ }
+ break;
+ case CI_RUNTIME_CONFIG:
+ bx_config_interface (BX_CI_RUNTIME);
+ break;
+ case CI_SHUTDOWN:
+ //fprintf (stderr, "textconfig.cc: shutdown\n");
+ break;
+ }
+ return 0;
+}
+
+// if I can make things compile without this module linked in, then
+// this file can become a plugin too.
+int init_text_config_interface ()
+{
+ //fprintf (stderr, "plugin_init for textconfig.cc\n");
+ SIM->register_configuration_interface ("textconfig", ci_callback, NULL);
+ return 0; // success
+}
diff --git a/tools/ioemu/gui/textconfig.h b/tools/ioemu/gui/textconfig.h
new file mode 100644
index 0000000000..01687ca269
--- /dev/null
+++ b/tools/ioemu/gui/textconfig.h
@@ -0,0 +1,19 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: textconfig.h,v 1.1 2002/10/29 20:16:04 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+enum {
+ BX_CI_INIT,
+ BX_CI_START_MENU,
+ BX_CI_START_OPTS,
+ BX_CI_START_OPTS_MEM,
+ BX_CI_START_OPTS_INTERFACE,
+ BX_CI_START_OPTS_DISK,
+ BX_CI_START_OPTS_SOUND,
+ BX_CI_START_OPTS_MISC,
+ BX_CI_START_SIMULATION,
+ BX_CI_RUNTIME,
+ BX_CI_N_MENUS
+};
+
+int init_text_config_interface ();
diff --git a/tools/ioemu/gui/x.cc b/tools/ioemu/gui/x.cc
new file mode 100644
index 0000000000..5d1cae917a
--- /dev/null
+++ b/tools/ioemu/gui/x.cc
@@ -0,0 +1,1848 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: x.cc,v 1.76 2003/08/11 19:27:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#define XK_PUBLISHING
+#define XK_TECHNICAL
+
+// 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"
+#if BX_WITH_X11
+
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#if BX_HAVE_XPM_H
+#include <X11/xpm.h>
+#endif
+}
+
+#if BX_HAVE_XPM_H
+#include "icon_bochs.xpm"
+#else
+#include "icon_bochs.h"
+#endif
+
+#include "font/vga.bitmap.h"
+
+class bx_x_gui_c : public bx_gui_c {
+public:
+ bx_x_gui_c (void);
+ DECLARE_GUI_VIRTUAL_METHODS()
+#if BX_USE_IDLE_HACK
+ virtual void sim_is_idle(void);
+#endif
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_x_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(x)
+
+#define LOG_THIS theGui->
+
+#define MAX_MAPPED_STRING_LENGTH 10
+
+/* These are used as arguments to nearly every Xlib routine, so it saves
+ * routine arguments to declare them global. If there were
+ * additional source files, they would be declared extern there. */
+Display *bx_x_display;
+int bx_x_screen_num;
+static Colormap default_cmap;
+static unsigned long white_pixel=0, black_pixel=0;
+
+static char *progname; /* name this program was invoked by */
+
+static unsigned int text_rows=25, text_cols=80;
+static Bit8u h_panning = 0, v_panning = 0;
+
+static Window win;
+static GC gc, gc_inv, gc_headerbar, gc_headerbar_inv;
+static unsigned font_width, font_height;
+static unsigned dimension_x=0, dimension_y=0;
+static unsigned vga_bpp=8;
+
+static XImage *ximage = NULL;
+static unsigned imDepth, imWide, imBPP;
+
+// current cursor coordinates
+static int prev_x=-1, prev_y=-1;
+static int current_x=-1, current_y=-1;
+static unsigned mouse_button_state = 0;
+
+static unsigned prev_cursor_x=0;
+static unsigned prev_cursor_y=0;
+
+static int warp_home_x = 200;
+static int warp_home_y = 200;
+static int mouse_enable_x = 0;
+static int mouse_enable_y = 0;
+static int warp_dx = 0;
+static int warp_dy = 0;
+
+static void warp_cursor(int dx, int dy);
+static void disable_cursor();
+static void enable_cursor();
+
+static Bit32u convertStringToXKeysym (const char *string);
+
+static bx_bool x_init_done = false;
+
+static Pixmap vgafont[256];
+
+struct {
+ Pixmap bmap;
+ unsigned xdim;
+ unsigned ydim;
+ } bx_bitmaps[BX_MAX_PIXMAPS];
+unsigned bx_bitmap_entries = 0;
+
+static struct {
+ Pixmap bitmap;
+ unsigned xdim;
+ unsigned ydim;
+ unsigned xorigin;
+ unsigned yorigin;
+ unsigned alignment;
+ void (*f)(void);
+ } bx_headerbar_entry[BX_MAX_HEADERBAR_ENTRIES];
+static unsigned bx_headerbar_y = 0;
+static unsigned bx_headerbar_entries = 0;
+static unsigned bx_bitmap_left_xorigin = 0; // pixels from left
+static unsigned bx_bitmap_right_xorigin = 0; // pixels from right
+
+static void headerbar_click(int x, int y);
+static void send_keyboard_mouse_status(void);
+
+
+
+
+Bit32u ascii_to_key_event[0x5f] = {
+ // !"#$%&'
+ BX_KEY_SPACE,
+ BX_KEY_1,
+ BX_KEY_SINGLE_QUOTE,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_7,
+ BX_KEY_SINGLE_QUOTE,
+
+ // ()*+,-./
+ BX_KEY_9,
+ BX_KEY_0,
+ BX_KEY_8,
+ BX_KEY_EQUALS,
+ BX_KEY_COMMA,
+ BX_KEY_MINUS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // 01234567
+ BX_KEY_0,
+ BX_KEY_1,
+ BX_KEY_2,
+ BX_KEY_3,
+ BX_KEY_4,
+ BX_KEY_5,
+ BX_KEY_6,
+ BX_KEY_7,
+
+ // 89:;<=>?
+ BX_KEY_8,
+ BX_KEY_9,
+ BX_KEY_SEMICOLON,
+ BX_KEY_SEMICOLON,
+ BX_KEY_COMMA,
+ BX_KEY_EQUALS,
+ BX_KEY_PERIOD,
+ BX_KEY_SLASH,
+
+ // @ABCDEFG
+ BX_KEY_2,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+
+ // HIJKLMNO
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+
+ // PQRSTUVW
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // XYZ[\]^_
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_6,
+ BX_KEY_MINUS,
+
+ // `abcdefg
+ BX_KEY_GRAVE,
+ BX_KEY_A,
+ BX_KEY_B,
+ BX_KEY_C,
+ BX_KEY_D,
+ BX_KEY_E,
+ BX_KEY_F,
+ BX_KEY_G,
+
+ // hijklmno
+ BX_KEY_H,
+ BX_KEY_I,
+ BX_KEY_J,
+ BX_KEY_K,
+ BX_KEY_L,
+ BX_KEY_M,
+ BX_KEY_N,
+ BX_KEY_O,
+
+ // pqrstuvw
+ BX_KEY_P,
+ BX_KEY_Q,
+ BX_KEY_R,
+ BX_KEY_S,
+ BX_KEY_T,
+ BX_KEY_U,
+ BX_KEY_V,
+ BX_KEY_W,
+
+ // xyz{|}~
+ BX_KEY_X,
+ BX_KEY_Y,
+ BX_KEY_Z,
+ BX_KEY_LEFT_BRACKET,
+ BX_KEY_BACKSLASH,
+ BX_KEY_RIGHT_BRACKET,
+ BX_KEY_GRAVE
+ };
+
+extern Bit8u graphics_snapshot[32 * 1024];
+
+
+static void create_internal_vga_font(void);
+static void xkeypress(KeySym keysym, int press_release);
+// extern "C" void select_visual(void);
+
+#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
+
+
+#define MAX_VGA_COLORS 256
+
+unsigned long col_vals[MAX_VGA_COLORS]; // 256 VGA colors
+unsigned curr_foreground, curr_background;
+
+static unsigned x_tilesize, y_tilesize;
+
+
+// Try to allocate NCOLORS at once in the colormap provided. If it can
+// be done, return true. If not, return false. (In either case, free
+// up the color cells so that we don't add to the problem!) This is used
+// to determine whether Bochs should use a private colormap even when the
+// user did not specify it.
+static bx_bool
+test_alloc_colors (Colormap cmap, Bit32u n_tries) {
+ XColor color;
+ unsigned long pixel[MAX_VGA_COLORS];
+ bx_bool pixel_valid[MAX_VGA_COLORS];
+ Bit32u n_allocated = 0;
+ Bit32u i;
+ color.flags = DoRed | DoGreen | DoBlue;
+ for (i=0; i<n_tries; i++) {
+ // choose wierd color values that are unlikely to already be in the
+ // colormap.
+ color.red = ((i+41)%MAX_VGA_COLORS) << 8;
+ color.green = ((i+42)%MAX_VGA_COLORS) << 8;
+ color.blue = ((i+43)%MAX_VGA_COLORS) << 8;
+ pixel_valid[i] = false;
+ if (XAllocColor (bx_x_display, cmap, &color)) {
+ pixel[i] = color.pixel;
+ pixel_valid[i] = true;
+ n_allocated++;
+ }
+ }
+ BX_INFO (("test_alloc_colors: %d colors available out of %d colors tried", n_allocated, n_tries));
+ // now free them all
+ for (i=0; i<n_tries; i++) {
+ if (pixel_valid[i]) XFreeColors (bx_x_display, cmap, &pixel[i], 1, 0);
+ }
+ return (n_allocated == n_tries);
+}
+
+bx_x_gui_c::bx_x_gui_c () {
+}
+
+ void
+bx_x_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+ unsigned headerbar_y)
+{
+ unsigned i;
+ int x, y; /* window position */
+ unsigned int border_width = 4; /* four pixels */
+#if BX_CPU_LEVEL < 2
+ char *window_name = "Bochs 8086 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 2
+ char *window_name = "Bochs 80286 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 3
+ char *window_name = "Bochs 80386 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 4
+ char *window_name = "Bochs 80486 emulator, http://bochs.sourceforge.net/";
+#else
+ char *window_name = "VTXen";
+#endif
+ char *icon_name = "Bochs";
+ Pixmap icon_pixmap;
+#if BX_HAVE_XPM_H
+ Pixmap icon_mask;
+#endif
+ XSizeHints size_hints;
+ char *display_name = NULL;
+ /* create GC for text and drawing */
+ unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
+ XGCValues values;
+ Visual *default_visual;
+ int default_depth;
+ XEvent report;
+ XSetWindowAttributes win_attr;
+ unsigned long plane_masks_return[1];
+ XColor color;
+
+ put("XGUI");
+
+ x_tilesize = tilewidth;
+ y_tilesize = tileheight;
+ bx_headerbar_y = headerbar_y;
+
+ progname = argv[0];
+
+ /* connect to X server */
+ if ( (bx_x_display=XOpenDisplay(display_name)) == NULL )
+ {
+ BX_PANIC(("%s: cannot connect to X server %s",
+ progname, XDisplayName(display_name)));
+ }
+
+ /* get screen size from display structure macro */
+ bx_x_screen_num = DefaultScreen(bx_x_display);
+
+ /* Note that in a real application, x and y would default to 0
+ * but would be settable from the command line or resource database.
+ */
+ x = y = 0;
+
+
+ // Temporary values so we can create the window
+ font_width = 8;
+ font_height = 16;
+
+ dimension_x = text_cols * font_width;
+ dimension_y = text_rows * font_height + headerbar_y;
+
+ /* create opaque window */
+ win = XCreateSimpleWindow(bx_x_display, RootWindow(bx_x_display,bx_x_screen_num),
+ x, y,
+ dimension_x,
+ dimension_y,
+ border_width,
+ BlackPixel(bx_x_display, bx_x_screen_num),
+ BlackPixel(bx_x_display, bx_x_screen_num));
+
+ // (attempt to) enable backing store
+ win_attr.save_under=1;
+ win_attr.backing_store=Always;
+ XChangeWindowAttributes(bx_x_display,win,CWSaveUnder|CWBackingStore,&win_attr);
+
+ default_depth = DefaultDepth(bx_x_display, bx_x_screen_num);
+ default_visual = DefaultVisual(bx_x_display, bx_x_screen_num);
+
+ if (!bx_options.Oprivate_colormap->get ()) {
+ default_cmap = DefaultColormap(bx_x_display, bx_x_screen_num);
+ // try to use default colormap. If not enough colors are available,
+ // then switch to private colormap despite the user setting. There
+ // are too many cases when no colors are available and Bochs simply
+ // draws everything in black on black.
+ if (!test_alloc_colors (default_cmap, 16)) {
+ BX_ERROR (("I can't even allocate 16 colors! Switching to a private colormap"));
+ bx_options.Oprivate_colormap->set (1);
+ }
+ col_vals[0] = BlackPixel(bx_x_display, bx_x_screen_num);
+ col_vals[15] = WhitePixel(bx_x_display, bx_x_screen_num);
+ for (i = 1; i < MAX_VGA_COLORS; i++) {
+ if (i==15) continue;
+ col_vals[i] = col_vals[0];
+ }
+ }
+
+ if (bx_options.Oprivate_colormap->get ()) {
+ default_cmap = XCreateColormap(bx_x_display, DefaultRootWindow(bx_x_display),
+ default_visual, AllocNone);
+ if (XAllocColorCells(bx_x_display, default_cmap, False,
+ plane_masks_return, 0, col_vals, MAX_VGA_COLORS) == 0) {
+ BX_PANIC(("XAllocColorCells returns error. Maybe your screen does not support a private colormap?"));
+ }
+
+ win_attr.colormap = default_cmap;
+ XChangeWindowAttributes(bx_x_display, win, CWColormap, &win_attr);
+
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ for (i=0; i < MAX_VGA_COLORS; i++) {
+ color.pixel = i;
+ if (i==15) {
+ color.red = 0xffff;
+ color.green = 0xffff;
+ color.blue = 0xffff;
+ }
+ else {
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ }
+ XStoreColor(bx_x_display, default_cmap, &color);
+ }
+ }
+
+ // convenience variables which hold the black & white color indeces
+ black_pixel = col_vals[0];
+ white_pixel = col_vals[15];
+
+ BX_INFO(("font %u wide x %u high, display depth = %d",
+ (unsigned) font_width, (unsigned) font_height, default_depth));
+
+ //select_visual();
+
+
+ /* Get available icon sizes from Window manager */
+
+#if BX_HAVE_XPM_H
+ /* Create pixmap from XPM for icon */
+ XCreatePixmapFromData(bx_x_display, win, icon_bochs_xpm, &icon_pixmap, &icon_mask, NULL);
+#else
+ /* Create pixmap of depth 1 (bitmap) for icon */
+ icon_pixmap = XCreateBitmapFromData(bx_x_display, win,
+ (char *) bochs_icon_bits, bochs_icon_width, bochs_icon_height);
+#endif
+
+ /* Set size hints for window manager. The window manager may
+ * override these settings. Note that in a real
+ * application if size or position were set by the user
+ * the flags would be UPosition and USize, and these would
+ * override the window manager's preferences for this window. */
+ /* x, y, width, and height hints are now taken from
+ * the actual settings of the window when mapped. Note
+ * that PPosition and PSize must be specified anyway. */
+
+ size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;
+ size_hints.max_width = size_hints.min_width = dimension_x;
+ size_hints.max_height = size_hints.min_height = dimension_y;
+
+ {
+ XWMHints wm_hints;
+ XClassHint class_hints;
+
+ /* format of the window name and icon name
+ * arguments has changed in R4 */
+ XTextProperty windowName, iconName;
+
+ /* These calls store window_name and icon_name into
+ * XTextProperty structures and set their other
+ * fields properly. */
+ if (XStringListToTextProperty(&window_name, 1, &windowName) == 0) {
+ BX_PANIC(("%s: structure allocation for windowName failed.",
+ progname));
+ }
+
+ if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0) {
+ BX_PANIC(("%s: structure allocation for iconName failed.",
+ progname));
+ }
+
+ wm_hints.initial_state = NormalState;
+ wm_hints.input = True;
+ wm_hints.icon_pixmap = icon_pixmap;
+#if BX_HAVE_XPM_H
+ wm_hints.icon_mask = icon_mask;
+ wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
+#else
+ wm_hints.flags = StateHint | IconPixmapHint | InputHint;
+#endif
+ class_hints.res_name = progname;
+ class_hints.res_class = "Bochs";
+
+ XSetWMProperties(bx_x_display, win, &windowName, &iconName,
+ argv, argc, &size_hints, &wm_hints,
+ &class_hints);
+ }
+
+ /* Select event types wanted */
+ XSelectInput(bx_x_display, win, ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | PointerMotionMask |
+ EnterWindowMask | LeaveWindowMask );
+
+
+ /* Create default Graphics Context */
+ gc = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_inv = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_headerbar = XCreateGC(bx_x_display, win, valuemask, &values);
+ gc_headerbar_inv = XCreateGC(bx_x_display, win, valuemask, &values);
+
+ XSetState(bx_x_display, gc, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+ XSetState(bx_x_display, gc_inv, black_pixel, white_pixel, GXinvert,AllPlanes);
+
+ XSetState(bx_x_display, gc_headerbar, black_pixel, white_pixel, GXcopy,AllPlanes);
+
+ XSetState(bx_x_display, gc_headerbar_inv, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+
+ /* Display window */
+ XMapWindow(bx_x_display, win);
+ XSync(bx_x_display, /* no discard */ 0);
+
+ BX_DEBUG(("waiting for MapNotify"));
+ while (1) {
+ XNextEvent(bx_x_display, &report);
+ if (report.type == MapNotify) break;
+ }
+ BX_DEBUG(("MapNotify found."));
+
+ // Create the VGA font
+ create_internal_vga_font();
+
+
+{
+ char *imagedata;
+
+ ximage = XCreateImage(bx_x_display, default_visual,
+ default_depth, // depth of image (bitplanes)
+ ZPixmap,
+ 0, // offset
+ NULL, // malloc() space after
+ x_tilesize, y_tilesize, // x & y size of image
+ 32, // # bits of padding
+ 0 ); // bytes_per_line, let X11 calculate
+ if (!ximage)
+ BX_PANIC(("vga: couldn't XCreateImage()"));
+
+ imDepth = default_depth;
+ imWide = ximage->bytes_per_line;
+ imBPP = ximage->bits_per_pixel;
+
+ imagedata = (char *) malloc( (size_t) (ximage->bytes_per_line * y_tilesize) );
+ if (!imagedata) BX_PANIC(("imagedata: malloc returned error"));
+
+ ximage->data = imagedata;
+
+ if (imBPP < imDepth) {
+ BX_PANIC(("vga_x: bits_per_pixel < depth ?"));
+ }
+
+ x_init_done = true;
+
+}
+
+ curr_background = 0;
+ XSetBackground(bx_x_display, gc, col_vals[curr_background]);
+ curr_foreground = 1;
+ XSetForeground(bx_x_display, gc, col_vals[curr_foreground]);
+ //XGrabPointer( bx_x_display, win, True, 0, GrabModeAsync, GrabModeAsync,
+ // win, None, CurrentTime );
+
+
+ XFlush(bx_x_display);
+
+ // loads keymap for x11
+ if(bx_options.keyboard.OuseMapping->get()) {
+ bx_keymap.loadKeymap(convertStringToXKeysym);
+ }
+}
+
+
+// This is called whenever the mouse_enabled parameter changes. It
+// can change because of a gui event such as clicking on the mouse-enable
+// bitmap or pressing the middle button, or from the configuration interface.
+// In all those cases, setting the parameter value will get you here.
+ void
+bx_x_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+ BX_DEBUG (("mouse_enabled=%d, x11 specific code", val?1:0));
+ if (val) {
+ BX_INFO(("[x] Mouse on"));
+ mouse_enable_x = current_x;
+ mouse_enable_y = current_y;
+ disable_cursor();
+ // Move the cursor to a 'safe' place
+ warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+ } else {
+ BX_INFO(("[x] Mouse off"));
+ enable_cursor();
+ warp_cursor(mouse_enable_x-current_x, mouse_enable_y-current_y);
+ }
+}
+
+ void
+create_internal_vga_font(void)
+{
+ // Default values
+ font_width=8;
+ font_height=16;
+
+ for(int i=0; i<256; i++) {
+ vgafont[i]=XCreateBitmapFromData(bx_x_display, win, (const char*)bx_vgafont[i].data,
+ font_width, font_height);
+ if(vgafont[i] == None)
+ BX_PANIC(("Can't create vga font [%d]", i));
+ }
+}
+
+ void
+bx_x_gui_c::handle_events(void)
+{
+ XEvent report;
+ XKeyEvent *key_event;
+ KeySym keysym;
+ XComposeStatus compose;
+ char buffer[MAX_MAPPED_STRING_LENGTH];
+ int bufsize = MAX_MAPPED_STRING_LENGTH;
+ int charcount;
+ bx_bool mouse_update;
+ int y, height;
+
+
+ XPointerMovedEvent *pointer_event;
+ XEnterWindowEvent *enter_event;
+ XLeaveWindowEvent *leave_event;
+ XButtonEvent *button_event;
+ XExposeEvent *expose_event;
+
+
+ //current_x = -1;
+ //current_y = -1;
+ mouse_update = 0;
+
+ while (XPending(bx_x_display) > 0) {
+ XNextEvent(bx_x_display, &report);
+ switch (report.type) {
+
+ case Expose:
+ expose_event = &report.xexpose;
+ /* Adjust y, and reduce height if it overlaps headerbar. */
+ y = expose_event->y - BX_HEADER_BAR_Y;
+ height = expose_event->height;
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+
+ DEV_vga_redraw_area(
+ (unsigned) expose_event->x,
+ y,
+ (unsigned) expose_event->width,
+ height);
+
+ /* Always draw headerbar, even if not touched by expose event.
+ * As a small optimization, only do it on last contigous expose.
+ */
+ if (expose_event->count == 0) {
+ show_headerbar();
+ }
+ break;
+
+ case ConfigureNotify:
+ BX_DEBUG(("ConfigureNotify Xevent"));
+ /* FIXME: It's not clear why we have to show the headerbar here.
+ * This should be forced by the following expose events.
+ */
+ show_headerbar();
+ break;
+
+ case ButtonPress:
+ button_event = (XButtonEvent *) &report;
+ BX_DEBUG(("xxx: buttonpress"));
+ if (button_event->y < BX_HEADER_BAR_Y) {
+ BX_DEBUG(("xxx: in headerbar"));
+ if (mouse_update) {
+ BX_DEBUG(("xxx: mouse_update=1"));
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ }
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ headerbar_click(button_event->x, button_event->y);
+ break;
+ }
+ current_x = button_event->x;
+ current_y = button_event->y;
+ mouse_update = 1;
+ BX_DEBUG(("xxx: x,y=(%d,%d)", current_x, current_y));
+ switch (button_event->button) {
+ case Button1:
+ BX_DEBUG(("xxx: button1"));
+ mouse_button_state |= 0x01;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ case Button2:
+ BX_DEBUG(("XXX: button2"));
+
+ // (mch) Hack for easier mouse handling (toggle mouse enable)
+ toggle_mouse_enable();
+
+ //mouse_button_state |= ;
+ //send_keyboard_mouse_status();
+ //mouse_update = 0;
+ break;
+ case Button3:
+ BX_DEBUG(("xxx: button3"));
+ mouse_button_state |= 0x02;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ }
+ break;
+
+ case ButtonRelease:
+ button_event = (XButtonEvent *) &report;
+//BX_INFO(("xxx: buttonrelease"));
+ if (button_event->y < BX_HEADER_BAR_Y) {
+//BX_INFO(("xxx: in headerbar"));
+ if (mouse_update) {
+//BX_INFO(("xxx: mouse_update=1"));
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ }
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ // ignore, in headerbar area
+ break;
+ }
+ current_x = button_event->x;
+ current_y = button_event->y;
+ mouse_update = 1;
+//BX_INFO(("xxx: x,y=(%d,%d)", current_x, current_y));
+ switch (button_event->button) {
+ case Button1:
+//BX_INFO(("xxx: button1"));
+ mouse_button_state &= ~0x01;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ case Button2:
+//BX_INFO(("xxx: button2"));
+ //mouse_button_state &= ~;
+ //send_keyboard_mouse_status();
+ //mouse_update = 0;
+ break;
+ case Button3:
+//BX_INFO(("xxx: button3"));
+ mouse_button_state &= ~0x02;
+ send_keyboard_mouse_status();
+ mouse_update = 0;
+ break;
+ }
+ break;
+
+ case KeyPress:
+ key_event = (XKeyEvent *) &report;
+ charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+ xkeypress(keysym, 0);
+ break;
+
+ case KeyRelease:
+ key_event = (XKeyEvent *) &report;
+ charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+ xkeypress(keysym, 1);
+ break;
+
+ case MotionNotify:
+ pointer_event = (XPointerMovedEvent *) &report;
+ current_x = pointer_event->x;
+ current_y = pointer_event->y;
+ mouse_update = 1;
+//BX_INFO(("xxx: motionNotify x,y=(%d,%d)", current_x, current_y));
+ break;
+
+ case EnterNotify:
+ enter_event = (XEnterWindowEvent *) &report;
+ prev_x = current_x = enter_event->x;
+ prev_y = current_y = enter_event->y;
+//BX_INFO(("xxx: enterNotify x,y=(%d,%d)", current_x, current_y));
+ break;
+
+ case LeaveNotify:
+ leave_event = (XLeaveWindowEvent *) &report;
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+//BX_INFO(("xxx: LeaveNotify x,y set to -1"));
+ break;
+
+ case MapNotify:
+ /* screen needs redraw, since X would have tossed previous
+ * requests before window mapped
+ */
+//BX_INFO(("xxx: mapnotify: found"));
+ //retval = 1;
+ break;
+
+ default:
+ // (mch) Ignore...
+ BX_DEBUG(("XXX: default Xevent type"));
+ /* all events selected by StructureNotifyMask are thrown away here,
+ * since nothing is done with them */
+ break;
+ } /* end switch */
+ } /* end while */
+
+ if (mouse_update) {
+ BX_DEBUG(("XXX: bottom, send status"));
+ send_keyboard_mouse_status();
+ }
+}
+
+
+ void
+send_keyboard_mouse_status(void)
+{
+ BX_DEBUG(("XXX: prev=(%d,%d) curr=(%d,%d)",
+ prev_x, prev_y, current_x, current_y));
+
+ if ( (prev_x!=-1) && (current_x!=-1) && (prev_y!=-1) && (current_y!=-1)) {
+ int dx, dy;
+
+ // (mch) consider warping here
+ dx = current_x - prev_x - warp_dx;
+ dy = -(current_y - prev_y - warp_dy);
+ warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+
+//BX_INFO(("xxx: MOUSE_MOTION: dx=%d, dy=%d", (int) dx, (int) dy));
+ DEV_mouse_motion (dx, dy, mouse_button_state);
+ //if (warped) {
+ // prev_x = current_x = -1;
+ // prev_y = current_y = -1;
+ // }
+ //else {
+ prev_x = current_x;
+ prev_y = current_y;
+ // }
+ }
+ else {
+ if ( (current_x!=-1) && (current_y!=-1)) {
+ prev_x = current_x;
+ prev_y = current_y;
+ }
+ else {
+ prev_x = current_x = -1;
+ prev_y = current_y = -1;
+ }
+ }
+}
+
+ void
+bx_x_gui_c::flush(void)
+{
+ if (bx_x_display)
+ XFlush(bx_x_display);
+}
+
+
+ void
+xkeypress(KeySym keysym, int press_release)
+{
+ Bit32u key_event;
+
+ /* Old (no mapping) behavior */
+ if(!bx_options.keyboard.OuseMapping->get()){
+
+ // this depends on the fact that the X11 keysyms which
+ // correspond to the ascii characters space .. tilde
+ // are in consequtive order.
+ if ((keysym >= XK_space) && (keysym <= XK_asciitilde)) {
+ key_event = ascii_to_key_event[keysym - XK_space];
+ }
+ else switch (keysym) {
+ case XK_KP_1:
+#ifdef XK_KP_End
+ case XK_KP_End:
+#endif
+ key_event = BX_KEY_KP_END; break;
+
+ case XK_KP_2:
+#ifdef XK_KP_Down
+ case XK_KP_Down:
+#endif
+ key_event = BX_KEY_KP_DOWN; break;
+
+ case XK_KP_3:
+#ifdef XK_KP_Page_Down
+ case XK_KP_Page_Down:
+#endif
+ key_event = BX_KEY_KP_PAGE_DOWN; break;
+
+ case XK_KP_4:
+#ifdef XK_KP_Left
+ case XK_KP_Left:
+#endif
+ key_event = BX_KEY_KP_LEFT; break;
+
+ case XK_KP_5:
+#ifdef XK_KP_Begin
+ case XK_KP_Begin:
+#endif
+ key_event = BX_KEY_KP_5; break;
+
+ case XK_KP_6:
+#ifdef XK_KP_Right
+ case XK_KP_Right:
+#endif
+ key_event = BX_KEY_KP_RIGHT; break;
+
+ case XK_KP_7:
+#ifdef XK_KP_Home
+ case XK_KP_Home:
+#endif
+ key_event = BX_KEY_KP_HOME; break;
+
+ case XK_KP_8:
+#ifdef XK_KP_Up
+ case XK_KP_Up:
+#endif
+ key_event = BX_KEY_KP_UP; break;
+
+ case XK_KP_9:
+#ifdef XK_KP_Page_Up
+ case XK_KP_Page_Up:
+#endif
+ key_event = BX_KEY_KP_PAGE_UP; break;
+
+ case XK_KP_0:
+#ifdef XK_KP_Insert
+ case XK_KP_Insert:
+#endif
+ key_event = BX_KEY_KP_INSERT; break;
+
+ case XK_KP_Decimal:
+#ifdef XK_KP_Delete
+ case XK_KP_Delete:
+#endif
+ key_event = BX_KEY_KP_DELETE; break;
+
+#ifdef XK_KP_Enter
+ case XK_KP_Enter: key_event = BX_KEY_KP_ENTER; break;
+#endif
+
+ case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
+ case XK_KP_Add: key_event = BX_KEY_KP_ADD; break;
+
+ case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
+ case XK_KP_Divide: key_event = BX_KEY_KP_DIVIDE; break;
+
+
+ case XK_Up: key_event = BX_KEY_UP; break;
+ case XK_Down: key_event = BX_KEY_DOWN; break;
+ case XK_Left: key_event = BX_KEY_LEFT; break;
+ case XK_Right: key_event = BX_KEY_RIGHT; break;
+
+
+ case XK_Delete: key_event = BX_KEY_DELETE; break;
+ case XK_BackSpace: key_event = BX_KEY_BACKSPACE; break;
+ case XK_Tab: key_event = BX_KEY_TAB; break;
+#ifdef XK_ISO_Left_Tab
+ case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
+#endif
+ case XK_Return: key_event = BX_KEY_ENTER; break;
+ case XK_Escape: key_event = BX_KEY_ESC; break;
+ case XK_F1: key_event = BX_KEY_F1; break;
+ case XK_F2: key_event = BX_KEY_F2; break;
+ case XK_F3: key_event = BX_KEY_F3; break;
+ case XK_F4: key_event = BX_KEY_F4; break;
+ case XK_F5: key_event = BX_KEY_F5; break;
+ case XK_F6: key_event = BX_KEY_F6; break;
+ case XK_F7: key_event = BX_KEY_F7; break;
+ case XK_F8: key_event = BX_KEY_F8; break;
+ case XK_F9: key_event = BX_KEY_F9; break;
+ case XK_F10: key_event = BX_KEY_F10; break;
+ case XK_F11: key_event = BX_KEY_F11; break;
+ case XK_F12: key_event = BX_KEY_F12; break;
+ case XK_Control_L: key_event = BX_KEY_CTRL_L; break;
+#ifdef XK_Control_R
+ case XK_Control_R: key_event = BX_KEY_CTRL_R; break;
+#endif
+ case XK_Shift_L: key_event = BX_KEY_SHIFT_L; break;
+ case XK_Shift_R: key_event = BX_KEY_SHIFT_R; break;
+ case XK_Alt_L: key_event = BX_KEY_ALT_L; break;
+#ifdef XK_Alt_R
+ case XK_Alt_R: key_event = BX_KEY_ALT_R; break;
+#endif
+ case XK_Caps_Lock: key_event = BX_KEY_CAPS_LOCK; break;
+ case XK_Num_Lock: key_event = BX_KEY_NUM_LOCK; break;
+#ifdef XK_Scroll_Lock
+ case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
+#endif
+#ifdef XK_Print
+ case XK_Print: key_event = BX_KEY_PRINT; break;
+#endif
+#ifdef XK_Pause
+ case XK_Pause: key_event = BX_KEY_PAUSE; break;
+#endif
+
+ case XK_Insert: key_event = BX_KEY_INSERT; break;
+ case XK_Home: key_event = BX_KEY_HOME; break;
+ case XK_End: key_event = BX_KEY_END; break;
+ case XK_Page_Up: key_event = BX_KEY_PAGE_UP; break;
+ case XK_Page_Down: key_event = BX_KEY_PAGE_DOWN; break;
+
+ default:
+ BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+ return;
+ break;
+ }
+ }
+ else {
+ /* use mapping */
+ BXKeyEntry *entry = bx_keymap.findHostKey (keysym);
+ if (!entry) {
+ BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+ return;
+ }
+ key_event = entry->baseKey;
+ }
+
+ if (press_release)
+ key_event |= BX_KEY_RELEASED;
+
+ DEV_kbd_gen_scancode(key_event);
+}
+
+
+ void
+bx_x_gui_c::clear_screen(void)
+{
+ XClearArea(bx_x_display, win, 0, bx_headerbar_y, dimension_x, dimension_y-bx_headerbar_y, 0);
+}
+
+
+
+
+ void
+bx_x_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+ unsigned long cursor_x, unsigned long cursor_y,
+ bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+ unsigned char *old_line, *new_line;
+ unsigned char cChar;
+ unsigned int curs, hchars, i, j, offset, rows, x, y, xc, yc, yc2;
+ unsigned new_foreground, new_background;
+ Bit8u cfwidth, cfheight, cfheight2, font_col, font_row, font_row2;
+ bx_bool force_update=0;
+ unsigned char cell[64];
+
+ UNUSED(nrows);
+ if (charmap_updated) {
+ BX_INFO(("charmap update. Font Height is %d",font_height));
+ for (unsigned c = 0; c<256; c++) {
+ if (char_changed[c]) {
+ XFreePixmap(bx_x_display, vgafont[c]);
+ bx_bool gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);
+ j = 0;
+ memset(cell, 0, sizeof(cell));
+ for(i=0; i<font_height*2; i+=2) {
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x01)<<7);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x02)<<5);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x04)<<3);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x08)<<1);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x10)>>1);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x20)>>3);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x40)>>5);
+ cell[i] |= ((vga_charmap[(c<<5)+j] & 0x80)>>7);
+ if (gfxchar) {
+ cell[i+1] = (vga_charmap[(c<<5)+j] & 0x01);
+ }
+ j++;
+ }
+
+ vgafont[c]=XCreateBitmapFromData(bx_x_display, win,
+ (const char*)cell,
+ font_width, font_height);
+ if(vgafont[c] == None)
+ BX_PANIC(("Can't create vga font [%d]", c));
+ char_changed[c] = 0;
+ }
+ }
+ force_update = 1;
+ charmap_updated = 0;
+ }
+
+ if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {
+ force_update = 1;
+ h_panning = tm_info.h_panning;
+ v_panning = tm_info.v_panning;
+ }
+
+ // first invalidate character at previous and new cursor location
+ if ( (prev_cursor_y < text_rows) && (prev_cursor_x < text_cols) ) {
+ curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;
+ old_text[curs] = ~new_text[curs];
+ }
+ if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
+ (cursor_y < text_rows) && (cursor_x < text_cols)) {
+ curs = cursor_y * tm_info.line_offset + cursor_x * 2;
+ old_text[curs] = ~new_text[curs];
+ } else {
+ curs = 0xffff;
+ }
+
+ rows = text_rows;
+ if (v_panning) rows++;
+ y = 0;
+ do {
+ hchars = text_cols;
+ if (h_panning) hchars++;
+ if (v_panning) {
+ if (y == 0) {
+ yc = bx_headerbar_y;
+ font_row = v_panning;
+ cfheight = font_height - v_panning;
+ } else {
+ yc = y * font_height + bx_headerbar_y - v_panning;
+ font_row = 0;
+ if (rows == 1) {
+ cfheight = v_panning;
+ } else {
+ cfheight = font_height;
+ }
+ }
+ } else {
+ yc = y * font_height + bx_headerbar_y;
+ font_row = 0;
+ cfheight = font_height;
+ }
+ new_line = new_text;
+ old_line = old_text;
+ x = 0;
+ offset = y * tm_info.line_offset;
+ do {
+ if (h_panning) {
+ if (hchars > text_cols) {
+ xc = 0;
+ font_col = h_panning;
+ cfwidth = font_width - h_panning;
+ } else {
+ xc = x * font_width - h_panning;
+ font_col = 0;
+ if (hchars == 1) {
+ cfwidth = h_panning;
+ } else {
+ cfwidth = font_width;
+ }
+ }
+ } else {
+ xc = x * font_width;
+ font_col = 0;
+ cfwidth = font_width;
+ }
+ if ( force_update || (old_text[0] != new_text[0])
+ || (old_text[1] != new_text[1]) ) {
+
+ cChar = new_text[0];
+ new_foreground = new_text[1] & 0x0f;
+ new_background = (new_text[1] & 0xf0) >> 4;
+
+ XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+ XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+
+ XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row, cfwidth, cfheight,
+ xc, yc, 1);
+ if (offset == curs) {
+ XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+ XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+ if (font_row == 0) {
+ yc2 = yc + tm_info.cs_start;
+ font_row2 = tm_info.cs_start;
+ cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+ } else {
+ if (v_panning > tm_info.cs_start) {
+ yc2 = yc;
+ font_row2 = font_row;
+ cfheight2 = tm_info.cs_end - v_panning + 1;
+ } else {
+ yc2 = yc + tm_info.cs_start - v_panning;
+ font_row2 = tm_info.cs_start;
+ cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+ }
+ }
+ XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row2, cfwidth,
+ cfheight2, xc, yc2, 1);
+ }
+ }
+ x++;
+ new_text+=2;
+ old_text+=2;
+ offset+=2;
+ } while (--hchars);
+ y++;
+ new_text = new_line + tm_info.line_offset;
+ old_text = old_line + tm_info.line_offset;
+ } while (--rows);
+
+ prev_cursor_x = cursor_x;
+ prev_cursor_y = cursor_y;
+
+ XFlush(bx_x_display);
+}
+
+ int
+bx_x_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+ int len;
+ Bit8u *tmp = (Bit8u *)XFetchBytes (bx_x_display, &len);
+ // according to man XFetchBytes, tmp must be freed by XFree(). So allocate
+ // a new buffer with "new". The keyboard code will free it with delete []
+ // when the paste is done.
+ Bit8u *buf = new Bit8u[len];
+ memcpy (buf, tmp, len);
+ *bytes = buf;
+ *nbytes = len;
+ XFree (tmp);
+ return 1;
+}
+
+ int
+bx_x_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+ // this writes data to the clipboard.
+ BX_INFO (("storing %d bytes to X windows clipboard", len));
+ XSetSelectionOwner(bx_x_display, XA_PRIMARY, None, CurrentTime);
+ XStoreBytes (bx_x_display, (char *)text_snapshot, len);
+ return 1;
+}
+
+
+ void
+bx_x_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+ unsigned x, y;
+ unsigned color, offset;
+ Bit8u b0, b1, b2, b3;
+
+ Bit16u *tile16 = (Bit16u *)tile;
+ switch (vga_bpp) {
+ case 32: // 32 bits per pixel
+ if (ximage->byte_order == LSBFirst) {
+ memcpy(&ximage->data[0], tile, x_tilesize*y_tilesize*4);
+ }
+ else { // MSBFirst
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ offset = imWide*y + 4*x;
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*4 + 3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*4 + 2];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*4 + 1];
+ ximage->data[offset + 3] = tile[(y*x_tilesize + x)*4];
+ }
+ }
+ }
+ break;
+ case 24: // 24 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3];
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 2];
+ ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 1];
+ ximage->data[offset + 3] = tile[(y*x_tilesize + x)*3];
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 16: // 16 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2 + 1];
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2 + 1];
+ ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2];
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+ b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+ b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case 15: // 15 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ switch (imBPP) {
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f);
+ b0 |= (tile16[y*x_tilesize + x] & 0x0060) << 1;
+ b1 = (tile16[y*x_tilesize + x] & 0x7f80) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b1;
+ ximage->data[offset + 1] = b0;
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+ b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+ b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+ b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = 0;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = 0;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ default: // 8 bits per pixel
+ for (y=0; y<y_tilesize; y++) {
+ for (x=0; x<x_tilesize; x++) {
+ color = col_vals[tile[y*x_tilesize + x]];
+ switch (imBPP) {
+ case 8: // 8 bits per pixel
+ ximage->data[imWide*y + x] = color;
+ break;
+ case 16: // 16 bits per pixel
+ offset = imWide*y + 2*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b1;
+ ximage->data[offset + 1] = b0;
+ }
+ break;
+ case 24: // 24 bits per pixel
+ offset = imWide*y + 3*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ b2 = color >> 16;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b2;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b0;
+ }
+ break;
+ case 32: // 32 bits per pixel
+ offset = imWide*y + 4*x;
+ b0 = color >> 0;
+ b1 = color >> 8;
+ b2 = color >> 16;
+ b3 = color >> 24;
+ if (ximage->byte_order == LSBFirst) {
+ ximage->data[offset + 0] = b0;
+ ximage->data[offset + 1] = b1;
+ ximage->data[offset + 2] = b2;
+ ximage->data[offset + 3] = b3;
+ }
+ else { // MSBFirst
+ ximage->data[offset + 0] = b3;
+ ximage->data[offset + 1] = b2;
+ ximage->data[offset + 2] = b1;
+ ximage->data[offset + 3] = b0;
+ }
+ break;
+ default:
+ BX_PANIC(("X_graphics_tile_update: bits_per_pixel %u not implemented",
+ (unsigned) imBPP));
+ break;
+ }
+ }
+ }
+ }
+ XPutImage(bx_x_display, win, gc, ximage, 0, 0, x0, y0+bx_headerbar_y,
+ x_tilesize, y_tilesize);
+}
+
+
+ bx_bool
+bx_x_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+ // returns: 0=no screen update needed (color map change has direct effect)
+ // 1=screen updated needed (redraw using current colormap)
+ XColor color;
+
+ color.flags = DoRed | DoGreen | DoBlue;
+ color.red = red << 8;
+ color.green = green << 8;
+ color.blue = blue << 8;
+
+ if (bx_options.Oprivate_colormap->get ()) {
+ color.pixel = index;
+ XStoreColor(bx_x_display, default_cmap, &color);
+ return(0); // no screen update needed
+ }
+ else {
+ XAllocColor(bx_x_display, DefaultColormap(bx_x_display, bx_x_screen_num),
+ &color);
+ col_vals[index] = color.pixel;
+ return(1); // screen update needed
+ }
+}
+
+
+ void
+bx_x_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+ if ((bpp <= imBPP) && ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32))) {
+ vga_bpp = bpp;
+ } else {
+ BX_PANIC(("%d bpp graphics mode not supported", bpp));
+ }
+ if (fheight > 0) {
+ font_height = fheight;
+ font_width = fwidth;
+ text_cols = x / font_width;
+ text_rows = y / font_height;
+ }
+ if ( (x != dimension_x) || (y != (dimension_y-bx_headerbar_y)) ) {
+ XSizeHints hints;
+ long supplied_return;
+
+ if ( XGetWMNormalHints(bx_x_display, win, &hints, &supplied_return) &&
+ supplied_return & PMaxSize ) {
+ hints.max_width = hints.min_width = x;
+ hints.max_height = hints.min_height = y+bx_headerbar_y;
+ XSetWMNormalHints(bx_x_display, win, &hints);
+ }
+ XResizeWindow(bx_x_display, win, x, y+bx_headerbar_y);
+ dimension_x = x;
+ dimension_y = y + bx_headerbar_y;
+ }
+}
+
+
+ void
+bx_x_gui_c::show_headerbar(void)
+{
+ unsigned xorigin;
+ int xleft, xright;
+
+ // clear header bar area to white
+ XFillRectangle(bx_x_display, win, gc_headerbar_inv, 0,0, dimension_x, bx_headerbar_y);
+
+ xleft = 0;
+ xright = dimension_x;
+ for (unsigned i=0; i<bx_headerbar_entries; i++) {
+ if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT) {
+ xorigin = bx_headerbar_entry[i].xorigin;
+ xleft += bx_headerbar_entry[i].xdim;
+ }
+ else {
+ xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+ xright = xorigin;
+ }
+ if (xright < xleft) break;
+ XCopyPlane(bx_x_display, bx_headerbar_entry[i].bitmap, win, gc_headerbar,
+ 0,0, bx_headerbar_entry[i].xdim, bx_headerbar_entry[i].ydim,
+ xorigin, 0, 1);
+ }
+}
+
+
+ unsigned
+bx_x_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+ if (bx_bitmap_entries >= BX_MAX_PIXMAPS) {
+ BX_PANIC(("x: too many pixmaps, increase BX_MAX_PIXMAPS"));
+ }
+
+ bx_bitmaps[bx_bitmap_entries].bmap =
+ XCreateBitmapFromData(bx_x_display, win, (const char *) bmap, xdim, ydim);
+ bx_bitmaps[bx_bitmap_entries].xdim = xdim;
+ bx_bitmaps[bx_bitmap_entries].ydim = ydim;
+ if (!bx_bitmaps[bx_bitmap_entries].bmap) {
+ BX_PANIC(("x: could not create bitmap"));
+ }
+ bx_bitmap_entries++;
+ return(bx_bitmap_entries-1); // return index as handle
+}
+
+
+ unsigned
+bx_x_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+ unsigned hb_index;
+
+ if ( (bx_headerbar_entries+1) > BX_MAX_HEADERBAR_ENTRIES )
+ BX_PANIC(("x: too many headerbar entries, increase BX_MAX_HEADERBAR_ENTRIES"));
+
+ bx_headerbar_entries++;
+ hb_index = bx_headerbar_entries - 1;
+
+ bx_headerbar_entry[hb_index].bitmap = bx_bitmaps[bmap_id].bmap;
+ bx_headerbar_entry[hb_index].xdim = bx_bitmaps[bmap_id].xdim;
+ bx_headerbar_entry[hb_index].ydim = bx_bitmaps[bmap_id].ydim;
+ bx_headerbar_entry[hb_index].alignment = alignment;
+ bx_headerbar_entry[hb_index].f = f;
+ if (alignment == BX_GRAVITY_LEFT) {
+ bx_headerbar_entry[hb_index].xorigin = bx_bitmap_left_xorigin;
+ bx_headerbar_entry[hb_index].yorigin = 0;
+ bx_bitmap_left_xorigin += bx_bitmaps[bmap_id].xdim;
+ }
+ else { // BX_GRAVITY_RIGHT
+ bx_bitmap_right_xorigin += bx_bitmaps[bmap_id].xdim;
+ bx_headerbar_entry[hb_index].xorigin = bx_bitmap_right_xorigin;
+ bx_headerbar_entry[hb_index].yorigin = 0;
+ }
+ return(hb_index);
+}
+
+ void
+bx_x_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+ unsigned xorigin;
+
+ bx_headerbar_entry[hbar_id].bitmap = bx_bitmaps[bmap_id].bmap;
+
+ if (bx_headerbar_entry[hbar_id].alignment == BX_GRAVITY_LEFT)
+ xorigin = bx_headerbar_entry[hbar_id].xorigin;
+ else
+ xorigin = dimension_x - bx_headerbar_entry[hbar_id].xorigin;
+ XCopyPlane(bx_x_display, bx_headerbar_entry[hbar_id].bitmap, win, gc_headerbar,
+ 0,0, bx_headerbar_entry[hbar_id].xdim, bx_headerbar_entry[hbar_id].ydim,
+ xorigin, 0, 1);
+}
+
+
+ void
+headerbar_click(int x, int y)
+{
+ int xorigin;
+
+ // assuming y is in bounds
+ UNUSED(y);
+ for (unsigned i=0; i<bx_headerbar_entries; i++) {
+ if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT)
+ xorigin = bx_headerbar_entry[i].xorigin;
+ else
+ xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+ if ( (x>=xorigin) && (x<(xorigin+int(bx_headerbar_entry[i].xdim))) ) {
+ bx_headerbar_entry[i].f();
+ return;
+ }
+ }
+}
+
+ void
+bx_x_gui_c::exit(void)
+{
+ if (!x_init_done) return;
+
+ // Delete the font bitmaps
+ for (int i=0; i<256; i++) {
+ //if (vgafont[i] != NULL)
+ XFreePixmap(bx_x_display,vgafont[i]);
+ }
+
+ if (bx_x_display)
+ XCloseDisplay (bx_x_display);
+ BX_INFO(("Exit."));
+}
+
+static void warp_cursor (int dx, int dy)
+{
+ if (bx_options.Omouse_enabled->get () &&
+ (warp_dx || warp_dy || dx || dy)
+ ) {
+ warp_dx = dx;
+ warp_dy = dy;
+ XWarpPointer(bx_x_display, None, None, 0, 0, 0, 0, dx, dy);
+ }
+}
+
+static void disable_cursor ()
+{
+ static Cursor cursor;
+ static unsigned cursor_created = 0;
+
+ static int shape_width = 16,
+ shape_height = 16,
+ mask_width = 16,
+ mask_height = 16;
+
+ static uint32 shape_bits[(16*16)/32] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ };
+ static uint32 mask_bits[(16*16)/32] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ };
+
+ if (!cursor_created) {
+ Pixmap shape, mask;
+ XColor white, black;
+ shape = XCreatePixmapFromBitmapData(bx_x_display,
+ RootWindow(bx_x_display,bx_x_screen_num),
+ (char*)shape_bits,
+ shape_width,
+ shape_height,
+ 1, 0, 1);
+ mask = XCreatePixmapFromBitmapData(bx_x_display,
+ RootWindow(bx_x_display,bx_x_screen_num),
+ (char*)mask_bits,
+ mask_width,
+ mask_height,
+ 1, 0, 1);
+ XParseColor(bx_x_display, default_cmap, "black", &black);
+ XParseColor(bx_x_display, default_cmap, "white", &white);
+ cursor = XCreatePixmapCursor(bx_x_display, shape, mask,
+ &white, &black, 1, 1);
+ cursor_created = 1;
+ }
+
+ XDefineCursor(bx_x_display, win, cursor);
+}
+
+static void enable_cursor ()
+{
+ XUndefineCursor(bx_x_display, win);
+}
+
+/* convertStringToXKeysym is a keymap callback
+ * used when reading the keymap file.
+ * It converts a Symblic String to a GUI Constant
+ *
+ * It returns a Bit32u constant or BX_KEYMAP_UNKNOWN if it fails
+ */
+static Bit32u convertStringToXKeysym (const char *string)
+{
+ if (strncmp ("XK_", string, 3) != 0)
+ return BX_KEYMAP_UNKNOWN;
+ KeySym keysym=XStringToKeysym(string+3);
+
+ // failure, return unknown
+ if(keysym==NoSymbol) return BX_KEYMAP_UNKNOWN;
+
+ return((Bit32u)keysym);
+}
+
+#if BX_USE_IDLE_HACK
+
+/* BX_USE_IDLE_HACK: a small idle hack by
+ * Roland.Mainz@informatik.med.uni-giessen.de to prevent bochs
+ * from consuming 100% CPU time even when it is not required (for
+ * example, the OS in the emulator calls HLT to wait for an interupt)
+ * pro:
+ * - no more 100% CPU usage
+ * contra:
+ * - we're sleeping too long
+ * - bochs still consumes ~10%-20% CPU time while executing an idle
+ * linux kernel
+ * - this is an hack
+ */
+
+/* XPeekEvent() with timeout
+ * (adopted from mozilla/gfx/src/xprint/xprintutil_printtofile.c#XNextEventTimeout())
+ */
+static
+Bool XPeekEventTimeout( Display *display, XEvent *event_return, struct timeval *timeout )
+{
+ int res;
+ fd_set readfds;
+ int display_fd = XConnectionNumber(display);
+
+ /* small shortcut... */
+ if( timeout == NULL )
+ {
+ XPeekEvent(display, event_return);
+ return(True);
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(display_fd, &readfds);
+
+ /* Note/bug: In the case of internal X events (like used to trigger callbacks
+ * registered by XpGetDocumentData()&co.) select() will return with "new info"
+ * - but XNextEvent() below processes these _internal_ events silently - and
+ * will block if there are no other non-internal events.
+ * The workaround here is to check with XEventsQueued() if there are non-internal
+ * events queued - if not select() will be called again - unfortunately we use
+ * the old timeout here instead of the "remaining" time... (this only would hurt
+ * if the timeout would be really long - but for current use with values below
+ * 1/2 secs it does not hurt... =:-)
+ */
+ while( XEventsQueued(display, QueuedAfterFlush) == 0 )
+ {
+ res = select(display_fd+1, &readfds, NULL, NULL, timeout);
+
+ switch(res)
+ {
+ case -1: /* select() error - should not happen */
+ perror("XPeekEventTimeout: select() failure");
+ return(False);
+ case 0: /* timeout */
+ return(False);
+ }
+ }
+
+ XPeekEvent(display, event_return);
+ return(True);
+}
+
+#if BX_USE_IDLE_HACK
+void bx_x_gui_c::sim_is_idle () {
+ XEvent dummy;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1000; /* 1/1000 s */
+ XPeekEventTimeout(bx_x_display, &dummy, &timeout);
+}
+#endif
+#endif /* BX_USE_IDLE_HACK */
+
+#endif /* if BX_WITH_X11 */
diff --git a/tools/ioemu/include/bochs.h b/tools/ioemu/include/bochs.h
new file mode 100644
index 0000000000..59b306702d
--- /dev/null
+++ b/tools/ioemu/include/bochs.h
@@ -0,0 +1,771 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: bochs.h,v 1.128.2.1 2004/02/06 22:14:25 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// bochs.h is the master header file for all C++ code. It includes all
+// the system header files needed by bochs, and also includes all the bochs
+// C++ header files. Because bochs.h and the files that it includes has
+// structure and class definitions, it cannot be called from C code.
+//
+
+#ifndef BX_BOCHS_H
+# define BX_BOCHS_H 1
+
+#include "config.h" /* generated by configure script from config.h.in */
+
+extern "C" {
+
+#ifdef WIN32
+// In a win32 compile (including cygwin), windows.h is required for several
+// files in gui and iodev. It is important to include it here in a header
+// file so that WIN32-specific data types can be used in fields of classes.
+#include <windows.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+#include <time.h>
+#if BX_WITH_MACOS
+#define Float32 KLUDGE_Float32
+#define Float64 KLUDGE_Float64
+# include <types.h>
+#undef Float32
+#undef Float64
+# include <stat.h>
+# include <cstdio>
+# include <unistd.h>
+#elif BX_WITH_CARBON
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/param.h> /* for MAXPATHLEN */
+# include <utime.h>
+#else
+# ifndef WIN32
+# include <sys/time.h>
+# endif
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef macintosh
+# define SuperDrive "[fd:]"
+#endif
+}
+
+#include "osdep.h" /* platform dependent includes and defines */
+#include "bxversion.h"
+
+#include "gui/siminterface.h"
+
+// prototypes
+int bx_begin_simulation (int argc, char *argv[]);
+
+//
+// some macros to interface the CPU and memory to external environment
+// so that these functions can be redirected to the debugger when
+// needed.
+//
+
+#if ((BX_DEBUGGER == 1) && (BX_NUM_SIMULATORS >= 2))
+// =-=-=-=-=-=-=- Redirected to cosimulation debugger -=-=-=-=-=-=-=
+#define DEV_vga_mem_read(addr) bx_dbg_ucmem_read(addr)
+#define DEV_vga_mem_write(addr, val) bx_dbg_ucmem_write(addr, val)
+
+#if BX_SUPPORT_A20
+# define A20ADDR(x) ( (x) & bx_pc_system.a20_mask )
+#else
+# define A20ADDR(x) (x)
+#endif
+#define BX_INP(addr, len) bx_dbg_inp(addr, len)
+#define BX_OUTP(addr, val, len) bx_dbg_outp(addr, val, len)
+#define BX_HRQ (bx_pc_system.HRQ)
+#define BX_RAISE_HLDA() bx_dbg_raise_HLDA()
+#define BX_TICK1()
+#define BX_INTR bx_pc_system.INTR
+#define BX_SET_INTR(b) bx_dbg_set_INTR(b)
+#if BX_SIM_ID == 0
+# define BX_CPU_C bx_cpu0_c
+# define BX_CPU bx_cpu0
+# define BX_MEM_C bx_mem0_c
+# define BX_MEM bx_mem0
+#else
+# define BX_CPU_C bx_cpu1_c
+# define BX_CPU bx_cpu1
+# define BX_MEM_C bx_mem1_c
+# define BX_MEM bx_mem1
+#endif
+#define BX_SET_ENABLE_A20(enabled) bx_dbg_async_pin_request(BX_DBG_ASYNC_PENDING_A20, \
+ enabled)
+#define BX_GET_ENABLE_A20() bx_pc_system.get_enable_a20()
+#error FIXME: cosim mode not fixed yet
+
+#else
+
+// =-=-=-=-=-=-=- Normal optimized use -=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#if BX_SUPPORT_A20
+# define A20ADDR(x) ( (x) & bx_pc_system.a20_mask )
+#else
+# define A20ADDR(x) (x)
+#endif
+//
+// some pc_systems functions just redirect to the IO devices so optimize
+// by eliminating call here
+//
+// #define BX_INP(addr, len) bx_pc_system.inp(addr, len)
+// #define BX_OUTP(addr, val, len) bx_pc_system.outp(addr, val, len)
+#define BX_INP(addr, len) bx_devices.inp(addr, len)
+#define BX_OUTP(addr, val, len) bx_devices.outp(addr, val, len)
+#define BX_TICK1() bx_pc_system.tick1()
+#define BX_TICKN(n) bx_pc_system.tickn(n)
+#define BX_INTR bx_pc_system.INTR
+#define BX_SET_INTR(b) bx_pc_system.set_INTR(b)
+#define BX_CPU_C bx_cpu_c
+#define BX_MEM_C bx_mem_c
+#define BX_HRQ (bx_pc_system.HRQ)
+#define BX_MEM_READ_PHYSICAL(phy_addr, len, ptr) \
+ BX_MEM(0)->readPhysicalPage(BX_CPU(0), phy_addr, len, ptr)
+#define BX_MEM_WRITE_PHYSICAL(phy_addr, len, ptr) \
+ BX_MEM(0)->writePhysicalPage(BX_CPU(0), phy_addr, len, ptr)
+
+#if BX_SMP_PROCESSORS==1
+#define BX_CPU(x) (&bx_cpu)
+#define BX_MEM(x) (&bx_mem)
+#else
+#define BX_CPU(x) (bx_cpu_array[x])
+#define BX_MEM(x) (bx_mem_array[x])
+#endif
+
+#define BX_SET_ENABLE_A20(enabled) bx_pc_system.set_enable_a20(enabled)
+#define BX_GET_ENABLE_A20() bx_pc_system.get_enable_a20()
+
+#endif
+
+
+// you can't use static member functions on the CPU, if there are going
+// to be 2 cpus. Check this early on.
+#if (BX_SMP_PROCESSORS>1)
+# if (BX_USE_CPU_SMF!=0)
+# error For SMP simulation, BX_USE_CPU_SMF must be 0.
+# endif
+#endif
+
+
+// #define BX_IAC() bx_pc_system.IAC()
+//#define BX_IAC() bx_dbg_IAC()
+
+//
+// Ways for the the external environment to report back information
+// to the debugger.
+//
+
+#if BX_DEBUGGER
+# define BX_DBG_ASYNC_INTR bx_guard.async.irq
+# define BX_DBG_ASYNC_DMA bx_guard.async.dma
+#if (BX_NUM_SIMULATORS > 1)
+// for multiple simulators, we always need this info, since we're
+// going to replay it.
+# define BX_DBG_DMA_REPORT(addr, len, what, val) \
+ bx_dbg_dma_report(addr, len, what, val)
+# define BX_DBG_IAC_REPORT(vector, irq) \
+ bx_dbg_iac_report(vector, irq)
+# define BX_DBG_A20_REPORT(val) \
+ bx_dbg_a20_report(val)
+# define BX_DBG_IO_REPORT(addr, size, op, val) \
+ bx_dbg_io_report(addr, size, op, val)
+# define BX_DBG_UCMEM_REPORT(addr, size, op, val)
+#else
+// for a single simulator debug environment, we can optimize a little
+// by conditionally calling, as per requested.
+
+# define BX_DBG_DMA_REPORT(addr, len, what, val) \
+ if (bx_guard.report.dma) bx_dbg_dma_report(addr, len, what, val)
+# define BX_DBG_IAC_REPORT(vector, irq) \
+ if (bx_guard.report.irq) bx_dbg_iac_report(vector, irq)
+# define BX_DBG_A20_REPORT(val) \
+ if (bx_guard.report.a20) bx_dbg_a20_report(val)
+# define BX_DBG_IO_REPORT(addr, size, op, val) \
+ if (bx_guard.report.io) bx_dbg_io_report(addr, size, op, val)
+# define BX_DBG_UCMEM_REPORT(addr, size, op, val) \
+ if (bx_guard.report.ucmem) bx_dbg_ucmem_report(addr, size, op, val)
+#endif // #if (BX_NUM_SIMULATORS > 1)
+
+#else // #if BX_DEBUGGER
+// debugger not compiled in, use empty stubs
+# define BX_DBG_ASYNC_INTR 1
+# define BX_DBG_ASYNC_DMA 1
+# define BX_DBG_DMA_REPORT(addr, len, what, val)
+# define BX_DBG_IAC_REPORT(vector, irq)
+# define BX_DBG_A20_REPORT(val)
+# define BX_DBG_IO_REPORT(addr, size, op, val)
+# define BX_DBG_UCMEM_REPORT(addr, size, op, val)
+#endif // #if BX_DEBUGGER
+
+#define MAGIC_LOGNUM 0x12345678
+
+typedef class BOCHSAPI logfunctions {
+ char *prefix;
+ int type;
+// values of onoff: 0=ignore, 1=report, 2=ask, 3=fatal
+#define ACT_IGNORE 0
+#define ACT_REPORT 1
+#define ACT_ASK 2
+#define ACT_FATAL 3
+#define N_ACT 4
+ int onoff[N_LOGLEV];
+ class iofunctions *logio;
+ // default log actions for all devices, declared and initialized
+ // in logio.cc.
+ BOCHSAPI_CYGONLY static int default_onoff[N_LOGLEV];
+public:
+ logfunctions(void);
+ logfunctions(class iofunctions *);
+ ~logfunctions(void);
+
+ void info(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+ void error(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+ void panic(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+ void pass(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+ void ldebug(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+ void fatal (const char *prefix, const char *fmt, va_list ap, int exit_status);
+#if BX_EXTERNAL_DEBUGGER
+ virtual void ask (int level, const char *prefix, const char *fmt, va_list ap);
+#else
+ void ask (int level, const char *prefix, const char *fmt, va_list ap);
+#endif
+ void put(char *);
+ void settype(int);
+ void setio(class iofunctions *);
+ void setonoff(int loglev, int value) {
+ assert (loglev >= 0 && loglev < N_LOGLEV);
+ onoff[loglev] = value;
+ }
+ char *getprefix () { return prefix; }
+ int getonoff(int level) {
+ assert (level>=0 && level<N_LOGLEV);
+ return onoff[level];
+ }
+ static void set_default_action (int loglev, int action) {
+ assert (loglev >= 0 && loglev < N_LOGLEV);
+ assert (action >= 0 && action < N_ACT);
+ default_onoff[loglev] = action;
+ }
+ static int get_default_action (int loglev) {
+ assert (loglev >= 0 && loglev < N_LOGLEV);
+ return default_onoff[loglev];
+ }
+} logfunc_t;
+
+#define BX_LOGPREFIX_SIZE 51
+
+enum {
+ IOLOG=0, FDLOG, GENLOG, CMOSLOG, CDLOG, DMALOG, ETHLOG, G2HLOG, HDLOG, KBDLOG,
+ NE2KLOG, PARLOG, PCILOG, PICLOG, PITLOG, SB16LOG, SERLOG, VGALOG,
+ STLOG, // state_file.cc
+ DEVLOG, MEMLOG, DISLOG, GUILOG, IOAPICLOG, APICLOG, CPU0LOG, CPU1LOG,
+ CPU2LOG, CPU3LOG, CPU4LOG, CPU5LOG, CPU6LOG, CPU7LOG, CPU8LOG, CPU9LOG,
+ CPU10LOG, CPU11LOG, CPU12LOG, CPU13LOG, CPU14LOG, CPU15LOG, CTRLLOG,
+ UNMAPLOG, SERRLOG, BIOSLOG, PIT81LOG, PIT82LOG, IODEBUGLOG, PCI2ISALOG,
+ PLUGINLOG, EXTFPUIRQLOG , PCIVGALOG, PCIUSBLOG, VTIMERLOG, STIMERLOG
+};
+
+class BOCHSAPI iofunctions {
+ int magic;
+ char logprefix[BX_LOGPREFIX_SIZE];
+ FILE *logfd;
+ class logfunctions *log;
+ void init(void);
+ void flush(void);
+
+// Log Class types
+public:
+ iofunctions(void);
+ iofunctions(FILE *);
+ iofunctions(int);
+ iofunctions(const char *);
+ ~iofunctions(void);
+
+ void out(int facility, int level, const char *pre, const char *fmt, va_list ap);
+
+ void init_log(const char *fn);
+ void init_log(int fd);
+ void init_log(FILE *fs);
+ void set_log_prefix(const char *prefix);
+ int get_n_logfns () { return n_logfn; }
+ logfunc_t *get_logfn (int index) { return logfn_list[index]; }
+ void add_logfn (logfunc_t *fn);
+ void set_log_action (int loglevel, int action);
+ const char *getlevel(int i) {
+ static const char *loglevel[N_LOGLEV] = {
+ "DEBUG",
+ "INFO",
+ "ERROR",
+ "PANIC",
+ "PASS"
+ };
+ if (i>=0 && i<N_LOGLEV) return loglevel[i];
+ else return "?";
+ }
+ char *getaction(int i) {
+ static char *name[] = { "ignore", "report", "ask", "fatal" };
+ assert (i>=ACT_IGNORE && i<N_ACT);
+ return name[i];
+ }
+
+protected:
+ int n_logfn;
+#define MAX_LOGFNS 128
+ logfunc_t *logfn_list[MAX_LOGFNS];
+ char *logfn;
+
+
+};
+
+typedef class BOCHSAPI iofunctions iofunc_t;
+
+
+#define SAFE_GET_IOFUNC() \
+ ((io==NULL)? (io=new iofunc_t("/dev/stderr")) : io)
+#define SAFE_GET_GENLOG() \
+ ((genlog==NULL)? (genlog=new logfunc_t(SAFE_GET_IOFUNC())) : genlog)
+/* #define NO_LOGGING */
+#ifndef NO_LOGGING
+
+#define BX_INFO(x) (LOG_THIS info) x
+#define BX_DEBUG(x) (LOG_THIS ldebug) x
+#define BX_ERROR(x) (LOG_THIS error) x
+#define BX_PANIC(x) (LOG_THIS panic) x
+#define BX_PASS(x) (LOG_THIS pass) x
+
+#else
+
+#define EMPTY do { } while(0)
+
+#define BX_INFO(x) EMPTY
+#define BX_DEBUG(x) EMPTY
+#define BX_ERROR(x) EMPTY
+#define BX_PANIC(x) (LOG_THIS panic) x
+#define BX_PASS(x) (LOG_THIS pass) x
+
+#endif
+
+BOCHSAPI extern iofunc_t *io;
+BOCHSAPI extern logfunc_t *genlog;
+
+#include "state_file.h"
+
+#ifndef UNUSED
+# define UNUSED(x) ((void)x)
+#endif
+
+#define uint8 Bit8u
+#define uint16 Bit16u
+#define uint32 Bit32u
+
+#ifdef BX_USE_VMX
+extern "C" {
+#include "xc.h"
+}
+
+extern void *shared_page;
+BOCHSAPI extern int xc_handle;
+#endif
+
+#if BX_PROVIDE_CPU_MEMORY==1
+# include "cpu/cpu.h"
+#endif
+
+#if BX_EXTERNAL_DEBUGGER
+# include "cpu/extdb.h"
+#endif
+
+#if BX_GDBSTUB
+// defines for GDB stub
+void bx_gdbstub_init(int argc, char* argv[]);
+int bx_gdbstub_check(unsigned int eip);
+#define GDBSTUB_STOP_NO_REASON (0xac0)
+
+#if BX_SMP_PROCESSORS!=1
+#error GDB stub was written for single processor support. If multiprocessor support is added, then we can remove this check.
+// The big problem is knowing which CPU gdb is referring to. In other words,
+// what should we put for "n" in BX_CPU(n)->dbg_xlate_linear2phy() and
+// BX_CPU(n)->dword.eip, etc.
+#endif
+
+#endif
+
+#if BX_DISASM
+# include "disasm/disasm.h"
+#endif
+
+typedef struct {
+ bx_bool floppy;
+ bx_bool keyboard;
+ bx_bool video;
+ bx_bool disk;
+ bx_bool pit;
+ bx_bool pic;
+ bx_bool bios;
+ bx_bool cmos;
+ bx_bool a20;
+ bx_bool interrupts;
+ bx_bool exceptions;
+ bx_bool unsupported;
+ bx_bool temp;
+ bx_bool reset;
+ bx_bool debugger;
+ bx_bool mouse;
+ bx_bool io;
+ bx_bool xms;
+ bx_bool v8086;
+ bx_bool paging;
+ bx_bool creg;
+ bx_bool dreg;
+ bx_bool dma;
+ bx_bool unsupported_io;
+ bx_bool serial;
+ bx_bool cdrom;
+#ifdef MAGIC_BREAKPOINT
+ bx_bool magic_break_enabled;
+#endif /* MAGIC_BREAKPOINT */
+#if BX_SUPPORT_APIC
+ bx_bool apic;
+ bx_bool ioapic;
+#endif
+#if BX_DEBUG_LINUX
+ bx_bool linux_syscall;
+#endif
+ void* record_io;
+ } bx_debug_t;
+
+#define BX_ASSERT(x) do {if (!(x)) BX_PANIC(("failed assertion \"%s\" at %s:%d\n", #x, __FILE__, __LINE__));} while (0)
+void bx_signal_handler (int signum);
+int bx_atexit(void);
+BOCHSAPI extern bx_debug_t bx_dbg;
+
+
+
+/* Already in gui/siminterface.h ???
+#define BX_FLOPPY_NONE 10 // floppy not present
+#define BX_FLOPPY_1_2 11 // 1.2M 5.25"
+#define BX_FLOPPY_1_44 12 // 1.44M 3.5"
+#define BX_FLOPPY_2_88 13 // 2.88M 3.5"
+#define BX_FLOPPY_720K 14 // 720K 3.5"
+#define BX_FLOPPY_360K 15 // 360K 5.25"
+#define BX_FLOPPY_LAST 15 // last one
+*/
+
+
+#define BX_READ 0
+#define BX_WRITE 1
+#define BX_RW 2
+
+
+
+
+
+#include "memory/memory.h"
+
+
+enum PCS_OP { PCS_CLEAR, PCS_SET, PCS_TOGGLE };
+
+#include "pc_system.h"
+#include "plugin.h"
+#include "gui/gui.h"
+#include "gui/textconfig.h"
+#include "gui/keymap.h"
+#include "iodev/iodev.h"
+
+
+
+
+
+
+
+/* --- EXTERNS --- */
+
+#if ( BX_PROVIDE_DEVICE_MODELS==1 )
+BOCHSAPI extern bx_devices_c bx_devices;
+#endif
+
+#if BX_GUI_SIGHANDLER
+extern bx_bool bx_gui_sighandler;
+#endif
+
+// This value controls how often each I/O device's periodic() method
+// gets called. The timer is set up in iodev/devices.cc.
+#define BX_IODEV_HANDLER_PERIOD 100 // microseconds
+//#define BX_IODEV_HANDLER_PERIOD 10 // microseconds
+
+char *bx_find_bochsrc (void);
+int bx_parse_cmdline (int arg, int argc, char *argv[]);
+int bx_read_configuration (char *rcfile);
+int bx_write_configuration (char *rcfile, int overwrite);
+void bx_reset_options (void);
+
+#define BX_PATHNAME_LEN 512
+
+typedef struct {
+ bx_param_bool_c *Opresent;
+ bx_param_num_c *Oioaddr1;
+ bx_param_num_c *Oioaddr2;
+ bx_param_num_c *Oirq;
+ } bx_ata_options;
+
+typedef struct {
+ bx_param_string_c *Opath;
+ bx_param_num_c *Oaddress;
+ } bx_rom_options;
+
+typedef struct {
+ bx_param_string_c *Opath;
+ } bx_vgarom_options;
+
+typedef struct {
+ bx_param_num_c *Osize;
+ } bx_mem_options;
+
+typedef struct {
+ bx_param_bool_c *Oenabled;
+ bx_param_string_c *Ooutfile;
+} bx_parport_options;
+
+typedef struct {
+ bx_param_string_c *Opath;
+ bx_param_bool_c *OcmosImage;
+ } bx_cmos_options;
+
+typedef struct {
+ bx_param_num_c *Otime0;
+ bx_param_enum_c *Osync;
+ } bx_clock_options;
+
+typedef struct {
+ bx_param_bool_c *Opresent;
+ bx_param_num_c *Oioaddr;
+ bx_param_num_c *Oirq;
+ bx_param_string_c *Omacaddr;
+ bx_param_enum_c *Oethmod;
+ bx_param_string_c *Oethdev;
+ bx_param_string_c *Oscript;
+ } bx_ne2k_options;
+
+typedef struct {
+// These options are used for a special hack to load a
+// 32bit OS directly into memory, so it can be run without
+// any of the 16bit real mode or BIOS assistance. This
+// is for the development of plex86, so we don't have
+// to implement real mode up front.
+ bx_param_num_c *OwhichOS;
+ bx_param_string_c *Opath;
+ bx_param_string_c *Oiolog;
+ bx_param_string_c *Oinitrd;
+ } bx_load32bitOSImage_t;
+
+typedef struct {
+ bx_param_string_c *Ofilename;
+ bx_param_string_c *Oprefix;
+ bx_param_string_c *Odebugger_filename;
+} bx_log_options;
+
+typedef struct {
+ bx_param_bool_c *Opresent;
+ bx_param_string_c *Omidifile;
+ bx_param_string_c *Owavefile;
+ bx_param_string_c *Ologfile;
+ bx_param_num_c *Omidimode;
+ bx_param_num_c *Owavemode;
+ bx_param_num_c *Ologlevel;
+ bx_param_num_c *Odmatimer;
+ } bx_sb16_options;
+
+typedef struct {
+ unsigned int port;
+ unsigned int text_base;
+ unsigned int data_base;
+ unsigned int bss_base;
+ } bx_gdbstub_t;
+
+typedef struct {
+ bx_param_bool_c *OuseMapping;
+ bx_param_string_c *Okeymap;
+ } bx_keyboard_options;
+
+#define BX_KBD_XT_TYPE 0
+#define BX_KBD_AT_TYPE 1
+#define BX_KBD_MF_TYPE 2
+
+#define BX_N_OPTROM_IMAGES 4
+#define BX_N_SERIAL_PORTS 1
+#define BX_N_PARALLEL_PORTS 1
+#define BX_N_USB_HUBS 1
+
+typedef struct BOCHSAPI {
+ bx_floppy_options floppya;
+ bx_floppy_options floppyb;
+ bx_ata_options ata[BX_MAX_ATA_CHANNEL];
+ bx_atadevice_options atadevice[BX_MAX_ATA_CHANNEL][2];
+ // bx_disk_options diskc;
+ // bx_disk_options diskd;
+ // bx_cdrom_options cdromd;
+ bx_serial_options com[BX_N_SERIAL_PORTS];
+ bx_usb_options usb[BX_N_USB_HUBS];
+ bx_rom_options rom;
+ bx_vgarom_options vgarom;
+ bx_rom_options optrom[BX_N_OPTROM_IMAGES]; // Optional rom images
+ bx_mem_options memory;
+ bx_parport_options par[BX_N_PARALLEL_PORTS]; // parallel ports
+ bx_sb16_options sb16;
+ bx_param_num_c *Obootdrive;
+ bx_param_bool_c *OfloppySigCheck;
+ bx_param_num_c *Ovga_update_interval;
+ bx_param_num_c *Okeyboard_serial_delay;
+ bx_param_num_c *Okeyboard_paste_delay;
+ bx_param_enum_c *Okeyboard_type;
+ bx_param_num_c *Ofloppy_command_delay;
+ bx_param_num_c *Oips;
+ bx_param_bool_c *Orealtime_pit;
+ bx_param_bool_c *Otext_snapshot_check;
+ bx_param_bool_c *Omouse_enabled;
+ bx_param_bool_c *Oprivate_colormap;
+#if BX_WITH_AMIGAOS
+ bx_param_bool_c *Ofullscreen;
+ bx_param_string_c *Oscreenmode;
+#endif
+ bx_param_bool_c *Oi440FXSupport;
+ bx_cmos_options cmos;
+ bx_clock_options clock;
+ bx_ne2k_options ne2k;
+ bx_param_bool_c *OnewHardDriveSupport;
+ bx_load32bitOSImage_t load32bitOSImage;
+ bx_log_options log;
+ bx_keyboard_options keyboard;
+ bx_param_string_c *Ouser_shortcut;
+ bx_gdbstub_t gdbstub;
+ bx_param_enum_c *Osel_config;
+ bx_param_enum_c *Osel_displaylib;
+ } bx_options_t;
+
+BOCHSAPI extern bx_options_t bx_options;
+
+void bx_center_print (FILE *file, char *line, int maxwidth);
+
+#if BX_PROVIDE_CPU_MEMORY==1
+#else
+// # include "external_interface.h"
+#endif
+
+#define BX_USE_PS2_MOUSE 1
+
+int bx_init_hardware ();
+
+#include "instrument.h"
+
+// These are some convenience macros which abstract out accesses between
+// a variable in native byte ordering to/from guest (x86) memory, which is
+// always in little endian format. You must deal with alignment (if your
+// system cares) and endian rearranging. Don't assume anything. You could
+// put some platform specific asm() statements here, to make use of native
+// instructions to help perform these operations more efficiently than C++.
+
+
+#ifdef __i386__
+
+#define WriteHostWordToLittleEndian(hostPtr, nativeVar16) \
+ *((Bit16u*)(hostPtr)) = (nativeVar16)
+#define WriteHostDWordToLittleEndian(hostPtr, nativeVar32) \
+ *((Bit32u*)(hostPtr)) = (nativeVar32)
+#define WriteHostQWordToLittleEndian(hostPtr, nativeVar64) \
+ *((Bit64u*)(hostPtr)) = (nativeVar64)
+#define ReadHostWordFromLittleEndian(hostPtr, nativeVar16) \
+ (nativeVar16) = *((Bit16u*)(hostPtr))
+#define ReadHostDWordFromLittleEndian(hostPtr, nativeVar32) \
+ (nativeVar32) = *((Bit32u*)(hostPtr))
+#define ReadHostQWordFromLittleEndian(hostPtr, nativeVar64) \
+ (nativeVar64) = *((Bit64u*)(hostPtr))
+
+#else
+
+#define WriteHostWordToLittleEndian(hostPtr, nativeVar16) { \
+ ((Bit8u *)(hostPtr))[0] = (Bit8u) (nativeVar16); \
+ ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar16)>>8); \
+ }
+#define WriteHostDWordToLittleEndian(hostPtr, nativeVar32) { \
+ ((Bit8u *)(hostPtr))[0] = (Bit8u) (nativeVar32); \
+ ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar32)>>8); \
+ ((Bit8u *)(hostPtr))[2] = (Bit8u) ((nativeVar32)>>16); \
+ ((Bit8u *)(hostPtr))[3] = (Bit8u) ((nativeVar32)>>24); \
+ }
+#define WriteHostQWordToLittleEndian(hostPtr, nativeVar64) { \
+ ((Bit8u *)(hostPtr))[0] = (Bit8u) (nativeVar64); \
+ ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar64)>>8); \
+ ((Bit8u *)(hostPtr))[2] = (Bit8u) ((nativeVar64)>>16); \
+ ((Bit8u *)(hostPtr))[3] = (Bit8u) ((nativeVar64)>>24); \
+ ((Bit8u *)(hostPtr))[4] = (Bit8u) ((nativeVar64)>>32); \
+ ((Bit8u *)(hostPtr))[5] = (Bit8u) ((nativeVar64)>>40); \
+ ((Bit8u *)(hostPtr))[6] = (Bit8u) ((nativeVar64)>>48); \
+ ((Bit8u *)(hostPtr))[7] = (Bit8u) ((nativeVar64)>>56); \
+ }
+#define ReadHostWordFromLittleEndian(hostPtr, nativeVar16) { \
+ (nativeVar16) = ((Bit16u) ((Bit8u *)(hostPtr))[0]) | \
+ (((Bit16u) ((Bit8u *)(hostPtr))[1])<<8) ; \
+ }
+#define ReadHostDWordFromLittleEndian(hostPtr, nativeVar32) { \
+ (nativeVar32) = ((Bit32u) ((Bit8u *)(hostPtr))[0]) | \
+ (((Bit32u) ((Bit8u *)(hostPtr))[1])<<8) | \
+ (((Bit32u) ((Bit8u *)(hostPtr))[2])<<16) | \
+ (((Bit32u) ((Bit8u *)(hostPtr))[3])<<24); \
+ }
+#define ReadHostQWordFromLittleEndian(hostPtr, nativeVar64) { \
+ (nativeVar64) = ((Bit64u) ((Bit8u *)(hostPtr))[0]) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[1])<<8) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[2])<<16) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[3])<<24) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[4])<<32) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[5])<<40) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[6])<<48) | \
+ (((Bit64u) ((Bit8u *)(hostPtr))[7])<<56); \
+ }
+
+#endif
+
+#ifdef BX_USE_VMX
+extern int domid;
+extern unsigned long megabytes;
+#endif
+
+#endif /* BX_BOCHS_H */
diff --git a/tools/ioemu/include/bxversion.h b/tools/ioemu/include/bxversion.h
new file mode 100644
index 0000000000..1c640f9f86
--- /dev/null
+++ b/tools/ioemu/include/bxversion.h
@@ -0,0 +1,7 @@
+/////////////////////////////////////////////////////////////////////////
+// This file is checked in as bxversion.h.in. The configure script
+// substitutes variables and creates bxversion.h.
+/////////////////////////////////////////////////////////////////////////
+
+#define VER_STRING "2.1.1"
+#define REL_STRING "February 08, 2004"
diff --git a/tools/ioemu/include/config.h b/tools/ioemu/include/config.h
new file mode 100644
index 0000000000..e48f2d97e5
--- /dev/null
+++ b/tools/ioemu/include/config.h
@@ -0,0 +1,919 @@
+/* config.h. Generated by configure. */
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// config.h.in is distributed in the source TAR file. When you run
+// the configure script, it generates config.h with some changes
+// according to your build environment. For example, in config.h.in,
+// SIZEOF_UNSIGNED_CHAR is set to 0. When configure produces config.h
+// it will change "0" to the detected value for your system.
+//
+// config.h contains ONLY preprocessor #defines and a few typedefs.
+// It must be included by both C and C++ files, so it must not
+// contain anything language dependent such as a class declaration.
+//
+
+#ifdef _BX_CONFIG_H_
+#else
+#define _BX_CONFIG_H_ 1
+
+///////////////////////////////////////////////////////////////////
+// USER CONFIGURABLE OPTIONS : EDIT ONLY OPTIONS IN THIS SECTION //
+///////////////////////////////////////////////////////////////////
+
+
+#if 1
+// quit_sim is defined in gui/siminterface.h
+#define BX_EXIT(x) SIM->quit_sim (x)
+#else
+// provide the real main and the usual exit.
+#define BX_EXIT(x) ::exit(x)
+#endif
+
+#define BX_USE_CONFIG_INTERFACE 0
+#define BX_USE_VMX 1
+
+// I have tested the following combinations:
+// * processors=1, bootstrap=0, ioapic_id=1 (uniprocessor system)
+// * processors=2, bootstrap=0, ioapic_id=2
+// * processors=4, bootstrap=2, ioapic_id=4
+#define BX_SMP_PROCESSORS 1
+#define BX_BOOTSTRAP_PROCESSOR 0
+// choose IOAPIC id to be equal to the number of processors. This leaves
+// one space for each processor to have an ID, starting with 0.
+#define BX_IOAPIC_DEFAULT_ID 1
+
+#define BX_ADDRESS_SPACES 1
+// controls how many instances of BX_MEM_C are created. For
+// SMP, use several processors with one shared memory space.
+// For cosimulation, you could use two processors and two address
+// spaces.
+
+#define BX_SUPPORT_APIC 0
+// include in APIC models, required for a multiprocessor system.
+
+#if (BX_SMP_PROCESSORS>1 && !BX_SUPPORT_APIC)
+#error For multiprocessor simulation, BX_SUPPORT_APIC is required.
+#endif
+
+#define BX_DEBUG_LINUX 0
+// if simulating Linux, this provides a few more debugging options
+// such as tracing all system calls.
+
+#define HAVE_LIBREADLINE 0
+#define HAVE_READLINE_HISTORY_H 1
+// adds support for the GNU readline library in the debugger command
+// prompt.
+
+#define HAVE_LOCALE_H 0
+// Define to 1 if you have <locale.h>
+
+// I rebuilt the code which provides timers to IO devices.
+// Setting this to 1 will introduce a little code which
+// will panic out if cases which shouldn't happen occur.
+// Set this to 0 for optimal performance.
+#define BX_TIMER_DEBUG 1
+
+// Settable A20 line. For efficiency, you can disable
+// having a settable A20 line, eliminating conditional
+// code for every physical memory access. You'll have
+// to tell your software not to mess with the A20 line,
+// and accept it as always being on if you change this.
+// 1 = use settable A20 line. (normal)
+// 0 = A20 is like the rest of the address lines
+
+#define BX_SUPPORT_A20 1
+
+// Processor Instructions Per Second
+// To find out what value to use for the 'ips' directive
+// in your '.bochsrc' file, set BX_SHOW_IPS to 1, and
+// run the software in bochs you plan to use most. Bochs
+// will print out periodic IPS ratings. This will change
+// based on the processor mode at the time, and various
+// other factors. You'll get a reasonable estimate though.
+// When you're done, reset BX_SHOW_IPS to 0, do a
+// 'make all-clean', then 'make' again.
+
+#define BX_SHOW_IPS 0
+
+
+#if (BX_SHOW_IPS) && defined(__MINGW32__)
+#define SIGALRM 14
+#endif
+
+// Paging Options:
+// ---------------
+// Support Paging mechanism.
+// 0 = don't support paging at all (DOS & Minix don't require it)
+// 1 = support paging. (Most other OS's require paging)
+// Use Translation Lookaside Buffer (TLB) for caching
+// paging translations. This will make paging mode
+// more efficient. If you're OS doesn't use paging,
+// then you won't need either.
+// 1 = Use a TLB for effiency
+// 0 = don't use a TLB, walk the page tables for every access
+// BX_TLB_SIZE: Number of entries in TLB
+// BX_TLB_INDEX_OF(lpf): This macro is passed the linear page frame
+// (top 20 bits of the linear address. It must map these bits to
+// one of the TLB cache slots, given the size of BX_TLB_SIZE.
+// There will be a many-to-one mapping to each TLB cache slot.
+// When there are collisions, the old entry is overwritten with
+// one for the newest access.
+
+#define BX_SUPPORT_PAGING 1
+#define BX_USE_TLB 1
+
+#define BX_TLB_SIZE 1024
+#define BX_TLB_INDEX_OF(lpf) (((lpf) & 0x003ff000) >> 12)
+
+#define BX_USE_QUICK_TLB_INVALIDATE 0
+
+// Compile in support for DMA & FLOPPY IO. You'll need this
+// if you plan to use the floppy drive emulation. But if
+// you're environment doesn't require it, you can change
+// it to 0.
+
+#define BX_DMA_FLOPPY_IO 1
+
+
+// Default number of Megs of memory to emulate. The
+// 'megs:' directive in the '.bochsrc' file overrides this,
+// allowing per-run settings.
+
+#define BX_DEFAULT_MEM_MEGS 4
+
+
+// CPU level emulation. Default level is set in
+// the configure script. BX_CPU_LEVEL defines the CPU level
+// to emulate. BX_CPU_LEVEL_HACKED is a hack to define the
+// level of some integer instructions, so they can be tested
+// before the rest of the emulation is up to that level.
+
+#define BX_CPU_LEVEL 5
+#define BX_CPU_LEVEL_HACKED 5
+
+// emulate x86-64 instruction set?
+#define BX_SUPPORT_X86_64 0
+
+// Virtual 8086 mode emulation.
+// 1 = compile in support for v8086 mode.
+// 0 = don't compile in support for v8086 mode.
+#define BX_SUPPORT_V8086_MODE 1
+
+// Defines if the simulation should reset on triple fault
+// if set to 0, the simulation will panic.
+#define BX_RESET_ON_TRIPLE_FAULT 1
+
+// Support shadowing of ROM from C0000 to FFFFF.
+// This allows that region to be written to.
+#define BX_SHADOW_RAM 0
+
+// Number of CMOS registers
+#define BX_NUM_CMOS_REGS 64
+//#define BX_NUM_CMOS_REGS 128
+
+// Use Greg Alexander's new PIT model (summer 2001) instead of the original.
+#define BX_USE_NEW_PIT 1
+
+#define BX_USE_SLOWDOWN_TIMER 0
+#define BX_HAVE_SLEEP 1
+#define BX_HAVE_MSLEEP 0
+#define BX_HAVE_USLEEP 1
+#define BX_HAVE_NANOSLEEP 1
+#define BX_HAVE_ABORT 1
+#define BX_HAVE_SOCKLEN_T 1
+#define BX_HAVE_SOCKADDR_IN_SIN_LEN 0
+#define BX_HAVE_GETTIMEOFDAY 1
+#if defined(WIN32)
+#define BX_HAVE_REALTIME_USEC 1
+#else
+#define BX_HAVE_REALTIME_USEC (BX_HAVE_GETTIMEOFDAY)
+#endif
+#define BX_HAVE_MKSTEMP 1
+#define BX_HAVE_SYS_MMAN_H 1
+#define BX_HAVE_XPM_H 1
+#define BX_HAVE_TIMELOCAL 1
+#define BX_HAVE_GMTIME 1
+#define BX_HAVE_MKTIME 1
+
+// This turns on Roland Mainz's idle hack. Presently it is specific to the X11
+// gui. If people try to enable it elsewhere, give a compile error after the
+// gui definition so that they don't waste their time trying.
+#define BX_USE_IDLE_HACK 0
+
+// Minimum Emulated IPS.
+// This is used in the realtime PIT as well as for checking the
+// IPS value set in the config file.
+#define BX_MIN_IPS 200000
+
+// Use Static Member Funtions to eliminate 'this' pointer passing
+// If you want the efficiency of 'C', you can make all the
+// members of the C++ CPU class to be static.
+// This defaults to 1 since it should improve performance, but when
+// SMP mode is enabled, it will be turned off by configure.
+
+#define BX_USE_CPU_SMF 1
+
+// Use static member functions in IO DEVice emulation modules.
+// For efficiency, use C like functions for IO handling,
+// and declare a device instance at compile time,
+// instead of using 'new' and storing the pointer. This
+// eliminates some overhead, especially for high-use IO
+// devices like the disk drive.
+// 1 = Use static member efficiency (normal)
+// 0 = Use nonstatic member functions (use only if you need
+// multiple instances of a device class
+
+#define BX_USE_HD_SMF 1 // Hard drive
+#define BX_USE_BIOS_SMF 1 // BIOS
+#define BX_USE_CMOS_SMF 1 // CMOS
+#define BX_USE_DMA_SMF 1 // DMA
+#define BX_USE_FD_SMF 1 // Floppy
+#define BX_USE_KEY_SMF 1 // Keyboard
+#define BX_USE_PAR_SMF 1 // Parallel
+#define BX_USE_PIC_SMF 1 // PIC
+#define BX_USE_PIT_SMF 1 // PIT
+#define BX_USE_SER_SMF 1 // Serial
+#define BX_USE_UM_SMF 1 // Unmapped
+#define BX_USE_VGA_SMF 1 // VGA
+#define BX_USE_SB16_SMF 1 // Sound (SB 16)
+#define BX_USE_DEV_SMF 1 // System Devices (port92)
+#define BX_USE_PCI_SMF 1 // PCI
+#define BX_USE_P2I_SMF 1 // PCI-to-ISA bridge
+#define BX_USE_PCIVGA_SMF 1 // PCI-VGA
+#define BX_USE_PCIUSB_SMF 1 // USB hub
+#define BX_USE_NE2K_SMF 1 // NE2K
+#define BX_USE_EFI_SMF 1 // External FPU IRQ
+#define BX_USE_GAME_SMF 1 // Gameport
+
+#define BX_PLUGINS 0
+#define BX_HAVE_DLFCN_H 1
+
+#if BX_PLUGINS && \
+ ( !BX_USE_HD_SMF || !BX_USE_BIOS_SMF || !BX_USE_CMOS_SMF \
+ || !BX_USE_DMA_SMF || !BX_USE_FD_SMF || !BX_USE_KEY_SMF \
+ || !BX_USE_PAR_SMF || !BX_USE_PIC_SMF || !BX_USE_PIT_SMF \
+ || !BX_USE_SER_SMF || !BX_USE_UM_SMF || !BX_USE_VGA_SMF \
+ || !BX_USE_SB16_SMF || !BX_USE_DEV_SMF || !BX_USE_PCI_SMF \
+ || !BX_USE_P2I_SMF || !BX_USE_PCIVGA_SMF || !BX_USE_PCIUSB_SMF \
+ || !BX_USE_NE2K_SMF || !BX_USE_EFI_SMF || !BX_USE_GAME_SMF)
+#error You must use SMF to have plugins
+#endif
+
+#define BX_SUPPORT_SB16 0
+#define BX_SUPPORT_GAME 0
+
+#if BX_SUPPORT_SB16
+// Use virtual methods for the sound output functions
+#define BX_USE_SOUND_VIRTUAL 1
+// Determines which sound output class is to be used.
+// Currently the following are available:
+// bx_sound_linux_c Output for Linux, to /dev/dsp and /dev/midi00
+// bx_sound_windows_c Output for Windows midi and wave mappers
+// bx_sound_output_c Dummy functions, no output
+#define BX_SOUND_OUTPUT_C bx_sound_output_c
+#endif
+
+#define USE_RAW_SERIAL 0
+
+#define BX_USE_SPECIFIED_TIME0 0
+
+// This enables writing to port 0xe9 and the output
+// is sent to the console. Reading from port 0xe9
+// will return 0xe9 to let you know this is available.
+// Leave this 0 unless you have a reason to use it.
+#define BX_PORT_E9_HACK 1
+
+#define BX_GDBSTUB 0
+
+// This option enables compressed (zlib) hd support
+#define BX_COMPRESSED_HD_SUPPORT 0
+#define BX_HAVE_ZLIB 1
+
+#if BX_COMPRESSED_HD_SUPPORT && !BX_HAVE_ZLIB
+#error You must have zlib to enable compressed hd support
+#endif
+
+// This option defines the number of supported ATA channels.
+// There are up to two drives per ATA channel.
+#define BX_MAX_ATA_CHANNEL 4
+
+#if (BX_MAX_ATA_CHANNEL>4 || BX_MAX_ATA_CHANNEL<1)
+# error "BX_MAX_ATA_CHANNEL should be between 1 and 4"
+#endif
+
+// =================================================================
+// BEGIN: OPTIONAL DEBUGGER SECTION
+//
+// These options are only used if you compile in support for the
+// native command line debugging environment. Typically, the debugger
+// is not used, and this section can be ignored.
+// =================================================================
+
+#define BX_MAX_DIRTY_PAGE_TABLE_MEGS 1024
+
+// Compile in support for virtual/linear/physical breakpoints.
+// Set to 1, only those you need. Recommend using only linear
+// breakpoints, unless you need others. Less supported means
+// slightly faster execution time.
+#define BX_DBG_SUPPORT_VIR_BPOINT 1
+#define BX_DBG_SUPPORT_LIN_BPOINT 1
+#define BX_DBG_SUPPORT_PHY_BPOINT 1
+
+// You need only define one initial breakpoint into each
+// cpu simulator (emulator) here. Each simulator sets callbacks
+// and variables which the debugger uses from then on.
+#define BX_SIM1_INIT bx_dbg_init_cpu_mem_env0
+#ifndef BX_SIM2_INIT
+#define BX_SIM2_INIT bx_dbg_init_cpu_mem_env1
+#endif
+//#define BX_SIM2_INIT sim2_init
+
+// max number of virtual/linear/physical breakpoints handled
+#define BX_DBG_MAX_VIR_BPOINTS 10
+#define BX_DBG_MAX_LIN_BPOINTS 10
+#define BX_DBG_MAX_PHY_BPOINTS 10
+
+// max file pathname size for debugger commands
+#define BX_MAX_PATH 256
+// max nesting level for debug scripts including other scripts
+#define BX_INFILE_DEPTH 10
+// use this command to include (nest) debug scripts
+#define BX_INCLUDE_CMD "source"
+
+// Use either 32 or 64 bit instruction counter for
+// debugger purposes. Uncomment one of these.
+//#define BX_DBG_ICOUNT_SIZE 32
+#define BX_DBG_ICOUNT_SIZE 64
+
+// Make a call to command line debugger extensions. If set to 1,
+// a call is made. An external routine has a chance to process
+// the command. If it does, than the debugger ignores the command.
+#define BX_DBG_EXTENSIONS 0
+
+// =================================================================
+// END: OPTIONAL DEBUGGER SECTION
+// =================================================================
+
+
+//////////////////////////////////////////////////////////////////////
+// END OF USER CONFIGURABLE OPTIONS : DON'T EDIT ANYTHING BELOW !!! //
+// THIS IS GENERATED BY THE ./configure SCRIPT //
+//////////////////////////////////////////////////////////////////////
+
+
+#define BX_WITH_X11 1
+#define BX_WITH_BEOS 0
+#define BX_WITH_WIN32 0
+#define BX_WITH_MACOS 0
+#define BX_WITH_CARBON 0
+#define BX_WITH_NOGUI 0
+#define BX_WITH_TERM 0
+#define BX_WITH_RFB 0
+#define BX_WITH_AMIGAOS 0
+#define BX_WITH_SDL 0
+#define BX_WITH_SVGA 0
+#define BX_WITH_WX 0
+
+// add special export symbols for win32 DLL building. The main code must
+// have __declspec(dllexport) on variables, functions, or classes that the
+// plugins can access. The plugins should #define PLUGGABLE which will
+// activate the __declspec(dllimport) instead.
+#if defined(WIN32) || defined(__CYGWIN__)
+# if BX_PLUGINS && defined(BX_PLUGGABLE)
+// #warning I will import DLL symbols from Bochs main program.
+# define BOCHSAPI __declspec(dllimport)
+# else
+// #warning I will export DLL symbols.
+# define BOCHSAPI __declspec(dllexport)
+# endif
+#endif
+#ifndef BOCHSAPI
+# define BOCHSAPI
+#endif
+
+#if defined(__CYGWIN__)
+// Make BOCHSAPI_CYGONLY exactly the same as BOCHSAPI. This symbol
+// will be used for any cases where Cygwin requires a special tag
+// but VC++ does not.
+#define BOCHSAPI_CYGONLY BOCHSAPI
+#else
+// define the symbol to be empty
+#define BOCHSAPI_CYGONLY /*empty*/
+#endif
+
+#define BX_DEFAULT_CONFIG_INTERFACE "defined_by_configure"
+#define BX_DEFAULT_DISPLAY_LIBRARY "defined_by_configure"
+
+// Roland Mainz's idle hack is presently specific to X11. If people try to
+// enable it elsewhere, give a compile error so that they don't waste their
+// time trying.
+#if (BX_USE_IDLE_HACK && !BX_WITH_X11)
+# error IDLE_HACK will only work with the X11 gui. Correct configure args and retry.
+#endif
+
+#define WORDS_BIGENDIAN 0
+
+#define SIZEOF_UNSIGNED_CHAR 1
+#define SIZEOF_UNSIGNED_SHORT 2
+#define SIZEOF_UNSIGNED_INT 4
+#define SIZEOF_UNSIGNED_LONG 4
+#define SIZEOF_UNSIGNED_LONG_LONG 8
+#define SIZEOF_INT_P 4
+
+#define BX_64BIT_CONSTANTS_USE_LL 1
+#if BX_64BIT_CONSTANTS_USE_LL
+// doesn't work on Microsoft Visual C++, maybe others
+#define BX_CONST64(x) (x##LL)
+#else
+#define BX_CONST64(x) (x)
+#endif
+
+#if defined(WIN32)
+ typedef unsigned char Bit8u;
+ typedef signed char Bit8s;
+ typedef unsigned short Bit16u;
+ typedef signed short Bit16s;
+ typedef unsigned int Bit32u;
+ typedef signed int Bit32s;
+#ifdef __MINGW32__
+ typedef unsigned long long Bit64u;
+ typedef signed long long Bit64s;
+#include <sys/types.h>
+#else
+ typedef unsigned __int64 Bit64u;
+ typedef signed __int64 Bit64s;
+#endif
+#elif BX_WITH_MACOS
+ typedef unsigned char Bit8u;
+ typedef signed char Bit8s;
+ typedef unsigned short Bit16u;
+ typedef signed short Bit16s;
+ typedef unsigned int Bit32u;
+ typedef signed int Bit32s;
+ typedef unsigned long long Bit64u;
+ typedef signed long long Bit64s;
+#else
+
+// Unix like platforms
+
+#if SIZEOF_UNSIGNED_CHAR != 1
+# error "sizeof (unsigned char) != 1"
+#else
+ typedef unsigned char Bit8u;
+ typedef signed char Bit8s;
+#endif
+
+#if SIZEOF_UNSIGNED_SHORT != 2
+# error "sizeof (unsigned short) != 2"
+#else
+ typedef unsigned short Bit16u;
+ typedef signed short Bit16s;
+#endif
+
+#if SIZEOF_UNSIGNED_INT == 4
+ typedef unsigned int Bit32u;
+ typedef signed int Bit32s;
+#elif SIZEOF_UNSIGNED_LONG == 4
+ typedef unsigned long Bit32u;
+ typedef signed long Bit32s;
+#else
+# error "can't find sizeof(type) of 4 bytes!"
+#endif
+
+#if SIZEOF_UNSIGNED_LONG == 8
+ typedef unsigned long Bit64u;
+ typedef signed long Bit64s;
+#elif SIZEOF_UNSIGNED_LONG_LONG == 8
+ typedef unsigned long long Bit64u;
+ typedef signed long long Bit64s;
+#else
+# error "can't find data type of 8 bytes"
+#endif
+
+#endif
+
+// now that Bit32u and Bit64u exist, defined bx_address
+#if BX_SUPPORT_X86_64
+typedef Bit64u bx_address;
+#else
+typedef Bit32u bx_address;
+#endif
+
+
+// technically, in an 8 bit signed the real minimum is -128, not -127.
+// But if you decide to negate -128 you tend to get -128 again, so it's
+// better not to use the absolute maximum in the signed range.
+#define BX_MAX_BIT64U ( (Bit64u) -1 )
+#define BX_MIN_BIT64U ( 0 )
+#define BX_MAX_BIT64S ( ((Bit64u) -1) >> 1 )
+#define BX_MIN_BIT64S ( -(((Bit64u) -1) >> 1) )
+#define BX_MAX_BIT32U ( (Bit32u) -1 )
+#define BX_MIN_BIT32U ( 0 )
+#define BX_MAX_BIT32S ( ((Bit32u) -1) >> 1 )
+#define BX_MIN_BIT32S ( -(((Bit32u) -1) >> 1) )
+#define BX_MAX_BIT16U ( (Bit16u) -1 )
+#define BX_MIN_BIT16U ( 0 )
+#define BX_MAX_BIT16S ( ((Bit16u) -1) >> 1 )
+#define BX_MIN_BIT16S ( -(((Bit16u) -1) >> 1) )
+#define BX_MAX_BIT8U ( (Bit8u) -1 )
+#define BX_MIN_BIT8U ( 0 )
+#define BX_MAX_BIT8S ( ((Bit8u) -1) >> 1 )
+#define BX_MIN_BIT8S ( -(((Bit8u) -1) >> 1) )
+
+
+// create an unsigned integer type that is the same size as a pointer.
+// You can typecast a pointer to a bx_pr_equiv_t without losing any
+// bits (and without getting the compiler excited). This is used in
+// the FPU emulation code, where pointers and integers are often
+// used interchangeably.
+#if SIZEOF_INT_P == 4
+ typedef Bit32u bx_ptr_equiv_t;
+#elif SIZEOF_INT_P == 8
+ typedef Bit64u bx_ptr_equiv_t;
+#else
+# error "could not define bx_ptr_equiv_t to size of int*"
+#endif
+
+// Use a boolean type that will not conflict with the builtin type
+// on any system.
+typedef Bit32u bx_bool;
+
+#if BX_WITH_MACOS
+# define bx_ptr_t char *
+#else
+# define bx_ptr_t void *
+#endif
+
+#if defined(WIN32)
+# define BX_LITTLE_ENDIAN
+#elif BX_WITH_MACOS
+# define BX_BIG_ENDIAN
+#else
+#if WORDS_BIGENDIAN
+# define BX_BIG_ENDIAN
+#else
+# define BX_LITTLE_ENDIAN
+#endif
+#endif // defined(WIN32)
+
+
+#if BX_SUPPORT_X86_64
+#ifdef BX_LITTLE_ENDIAN
+typedef
+ struct {
+ Bit64u lo;
+ Bit64u hi;
+ } Bit128u;
+typedef
+ struct {
+ Bit64u lo;
+ Bit64s hi;
+ } Bit128s;
+#else // must be Big Endian
+typedef
+ struct {
+ Bit64u hi;
+ Bit64u lo;
+ } Bit128u;
+typedef
+ struct {
+ Bit64s hi;
+ Bit64u lo;
+ } Bit128s;
+#endif
+#endif // #if BX_SUPPORT_X86_64
+
+
+// for now only term.cc requires a GUI sighandler.
+#define BX_GUI_SIGHANDLER (BX_WITH_TERM)
+
+#define HAVE_SIGACTION 1
+
+// configure will change the definition of "inline" to the value
+// that the C compiler allows. It tests the following keywords to
+// see if any is permitted: inline, __inline__, __inline. If none
+// is permitted, it defines inline to be empty.
+#define inline inline
+
+// inline functions in headers that are compiled with C compiler
+// (e.g. fpu code) are declared with BX_C_INLINE macro. Note that
+// the word "inline" itself may now be redefined by the above #define.
+// Many compilers are known to work with "static inline". If the
+// compiler can put the function inline, it does so and never creates
+// a symbol for the function. If optimization is off, or inline is
+// defined to be empty, the static keyword causes the function to create
+// a symbol that's visible only to that .c file. Each .c file that
+// includes the header will produde another local version of the
+// BX_C_INLINE function (not ideal). However without "static" you can
+// duplicate symbol problems which are even worse.
+#define BX_C_INLINE static inline
+
+// Use BX_CPP_INLINE for all C++ inline functions. Note that the
+// word "inline" itself may now be redefined by the above #define.
+#define BX_CPP_INLINE inline
+
+#ifdef __GNUC__
+
+// Some helpful compiler hints for compilers that allow them; GCC for now.
+//
+// BX_CPP_AlignN(n):
+// Align a construct on an n-byte boundary.
+//
+// BX_CPP_AttrPrintf(formatArg, firstArg):
+// This function takes printf-like arguments, so the compiler can check
+// the consistency of the format string and the matching arguments.
+// 'formatArg' is the parameter number (starting from 1) of the format
+// string argument. 'firstArg' is the parameter number of the 1st argument
+// to check against the string argument. NOTE: For non-static member
+// functions, the this-ptr is argument number 1 but is invisible on
+// the function prototype declaration - but you still have to count it.
+//
+// BX_CPP_AttrNoReturn():
+// This function never returns. The compiler can optimize-out following
+// code accordingly.
+
+#define BX_CPP_AlignN(n) __attribute__ ((aligned (n)))
+#define BX_CPP_AttrPrintf(formatArg, firstArg) \
+ __attribute__ ((format (printf, formatArg, firstArg)))
+#define BX_CPP_AttrNoReturn() __attribute__ ((noreturn))
+
+#else
+
+#define BX_CPP_AlignN(n) /* Not supported. */
+#define BX_CPP_AttrPrintf(formatArg, firstArg) /* Not supported. */
+#define BX_CPP_AttrNoReturn() /* Not supported. */
+
+#endif
+
+#define BX_DEBUGGER 0
+#define BX_DISASM 0
+
+#define BX_PROVIDE_CPU_MEMORY 1
+#define BX_PROVIDE_DEVICE_MODELS 1
+
+#define BX_SUPPORT_VBE 0
+
+#define BX_PROVIDE_MAIN 1
+
+#define BX_INSTRUMENTATION 0
+
+#define BX_USE_LOADER 0
+
+// for debugger, CPU simulator handle ID
+// 0 is the default, for using only one CPU simulator
+// 1 is for the 2nd CPU simulator
+#define BX_SIM_ID 0
+#define BX_NUM_SIMULATORS 1
+
+// limited i440FX PCI support
+#define BX_PCI_SUPPORT 1
+
+// Experimental VGA on PCI
+#define BX_PCI_VGA_SUPPORT 1
+
+// limited USB on PCI
+#define BX_PCI_USB_SUPPORT 1
+
+#if (BX_PCI_USB_SUPPORT && !BX_PCI_SUPPORT)
+#error To enable USB, you must also enable PCI
+#endif
+
+// Promise VLBIDE DC2300 Support
+#define BX_PDC20230C_VLBIDE_SUPPORT 0
+
+#define BX_SUPPORT_FPU 1
+#define BX_SUPPORT_MMX 1
+#define BX_SUPPORT_3DNOW 0
+#define BX_SUPPORT_SSE 0
+#define BX_SUPPORT_DAZ 0
+#define BX_SUPPORT_PNI 0
+#define BX_SUPPORT_SEP 0
+#define BX_SUPPORT_4MEG_PAGES 0
+
+#define BX_SupportGuest2HostTLB 0
+#define BX_SupportRepeatSpeedups 0
+#define BX_SupportGlobalPages 0
+#define BX_SupportPAE 0
+#define BX_SupportICache 0
+#define BX_SupportHostAsms 1
+
+
+// if 1, don't do gpf on MSRs that we don't implement
+#define BX_IGNORE_BAD_MSR 0
+
+// ========================================================
+// These are some very temporary hacks I made to the 64-bit
+// support to help Peter with debugging etc. They will be removed
+// soon and there is no configure option for them (on purpose).
+// By default, they are not compiled in.
+
+// I set this to 1 to bail in instructions which may not be honoring
+// the 64-bit widths of RIP/RSP. If I trip a panic, then I clean
+// the function up and remove the panic. You don't have to use
+// these.
+#if 0
+#define BailBigRSP(s) \
+ if ( (RIP > 0xffffffff) || \
+ (RSP > 0xffffffff) ) \
+ BX_PANIC((s ": bailing due to big RSP value, mode==%u", \
+ BX_CPU_THIS_PTR cpu_mode))
+#else
+#define BailBigRSP(s)
+#endif
+// ========================================================
+
+
+#if (BX_SUPPORT_MMX && BX_CPU_LEVEL < 5)
+#error With CPU level < 5, you must disable MMX support.
+#endif
+
+#if (!BX_SUPPORT_FPU && BX_CPU_LEVEL >= 5)
+#error With CPU level >= 5, you must enable FPU support.
+#endif
+
+#if (BX_SUPPORT_MMX && !BX_SUPPORT_FPU)
+#error "MMX cannot be compiled without FPU support"
+#endif
+
+#if (BX_SUPPORT_3DNOW && !BX_SUPPORT_MMX)
+#error "3DNow! cannot be compiled without MMX support"
+#endif
+
+#if (BX_SUPPORT_SSE && !BX_SUPPORT_MMX)
+#error "SSE cannot be compiled without FPU+MMX support"
+#endif
+
+#if (BX_CPU_LEVEL<6 && BX_SUPPORT_SSE)
+#error SSE is only supported with CPU_LEVEL >= 6
+#endif
+
+#if (BX_SUPPORT_PNI && BX_SUPPORT_SSE <= 1)
+#error "PNI cannot be compiled without SSE/SSE2 support"
+#endif
+
+#if (BX_CPU_LEVEL<6 && BX_SUPPORT_SEP)
+#error SYSENTER/SYSEXIT only supported with CPU_LEVEL >= 6
+#endif
+
+#if BX_SUPPORT_X86_64
+// Sanity checks to ensure that you cannot accidently use conflicting options.
+
+#if BX_CPU_LEVEL < 5
+#error X86-64 requires cpu level 6 or greater
+#endif
+#if (BX_SUPPORT_SSE<2)
+#error X86-64 requires SSE2
+#endif
+#if !BX_SupportPAE
+#error X86-64 requires Physical Address Extensions (PAE)
+#endif
+#if !BX_SupportGlobalPages
+#error X86-64 requires Page Global Extension (PGE)
+#endif
+#if !BX_SUPPORT_4MEG_PAGES
+#error X86-64 requires Page Size Extension (PSE)
+#endif
+
+#if BX_SUPPORT_SEP
+#error SYSENTER/SYSEXIT not implemented for X86-64
+#endif
+
+#endif
+
+#define BX_HAVE_GETENV 1
+#define BX_HAVE_SETENV 1
+#define BX_HAVE_SELECT 1
+#define BX_HAVE_SNPRINTF 1
+#define BX_HAVE_STRTOULL 1
+#define BX_HAVE_STRTOUQ 1
+#define BX_HAVE_STRDUP 1
+#define BX_HAVE_STRREV 0
+#define BX_HAVE_STRUCT_TIMEVAL 1
+
+// used in term gui
+#define BX_HAVE_COLOR_SET 0
+#define BX_HAVE_MVHLINE 0
+#define BX_HAVE_MVVLINE 0
+
+
+// set if your compiler does not permit an empty struct
+#define BX_NO_EMPTY_STRUCTS 0
+
+// set if your compiler does not understand __attribute__ after a struct
+#define BX_NO_ATTRIBUTES 0
+#if BX_NO_ATTRIBUTES
+#define GCC_ATTRIBUTE(x) /* attribute not supported */
+#else
+#define GCC_ATTRIBUTE __attribute__
+#endif
+
+// set to use fast function calls
+#define BX_FAST_FUNC_CALL 0
+
+// On gcc2.95+ x86 only
+#if BX_FAST_FUNC_CALL && defined(__i386__) && defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+# define BX_CPP_AttrRegparmN(X) __attribute__((regparm(X)))
+#else
+# define BX_CPP_AttrRegparmN(X) /* Not defined */
+#endif
+
+// set if your compiler does not allow label at the end of a {} block
+#define BX_NO_BLANK_LABELS 0
+
+// set if you do have <hash_map>, used in bx_debug/dbg_main.c
+#define BX_HAVE_HASH_MAP 0
+
+// set if you do have <hash_map.h>, used in bx_debug/dbg_main.c
+#define BX_HAVE_HASH_MAP_H 1
+
+// set if you do have <set>, used in bx_debug/dbg_main.c
+#define BX_HAVE_SET 1
+
+// set if you do have <set.h>, used in bx_debug/dbg_main.c
+#define BX_HAVE_SET_H 1
+
+// Support x86 hardware debugger registers and facilites.
+// These are the debug facilites offered by the x86 architecture,
+// not the optional built-in debugger.
+#define BX_X86_DEBUGGER 0
+
+#define BX_SUPPORT_CDROM 1
+
+#if BX_SUPPORT_CDROM
+ // This is the C++ class name to use if we are supporting
+ // low-level CDROM.
+# define LOWLEVEL_CDROM cdrom_interface
+#endif
+
+// NE2K network emulation
+#define BX_NE2K_SUPPORT 1
+#define BX_ETH_NULL_LOGGING 1
+#define BX_ETH_FBSD_LOGGING 1
+
+// determine which NE2K packet mover modules will be enabled
+// (this was moved from iodev/eth.h)
+#define ETH_NULL 1
+#ifdef BX_USE_ETH_ARPBACK
+# define ETH_ARPBACK 1
+#endif
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+#define ETH_FBSD 1
+#endif
+#if defined(linux)
+#define ETH_LINUX 1
+#endif
+#if defined(WIN32)
+#define ETH_WIN32 1
+#endif
+
+// this enables Ethertap packet mover; determined by configure script
+#define HAVE_ETHERTAP 0
+
+// this enables TUN/TAP packet mover; determined by configure script
+#define HAVE_TUNTAP 1
+
+
+// I/O Interface to debug
+#define BX_IODEBUG_SUPPORT 0
+
+// External Debugger
+#define BX_EXTERNAL_DEBUGGER 0
+#define BX_OVERRIDE_ASK 0
+
+#ifdef WIN32
+#define BX_FLOPPY0_NAME "Floppy Disk A:"
+#define BX_FLOPPY1_NAME "Floppy Disk B:"
+#else
+#define BX_FLOPPY0_NAME "Floppy Disk 0"
+#define BX_FLOPPY1_NAME "Floppy Disk 1"
+#endif
+
+// This is handy for certain performance testing purposes, but otherwise
+// totally useless. If you define BX_SCHEDULED_DIE_TIME then it enables code
+// in bx_pit_c::periodic that will cause Bochs to exit() after a certain number
+// of instructions.
+//#define BX_SCHEDULED_DIE_TIME 1162230000 // end of redhat6.0 boot
+
+
+#endif // _BX_CONFIG_H
diff --git a/tools/ioemu/include/cpu/cpu.h b/tools/ioemu/include/cpu/cpu.h
new file mode 100644
index 0000000000..0627ee385e
--- /dev/null
+++ b/tools/ioemu/include/cpu/cpu.h
@@ -0,0 +1,116 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cpu.h,v 1.155 2003/12/30 22:12:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#ifndef BX_CPU_H
+# define BX_CPU_H 1
+
+#include <setjmp.h>
+#ifdef BX_USE_VMX
+extern "C" {
+#include <io/ioreq.h>
+}
+#endif
+
+
+#if BX_SUPPORT_APIC
+#define BX_CPU_INTR (BX_CPU_THIS_PTR INTR || BX_CPU_THIS_PTR local_apic.INTR)
+#else
+#define BX_CPU_INTR BX_CPU_THIS_PTR INTR
+#endif
+
+class BX_CPU_C;
+class BX_MEM_C;
+
+#if BX_USE_CPU_SMF == 0
+// normal member functions. This can ONLY be used within BX_CPU_C classes.
+// Anyone on the outside should use the BX_CPU macro (defined in bochs.h)
+// instead.
+# define BX_CPU_THIS_PTR this->
+# define BX_CPU_THIS this
+# define BX_SMF
+# define BX_CPU_C_PREFIX BX_CPU_C::
+// with normal member functions, calling a member fn pointer looks like
+// object->*(fnptr)(arg, ...);
+// Since this is different from when SMF=1, encapsulate it in a macro.
+# define BX_CPU_CALL_METHOD(func, args) \
+ (this->*((BxExecutePtr_t) (func))) args
+# define BX_CPU_CALL_METHODR(func, args) \
+ (this->*((BxExecutePtr_tR) (func))) args
+#else
+// static member functions. With SMF, there is only one CPU by definition.
+# define BX_CPU_THIS_PTR BX_CPU(0)->
+# define BX_CPU_THIS BX_CPU(0)
+# define BX_SMF static
+# define BX_CPU_C_PREFIX
+# define BX_CPU_CALL_METHOD(func, args) \
+ ((BxExecutePtr_t) (func)) args
+# define BX_CPU_CALL_METHODR(func, args) \
+ ((BxExecutePtr_tR) (func)) args
+#endif
+
+#if BX_SMP_PROCESSORS==1
+// single processor simulation, so there's one of everything
+BOCHSAPI extern BX_CPU_C bx_cpu;
+#else
+// multiprocessor simulation, we need an array of cpus and memories
+BOCHSAPI extern BX_CPU_C *bx_cpu_array[BX_SMP_PROCESSORS];
+#endif
+
+class BOCHSAPI BX_CPU_C : public logfunctions {
+
+public: // for now...
+
+ volatile bx_bool async_event;
+ volatile bx_bool INTR;
+ volatile bx_bool kill_bochs_request;
+
+ // constructors & destructors...
+ BX_CPU_C();
+ ~BX_CPU_C(void);
+ void init (BX_MEM_C *addrspace);
+ void interrupt(Bit8u vector);
+
+ BX_SMF void pagingA20Changed(void);
+ BX_SMF void reset(unsigned source);
+ BX_SMF void set_INTR(bx_bool value);
+ BX_SMF void atexit(void);
+
+ // now for some ancillary functions...
+ void cpu_loop(Bit32s max_instr_count);
+
+#ifdef BX_USE_VMX
+ ioreq_t* __get_ioreq(void);
+ ioreq_t* get_ioreq(void);
+ void dispatch_ioreq(ioreq_t *req);
+ void handle_ioreq();
+ void timer_handler();
+
+ int send_event;
+#endif
+};
+
+#endif // #ifndef BX_CPU_H
diff --git a/tools/ioemu/include/extplugin.h b/tools/ioemu/include/extplugin.h
new file mode 100644
index 0000000000..f3e43f79d4
--- /dev/null
+++ b/tools/ioemu/include/extplugin.h
@@ -0,0 +1,51 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extplugin.h,v 1.4 2002/12/12 15:28:37 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// extplugin.h
+//
+// This header file defines the types necessary to make a Bochs plugin,
+// but without mentioning all the details of Bochs internals (bochs.h).
+// It is included by the configuration interfaces and possibly other
+// things which are intentionally isolated from other parts of the program.
+//
+// The plugin_t struct comes from the plugin.h file from plex86.
+// Plex86 is Copyright (C) 1999-2000 The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef __EXTPLUGIN_H
+#define __EXTPLUGIN_H
+
+#if BX_PLUGINS
+#include "ltdl.h"
+#endif
+
+enum plugintype_t {
+ PLUGTYPE_NULL=100,
+ PLUGTYPE_CORE,
+ PLUGTYPE_OPTIONAL,
+ PLUGTYPE_USER
+};
+
+#define MAX_ARGC 10
+
+typedef struct _plugin_t
+{
+ plugintype_t type;
+ int initialized;
+#if BX_PLUGINS
+ lt_dlhandle handle;
+#endif
+ int argc;
+ char *name, *args, *argv[MAX_ARGC];
+ int (*plugin_init)(struct _plugin_t *plugin, plugintype_t type, int argc, char *argv[]);
+ void (*plugin_fini)(void);
+
+ struct _plugin_t *next;
+} plugin_t;
+
+
+
+#endif /* __EXTPLUGIN_H */
+
diff --git a/tools/ioemu/include/instrument.h b/tools/ioemu/include/instrument.h
new file mode 100644
index 0000000000..8d753ff7d7
--- /dev/null
+++ b/tools/ioemu/include/instrument.h
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: instrument.h,v 1.14 2003/10/09 19:05:13 sshwarts Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// possible types passed to BX_INSTR_TLB_CNTRL()
+#define BX_INSTR_MOV_CR3 10
+#define BX_INSTR_INVLPG 11
+#define BX_INSTR_TASKSWITCH 12
+
+// possible types passed to BX_INSTR_CACHE_CNTRL()
+#define BX_INSTR_INVD 20
+#define BX_INSTR_WBINVD 21
+
+#define BX_INSTR_IS_CALL 10
+#define BX_INSTR_IS_RET 11
+#define BX_INSTR_IS_IRET 12
+#define BX_INSTR_IS_JMP 13
+#define BX_INSTR_IS_INT 14
+
+#define BX_INSTR_PREFETCH_NTA 00
+#define BX_INSTR_PREFETCH_T0 01
+#define BX_INSTR_PREFETCH_T1 02
+#define BX_INSTR_PREFETCH_T2 03
+
+
+
+
+
+#if BX_INSTRUMENTATION
+
+class bxInstruction_c;
+
+// called from the CPU core
+
+void bx_instr_init(unsigned cpu);
+void bx_instr_shutdown(unsigned cpu);
+void bx_instr_reset(unsigned cpu);
+void bx_instr_new_instruction(unsigned cpu);
+
+void bx_instr_debug_promt();
+void bx_instr_start();
+void bx_instr_stop();
+void bx_instr_print();
+
+void bx_instr_cnear_branch_taken(unsigned cpu, bx_address new_eip);
+void bx_instr_cnear_branch_not_taken(unsigned cpu);
+void bx_instr_ucnear_branch(unsigned cpu, unsigned what, bx_address new_eip);
+void bx_instr_far_branch(unsigned cpu, unsigned what, Bit16u new_cs, bx_address new_eip);
+
+void bx_instr_opcode(unsigned cpu, Bit8u *opcode, unsigned len, bx_bool is32);
+void bx_instr_fetch_decode_completed(unsigned cpu, const bxInstruction_c *i);
+
+void bx_instr_prefix_as(unsigned cpu);
+void bx_instr_prefix_os(unsigned cpu);
+void bx_instr_prefix_rep(unsigned cpu);
+void bx_instr_prefix_repne(unsigned cpu);
+void bx_instr_prefix_lock(unsigned cpu);
+void bx_instr_prefix_cs(unsigned cpu);
+void bx_instr_prefix_ss(unsigned cpu);
+void bx_instr_prefix_ds(unsigned cpu);
+void bx_instr_prefix_es(unsigned cpu);
+void bx_instr_prefix_fs(unsigned cpu);
+void bx_instr_prefix_gs(unsigned cpu);
+void bx_instr_prefix_extend8b(unsigned cpu);
+
+void bx_instr_interrupt(unsigned cpu, unsigned vector);
+void bx_instr_exception(unsigned cpu, unsigned vector);
+void bx_instr_hwinterrupt(unsigned cpu, unsigned vector, Bit16u cs, bx_address eip);
+
+void bx_instr_tlb_cntrl(unsigned cpu, unsigned what, Bit32u newval);
+void bx_instr_cache_cntrl(unsigned cpu, unsigned what);
+void bx_instr_prefetch_hint(unsigned cpu, unsigned what, unsigned seg, bx_address offset);
+
+void bx_instr_before_execution(unsigned cpu);
+void bx_instr_after_execution(unsigned cpu);
+void bx_instr_repeat_iteration(unsigned cpu);
+
+void bx_instr_inp(Bit16u addr, unsigned len);
+void bx_instr_outp(Bit16u addr, unsigned len);
+void bx_instr_inp2(Bit16u addr, unsigned len, unsigned val);
+void bx_instr_outp2(Bit16u addr, unsigned len, unsigned val);
+
+void bx_instr_mem_code(unsigned cpu, bx_address linear, unsigned size);
+void bx_instr_mem_data(unsigned cpu, bx_address linear, unsigned size, unsigned rw);
+
+void bx_instr_lin_read(unsigned cpu, bx_address lin, bx_address phy, unsigned len);
+void bx_instr_lin_write(unsigned cpu, bx_address lin, bx_address phy, unsigned len);
+
+void bx_instr_phy_write(unsigned cpu, bx_address addr, unsigned len);
+void bx_instr_phy_read(unsigned cpu, bx_address addr, unsigned len);
+
+/* simulation init, shutdown, reset */
+# define BX_INSTR_INIT(cpu_id) bx_instr_init(cpu_id)
+# define BX_INSTR_SHUTDOWN(cpu_id) bx_instr_shutdown(cpu_id)
+# define BX_INSTR_RESET(cpu_id) bx_instr_reset(cpu_id)
+# define BX_INSTR_NEW_INSTRUCTION(cpu_id) bx_instr_new_instruction(cpu_id)
+
+/* called from command line debugger */
+# define BX_INSTR_DEBUG_PROMPT() bx_instr_debug_promt()
+# define BX_INSTR_START() bx_instr_start()
+# define BX_INSTR_STOP() bx_instr_stop()
+# define BX_INSTR_PRINT() bx_instr_print()
+
+/* branch resoultion */
+# define BX_INSTR_CNEAR_BRANCH_TAKEN(cpu_id, new_eip) bx_instr_cnear_branch_taken(cpu_id, new_eip)
+# define BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(cpu_id) bx_instr_cnear_branch_not_taken(cpu_id)
+# define BX_INSTR_UCNEAR_BRANCH(cpu_id, what, new_eip) bx_instr_ucnear_branch(cpu_id, what, new_eip)
+# define BX_INSTR_FAR_BRANCH(cpu_id, what, new_cs, new_eip) bx_instr_far_branch(cpu_id, what, new_cs, new_eip)
+
+/* decoding completed */
+# define BX_INSTR_OPCODE(cpu_id, opcode, len, is32) \
+ bx_instr_opcode(cpu_id, opcode, len, is32)
+# define BX_INSTR_FETCH_DECODE_COMPLETED(cpu_id, i) \
+ bx_instr_fetch_decode_completed(cpu_id, i)
+
+/* prefix decoded */
+# define BX_INSTR_PREFIX_AS(cpu_id) bx_instr_prefix_as(cpu_id)
+# define BX_INSTR_PREFIX_OS(cpu_id) bx_instr_prefix_os(cpu_id)
+# define BX_INSTR_PREFIX_REP(cpu_id) bx_instr_prefix_rep(cpu_id)
+# define BX_INSTR_PREFIX_REPNE(cpu_id) bx_instr_prefix_repne(cpu_id)
+# define BX_INSTR_PREFIX_LOCK(cpu_id) bx_instr_prefix_lock(cpu_id)
+# define BX_INSTR_PREFIX_CS(cpu_id) bx_instr_prefix_cs(cpu_id)
+# define BX_INSTR_PREFIX_SS(cpu_id) bx_instr_prefix_ss(cpu_id)
+# define BX_INSTR_PREFIX_DS(cpu_id) bx_instr_prefix_ds(cpu_id)
+# define BX_INSTR_PREFIX_ES(cpu_id) bx_instr_prefix_es(cpu_id)
+# define BX_INSTR_PREFIX_FS(cpu_id) bx_instr_prefix_fs(cpu_id)
+# define BX_INSTR_PREFIX_GS(cpu_id) bx_instr_prefix_gs(cpu_id)
+# define BX_INSTR_PREFIX_EXTEND8B(cpu_id) bx_instr_prefix_extend8b(cpu_id)
+
+/* exceptional case and interrupt */
+# define BX_INSTR_EXCEPTION(cpu_id, vector) bx_instr_exception(cpu_id, vector)
+# define BX_INSTR_INTERRUPT(cpu_id, vector) bx_instr_interrupt(cpu_id, vector)
+# define BX_INSTR_HWINTERRUPT(cpu_id, vector, cs, eip) bx_instr_hwinterrupt(cpu_id, vector, cs, eip)
+
+/* TLB/CACHE control instruction executed */
+# define BX_INSTR_CACHE_CNTRL(cpu_id, what) bx_instr_cache_cntrl(cpu_id, what)
+# define BX_INSTR_TLB_CNTRL(cpu_id, what, newval) bx_instr_tlb_cntrl(cpu_id, what, newval)
+# define BX_INSTR_PREFETCH_HINT(cpu_id, what, seg, offset) \
+ bx_instr_prefetch_hint(cpu_id, what, seg, offset)
+
+/* execution */
+# define BX_INSTR_BEFORE_EXECUTION(cpu_id) bx_instr_before_execution(cpu_id)
+# define BX_INSTR_AFTER_EXECUTION(cpu_id) bx_instr_after_execution(cpu_id)
+# define BX_INSTR_REPEAT_ITERATION(cpu_id) bx_instr_repeat_iteration(cpu_id)
+
+/* memory access */
+# define BX_INSTR_LIN_READ(cpu_id, lin, phy, len) bx_instr_lin_read(cpu_id, lin, phy, len)
+# define BX_INSTR_LIN_WRITE(cpu_id, lin, phy, len) bx_instr_lin_write(cpu_id, lin, phy, len)
+
+# define BX_INSTR_MEM_CODE(cpu_id, linear, size) bx_instr_mem_code(cpu_id, linear, size)
+# define BX_INSTR_MEM_DATA(cpu_id, linear, size, rw) bx_instr_mem_data(cpu_id, linear, size, rw)
+
+/* called from memory object */
+# define BX_INSTR_PHY_WRITE(cpu_id, addr, len) bx_instr_phy_write(cpu_id, addr, len)
+# define BX_INSTR_PHY_READ(cpu_id, addr, len) bx_instr_phy_read(cpu_id, addr, len)
+
+/* feedback from device units */
+# define BX_INSTR_INP(addr, len) bx_instr_inp(addr, len)
+# define BX_INSTR_INP2(addr, len, val) bx_instr_inp2(addr, len, val)
+# define BX_INSTR_OUTP(addr, len) bx_instr_outp(addr, len)
+# define BX_INSTR_OUTP2(addr, len, val) bx_instr_outp2(addr, len, val)
+
+#else
+
+/* simulation init, shutdown, reset */
+# define BX_INSTR_INIT(cpu_id)
+# define BX_INSTR_SHUTDOWN(cpu_id)
+# define BX_INSTR_RESET(cpu_id)
+# define BX_INSTR_NEW_INSTRUCTION(cpu_id)
+
+/* called from command line debugger */
+# define BX_INSTR_DEBUG_PROMPT()
+# define BX_INSTR_START()
+# define BX_INSTR_STOP()
+# define BX_INSTR_PRINT()
+
+/* branch resoultion */
+# define BX_INSTR_CNEAR_BRANCH_TAKEN(cpu_id, new_eip)
+# define BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(cpu_id)
+# define BX_INSTR_UCNEAR_BRANCH(cpu_id, what, new_eip)
+# define BX_INSTR_FAR_BRANCH(cpu_id, what, new_cs, new_eip)
+
+/* decoding completed */
+# define BX_INSTR_OPCODE(cpu_id, opcode, len, is32)
+# define BX_INSTR_FETCH_DECODE_COMPLETED(cpu_id, i)
+
+/* prefix decoded */
+# define BX_INSTR_PREFIX_AS(cpu_id)
+# define BX_INSTR_PREFIX_OS(cpu_id)
+# define BX_INSTR_PREFIX_REP(cpu_id)
+# define BX_INSTR_PREFIX_REPNE(cpu_id)
+# define BX_INSTR_PREFIX_LOCK(cpu_id)
+# define BX_INSTR_PREFIX_CS(cpu_id)
+# define BX_INSTR_PREFIX_SS(cpu_id)
+# define BX_INSTR_PREFIX_DS(cpu_id)
+# define BX_INSTR_PREFIX_ES(cpu_id)
+# define BX_INSTR_PREFIX_FS(cpu_id)
+# define BX_INSTR_PREFIX_GS(cpu_id)
+# define BX_INSTR_PREFIX_EXTEND8B(cpu_id)
+
+/* exceptional case and interrupt */
+# define BX_INSTR_EXCEPTION(cpu_id, vector)
+# define BX_INSTR_INTERRUPT(cpu_id, vector)
+# define BX_INSTR_HWINTERRUPT(cpu_id, vector, cs, eip)
+
+/* TLB/CACHE control instruction executed */
+# define BX_INSTR_CACHE_CNTRL(cpu_id, what)
+# define BX_INSTR_TLB_CNTRL(cpu_id, what, newval)
+# define BX_INSTR_PREFETCH_HINT(cpu_id, what, seg, offset)
+
+/* execution */
+# define BX_INSTR_BEFORE_EXECUTION(cpu_id)
+# define BX_INSTR_AFTER_EXECUTION(cpu_id)
+# define BX_INSTR_REPEAT_ITERATION(cpu_id)
+
+/* memory access */
+# define BX_INSTR_LIN_READ(cpu_id, lin, phy, len)
+# define BX_INSTR_LIN_WRITE(cpu_id, lin, phy, len)
+
+# define BX_INSTR_MEM_CODE(cpu_id, linear, size)
+# define BX_INSTR_MEM_DATA(cpu_id, linear, size, rw)
+
+/* called from memory object */
+# define BX_INSTR_PHY_WRITE(cpu_id, addr, len)
+# define BX_INSTR_PHY_READ(cpu_id, addr, len)
+
+/* feedback from device units */
+# define BX_INSTR_INP(addr, len)
+# define BX_INSTR_INP2(addr, len, val)
+# define BX_INSTR_OUTP(addr, len)
+# define BX_INSTR_OUTP2(addr, len, val)
+
+#endif
diff --git a/tools/ioemu/include/ltdl.h b/tools/ioemu/include/ltdl.h
new file mode 100644
index 0000000000..3a02b311c2
--- /dev/null
+++ b/tools/ioemu/include/ltdl.h
@@ -0,0 +1,398 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ltdl.h,v 1.2 2002/10/24 21:04:37 bdenney Exp $
+//
+// NOTE: The ltdl library comes from the Libtool package. Bochs uses
+// ltdl and libtool to build and load plugins. The libtool
+// documentation describes how to copy ltdl.c and ltdl.h into your
+// distribution, so it is clearly legal to do so.
+/////////////////////////////////////////////////////////////////////////
+
+/* ltdl.h -- generic dlopen functions
+ Copyright (C) 1998-2000 Free Software Foundation, Inc.
+ Originally by Thomas Tanner <tanner@ffii.org>
+ This file is part of GNU Libtool.
+
+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.
+
+As a special exception to the GNU Lesser General Public License,
+if you distribute this file as part of a program or library that
+is built using GNU libtool, you may include it under the same
+distribution terms that you use for the rest of that program.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA
+*/
+
+/* Only include this header file once. */
+#ifndef LTDL_H
+#define LTDL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <sys/types.h> /* for size_t declaration */
+#ifdef __cplusplus
+};
+#endif
+
+
+/* --- MACROS FOR PORTABILITY --- */
+
+
+/* Saves on those hard to debug '\0' typos.... */
+#define LT_EOS_CHAR '\0'
+
+/* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations,
+ so that C++ compilers don't mangle their names. Use LTDL_END_C_DECLS at
+ the end of C declarations. */
+#ifdef __cplusplus
+# define LT_BEGIN_C_DECLS extern "C" {
+# define LT_END_C_DECLS }
+#else
+# define LT_BEGIN_C_DECLS /* empty */
+# define LT_END_C_DECLS /* empty */
+#endif
+
+LT_BEGIN_C_DECLS
+
+
+/* LT_PARAMS is a macro used to wrap function prototypes, so that compilers
+ that don't understand ANSI C prototypes still work, and ANSI C
+ compilers can issue warnings about type mismatches. */
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus)
+# define LT_PARAMS(protos) protos
+# define lt_ptr void*
+#else
+# define LT_PARAMS(protos) ()
+# define lt_ptr char*
+#endif
+
+/* LT_STMT_START/END are used to create macros which expand to a
+ a single compound statement in a portable way. */
+#if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
+# define LT_STMT_START (void)(
+# define LT_STMT_END )
+#else
+# if (defined (sun) || defined (__sun__))
+# define LT_STMT_START if (1)
+# define LT_STMT_END else (void)0
+# else
+# define LT_STMT_START do
+# define LT_STMT_END while (0)
+# endif
+#endif
+
+/* LT_CONC creates a new concatenated symbol for the compiler
+ in a portable way. */
+#if defined(__STDC__) || defined(__cplusplus)
+# define LT_CONC(s,t) s##t
+#else
+# define LT_CONC(s,t) s/**/t
+#endif
+
+/* LT_STRLEN can be used safely on NULL pointers. */
+#define LT_STRLEN(s) (((s) && (s)[0]) ? strlen (s) : 0)
+
+
+
+/* --- WINDOWS SUPPORT --- */
+
+
+/* Canonicalise Windows and Cygwin recognition macros. */
+#ifdef __CYGWIN32__
+# ifndef __CYGWIN__
+# define __CYGWIN__ __CYGWIN32__
+# endif
+#endif
+#if defined(_WIN32) || defined(WIN32)
+# ifndef __WINDOWS__
+# ifdef _WIN32
+# define __WINDOWS__ _WIN32
+# else
+# ifdef WIN32
+# define __WINDOWS__ WIN32
+# endif
+# endif
+# endif
+#endif
+
+#ifdef __WINDOWS__
+# ifndef __CYGWIN__
+/* LT_DIRSEP_CHAR is accepted *in addition* to '/' as a directory
+ separator when it is set. */
+# define LT_DIRSEP_CHAR '\\'
+# define LT_PATHSEP_CHAR ';'
+# endif
+#endif
+#ifndef LT_PATHSEP_CHAR
+# define LT_PATHSEP_CHAR ':'
+#endif
+
+/* DLL building support on win32 hosts; mostly to workaround their
+ ridiculous implementation of data symbol exporting. */
+#ifndef LT_SCOPE
+# ifdef __WINDOWS__
+# ifdef DLL_EXPORT /* defined by libtool (if required) */
+# define LT_SCOPE __declspec(dllexport)
+# endif
+# ifdef LIBLTDL_DLL_IMPORT /* define if linking with this dll */
+# define LT_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+# ifndef LT_SCOPE /* static linking or !__WINDOWS__ */
+# define LT_SCOPE extern
+# endif
+#endif
+
+
+
+
+/* --- DYNAMIC MODULE LOADING API --- */
+
+
+typedef struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module. */
+
+/* Initialisation and finalisation functions for libltdl. */
+extern int lt_dlinit LT_PARAMS((void));
+extern int lt_dlexit LT_PARAMS((void));
+
+/* Module search path manipulation. */
+extern int lt_dladdsearchdir LT_PARAMS((const char *search_dir));
+extern int lt_dlinsertsearchdir LT_PARAMS((const char *before,
+ const char *search_dir));
+extern int lt_dlsetsearchpath LT_PARAMS((const char *search_path));
+extern const char *lt_dlgetsearchpath LT_PARAMS((void));
+extern int lt_dlforeachfile LT_PARAMS((
+ const char *search_path,
+ int (*func) (const char *filename, lt_ptr data),
+ lt_ptr data));
+
+/* Portable libltdl versions of the system dlopen() API. */
+extern lt_dlhandle lt_dlopen LT_PARAMS((const char *filename));
+extern lt_dlhandle lt_dlopenext LT_PARAMS((const char *filename));
+extern lt_ptr lt_dlsym LT_PARAMS((lt_dlhandle handle,
+ const char *name));
+extern const char *lt_dlerror LT_PARAMS((void));
+extern int lt_dlclose LT_PARAMS((lt_dlhandle handle));
+
+/* Module residency management. */
+extern int lt_dlmakeresident LT_PARAMS((lt_dlhandle handle));
+extern int lt_dlisresident LT_PARAMS((lt_dlhandle handle));
+
+
+
+
+/* --- MUTEX LOCKING --- */
+
+
+typedef void lt_dlmutex_lock LT_PARAMS((void));
+typedef void lt_dlmutex_unlock LT_PARAMS((void));
+typedef void lt_dlmutex_seterror LT_PARAMS((const char *errmsg));
+typedef const char *lt_dlmutex_geterror LT_PARAMS((void));
+
+extern int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock,
+ lt_dlmutex_unlock *unlock,
+ lt_dlmutex_seterror *seterror,
+ lt_dlmutex_geterror *geterror));
+
+
+
+
+/* --- MEMORY HANDLING --- */
+
+
+/* By default, the realloc function pointer is set to our internal
+ realloc implementation which iself uses lt_dlmalloc and lt_dlfree.
+ libltdl relies on a featureful realloc, but if you are sure yours
+ has the right semantics then you can assign it directly. Generally,
+ it is safe to assign just a malloc() and a free() function. */
+LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size));
+LT_SCOPE lt_ptr (*lt_dlrealloc) LT_PARAMS((lt_ptr ptr, size_t size));
+LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr));
+
+
+
+
+/* --- PRELOADED MODULE SUPPORT --- */
+
+
+/* A preopened symbol. Arrays of this type comprise the exported
+ symbols for a dlpreopened module. */
+typedef struct {
+ const char *name;
+ lt_ptr address;
+} lt_dlsymlist;
+
+extern int lt_dlpreload LT_PARAMS((const lt_dlsymlist *preloaded));
+extern int lt_dlpreload_default
+ LT_PARAMS((const lt_dlsymlist *preloaded));
+
+#define LTDL_SET_PRELOADED_SYMBOLS() LT_STMT_START{ \
+ extern const lt_dlsymlist lt_preloaded_symbols[]; \
+ lt_dlpreload_default(lt_preloaded_symbols); \
+ }LT_STMT_END
+
+
+
+
+/* --- MODULE INFORMATION --- */
+
+
+/* Read only information pertaining to a loaded module. */
+typedef struct {
+ char *filename; /* file name */
+ char *name; /* module name */
+ int ref_count; /* number of times lt_dlopened minus
+ number of times lt_dlclosed. */
+} lt_dlinfo;
+
+extern const lt_dlinfo *lt_dlgetinfo LT_PARAMS((lt_dlhandle handle));
+extern lt_dlhandle lt_dlhandle_next LT_PARAMS((lt_dlhandle place));
+extern int lt_dlforeach LT_PARAMS((
+ int (*func) (lt_dlhandle handle, lt_ptr data),
+ lt_ptr data));
+
+/* Associating user data with loaded modules. */
+typedef unsigned lt_dlcaller_id;
+
+extern lt_dlcaller_id lt_dlcaller_register LT_PARAMS((void));
+extern lt_ptr lt_dlcaller_set_data LT_PARAMS((lt_dlcaller_id key,
+ lt_dlhandle handle,
+ lt_ptr data));
+extern lt_ptr lt_dlcaller_get_data LT_PARAMS((lt_dlcaller_id key,
+ lt_dlhandle handle));
+
+
+
+/* --- USER MODULE LOADER API --- */
+
+
+typedef struct lt_dlloader lt_dlloader;
+typedef lt_ptr lt_user_data;
+typedef lt_ptr lt_module;
+
+/* Function pointer types for creating user defined module loaders. */
+typedef lt_module lt_module_open LT_PARAMS((lt_user_data loader_data,
+ const char *filename));
+typedef int lt_module_close LT_PARAMS((lt_user_data loader_data,
+ lt_module handle));
+typedef lt_ptr lt_find_sym LT_PARAMS((lt_user_data loader_data,
+ lt_module handle,
+ const char *symbol));
+typedef int lt_dlloader_exit LT_PARAMS((lt_user_data loader_data));
+
+struct lt_user_dlloader {
+ const char *sym_prefix;
+ lt_module_open *module_open;
+ lt_module_close *module_close;
+ lt_find_sym *find_sym;
+ lt_dlloader_exit *dlloader_exit;
+ lt_user_data dlloader_data;
+};
+
+extern lt_dlloader *lt_dlloader_next LT_PARAMS((lt_dlloader *place));
+extern lt_dlloader *lt_dlloader_find LT_PARAMS((
+ const char *loader_name));
+extern const char *lt_dlloader_name LT_PARAMS((lt_dlloader *place));
+extern lt_user_data *lt_dlloader_data LT_PARAMS((lt_dlloader *place));
+extern int lt_dlloader_add LT_PARAMS((lt_dlloader *place,
+ const struct lt_user_dlloader *dlloader,
+ const char *loader_name));
+extern int lt_dlloader_remove LT_PARAMS((
+ const char *loader_name));
+
+
+
+/* --- ERROR MESSAGE HANDLING --- */
+
+/* Bryce rewrote the error table in a way that would be likely to work
+ on all compilers. VC++ was not able to handle it the way it was
+ done originally. */
+
+/* ORIG COMMENT: Defining error strings alongside their symbolic names in a
+ macro in this way allows us to expand the macro in different contexts with
+ confidence that the enumeration of symbolic names will map correctly
+ onto the table of error strings. */
+
+#define lt_dlerror_symbols_list \
+ LT_ERROR_UNKNOWN, \
+ LT_ERROR_DLOPEN_NOT_SUPPORTED, \
+ LT_ERROR_INVALID_LOADER, \
+ LT_ERROR_INIT_LOADER, \
+ LT_ERROR_REMOVE_LOADER, \
+ LT_ERROR_FILE_NOT_FOUND, \
+ LT_ERROR_DEPLIB_NOT_FOUND, \
+ LT_ERROR_NO_SYMBOLS, \
+ LT_ERROR_CANNOT_OPEN, \
+ LT_ERROR_CANNOT_CLOSE, \
+ LT_ERROR_SYMBOL_NOT_FOUND, \
+ LT_ERROR_NO_MEMORY, \
+ LT_ERROR_INVALID_HANDLE, \
+ LT_ERROR_BUFFER_OVERFLOW, \
+ LT_ERROR_INVALID_ERRORCODE, \
+ LT_ERROR_SHUTDOWN, \
+ LT_ERROR_CLOSE_RESIDENT_MODULE, \
+ LT_ERROR_INVALID_MUTEX_ARGS, \
+ LT_ERROR_INVALID_POSITION,
+
+#define lt_dlerror_names_list \
+ "unknown error", \
+ "dlopen support not available", \
+ "invalid loader", \
+ "loader initialization failed", \
+ "loader removal failed", \
+ "file not found", \
+ "dependency library not found", \
+ "no symbols defined", \
+ "can't open the module", \
+ "can't close the module", \
+ "symbol not found", \
+ "not enough memory", \
+ "invalid module handle", \
+ "internal buffer overflow", \
+ "invalid errorcode", \
+ "library already shutdown", \
+ "can't close resident module", \
+ "invalid mutex handler registration", \
+ "invalid search path insert position",
+
+/* Enumerate the symbolic error names. */
+enum {
+ lt_dlerror_symbols_list
+ LT_ERROR_MAX
+};
+
+/* These functions are only useful from inside custom module loaders. */
+extern int lt_dladderror LT_PARAMS((const char *diagnostic));
+extern int lt_dlseterror LT_PARAMS((int errorcode));
+
+
+
+
+/* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */
+
+
+#ifdef LT_NON_POSIX_NAMESPACE
+# define lt_ptr_t lt_ptr
+# define lt_module_t lt_module
+# define lt_module_open_t lt_module_open
+# define lt_module_close_t lt_module_close
+# define lt_find_sym_t lt_find_sym
+# define lt_dlloader_exit_t lt_dlloader_exit
+# define lt_dlloader_t lt_dlloader
+# define lt_dlloader_data_t lt_user_data
+#endif
+
+LT_END_C_DECLS
+
+#endif /* !LTDL_H */
diff --git a/tools/ioemu/include/ltdlconf.h b/tools/ioemu/include/ltdlconf.h
new file mode 100644
index 0000000000..5ffd0e7916
--- /dev/null
+++ b/tools/ioemu/include/ltdlconf.h
@@ -0,0 +1,161 @@
+/* ltdlconf.h. Generated by configure. */
+/////////////////////////////////////////////////////////////////////////
+// $Id: ltdlconf.h.in,v 1.2 2002/10/24 21:04:38 bdenney Exp $
+//
+// The configure script reads this file and produces ltdlconf.h, which
+// tells ltdl.c how to compile. It was copied out of the libtool package
+// but appears to have been generated by autoheader.
+/////////////////////////////////////////////////////////////////////////
+
+/* config-h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define as __inline if that's what the C compiler calls it. */
+/* #undef inline */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the argz_append function. */
+#define HAVE_ARGZ_APPEND 1
+
+/* Define if you have the argz_create_sep function. */
+#define HAVE_ARGZ_CREATE_SEP 1
+
+/* Define if you have the argz_insert function. */
+#define HAVE_ARGZ_INSERT 1
+
+/* Define if you have the argz_next function. */
+#define HAVE_ARGZ_NEXT 1
+
+/* Define if you have the argz_stringify function. */
+#define HAVE_ARGZ_STRINGIFY 1
+
+/* Define if you have the bcopy function. */
+/* #undef HAVE_BCOPY */
+
+/* Define if you have the dlerror function. */
+#define HAVE_DLERROR 1
+
+/* Define if you have the index function. */
+/* #undef HAVE_INDEX */
+
+/* Define if you have the memcpy function. */
+#define HAVE_MEMCPY 1
+
+/* Define if you have the memmove function. */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the rindex function. */
+/* #undef HAVE_RINDEX */
+
+/* Define if you have the strchr function. */
+#define HAVE_STRCHR 1
+
+/* Define if you have the strcmp function. */
+#define HAVE_STRCMP 1
+
+/* Define if you have the strrchr function. */
+#define HAVE_STRRCHR 1
+
+/* Define if you have the <argz.h> header file. */
+#define HAVE_ARGZ_H 1
+
+/* Define if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <ctype.h> header file. */
+#define HAVE_CTYPE_H 1
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <dl.h> header file. */
+/* #undef HAVE_DL_H */
+
+/* Define if you have the <dld.h> header file. */
+/* #undef HAVE_DLD_H */
+
+/* Define if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/dl.h> header file. */
+/* #undef HAVE_SYS_DL_H */
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the extension used for shared libraries, say, .so. */
+#define LTDL_SHLIB_EXT ".so"
+
+/* Define to the name of the environment variable that determines the dynamic library search path. */
+#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH"
+
+/* Define to the system default library search path. */
+#define LTDL_SYSSEARCHPATH "/lib:/usr/lib"
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries. */
+#define LTDL_OBJDIR ".libs/"
+
+/* Define if libtool can extract symbol lists from object files. */
+#define HAVE_PRELOADED_SYMBOLS 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define if you have the shl_load function. */
+/* #undef HAVE_SHL_LOAD */
+
+/* Define if you have the shl_load function. */
+/* #undef HAVE_SHL_LOAD */
+
+/* Define if you have the GNU dld library. */
+/* #undef HAVE_DLD */
+
+/* Define if dlsym() requires a leading underscode in symbol names. */
+/* #undef NEED_USCORE */
+
+/* Define if the OS needs help to load dependent libraries for dlopen(). */
+/* #undef LTDL_DLOPEN_DEPLIBS */
+
+/* Define to a type to use for `error_t' if it is not otherwise available. */
+/* #undef error_t */
+
diff --git a/tools/ioemu/include/osdep.h b/tools/ioemu/include/osdep.h
new file mode 100644
index 0000000000..a47b88d06e
--- /dev/null
+++ b/tools/ioemu/include/osdep.h
@@ -0,0 +1,176 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: osdep.h,v 1.19 2003/08/20 06:26:27 japj Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// osdep.h
+//
+// requires Bit32u/Bit64u from config.h, size_t from stdio.h
+//
+// Operating system dependent includes and defines for Bochs. These
+// declarations can be included by C or C++., but they require definition of
+// size_t beforehand. This makes it difficult to place them into either
+// config.h or bochs.h. If in config.h, size_t is not always available yet.
+// If in bochs.h, they can't be included by C programs so they lose.
+//
+
+#ifndef BX_OSDEP_H
+#define BX_OSDEP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+//////////////////////////////////////////////////////////////////////
+// Hacks for win32, but exclude MINGW32 because it doesn't need them.
+//////////////////////////////////////////////////////////////////////
+#ifdef WIN32
+
+// Definitions that are needed for all WIN32 compilers.
+# define ssize_t long
+
+#ifndef __MINGW32__
+#define FMT_LL "%I64"
+
+// Definitions that are needed for WIN32 compilers EXCEPT FOR
+// cygwin compiling with -mno-cygwin. e.g. VC++.
+
+// always return regular file.
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+
+// win32 has snprintf though with different name.
+#define snprintf _snprintf
+#else /* ifnndef __MINGW32__ */
+#define FMT_LL "%ll"
+#endif /* ifnndef __MINGW32__ */
+#else /* WIN32 */
+#define FMT_LL "%ll"
+#endif /* WIN32 */
+
+// Missing defines for open
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#define S_IWGRP 0020
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#define S_IWOTH 0002
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions.
+// These should work on any platform that needs them.
+//
+// A missing library function is renamed to a bx_* function, so that when
+// debugging and linking there's no confusion over which version is used.
+// Because of renaming, the bx_* replacement functions can be tested on
+// machines which have the real library function without duplicate symbols.
+//
+// If you're considering implementing a missing library function, note
+// that it might be cleaner to conditionally disable the function call!
+//////////////////////////////////////////////////////////////////////
+
+#if !BX_HAVE_SNPRINTF
+#define snprintf bx_snprintf
+ extern int bx_snprintf (char *s, size_t maxlen, const char *format, ...);
+#endif
+
+#if BX_HAVE_STRTOULL
+ // great, just use the usual function
+#elif BX_HAVE_STRTOUQ
+ // they have strtouq and not strtoull
+ #define strtoull strtouq
+#else
+ #define strtoull bx_strtoull
+ extern Bit64u bx_strtoull (const char *nptr, char **endptr, int baseignore);
+#endif
+
+#if !BX_HAVE_STRDUP
+#define strdup bx_strdup
+ extern char *bx_strdup(const char *str);
+#endif
+
+#if !BX_HAVE_STRREV
+#define strrev bx_strrev
+ extern char *bx_strrev(char *str);
+#endif
+
+#if !BX_HAVE_SOCKLEN_T
+// needed on MacOS X 10.1
+typedef int socklen_t;
+#endif
+
+#if !BX_HAVE_MKSTEMP
+#define mkstemp bx_mkstemp
+ extern int bx_mkstemp(char *tpl);
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions, implemented for MacOS only
+//////////////////////////////////////////////////////////////////////
+
+#if BX_WITH_MACOS
+// fd_read and fd_write are called by floppy.cc to access the Mac
+// floppy drive directly, since the MacOS doesn't have "special"
+// pathnames which map directly to IO devices
+
+int fd_read(char *buffer, Bit32u offset, Bit32u bytes);
+int fd_write(char *buffer, Bit32u offset, Bit32u bytes);
+int fd_stat(struct stat *buf);
+FILE * fdopen(int fd, const char *type);
+
+typedef long ssize_t ;
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// New functions to replace library functions
+// with OS-independent versions
+//////////////////////////////////////////////////////////////////////
+
+#if BX_HAVE_REALTIME_USEC
+// 64-bit time in useconds.
+extern Bit64u bx_get_realtime64_usec (void);
+#endif
+
+#ifdef WIN32
+#undef BX_HAVE_MSLEEP
+#define BX_HAVE_MSLEEP 1
+#ifndef __MINGW32__
+#define msleep(msec) _sleep(msec)
+#else
+#define msleep(msec) Sleep(msec)
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ifdef BX_OSDEP_H */
diff --git a/tools/ioemu/include/pc_system.h b/tools/ioemu/include/pc_system.h
new file mode 100644
index 0000000000..c8ea664577
--- /dev/null
+++ b/tools/ioemu/include/pc_system.h
@@ -0,0 +1,226 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pc_system.h,v 1.25 2003/03/02 23:59:08 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+#define BX_MAX_TIMERS 64
+#define BX_NULL_TIMER_HANDLE 10000
+
+
+#if BX_SHOW_IPS
+extern unsigned long ips_count;
+#endif
+
+
+typedef void (*bx_timer_handler_t)(void *);
+
+
+BOCHSAPI extern class bx_pc_system_c bx_pc_system;
+
+#ifdef PROVIDE_M_IPS
+extern double m_ips;
+#endif
+
+#ifdef BX_USE_VMX
+extern unsigned int tsc_per_bx_tick;
+
+#define rdtscll(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+#endif
+
+class BOCHSAPI bx_pc_system_c : private logfunctions {
+private:
+
+ // ===============================
+ // Timer oriented private features
+ // ===============================
+
+ struct {
+ bx_bool inUse; // Timer slot is in-use (currently registered).
+ Bit64u period; // Timer periodocity in cpu ticks.
+ Bit64u timeToFire; // Time to fire next (in absolute ticks).
+ bx_bool active; // 0=inactive, 1=active.
+ bx_bool continuous; // 0=one-shot timer, 1=continuous periodicity.
+ bx_timer_handler_t funct; // A callback function for when the
+ // timer fires.
+ void *this_ptr; // The this-> pointer for C++ callbacks
+ // has to be stored as well.
+#define BxMaxTimerIDLen 32
+ char id[BxMaxTimerIDLen]; // String ID of timer.
+ } timer[BX_MAX_TIMERS];
+
+ unsigned numTimers; // Number of currently allocated timers.
+ Bit32u currCountdown; // Current countdown ticks value (decrements to 0).
+ Bit32u currCountdownPeriod; // Length of current countdown period.
+ Bit64u ticksTotal; // Num ticks total since start of emulator execution.
+ Bit64u lastTimeUsec; // Last sequentially read time in usec.
+ Bit64u usecSinceLast; // Number of useconds claimed since then.
+
+ // A special null timer is always inserted in the timer[0] slot. This
+ // make sure that at least one timer is always active, and that the
+ // duration is always less than a maximum 32-bit integer, so a 32-bit
+ // counter can be used for the current countdown.
+ static const Bit64u NullTimerInterval;
+ static void nullTimer(void* this_ptr);
+
+#if !defined(PROVIDE_M_IPS)
+ // This is the emulator speed, as measured in millions of
+ // x86 instructions per second that it can emulate on some hypothetically
+ // nomimal workload.
+ double m_ips; // Millions of Instructions Per Second
+#endif
+
+#ifdef BX_USE_VMX
+ static Bit64s get_clock(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000LL + tv.tv_usec;
+ }
+
+ static Bit64u cpu_calibrate_ticks(void) {
+ Bit64s usec, t1, t2;
+
+ usec = get_clock();
+ rdtscll(t1);
+
+ usleep(50 * 1000);
+ usec = get_clock() - usec;
+ rdtscll(t2);
+
+ return (((t2 - t1) * 1000000LL + (usec >> 1)) / usec);
+ }
+#endif
+ // This handler is called when the function which decrements the clock
+ // ticks finds that an event has occurred.
+ void countdownEvent(void);
+
+public:
+
+ // ==============================
+ // Timer oriented public features
+ // ==============================
+
+ void init_ips(Bit32u ips);
+ int register_timer( void *this_ptr, bx_timer_handler_t, Bit32u useconds,
+ bx_bool continuous, bx_bool active, const char *id);
+ unsigned unregisterTimer(int timerID);
+ void start_timers(void);
+ void activate_timer( unsigned timer_index, Bit32u useconds,
+ bx_bool continuous );
+ void deactivate_timer( unsigned timer_index );
+ static BX_CPP_INLINE void tick1(void) {
+#if BX_SHOW_IPS
+ {
+ extern unsigned long ips_count;
+ ips_count++;
+ }
+#endif
+ if (--bx_pc_system.currCountdown == 0) {
+ bx_pc_system.countdownEvent();
+ }
+ }
+ static BX_CPP_INLINE void tickn(Bit64u n) {
+#if BX_SHOW_IPS
+ {
+ extern unsigned long ips_count;
+ ips_count += n;
+ }
+#endif
+ while (n >= Bit64u(bx_pc_system.currCountdown)) {
+ n -= Bit64u(bx_pc_system.currCountdown);
+ bx_pc_system.currCountdown = 0;
+ bx_pc_system.countdownEvent();
+ // bx_pc_system.currCountdown is adjusted to new value by countdownevent().
+ };
+ // 'n' is not (or no longer) >= the countdown size. We can just decrement
+ // the remaining requested ticks and continue.
+ bx_pc_system.currCountdown -= Bit32u(n);
+ }
+
+ int register_timer_ticks(void* this_ptr, bx_timer_handler_t, Bit64u ticks,
+ bx_bool continuous, bx_bool active, const char *id);
+ void activate_timer_ticks(unsigned index, Bit64u instructions,
+ bx_bool continuous);
+ Bit64u time_usec();
+ Bit64u time_usec_sequential();
+ static BX_CPP_INLINE Bit64u time_ticks() {
+ return bx_pc_system.ticksTotal +
+ Bit64u(bx_pc_system.currCountdownPeriod - bx_pc_system.currCountdown);
+ }
+ static BX_CPP_INLINE Bit64u getTicksTotal(void) {
+ return bx_pc_system.ticksTotal;
+ }
+
+ static BX_CPP_INLINE Bit32u getNumCpuTicksLeftNextEvent(void) {
+ return bx_pc_system.currCountdown;
+ }
+#if BX_DEBUGGER
+ static void timebp_handler(void* this_ptr);
+#endif
+
+
+ // ===========================
+ // Non-timer oriented features
+ // ===========================
+
+ bx_bool HRQ; // Hold Request
+ //bx_bool INTR; // Interrupt
+
+
+ // Address line 20 control:
+ // 1 = enabled: extended memory is accessible
+ // 0 = disabled: A20 address line is forced low to simulate
+ // an 8088 address map
+ bx_bool enable_a20;
+
+ // start out masking physical memory addresses to:
+ // 8086: 20 bits
+ // 286: 24 bits
+ // 386: 32 bits
+ // when A20 line is disabled, mask physical memory addresses to:
+ // 286: 20 bits
+ // 386: 20 bits
+ //
+ Bit32u a20_mask;
+
+ void set_HRQ(bx_bool val); // set the Hold ReQuest line
+ void set_INTR(bx_bool value); // set the INTR line to value
+
+ int IntEnabled( void );
+ int InterruptSignal( PCS_OP operation );
+ int ResetSignal( PCS_OP operation );
+ Bit8u IAC(void);
+
+ bx_pc_system_c(void);
+
+ 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 set_enable_a20(Bit8u value) BX_CPP_AttrRegparmN(1);
+ bx_bool get_enable_a20(void);
+ void exit(void);
+
+ };
diff --git a/tools/ioemu/include/plugin.h b/tools/ioemu/include/plugin.h
new file mode 100644
index 0000000000..dabd13fdcc
--- /dev/null
+++ b/tools/ioemu/include/plugin.h
@@ -0,0 +1,323 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: plugin.h,v 1.20 2003/08/04 16:03:08 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file provides macros and types needed for plugins. It is based on
+// the plugin.h file from plex86, but with significant changes to make
+// it work in Bochs.
+// Plex86 is Copyright (C) 1999-2000 The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef __PLUGIN_H
+#define __PLUGIN_H
+
+#include "extplugin.h"
+
+class bx_devices_c;
+BOCHSAPI extern logfunctions *pluginlog;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BX_PLUGIN_UNMAPPED "unmapped"
+#define BX_PLUGIN_BIOSDEV " biosdev"
+#define BX_PLUGIN_CMOS "cmos"
+#define BX_PLUGIN_VGA "vga"
+#define BX_PLUGIN_FLOPPY "floppy"
+#define BX_PLUGIN_PARALLEL "parallel"
+#define BX_PLUGIN_SERIAL "serial"
+#define BX_PLUGIN_KEYBOARD "keyboard"
+#define BX_PLUGIN_HARDDRV "harddrv"
+#define BX_PLUGIN_DMA "dma"
+#define BX_PLUGIN_PIC "pic"
+#define BX_PLUGIN_PCI "pci"
+#define BX_PLUGIN_PCI2ISA "pci2isa"
+#define BX_PLUGIN_SB16 "sb16"
+#define BX_PLUGIN_NE2K "ne2k"
+#define BX_PLUGIN_EXTFPUIRQ "extfpuirq"
+#define BX_PLUGIN_PCIVGA "pcivga"
+#define BX_PLUGIN_PCIUSB "pciusb"
+#define BX_PLUGIN_GAMEPORT "gameport"
+
+
+#define BX_REGISTER_DEVICE_DEVMODEL(a,b,c,d) pluginRegisterDeviceDevmodel(a,b,c,d)
+
+#if BX_PLUGINS
+
+#define DEV_init_devices() {bx_devices.init(BX_MEM(0)); }
+#define DEV_reset_devices(type) {bx_devices.reset(type); }
+#define PLUG_load_plugin(name,type) {bx_load_plugin(#name,type);}
+
+#define DEV_register_ioread_handler(b,c,d,e,f) pluginRegisterIOReadHandler(b,c,d,e,f)
+#define DEV_register_iowrite_handler(b,c,d,e,f) pluginRegisterIOWriteHandler(b,c,d,e,f)
+#define DEV_register_default_ioread_handler(b,c,d,e) pluginRegisterDefaultIOReadHandler(b,c,d,e)
+#define DEV_register_default_iowrite_handler(b,c,d,e) pluginRegisterDefaultIOWriteHandler(b,c,d,e)
+
+#define DEV_register_irq(b,c) pluginRegisterIRQ(b,c)
+#define DEV_unregister_irq(b,c) pluginUnregisterIRQ(b,c)
+
+#else
+
+#define DEV_init_devices() {bx_devices.init(BX_MEM(0)); }
+#define DEV_reset_devices(type) {bx_devices.reset(type); }
+// When plugins are off, PLUG_load_plugin will call the plugin_init function
+// directly.
+#define PLUG_load_plugin(name,type) {lib##name##_LTX_plugin_init(NULL,type,0,NULL);}
+#define DEV_register_ioread_handler(b,c,d,e,f) bx_devices.register_io_read_handler(b,c,d,e,f)
+#define DEV_register_iowrite_handler(b,c,d,e,f) bx_devices.register_io_write_handler(b,c,d,e,f)
+#define DEV_register_default_ioread_handler(b,c,d,e) bx_devices.register_default_io_read_handler(b,c,d,e)
+#define DEV_register_default_iowrite_handler(b,c,d,e) bx_devices.register_default_io_write_handler(b,c,d,e)
+#define DEV_register_irq(b,c) bx_devices.register_irq(b,c)
+#define DEV_unregister_irq(b,c) bx_devices.unregister_irq(b,c)
+
+#endif // #if BX_PLUGINS
+
+#define DEV_ioapic_present() (bx_devices.ioapic != NULL)
+
+// FIXME Do we really need pluginRegisterTimer ?
+#define DEV_register_timer(a,b,c,d,e,f) bx_pc_system.register_timer(a,b,c,d,e,f)
+
+///////// CMOS macros
+#define DEV_cmos_get_reg(a) (bx_devices.pluginCmosDevice->get_reg(a))
+#define DEV_cmos_set_reg(a,b) (bx_devices.pluginCmosDevice->set_reg(a,b))
+#define DEV_cmos_checksum() (bx_devices.pluginCmosDevice->checksum_cmos())
+#define DEV_cmos_get_timeval() (bx_devices.pluginCmosDevice->get_timeval())
+
+///////// keyboard macros
+#define DEV_mouse_motion(dx, dy, state) \
+ (bx_devices.pluginKeyboard->mouse_motion(dx, dy, state))
+#define DEV_kbd_gen_scancode(key) \
+ (bx_devices.pluginKeyboard->gen_scancode(key))
+#define DEV_kbd_paste_bytes(bytes, count) \
+ (bx_devices.pluginKeyboard->paste_bytes(bytes,count))
+#define DEV_kbd_paste_delay_changed() \
+ (bx_devices.pluginKeyboard->paste_delay_changed())
+#define DEV_mouse_enabled_changed(val) \
+ (bx_devices.pluginKeyboard->mouse_enabled_changed(val))
+
+///////// hard drive macros
+#define DEV_hd_read_handler(a, b, c) \
+ (bx_devices.pluginHardDrive->virt_read_handler(b, c))
+#define DEV_hd_write_handler(a, b, c, d) \
+ (bx_devices.pluginHardDrive->virt_write_handler(b, c, d))
+#define DEV_hd_get_first_cd_handle() \
+ (bx_devices.pluginHardDrive->get_first_cd_handle())
+#define DEV_hd_get_device_handle(a,b) \
+ (bx_devices.pluginHardDrive->get_device_handle(a,b))
+#define DEV_hd_get_cd_media_status(handle) \
+ (bx_devices.pluginHardDrive->get_cd_media_status(handle))
+#define DEV_hd_set_cd_media_status(handle, status) \
+ (bx_devices.pluginHardDrive->set_cd_media_status(handle, status))
+#define DEV_hd_close_harddrive() bx_devices.pluginHardDrive->close_harddrive()
+#define DEV_hd_present() (bx_devices.pluginHardDrive != &bx_devices.stubHardDrive)
+
+#define DEV_bulk_io_quantum_requested() (bx_devices.bulkIOQuantumsRequested)
+#define DEV_bulk_io_quantum_transferred() (bx_devices.bulkIOQuantumsTransferred)
+#define DEV_bulk_io_host_addr() (bx_devices.bulkIOHostAddr)
+
+///////// FLOPPY macros
+#define DEV_floppy_get_media_status(drive) bx_devices.pluginFloppyDevice->get_media_status(drive)
+#define DEV_floppy_set_media_status(drive, status) bx_devices.pluginFloppyDevice->set_media_status(drive, status)
+#define DEV_floppy_present() (bx_devices.pluginFloppyDevice != &bx_devices.stubFloppy)
+
+///////// DMA macros
+#define DEV_dma_register_8bit_channel(channel, dmaRead, dmaWrite, name) \
+ (bx_devices.pluginDmaDevice->registerDMA8Channel(channel, dmaRead, dmaWrite, name))
+#define DEV_dma_register_16bit_channel(channel, dmaRead, dmaWrite, name) \
+ (bx_devices.pluginDmaDevice->registerDMA16Channel(channel, dmaRead, dmaWrite, name))
+#define DEV_dma_unregister_channel(channel) \
+ (bx_devices.pluginDmaDevice->unregisterDMAChannel(channel))
+#define DEV_dma_set_drq(channel, val) \
+ (bx_devices.pluginDmaDevice->set_DRQ(channel, val))
+#define DEV_dma_get_tc() \
+ (bx_devices.pluginDmaDevice->get_TC())
+#define DEV_dma_raise_hlda() \
+ (bx_devices.pluginDmaDevice->raise_HLDA())
+
+///////// PIC macros
+#define DEV_pic_lower_irq(b) (bx_devices.pluginPicDevice->lower_irq(b))
+#define DEV_pic_raise_irq(b) (bx_devices.pluginPicDevice->raise_irq(b))
+#define DEV_pic_iac() (bx_devices.pluginPicDevice->IAC())
+#define DEV_pic_show_pic_state() (bx_devices.pluginPicDevice->show_pic_state())
+
+///////// VGA macros
+#define DEV_vga_mem_read(addr) (bx_devices.pluginVgaDevice->mem_read(addr))
+#define DEV_vga_mem_write(addr, val) (bx_devices.pluginVgaDevice->mem_write(addr, val))
+#define DEV_vga_redraw_area(left, top, right, bottom) \
+ (bx_devices.pluginVgaDevice->redraw_area(left, top, right, bottom))
+#define DEV_vga_get_text_snapshot(rawsnap, height, width) \
+ (bx_devices.pluginVgaDevice->get_text_snapshot(rawsnap, height, width))
+#define DEV_vga_refresh() \
+ (bx_devices.pluginVgaDevice->trigger_timer(bx_devices.pluginVgaDevice))
+#define DEV_vga_set_update_interval(val) \
+ (bx_devices.pluginVgaDevice->set_update_interval(val))
+#define DEV_vga_get_actl_pal_idx(index) (bx_devices.pluginVgaDevice->get_actl_palette_idx(index))
+
+///////// PCI macros
+#define DEV_register_pci_handlers(b,c,d,e,f) \
+ (bx_devices.pluginPciBridge->register_pci_handlers(b,c,d,e,f))
+#define DEV_pci_rd_memtype(addr) bx_devices.pluginPciBridge->rd_memType(addr)
+#define DEV_pci_wr_memtype(addr) bx_devices.pluginPciBridge->wr_memType(addr)
+#define DEV_pci_print_i440fx_state() bx_devices.pluginPciBridge->print_i440fx_state()
+
+///////// NE2000 macro
+#define DEV_ne2k_print_info(file,page,reg,brief) \
+ bx_devices.pluginNE2kDevice->print_info(file,page,reg,brief)
+
+
+#if BX_HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+typedef Bit32u (*ioReadHandler_t)(void *, Bit32u, unsigned);
+typedef void (*ioWriteHandler_t)(void *, Bit32u, Bit32u, unsigned);
+
+extern plugin_t *plugins;
+
+typedef struct _device_t
+{
+ const char *name;
+ plugin_t *plugin;
+ void (*device_init_mem)(BX_MEM_C *);
+ void (*device_init_dev)();
+ void (*device_reset)(unsigned);
+ void (*device_load_state)();
+ void (*device_save_state)();
+
+ int use_devmodel_interface; // BBD hack
+ class bx_devmodel_c *devmodel; // BBD hack
+
+ struct _device_t *next;
+} device_t;
+
+
+extern device_t *devices;
+
+void plugin_startup (void);
+void plugin_load (char *name, char *args, plugintype_t);
+plugin_t *plugin_unload (plugin_t *plugin);
+void plugin_init_all (void);
+void plugin_fini_all (void);
+
+/* === Device Stuff === */
+typedef void (*deviceInitMem_t)(BX_MEM_C *);
+typedef void (*deviceInitDev_t)(void);
+typedef void (*deviceReset_t)(unsigned);
+typedef void (*deviceLoad_t)(void);
+typedef void (*deviceSave_t)(void);
+
+BOCHSAPI void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *dev, char *name);
+BOCHSAPI bx_bool pluginDevicePresent(char *name);
+
+/* === IO port stuff === */
+BOCHSAPI extern int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+ unsigned base, const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ unsigned base, const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+ const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ const char *name, Bit8u mask);
+
+/* === A20 enable line stuff === */
+BOCHSAPI extern unsigned (*pluginGetA20E)(void);
+BOCHSAPI extern void (*pluginSetA20E)(unsigned val);
+
+/* === IRQ stuff === */
+BOCHSAPI extern void (*pluginRegisterIRQ)(unsigned irq, const char *name);
+BOCHSAPI extern void (*pluginUnregisterIRQ)(unsigned irq, const char *name);
+
+/* === Floppy stuff ===*/
+BOCHSAPI extern unsigned (* pluginFloppyGetMediaStatus)(unsigned drive);
+BOCHSAPI extern unsigned (* pluginFloppySetMediaStatus)(unsigned drive, unsigned status);
+
+/* === VGA stuff === */
+BOCHSAPI extern void (* pluginVGARedrawArea)(unsigned x0, unsigned y0,
+ unsigned width, unsigned height);
+BOCHSAPI extern Bit8u (* pluginVGAMemRead)(Bit32u addr);
+BOCHSAPI extern void (* pluginVGAMemWrite)(Bit32u addr, Bit8u value);
+BOCHSAPI extern void (* pluginVGAGetTextSnapshot)(Bit8u **text_snapshot,
+ unsigned *txHeight, unsigned *txWidth);
+BOCHSAPI extern void (* pluginVGARefresh)(void *);
+BOCHSAPI extern void (* pluginVGASetUpdateInterval)(unsigned);
+BOCHSAPI extern Bit8u (* pluginVGAGetActlPaletteIdx)(Bit8u index);
+
+/* === Timer stuff === */
+BOCHSAPI extern int (*pluginRegisterTimer)(void *this_ptr, void (*funct)(void *),
+ Bit32u useconds, bx_bool continuous,
+ bx_bool active, const char *name);
+
+BOCHSAPI extern void (*pluginActivateTimer)(unsigned id, Bit32u usec, bx_bool continuous);
+BOCHSAPI extern void (*pluginDeactivateTimer)(unsigned id);
+
+/* === HRQ stuff === */
+BOCHSAPI extern void (*pluginSetHRQ)(unsigned val);
+BOCHSAPI extern void (*pluginSetHRQHackCallback)( void (*callback)(void) );
+
+/* === Reset stuff === */
+BOCHSAPI extern void (*pluginResetSignal)(unsigned sig);
+
+/* === PCI stuff === */
+BOCHSAPI extern bx_bool (*pluginRegisterPCIDevice)(void *this_ptr,
+ Bit32u (*bx_pci_read_handler)(void *, Bit8u, unsigned),
+ void(*bx_pci_write_handler)(void *, Bit8u, Bit32u, unsigned),
+ Bit8u devfunc, const char *name);
+BOCHSAPI extern Bit8u (*pluginRd_memType)(Bit32u addr);
+BOCHSAPI extern Bit8u (*pluginWr_memType)(Bit32u addr);
+
+void plugin_abort (void);
+
+int bx_load_plugin (const char *name, plugintype_t type);
+extern void bx_init_plugins (void);
+extern void bx_reset_plugins (unsigned);
+
+// every plugin must define these, within the extern"C" block, so that
+// a non-mangled function symbol is available in the shared library.
+void plugin_fini(void);
+int plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[]);
+
+// still in extern "C"
+#define DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(mod) \
+ int lib##mod##_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[]); \
+ void lib##mod##_LTX_plugin_fini(void);
+
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(harddrv)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(keyboard)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(serial)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(unmapped)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(biosdev)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(cmos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(dma)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pic)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(vga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(floppy)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(parallel)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci2isa)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pcivga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pciusb)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sb16)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(ne2k)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(extfpuirq)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(gameport)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(amigaos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(beos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(carbon)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(macintosh)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(nogui)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(rfb)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sdl)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(svga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(term)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(win32)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(wx)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(x)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PLUGIN_H */
diff --git a/tools/ioemu/include/state_file.h b/tools/ioemu/include/state_file.h
new file mode 100644
index 0000000000..7cef477043
--- /dev/null
+++ b/tools/ioemu/include/state_file.h
@@ -0,0 +1,61 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: state_file.h,v 1.5 2002/10/24 21:05:00 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Classes for helping to make checkpoints of the emulator state.
+
+#ifndef _STATE_FILE_H
+#define _STATE_FILE_H
+#include <stdio.h>
+#include <stddef.h>
+
+
+class BOCHSAPI state_file {
+ void init(void);
+public:
+ FILE *file;
+ class logfunctions *log;
+
+ FILE *get_handle();
+ void write(Bit8u);
+ void write(Bit16u);
+ void write(Bit32u);
+ void write(Bit64u);
+ void write(const void*, size_t);
+ void read(Bit8u &);
+ void read(Bit16u &);
+ void read(Bit32u &);
+ void read(Bit64u &);
+ void read(void *, size_t);
+ void write_check(const char *);
+ void read_check (const char *);
+
+ state_file (const char *name, const char *options);
+ state_file (FILE *f);
+ ~state_file();
+};
+
+#endif // #ifndef _STATE_FILE_H
diff --git a/tools/ioemu/iodev/Makefile b/tools/ioemu/iodev/Makefile
new file mode 100644
index 0000000000..3a43661918
--- /dev/null
+++ b/tools/ioemu/iodev/Makefile
@@ -0,0 +1,15 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS=$(patsubst %.cc,%.o,$(wildcard *.cc))
+BXLIBS = ../gui/libgui.a ../memory/libmemory.a
+LDLIBS= $(BXLIBS) -L/usr/X11R6/lib -lX11 -lXpm -lstdc++ -L ../../../tools/libxc -L ../../../tools/libxutil -lxc -lxutil
+
+all: device-model
+
+device-model: $(OBJS) $(BXLIBS)
+ $(LINK.o) $(OBJS) $(LOADLIBES) $(LDLIBS) -o $@
+
+include $(TOPDIR)/mk/helix.mk
+
+install:: all
+ install device-model $(DESTDIR)/usr/sbin
diff --git a/tools/ioemu/iodev/aspi-win32.h b/tools/ioemu/iodev/aspi-win32.h
new file mode 100644
index 0000000000..afa62d1e19
--- /dev/null
+++ b/tools/ioemu/iodev/aspi-win32.h
@@ -0,0 +1,210 @@
+//
+// iodev/aspi-win32.h
+// $Id: aspi-win32.h,v 1.2 2001/06/25 12:52:37 bdenney Exp $
+//
+// 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
diff --git a/tools/ioemu/iodev/biosdev.cc b/tools/ioemu/iodev/biosdev.cc
new file mode 100644
index 0000000000..d4a6ef2b8c
--- /dev/null
+++ b/tools/ioemu/iodev/biosdev.cc
@@ -0,0 +1,212 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: biosdev.cc,v 1.7 2003/12/08 19:36:23 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Here are the virtual ports use to display messages from the bioses :
+//
+// 0x0400 : rombios Panic port with message
+// 0x0401 : rombios Panic port with 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 message
+// 0x0502 : vgabios Panic port with 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 "bochs.h"
+
+bx_biosdev_c *theBiosDevice;
+
+ int
+libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theBiosDevice = new bx_biosdev_c ();
+ bx_devices.pluginBiosDevice = theBiosDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
+ return(0); // Success
+}
+
+ void
+libbiosdev_LTX_plugin_fini(void)
+{
+}
+
+logfunctions *bioslog;
+logfunctions *vgabioslog;
+
+bx_biosdev_c::bx_biosdev_c(void)
+{
+ bioslog = new logfunctions();
+ bioslog->put("BIOS");
+ bioslog->settype(BIOSLOG);
+ s.bios_message_i = 0;
+
+ vgabioslog = new logfunctions();
+ vgabioslog->put("VBIOS");
+ vgabioslog->settype(BIOSLOG);
+ s.vgabios_message_i = 0;
+}
+
+bx_biosdev_c::~bx_biosdev_c(void)
+{
+ 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, 0x0403, "Bios Debug Port", 1);
+ DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios 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);
+ DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
+}
+
+ void
+bx_biosdev_c::reset(unsigned type)
+{
+}
+
+ // 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 (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:
+ 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 (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
+ else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
+ }
+ break;
+
+ // 0x501-0x502 are used as panic ports for the vgabios
+ case 0x0502:
+ 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:
+ vgabioslog->panic("BIOS panic at rombios.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 (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
+ else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/tools/ioemu/iodev/biosdev.h b/tools/ioemu/iodev/biosdev.h
new file mode 100644
index 0000000000..7cd98736f4
--- /dev/null
+++ b/tools/ioemu/iodev/biosdev.h
@@ -0,0 +1,63 @@
+
+// $Id: biosdev.h,v 1.3 2002/10/24 21:07:09 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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(void);
+ ~bx_biosdev_c(void);
+
+ 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;
+
+ Bit8u vgabios_message[BX_BIOS_MESSAGE_SIZE];
+ unsigned int vgabios_message_i;
+ } s; // state information
+
+ };
diff --git a/tools/ioemu/iodev/cdrom.cc b/tools/ioemu/iodev/cdrom.cc
new file mode 100644
index 0000000000..2b78e8d15a
--- /dev/null
+++ b/tools/ioemu/iodev/cdrom.cc
@@ -0,0 +1,1338 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdrom.cc,v 1.66 2003/12/08 23:49:48 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// 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.
+
+
+// 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"
+#if BX_SUPPORT_CDROM
+
+#define LOG_THIS /* no SMF tricks here, not needed */
+
+extern "C" {
+#include <errno.h>
+}
+
+#ifdef __linux__
+extern "C" {
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+// I use the framesize in non OS specific code too
+#define BX_CD_FRAMESIZE CD_FRAMESIZE
+}
+
+#elif defined(__GNU__) || (defined(__CYGWIN32__) && !defined(WIN32))
+extern "C" {
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+}
+
+#elif BX_WITH_MACOS
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+
+#elif defined(__sun)
+extern "C" {
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/cdio.h>
+#define BX_CD_FRAMESIZE CDROM_BLK_2048
+}
+
+#elif defined(__DJGPP__)
+extern "C" {
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+}
+
+#elif defined(__BEOS__)
+#include "cdrom_beos.h"
+#define BX_CD_FRAMESIZE 2048
+
+#elif (defined (__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__))
+// OpenBSD pre version 2.7 may require extern "C" { } structure around
+// all the includes, because the i386 sys/disklabel.h contains code which
+// c++ considers invalid.
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/cdio.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+// ntohl(x) et al have been moved out of sys/param.h in FreeBSD 5
+#include <netinet/in.h>
+
+// XXX
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+
+#elif defined(__APPLE__)
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <dev/disk.h>
+#include <errno.h>
+#include <paths.h>
+#include <sys/param.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+// These definitions were taken from mount_cd9660.c
+// There are some similar definitions in IOCDTypes.h
+// however there seems to be some dissagreement in
+// the definition of CDTOC.length
+struct _CDMSF {
+ u_char minute;
+ u_char second;
+ u_char frame;
+};
+
+#define MSF_TO_LBA(msf) \
+ (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
+
+struct _CDTOC_Desc {
+ u_char session;
+ u_char ctrl_adr; /* typed to be machine and compiler independent */
+ u_char tno;
+ u_char point;
+ struct _CDMSF address;
+ u_char zero;
+ struct _CDMSF p;
+};
+
+struct _CDTOC {
+ u_short length; /* in native cpu endian */
+ u_char first_session;
+ u_char last_session;
+ struct _CDTOC_Desc trackdesc[1];
+};
+
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator, mach_port_t *masterPort );
+static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator, char *deviceFilePath, CFIndex maxPathSize );
+//int OpenDrive( const char *deviceFilePath );
+static struct _CDTOC * ReadTOC( const char * devpath );
+
+static char CDDevicePath[ MAXPATHLEN ];
+
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+
+#elif defined(WIN32)
+// windows.h included by bochs.h
+#include <winioctl.h>
+#include "aspi-win32.h"
+#include "scsidefs.h"
+
+DWORD (*GetASPI32SupportInfo)(void);
+DWORD (*SendASPI32Command)(LPSRB);
+BOOL (*GetASPI32Buffer)(PASPI32BUFF);
+BOOL (*FreeASPI32Buffer)(PASPI32BUFF);
+BOOL (*TranslateASPI32Address)(PDWORD,PDWORD);
+DWORD (*GetASPI32DLLVersion)(void);
+
+
+static BOOL bUseASPI = FALSE;
+static BOOL bHaveDev;
+static UINT cdromCount = 0;
+static HINSTANCE hASPI = NULL;
+
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+
+#else // all others (Irix, Tru64)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+#endif
+
+#include <stdio.h>
+
+#ifdef __APPLE__
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator,
+ mach_port_t *masterPort )
+{
+ kern_return_t kernResult;
+ CFMutableDictionaryRef classesToMatch;
+ kernResult = IOMasterPort( bootstrap_port, masterPort );
+ if ( kernResult != KERN_SUCCESS )
+ {
+ fprintf ( stderr, "IOMasterPort returned %d\n", kernResult );
+ return kernResult;
+ }
+ // CD media are instances of class kIOCDMediaClass.
+ classesToMatch = IOServiceMatching( kIOCDMediaClass );
+ if ( classesToMatch == NULL )
+ fprintf ( stderr, "IOServiceMatching returned a NULL dictionary.\n" );
+ else
+ {
+ // Each IOMedia object has a property with key kIOMediaEjectableKey
+ // which is true if the media is indeed ejectable. So add property
+ // to CFDictionary for matching.
+ CFDictionarySetValue( classesToMatch,
+ CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+ }
+ kernResult = IOServiceGetMatchingServices( *masterPort,
+ classesToMatch, mediaIterator );
+ if ( (kernResult != KERN_SUCCESS) || (*mediaIterator == NULL) )
+ fprintf( stderr, "No ejectable CD media found.\n kernResult = %d\n", kernResult );
+
+ return kernResult;
+}
+
+
+static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator,
+ char *deviceFilePath, CFIndex maxPathSize )
+{
+ io_object_t nextMedia;
+ kern_return_t kernResult = KERN_FAILURE;
+ nextMedia = IOIteratorNext( mediaIterator );
+ if ( nextMedia == NULL )
+ {
+ *deviceFilePath = '\0';
+ }
+ else
+ {
+ CFTypeRef deviceFilePathAsCFString;
+ deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
+ nextMedia, CFSTR( kIOBSDNameKey ),
+ kCFAllocatorDefault, 0 );
+ *deviceFilePath = '\0';
+ if ( deviceFilePathAsCFString )
+ {
+ size_t devPathLength = strlen( _PATH_DEV );
+ strcpy( deviceFilePath, _PATH_DEV );
+ if ( CFStringGetCString( (const __CFString *) deviceFilePathAsCFString,
+ deviceFilePath + devPathLength,
+ maxPathSize - devPathLength,
+ kCFStringEncodingASCII ) )
+ {
+ // fprintf( stderr, "BSD path: %s\n", deviceFilePath );
+ kernResult = KERN_SUCCESS;
+ }
+ CFRelease( deviceFilePathAsCFString );
+ }
+ }
+ IOObjectRelease( nextMedia );
+ return kernResult;
+}
+
+
+static int OpenDrive( const char *deviceFilePath )
+{
+
+ int fileDescriptor;
+
+ fileDescriptor = open( deviceFilePath, O_RDONLY );
+ if ( fileDescriptor == -1 )
+ fprintf( stderr, "Error %d opening device %s.\n", errno, deviceFilePath );
+ return fileDescriptor;
+
+}
+
+static struct _CDTOC * ReadTOC( const char * devpath ) {
+
+ struct _CDTOC * toc_p = NULL;
+ io_iterator_t iterator = 0;
+ io_registry_entry_t service = 0;
+ CFDictionaryRef properties = 0;
+ CFDataRef data = 0;
+ mach_port_t port = 0;
+ char * devname;
+
+ if (( devname = strrchr( devpath, '/' )) != NULL ) {
+ ++devname;
+ }
+ else {
+ devname = (char *) devpath;
+ }
+
+ if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS ) {
+ fprintf( stderr, "IOMasterPort failed\n" );
+ goto Exit;
+ }
+
+ if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
+ &iterator ) != KERN_SUCCESS ) {
+ fprintf( stderr, "IOServiceGetMatchingServices failed\n" );
+ goto Exit;
+ }
+
+ service = IOIteratorNext( iterator );
+
+ IOObjectRelease( iterator );
+
+ iterator = 0;
+
+ while ( service && !IOObjectConformsTo( service, "IOCDMedia" )) {
+ if ( IORegistryEntryGetParentIterator( service, kIOServicePlane,
+ &iterator ) != KERN_SUCCESS ) {
+ fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
+ goto Exit;
+ }
+
+ IOObjectRelease( service );
+ service = IOIteratorNext( iterator );
+ IOObjectRelease( iterator );
+
+ }
+
+ if ( service == NULL ) {
+ fprintf( stderr, "CD media not found\n" );
+ goto Exit;
+ }
+
+ if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
+ kCFAllocatorDefault,
+ kNilOptions ) != KERN_SUCCESS ) {
+ fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
+ goto Exit;
+ }
+
+ data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR(kIOCDMediaTOCKey) );
+ if ( data == NULL ) {
+ fprintf( stderr, "CFDictionaryGetValue failed\n" );
+ goto Exit;
+ }
+ else {
+
+ CFRange range;
+ CFIndex buflen;
+
+ buflen = CFDataGetLength( data ) + 1;
+ range = CFRangeMake( 0, buflen );
+ toc_p = (struct _CDTOC *) malloc( buflen );
+ if ( toc_p == NULL ) {
+ fprintf( stderr, "Out of memory\n" );
+ goto Exit;
+ }
+ else {
+ CFDataGetBytes( data, range, (unsigned char *) toc_p );
+ }
+
+ /*
+ fprintf( stderr, "Table of contents\n length %d first %d last %d\n",
+ toc_p->length, toc_p->first_session, toc_p->last_session );
+ */
+
+ CFRelease( properties );
+
+ }
+
+
+ Exit:
+
+ if ( service ) {
+ IOObjectRelease( service );
+ }
+
+ return toc_p;
+
+}
+#endif
+
+#ifdef WIN32
+
+bool ReadCDSector(unsigned int hid, unsigned int tid, unsigned int lun, unsigned long frame, unsigned char *buf, int bufsize)
+{
+ HANDLE hEventSRB;
+ SRB_ExecSCSICmd srb;
+ DWORD dwStatus;
+
+ hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ memset(&srb,0,sizeof(SRB_ExecSCSICmd));
+ srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
+ srb.SRB_HaId = hid;
+ srb.SRB_Target = tid;
+ srb.SRB_Lun = lun;
+ srb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+ srb.SRB_SenseLen = SENSE_LEN;
+ srb.SRB_PostProc = hEventSRB;
+ srb.SRB_BufPointer = buf;
+ srb.SRB_BufLen = bufsize;
+ srb.SRB_CDBLen = 10;
+ srb.CDBByte[0] = SCSI_READ10;
+ srb.CDBByte[2] = (unsigned char) (frame>>24);
+ srb.CDBByte[3] = (unsigned char) (frame>>16);
+ srb.CDBByte[4] = (unsigned char) (frame>>8);
+ srb.CDBByte[5] = (unsigned char) (frame);
+ srb.CDBByte[7] = 0;
+ srb.CDBByte[8] = 1; /* read 1 frames */
+
+ ResetEvent(hEventSRB);
+ dwStatus = SendASPI32Command((SRB *)&srb);
+ if(dwStatus == SS_PENDING) {
+ WaitForSingleObject(hEventSRB, 100000);
+ }
+ CloseHandle(hEventSRB);
+ return (srb.SRB_TargStat == STATUS_GOOD);
+}
+
+int GetCDCapacity(unsigned int hid, unsigned int tid, unsigned int lun)
+{
+ HANDLE hEventSRB;
+ SRB_ExecSCSICmd srb;
+ DWORD dwStatus;
+ unsigned char buf[8];
+
+ hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ memset(&buf, 0, sizeof(buf));
+ memset(&srb,0,sizeof(SRB_ExecSCSICmd));
+ srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
+ srb.SRB_HaId = hid;
+ srb.SRB_Target = tid;
+ srb.SRB_Lun = lun;
+ srb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+ srb.SRB_SenseLen = SENSE_LEN;
+ srb.SRB_PostProc = hEventSRB;
+ srb.SRB_BufPointer = (unsigned char *)buf;
+ srb.SRB_BufLen = 8;
+ srb.SRB_CDBLen = 10;
+ srb.CDBByte[0] = SCSI_READCDCAP;
+ srb.CDBByte[2] = 0;
+ srb.CDBByte[3] = 0;
+ srb.CDBByte[4] = 0;
+ srb.CDBByte[5] = 0;
+ srb.CDBByte[8] = 0;
+
+ ResetEvent(hEventSRB);
+ dwStatus = SendASPI32Command((SRB *)&srb);
+ if(dwStatus == SS_PENDING) {
+ WaitForSingleObject(hEventSRB, 100000);
+ }
+
+ CloseHandle(hEventSRB);
+ return ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]) * ((buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]);
+}
+
+#endif
+
+cdrom_interface::cdrom_interface(char *dev)
+{
+ put("CD");
+ settype(CDLOG);
+ fd = -1; // File descriptor not yet allocated
+
+ if ( dev == NULL )
+ path = NULL;
+ else {
+ path = strdup(dev);
+ }
+ using_file=0;
+}
+
+void
+cdrom_interface::init(void) {
+ BX_DEBUG(("Init $Id: cdrom.cc,v 1.66 2003/12/08 23:49:48 danielg4 Exp $"));
+ BX_INFO(("file = '%s'",path));
+}
+
+cdrom_interface::~cdrom_interface(void)
+{
+#ifdef WIN32
+#else
+ if (fd >= 0)
+ close(fd);
+#endif
+ if (path)
+ free(path);
+ BX_DEBUG(("Exit"));
+}
+
+ bx_bool
+cdrom_interface::insert_cdrom(char *dev)
+{
+ unsigned char buffer[BX_CD_FRAMESIZE];
+ ssize_t ret;
+
+ // Load CD-ROM. Returns false if CD is not ready.
+ if (dev != NULL) path = strdup(dev);
+ BX_INFO (("load cdrom with path=%s", path));
+#ifdef WIN32
+ char drive[256];
+ OSVERSIONINFO osi;
+ if ( (path[1] == ':') && (strlen(path) == 2) )
+ {
+ osi.dwOSVersionInfoSize = sizeof(osi);
+ GetVersionEx(&osi);
+ if(osi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ // Use direct device access under windows NT/2k
+
+ // With all the backslashes it's hard to see, but to open D: drive
+ // the name would be: \\.\d:
+ sprintf(drive, "\\\\.\\%s", path);
+ using_file = 0;
+ BX_INFO (("Using direct access for cdrom."));
+ // This trick only works for Win2k and WinNT, so warn the user of that.
+ } else {
+ BX_INFO(("Using ASPI for cdrom. Drive letters are unused yet."));
+ bUseASPI = TRUE;
+ }
+ }
+ else
+ {
+ strcpy(drive,path);
+ using_file = 1;
+ bUseASPI = FALSE;
+ BX_INFO (("Opening image file as a cd"));
+ }
+ if(bUseASPI) {
+ DWORD d;
+ UINT cdr, cnt, max;
+ UINT i, j, k;
+ SRB_HAInquiry sh;
+ SRB_GDEVBlock sd;
+ if (!hASPI) {
+ hASPI = LoadLibrary("WNASPI32.DLL");
+ }
+ if(hASPI) {
+ SendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress( hASPI, "SendASPI32Command" );
+ GetASPI32DLLVersion = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32DLLVersion" );
+ GetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32SupportInfo" );
+// BX_INFO(("Using first CDROM. Please upgrade your ASPI drivers to version 4.01 or later if you wish to specify a cdrom driver."));
+
+ cdr = 0;
+ bHaveDev = FALSE;
+ d = GetASPI32SupportInfo();
+ cnt = LOBYTE(LOWORD(d));
+ for(i = 0; i < cnt; i++) {
+ memset(&sh, 0, sizeof(sh));
+ sh.SRB_Cmd = SC_HA_INQUIRY;
+ sh.SRB_HaId = i;
+ SendASPI32Command((LPSRB)&sh);
+ if(sh.SRB_Status != SS_COMP)
+ continue;
+
+ max = (int)sh.HA_Unique[3];
+ for(j = 0; j < max; j++) {
+ for(k = 0; k < 8; k++) {
+ memset(&sd, 0, sizeof(sd));
+ sd.SRB_Cmd = SC_GET_DEV_TYPE;
+ sd.SRB_HaId = i;
+ sd.SRB_Target = j;
+ sd.SRB_Lun = k;
+ SendASPI32Command((LPSRB)&sd);
+ if(sd.SRB_Status == SS_COMP) {
+ if(sd.SRB_DeviceType == DTYPE_CDROM) {
+ cdr++;
+ if(cdr > cdromCount) {
+ hid = i;
+ tid = j;
+ lun = k;
+ cdromCount++;
+ bHaveDev = TRUE;
+ }
+ }
+ }
+ if(bHaveDev) break;
+ }
+ if(bHaveDev) break;
+ }
+
+ }
+ } else {
+ BX_PANIC(("Could not load ASPI drivers, so cdrom access will fail"));
+ }
+ fd=1;
+ } else {
+ BX_INFO(("Using direct access for CDROM"));
+ hFile=CreateFile((char *)&drive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+ if (hFile !=(void *)0xFFFFFFFF)
+ fd=1;
+ }
+#elif defined(__APPLE__)
+ if(strcmp(path, "drive") == 0)
+ {
+ mach_port_t masterPort = NULL;
+ io_iterator_t mediaIterator;
+ kern_return_t kernResult;
+
+ BX_INFO(( "Insert CDROM" ));
+
+ kernResult = FindEjectableCDMedia( &mediaIterator, &masterPort );
+ if ( kernResult != KERN_SUCCESS ) {
+ BX_INFO (("Unable to find CDROM"));
+ return false;
+ }
+
+ kernResult = GetDeviceFilePath( mediaIterator, CDDevicePath, sizeof( CDDevicePath ) );
+ if ( kernResult != KERN_SUCCESS ) {
+ BX_INFO (("Unable to get CDROM device file path" ));
+ return false;
+ }
+
+ // Here a cdrom was found so see if we can read from it.
+ // At this point a failure will result in panic.
+ if ( strlen( CDDevicePath ) ) {
+ fd = open(CDDevicePath, O_RDONLY);
+ }
+ }
+ else
+ {
+ fd = open(path, O_RDONLY);
+ }
+#else
+ // all platforms except win32
+ fd = open(path, O_RDONLY);
+#endif
+ if (fd < 0) {
+ BX_ERROR(( "open cd failed for %s: %s", path, strerror(errno)));
+ return(false);
+ }
+
+ // I just see if I can read a sector to verify that a
+ // CD is in the drive and readable.
+#ifdef WIN32
+ if(bUseASPI) {
+ return ReadCDSector(hid, tid, lun, 0, buffer, BX_CD_FRAMESIZE);
+ } else {
+ if (!ReadFile(hFile, (void *) buffer, BX_CD_FRAMESIZE, (unsigned long *) &ret, NULL)) {
+ CloseHandle(hFile);
+ fd = -1;
+ BX_DEBUG(( "insert_cdrom: read returns error." ));
+ return(false);
+ }
+ }
+#else
+ // do fstat to determine if it's a file or a device, then set using_file.
+ struct stat stat_buf;
+ ret = fstat (fd, &stat_buf);
+ if (ret) {
+ BX_PANIC (("fstat cdrom file returned error: %s", strerror (errno)));
+ }
+ if (S_ISREG (stat_buf.st_mode)) {
+ using_file = 1;
+ BX_INFO (("Opening image file %s as a cd.", path));
+ } else {
+ using_file = 0;
+ BX_INFO (("Using direct access for cdrom."));
+ }
+
+ ret = read(fd, (char*) &buffer, BX_CD_FRAMESIZE);
+ if (ret < 0) {
+ close(fd);
+ fd = -1;
+ BX_DEBUG(( "insert_cdrom: read returns error: %s", strerror (errno) ));
+ return(false);
+ }
+#endif
+ return(true);
+}
+
+ int
+cdrom_interface::start_cdrom()
+{
+ // Spin up the cdrom drive.
+
+ if (fd >= 0) {
+#if defined(__NetBSD__)
+ if (ioctl (fd, CDIOCSTART) < 0)
+ BX_DEBUG(( "start_cdrom: start returns error: %s", strerror (errno) ));
+ return(true);
+#else
+ BX_INFO(("start_cdrom: your OS is not supported yet."));
+ return(false); // OS not supported yet, return false always.
+#endif
+ }
+ return(false);
+}
+
+ void
+cdrom_interface::eject_cdrom()
+{
+ // Logically eject the CD. I suppose we could stick in
+ // some ioctl() calls to really eject the CD as well.
+
+ if (fd >= 0) {
+#if (defined(__OpenBSD__) || defined(__FreeBSD__))
+ (void) ioctl (fd, CDIOCALLOW);
+ if (ioctl (fd, CDIOCEJECT) < 0)
+ BX_DEBUG(( "eject_cdrom: eject returns error." ));
+#endif
+
+#ifdef WIN32
+if (using_file == 0)
+{
+ if(bUseASPI) {
+ } else {
+ DWORD lpBytesReturned;
+ DeviceIoControl(hFile, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+ }
+}
+#else // WIN32
+
+#if __linux__
+ if (!using_file)
+ ioctl (fd, CDROMEJECT, NULL);
+#endif
+
+ close(fd);
+#endif // WIN32
+ fd = -1;
+ }
+}
+
+
+ bx_bool
+cdrom_interface::read_toc(uint8* buf, int* length, bx_bool msf, int start_track)
+{
+ // Read CD TOC. Returns false if start track is out of bounds.
+
+ if (fd < 0) {
+ BX_PANIC(("cdrom: read_toc: file not open."));
+ }
+
+#if defined(WIN32)
+ if (1) { // This is a hack and works okay if there's one rom track only
+#else
+ if (using_file) {
+#endif
+ // From atapi specs : start track can be 0-63, AA
+ if ((start_track > 1) && (start_track != 0xaa))
+ return false;
+
+ buf[2] = 1;
+ buf[3] = 1;
+
+ int len = 4;
+ if (start_track <= 1) {
+ buf[len++] = 0; // Reserved
+ buf[len++] = 0x14; // ADR, control
+ buf[len++] = 1; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = 0; // minute
+ buf[len++] = 2; // second
+ buf[len++] = 0; // frame
+ } else {
+ buf[len++] = 0;
+ buf[len++] = 0;
+ buf[len++] = 0;
+ buf[len++] = 0; // logical sector 0
+ }
+ }
+
+ // Lead out track
+ buf[len++] = 0; // Reserved
+ buf[len++] = 0x16; // ADR, control
+ buf[len++] = 0xaa; // Track number
+ buf[len++] = 0; // Reserved
+
+ uint32 blocks = capacity();
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = (uint8)(((blocks + 150) / 75) / 60); // minute
+ buf[len++] = (uint8)(((blocks + 150) / 75) % 60); // second
+ buf[len++] = (uint8)((blocks + 150) % 75); // frame;
+ } else {
+ buf[len++] = (blocks >> 24) & 0xff;
+ buf[len++] = (blocks >> 16) & 0xff;
+ buf[len++] = (blocks >> 8) & 0xff;
+ buf[len++] = (blocks >> 0) & 0xff;
+ }
+
+ buf[0] = ((len-2) >> 8) & 0xff;
+ buf[1] = (len-2) & 0xff;
+
+ *length = len;
+
+ return true;
+ }
+ // all these implementations below are the platform-dependent code required
+ // to read the TOC from a physical cdrom.
+#ifdef WIN32
+ {
+/* #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+ #define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+ unsigned long iBytesReturned;
+ DeviceIoControl(hFile, IOCTL_CDROM_READ_TOC, NULL, 0, NULL, 0, &iBytesReturned, NULL); */
+ BX_ERROR (("WARNING: read_toc is not implemented, just returning length=1"));
+ *length = 1;
+ return true;
+ }
+#elif __linux__ || defined(__sun)
+ {
+ struct cdrom_tochdr tochdr;
+ if (ioctl(fd, CDROMREADTOCHDR, &tochdr))
+ BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
+
+ if ((start_track > tochdr.cdth_trk1) && (start_track != 0xaa))
+ return false;
+
+ buf[2] = tochdr.cdth_trk0;
+ buf[3] = tochdr.cdth_trk1;
+
+ if (start_track < tochdr.cdth_trk0)
+ start_track = tochdr.cdth_trk0;
+
+ int len = 4;
+ for (int i = start_track; i <= tochdr.cdth_trk1; i++) {
+ struct cdrom_tocentry tocentry;
+ tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
+ tocentry.cdte_track = i;
+ if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
+ BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
+ buf[len++] = 0; // Reserved
+ buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
+ buf[len++] = i; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = tocentry.cdte_addr.msf.minute;
+ buf[len++] = tocentry.cdte_addr.msf.second;
+ buf[len++] = tocentry.cdte_addr.msf.frame;
+ } else {
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
+ }
+ }
+
+ // Lead out track
+ struct cdrom_tocentry tocentry;
+ tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
+#ifdef CDROM_LEADOUT
+ tocentry.cdte_track = CDROM_LEADOUT;
+#else
+ tocentry.cdte_track = 0xaa;
+#endif
+ if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
+ BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
+ buf[len++] = 0; // Reserved
+ buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
+ buf[len++] = 0xaa; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = tocentry.cdte_addr.msf.minute;
+ buf[len++] = tocentry.cdte_addr.msf.second;
+ buf[len++] = tocentry.cdte_addr.msf.frame;
+ } else {
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
+ buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
+ }
+
+ buf[0] = ((len-2) >> 8) & 0xff;
+ buf[1] = (len-2) & 0xff;
+
+ *length = len;
+
+ return true;
+ }
+#elif (defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__))
+ {
+ struct ioc_toc_header h;
+ struct ioc_read_toc_entry t;
+
+ if (ioctl (fd, CDIOREADTOCHEADER, &h) < 0)
+ BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
+
+ if ((start_track > h.ending_track) && (start_track != 0xaa))
+ return false;
+
+ buf[2] = h.starting_track;
+ buf[3] = h.ending_track;
+
+ if (start_track < h.starting_track)
+ start_track = h.starting_track;
+
+ int len = 4;
+ for (int i = start_track; i <= h.ending_track; i++) {
+ struct cd_toc_entry tocentry;
+ t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
+ t.starting_track = i;
+ t.data_len = sizeof(tocentry);
+ t.data = &tocentry;
+
+ if (ioctl (fd, CDIOREADTOCENTRYS, &t) < 0)
+ BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
+
+ buf[len++] = 0; // Reserved
+ buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
+ buf[len++] = i; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = tocentry.addr.msf.minute;
+ buf[len++] = tocentry.addr.msf.second;
+ buf[len++] = tocentry.addr.msf.frame;
+ } else {
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
+ }
+ }
+
+ // Lead out track
+ struct cd_toc_entry tocentry;
+ t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
+ t.starting_track = 0xaa;
+ t.data_len = sizeof(tocentry);
+ t.data = &tocentry;
+
+ if (ioctl (fd, CDIOREADTOCENTRYS, &t) < 0)
+ BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
+
+ buf[len++] = 0; // Reserved
+ buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
+ buf[len++] = 0xaa; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = tocentry.addr.msf.minute;
+ buf[len++] = tocentry.addr.msf.second;
+ buf[len++] = tocentry.addr.msf.frame;
+ } else {
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
+ buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
+ }
+
+ buf[0] = ((len-2) >> 8) & 0xff;
+ buf[1] = (len-2) & 0xff;
+
+ *length = len;
+
+ return true;
+ }
+#elif defined(__APPLE__)
+ // Read CD TOC. Returns false if start track is out of bounds.
+
+#if 1
+ {
+ struct _CDTOC * toc = ReadTOC( CDDevicePath );
+
+ if ((start_track > toc->last_session) && (start_track != 0xaa))
+ return false;
+
+ buf[2] = toc->first_session;
+ buf[3] = toc->last_session;
+
+ if (start_track < toc->first_session)
+ start_track = toc->first_session;
+
+ int len = 4;
+ for (int i = start_track; i <= toc->last_session; i++) {
+ buf[len++] = 0; // Reserved
+ buf[len++] = toc->trackdesc[i].ctrl_adr ; // ADR, control
+ buf[len++] = i; // Track number
+ buf[len++] = 0; // Reserved
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = toc->trackdesc[i].address.minute;
+ buf[len++] = toc->trackdesc[i].address.second;
+ buf[len++] = toc->trackdesc[i].address.frame;
+ } else {
+ unsigned lba = (unsigned)(MSF_TO_LBA(toc->trackdesc[i].address));
+ buf[len++] = (lba >> 24) & 0xff;
+ buf[len++] = (lba >> 16) & 0xff;
+ buf[len++] = (lba >> 8) & 0xff;
+ buf[len++] = (lba >> 0) & 0xff;
+ }
+ }
+
+ // Lead out track
+ buf[len++] = 0; // Reserved
+ buf[len++] = 0x16; // ADR, control
+ buf[len++] = 0xaa; // Track number
+ buf[len++] = 0; // Reserved
+
+ uint32 blocks = capacity();
+
+ // Start address
+ if (msf) {
+ buf[len++] = 0; // reserved
+ buf[len++] = (uint8)(((blocks + 150) / 75) / 60); // minute
+ buf[len++] = (uint8)(((blocks + 150) / 75) % 60); // second
+ buf[len++] = (uint8)((blocks + 150) % 75); // frame;
+ } else {
+ buf[len++] = (blocks >> 24) & 0xff;
+ buf[len++] = (blocks >> 16) & 0xff;
+ buf[len++] = (blocks >> 8) & 0xff;
+ buf[len++] = (blocks >> 0) & 0xff;
+ }
+
+ buf[0] = ((len-2) >> 8) & 0xff;
+ buf[1] = (len-2) & 0xff;
+
+ *length = len;
+
+ return true;
+// BX_INFO(( "Read TOC - Not Implemented" ));
+// return false;
+ }
+#else
+ BX_INFO(( "Read TOC - Not Implemented" ));
+ return false;
+#endif
+#else
+ BX_INFO(("read_toc: your OS is not supported yet."));
+ return(false); // OS not supported yet, return false always.
+#endif
+}
+
+
+ uint32
+cdrom_interface::capacity()
+{
+ // Return CD-ROM capacity. I believe you want to return
+ // the number of blocks of capacity the actual media has.
+
+#if !defined WIN32
+ // win32 has its own way of doing this
+ if (using_file) {
+ // return length of the image file
+ struct stat stat_buf;
+ int ret = fstat (fd, &stat_buf);
+ if (ret) {
+ BX_PANIC (("fstat on cdrom image returned err: %s", strerror(errno)));
+ }
+ BX_INFO (("cdrom size is %lld bytes", stat_buf.st_size));
+ if ((stat_buf.st_size % 2048) != 0) {
+ BX_ERROR (("expected cdrom image to be a multiple of 2048 bytes"));
+ }
+ return stat_buf.st_size / 2048;
+ }
+#endif
+
+#ifdef __BEOS__
+ return GetNumDeviceBlocks(fd, BX_CD_FRAMESIZE);
+#elif defined(__sun)
+ {
+ struct stat buf = {0};
+
+ if (fd < 0) {
+ BX_PANIC(("cdrom: capacity: file not open."));
+ }
+
+ if( fstat(fd, &buf) != 0 )
+ BX_PANIC(("cdrom: capacity: stat() failed."));
+
+ return(buf.st_size);
+ }
+#elif (defined(__NetBSD__) || defined(__OpenBSD__))
+ {
+ // We just read the disklabel, imagine that...
+ struct disklabel lp;
+
+ if (fd < 0)
+ BX_PANIC(("cdrom: capacity: file not open."));
+
+ if (ioctl(fd, DIOCGDINFO, &lp) < 0)
+ BX_PANIC(("cdrom: ioctl(DIOCGDINFO) failed"));
+
+ BX_DEBUG(( "capacity: %u", lp.d_secperunit ));
+ return(lp.d_secperunit);
+ }
+#elif defined(__linux__)
+ {
+ // Read the TOC to get the data size, since BLKGETSIZE doesn't work on
+ // non-ATAPI drives. This is based on Keith Jones code below.
+ // <splite@purdue.edu> 21 June 2001
+
+ int i, dtrk_lba, num_sectors;
+ int dtrk = 0;
+ struct cdrom_tochdr td;
+ struct cdrom_tocentry te;
+
+ if (fd < 0)
+ BX_PANIC(("cdrom: capacity: file not open."));
+
+ if (ioctl(fd, CDROMREADTOCHDR, &td) < 0)
+ BX_PANIC(("cdrom: ioctl(CDROMREADTOCHDR) failed"));
+
+ num_sectors = -1;
+ dtrk_lba = -1;
+
+ for (i = td.cdth_trk0; i <= td.cdth_trk1; i++) {
+ te.cdte_track = i;
+ te.cdte_format = CDROM_LBA;
+ if (ioctl(fd, CDROMREADTOCENTRY, &te) < 0)
+ BX_PANIC(("cdrom: ioctl(CDROMREADTOCENTRY) failed"));
+
+ if (dtrk_lba != -1) {
+ num_sectors = te.cdte_addr.lba - dtrk_lba;
+ break;
+ }
+ if (te.cdte_ctrl & CDROM_DATA_TRACK) {
+ dtrk = i;
+ dtrk_lba = te.cdte_addr.lba;
+ }
+ }
+
+ if (num_sectors < 0) {
+ if (dtrk_lba != -1) {
+ te.cdte_track = CDROM_LEADOUT;
+ te.cdte_format = CDROM_LBA;
+ if (ioctl(fd, CDROMREADTOCENTRY, &te) < 0)
+ BX_PANIC(("cdrom: ioctl(CDROMREADTOCENTRY) failed"));
+ num_sectors = te.cdte_addr.lba - dtrk_lba;
+ } else
+ BX_PANIC(("cdrom: no data track found"));
+ }
+
+ BX_INFO(("cdrom: Data track %d, length %d", dtrk, num_sectors));
+
+ return(num_sectors);
+
+ }
+#elif defined(__FreeBSD__)
+ {
+ // Read the TOC to get the size of the data track.
+ // Keith Jones <freebsd.dev@blueyonder.co.uk>, 16 January 2000
+
+#define MAX_TRACKS 100
+
+ int i, num_tracks, num_sectors;
+ struct ioc_toc_header td;
+ struct ioc_read_toc_entry rte;
+ struct cd_toc_entry toc_buffer[MAX_TRACKS + 1];
+
+ if (fd < 0)
+ BX_PANIC(("cdrom: capacity: file not open."));
+
+ if (ioctl(fd, CDIOREADTOCHEADER, &td) < 0)
+ BX_PANIC(("cdrom: ioctl(CDIOREADTOCHEADER) failed"));
+
+ num_tracks = (td.ending_track - td.starting_track) + 1;
+ if (num_tracks > MAX_TRACKS)
+ BX_PANIC(("cdrom: TOC is too large"));
+
+ rte.address_format = CD_LBA_FORMAT;
+ rte.starting_track = td.starting_track;
+ rte.data_len = (num_tracks + 1) * sizeof(struct cd_toc_entry);
+ rte.data = toc_buffer;
+ if (ioctl(fd, CDIOREADTOCENTRYS, &rte) < 0)
+ BX_PANIC(("cdrom: ioctl(CDIOREADTOCENTRYS) failed"));
+
+ num_sectors = -1;
+ for (i = 0; i < num_tracks; i++) {
+ if (rte.data[i].control & 4) { /* data track */
+ num_sectors = ntohl(rte.data[i + 1].addr.lba)
+ - ntohl(rte.data[i].addr.lba);
+ BX_INFO(( "cdrom: Data track %d, length %d",
+ rte.data[i].track, num_sectors));
+ break;
+ }
+ }
+
+ if (num_sectors < 0)
+ BX_PANIC(("cdrom: no data track found"));
+
+ return(num_sectors);
+
+ }
+#elif defined WIN32
+ {
+ if(bUseASPI) {
+ return (GetCDCapacity(hid, tid, lun) / 2352);
+ } else if(using_file) {
+ ULARGE_INTEGER FileSize;
+ FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
+ return (FileSize.QuadPart / 2048);
+ } else { /* direct device access */
+ DWORD SectorsPerCluster;
+ DWORD TotalNumOfClusters;
+ GetDiskFreeSpace( path, &SectorsPerCluster, NULL, NULL, &TotalNumOfClusters);
+ return (TotalNumOfClusters * SectorsPerCluster);
+ }
+ }
+#elif defined __APPLE__
+// Find the size of the first data track on the cd. This has produced
+// the same results as the linux version on every cd I have tried, about
+// 5. The differences here seem to be that the entries in the TOC when
+// retrieved from the IOKit interface appear in a reversed order when
+// compared with the linux READTOCENTRY ioctl.
+ {
+ // Return CD-ROM capacity. I believe you want to return
+ // the number of bytes of capacity the actual media has.
+
+ BX_INFO(( "Capacity" ));
+
+ struct _CDTOC * toc = ReadTOC( CDDevicePath );
+
+ if ( toc == NULL ) {
+ BX_PANIC(( "capacity: Failed to read toc" ));
+ }
+
+ size_t toc_entries = ( toc->length - 2 ) / sizeof( struct _CDTOC_Desc );
+
+ BX_DEBUG(( "reading %d toc entries\n", toc_entries ));
+
+ int start_sector = -1;
+ int data_track = -1;
+
+ // Iterate through the list backward. Pick the first data track and
+ // get the address of the immediately previous (or following depending
+ // on how you look at it). The difference in the sector numbers
+ // is returned as the sized of the data track.
+ for ( int i=toc_entries - 1; i>=0; i-- ) {
+
+ BX_DEBUG(( "session %d ctl_adr %d tno %d point %d lba %d z %d p lba %d\n",
+ (int)toc->trackdesc[i].session,
+ (int)toc->trackdesc[i].ctrl_adr,
+ (int)toc->trackdesc[i].tno,
+ (int)toc->trackdesc[i].point,
+ MSF_TO_LBA( toc->trackdesc[i].address ),
+ (int)toc->trackdesc[i].zero,
+ MSF_TO_LBA(toc->trackdesc[i].p )));
+
+ if ( start_sector != -1 ) {
+
+ start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
+ break;
+
+ }
+
+ if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 ) continue;
+
+ if ( toc->trackdesc[i].ctrl_adr & 0x04 ) {
+
+ data_track = toc->trackdesc[i].point;
+
+ start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
+
+ }
+
+ }
+
+ free( toc );
+
+ if ( start_sector == -1 ) {
+ start_sector = 0;
+ }
+
+ BX_INFO(("first data track %d data size is %d", data_track, start_sector));
+
+ return start_sector;
+ }
+#else
+ BX_ERROR(( "capacity: your OS is not supported yet." ));
+ return(0);
+#endif
+}
+
+ void BX_CPP_AttrRegparmN(2)
+cdrom_interface::read_block(uint8* buf, int lba)
+{
+ // Read a single block from the CD
+
+#ifdef WIN32
+ LARGE_INTEGER pos;
+#else
+ off_t pos;
+#endif
+ ssize_t n;
+
+#ifdef WIN32
+ if(bUseASPI) {
+ ReadCDSector(hid, tid, lun, lba, buf, BX_CD_FRAMESIZE);
+ n = BX_CD_FRAMESIZE;
+ } else {
+ pos.QuadPart = (LONGLONG)lba*BX_CD_FRAMESIZE;
+ pos.LowPart = SetFilePointer(hFile, pos.LowPart, &pos.HighPart, SEEK_SET);
+ if ((pos.LowPart == 0xffffffff) && (GetLastError() != NO_ERROR)) {
+ BX_PANIC(("cdrom: read_block: SetFilePointer returned error."));
+ }
+ ReadFile(hFile, (void *) buf, BX_CD_FRAMESIZE, (unsigned long *) &n, NULL);
+ }
+#elif defined(__APPLE__)
+#define CD_SEEK_DISTANCE kCDSectorSizeWhole
+ if(using_file)
+ {
+ pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
+ if (pos < 0) {
+ BX_PANIC(("cdrom: read_block: lseek returned error."));
+ }
+ n = read(fd, buf, BX_CD_FRAMESIZE);
+ }
+ else
+ {
+ // This seek will leave us 16 bytes from the start of the data
+ // hence the magic number.
+ pos = lseek(fd, lba*CD_SEEK_DISTANCE + 16, SEEK_SET);
+ if (pos < 0) {
+ BX_PANIC(("cdrom: read_block: lseek returned error."));
+ }
+ n = read(fd, buf, CD_FRAMESIZE);
+ }
+#else
+ pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
+ if (pos < 0) {
+ BX_PANIC(("cdrom: read_block: lseek returned error."));
+ }
+ n = read(fd, (char*) buf, BX_CD_FRAMESIZE);
+#endif
+
+ if (n != BX_CD_FRAMESIZE) {
+ BX_PANIC(("cdrom: read_block: read returned %d",
+ (int) n));
+ }
+}
+
+#endif /* if BX_SUPPORT_CDROM */
diff --git a/tools/ioemu/iodev/cdrom.h b/tools/ioemu/iodev/cdrom.h
new file mode 100644
index 0000000000..29fdfaff85
--- /dev/null
+++ b/tools/ioemu/iodev/cdrom.h
@@ -0,0 +1,67 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdrom.h,v 1.13 2003/08/19 00:37:03 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Header file for low-level OS specific CDROM emulation
+
+
+class cdrom_interface : public logfunctions {
+public:
+ cdrom_interface(char *dev);
+ ~cdrom_interface(void);
+ void init(void);
+
+ // Load CD-ROM. Returns false if CD is not ready.
+ bx_bool insert_cdrom(char *dev = NULL);
+
+ // Logically eject the CD.
+ void eject_cdrom();
+
+ // Read CD TOC. Returns false if start track is out of bounds.
+ bx_bool read_toc(uint8* buf, int* length, bx_bool msf, int start_track);
+
+ // Return CD-ROM capacity (in 2048 byte frames)
+ uint32 capacity();
+
+ // Read a single block from the CD
+ void read_block(uint8* buf, int lba) BX_CPP_AttrRegparmN(2);
+
+ // Start (spin up) the CD.
+ int start_cdrom();
+
+private:
+ int fd;
+ char *path;
+
+ int using_file;
+#ifdef WIN32
+ HANDLE hFile;
+ int hid;
+ int tid;
+ int lun;
+#endif
+ };
+
diff --git a/tools/ioemu/iodev/cdrom_beos.h b/tools/ioemu/iodev/cdrom_beos.h
new file mode 100644
index 0000000000..8a22d5c0f8
--- /dev/null
+++ b/tools/ioemu/iodev/cdrom_beos.h
@@ -0,0 +1,10 @@
+#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
diff --git a/tools/ioemu/iodev/cmos.cc b/tools/ioemu/iodev/cmos.cc
new file mode 100644
index 0000000000..fbf3144989
--- /dev/null
+++ b/tools/ioemu/iodev/cmos.cc
@@ -0,0 +1,824 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cmos.cc,v 1.44 2003/12/27 13:43:41 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+
+// 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"
+
+#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 (to be completed)
+//
+// Idx Len Description
+// 0x15 2 Base memory in 1k
+// 0x17 2 Memory size above 1M in 1k
+// 0x30 2 Memory size above 1M in 1k
+// 0x34 2 Memory size above 16M in 64k
+//
+
+// check that BX_NUM_CMOS_REGS is 64 or 128
+#if (BX_NUM_CMOS_REGS == 64)
+#elif (BX_NUM_CMOS_REGS == 128)
+#else
+#error "Invalid BX_NUM_CMOS_REGS value in config.h"
+#endif
+
+
+ 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)
+{
+}
+
+bx_cmos_c::bx_cmos_c(void)
+{
+ put("CMOS");
+ settype(CMOSLOG);
+
+ unsigned i;
+ for (i=0; i<BX_NUM_CMOS_REGS; 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)
+{
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_cmos_c::init(void)
+{
+ BX_DEBUG(("Init $Id: cmos.cc,v 1.44 2003/12/27 13:43:41 vruppert Exp $"));
+ // 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 BX_USE_SPECIFIED_TIME0 != 0
+ // ??? this will not be correct for using an image file.
+ // perhaps take values in CMOS and work backwards to find
+ // s.timeval from values read in.
+ BX_CMOS_THIS s.timeval = BX_USE_SPECIFIED_TIME0;
+
+#else // BX_USE_SPECIFIED_TIME0 != 0
+
+ // localtime
+ if (bx_options.clock.Otime0->get () == BX_CLOCK_TIME0_LOCAL) {
+ BX_INFO(("Using local time for initial clock"));
+ BX_CMOS_THIS s.timeval = time(NULL);
+ }
+ // utc
+ else if (bx_options.clock.Otime0->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 = bx_options.clock.Otime0->get ();
+ }
+#endif // BX_USE_SPECIFIED_TIME0 != 0
+
+ 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));
+
+ update_clock();
+ BX_CMOS_THIS s.timeval_change = 0;
+
+ // load CMOS from image file if requested.
+ if (bx_options.cmos.OcmosImage->get ()) {
+ // CMOS image file requested
+ int fd, ret;
+ struct stat stat_buf;
+
+ fd = open(bx_options.cmos.Opath->getptr (), O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0) {
+ BX_PANIC(("trying to open cmos image file '%s'",
+ bx_options.cmos.Opath->getptr ()));
+ }
+ ret = fstat(fd, &stat_buf);
+ if (ret) {
+ BX_PANIC(("CMOS: could not fstat() image file."));
+ }
+ if (stat_buf.st_size != BX_NUM_CMOS_REGS) {
+ BX_PANIC(("CMOS: image file not same size as BX_NUM_CMOS_REGS."));
+ }
+
+ ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, BX_NUM_CMOS_REGS);
+ if (ret != BX_NUM_CMOS_REGS) {
+ BX_PANIC(("CMOS: error reading cmos file."));
+ }
+ close(fd);
+ BX_INFO(("successfuly read from image file '%s'.",
+ bx_options.cmos.Opath->getptr ()));
+ }
+ 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
+ }
+}
+
+ 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::CRA_change(void)
+{
+ unsigned nibble;
+
+ // Periodic Interrupt timer
+ nibble = BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f;
+ if (nibble == 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;
+
+ if (bx_dbg.cmos)
+ BX_INFO(("CMOS read of CMOS register 0x%02x",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+
+
+ switch (address) {
+ case 0x0070:
+ BX_INFO(("read of index port 0x70. returning 0xff"));
+ // Volker says his boxes return 0xff
+ //ret8 = BX_CMOS_THIS s.cmos_mem_address;
+ return(0xff);
+ break;
+ case 0x0071:
+ if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+ BX_PANIC(("unsupported cmos io read, register(0x%02x)!",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+ }
+
+ 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);
+ break;
+
+ default:
+ BX_PANIC(("unsupported cmos read, address=0x%04x!",
+ (unsigned) address));
+ return(0);
+ break;
+ }
+}
+
+
+ // 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
+
+ if (bx_dbg.cmos)
+ BX_INFO(("CMOS write to address: 0x%04x = 0x%02x",
+ (unsigned) address, (unsigned) value));
+
+
+ switch (address) {
+ case 0x0070:
+#if (BX_NUM_CMOS_REGS == 64)
+ BX_CMOS_THIS s.cmos_mem_address = value & 0x3F;
+#else
+ BX_CMOS_THIS s.cmos_mem_address = value & 0x7F;
+#endif
+ break;
+
+ case 0x0071:
+ if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+ BX_PANIC(("unsupported cmos io write, register(0x%02x) = 0x%02x !",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+ return;
+ }
+ 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]));
+ return;
+ 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_INFO(("write reg 0x%02x: value = 0x%02x",
+ // (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value);
+ 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();
+ }
+ return;
+ 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();
+ return;
+ 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 houre 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
+
+ // can not handle binary or 12-hour mode yet.
+ if (value & 0x04)
+ BX_PANIC(("write status reg B, binary format enabled."));
+ if ( !(value & 0x02) )
+ BX_PANIC(("write status reg B, 12 hour mode enabled."));
+
+ 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 & 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;
+ }
+ return;
+ break;
+
+ case REG_STAT_C: // Control Register C
+ case REG_STAT_D: // Control Register D
+ BX_ERROR(("write to control register 0x%02x (read-only)",
+ BX_CMOS_THIS s.cmos_mem_address));
+ break;
+
+ case REG_DIAGNOSTIC_STATUS:
+ BX_DEBUG(("write register 0x0e: 0x%02x", (unsigned) 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"));
+ 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_PANIC(("unsupported cmos io write to reg F, case 0x%02x!",
+ (unsigned) value));
+ break;
+ }
+ break;
+
+ default:
+ BX_DEBUG(("write reg 0x%02x: value = 0x%02x",
+ (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+ break;
+ }
+
+ BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+ break;
+ }
+}
+
+
+ void
+bx_cmos_c::checksum_cmos(void)
+{
+ unsigned i;
+ Bit16u sum;
+
+ sum = 0;
+ for (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;
+
+ time_calendar = localtime(& BX_CMOS_THIS s.timeval);
+
+ // update seconds
+ val_bcd =
+ ((time_calendar->tm_sec / 10) << 4) |
+ (time_calendar->tm_sec % 10);
+ BX_CMOS_THIS s.reg[REG_SEC] = val_bcd;
+
+ // update minutes
+ val_bcd =
+ ((time_calendar->tm_min / 10) << 4) |
+ (time_calendar->tm_min % 10);
+ BX_CMOS_THIS s.reg[REG_MIN] = val_bcd;
+
+ // update hours
+ val_bcd =
+ ((time_calendar->tm_hour / 10) << 4) |
+ (time_calendar->tm_hour % 10);
+ BX_CMOS_THIS s.reg[REG_HOUR] = val_bcd;
+
+ // update day of the week
+ day = time_calendar->tm_wday + 1; // 0..6 to 1..7
+ BX_CMOS_THIS s.reg[REG_WEEK_DAY] = ((day / 10) << 4) | (day % 10);
+
+ // update day of the month
+ day = time_calendar->tm_mday;
+ BX_CMOS_THIS s.reg[REG_MONTH_DAY] = ((day / 10) << 4) | (day % 10);
+
+ // update month
+ month = time_calendar->tm_mon + 1;
+ BX_CMOS_THIS s.reg[REG_MONTH] = ((month / 10) << 4) | (month % 10);
+
+ // update year
+ year = time_calendar->tm_year % 100;
+ BX_CMOS_THIS s.reg[REG_YEAR] = ((year / 10) << 4) | (year % 10);
+
+ // update century
+ century = (time_calendar->tm_year / 100) + 19;
+ BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] =
+ ((century / 10) << 4) | (century % 10);
+
+ // 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;
+
+ // update seconds
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_SEC] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_SEC] & 0x0f);
+ time_calendar.tm_sec = val_bin;
+
+ // update minutes
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_MIN] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_MIN] & 0x0f);
+ time_calendar.tm_min = val_bin;
+
+ // update hours
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_HOUR] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_HOUR] & 0x0f);
+ time_calendar.tm_hour = val_bin;
+
+ // update day of the month
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_MONTH_DAY] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_MONTH_DAY] & 0x0f);
+ time_calendar.tm_mday = val_bin;
+
+ // update month
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_MONTH] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_MONTH] & 0x0f);
+ time_calendar.tm_mon = val_bin - 1;
+
+ // update year
+ val_bin =
+ ((BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] & 0x0f);
+ val_bin = (val_bin - 19) * 100;
+ val_bin +=
+ (((BX_CMOS_THIS s.reg[REG_YEAR] >> 4) * 10) +
+ (BX_CMOS_THIS s.reg[REG_YEAR] & 0x0f));
+ time_calendar.tm_year = val_bin;
+
+ BX_CMOS_THIS s.timeval = mktime(& time_calendar);
+}
diff --git a/tools/ioemu/iodev/cmos.h b/tools/ioemu/iodev/cmos.h
new file mode 100644
index 0000000000..c53907db3e
--- /dev/null
+++ b/tools/ioemu/iodev/cmos.h
@@ -0,0 +1,90 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cmos.h,v 1.9 2003/01/04 00:02:07 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+
+#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(void);
+ ~bx_cmos_c(void);
+
+ virtual void init(void);
+ virtual void checksum_cmos(void);
+ virtual void reset(unsigned type);
+
+ 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;
+
+ Bit8u reg[BX_NUM_CMOS_REGS];
+ } 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);
+ };
diff --git a/tools/ioemu/iodev/cpu.cc b/tools/ioemu/iodev/cpu.cc
new file mode 100644
index 0000000000..59e4c51c05
--- /dev/null
+++ b/tools/ioemu/iodev/cpu.cc
@@ -0,0 +1,334 @@
+/*
+ * Main cpu loop for handling I/O requests coming from a virtual machine
+ * Copyright © 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "bochs.h"
+#include <cpu/cpu.h>
+#ifdef BX_USE_VMX
+#include <sys/ioctl.h>
+/* According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <values.h>
+#endif
+
+#define LOG_THIS BX_CPU_THIS_PTR
+
+#ifdef BX_USE_VMX
+
+//the evtchn fd for polling
+int evtchn_fd = -1;
+//the evtchn port for polling the notification, should be inputed as bochs's parameter
+u16 ioreq_port = 0;
+
+void *shared_page = NULL;
+
+//some functions to handle the io req packet
+
+//get the ioreq packets from share mem
+ioreq_t* bx_cpu_c::__get_ioreq(void)
+{
+ ioreq_t *req;
+ req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+ if (req->state == STATE_IOREQ_READY) {
+ req->state = STATE_IOREQ_INPROCESS;
+ } else {
+ BX_INFO(("False I/O requrest ... in-service already: %lx, pvalid: %lx,port: %lx, data: %lx, count: %lx, size: %lx\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size));
+ req = NULL;
+ }
+
+ return req;
+}
+
+//use poll to get the port notification
+//ioreq_vec--out,the
+//retval--the number of ioreq packet
+ioreq_t* bx_cpu_c::get_ioreq(void)
+{
+ ioreq_t *req;
+ int rc;
+ u16 buf[2];
+ rc = read(evtchn_fd, buf, 2);
+ if (rc == 2 && buf[0] == ioreq_port){//got only one matched 16bit port index
+ // unmask the wanted port again
+ write(evtchn_fd, &ioreq_port, 2);
+
+ //get the io packet from shared memory
+ return __get_ioreq();
+ }
+
+ //read error or read nothing
+ return NULL;
+}
+
+//send the ioreq to device model
+void bx_cpu_c::dispatch_ioreq(ioreq_t *req)
+{
+ int ret, i;
+ int sign;
+
+ sign = (req->df) ? -1 : 1;
+
+ if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) {
+ if (req->size != 4) {
+ // Bochs expects higher bits to be 0
+ req->u.data &= (1UL << (8 * req->size))-1;
+ }
+ }
+ if (req->port_mm == 0){//port io
+ if(req->dir == IOREQ_READ){//read
+ if (!req->pdata_valid)
+ req->u.data = BX_INP(req->addr, req->size);
+ else {
+ unsigned long tmp;
+
+ for (i = 0; i < req->count; i++) {
+ tmp = BX_INP(req->addr, req->size);
+ BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size),
+ req->size, &tmp);
+ }
+ }
+ } else if(req->dir == IOREQ_WRITE) {
+ if (!req->pdata_valid) {
+ BX_OUTP(req->addr, (Bit32u) req->u.data, req->size);
+ } else {
+ for (i = 0; i < req->count; i++) {
+ unsigned long tmp;
+
+ BX_MEM_READ_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size), req->size,
+ &tmp);
+ BX_OUTP(req->addr, (Bit32u) tmp, req->size);
+ }
+ }
+
+ }
+ } else if (req->port_mm == 1){//memory map io
+ if (!req->pdata_valid) {
+ if(req->dir == IOREQ_READ){//read
+ BX_MEM_READ_PHYSICAL(req->addr, req->size, &req->u.data);
+ } else if(req->dir == IOREQ_WRITE)//write
+ BX_MEM_WRITE_PHYSICAL(req->addr, req->size, &req->u.data);
+ } else {
+ //handle movs
+ unsigned long tmp;
+ if (req->dir == IOREQ_READ) {
+ //BX_INFO(("<READ>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
+ for (i = 0; i < req->count; i++) {
+ BX_MEM_READ_PHYSICAL(req->addr + (sign * i * req->size), req->size, &tmp);
+ BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (sign * i * req->size), req->size, &tmp);
+ }
+ } else if (req->dir == IOREQ_WRITE) {
+ //BX_INFO(("<WRITE>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
+ for (i = 0; i < req->count; i++) {
+ BX_MEM_READ_PHYSICAL((Bit32u)req->u.pdata + (sign * i * req->size), req->size, &tmp);
+ BX_MEM_WRITE_PHYSICAL(req->addr + (sign * i * req->size), req->size, &tmp);
+ }
+ }
+ }
+ }
+
+ /* No state change if state = STATE_IORESP_HOOK */
+ if (req->state == STATE_IOREQ_INPROCESS)
+ req->state = STATE_IORESP_READY;
+
+ send_event = 1;
+}
+
+void
+bx_cpu_c::handle_ioreq(void)
+{
+ ioreq_t *req = get_ioreq();
+ if (req)
+ dispatch_ioreq(req);
+}
+
+void
+bx_cpu_c::timer_handler(void)
+{
+ handle_ioreq();
+}
+
+#endif
+
+#define rdtscl(low) \
+ __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
+
+void
+bx_cpu_c::cpu_loop(int max_instr_count)
+{
+ Bit8u vector;
+ fd_set rfds;
+ unsigned long stime_usec;
+ struct timeval tv;
+ int retval;
+
+ /* Watch stdin (fd 0) to see when it has input. */
+ FD_ZERO(&rfds);
+
+ while (1) {
+ static unsigned long long t1 = 0;
+ unsigned long long t2;
+
+ /* Wait up to one seconds. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ FD_SET(evtchn_fd, &rfds);
+
+ send_event = 0;
+
+ if (t1 == 0) // the first time
+ rdtscll(t1);
+
+ retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
+ if (retval == -1) {
+ perror("select");
+ return;
+ }
+
+ rdtscll(t2);
+
+#if __WORDSIZE == 32
+#define ULONGLONG_MAX 0xffffffffffffffffULL
+#else
+#define ULONGLONG_MAX ULONG_MAX
+#endif
+
+ if (t2 <= t1)
+ BX_TICKN((t2 + ULONGLONG_MAX - t1) / tsc_per_bx_tick);
+ else
+ BX_TICKN((t2 - t1) / tsc_per_bx_tick);
+ t1 = t2;
+
+ timer_handler();
+ if (BX_CPU_INTR) {
+#if BX_SUPPORT_APIC
+ if (BX_CPU_THIS_PTR local_apic.INTR)
+ vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
+ else
+ vector = DEV_pic_iac(); // may set INTR with next interrupt
+#else
+ // if no local APIC, always acknowledge the PIC.
+ vector = DEV_pic_iac(); // may set INTR with next interrupt
+#endif
+ interrupt(vector);
+ }
+ /* we check DMA after interrupt check*/
+ while(BX_HRQ){
+ DEV_dma_raise_hlda();
+ }
+
+ if (send_event) {
+ int ret;
+ ret = xc_evtchn_send(xc_handle, ioreq_port);
+ if (ret == -1) {
+ BX_ERROR(("evtchn_send failed on port: %d\n", ioreq_port));
+ }
+ }
+ }
+}
+
+static __inline__ void set_bit(long nr, volatile void *addr)
+{
+ __asm__ __volatile__( "lock ; "
+ "btsl %1,%0"
+ :"=m" ((*(volatile long *)addr))
+ :"Ir" (nr));
+
+ return;
+}
+
+void
+bx_cpu_c::interrupt(Bit8u vector)
+{
+ unsigned long *intr, tscl;
+ int ret;
+
+ // Send a message on the event channel. Add the vector to the shared mem
+ // page.
+
+ rdtscl(tscl);
+ BX_DEBUG(("%lx: injecting vector: %x\n", tscl, vector));
+ intr = &(((vcpu_iodata_t *) shared_page)->vp_intr[0]);
+ set_bit(vector, intr);
+
+ send_event = 1;
+}
+
+void
+bx_cpu_c::init(bx_mem_c*)
+{
+#ifdef BX_USE_VMX
+ if (evtchn_fd != -1)//the evtchn has been opened by another cpu object
+ return;
+
+ //use nonblock reading not polling, may change in future.
+ evtchn_fd = open("/dev/xen/evtchn", O_RDWR|O_NONBLOCK);
+ if (evtchn_fd == -1) {
+ perror("open");
+ return;
+ }
+
+ BX_INFO(("listening to port: %d\n", ioreq_port));
+ /*unmask the wanted port -- bind*/
+ if (ioctl(evtchn_fd, ('E'<<8)|2, ioreq_port) == -1) {
+ perror("ioctl");
+ return;
+ }
+
+#if 0
+ //register the reading evtchn function as timer
+ bx_pc_system.register_timer(this, timer_handler, 1000,//1000 us, may change
+ 1,//continuous timer
+ 1,//active
+ "cpu reading evtchn handler");
+#endif
+
+#endif
+}
+
+void
+bx_cpu_c::reset(unsigned)
+{
+}
+
+void
+bx_cpu_c::atexit()
+{
+}
+
+void
+bx_cpu_c::set_INTR(unsigned value)
+{
+ BX_CPU_THIS_PTR INTR = value;
+}
+
+void
+bx_cpu_c::pagingA20Changed()
+{
+}
+
+bx_cpu_c::bx_cpu_c()
+{
+}
+
+bx_cpu_c::~bx_cpu_c()
+{
+}
diff --git a/tools/ioemu/iodev/crc32.cc b/tools/ioemu/iodev/crc32.cc
new file mode 100644
index 0000000000..a20abaaf82
--- /dev/null
+++ b/tools/ioemu/iodev/crc32.cc
@@ -0,0 +1,49 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: crc32.cc,v 1.4 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* 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;
+}
+
diff --git a/tools/ioemu/iodev/crc32.h b/tools/ioemu/iodev/crc32.h
new file mode 100644
index 0000000000..faedaf840b
--- /dev/null
+++ b/tools/ioemu/iodev/crc32.h
@@ -0,0 +1,25 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: crc32.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* CRC-32 calculator
+ * Adapted from http://www.createwindow.org/programming/crc32/
+ */
+
+#ifndef _CRC_32_H_
+#define _CRC_32_H_
+
+#include "bochs.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_
+
diff --git a/tools/ioemu/iodev/devices.cc b/tools/ioemu/iodev/devices.cc
new file mode 100644
index 0000000000..5dd7f5daa3
--- /dev/null
+++ b/tools/ioemu/iodev/devices.cc
@@ -0,0 +1,685 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#include "bochs.h"
+#define LOG_THIS bx_devices.
+
+
+
+/* main memory size (in Kbytes)
+ * subtract 1k for extended BIOS area
+ * report only base memory, not extended mem
+ */
+#define BASE_MEMORY_IN_K 640
+
+
+bx_devices_c bx_devices;
+
+
+
+
+// constructor for bx_devices_c
+bx_devices_c::bx_devices_c(void)
+{
+ put("DEV");
+ settype(DEVLOG);
+
+#if BX_PCI_SUPPORT
+ pluginPciBridge = &stubPci;
+ pluginPci2IsaBridge = NULL;
+#if BX_PCI_VGA_SUPPORT
+ pluginPciVgaAdapter = NULL;
+#endif
+#if BX_PCI_USB_SUPPORT
+ pluginPciUSBAdapter = NULL;
+#endif
+#endif
+ pit = NULL;
+ pluginKeyboard = &stubKeyboard;
+ pluginDmaDevice = &stubDma;
+ pluginFloppyDevice = &stubFloppy;
+ pluginBiosDevice = NULL;
+ pluginCmosDevice = &stubCmos;
+ pluginSerialDevice = NULL;
+ pluginParallelDevice = NULL;
+ pluginUnmapped = NULL;
+ pluginVgaDevice = &stubVga;
+ pluginPicDevice = &stubPic;
+ pluginHardDrive = &stubHardDrive;
+ pluginSB16Device = NULL;
+ pluginNE2kDevice =&stubNE2k;
+ pluginExtFpuIrq = NULL;
+ pluginGameport = NULL;
+ g2h = NULL;
+#if BX_IODEBUG_SUPPORT
+ iodebug = NULL;
+#endif
+}
+
+
+bx_devices_c::~bx_devices_c(void)
+{
+ // nothing needed for now
+ BX_DEBUG(("Exit."));
+ timer_handle = BX_NULL_TIMER_HANDLE;
+}
+
+
+ void
+bx_devices_c::init(BX_MEM_C *newmem)
+{
+ unsigned i;
+
+ BX_DEBUG(("Init $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $"));
+ mem = newmem;
+
+ /* no read / write handlers defined */
+ num_read_handles = 0;
+ num_write_handles = 0;
+
+ /* set unused elements to appropriate values */
+ for (i=0; i < BX_MAX_IO_DEVICES; i++) {
+ io_read_handler[i].funct = NULL;
+ io_write_handler[i].funct = NULL;
+ }
+
+ /* set no-default handlers, will be overwritten by the real default handler */
+ io_read_handler[BX_DEFAULT_IO_DEVICE].handler_name = "Default";
+ io_read_handler[BX_DEFAULT_IO_DEVICE].funct = &default_read_handler;
+ io_read_handler[BX_DEFAULT_IO_DEVICE].this_ptr = NULL;
+ io_read_handler[BX_DEFAULT_IO_DEVICE].mask = 7;
+ io_write_handler[BX_DEFAULT_IO_DEVICE].handler_name = "Default";
+ io_write_handler[BX_DEFAULT_IO_DEVICE].funct = &default_write_handler;
+ io_write_handler[BX_DEFAULT_IO_DEVICE].this_ptr = NULL;
+ io_write_handler[BX_DEFAULT_IO_DEVICE].mask = 7;
+
+ /* set handlers to the default one */
+ for (i=0; i < 0x10000; i++) {
+ read_handler_id[i] = BX_DEFAULT_IO_DEVICE;
+ write_handler_id[i] = BX_DEFAULT_IO_DEVICE;
+ }
+
+ for (i=0; i < BX_MAX_IRQS; i++) {
+ irq_handler_name[i] = NULL;
+ }
+
+ // BBD: At present, the only difference between "core" and "optional"
+ // plugins is that initialization and reset of optional plugins is handled
+ // by the plugin device list (). Init and reset of core plugins is done
+ // "by hand" in this file. Basically, we're using core plugins when we
+ // want to control the init order.
+ //
+ // CB: UNMAPPED and BIOSDEV should maybe be optional
+ PLUG_load_plugin(unmapped, PLUGTYPE_CORE);
+ PLUG_load_plugin(biosdev, PLUGTYPE_CORE);
+ PLUG_load_plugin(cmos, PLUGTYPE_CORE);
+ PLUG_load_plugin(dma, PLUGTYPE_CORE);
+ PLUG_load_plugin(pic, PLUGTYPE_CORE);
+ PLUG_load_plugin(vga, PLUGTYPE_CORE);
+ PLUG_load_plugin(floppy, PLUGTYPE_CORE);
+ PLUG_load_plugin(harddrv, PLUGTYPE_OPTIONAL);
+ PLUG_load_plugin(keyboard, PLUGTYPE_OPTIONAL);
+ if (is_serial_enabled ())
+ PLUG_load_plugin(serial, PLUGTYPE_OPTIONAL);
+ if (is_parallel_enabled ())
+ PLUG_load_plugin(parallel, PLUGTYPE_OPTIONAL);
+ PLUG_load_plugin(extfpuirq, PLUGTYPE_OPTIONAL);
+#if BX_SUPPORT_GAME
+ PLUG_load_plugin(gameport, PLUGTYPE_OPTIONAL);
+#endif
+
+ // Start with registering the default (unmapped) handler
+ pluginUnmapped->init ();
+
+ // PCI logic (i440FX)
+ if (bx_options.Oi440FXSupport->get ()) {
+#if BX_PCI_SUPPORT
+ PLUG_load_plugin(pci, PLUGTYPE_OPTIONAL);
+ PLUG_load_plugin(pci2isa, PLUGTYPE_OPTIONAL);
+#if BX_PCI_VGA_SUPPORT
+ PLUG_load_plugin(pcivga, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_PCI_USB_SUPPORT
+ PLUG_load_plugin(pciusb, PLUGTYPE_OPTIONAL);
+#endif
+#else
+ BX_ERROR(("Bochs is not compiled with PCI support"));
+#endif
+ }
+
+#if BX_SUPPORT_APIC
+ // I/O APIC 82093AA
+ ioapic = & bx_ioapic;
+ ioapic->init ();
+#endif
+
+ // BIOS log
+ pluginBiosDevice->init ();
+
+ // CMOS RAM & RTC
+ pluginCmosDevice->init ();
+
+ /*--- 8237 DMA ---*/
+ pluginDmaDevice->init();
+
+ //--- FLOPPY ---
+ pluginFloppyDevice->init();
+
+ //--- SOUND ---
+ if (bx_options.sb16.Opresent->get ()) {
+#if BX_SUPPORT_SB16
+ PLUG_load_plugin(sb16, PLUGTYPE_OPTIONAL);
+#else
+ BX_ERROR(("Bochs is not compiled with SB16 support"));
+#endif
+ }
+
+ /*--- VGA adapter ---*/
+ pluginVgaDevice->init ();
+
+ /*--- 8259A PIC ---*/
+ pluginPicDevice->init();
+
+ /*--- 8254 PIT ---*/
+ pit = & bx_pit;
+ pit->init();
+
+ bx_virt_timer.init();
+
+ bx_slowdown_timer.init();
+
+#if BX_IODEBUG_SUPPORT
+ iodebug = &bx_iodebug;
+ iodebug->init();
+#endif
+
+ // NE2000 NIC
+ if (bx_options.ne2k.Opresent->get ()) {
+#if BX_NE2K_SUPPORT
+ PLUG_load_plugin(ne2k, PLUGTYPE_OPTIONAL);
+#else
+ BX_ERROR(("Bochs is not compiled with NE2K support"));
+#endif
+ }
+
+#if 0
+ // Guest to Host interface. Used with special guest drivers
+ // which move data to/from the host environment.
+ g2h = &bx_g2h;
+ g2h->init();
+#endif
+
+ // system hardware
+ register_io_read_handler( this,
+ &read_handler,
+ 0x0092,
+ "Port 92h System Control", 1 );
+ register_io_write_handler(this,
+ &write_handler,
+ 0x0092,
+ "Port 92h System Control", 1 );
+
+ // misc. CMOS
+ Bit32u extended_memory_in_k = mem->get_memory_in_k() > 1024 ? (mem->get_memory_in_k() - 1024) : 0;
+ if (extended_memory_in_k > 0xffff) extended_memory_in_k = 0xffff;
+
+ DEV_cmos_set_reg(0x15, (Bit8u) BASE_MEMORY_IN_K);
+ DEV_cmos_set_reg(0x16, (Bit8u) (BASE_MEMORY_IN_K >> 8));
+ DEV_cmos_set_reg(0x17, (Bit8u) (extended_memory_in_k & 0xff) );
+ DEV_cmos_set_reg(0x18, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) );
+ DEV_cmos_set_reg(0x30, (Bit8u) (extended_memory_in_k & 0xff) );
+ DEV_cmos_set_reg(0x31, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) );
+
+ Bit32u extended_memory_in_64k = mem->get_memory_in_k() > 16384 ? (mem->get_memory_in_k() - 16384) / 64 : 0;
+ if (extended_memory_in_64k > 0xffff) extended_memory_in_64k = 0xffff;
+
+ DEV_cmos_set_reg(0x34, (Bit8u) (extended_memory_in_64k & 0xff) );
+ DEV_cmos_set_reg(0x35, (Bit8u) ((extended_memory_in_64k >> 8) & 0xff) );
+
+ if (timer_handle != BX_NULL_TIMER_HANDLE) {
+ timer_handle = bx_pc_system.register_timer( this, timer_handler,
+ (unsigned) BX_IODEV_HANDLER_PERIOD, 1, 1, "devices.cc");
+ }
+
+ // Clear fields for bulk IO acceleration transfers.
+ bulkIOHostAddr = 0;
+ bulkIOQuantumsRequested = 0;
+ bulkIOQuantumsTransferred = 0;
+
+ bx_init_plugins();
+
+ /* now perform checksum of CMOS memory */
+ DEV_cmos_checksum();
+}
+
+
+ void
+bx_devices_c::reset(unsigned type)
+{
+ pluginUnmapped->reset(type);
+#if BX_PCI_SUPPORT
+ if (bx_options.Oi440FXSupport->get ()) {
+ pluginPciBridge->reset(type);
+ pluginPci2IsaBridge->reset(type);
+#if BX_PCI_VGA_SUPPORT
+ pluginPciVgaAdapter->reset(type);
+#endif
+#if BX_PCI_USB_SUPPORT
+ pluginPciUSBAdapter->reset(type);
+#endif
+ }
+#endif
+#if BX_SUPPORT_IOAPIC
+ ioapic->reset (type);
+#endif
+ pluginBiosDevice->reset(type);
+ pluginCmosDevice->reset(type);
+ pluginDmaDevice->reset(type);
+ pluginFloppyDevice->reset(type);
+#if BX_SUPPORT_SB16
+ if (pluginSB16Device) pluginSB16Device->reset(type);
+#endif
+ pluginVgaDevice->reset(type);
+ pluginPicDevice->reset(type);
+ pit->reset(type);
+ bx_slowdown_timer.reset(type);
+#if BX_IODEBUG_SUPPORT
+ iodebug->reset(type);
+#endif
+#if BX_NE2K_SUPPORT
+ if (pluginNE2kDevice) pluginNE2kDevice->reset(type);
+#endif
+
+ bx_reset_plugins(type);
+}
+
+
+ Bit32u
+bx_devices_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_DEV_SMF
+ bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+ return( class_ptr->port92_read(address, io_len) );
+}
+
+
+ Bit32u
+bx_devices_c::port92_read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_DEV_SMF
+
+ BX_DEBUG(("port92h read partially supported!!!"));
+ BX_DEBUG((" returning %02x", (unsigned) (BX_GET_ENABLE_A20() << 1)));
+ return(BX_GET_ENABLE_A20() << 1);
+}
+
+
+ void
+bx_devices_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_DEV_SMF
+ bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+ class_ptr->port92_write(address, value, io_len);
+}
+
+ void
+bx_devices_c::port92_write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_DEV_SMF
+ bx_bool bx_cpu_reset;
+
+ BX_DEBUG(("port92h write of %02x partially supported!!!",
+ (unsigned) value));
+ BX_DEBUG(("A20: set_enable_a20() called"));
+ BX_SET_ENABLE_A20( (value & 0x02) >> 1 );
+ BX_DEBUG(("A20: now %u", (unsigned) BX_GET_ENABLE_A20()));
+ bx_cpu_reset = (value & 0x01); /* high speed reset */
+ if (bx_cpu_reset) {
+ BX_PANIC(("PORT 92h write: CPU reset requested!"));
+ }
+}
+
+
+// This defines a no-default read handler,
+// so Bochs does not segfault if unmapped is not loaded
+ Bit32u
+bx_devices_c::default_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+ UNUSED(this_ptr);
+ BX_PANIC(("No default io-read handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len));
+ return 0xffffffff;
+}
+
+// This defines a no-default write handler,
+// so Bochs does not segfault if unmapped is not loaded
+ void
+bx_devices_c::default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+ UNUSED(this_ptr);
+ BX_PANIC(("No default io-write handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len));
+}
+
+ void
+bx_devices_c::timer_handler(void *this_ptr)
+{
+ bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+ class_ptr->timer();
+}
+
+ void
+bx_devices_c::timer()
+{
+#if (BX_USE_NEW_PIT==0)
+ if ( pit->periodic( BX_IODEV_HANDLER_PERIOD ) ) {
+ // This is a hack to make the IRQ0 work
+ DEV_pic_lower_irq(0);
+ DEV_pic_raise_irq(0);
+ }
+#endif
+
+
+ // separate calls to bx_gui->handle_events from the keyboard code.
+ {
+ static int multiple=0;
+ if ( ++multiple==10)
+ {
+ multiple=0;
+ SIM->periodic ();
+ if (!BX_CPU(0)->kill_bochs_request)
+ bx_gui->handle_events();
+ }
+ }
+
+// KPL Removed lapic periodic timer registration here.
+}
+
+
+ bx_bool
+bx_devices_c::register_irq(unsigned irq, const char *name)
+{
+ if (irq >= BX_MAX_IRQS) {
+ BX_PANIC(("IO device %s registered with IRQ=%d above %u",
+ name, irq, (unsigned) BX_MAX_IRQS-1));
+ return false;
+ }
+ if (irq_handler_name[irq]) {
+ BX_PANIC(("IRQ %u conflict, %s with %s", irq,
+ irq_handler_name[irq], name));
+ return false;
+ }
+ irq_handler_name[irq] = name;
+ return true;
+}
+
+ bx_bool
+bx_devices_c::unregister_irq(unsigned irq, const char *name)
+{
+ if (irq >= BX_MAX_IRQS) {
+ BX_PANIC(("IO device %s tried to unregister IRQ %d above %u",
+ name, irq, (unsigned) BX_MAX_IRQS-1));
+ return false;
+ }
+
+ if (!irq_handler_name[irq]) {
+ BX_INFO(("IO device %s tried to unregister IRQ %d, not registered",
+ name, irq));
+ return false;
+ }
+
+ if (strcmp(irq_handler_name[irq], name)) {
+ BX_INFO(("IRQ %u not registered to %s but to %s", irq,
+ name, irq_handler_name[irq]));
+ return false;
+ }
+ irq_handler_name[irq] = NULL;
+ return true;
+}
+
+ bx_bool
+bx_devices_c::register_io_read_handler( void *this_ptr, bx_read_handler_t f,
+ Bit32u addr, const char *name, Bit8u mask )
+{
+ unsigned handle;
+
+ addr &= 0x0000ffff;
+
+ /* first find existing handle for function or create new one */
+ for (handle=0; handle < num_read_handles; handle++) {
+ if ((io_read_handler[handle].funct == f) &&
+ (io_read_handler[handle].mask == mask)) break;
+ }
+
+ if (handle >= num_read_handles) {
+ /* no existing handle found, create new one */
+ if (num_read_handles >= BX_DEFAULT_IO_DEVICE) {
+ BX_INFO(("too many IO devices installed."));
+ BX_PANIC((" try increasing BX_MAX_IO_DEVICES"));
+ }
+ num_read_handles++;
+ io_read_handler[handle].funct = f;
+ io_read_handler[handle].this_ptr = this_ptr;
+ io_read_handler[handle].handler_name = name;
+ io_read_handler[handle].mask = mask;
+ }
+
+ /* change table to reflect new handler id for that address */
+ if (read_handler_id[addr] < BX_DEFAULT_IO_DEVICE) {
+ // another handler is already registered for that address
+ BX_ERROR(("IO device address conflict(read) at IO address %Xh",
+ (unsigned) addr));
+ BX_ERROR((" conflicting devices: %s & %s",
+ io_read_handler[handle].handler_name, io_read_handler[read_handler_id[addr]].handler_name));
+ return false; // address not available, return false.
+ }
+ read_handler_id[addr] = handle;
+ return true; // address mapped successfully
+}
+
+
+
+ bx_bool
+bx_devices_c::register_io_write_handler( void *this_ptr, bx_write_handler_t f,
+ Bit32u addr, const char *name, Bit8u mask )
+{
+ unsigned handle;
+
+ addr &= 0x0000ffff;
+
+ /* first find existing handle for function or create new one */
+ for (handle=0; handle < num_write_handles; handle++) {
+ if ((io_write_handler[handle].funct == f) &&
+ (io_write_handler[handle].mask == mask)) break;
+ }
+
+ if (handle >= num_write_handles) {
+ /* no existing handle found, create new one */
+ if (num_write_handles >= BX_DEFAULT_IO_DEVICE) {
+ BX_INFO(("too many IO devices installed."));
+ BX_PANIC((" try increasing BX_MAX_IO_DEVICES"));
+ }
+ num_write_handles++;
+ io_write_handler[handle].funct = f;
+ io_write_handler[handle].this_ptr = this_ptr;
+ io_write_handler[handle].handler_name = name;
+ io_write_handler[handle].mask = mask;
+ }
+
+ /* change table to reflect new handler id for that address */
+ if (write_handler_id[addr] < BX_DEFAULT_IO_DEVICE) {
+ // another handler is already registered for that address
+ BX_ERROR(("IO device address conflict(write) at IO address %Xh",
+ (unsigned) addr));
+ BX_ERROR((" conflicting devices: %s & %s",
+ io_write_handler[handle].handler_name, io_write_handler[write_handler_id[addr]].handler_name));
+ return false; //unable to map iodevice.
+ }
+ write_handler_id[addr] = handle;
+ return true; // done!
+}
+
+
+// Registration of default handlers (mainly be the unmapped device)
+// The trick here is to define a handler for the max index, so
+// unregisterd io address will get handled by the default function
+// This will be helpful when we want to unregister io handlers
+
+ bx_bool
+bx_devices_c::register_default_io_read_handler( void *this_ptr, bx_read_handler_t f,
+ const char *name, Bit8u mask )
+{
+ unsigned handle;
+
+ /* handle is fixed to the default I/O device */
+ handle = BX_DEFAULT_IO_DEVICE;
+
+ if (strcmp(io_read_handler[handle].handler_name, "Default")) {
+ BX_ERROR(("Default io read handler already registered '%s'",io_read_handler[handle].handler_name));
+ return false;
+ }
+
+ io_read_handler[handle].funct = f;
+ io_read_handler[handle].this_ptr = this_ptr;
+ io_read_handler[handle].handler_name = name;
+ io_read_handler[handle].mask = mask;
+
+ return true;
+}
+
+
+
+ bx_bool
+bx_devices_c::register_default_io_write_handler( void *this_ptr, bx_write_handler_t f,
+ const char *name, Bit8u mask )
+{
+ unsigned handle;
+
+ /* handle is fixed to the MAX */
+ handle = BX_DEFAULT_IO_DEVICE;
+
+ if (strcmp(io_write_handler[handle].handler_name, "Default")) {
+ BX_ERROR(("Default io write handler already registered '%s'",io_write_handler[handle].handler_name));
+ return false;
+ }
+
+ io_write_handler[handle].funct = f;
+ io_write_handler[handle].this_ptr = this_ptr;
+ io_write_handler[handle].handler_name = name;
+ io_write_handler[handle].mask = mask;
+
+ return true;
+}
+
+
+
+/*
+ * Read a byte of data from the IO memory address space
+ */
+
+ Bit32u BX_CPP_AttrRegparmN(2)
+bx_devices_c::inp(Bit16u addr, unsigned io_len)
+{
+ Bit8u handle;
+ Bit32u ret;
+
+ BX_INSTR_INP(addr, io_len);
+
+ handle = read_handler_id[addr];
+ if ((io_read_handler[handle].funct != NULL) &&
+ (io_read_handler[handle].mask & io_len)) {
+ ret = (* io_read_handler[handle].funct)(io_read_handler[handle].this_ptr,
+ (Bit32u) addr, io_len);
+ } else {
+ switch (io_len) {
+ case 1: ret = 0xff; break;
+ case 2: ret = 0xffff; break;
+ default: ret = 0xffffffff; break;
+ }
+ BX_ERROR(("read from port 0x%04x with len %d returns 0x%x", addr, io_len, ret));
+ }
+ BX_INSTR_INP2(addr, io_len, ret);
+ BX_DBG_IO_REPORT(addr, io_len, BX_READ, ret);
+
+ return(ret);
+}
+
+
+/*
+ * Write a byte of data to the IO memory address space.
+ */
+
+ void BX_CPP_AttrRegparmN(3)
+bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned io_len)
+{
+ Bit8u handle;
+
+ BX_INSTR_OUTP(addr, io_len);
+ BX_INSTR_OUTP2(addr, io_len, value);
+
+ BX_DBG_IO_REPORT(addr, io_len, BX_WRITE, value);
+ handle = write_handler_id[addr];
+ if ((io_write_handler[handle].funct != NULL) &&
+ (io_write_handler[handle].mask & io_len)) {
+ (* io_write_handler[handle].funct)(io_write_handler[handle].this_ptr,
+ (Bit32u) addr, value, io_len);
+ } else {
+ BX_ERROR(("write to port 0x%04x with len %d ignored", addr, io_len));
+ }
+}
+
+bx_bool bx_devices_c::is_serial_enabled ()
+{
+ for (int i=0; i<BX_N_SERIAL_PORTS; i++) {
+ if (SIM->get_param_bool (BXP_COMx_ENABLED(i+1))->get())
+ return true;
+ }
+ return false;
+}
+
+bx_bool bx_devices_c::is_usb_enabled ()
+{
+ for (int i=0; i<BX_N_USB_HUBS; i++) {
+ if (SIM->get_param_bool (BXP_USBx_ENABLED(i+1))->get())
+ return true;
+ }
+ return false;
+}
+
+bx_bool bx_devices_c::is_parallel_enabled ()
+{
+ for (int i=0; i<BX_N_PARALLEL_PORTS; i++) {
+ if (SIM->get_param_bool (BXP_PARPORTx_ENABLED(i+1))->get())
+ return true;
+ }
+ return false;
+}
diff --git a/tools/ioemu/iodev/dma.cc b/tools/ioemu/iodev/dma.cc
new file mode 100644
index 0000000000..afe0238a92
--- /dev/null
+++ b/tools/ioemu/iodev/dma.cc
@@ -0,0 +1,825 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: dma.cc,v 1.30 2003/07/31 15:29:34 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// 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"
+
+#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)
+{
+}
+
+bx_dma_c::bx_dma_c(void)
+{
+ put("DMA");
+ settype(DMALOG);
+}
+
+bx_dma_c::~bx_dma_c(void)
+{
+ 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: dma.cc,v 1.30 2003/07/31 15:29:34 vruppert Exp $"));
+
+ /* 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);
+ }
+
+ // 00081..008F
+ for (i=0x0081; 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;
+ }
+ }
+ BX_DMA_THIS s[1].chan[0].used = 1; // cascade channel in use
+ BX_INFO(("channel 4 used by cascade"));
+ bios_init();
+}
+
+/* Remove it when guest fw ready*/
+ void
+bx_dma_c::bios_init(void){
+ BX_DMA_THIS s[1].mask[0] = 0; // unmask cascade channel
+ BX_DMA_THIS s[1].chan[0].mode.mode_type = 3; // cascade mode for channel 4
+}
+
+ void
+bx_dma_c::reset(unsigned type)
+{
+ reset_controller(0);
+ reset_controller(1);
+ bios_init();
+}
+
+ 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].command_reg = 0;
+ BX_DMA_THIS s[num].status_reg = 0;
+ BX_DMA_THIS s[num].request_reg = 0;
+ BX_DMA_THIS s[num].temporary_reg = 0;
+ BX_DMA_THIS s[num].flip_flop = 0;
+}
+
+ // 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_bool ma_sl;
+
+ 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
+
+ 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 */
+ ma_sl = (address >= 0xc0);
+ 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 */
+ ma_sl = (address >= 0xc2);
+ 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)
+ ma_sl = (address == 0xd0);
+ retval = BX_DMA_THIS s[ma_sl].status_reg;
+ BX_DMA_THIS s[ma_sl].status_reg &= 0xf0;
+ return(retval);
+ break;
+ case 0x0d: // DMA-1: temporary register
+ case 0xda: // DMA-2: temporary register
+ ma_sl = (address == 0xda);
+ BX_ERROR(("DMA-%d: read of temporary register", ma_sl+1));
+ // Note: write to 0x0D clears temporary register
+ return(0);
+ break;
+
+ 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 0x0084:
+ case 0x0085:
+ case 0x0086:
+ case 0x0088:
+ case 0x008c:
+ case 0x008d:
+ case 0x008e:
+ BX_DEBUG(("read: extra page register 0x%04x unsupported", (unsigned) address));
+ return(0);
+
+ 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;
+ bx_bool ma_sl;
+
+ 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
+
+ switch (address) {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0xc0:
+ case 0xc4:
+ case 0xc8:
+ case 0xcc:
+ ma_sl = (address >= 0xc0);
+ 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;
+ return;
+ break;
+
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0xc2:
+ case 0xc6:
+ case 0xca:
+ case 0xce:
+ ma_sl = (address >= 0xc2);
+ 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;
+ return;
+ break;
+
+ case 0x08: /* DMA-1: command register */
+ case 0xd0: /* DMA-2: command register */
+ ma_sl = (address == 0xd0);
+ if (value != 0x00)
+ BX_ERROR(("write to command register: value(%02xh) not 0x00",
+ (unsigned) value));
+ BX_DMA_THIS s[ma_sl].command_reg = value;
+ return;
+ break;
+
+ case 0x09: // DMA-1: request register
+ case 0xd2: // DMA-2: request register
+ ma_sl = (address == 0xd2);
+ channel = value & 0x03;
+ BX_ERROR(("DMA-%d: write to request register (%02x)", ma_sl+1, (unsigned) value));
+ // note: write to 0x0d 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);
+ return;
+ break;
+
+ case 0x0a:
+ case 0xd4:
+ ma_sl = (address == 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);
+ return;
+ break;
+
+ case 0x0b: /* DMA-1 mode register */
+ case 0xd6: /* DMA-2 mode register */
+ ma_sl = (address == 0xd6);
+ 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));
+ return;
+ break;
+
+ case 0x0c: /* DMA-1 clear byte flip/flop */
+ case 0xd8: /* DMA-2 clear byte flip/flop */
+ ma_sl = (address == 0xd8);
+ BX_DEBUG(("DMA-%d: clear flip/flop", ma_sl+1));
+ BX_DMA_THIS s[ma_sl].flip_flop = 0;
+ return;
+ break;
+
+ case 0x0d: // DMA-1: master clear
+ case 0xda: // DMA-2: master clear
+ ma_sl = (address == 0xda);
+ 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);
+ return;
+ break;
+
+ case 0x0e: // DMA-1: clear mask register
+ case 0xdc: // DMA-2: clear mask register
+ ma_sl = (address == 0xdc);
+ 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);
+ return;
+ break;
+
+ case 0x0f: // DMA-1: write all mask bits
+ case 0xde: // DMA-2: write all mask bits
+ ma_sl = (address == 0xde);
+ 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);
+ return;
+ 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));
+ return;
+ 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));
+ return;
+ break;
+
+ case 0x0084:
+ case 0x0085:
+ case 0x0086:
+ case 0x0088:
+ case 0x008c:
+ case 0x008d:
+ case 0x008e:
+ BX_DEBUG(("write: extra page register 0x%04x unsupported", (unsigned) address));
+ return;
+ 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;
+
+ // 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;
+ Bit32u 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));
+
+ BX_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));
+
+ BX_MEM_WRITE_PHYSICAL(phy_addr, 2, &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) {
+ BX_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 {
+ BX_MEM_READ_PHYSICAL(phy_addr, 2, &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
+ }
+ }
+}
diff --git a/tools/ioemu/iodev/dma.h b/tools/ioemu/iodev/dma.h
new file mode 100644
index 0000000000..9f6c4eb60e
--- /dev/null
+++ b/tools/ioemu/iodev/dma.h
@@ -0,0 +1,114 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: dma.h,v 1.15 2003/05/03 07:41:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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();
+ ~bx_dma_c(void);
+
+ virtual void init(void);
+ virtual void bios_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 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;
+ Bit8u request_reg;
+ Bit8u temporary_reg;
+ 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
+
+ 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
diff --git a/tools/ioemu/iodev/eth.cc b/tools/ioemu/iodev/eth.cc
new file mode 100644
index 0000000000..d6ee9d2948
--- /dev/null
+++ b/tools/ioemu/iodev/eth.cc
@@ -0,0 +1,194 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth.cc,v 1.16 2003/04/28 13:01:09 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#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
+#ifdef ETH_TEST
+extern bx_test_match;
+#endif
+#ifdef ETH_ARPBACK
+extern class bx_arpback_locator_c bx_arpback_match;
+#endif
+
+//
+// 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, void *rxarg)
+{
+#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, rxarg));
+ }
+#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_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
+#ifdef ETH_TEST
+ {
+ if (!strcmp(type, "test"))
+ ptr = (eth_locator_c *) &bx_test_match;
+ }
+#endif
+ if (ptr)
+ return (ptr->allocate(netif, macaddr, rxh, rxarg));
+#endif
+
+ return (NULL);
+}
+
+#if (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1)
+
+extern "C" {
+#include <sys/wait.h>
+};
+
+#undef LOG_THIS
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+// This is a utility script used for tuntap or ethertap
+int execute_script( 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
+ BX_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)
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth.h b/tools/ioemu/iodev/eth.h
new file mode 100644
index 0000000000..8ac8c6ff3e
--- /dev/null
+++ b/tools/ioemu/iodev/eth.h
@@ -0,0 +1,76 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth.h,v 1.12 2003/04/26 14:48:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+// eth.h - see eth_null.cc for implementation details
+
+typedef void (*eth_rx_handler_t)(void *arg, const void *buf, unsigned len);
+
+int execute_script(char *name, char* arg1);
+
+//
+// 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 (void) {}
+protected:
+ eth_rx_handler_t rxh; // receive callback
+ void *rxarg;
+};
+
+
+//
+// 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,
+ void *rxarg);
+protected:
+ eth_locator_c(const char *type);
+ virtual eth_pktmover_c *allocate(const char *netif,
+ const char *macaddr,
+ eth_rx_handler_t rxh,
+ void *rxarg) = 0;
+private:
+ static eth_locator_c *all;
+ eth_locator_c *next;
+ const char *type;
+};
+
diff --git a/tools/ioemu/iodev/eth_arpback.cc b/tools/ioemu/iodev/eth_arpback.cc
new file mode 100644
index 0000000000..0f30711dfb
--- /dev/null
+++ b/tools/ioemu/iodev/eth_arpback.cc
@@ -0,0 +1,214 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_arpback.cc,v 1.11 2002/11/20 19:06:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+
+#if BX_NE2K_SUPPORT && defined(ETH_ARPBACK)
+
+#include "crc32.h"
+#include "eth_packetmaker.h"
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+
+//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 broadcast_mac[]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
+//static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
+
+#define MAX_FRAME_SIZE 2048
+
+//
+// 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,
+ void *rxarg);
+ void sendpkt(void *buf, unsigned io_len);
+private:
+ int rx_timer_index;
+ static void rx_timer_handler(void *);
+ void rx_timer(void);
+ FILE *txlog, *txlog_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,
+ void *rxarg) {
+ return (new bx_arpback_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+ this->rx_timer_index =
+ bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
+ 1, 1, "eth_arpback"); // continuous, active
+ this->rxh = rxh;
+ this->rxarg = rxarg;
+ //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.
+ 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, "arpback 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_arpback_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+ if(io_len<MAX_FRAME_SIZE) {
+ 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_mac, 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, txlog);
+ if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
+ // dump packet in hex into an ascii log file
+ fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (txlog_txt, "\n");
+ fprintf (txlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (txlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (txlog);
+ fflush (txlog_txt);
+#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)
+{
+ int nbytes = 0;
+ struct bpf_hdr *bhdr;
+ eth_packet rubble;
+
+ if(packetmaker.getpacket(rubble)) {
+ //bufvalid=0;
+ void * buf=rubble.buf;
+ unsigned io_len=rubble.len;
+ Bit32u n;
+ fprintf (txlog_txt, "NE2K receiving a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (txlog_txt, "\n");
+ fprintf (txlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (txlog_txt, "\n--\n");
+ fflush (txlog_txt);
+
+ (*rxh)(rxarg, buf, io_len);
+ }
+}
+
+#endif /* if BX_NE2K_SUPPORT && defined(ETH_ARPBACK) */
+
diff --git a/tools/ioemu/iodev/eth_fbsd.cc b/tools/ioemu/iodev/eth_fbsd.cc
new file mode 100644
index 0000000000..0c24b9b828
--- /dev/null
+++ b/tools/ioemu/iodev/eth_fbsd.cc
@@ -0,0 +1,385 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_fbsd.cc,v 1.26 2002/11/20 19:06:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if BX_NE2K_SUPPORT && defined(ETH_FBSD)
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+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_BUFSIZ 2048 // enough for an ether frame + bpf hdr
+
+#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,
+ void *rxarg);
+ 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,
+ void *rxarg) {
+ return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+ char device[sizeof "/dev/bpf000"];
+ int tmpfd;
+ int n = 0;
+ struct ifreq ifr;
+ struct bpf_version bv;
+ struct bpf_program bp;
+ u_int v;
+
+ 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_BPF_BUFSIZ;
+ 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;
+ }
+
+ // 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;
+ this->rxarg = rxarg;
+
+#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
+ fprintf (ne2klog_txt, "NE2K TX packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (ne2klog_txt, "\n");
+ fprintf (ne2klog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (ne2klog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (ne2klog);
+ fflush (ne2klog_txt);
+#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_BPF_BUFSIZ];
+ 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)(rxarg, phdr + bhdr->bh_hdrlen, bhdr->bh_caplen);
+ }
+
+#if BX_ETH_FBSD_LOGGING
+ /// hey wait there is no receive data with a NULL ethernet, is there....
+ 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
+ fprintf (this->ne2klog_txt, "NE2K RX packet, length %u\n", bhdr->bh_caplen);
+ Bit8u *charrxbuf = (Bit8u *)rxbuf;
+ int n;
+ for (n=0; n<bhdr->bh_caplen; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (this->ne2klog_txt, "\n");
+ fprintf (this->ne2klog_txt, "%02x ", phdr[n]);
+ }
+ fprintf (this->ne2klog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (this->ne2klog);
+ fflush (this->ne2klog_txt);
+#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_NE2K_SUPPORT && defined(ETH_FBSD) */
+
diff --git a/tools/ioemu/iodev/eth_linux.cc b/tools/ioemu/iodev/eth_linux.cc
new file mode 100644
index 0000000000..ec5f1fee73
--- /dev/null
+++ b/tools/ioemu/iodev/eth_linux.cc
@@ -0,0 +1,286 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_linux.cc,v 1.14 2003/02/16 19:35:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if BX_NE2K_SUPPORT && defined (ETH_LINUX)
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+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
+
+#define BX_PACKET_BUFSIZ 2048 // Enough for an ether frame
+
+// 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,
+ void *rxarg);
+ 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,
+ void *rxarg) {
+ return (new bx_linux_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+ struct sockaddr_ll sll;
+ struct packet_mreq mr;
+ struct ifreq ifr;
+ struct sock_fprog fp;
+
+ 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=%x", fp.len, (unsigned) 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;
+ this->rxarg = rxarg;
+ BX_INFO(("eth_linux: enabled NE2K emulation on 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_BUFSIZ];
+ struct sockaddr_ll sll;
+ socklen_t fromlen;
+//static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+ 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, bcast_addr, 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)(rxarg, rxbuf, nbytes);
+// }
+}
+#endif /* if BX_NE2K_SUPPORT && defined ETH_LINUX */
diff --git a/tools/ioemu/iodev/eth_null.cc b/tools/ioemu/iodev/eth_null.cc
new file mode 100644
index 0000000000..11162798ef
--- /dev/null
+++ b/tools/ioemu/iodev/eth_null.cc
@@ -0,0 +1,164 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_null.cc,v 1.13 2002/11/20 19:06:23 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+
+//
+// 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,
+ void *rxarg);
+ 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,
+ void *rxarg) {
+ return (new bx_null_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+#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;
+ this->rxarg = rxarg;
+ // 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.
+ unsigned 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
+ fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (txlog_txt, "\n");
+ fprintf (txlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (txlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (txlog);
+ fflush (txlog_txt);
+#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;
+ 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.
+ int 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
+ fprintf (class_ptr->rxlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (class_ptr->rxlog_txt, "\n");
+ fprintf (class_ptr->rxlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (class_ptr->rxlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (class_ptr->rxlog);
+ fflush (class_ptr->rxlog_txt);
+ }
+#endif
+}
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth_packetmaker.cc b/tools/ioemu/iodev/eth_packetmaker.cc
new file mode 100644
index 0000000000..5ed5e47c8c
--- /dev/null
+++ b/tools/ioemu/iodev/eth_packetmaker.cc
@@ -0,0 +1,184 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_packetmaker.cc,v 1.8 2002/11/20 19:06:23 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// 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"
+
+#if BX_NE2K_SUPPORT && defined(ETH_ARPBACK)
+
+#include "eth_packetmaker.h"
+
+
+bx_bool sendable(const eth_packet& outpacket) {
+ //FINISH ME!
+}
+
+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) {
+ Bit8u out;
+ out=0xFF & *(outpacket.buf+23);
+}
+
+Bit32u eth_IPmaker::source(const eth_packet& outpacket) {
+ Bit32u out;
+ 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;
+ 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_mac, 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_mac, 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_NE2K_SUPPORT && defined(ETH_ARPBACK) */
diff --git a/tools/ioemu/iodev/eth_packetmaker.h b/tools/ioemu/iodev/eth_packetmaker.h
new file mode 100644
index 0000000000..d442325a9f
--- /dev/null
+++ b/tools/ioemu/iodev/eth_packetmaker.h
@@ -0,0 +1,135 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_packetmaker.h,v 1.6 2002/10/25 11:44:39 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+
+#ifndef _ETH_PACKETMAKER_H_
+#define _ETH_PACKETMAKER_H_
+
+#include "../config.h"
+
+#ifdef ETH_ARPBACK
+
+#define PACKET_BUF_SIZE 2048
+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 broadcast_mac[]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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[PACKET_BUF_SIZE];
+ 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_
+
diff --git a/tools/ioemu/iodev/eth_tap.cc b/tools/ioemu/iodev/eth_tap.cc
new file mode 100644
index 0000000000..cb1bf1df89
--- /dev/null
+++ b/tools/ioemu/iodev/eth_tap.cc
@@ -0,0 +1,370 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_tap.cc,v 1.16 2003/10/02 11:33:41 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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.
+//
+
+// 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"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+#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(__FreeBSD__) || defined(__APPLE__) // Should be fixed for other *BSD
+#include <net/if.h>
+#else
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/if.h>
+#endif
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define TAP_VIRTUAL_HW_ADDR 0xDEADBEEF
+#define BX_ETH_TAP_LOGGING 1
+#define BX_PACKET_BUFSIZ 2048 // Enough for an ether frame
+
+//
+// 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,
+ void *rxarg);
+ 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;
+};
+
+
+//
+// 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,
+ void *rxarg) {
+ return (new bx_tap_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+ int flags;
+ char filename[BX_PATHNAME_LEN];
+ if (strncmp (netif, "tap", 3) != 0) {
+ BX_PANIC (("eth_tap: interface name (%s) must be tap0..tap15", netif));
+ }
+ sprintf (filename, "/dev/%s", netif);
+
+#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 %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 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 (("eth_tap: opened %s device", netif));
+
+ /* Execute the configuration script */
+ char intname[IFNAMSIZ];
+ strcpy(intname,netif);
+ char *scriptname=bx_options.ne2k.Oscript->getptr();
+ if((scriptname != NULL)
+ &&(strcmp(scriptname, "") != 0)
+ &&(strcmp(scriptname, "none") != 0)) {
+ if (execute_script(scriptname, intname) < 0)
+ BX_ERROR (("execute script '%s' on %s failed", scriptname, 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;
+ this->rxarg = rxarg;
+#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_BUFSIZ];
+ txbuf[0] = 0;
+ txbuf[1] = 0;
+#if defined(__FreeBSD__) || defined(__APPLE__) // Should be fixed for other *BSD
+ memcpy (txbuf, buf, io_len);
+ unsigned int size = write (fd, txbuf, io_len);
+ if (size != io_len) {
+#else
+ memcpy (txbuf+2, buf, io_len);
+ unsigned int size = write (fd, txbuf, io_len+2);
+ if (size != io_len+2) {
+#endif
+ BX_PANIC (("write on tap device: %s", strerror (errno)));
+ } else {
+ BX_INFO (("wrote %d bytes + 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
+ fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<(int)io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (txlog_txt, "\n");
+ fprintf (txlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (txlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (txlog);
+ fflush (txlog_txt);
+#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_BUFSIZ];
+ Bit8u *rxbuf;
+ if (fd<0) return;
+ nbytes = read (fd, buf, sizeof(buf));
+
+ // hack: discard first two bytes
+#if defined(__FreeBSD__) || defined(__APPLE__) // Should be fixed for other *BSD
+ rxbuf = buf;
+#else
+ rxbuf = buf+2;
+ nbytes-=2;
+#endif
+
+ // 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 defined(__linux__)
+ rxbuf[5] = 1;
+#endif
+
+ if (nbytes>0)
+ BX_INFO (("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
+ fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
+ for (n=0; n<nbytes; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (rxlog_txt, "\n");
+ fprintf (rxlog_txt, "%02x ", rxbuf[n]);
+ }
+ fprintf (rxlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (rxlog);
+ fflush (rxlog_txt);
+ }
+#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)(rxarg, rxbuf, nbytes);
+}
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth_tuntap.cc b/tools/ioemu/iodev/eth_tuntap.cc
new file mode 100644
index 0000000000..f910fd55f1
--- /dev/null
+++ b/tools/ioemu/iodev/eth_tuntap.cc
@@ -0,0 +1,401 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_tuntap.cc,v 1.9 2003/04/26 14:48:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// eth_tuntap.cc - TUN/TAP interface by Renzo Davoli <renzo@cs.unibo.it>
+//
+// WARNING: These instructions were written for ethertap, not TUN/TAP.
+//
+// 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.
+//
+
+// 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"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/netlink.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define TUNTAP_VIRTUAL_HW_ADDR 0xDEADBEEF
+#define BX_ETH_TUNTAP_LOGGING 0
+#define BX_PACKET_BUFSIZ 2048 // Enough for an ether frame
+
+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,
+ void *rxarg);
+ 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;
+};
+
+
+//
+// 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,
+ void *rxarg) {
+ return (new bx_tuntap_pktmover_c(netif, macaddr, rxh, rxarg));
+ }
+} 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,
+ void *rxarg)
+{
+ int flags;
+ if (strncmp (netif, "tun", 3) != 0) {
+ BX_PANIC (("eth_tuntap: interface name (%s) must be tun", netif));
+ }
+#ifdef NEVERDEF
+ 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[IFNAMSIZ];
+ strcpy(intname,netif);
+ 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 (("eth_tuntap: opened %s device", netif));
+
+ /* Execute the configuration script */
+ char *scriptname=bx_options.ne2k.Oscript->getptr();
+ if((scriptname != NULL)
+ &&(strcmp(scriptname, "") != 0)
+ &&(strcmp(scriptname, "none") != 0)) {
+ if (execute_script(scriptname, intname) < 0)
+ BX_ERROR (("execute script '%s' on %s failed", scriptname, 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;
+ this->rxarg = rxarg;
+#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 NEVERDEF
+ Bit8u txbuf[BX_PACKET_BUFSIZ];
+ 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_INFO (("wrote %d bytes + 2 byte pad on tuntap", io_len));
+ }
+#endif
+ unsigned int size = write (fd, buf, io_len);
+ if (size != io_len) {
+ BX_PANIC (("write on tuntap device: %s", strerror (errno)));
+ } else {
+ BX_INFO (("wrote %d bytes on tuntap", io_len));
+ }
+#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", io_len));
+ // dump packet in hex into an ascii log file
+ fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+ Bit8u *charbuf = (Bit8u *)buf;
+ for (n=0; n<io_len; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (txlog_txt, "\n");
+ fprintf (txlog_txt, "%02x ", charbuf[n]);
+ }
+ fprintf (txlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (txlog);
+ fflush (txlog_txt);
+#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_BUFSIZ];
+ Bit8u *rxbuf;
+ if (fd<0) return;
+ nbytes = read (fd, buf, sizeof(buf));
+
+#ifdef NEVERDEF
+ // hack: discard first two bytes
+ rxbuf = buf+2;
+ nbytes-=2;
+#else
+ 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.
+ rxbuf[5] = 1;
+
+ if (nbytes>0)
+ BX_INFO (("tuntap read returned %d bytes", nbytes));
+ if (nbytes<0) {
+ 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", nbytes));
+ // dump packet in hex into an ascii log file
+ fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
+ for (n=0; n<nbytes; n++) {
+ if (((n % 16) == 0) && n>0)
+ fprintf (rxlog_txt, "\n");
+ fprintf (rxlog_txt, "%02x ", rxbuf[n]);
+ }
+ fprintf (rxlog_txt, "\n--\n");
+ // flush log so that we see the packets as they arrive w/o buffering
+ fflush (rxlog);
+ fflush (rxlog_txt);
+ }
+#endif
+ BX_DEBUG(("eth_tuntap: 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)(rxarg, rxbuf, nbytes);
+}
+
+
+ int tun_alloc(char *dev)
+ {
+ struct ifreq ifr;
+ int fd, err;
+
+ if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
+ return -1;
+
+ 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;
+ if( *dev )
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+
+ if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
+ close(fd);
+ return err;
+ }
+
+ //strcpy(dev, ifr.ifr_name);
+ ioctl( fd, TUNSETNOCSUM, 1 );
+
+ return fd;
+ }
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/extfpuirq.cc b/tools/ioemu/iodev/extfpuirq.cc
new file mode 100644
index 0000000000..5d1ed986bf
--- /dev/null
+++ b/tools/ioemu/iodev/extfpuirq.cc
@@ -0,0 +1,107 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extfpuirq.cc,v 1.5 2003/07/31 12:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// 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 "bochs.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_devices.pluginExtFpuIrq = theExternalFpuIrq;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theExternalFpuIrq, BX_PLUGIN_EXTFPUIRQ);
+ return(0); // Success
+}
+
+ void
+libextfpuirq_LTX_plugin_fini(void)
+{
+}
+
+bx_extfpuirq_c::bx_extfpuirq_c(void)
+{
+ put("EFIRQ");
+ settype(EXTFPUIRQLOG);
+}
+
+bx_extfpuirq_c::~bx_extfpuirq_c(void)
+{
+ // nothing for now
+ 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);
+}
+
diff --git a/tools/ioemu/iodev/extfpuirq.h b/tools/ioemu/iodev/extfpuirq.h
new file mode 100644
index 0000000000..c32e71aa93
--- /dev/null
+++ b/tools/ioemu/iodev/extfpuirq.h
@@ -0,0 +1,51 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extfpuirq.h,v 1.2 2003/01/07 08:17:15 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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(void);
+ ~bx_extfpuirq_c(void);
+ 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
+ };
diff --git a/tools/ioemu/iodev/floppy.cc b/tools/ioemu/iodev/floppy.cc
new file mode 100644
index 0000000000..e4090d57b9
--- /dev/null
+++ b/tools/ioemu/iodev/floppy.cc
@@ -0,0 +1,1633 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppy.cc,v 1.69 2003/12/18 20:04:49 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+//
+// Floppy Disk Controller Docs:
+// Intel 82077A Data sheet
+// ftp://void-core.2y.net/pub/docs/fdc/82077AA_FloppyControllerDatasheet.pdf
+// Intel 82078 Data sheet
+// ftp://download.intel.com/design/periphrl/datashts/29047403.PDF
+// Other FDC references
+// http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html
+// And a port list:
+// http://mudlist.eorbit.net/~adam/pickey/ports.html
+//
+
+// 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
+
+
+extern "C" {
+#include <errno.h>
+}
+
+#ifdef __linux__
+extern "C" {
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+}
+#endif
+#include "bochs.h"
+// windows.h included by bochs.h
+#ifdef WIN32
+extern "C" {
+#include <winioctl.h>
+}
+#endif
+#define LOG_THIS theFloppyController->
+
+bx_floppy_ctrl_c *theFloppyController;
+
+/* for main status register */
+#define FD_MS_MRQ 0x80
+#define FD_MS_DIO 0x40
+#define FD_MS_NDMA 0x20
+#define FD_MS_BUSY 0x10
+#define FD_MS_ACTD 0x08
+#define FD_MS_ACTC 0x04
+#define FD_MS_ACTB 0x02
+#define FD_MS_ACTA 0x01
+
+#define FROM_FLOPPY 10
+#define TO_FLOPPY 11
+
+#define FLOPPY_DMA_CHAN 2
+
+typedef struct {
+ unsigned id;
+ Bit8u trk;
+ Bit8u hd;
+ Bit8u spt;
+ unsigned sectors;
+} floppy_type_t;
+
+static floppy_type_t floppy_type[8] = {
+ {BX_FLOPPY_160K, 40, 1, 8, 320},
+ {BX_FLOPPY_180K, 40, 1, 9, 360},
+ {BX_FLOPPY_320K, 40, 2, 8, 640},
+ {BX_FLOPPY_360K, 40, 2, 9, 720},
+ {BX_FLOPPY_720K, 80, 2, 9, 1440},
+ {BX_FLOPPY_1_2, 80, 2, 15, 2400},
+ {BX_FLOPPY_1_44, 80, 2, 18, 2880},
+ {BX_FLOPPY_2_88, 80, 2, 36, 5760}
+};
+
+
+ int
+libfloppy_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theFloppyController = new bx_floppy_ctrl_c ();
+ bx_devices.pluginFloppyDevice = theFloppyController;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theFloppyController, BX_PLUGIN_FLOPPY);
+ return(0); // Success
+}
+
+ void
+libfloppy_LTX_plugin_fini(void)
+{
+}
+
+
+bx_floppy_ctrl_c::bx_floppy_ctrl_c(void)
+{
+ put("FDD");
+ settype(FDLOG);
+ s.floppy_timer_index = BX_NULL_TIMER_HANDLE;
+}
+
+bx_floppy_ctrl_c::~bx_floppy_ctrl_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_floppy_ctrl_c::init(void)
+{
+ Bit8u i;
+
+ BX_DEBUG(("Init $Id: floppy.cc,v 1.69 2003/12/18 20:04:49 vruppert Exp $"));
+ DEV_dma_register_8bit_channel(2, dma_read, dma_write, "Floppy Drive");
+ DEV_register_irq(6, "Floppy Drive");
+ for (unsigned addr=0x03F2; addr<=0x03F7; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1);
+ }
+
+
+ DEV_cmos_set_reg(0x10, 0x00); /* start out with: no drive 0, no drive 1 */
+
+ BX_FD_THIS s.num_supported_floppies = 0;
+
+ for (i=0; i<4; i++) {
+ BX_FD_THIS s.device_type[i] = BX_FLOPPY_NONE;
+ BX_FD_THIS s.media[i].type = BX_FLOPPY_NONE;
+ }
+
+ //
+ // Floppy A setup
+ //
+ BX_FD_THIS s.media[0].sectors_per_track = 0;
+ BX_FD_THIS s.media[0].tracks = 0;
+ BX_FD_THIS s.media[0].heads = 0;
+ BX_FD_THIS s.media[0].sectors = 0;
+ BX_FD_THIS s.media[0].fd = -1;
+ BX_FD_THIS s.media_present[0] = 0;
+ BX_FD_THIS s.device_type[0] = bx_options.floppya.Odevtype->get ();
+
+ switch (BX_FD_THIS s.device_type[0]) {
+ case BX_FLOPPY_NONE:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x00);
+ break;
+ case BX_FLOPPY_360K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x10);
+ break;
+ case BX_FLOPPY_1_2:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x20);
+ break;
+ case BX_FLOPPY_720K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x30);
+ break;
+ case BX_FLOPPY_1_44:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x40);
+ break;
+ case BX_FLOPPY_2_88:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x50);
+ break;
+
+ // use CMOS reserved types
+ case BX_FLOPPY_160K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x60);
+ BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 6"));
+ break;
+ case BX_FLOPPY_180K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x70);
+ BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 7"));
+ break;
+ case BX_FLOPPY_320K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x80);
+ BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 8"));
+ break;
+
+ default:
+ BX_PANIC(("unknown floppya type"));
+ }
+ if (BX_FD_THIS s.device_type[0] != BX_FLOPPY_NONE)
+ BX_FD_THIS s.num_supported_floppies++;
+
+ if (bx_options.floppya.Otype->get () != BX_FLOPPY_NONE) {
+ if ( bx_options.floppya.Ostatus->get () == BX_INSERTED) {
+ if (evaluate_media(bx_options.floppya.Otype->get (), bx_options.floppya.Opath->getptr (),
+ & BX_FD_THIS s.media[0]))
+ BX_FD_THIS s.media_present[0] = 1;
+ else
+ bx_options.floppya.Ostatus->set(BX_EJECTED);
+#define MED (BX_FD_THIS s.media[0])
+ BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+ }
+ }
+
+
+ //
+ // Floppy B setup
+ //
+ BX_FD_THIS s.media[1].sectors_per_track = 0;
+ BX_FD_THIS s.media[1].tracks = 0;
+ BX_FD_THIS s.media[1].heads = 0;
+ BX_FD_THIS s.media[1].sectors = 0;
+ BX_FD_THIS s.media[1].fd = -1;
+ BX_FD_THIS s.media_present[1] = 0;
+ BX_FD_THIS s.device_type[1] = bx_options.floppyb.Odevtype->get ();
+
+ switch (BX_FD_THIS s.device_type[1]) {
+ case BX_FLOPPY_NONE:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x00);
+ break;
+ case BX_FLOPPY_360K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x01);
+ break;
+ case BX_FLOPPY_1_2:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x02);
+ break;
+ case BX_FLOPPY_720K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x03);
+ break;
+ case BX_FLOPPY_1_44:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x04);
+ break;
+ case BX_FLOPPY_2_88:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x05);
+ break;
+
+ // use CMOS reserved types
+ case BX_FLOPPY_160K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x06);
+ BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 6"));
+ break;
+ case BX_FLOPPY_180K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x07);
+ BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 7"));
+ break;
+ case BX_FLOPPY_320K:
+ DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x08);
+ BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 8"));
+ break;
+
+ default:
+ BX_PANIC(("unknown floppyb type"));
+ }
+ if (BX_FD_THIS s.device_type[1] != BX_FLOPPY_NONE)
+ BX_FD_THIS s.num_supported_floppies++;
+
+ if (bx_options.floppyb.Otype->get () != BX_FLOPPY_NONE) {
+ if ( bx_options.floppyb.Ostatus->get () == BX_INSERTED) {
+ if (evaluate_media(bx_options.floppyb.Otype->get (), bx_options.floppyb.Opath->getptr (),
+ & BX_FD_THIS s.media[1]))
+ BX_FD_THIS s.media_present[1] = 1;
+ else
+ bx_options.floppyb.Ostatus->set(BX_EJECTED);
+#define MED (BX_FD_THIS s.media[1])
+ BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+ }
+ }
+
+
+
+ /* CMOS Equipment Byte register */
+ if (BX_FD_THIS s.num_supported_floppies > 0) {
+ DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e) |
+ ((BX_FD_THIS s.num_supported_floppies-1) << 6) | 1);
+ }
+ else
+ DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e));
+
+
+ if (BX_FD_THIS s.floppy_timer_index == BX_NULL_TIMER_HANDLE) {
+ BX_FD_THIS s.floppy_timer_index =
+ bx_pc_system.register_timer( this, timer_handler,
+ bx_options.Ofloppy_command_delay->get (), 0,0, "floppy");
+ }
+
+ BX_DEBUG(("bx_options.Ofloppy_command_delay = %u",
+ (unsigned) bx_options.Ofloppy_command_delay->get ()));
+}
+
+
+
+ void
+bx_floppy_ctrl_c::reset(unsigned type)
+{
+ Bit32u i;
+
+ BX_FD_THIS s.pending_irq = 0;
+ BX_FD_THIS s.reset_sensei = 0; /* no reset result present */
+
+ BX_FD_THIS s.main_status_reg = 0;
+ BX_FD_THIS s.status_reg0 = 0;
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+ BX_FD_THIS s.status_reg3 = 0;
+
+ // software reset (via DOR port 0x3f2 bit 2) does not change DOR
+ if (type == BX_RESET_HARDWARE) {
+ BX_FD_THIS s.DOR = 0x0c;
+ // motor off, drive 3..0
+ // DMA/INT enabled
+ // normal operation
+ // drive select 0
+
+ // DIR and CCR affected only by hard reset
+ for (i=0; i<4; i++) {
+ BX_FD_THIS s.DIR[i] |= 0x80; // disk changed
+ }
+ BX_FD_THIS s.data_rate = 0; /* 500 Kbps */
+ }
+
+ for (i=0; i<4; i++) {
+ BX_FD_THIS s.cylinder[i] = 0;
+ BX_FD_THIS s.head[i] = 0;
+ BX_FD_THIS s.sector[i] = 0;
+ }
+
+ DEV_pic_lower_irq(6);
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_idle_phase();
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_floppy_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ /* reads from the floppy io ports */
+ Bit32u
+bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_FD_SMF
+ Bit8u status, value;
+
+ if (bx_dbg.floppy)
+ BX_INFO(("read access to port %04x", (unsigned) address));
+
+ switch (address) {
+#if BX_DMA_FLOPPY_IO
+ case 0x3F2: // diskette controller digital output register
+ value = BX_FD_THIS s.DOR;
+ return(value);
+ break;
+
+ case 0x3F4: /* diskette controller main status register */
+ status = BX_FD_THIS s.main_status_reg;
+ return(status);
+ break;
+
+ case 0x3F5: /* diskette controller data */
+ if (BX_FD_THIS s.result_size == 0) {
+ BX_ERROR(("port 0x3f5: no results to read"));
+ BX_FD_THIS s.main_status_reg = 0;
+ return BX_FD_THIS s.result[0];
+ }
+
+ value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++];
+ BX_FD_THIS s.main_status_reg &= 0xF0;
+ if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) {
+ if (!BX_FD_THIS s.reset_sensei) BX_FD_THIS s.pending_irq = 0;
+ DEV_pic_lower_irq(6);
+ enter_idle_phase();
+ }
+ return(value);
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+
+ case 0x3F3: // Tape Drive Register
+ // see http://www.smsc.com/main/datasheets/37c93x.pdf page 18 for more details
+
+ switch( BX_FD_THIS s.DOR & 0x03 )
+ {
+ case 0x00:
+ if( (BX_FD_THIS s.DOR & 0x10) == 0) break;
+ return(2);
+ case 0x01:
+ if( (BX_FD_THIS s.DOR & 0x20) == 0) break;
+ return(1);
+ }
+ return(3);
+
+ case 0x3F6: // Reserved for future floppy controllers
+ // This address shared with the hard drive controller
+ value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
+ return( value );
+ break;
+
+ case 0x3F7: // diskette controller digital input register
+ // This address shared with the hard drive controller:
+ // Bit 7 : floppy
+ // Bits 6..0: hard drive
+ value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
+ value &= 0x7f;
+ // add in diskette change line
+ value |= (BX_FD_THIS s.DIR[BX_FD_THIS s.DOR & 0x03] & 0x80);
+ return( value );
+ break;
+ default:
+ BX_ERROR(("io_read: unsupported address 0x%04x", (unsigned) address));
+ return(0);
+ break;
+ }
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_floppy_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ /* writes to the floppy io ports */
+ void
+bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_FD_SMF
+ Bit8u dma_and_interrupt_enable;
+ Bit8u normal_operation, prev_normal_operation;
+ Bit8u drive_select;
+ Bit8u motor_on_drive0, motor_on_drive1;
+
+ if (bx_dbg.floppy)
+ BX_INFO(("write access to port %04x, value=%02x",
+ (unsigned) address, (unsigned) value));
+
+ switch (address) {
+#if BX_DMA_FLOPPY_IO
+ case 0x3F2: /* diskette controller digital output register */
+ motor_on_drive1 = value & 0x20;
+ motor_on_drive0 = value & 0x10;
+ dma_and_interrupt_enable = value & 0x08;
+ if (!dma_and_interrupt_enable)
+ BX_DEBUG(("DMA and interrupt capabilities disabled"));
+ normal_operation = value & 0x04;
+ drive_select = value & 0x03;
+
+ prev_normal_operation = BX_FD_THIS s.DOR & 0x04;
+ BX_FD_THIS s.DOR = value;
+
+ if (prev_normal_operation==0 && normal_operation) {
+ // transition from RESET to NORMAL
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.Ofloppy_command_delay->get (), 0 );
+ }
+ else if (prev_normal_operation && normal_operation==0) {
+ // transition from NORMAL to RESET
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ BX_FD_THIS s.pending_command = 0xfe; // RESET pending
+
+ }
+ BX_DEBUG(("io_write: digital output register"));
+ BX_DEBUG((" motor on, drive1 = %d", motor_on_drive1 > 0));
+ BX_DEBUG((" motor on, drive0 = %d", motor_on_drive0 > 0));
+ BX_DEBUG((" dma_and_interrupt_enable=%02x",
+ (unsigned) dma_and_interrupt_enable));
+ BX_DEBUG((" normal_operation=%02x",
+ (unsigned) normal_operation));
+ BX_DEBUG((" drive_select=%02x",
+ (unsigned) drive_select));
+ if (BX_FD_THIS s.device_type[drive_select] == BX_FLOPPY_NONE) {
+ BX_DEBUG(("WARNING: not existing drive selected"));
+ }
+ break;
+
+ case 0x3f4: /* diskette controller data rate select register */
+ BX_ERROR(("io_write: data rate select register unsupported"));
+ break;
+
+ case 0x3F5: /* diskette controller data */
+ BX_DEBUG(("command = %02x", (unsigned) value));
+ if (BX_FD_THIS s.command_complete) {
+ if (BX_FD_THIS s.pending_command!=0)
+ BX_PANIC(("io: 3f5: receiving new comm, old one (%02x) pending",
+ (unsigned) BX_FD_THIS s.pending_command));
+ BX_FD_THIS s.command[0] = value;
+ BX_FD_THIS s.command_complete = 0;
+ BX_FD_THIS s.command_index = 1;
+ /* read/write command in progress */
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_BUSY;
+ switch (value) {
+ case 0x03: /* specify */
+ BX_FD_THIS s.command_size = 3;
+ break;
+ case 0x04: // get status
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0x07: /* recalibrate */
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0x08: /* sense interrupt status */
+ BX_FD_THIS s.command_size = 1;
+ break;
+ case 0x0f: /* seek */
+ BX_FD_THIS s.command_size = 3;
+ break;
+ case 0x4a: /* read ID */
+ BX_FD_THIS s.command_size = 2;
+ break;
+ case 0x4d: /* format track */
+ BX_FD_THIS s.command_size = 6;
+ break;
+ case 0x45:
+ case 0xc5: /* write normal data */
+ BX_FD_THIS s.command_size = 9;
+ break;
+ case 0x46:
+ case 0x66:
+ case 0xc6:
+ case 0xe6: /* read normal data */
+ BX_FD_THIS s.command_size = 9;
+ break;
+
+ case 0x13: // Configure command (Enhanced)
+ BX_FD_THIS s.command_size = 4;
+ break;
+
+ case 0x0e: // dump registers (Enhanced drives)
+ case 0x10: // Version command, standard controller returns 80h
+ case 0x18: // National Semiconductor version command; return 80h
+ // These commands are not implemented on the standard
+ // controller and return an error. They are available on
+ // the enhanced controller.
+ BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x",
+ (unsigned) value));
+ BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command
+ BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+ enter_result_phase();
+ break;
+
+ default:
+ BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x",
+ (unsigned) value));
+ BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command
+ BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+ enter_result_phase();
+ break;
+ }
+ }
+ else {
+ BX_FD_THIS s.command[BX_FD_THIS s.command_index++] =
+ value;
+ }
+ if (BX_FD_THIS s.command_index ==
+ BX_FD_THIS s.command_size) {
+ /* read/write command not in progress any more */
+ floppy_command();
+ BX_FD_THIS s.command_complete = 1;
+ }
+ BX_DEBUG(("io_write: diskette controller data"));
+ return;
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+
+ case 0x3F6: /* diskette controller (reserved) */
+ BX_DEBUG(("io_write: reserved register 0x3f6 unsupported"));
+ // this address shared with the hard drive controller
+ DEV_hd_write_handler(bx_devices.pluginHardDrive, address, value, io_len);
+ break;
+
+#if BX_DMA_FLOPPY_IO
+ case 0x3F7: /* diskette controller configuration control register */
+ BX_DEBUG(("io_write: config control register"));
+ BX_FD_THIS s.data_rate = value & 0x03;
+ switch (BX_FD_THIS s.data_rate) {
+ case 0: BX_DEBUG((" 500 Kbps")); break;
+ case 1: BX_DEBUG((" 300 Kbps")); break;
+ case 2: BX_DEBUG((" 250 Kbps")); break;
+ case 3: BX_DEBUG((" 1 Mbps")); break;
+ }
+ return;
+ break;
+
+ default:
+ BX_ERROR(("io_write ignored: 0x%04x = 0x%02x", (unsigned) address, (unsigned) value));
+ break;
+#endif // #if BX_DMA_FLOPPY_IO
+ }
+}
+
+
+
+ void
+bx_floppy_ctrl_c::floppy_command(void)
+{
+#if BX_PROVIDE_CPU_MEMORY==0
+ BX_PANIC(("floppy_command(): uses DMA: not supported for"
+ " external environment"));
+#else
+ unsigned i;
+ Bit8u step_rate_time;
+ Bit8u head_unload_time;
+ Bit8u head_load_time;
+ Bit8u motor_on;
+ Bit8u head, drive, cylinder, sector, eot;
+ Bit8u sector_size, data_length;
+ Bit32u logical_sector;
+
+
+ BX_DEBUG(("FLOPPY COMMAND: "));
+ for (i=0; i<BX_FD_THIS s.command_size; i++)
+ BX_DEBUG(("[%02x] ", (unsigned) BX_FD_THIS s.command[i]));
+
+#if 0
+ /* execute phase of command is in progress (non DMA mode) */
+ BX_FD_THIS s.main_status_reg |= 20;
+#endif
+
+ BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+ switch (BX_FD_THIS s.pending_command) {
+ case 0x03: // specify
+ // execution: specified parameters are loaded
+ // result: no result bytes, no interrupt
+ step_rate_time = BX_FD_THIS s.command[1] >> 4;
+ head_unload_time = BX_FD_THIS s.command[1] & 0x0f;
+ head_load_time = BX_FD_THIS s.command[2] >> 1;
+ if (BX_FD_THIS s.command[2] & 0x01)
+ BX_ERROR(("non DMA mode selected"));
+ enter_idle_phase();
+ return;
+ break;
+
+ case 0x04: // get status
+ drive = (BX_FD_THIS s.command[1] & 0x03);
+ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+ BX_FD_THIS s.status_reg3 = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive
+ | (BX_FD_THIS s.media[drive].write_protected ? 0x40 : 0x00);
+ if (BX_FD_THIS s.cylinder[drive] == 0) BX_FD_THIS s.status_reg3 |= 0x10;
+ enter_result_phase();
+ return;
+ break;
+
+ case 0x07: // recalibrate
+ drive = (BX_FD_THIS s.command[1] & 0x03);
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+ BX_DEBUG(("floppy_command(): recalibrate drive %u",
+ (unsigned) drive));
+ motor_on = ( (BX_FD_THIS s.DOR>>(drive+4))
+ & 0x01 );
+ if (motor_on == 0) {
+ BX_INFO(("floppy_command(): recal drive with motor off"));
+ }
+ if (drive==0)
+ BX_FD_THIS s.DOR |= 0x10; // turn on MOTA
+ else
+ BX_FD_THIS s.DOR |= 0x20; // turn on MOTB
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.Ofloppy_command_delay->get (), 0 );
+ /* command head to track 0
+ * controller set to non-busy
+ * error condition noted in Status reg 0's equipment check bit
+ * seek end bit set to 1 in Status reg 0 regardless of outcome
+ * The last two are taken care of in timer().
+ */
+ BX_FD_THIS s.cylinder[drive] = 0;
+ BX_FD_THIS s.main_status_reg = (1 << drive);
+ return;
+ break;
+
+ case 0x08: /* sense interrupt status */
+ /* execution:
+ * get status
+ * result:
+ * no interupt
+ * byte0 = status reg0
+ * byte1 = current cylinder number (0 to 79)
+ */
+ drive = BX_FD_THIS s.DOR & 0x03;
+ if (!BX_FD_THIS s.pending_irq) {
+ BX_FD_THIS s.status_reg0 = 0x80;
+ }
+ else {
+ if (BX_FD_THIS s.reset_sensei > 0) {
+ drive = 4 - BX_FD_THIS s.reset_sensei;
+ BX_FD_THIS s.status_reg0 &= 0xf8;
+ BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.reset_sensei--;
+ }
+ }
+
+ BX_DEBUG(("sense interrupt status"));
+ enter_result_phase();
+ return;
+ break;
+
+ case 0x0f: /* seek */
+ /* command:
+ * byte0 = 0F
+ * byte1 = drive & head select
+ * byte2 = cylinder number
+ * execution:
+ * postion head over specified cylinder
+ * result:
+ * no result bytes, issues an interrupt
+ */
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+ BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2];
+ /* ??? should also check cylinder validity */
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.Ofloppy_command_delay->get (), 0 );
+ /* data reg not ready, drive busy */
+ BX_FD_THIS s.main_status_reg = (1 << drive);
+ return;
+ break;
+
+ case 0x13: // Configure
+ BX_DEBUG(("configure (eis = 0x%02x)", BX_FD_THIS s.command[2] & 0x40 ));
+ BX_DEBUG(("configure (efifo = 0x%02x)", BX_FD_THIS s.command[2] & 0x20 ));
+ BX_DEBUG(("configure (no poll = 0x%02x)", BX_FD_THIS s.command[2] & 0x10 ));
+ BX_DEBUG(("configure (fifothr = 0x%02x)", BX_FD_THIS s.command[2] & 0x0f ));
+ BX_DEBUG(("configure (pretrk = 0x%02x)", BX_FD_THIS s.command[3] ));
+ enter_idle_phase();
+ return;
+ break;
+
+ case 0x4a: // read ID
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+ if (motor_on == 0) {
+ BX_ERROR(("floppy_command(): 0x4a: motor not on"));
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ return;
+ }
+ if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+ BX_PANIC(("floppy_command(): read ID: bad drive #%d", drive));
+ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive;
+ bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+ bx_options.Ofloppy_command_delay->get (), 0 );
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ return;
+ break;
+
+ case 0x4d: // format track
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+ if (motor_on == 0)
+ BX_PANIC(("floppy_command(): format track: motor not on"));
+ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+ sector_size = BX_FD_THIS s.command[2];
+ BX_FD_THIS s.format_count = BX_FD_THIS s.command[3];
+ BX_FD_THIS s.format_fillbyte = BX_FD_THIS s.command[5];
+ if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+ BX_PANIC(("floppy_command(): format track: bad drive #%d", drive));
+
+ if (sector_size != 0x02) { // 512 bytes
+ BX_PANIC(("format track: sector size %d not supported", 128<<sector_size));
+ }
+ if (BX_FD_THIS s.format_count != BX_FD_THIS s.media[drive].sectors_per_track) {
+ BX_PANIC(("format track: %d sectors/track requested (%d expected)",
+ BX_FD_THIS s.format_count, BX_FD_THIS s.media[drive].sectors_per_track));
+ }
+ if ( BX_FD_THIS s.media_present[drive] == 0 ) {
+ // media not in drive, return error
+ BX_INFO(("attempt to format track with media not present"));
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+ BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
+ return;
+ }
+ if (BX_FD_THIS s.media[drive].write_protected) {
+ // media write-protected, return error
+ BX_INFO(("attempt to format track with media write-protected"));
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+ BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
+ return;
+ }
+
+ /* 4 header bytes per sector are required */
+ BX_FD_THIS s.format_count <<= 2;
+
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ BX_DEBUG(("format track"));
+ return;
+ break;
+
+ case 0x46: // read normal data, MT=0, SK=0
+ case 0x66: // read normal data, MT=0, SK=1
+ case 0xc6: // read normal data, MT=1, SK=0
+ case 0xe6: // read normal data, MT=1, SK=1
+ case 0x45: // write normal data, MT=0
+ case 0xc5: // write normal data, MT=1
+ BX_FD_THIS s.multi_track = (BX_FD_THIS s.command[0] >> 7);
+ if ( (BX_FD_THIS s.DOR & 0x08) == 0 )
+ BX_PANIC(("read/write command with DMA and int disabled"));
+ drive = BX_FD_THIS s.command[1] & 0x03;
+ BX_FD_THIS s.DOR &= 0xfc;
+ BX_FD_THIS s.DOR |= drive;
+
+ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+ if (motor_on == 0)
+ BX_PANIC(("floppy_command(): read/write: motor not on"));
+ head = BX_FD_THIS s.command[3] & 0x01;
+ cylinder = BX_FD_THIS s.command[2]; /* 0..79 depending */
+ sector = BX_FD_THIS s.command[4]; /* 1..36 depending */
+ eot = BX_FD_THIS s.command[6]; /* 1..36 depending */
+ sector_size = BX_FD_THIS s.command[5];
+ data_length = BX_FD_THIS s.command[8];
+ BX_DEBUG(("read/write normal data"));
+ BX_DEBUG(("BEFORE"));
+ BX_DEBUG((" drive = %u", (unsigned) drive));
+ BX_DEBUG((" head = %u", (unsigned) head));
+ BX_DEBUG((" cylinder = %u", (unsigned) cylinder));
+ BX_DEBUG((" sector = %u", (unsigned) sector));
+ BX_DEBUG((" eot = %u", (unsigned) eot));
+ if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+ BX_PANIC(("floppy_command(): read/write: bad drive #%d", drive));
+
+ // check that head number in command[1] bit two matches the head
+ // reported in the head number field. Real floppy drives are
+ // picky about this, as reported in SF bug #439945, (Floppy drive
+ // read input error checking).
+ if (head != ((BX_FD_THIS s.command[1]>>2)&1)) {
+ BX_ERROR(("head number in command[1] doesn't match head field"));
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+ BX_FD_THIS s.status_reg1 = 0x04; // 0000 0100
+ BX_FD_THIS s.status_reg2 = 0x00; // 0000 0000
+ enter_result_phase();
+ return;
+ }
+
+ if ( BX_FD_THIS s.media_present[drive] == 0 ) {
+ // media not in drive, return error
+
+ BX_INFO(("attempt to read/write sector %u,"
+ " sectors/track=%u with media not present",
+ (unsigned) sector,
+ (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+ BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
+ return;
+ }
+
+ if (sector_size != 0x02) { // 512 bytes
+ BX_PANIC(("read/write command: sector size %d not supported", 128<<sector_size));
+ }
+ if ( cylinder >= BX_FD_THIS s.media[drive].tracks ) {
+ BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh",
+ (unsigned) sector, (unsigned) cylinder, (unsigned) eot,
+ (unsigned) head));
+ return;
+ }
+
+ if (sector > BX_FD_THIS s.media[drive].sectors_per_track) {
+ // requested sector > last sector on track
+ BX_INFO(("attempt to read/write sector %u,"
+ " sectors/track=%u", (unsigned) sector,
+ (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+ // set controller to where drive would have left off
+ // after it discovered the sector was past EOT
+ BX_FD_THIS s.cylinder[drive] = cylinder;
+ BX_FD_THIS s.head[drive] = head;
+ BX_FD_THIS s.sector[drive] = BX_FD_THIS s.media[drive].sectors_per_track;
+
+ // 0100 0HDD abnormal termination
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ // 1000 0101 end of cyl/NDAT/NID
+ BX_FD_THIS s.status_reg1 = 0x85;
+ // 0000 0000
+ BX_FD_THIS s.status_reg2 = 0x00;
+ enter_result_phase();
+ return;
+ }
+
+ if (cylinder != BX_FD_THIS s.cylinder[drive])
+ BX_DEBUG(("io: cylinder request != current cylinder"));
+
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (cylinder * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (head * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (sector - 1);
+
+ if (logical_sector >= BX_FD_THIS s.media[drive].sectors) {
+ BX_PANIC(("io: logical sector out of bounds"));
+ }
+
+ BX_FD_THIS s.cylinder[drive] = cylinder;
+ BX_FD_THIS s.sector[drive] = sector;
+ BX_FD_THIS s.head[drive] = head;
+
+ if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, FROM_FLOPPY);
+
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ return;
+ }
+ else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
+
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+ /* data reg not ready, controller busy */
+ BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+ return;
+ }
+ else
+ BX_PANIC(("floppy_command(): unknown read/write command"));
+
+ return;
+ break;
+
+ default: // invalid or unsupported command; these are captured in write() above
+ BX_PANIC(("You should never get here! cmd = 0x%02x",
+ BX_FD_THIS s.command[0]));
+ }
+#endif
+}
+
+ void
+bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer,
+ Bit32u bytes, Bit8u direction)
+{
+ int ret;
+
+ if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+ BX_PANIC(("floppy_xfer: bad drive #%d", drive));
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("drive=%u", (unsigned) drive));
+ BX_INFO(("offset=%u", (unsigned) offset));
+ BX_INFO(("bytes=%u", (unsigned) bytes));
+ BX_INFO(("direction=%s", (direction==FROM_FLOPPY)? "from" : "to"));
+ }
+
+#if BX_WITH_MACOS
+ if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+ {
+ ret = lseek(BX_FD_THIS s.media[drive].fd, offset, SEEK_SET);
+ if (ret < 0) {
+ BX_PANIC(("could not perform lseek() on floppy image file"));
+ }
+ }
+
+ if (direction == FROM_FLOPPY) {
+#if BX_WITH_MACOS
+ if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+ ret = fd_read((char *) buffer, offset, bytes);
+ else
+#endif
+ ret = ::read(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+ if (ret < int(bytes)) {
+ /* ??? */
+ if (ret > 0) {
+ BX_INFO(("partial read() on floppy image returns %u/%u",
+ (unsigned) ret, (unsigned) bytes));
+ memset(buffer + ret, 0, bytes - ret);
+ }
+ else {
+ BX_INFO(("read() on floppy image returns 0"));
+ memset(buffer, 0, bytes);
+ }
+ }
+ }
+
+ else { // TO_FLOPPY
+ BX_ASSERT (!BX_FD_THIS s.media[drive].write_protected);
+#if BX_WITH_MACOS
+ if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+ ret = fd_write((char *) buffer, offset, bytes);
+ else
+#endif
+ ret = ::write(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+ if (ret < int(bytes)) {
+ BX_PANIC(("could not perform write() on floppy image file"));
+ }
+ }
+}
+
+
+
+ void
+bx_floppy_ctrl_c::timer_handler(void *this_ptr)
+{
+
+ bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+ class_ptr->timer();
+}
+
+ void
+bx_floppy_ctrl_c::timer()
+{
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+ switch ( BX_FD_THIS s.pending_command ) {
+ case 0x07: // recal
+ case 0x0f: // seek
+ BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE) {
+ BX_FD_THIS s.status_reg0 |= 0x50;
+ }
+ else if (BX_FD_THIS s.media_present[drive] == 0) {
+ BX_FD_THIS s.status_reg0 |= 0x40;
+ BX_FD_THIS s.status_reg1 = 0x25;
+ BX_FD_THIS s.status_reg2 = 0x31;
+ }
+
+ /* reset changeline */
+ if (drive > 1) return;
+ if (BX_FD_THIS s.media_present[drive])
+ BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
+
+ enter_idle_phase();
+ raise_interrupt();
+ break;
+
+ case 0x4a: /* read ID */
+ enter_result_phase();
+ break;
+
+ case 0xfe: // (contrived) RESET
+ theFloppyController->reset(BX_RESET_SOFTWARE);
+ BX_FD_THIS s.pending_command = 0;
+ BX_FD_THIS s.status_reg0 = 0xc0;
+ raise_interrupt();
+ BX_FD_THIS s.reset_sensei = 4;
+ break;
+
+ case 0x00: // nothing pending?
+ break;
+
+ default:
+ BX_PANIC(("floppy:timer(): unknown case %02x",
+ (unsigned) BX_FD_THIS s.pending_command));
+ }
+ return;
+}
+
+ void
+bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
+{
+ // A DMA write is from I/O to Memory
+ // We need to return then next data byte from the floppy buffer
+ // to be transfered via the DMA to memory. (read block from floppy)
+
+
+ *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+ increment_sector(); // increment to next sector before retrieving next one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+ if (DEV_dma_get_tc()) { // Terminal Count line, done
+ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("<<READ DONE>>"));
+ BX_INFO(("AFTER"));
+ BX_INFO((" drive = %u", (unsigned) drive));
+ BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
+ BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
+ BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
+ }
+
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
+ }
+ else { // more data to transfer
+ Bit32u logical_sector;
+
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] *
+ BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, FROM_FLOPPY);
+ }
+ }
+}
+
+ void
+bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
+{
+ // A DMA read is from Memory to I/O
+ // We need to write the data_byte which was already transfered from memory
+ // via DMA to I/O (write block to floppy)
+
+ Bit8u drive;
+ Bit32u logical_sector;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+ if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
+ --BX_FD_THIS s.format_count;
+ switch (3 - (BX_FD_THIS s.format_count & 0x03)) {
+ case 0:
+ BX_FD_THIS s.cylinder[drive] = *data_byte;
+ break;
+ case 1:
+ if (*data_byte != BX_FD_THIS s.head[drive])
+ BX_ERROR(("head number does not match head field"));
+ break;
+ case 2:
+ BX_FD_THIS s.sector[drive] = *data_byte;
+ break;
+ case 3:
+ if (*data_byte != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*data_byte)));
+ BX_DEBUG(("formatting cylinder %u head %u sector %u",
+ BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive],
+ BX_FD_THIS s.sector[drive]));
+ for (unsigned i = 0; i < 512; i++) {
+ BX_FD_THIS s.floppy_buffer[i] = BX_FD_THIS s.format_fillbyte;
+ }
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, TO_FLOPPY);
+ break;
+ }
+ if ((BX_FD_THIS s.format_count == 0) || (DEV_dma_get_tc())) {
+ BX_FD_THIS s.format_count = 0;
+ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
+ }
+ return;
+ }
+
+ BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
+
+ if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+ // original assumed all floppies had two sides...now it does not *delete this comment line*
+ logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+ (BX_FD_THIS s.sector[drive] - 1);
+ if ( BX_FD_THIS s.media[drive].write_protected ) {
+ // write protected error
+ BX_INFO(("tried to write disk %u, which is write-protected", drive));
+ // ST0: IC1,0=01 (abnormal termination: started execution but failed)
+ BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+ // ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
+ BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+ // ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
+ BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+ enter_result_phase();
+ return;
+ }
+ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+ 512, TO_FLOPPY);
+ increment_sector(); // increment to next sector after writing current one
+ BX_FD_THIS s.floppy_buffer_index = 0;
+ if (DEV_dma_get_tc()) { // Terminal Count line, done
+ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+ BX_FD_THIS s.status_reg1 = 0;
+ BX_FD_THIS s.status_reg2 = 0;
+
+ if (bx_dbg.floppy) {
+ BX_INFO(("<<WRITE DONE>>"));
+ BX_INFO(("AFTER"));
+ BX_INFO((" drive = %u", (unsigned) drive));
+ BX_INFO((" head = %u", (unsigned) BX_FD_THIS s.head[drive]));
+ BX_INFO((" cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
+ BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive]));
+ }
+
+ DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+ enter_result_phase();
+ }
+ else { // more data to transfer
+ } // else
+ } // if BX_FD_THIS s.floppy_buffer_index >= 512
+}
+
+ void
+bx_floppy_ctrl_c::raise_interrupt(void)
+{
+ DEV_pic_raise_irq(6);
+ BX_FD_THIS s.pending_irq = 1;
+ BX_FD_THIS s.reset_sensei = 0;
+}
+
+
+ void
+bx_floppy_ctrl_c::increment_sector(void)
+{
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+
+ // values after completion of data xfer
+ // ??? calculation depends on base_count being multiple of 512
+ BX_FD_THIS s.sector[drive] ++;
+ if (BX_FD_THIS s.sector[drive] > BX_FD_THIS s.media[drive].sectors_per_track) {
+ BX_FD_THIS s.sector[drive] = 1;
+ if (BX_FD_THIS s.multi_track) {
+ BX_FD_THIS s.head[drive] ++;
+ if (BX_FD_THIS s.head[drive] > 1) {
+ BX_FD_THIS s.head[drive] = 0;
+ BX_FD_THIS s.cylinder[drive] ++;
+ }
+ }
+ else {
+ BX_FD_THIS s.cylinder[drive] ++;
+ }
+ if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) {
+ // Set to 1 past last possible cylinder value.
+ // I notice if I set it to tracks-1, prama linux won't boot.
+ BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks;
+ BX_INFO(("increment_sector: clamping cylinder to max"));
+ }
+ }
+}
+
+ unsigned
+bx_floppy_ctrl_c::set_media_status(unsigned drive, unsigned status)
+{
+ char *path;
+ unsigned type;
+
+ if (drive == 0)
+ type = bx_options.floppya.Otype->get ();
+ else
+ type = bx_options.floppyb.Otype->get ();
+
+ // if setting to the current value, nothing to do
+ if ((status == BX_FD_THIS s.media_present[drive]) &&
+ ((status == 0) || (type == BX_FD_THIS s.media[drive].type)))
+ return(status);
+
+ if (status == 0) {
+ // eject floppy
+ if (BX_FD_THIS s.media[drive].fd >= 0) {
+ close( BX_FD_THIS s.media[drive].fd );
+ BX_FD_THIS s.media[drive].fd = -1;
+ }
+ BX_FD_THIS s.media_present[drive] = 0;
+ if (drive == 0) {
+ bx_options.floppya.Ostatus->set(BX_EJECTED);
+ } else {
+ bx_options.floppyb.Ostatus->set(BX_EJECTED);
+ }
+ BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
+ return(0);
+ }
+ else {
+ // insert floppy
+ if (drive == 0) {
+ path = bx_options.floppya.Opath->getptr ();
+ }
+ else {
+ path = bx_options.floppyb.Opath->getptr ();
+ }
+ if (!strcmp(path, "none"))
+ return(0);
+ if (evaluate_media(type, path, & BX_FD_THIS s.media[drive])) {
+ BX_FD_THIS s.media_present[drive] = 1;
+ if (drive == 0) {
+#define MED (BX_FD_THIS s.media[0])
+ BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+ bx_options.floppya.Ostatus->set(BX_INSERTED);
+ } else {
+#define MED (BX_FD_THIS s.media[1])
+ BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
+ MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+ bx_options.floppyb.Ostatus->set(BX_INSERTED);
+ }
+ BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
+ return(1);
+ }
+ else {
+ BX_FD_THIS s.media_present[drive] = 0;
+ if (drive == 0) {
+ bx_options.floppya.Ostatus->set(BX_EJECTED);
+ } else {
+ bx_options.floppyb.Ostatus->set(BX_EJECTED);
+ }
+ return(0);
+ }
+ }
+}
+
+ unsigned
+bx_floppy_ctrl_c::get_media_status(unsigned drive)
+{
+ return( BX_FD_THIS s.media_present[drive] );
+}
+
+#ifdef O_BINARY
+#define BX_RDONLY O_RDONLY | O_BINARY
+#define BX_RDWR O_RDWR | O_BINARY
+#else
+#define BX_RDONLY O_RDONLY
+#define BX_RDWR O_RDWR
+#endif
+
+ bx_bool
+bx_floppy_ctrl_c::evaluate_media(unsigned type, char *path, floppy_t *media)
+{
+ struct stat stat_buf;
+ int i, ret;
+ int idx = -1;
+#ifdef __linux__
+ struct floppy_struct floppy_geom;
+#endif
+#ifdef WIN32
+ char sTemp[1024];
+ bx_bool raw_floppy = 0;
+ HANDLE hFile;
+ DWORD bytes;
+ DISK_GEOMETRY dg;
+ unsigned tracks, heads, spt;
+#endif
+
+ if (type == BX_FLOPPY_NONE)
+ return(0);
+
+ //If media file is already open, close it before reopening.
+ if(media->fd >=0) {
+ close(media->fd);
+ media->fd=-1;
+ }
+
+ // open media file (image file or device)
+ media->write_protected = 0;
+#ifdef macintosh
+ media->fd = 0;
+ if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+#ifdef WIN32
+ if ( (isalpha(path[0])) && (path[1] == ':') && (strlen(path) == 2) ) {
+ raw_floppy = 1;
+ wsprintf(sTemp, "\\\\.\\%s", path);
+ hFile = CreateFile(sTemp, GENERIC_READ, FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ BX_ERROR(("Cannot open floppy drive"));
+ return(0);
+ } else {
+ if (!DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytes, NULL)) {
+ BX_ERROR(("No media in floppy drive"));
+ CloseHandle(hFile);
+ return(0);
+ } else {
+ tracks = (unsigned)dg.Cylinders.QuadPart;
+ heads = (unsigned)dg.TracksPerCylinder;
+ spt = (unsigned)dg.SectorsPerTrack;
+ }
+ CloseHandle(hFile);
+ }
+ media->fd = open(sTemp, BX_RDWR);
+ } else {
+ media->fd = open(path, BX_RDWR);
+ }
+#else
+ media->fd = open(path, BX_RDWR);
+#endif
+
+ if (media->fd < 0) {
+ BX_INFO(( "tried to open '%s' read/write: %s",path,strerror(errno) ));
+ // try opening the file read-only
+ media->write_protected = 1;
+#ifdef macintosh
+ media->fd = 0;
+ if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+#ifdef WIN32
+ if (raw_floppy == 1) {
+ media->fd = open(sTemp, BX_RDONLY);
+ } else {
+ media->fd = open(path, BX_RDONLY);
+ }
+#else
+ media->fd = open(path, BX_RDONLY);
+#endif
+ if (media->fd < 0) {
+ // failed to open read-only too
+ BX_INFO(( "tried to open '%s' read only: %s",path,strerror(errno) ));
+ media->type = type;
+ return(0);
+ }
+ }
+
+#if BX_WITH_MACOS
+ if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+ ret = fd_stat(&stat_buf);
+ else
+ ret = fstat(media->fd, &stat_buf);
+#elif defined(WIN32)
+ if (raw_floppy) {
+ memset (&stat_buf, 0, sizeof(stat_buf));
+ stat_buf.st_mode = S_IFCHR;
+ ret = 0;
+ } else {
+ ret = fstat(media->fd, &stat_buf);
+ }
+#else
+ // unix
+ ret = fstat(media->fd, &stat_buf);
+#endif
+ if (ret) {
+ BX_PANIC(("fstat floppy 0 drive image file returns error: %s", strerror(errno)));
+ return(0);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (type == floppy_type[i].id) idx = i;
+ }
+ if (idx == -1 ) {
+ BX_PANIC(("evaluate_media: unknown media type"));
+ return(0);
+ }
+ if ( S_ISREG(stat_buf.st_mode) ) {
+ // regular file
+ switch (type) {
+ // use CMOS reserved types
+ case BX_FLOPPY_160K: // 160K 5.25"
+ case BX_FLOPPY_180K: // 180K 5.25"
+ case BX_FLOPPY_320K: // 320K 5.25"
+ // standard floppy types
+ case BX_FLOPPY_360K: // 360K 5.25"
+ case BX_FLOPPY_720K: // 720K 3.5"
+ case BX_FLOPPY_1_2: // 1.2M 5.25"
+ case BX_FLOPPY_2_88: // 2.88M 3.5"
+ media->type = type;
+ media->tracks = floppy_type[idx].trk;
+ media->heads = floppy_type[idx].hd;
+ media->sectors_per_track = floppy_type[idx].spt;
+ media->sectors = floppy_type[idx].sectors;
+ if (stat_buf.st_size > (media->sectors * 512)) {
+ BX_INFO(("evaluate_media: size of file '%s' (%lu) too large for selected type",
+ path, (unsigned long) stat_buf.st_size));
+ return(0);
+ }
+ break;
+ default: // 1.44M 3.5"
+ media->type = type;
+ if (stat_buf.st_size <= 1474560) {
+ media->tracks = floppy_type[idx].trk;
+ media->heads = floppy_type[idx].hd;
+ media->sectors_per_track = floppy_type[idx].spt;
+ }
+ else if (stat_buf.st_size == 1720320) {
+ media->sectors_per_track = 21;
+ media->tracks = 80;
+ media->heads = 2;
+ }
+ else if (stat_buf.st_size == 1763328) {
+ media->sectors_per_track = 21;
+ media->tracks = 82;
+ media->heads = 2;
+ }
+ else {
+ BX_INFO(("evaluate_media: file '%s' of unknown size %lu",
+ path, (unsigned long) stat_buf.st_size));
+ return(0);
+ }
+ media->sectors = media->heads * media->tracks * media->sectors_per_track;
+ }
+ return(1); // success
+ }
+
+ else if ( S_ISCHR(stat_buf.st_mode)
+#if BX_WITH_MACOS == 0
+#ifdef S_ISBLK
+ || S_ISBLK(stat_buf.st_mode)
+#endif
+#endif
+ ) {
+ // character or block device
+ // assume media is formatted to typical geometry for drive
+ media->type = type;
+#ifdef __linux__
+ if (ioctl(media->fd, FDGETPRM, &floppy_geom) < 0) {
+ BX_ERROR(("cannot determine media geometry"));
+ return(0);
+ }
+ media->tracks = floppy_geom.track;
+ media->heads = floppy_geom.head;
+ media->sectors_per_track = floppy_geom.sect;
+ media->sectors = floppy_geom.size;
+#elif defined(WIN32)
+ media->tracks = tracks;
+ media->heads = heads;
+ media->sectors_per_track = spt;
+ media->sectors = media->heads * media->tracks * media->sectors_per_track;
+#else
+ media->tracks = floppy_type[idx].trk;
+ media->heads = floppy_type[idx].hd;
+ media->sectors_per_track = floppy_type[idx].spt;
+ media->sectors = floppy_type[idx].sectors;
+#endif
+ return(1); // success
+ }
+ else {
+ // unknown file type
+ BX_INFO(("unknown mode type"));
+ return(0);
+ }
+}
+
+
+void
+bx_floppy_ctrl_c::enter_result_phase(void)
+{
+
+ Bit8u drive;
+
+ drive = BX_FD_THIS s.DOR & 0x03;
+
+ /* these are always the same */
+ BX_FD_THIS s.result_index = 0;
+ BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+
+ /* invalid command */
+ if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x80) {
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ return;
+ }
+
+ switch (BX_FD_THIS s.pending_command) {
+ case 0x04: // get status
+ BX_FD_THIS s.result_size = 1;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg3;
+ break;
+ case 0x08: // sense interrupt
+ BX_FD_THIS s.result_size = 2;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
+ break;
+ case 0x4a: // read ID
+ case 0x4d: // format track
+ case 0x46: // read normal data
+ case 0x66:
+ case 0xc6:
+ case 0xe6:
+ case 0x45: // write normal data
+ case 0xc5:
+ BX_FD_THIS s.result_size = 7;
+ BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+ BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1;
+ BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2;
+ BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+ BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+ BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+ BX_FD_THIS s.result[6] = 2; /* sector size code */
+ raise_interrupt();
+ break;
+ }
+}
+
+void
+bx_floppy_ctrl_c::enter_idle_phase(void)
+{
+ BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched
+ BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready
+
+ BX_FD_THIS s.command_complete = 1; /* waiting for new command */
+ BX_FD_THIS s.command_index = 0;
+ BX_FD_THIS s.command_size = 0;
+ BX_FD_THIS s.pending_command = 0;
+
+ BX_FD_THIS s.floppy_buffer_index = 0;
+}
+
diff --git a/tools/ioemu/iodev/floppy.h b/tools/ioemu/iodev/floppy.h
new file mode 100644
index 0000000000..d874539900
--- /dev/null
+++ b/tools/ioemu/iodev/floppy.h
@@ -0,0 +1,138 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppy.h,v 1.16 2002/11/30 09:39:29 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#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;
+ } floppy_t;
+
+class bx_floppy_ctrl_c : public bx_floppy_stub_c {
+public:
+
+ bx_floppy_ctrl_c(void);
+ ~bx_floppy_ctrl_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+ virtual unsigned set_media_status(unsigned drive, unsigned status);
+ virtual unsigned get_media_status(unsigned drive);
+
+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
+
+ /* 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[2];
+ 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
+ } 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 enter_idle_phase(void);
+ BX_FD_SMF void enter_result_phase(void);
+ static void timer_handler(void *);
+
+public:
+ BX_FD_SMF void timer(void);
+ BX_FD_SMF void increment_sector(void);
+ BX_FD_SMF bx_bool evaluate_media(unsigned type, char *path, floppy_t *floppy);
+ };
diff --git a/tools/ioemu/iodev/gameport.cc b/tools/ioemu/iodev/gameport.cc
new file mode 100644
index 0000000000..9adefa6551
--- /dev/null
+++ b/tools/ioemu/iodev/gameport.cc
@@ -0,0 +1,242 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gameport.cc,v 1.5 2003/12/29 21:48:56 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// 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 "bochs.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_devices.pluginGameport = theGameport;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theGameport, BX_PLUGIN_GAMEPORT);
+ return(0); // Success
+}
+
+ void
+libgameport_LTX_plugin_fini(void)
+{
+}
+
+bx_gameport_c::bx_gameport_c(void)
+{
+ put("GAME");
+ settype(EXTFPUIRQLOG);
+}
+
+bx_gameport_c::~bx_gameport_c(void)
+{
+ 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::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_GAME_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_GAME_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_GAME_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_GAME_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;
+}
diff --git a/tools/ioemu/iodev/gameport.h b/tools/ioemu/iodev/gameport.h
new file mode 100644
index 0000000000..d4acdddf69
--- /dev/null
+++ b/tools/ioemu/iodev/gameport.h
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gameport.h,v 1.1 2003/06/21 12:55:19 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#if BX_USE_GAME_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(void);
+ ~bx_gameport_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+
+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_GAME_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+ };
diff --git a/tools/ioemu/iodev/guest2host.h b/tools/ioemu/iodev/guest2host.h
new file mode 100644
index 0000000000..0003662aa2
--- /dev/null
+++ b/tools/ioemu/iodev/guest2host.h
@@ -0,0 +1,77 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: guest2host.h,v 1.8 2002/12/06 18:48:08 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#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(void);
+ ~bx_g2h_c(void);
+ 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;
diff --git a/tools/ioemu/iodev/harddrv.cc b/tools/ioemu/iodev/harddrv.cc
new file mode 100644
index 0000000000..24a9d41efa
--- /dev/null
+++ b/tools/ioemu/iodev/harddrv.cc
@@ -0,0 +1,4880 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: harddrv.cc,v 1.114.2.2 2004/02/06 22:14:35 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// Useful docs:
+// AT Attachment with Packet Interface
+// working draft by T13 at www.t13.org
+
+
+
+// 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"
+
+#if BX_HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#define LOG_THIS theHardDrive->
+
+// WARNING: dangerous options!
+// These options provoke certain kinds of errors for testing purposes when they
+// are set to a nonzero value. DO NOT ENABLE THEM when using any disk image
+// you care about.
+#define TEST_READ_BEYOND_END 0
+#define TEST_WRITE_BEYOND_END 0
+#ifdef __GNUC__
+# if TEST_READ_BEYOND_END || TEST_WRITE_BEYOND_END
+# warning BEWARE: Dangerous options are enabled in harddrv.cc. If you are not trying to provoke hard drive errors you should disable them right now.
+# endif
+#endif
+// end of dangerous options.
+
+
+#define INDEX_PULSE_CYCLE 10
+
+#define PACKET_SIZE 12
+
+static unsigned max_multiple_sectors = 0; // was 0x3f
+static unsigned curr_multiple_sectors = 0; // was 0x3f
+
+// some packet handling macros
+#define EXTRACT_FIELD(arr,byte,start,num_bits) (((arr)[(byte)] >> (start)) & ((1 << (num_bits)) - 1))
+#define get_packet_field(c,b,s,n) (EXTRACT_FIELD((BX_SELECTED_CONTROLLER((c)).buffer),(b),(s),(n)))
+#define get_packet_byte(c,b) (BX_SELECTED_CONTROLLER((c)).buffer[(b)])
+#define get_packet_word(c,b) (((uint16)BX_SELECTED_CONTROLLER((c)).buffer[(b)] << 8) | BX_SELECTED_CONTROLLER((c)).buffer[(b)+1])
+
+
+#define BX_CONTROLLER(c,a) (BX_HD_THIS channels[(c)].drives[(a)]).controller
+#define BX_DRIVE(c,a) (BX_HD_THIS channels[(c)].drives[(a)])
+
+#define BX_DRIVE_IS_PRESENT(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type != IDE_NONE)
+#define BX_DRIVE_IS_HD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_DISK)
+#define BX_DRIVE_IS_CD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_CDROM)
+
+#define BX_MASTER_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),0)
+#define BX_SLAVE_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),1)
+#define BX_ANY_IS_PRESENT(c) (BX_DRIVE_IS_PRESENT((c),0) || BX_DRIVE_IS_PRESENT((c),1))
+
+#define BX_SELECTED_CONTROLLER(c) (BX_CONTROLLER((c),BX_HD_THIS channels[(c)].drive_select))
+#define BX_SELECTED_DRIVE(c) (BX_DRIVE((c),BX_HD_THIS channels[(c)].drive_select))
+#define BX_MASTER_SELECTED(c) (!BX_HD_THIS channels[(c)].drive_select)
+#define BX_SLAVE_SELECTED(c) (BX_HD_THIS channels[(c)].drive_select)
+
+#define BX_SELECTED_IS_PRESENT(c) (BX_DRIVE_IS_PRESENT((c),BX_SLAVE_SELECTED((c))))
+#define BX_SELECTED_IS_HD(c) (BX_DRIVE_IS_HD((c),BX_SLAVE_SELECTED((c))))
+#define BX_SELECTED_IS_CD(c) (BX_DRIVE_IS_CD((c),BX_SLAVE_SELECTED((c))))
+
+#define BX_SELECTED_MODEL(c) (BX_HD_THIS channels[(c)].drives[BX_HD_THIS channels[(c)].drive_select].model_no)
+#define BX_SELECTED_TYPE_STRING(channel) ((BX_SELECTED_IS_CD(channel)) ? "CD-ROM" : "DISK")
+
+#define WRITE_FEATURES(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).features = _a; BX_CONTROLLER((c),1).features = _a; } while(0)
+#define WRITE_SECTOR_COUNT(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_count = _a; BX_CONTROLLER((c),1).sector_count = _a; } while(0)
+#define WRITE_SECTOR_NUMBER(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_no = _a; BX_CONTROLLER((c),1).sector_no = _a; } while(0)
+#define WRITE_CYLINDER_LOW(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).cylinder_no = (BX_CONTROLLER((c),0).cylinder_no & 0xff00) | _a; BX_CONTROLLER((c),1).cylinder_no = (BX_CONTROLLER((c),1).cylinder_no & 0xff00) | _a; } while(0)
+#define WRITE_CYLINDER_HIGH(c,a) do { uint16 _a = a; BX_CONTROLLER((c),0).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),0).cylinder_no & 0xff); BX_CONTROLLER((c),1).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),1).cylinder_no & 0xff); } while(0)
+#define WRITE_HEAD_NO(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).head_no = _a; BX_CONTROLLER((c),1).head_no = _a; } while(0)
+#define WRITE_LBA_MODE(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).lba_mode = _a; BX_CONTROLLER((c),1).lba_mode = _a; } while(0)
+
+bx_hard_drive_c *theHardDrive = NULL;
+
+ int
+libharddrv_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theHardDrive = new bx_hard_drive_c ();
+ bx_devices.pluginHardDrive = theHardDrive;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theHardDrive, BX_PLUGIN_HARDDRV);
+ return(0); // Success
+}
+
+ void
+libharddrv_LTX_plugin_fini(void)
+{
+}
+
+bx_hard_drive_c::bx_hard_drive_c(void)
+{
+#if DLL_HD_SUPPORT
+# error code must be fixed to use DLL_HD_SUPPORT and 4 ata channels
+#endif
+
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ channels[channel].drives[0].hard_drive = NULL;
+ channels[channel].drives[1].hard_drive = NULL;
+ put("HD");
+ settype(HDLOG);
+ }
+}
+
+
+bx_hard_drive_c::~bx_hard_drive_c(void)
+{
+ BX_DEBUG(("Exit."));
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if (channels[channel].drives[0].hard_drive != NULL ) /* DT 17.12.2001 21:55 */
+ {
+ delete channels[channel].drives[0].hard_drive;
+ channels[channel].drives[0].hard_drive = NULL;
+ }
+ if ( channels[channel].drives[1].hard_drive != NULL )
+ {
+ delete channels[channel].drives[1].hard_drive;
+ channels[channel].drives[1].hard_drive = NULL; /* DT 17.12.2001 21:56 */
+ }
+ }
+}
+
+
+
+
+ void
+bx_hard_drive_c::init(void)
+{
+ Bit8u channel;
+ char string[5];
+
+ BX_DEBUG(("Init $Id: harddrv.cc,v 1.114.2.2 2004/02/06 22:14:35 danielg4 Exp $"));
+
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if (bx_options.ata[channel].Opresent->get() == 1) {
+ BX_HD_THIS channels[channel].ioaddr1 = bx_options.ata[channel].Oioaddr1->get();
+ BX_HD_THIS channels[channel].ioaddr2 = bx_options.ata[channel].Oioaddr2->get();
+ BX_HD_THIS channels[channel].irq = bx_options.ata[channel].Oirq->get();
+
+ // Coherency check
+ if ( (BX_HD_THIS channels[channel].ioaddr1 == 0) ||
+ (BX_HD_THIS channels[channel].ioaddr2 == 0) ||
+ (BX_HD_THIS channels[channel].irq == 0) ) {
+ BX_PANIC(("incoherency for ata channel %d: io1=0x%x, io2=%x, irq=%d",
+ channel,
+ BX_HD_THIS channels[channel].ioaddr1,
+ BX_HD_THIS channels[channel].ioaddr2,
+ BX_HD_THIS channels[channel].irq));
+ }
+ }
+ else {
+ BX_HD_THIS channels[channel].ioaddr1 = 0;
+ BX_HD_THIS channels[channel].ioaddr2 = 0;
+ BX_HD_THIS channels[channel].irq = 0;
+ }
+ }
+
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ sprintf(string ,"ATA%d", channel);
+
+ if (BX_HD_THIS channels[channel].irq != 0)
+ DEV_register_irq(BX_HD_THIS channels[channel].irq, strdup(string));
+
+ if (BX_HD_THIS channels[channel].ioaddr1 != 0) {
+ DEV_register_ioread_handler(this, read_handler,
+ BX_HD_THIS channels[channel].ioaddr1, strdup(string), 6);
+ DEV_register_iowrite_handler(this, write_handler,
+ BX_HD_THIS channels[channel].ioaddr1, strdup(string), 6);
+ for (unsigned addr=0x1; addr<=0x7; addr++) {
+ DEV_register_ioread_handler(this, read_handler,
+ BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string), 1);
+ DEV_register_iowrite_handler(this, write_handler,
+ BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string), 1);
+ }
+ }
+
+ // We don't want to register addresses 0x3f6 and 0x3f7 as they are handled by the floppy controller
+ if ((BX_HD_THIS channels[channel].ioaddr2 != 0) && (BX_HD_THIS channels[channel].ioaddr2 != 0x3f0)) {
+ for (unsigned addr=0x6; addr<=0x7; addr++) {
+ DEV_register_ioread_handler(this, read_handler,
+ BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string), 1);
+ DEV_register_iowrite_handler(this, write_handler,
+ BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string), 1);
+ }
+ }
+
+ BX_HD_THIS channels[channel].drive_select = 0;
+ }
+
+ channel = 0;
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ for (Bit8u device=0; device<2; device ++) {
+
+ // Initialize controller state, even if device is not present
+ BX_CONTROLLER(channel,device).status.busy = 0;
+ BX_CONTROLLER(channel,device).status.drive_ready = 1;
+ BX_CONTROLLER(channel,device).status.write_fault = 0;
+ BX_CONTROLLER(channel,device).status.seek_complete = 1;
+ BX_CONTROLLER(channel,device).status.drq = 0;
+ BX_CONTROLLER(channel,device).status.corrected_data = 0;
+ BX_CONTROLLER(channel,device).status.index_pulse = 0;
+ BX_CONTROLLER(channel,device).status.index_pulse_count = 0;
+ BX_CONTROLLER(channel,device).status.err = 0;
+
+ BX_CONTROLLER(channel,device).error_register = 0x01; // diagnostic code: no error
+ BX_CONTROLLER(channel,device).head_no = 0;
+ BX_CONTROLLER(channel,device).sector_count = 1;
+ BX_CONTROLLER(channel,device).sector_no = 1;
+ BX_CONTROLLER(channel,device).cylinder_no = 0;
+ BX_CONTROLLER(channel,device).current_command = 0x00;
+ BX_CONTROLLER(channel,device).buffer_index = 0;
+
+ BX_CONTROLLER(channel,device).control.reset = 0;
+ BX_CONTROLLER(channel,device).control.disable_irq = 0;
+ BX_CONTROLLER(channel,device).reset_in_progress = 0;
+
+ BX_CONTROLLER(channel,device).sectors_per_block = 0x80;
+ BX_CONTROLLER(channel,device).lba_mode = 0;
+
+ BX_CONTROLLER(channel,device).features = 0;
+
+ // If not present
+ BX_HD_THIS channels[channel].drives[device].device_type = IDE_NONE;
+ if (!bx_options.atadevice[channel][device].Opresent->get()) {
+ continue;
+ }
+
+ // Make model string
+ strncpy((char*)BX_HD_THIS channels[channel].drives[device].model_no,
+ bx_options.atadevice[channel][device].Omodel->getptr(), 40);
+ while (strlen((char *)BX_HD_THIS channels[channel].drives[device].model_no) < 40) {
+ strcat ((char*)BX_HD_THIS channels[channel].drives[device].model_no, " ");
+ }
+
+ if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_DISK) {
+ BX_DEBUG(( "Hard-Disk on target %d/%d",channel,device));
+ BX_HD_THIS channels[channel].drives[device].device_type = IDE_DISK;
+
+ int cyl = bx_options.atadevice[channel][device].Ocylinders->get ();
+ int heads = bx_options.atadevice[channel][device].Oheads->get ();
+ int spt = bx_options.atadevice[channel][device].Ospt->get ();
+ Bit64u disk_size = (Bit64u)cyl * heads * spt * 512;
+
+ /* instantiate the right class */
+ switch (bx_options.atadevice[channel][device].Omode->get()) {
+
+ case BX_ATA_MODE_FLAT:
+ BX_INFO(("HD on ata%d-%d: '%s' 'flat' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new default_image_t();
+ break;
+
+ case BX_ATA_MODE_CONCAT:
+ BX_INFO(("HD on ata%d-%d: '%s' 'concat' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new concat_image_t();
+ break;
+
+#if EXTERNAL_DISK_SIMULATOR
+ case BX_ATA_MODE_EXTDISKSIM:
+ BX_INFO(("HD on ata%d-%d: '%s' 'External Simulator' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new EXTERNAL_DISK_SIMULATOR_CLASS();
+ break;
+#endif //EXTERNAL_DISK_SIMULATOR
+
+#if DLL_HD_SUPPORT
+ case BX_ATA_MODE_DLL_HD:
+ BX_INFO(("HD on ata%d-%d: '%s' 'dll' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new dll_image_t();
+ break;
+#endif //DLL_HD_SUPPORT
+
+ case BX_ATA_MODE_SPARSE:
+ BX_INFO(("HD on ata%d-%d: '%s' 'sparse' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new sparse_image_t();
+ break;
+
+#if 0
+ case BX_ATA_MODE_VMWARE3:
+ BX_INFO(("HD on ata%d-%d: '%s' 'vmware3' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new vmware3_image_t();
+ break;
+
+ case BX_ATA_MODE_SPLIT:
+ BX_INFO(("HD on ata%d-%d: '%s' 'split' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new split_image_t();
+ break;
+#endif
+
+ case BX_ATA_MODE_UNDOABLE:
+ BX_INFO(("HD on ata%d-%d: '%s' 'undoable' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new undoable_image_t(disk_size,
+ bx_options.atadevice[channel][device].Ojournal->getptr());
+ break;
+
+ case BX_ATA_MODE_GROWING:
+ BX_INFO(("HD on ata%d-%d: '%s' 'growing' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new growing_image_t(disk_size);
+ break;
+
+ case BX_ATA_MODE_VOLATILE:
+ BX_INFO(("HD on ata%d-%d: '%s' 'volatile' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new volatile_image_t(disk_size,
+ bx_options.atadevice[channel][device].Ojournal->getptr());
+ break;
+
+#if 0
+#if BX_COMPRESSED_HD_SUPPORT
+ case BX_ATA_MODE_Z_UNDOABLE:
+ BX_PANIC(("z-undoable disk support not implemented"));
+ BX_INFO(("HD on ata%d-%d: '%s' 'z-undoable' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new z_undoable_image_t(disk_size,
+ bx_options.atadevice[channel][device].Ojournal->getptr());
+ break;
+
+ case BX_ATA_MODE_Z_VOLATILE:
+ BX_PANIC(("z-volatile disk support not implemented"));
+ BX_INFO(("HD on ata%d-%d: '%s' 'z-volatile' mode ", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr ()));
+ channels[channel].drives[device].hard_drive = new z_volatile_image_t(disk_size,
+ bx_options.atadevice[channel][device].Ojournal->getptr());
+ break;
+#endif //BX_COMPRESSED_HD_SUPPORT
+#endif
+
+ default:
+ BX_PANIC(("HD on ata%d-%d: '%s' unsupported HD mode : %s", channel, device,
+ bx_options.atadevice[channel][device].Opath->getptr (),
+ atadevice_mode_names[bx_options.atadevice[channel][device].Omode->get()]));
+ break;
+ }
+
+ BX_HD_THIS channels[channel].drives[device].hard_drive->cylinders = cyl;
+ BX_HD_THIS channels[channel].drives[device].hard_drive->heads = heads;
+ BX_HD_THIS channels[channel].drives[device].hard_drive->sectors = spt;
+
+ if (cyl == 0 || heads == 0 || spt == 0) {
+ BX_PANIC(("ata%d/%d cannot have zero cylinders, heads, or sectors/track", channel, device));
+ }
+
+ /* open hard drive image file */
+ if ((BX_HD_THIS channels[channel].drives[device].hard_drive->open(bx_options.atadevice[channel][device].Opath->getptr ())) < 0) {
+ BX_PANIC(("ata%d-%d: could not open hard drive image file '%s'", channel, device, bx_options.atadevice[channel][device].Opath->getptr ()));
+ }
+ }
+ else if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_CDROM) {
+ BX_DEBUG(( "CDROM on target %d/%d",channel,device));
+ BX_HD_THIS channels[channel].drives[device].device_type = IDE_CDROM;
+ BX_HD_THIS channels[channel].drives[device].cdrom.locked = 0;
+ BX_HD_THIS channels[channel].drives[device].sense.sense_key = SENSE_NONE;
+ BX_HD_THIS channels[channel].drives[device].sense.asc = 0;
+ BX_HD_THIS channels[channel].drives[device].sense.ascq = 0;
+
+ // Check bit fields
+ BX_CONTROLLER(channel,device).sector_count = 0;
+ BX_CONTROLLER(channel,device).interrupt_reason.c_d = 1;
+ if (BX_CONTROLLER(channel,device).sector_count != 0x01)
+ BX_PANIC(("interrupt reason bit field error"));
+
+ BX_CONTROLLER(channel,device).sector_count = 0;
+ BX_CONTROLLER(channel,device).interrupt_reason.i_o = 1;
+ if (BX_CONTROLLER(channel,device).sector_count != 0x02)
+ BX_PANIC(("interrupt reason bit field error"));
+
+ BX_CONTROLLER(channel,device).sector_count = 0;
+ BX_CONTROLLER(channel,device).interrupt_reason.rel = 1;
+ if (BX_CONTROLLER(channel,device).sector_count != 0x04)
+ BX_PANIC(("interrupt reason bit field error"));
+
+ BX_CONTROLLER(channel,device).sector_count = 0;
+ BX_CONTROLLER(channel,device).interrupt_reason.tag = 3;
+ if (BX_CONTROLLER(channel,device).sector_count != 0x18)
+ BX_PANIC(("interrupt reason bit field error"));
+ BX_CONTROLLER(channel,device).sector_count = 0;
+
+ // allocate low level driver
+#ifdef LOWLEVEL_CDROM
+ BX_HD_THIS channels[channel].drives[device].cdrom.cd = new LOWLEVEL_CDROM(bx_options.atadevice[channel][device].Opath->getptr ());
+ BX_INFO(("CD on ata%d-%d: '%s'",channel, device, bx_options.atadevice[channel][device].Opath->getptr ()));
+
+ if (bx_options.atadevice[channel][device].Ostatus->get () == BX_INSERTED) {
+ if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom()) {
+ BX_INFO(( "Media present in CD-ROM drive"));
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
+ BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
+ } else {
+ BX_INFO(( "Could not locate CD-ROM, continuing with media not present"));
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+ }
+ } else {
+#endif
+ BX_INFO(( "Media not present in CD-ROM drive" ));
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+#ifdef LOWLEVEL_CDROM
+ }
+#endif
+ }
+ }
+ }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+ BX_HD_THIS pdc20230c.prog_mode = 0;
+ BX_HD_THIS pdc20230c.prog_count = 0;
+ BX_HD_THIS pdc20230c.p1f3_value = 0;
+ BX_HD_THIS pdc20230c.p1f4_value = 0;
+#endif
+
+
+ // generate CMOS values for hard drive if not using a CMOS image
+ if (!bx_options.cmos.OcmosImage->get ()) {
+ DEV_cmos_set_reg(0x12, 0x00); // start out with: no drive 0, no drive 1
+
+ if (BX_DRIVE_IS_HD(0,0)) {
+ // Flag drive type as Fh, use extended CMOS location as real type
+ DEV_cmos_set_reg(0x12, (DEV_cmos_get_reg(0x12) & 0x0f) | 0xf0);
+ DEV_cmos_set_reg(0x19, 47); // user definable type
+ // AMI BIOS: 1st hard disk #cyl low byte
+ DEV_cmos_set_reg(0x1b, (bx_options.atadevice[0][0].Ocylinders->get () & 0x00ff));
+ // AMI BIOS: 1st hard disk #cyl high byte
+ DEV_cmos_set_reg(0x1c, (bx_options.atadevice[0][0].Ocylinders->get () & 0xff00) >> 8);
+ // AMI BIOS: 1st hard disk #heads
+ DEV_cmos_set_reg(0x1d, (bx_options.atadevice[0][0].Oheads->get ()));
+ // AMI BIOS: 1st hard disk write precompensation cylinder, low byte
+ DEV_cmos_set_reg(0x1e, 0xff); // -1
+ // AMI BIOS: 1st hard disk write precompensation cylinder, high byte
+ DEV_cmos_set_reg(0x1f, 0xff); // -1
+ // AMI BIOS: 1st hard disk control byte
+ DEV_cmos_set_reg(0x20, (0xc0 | ((bx_options.atadevice[0][0].Oheads->get () > 8) << 3)));
+ // AMI BIOS: 1st hard disk landing zone, low byte
+ DEV_cmos_set_reg(0x21, DEV_cmos_get_reg(0x1b));
+ // AMI BIOS: 1st hard disk landing zone, high byte
+ DEV_cmos_set_reg(0x22, DEV_cmos_get_reg(0x1c));
+ // AMI BIOS: 1st hard disk sectors/track
+ DEV_cmos_set_reg(0x23, bx_options.atadevice[0][0].Ospt->get ());
+ }
+
+ //set up cmos for second hard drive
+ if (BX_DRIVE_IS_HD(0,1)) {
+ BX_DEBUG(("1: I will put 0xf into the second hard disk field"));
+ // fill in lower 4 bits of 0x12 for second HD
+ DEV_cmos_set_reg(0x12, (DEV_cmos_get_reg(0x12) & 0xf0) | 0x0f);
+ DEV_cmos_set_reg(0x1a, 47); // user definable type
+ // AMI BIOS: 2nd hard disk #cyl low byte
+ DEV_cmos_set_reg(0x24, (bx_options.atadevice[0][1].Ocylinders->get () & 0x00ff));
+ // AMI BIOS: 2nd hard disk #cyl high byte
+ DEV_cmos_set_reg(0x25, (bx_options.atadevice[0][1].Ocylinders->get () & 0xff00) >> 8);
+ // AMI BIOS: 2nd hard disk #heads
+ DEV_cmos_set_reg(0x26, (bx_options.atadevice[0][1].Oheads->get ()));
+ // AMI BIOS: 2nd hard disk write precompensation cylinder, low byte
+ DEV_cmos_set_reg(0x27, 0xff); // -1
+ // AMI BIOS: 2nd hard disk write precompensation cylinder, high byte
+ DEV_cmos_set_reg(0x28, 0xff); // -1
+ // AMI BIOS: 2nd hard disk, 0x80 if heads>8
+ DEV_cmos_set_reg(0x29, (bx_options.atadevice[0][1].Oheads->get () > 8) ? 0x80 : 0x00);
+ // AMI BIOS: 2nd hard disk landing zone, low byte
+ DEV_cmos_set_reg(0x2a, DEV_cmos_get_reg(0x24));
+ // AMI BIOS: 2nd hard disk landing zone, high byte
+ DEV_cmos_set_reg(0x2b, DEV_cmos_get_reg(0x25));
+ // AMI BIOS: 2nd hard disk sectors/track
+ DEV_cmos_set_reg(0x2c, bx_options.atadevice[0][1].Ospt->get ());
+ }
+
+ DEV_cmos_set_reg(0x39, 0);
+ DEV_cmos_set_reg(0x3a, 0);
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ for (Bit8u device=0; device<2; device ++) {
+ if (bx_options.atadevice[channel][device].Opresent->get()) {
+ if (BX_DRIVE_IS_HD(channel,device)) {
+ Bit16u cylinders = bx_options.atadevice[channel][device].Ocylinders->get();
+ Bit16u heads = bx_options.atadevice[channel][device].Oheads->get();
+ Bit16u spt = bx_options.atadevice[channel][device].Ospt->get();
+ Bit8u translation = bx_options.atadevice[channel][device].Otranslation->get();
+
+ Bit8u reg = 0x39 + channel/2;
+ Bit8u bitshift = 2 * (device+(2 * (channel%2)));
+
+ // Find the right translation if autodetect
+ if (translation == BX_ATA_TRANSLATION_AUTO) {
+ if((cylinders <= 1024) && (heads <= 16) && (spt <= 63)) {
+ translation = BX_ATA_TRANSLATION_NONE;
+ }
+ else if (((Bit32u)cylinders * (Bit32u)heads) <= 131072) {
+ translation = BX_ATA_TRANSLATION_LARGE;
+ }
+ else translation = BX_ATA_TRANSLATION_LBA;
+
+ BX_INFO(("translation on ata%d-%d set to '%s'",channel, device,
+ translation==BX_ATA_TRANSLATION_NONE?"none":
+ translation==BX_ATA_TRANSLATION_LARGE?"large":
+ "lba"));
+ }
+
+ // FIXME we should test and warn
+ // - if LBA and spt != 63
+ // - if RECHS and heads != 16
+ // - if NONE and size > 1024*16*SPT blocks
+ // - if LARGE and size > 8192*16*SPT blocks
+ // - if RECHS and size > 1024*240*SPT blocks
+ // - if LBA and size > 1024*255*63, not that we can do much about it
+
+ switch(translation) {
+ case BX_ATA_TRANSLATION_NONE:
+ DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (0 << bitshift));
+ break;
+ case BX_ATA_TRANSLATION_LBA:
+ DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (1 << bitshift));
+ break;
+ case BX_ATA_TRANSLATION_LARGE:
+ DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (2 << bitshift));
+ break;
+ case BX_ATA_TRANSLATION_RECHS:
+ DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (3 << bitshift));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Set the "non-extended" boot device. This will default to DISKC if cdrom
+ if ( bx_options.Obootdrive->get () != BX_BOOT_FLOPPYA) {
+ // system boot sequence C:, A:
+ DEV_cmos_set_reg(0x2d, DEV_cmos_get_reg(0x2d) & 0xdf);
+ }
+ else { // 'a'
+ // system boot sequence A:, C:
+ DEV_cmos_set_reg(0x2d, DEV_cmos_get_reg(0x2d) | 0x20);
+ }
+
+ // Set the "extended" boot device, byte 0x3D (needed for cdrom booting)
+ if ( bx_options.Obootdrive->get () == BX_BOOT_FLOPPYA) {
+ // system boot sequence A:
+ DEV_cmos_set_reg(0x3d, 0x01);
+ BX_INFO(("Boot device will be 'a'"));
+ }
+ else if ( bx_options.Obootdrive->get () == BX_BOOT_DISKC) {
+ // system boot sequence C:
+ DEV_cmos_set_reg(0x3d, 0x02);
+ BX_INFO(("Boot device will be 'c'"));
+ }
+ else if ( bx_options.Obootdrive->get () == BX_BOOT_CDROM) {
+ // system boot sequence cdrom
+ DEV_cmos_set_reg(0x3d, 0x03);
+ BX_INFO(("Boot device will be 'cdrom'"));
+ }
+
+ // Set the signature check flag in cmos, inverted for compatibility
+ DEV_cmos_set_reg(0x38, bx_options.OfloppySigCheck->get());
+ BX_INFO(("Floppy boot signature check is %sabled", bx_options.OfloppySigCheck->get() ? "dis" : "en"));
+ }
+
+}
+
+ void
+bx_hard_drive_c::reset(unsigned type)
+{
+ for (unsigned channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if (BX_HD_THIS channels[channel].irq)
+ DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+ }
+}
+
+
+#define GOTO_RETURN_VALUE if(io_len==4){\
+ goto return_value32;\
+ }\
+ else if(io_len==2){\
+ value16=(Bit16u)value32;\
+ goto return_value16;\
+ }\
+ else{\
+ value8=(Bit8u)value32;\
+ goto return_value8;\
+ }
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_hard_drive_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_HD_SMF
+ bx_hard_drive_c *class_ptr = (bx_hard_drive_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_hard_drive_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_HD_SMF
+ Bit8u value8;
+ Bit16u value16;
+ Bit32u value32;
+
+ Bit8u channel = BX_MAX_ATA_CHANNEL;
+ Bit32u port = 0xff; // undefined
+
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr1) {
+ port = address - BX_HD_THIS channels[channel].ioaddr1;
+ break;
+ }
+ else if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr2) {
+ port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10;
+ break;
+ }
+ }
+
+ if (channel == BX_MAX_ATA_CHANNEL) {
+ if ((address < 0x03f6) || (address > 0x03f7)) {
+ BX_PANIC(("read: unable to find ATA channel, ioport=0x%04x", address));
+ } else {
+ channel = 0;
+ port = address - 0x03e0;
+ }
+ }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20230c is only available for first ata channel
+if (channel == 0) {
+
+ // Detect the switch to programming mode
+ if (!BX_HD_THIS pdc20230c.prog_mode) {
+ switch (port) {
+ case 0x02:
+ if ((BX_HD_THIS pdc20230c.prog_count == 0) || (BX_HD_THIS pdc20230c.prog_count > 2)) {
+ BX_HD_THIS pdc20230c.prog_count++;
+ }
+ else {
+ BX_HD_THIS pdc20230c.prog_count=0;
+ }
+ break;
+ case 0x16:
+ if ((BX_HD_THIS pdc20230c.prog_count == 1) || (BX_HD_THIS pdc20230c.prog_count == 2)) {
+ BX_HD_THIS pdc20230c.prog_count++;
+ }
+ else {
+ BX_HD_THIS pdc20230c.prog_count=0;
+ }
+ break;
+ default:
+ BX_HD_THIS pdc20230c.prog_count=0;
+ }
+
+ if (BX_HD_THIS pdc20230c.prog_count == 5) {
+ BX_HD_THIS pdc20230c.prog_mode = 1;
+ BX_SELECTED_CONTROLLER(channel).sector_count &= 0x7f;
+ BX_INFO(("Promise VLB-IDE DC2300: Switching to Programming mode"));
+ }
+ }
+
+ // Returns value when in programming mode
+ if (BX_HD_THIS pdc20230c.prog_mode) {
+ switch (port) {
+ case 0x05:
+ // Leave programming mode
+ BX_HD_THIS pdc20230c.prog_mode = 0;
+ BX_INFO(("Promise VLB-IDE DC2300: Leaving Programming mode"));
+ // Value will be sent be normal code
+ break;
+ case 0x03:
+ // Special programming register
+ value32 = BX_HD_THIS pdc20230c.p1f3_value;
+ GOTO_RETURN_VALUE ;
+ break;
+ case 0x04:
+ // Special programming register
+ value32 = BX_HD_THIS pdc20230c.p1f4_value;
+ GOTO_RETURN_VALUE ;
+ break;
+ }
+ }
+}
+#endif
+
+ switch (port) {
+ case 0x00: // hard disk data (16bit) 0x1f0
+ if (BX_SELECTED_CONTROLLER(channel).status.drq == 0) {
+ BX_ERROR(("IO read(0x%04x) with drq == 0: last command was %02xh",
+ address, (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+ return(0);
+ }
+ BX_DEBUG(("IO read(0x%04x): current command is %02xh",
+ address, (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+ switch (BX_SELECTED_CONTROLLER(channel).current_command) {
+ case 0x20: // READ SECTORS, with retries
+ case 0x21: // READ SECTORS, without retries
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512)
+ BX_PANIC(("IO read(0x%04x): buffer_index >= 512", address));
+
+#if BX_SupportRepeatSpeedups
+ if (DEV_bulk_io_quantum_requested()) {
+ unsigned transferLen, quantumsMax;
+
+ quantumsMax =
+ (512 - BX_SELECTED_CONTROLLER(channel).buffer_index) / io_len;
+ if ( quantumsMax == 0)
+ BX_PANIC(("IO read(0x%04x): not enough space for read", address));
+ DEV_bulk_io_quantum_transferred() =
+ DEV_bulk_io_quantum_requested();
+ if (quantumsMax < DEV_bulk_io_quantum_transferred())
+ DEV_bulk_io_quantum_transferred() = quantumsMax;
+ transferLen = io_len * DEV_bulk_io_quantum_transferred();
+ memcpy((Bit8u*) DEV_bulk_io_host_addr(),
+ &BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index],
+ transferLen);
+ DEV_bulk_io_host_addr() += transferLen;
+ BX_SELECTED_CONTROLLER(channel).buffer_index += transferLen;
+ value32 = 0; // Value returned not important;
+ }
+ else
+#endif
+ {
+ value32 = 0L;
+ switch(io_len){
+ case 4:
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] << 24);
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] << 16);
+ case 2:
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] << 8);
+ value32 |= BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index];
+ }
+ BX_SELECTED_CONTROLLER(channel).buffer_index += io_len;
+ }
+
+ // if buffer completely read
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+ // update sector count, sector number, cylinder,
+ // drive, head, status
+ // if there are more sectors, read next one in...
+ //
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+
+ increment_address(channel);
+
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ if (bx_options.OnewHardDriveSupport->get ())
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ else
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ if (BX_SELECTED_CONTROLLER(channel).sector_count==0) {
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ }
+ else { /* read next one into controller buffer */
+ off_t logical_sector;
+ off_t ret;
+
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+
+#if TEST_READ_BEYOND_END==1
+ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+ if (!calculate_logical_address(channel, &logical_sector)) {
+ BX_ERROR(("multi-sector read reached invalid sector %lu, aborting", (unsigned long)logical_sector));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ GOTO_RETURN_VALUE ;
+ }
+ ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+ if (ret < 0) {
+ BX_ERROR(("could not lseek() hard drive image file"));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ GOTO_RETURN_VALUE ;
+ }
+ ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+ if (ret < 512) {
+ BX_ERROR(("logical sector was %lu", (unsigned long)logical_sector));
+ BX_ERROR(("could not read() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ GOTO_RETURN_VALUE ;
+ }
+
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ raise_interrupt(channel);
+ }
+ }
+ GOTO_RETURN_VALUE ;
+ break;
+
+ case 0xec: // IDENTIFY DEVICE
+ case 0xa1:
+ if (bx_options.OnewHardDriveSupport->get ()) {
+ unsigned index;
+
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ index = BX_SELECTED_CONTROLLER(channel).buffer_index;
+ value32 = BX_SELECTED_CONTROLLER(channel).buffer[index];
+ index++;
+ if (io_len >= 2) {
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 8);
+ index++;
+ }
+ if (io_len == 4) {
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 16);
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+1] << 24);
+ index += 2;
+ }
+ BX_SELECTED_CONTROLLER(channel).buffer_index = index;
+
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("Read all drive ID Bytes ..."));
+ }
+ GOTO_RETURN_VALUE;
+ }
+ else
+ BX_PANIC(("IO read(0x%04x): current command is %02xh", address,
+ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+
+ case 0xa0: {
+ unsigned index = BX_SELECTED_CONTROLLER(channel).buffer_index;
+ unsigned increment = 0;
+
+ // Load block if necessary
+ if (index >= 2048) {
+ if (index > 2048)
+ BX_PANIC(("index > 2048 : 0x%x",index));
+ switch (BX_SELECTED_DRIVE(channel).atapi.command) {
+ case 0x28: // read (10)
+ case 0xa8: // read (12)
+#ifdef LOWLEVEL_CDROM
+ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ BX_PANIC(("Read with CDROM not ready"));
+ }
+ BX_SELECTED_DRIVE(channel).cdrom.cd->read_block(BX_SELECTED_CONTROLLER(channel).buffer,
+ BX_SELECTED_DRIVE(channel).cdrom.next_lba);
+ BX_SELECTED_DRIVE(channel).cdrom.next_lba++;
+ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks--;
+
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ if (!BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks)
+ BX_INFO(("Last READ block loaded {CDROM}"));
+ else
+ BX_INFO(("READ block loaded (%d remaining) {CDROM}",
+ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks));
+
+ // one block transfered, start at beginning
+ index = 0;
+#else
+ BX_PANIC(("Read with no LOWLEVEL_CDROM"));
+#endif
+ break;
+
+ default: // no need to load a new block
+ break;
+ }
+ }
+
+ value32 = BX_SELECTED_CONTROLLER(channel).buffer[index+increment];
+ increment++;
+ if (io_len >= 2) {
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 8);
+ increment++;
+ }
+ if (io_len == 4) {
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 16);
+ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment+1] << 24);
+ increment += 2;
+ }
+ BX_SELECTED_CONTROLLER(channel).buffer_index = index + increment;
+ BX_SELECTED_CONTROLLER(channel).drq_index += increment;
+
+ if (BX_SELECTED_CONTROLLER(channel).drq_index >= (unsigned)BX_SELECTED_DRIVE(channel).atapi.drq_bytes) {
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).drq_index = 0;
+
+ BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining -= BX_SELECTED_DRIVE(channel).atapi.drq_bytes;
+
+ if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining > 0) {
+ // one or more blocks remaining (works only for single block commands)
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("PACKET drq bytes read"));
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0;
+
+ // set new byte count if last block
+ if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining < BX_SELECTED_CONTROLLER(channel).byte_count) {
+ BX_SELECTED_CONTROLLER(channel).byte_count = BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining;
+ }
+ BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count;
+
+ raise_interrupt(channel);
+ } else {
+ // all bytes read
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("PACKET all bytes read"));
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ raise_interrupt(channel);
+ }
+ }
+ GOTO_RETURN_VALUE;
+ break;
+ }
+
+ // List all the read operations that are defined in the ATA/ATAPI spec
+ // that we don't support. Commands that are listed here will cause a
+ // BX_ERROR, which is non-fatal, and the command will be aborted.
+ case 0x08: BX_ERROR(("read cmd 0x08 (DEVICE RESET) not supported")); command_aborted(channel, 0x08); break;
+ case 0x10: BX_ERROR(("read cmd 0x10 (RECALIBRATE) not supported")); command_aborted(channel, 0x10); break;
+ case 0x22: BX_ERROR(("read cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break;
+ case 0x23: BX_ERROR(("read cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break;
+ case 0x24: BX_ERROR(("read cmd 0x24 (READ SECTORS EXT) not supported")); command_aborted(channel, 0x24); break;
+ case 0x25: BX_ERROR(("read cmd 0x25 (READ DMA EXT) not supported")); command_aborted(channel, 0x25); break;
+ case 0x26: BX_ERROR(("read cmd 0x26 (READ DMA QUEUED EXT) not supported")); command_aborted(channel, 0x26); break;
+ case 0x27: BX_ERROR(("read cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x27); break;
+ case 0x29: BX_ERROR(("read cmd 0x29 (READ MULTIPLE EXT) not supported")); command_aborted(channel, 0x29); break;
+ case 0x2A: BX_ERROR(("read cmd 0x2A (READ STREAM DMA) not supported")); command_aborted(channel, 0x2A); break;
+ case 0x2B: BX_ERROR(("read cmd 0x2B (READ STREAM PIO) not supported")); command_aborted(channel, 0x2B); break;
+ case 0x2F: BX_ERROR(("read cmd 0x2F (READ LOG EXT) not supported")); command_aborted(channel, 0x2F); break;
+ case 0x30: BX_ERROR(("read cmd 0x30 (WRITE SECTORS) not supported")); command_aborted(channel, 0x30); break;
+ case 0x31: BX_ERROR(("read cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break;
+ case 0x32: BX_ERROR(("read cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break;
+ case 0x33: BX_ERROR(("read cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break;
+ case 0x34: BX_ERROR(("read cmd 0x34 (WRITE SECTORS EXT) not supported")); command_aborted(channel, 0x34); break;
+ case 0x35: BX_ERROR(("read cmd 0x35 (WRITE DMA EXT) not supported")); command_aborted(channel, 0x35); break;
+ case 0x36: BX_ERROR(("read cmd 0x36 (WRITE DMA QUEUED EXT) not supported")); command_aborted(channel, 0x36); break;
+ case 0x37: BX_ERROR(("read cmd 0x37 (SET MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x37); break;
+ case 0x38: BX_ERROR(("read cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported")); command_aborted(channel, 0x38); break;
+ case 0x39: BX_ERROR(("read cmd 0x39 (WRITE MULTIPLE EXT) not supported")); command_aborted(channel, 0x39); break;
+ case 0x3A: BX_ERROR(("read cmd 0x3A (WRITE STREAM DMA) not supported")); command_aborted(channel, 0x3A); break;
+ case 0x3B: BX_ERROR(("read cmd 0x3B (WRITE STREAM PIO) not supported")); command_aborted(channel, 0x3B); break;
+ case 0x3F: BX_ERROR(("read cmd 0x3F (WRITE LOG EXT) not supported")); command_aborted(channel, 0x3F); break;
+ case 0x40: BX_ERROR(("read cmd 0x40 (READ VERIFY SECTORS) not supported")); command_aborted(channel, 0x40); break;
+ case 0x41: BX_ERROR(("read cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break;
+ case 0x42: BX_ERROR(("read cmd 0x42 (READ VERIFY SECTORS EXT) not supported")); command_aborted(channel, 0x42); break;
+ case 0x50: BX_ERROR(("read cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break;
+ case 0x51: BX_ERROR(("read cmd 0x51 (CONFIGURE STREAM) not supported")); command_aborted(channel, 0x51); break;
+ case 0x70: BX_ERROR(("read cmd 0x70 (SEEK) not supported")); command_aborted(channel, 0x70); break;
+ case 0x87: BX_ERROR(("read cmd 0x87 (CFA TRANSLATE SECTOR) not supported")); command_aborted(channel, 0x87); break;
+ case 0x90: BX_ERROR(("read cmd 0x90 (EXECUTE DEVICE DIAGNOSTIC) not supported")); command_aborted(channel, 0x90); break;
+ case 0x91: BX_ERROR(("read cmd 0x91 (INITIALIZE DEVICE PARAMETERS) not supported")); command_aborted(channel, 0x91); break;
+ case 0x92: BX_ERROR(("read cmd 0x92 (DOWNLOAD MICROCODE) not supported")); command_aborted(channel, 0x92); break;
+ case 0x94: BX_ERROR(("read cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break;
+ case 0x95: BX_ERROR(("read cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break;
+ case 0x96: BX_ERROR(("read cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break;
+ case 0x97: BX_ERROR(("read cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break;
+ case 0x98: BX_ERROR(("read cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break;
+ case 0x99: BX_ERROR(("read cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break;
+ case 0xA2: BX_ERROR(("read cmd 0xA2 (SERVICE) not supported")); command_aborted(channel, 0xA2); break;
+ case 0xB0: BX_ERROR(("read cmd 0xB0 (SMART DISABLE OPERATIONS) not supported")); command_aborted(channel, 0xB0); break;
+ case 0xB1: BX_ERROR(("read cmd 0xB1 (DEVICE CONFIGURATION FREEZE LOCK) not supported")); command_aborted(channel, 0xB1); break;
+ case 0xC0: BX_ERROR(("read cmd 0xC0 (CFA ERASE SECTORS) not supported")); command_aborted(channel, 0xC0); break;
+ case 0xC4: BX_ERROR(("read cmd 0xC4 (READ MULTIPLE) not supported")); command_aborted(channel, 0xC4); break;
+ case 0xC5: BX_ERROR(("read cmd 0xC5 (WRITE MULTIPLE) not supported")); command_aborted(channel, 0xC5); break;
+ case 0xC6: BX_ERROR(("read cmd 0xC6 (SET MULTIPLE MODE) not supported")); command_aborted(channel, 0xC6); break;
+ case 0xC7: BX_ERROR(("read cmd 0xC7 (READ DMA QUEUED) not supported")); command_aborted(channel, 0xC7); break;
+ case 0xC8: BX_ERROR(("read cmd 0xC8 (READ DMA) not supported")); command_aborted(channel, 0xC8); break;
+ case 0xC9: BX_ERROR(("read cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break;
+ case 0xCA: BX_ERROR(("read cmd 0xCA (WRITE DMA) not supported")); command_aborted(channel, 0xCA); break;
+ case 0xCC: BX_ERROR(("read cmd 0xCC (WRITE DMA QUEUED) not supported")); command_aborted(channel, 0xCC); break;
+ case 0xCD: BX_ERROR(("read cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported")); command_aborted(channel, 0xCD); break;
+ case 0xD1: BX_ERROR(("read cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported")); command_aborted(channel, 0xD1); break;
+ case 0xDA: BX_ERROR(("read cmd 0xDA (GET MEDIA STATUS) not supported")); command_aborted(channel, 0xDA); break;
+ case 0xDE: BX_ERROR(("read cmd 0xDE (MEDIA LOCK) not supported")); command_aborted(channel, 0xDE); break;
+ case 0xDF: BX_ERROR(("read cmd 0xDF (MEDIA UNLOCK) not supported")); command_aborted(channel, 0xDF); break;
+ case 0xE0: BX_ERROR(("read cmd 0xE0 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0xE0); break;
+ case 0xE1: BX_ERROR(("read cmd 0xE1 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0xE1); break;
+ case 0xE2: BX_ERROR(("read cmd 0xE2 (STANDBY) not supported")); command_aborted(channel, 0xE2); break;
+ case 0xE3: BX_ERROR(("read cmd 0xE3 (IDLE) not supported")); command_aborted(channel, 0xE3); break;
+ case 0xE4: BX_ERROR(("read cmd 0xE4 (READ BUFFER) not supported")); command_aborted(channel, 0xE4); break;
+ case 0xE5: BX_ERROR(("read cmd 0xE5 (CHECK POWER MODE) not supported")); command_aborted(channel, 0xE5); break;
+ case 0xE6: BX_ERROR(("read cmd 0xE6 (SLEEP) not supported")); command_aborted(channel, 0xE6); break;
+ case 0xE7: BX_ERROR(("read cmd 0xE7 (FLUSH CACHE) not supported")); command_aborted(channel, 0xE7); break;
+ case 0xE8: BX_ERROR(("read cmd 0xE8 (WRITE BUFFER) not supported")); command_aborted(channel, 0xE8); break;
+ case 0xEA: BX_ERROR(("read cmd 0xEA (FLUSH CACHE EXT) not supported")); command_aborted(channel, 0xEA); break;
+ case 0xED: BX_ERROR(("read cmd 0xED (MEDIA EJECT) not supported")); command_aborted(channel, 0xED); break;
+ case 0xEF: BX_ERROR(("read cmd 0xEF (SET FEATURES) not supported")); command_aborted(channel, 0xEF); break;
+ case 0xF1: BX_ERROR(("read cmd 0xF1 (SECURITY SET PASSWORD) not supported")); command_aborted(channel, 0xF1); break;
+ case 0xF2: BX_ERROR(("read cmd 0xF2 (SECURITY UNLOCK) not supported")); command_aborted(channel, 0xF2); break;
+ case 0xF3: BX_ERROR(("read cmd 0xF3 (SECURITY ERASE PREPARE) not supported")); command_aborted(channel, 0xF3); break;
+ case 0xF4: BX_ERROR(("read cmd 0xF4 (SECURITY ERASE UNIT) not supported")); command_aborted(channel, 0xF4); break;
+ case 0xF5: BX_ERROR(("read cmd 0xF5 (SECURITY FREEZE LOCK) not supported")); command_aborted(channel, 0xF5); break;
+ case 0xF6: BX_ERROR(("read cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported")); command_aborted(channel, 0xF6); break;
+ case 0xF8: BX_ERROR(("read cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported")); command_aborted(channel, 0xF8); break;
+ case 0xF9: BX_ERROR(("read cmd 0xF9 (SET MAX ADDRESS) not supported")); command_aborted(channel, 0xF9); break;
+
+ default:
+ BX_PANIC(("IO read(0x%04x): current command is %02xh", address,
+ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+ }
+ break;
+
+ case 0x01: // hard disk error register 0x1f1
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).error_register;
+ goto return_value8;
+ break;
+ case 0x02: // hard disk sector count / interrupt reason 0x1f2
+ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_count;
+ goto return_value8;
+ break;
+ case 0x03: // sector number 0x1f3
+ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_no;
+ goto return_value8;
+ case 0x04: // cylinder low 0x1f4
+ // -- WARNING : On real hardware the controller registers are shared between drives.
+ // So we must respond even if the select device is not present. Some OS uses this fact
+ // to detect the disks.... minix2 for example
+ value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : (BX_SELECTED_CONTROLLER(channel).cylinder_no & 0x00ff);
+ goto return_value8;
+ case 0x05: // cylinder high 0x1f5
+ // -- WARNING : On real hardware the controller registers are shared between drives.
+ // So we must respond even if the select device is not present. Some OS uses this fact
+ // to detect the disks.... minix2 for example
+ value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).cylinder_no >> 8;
+ goto return_value8;
+
+ case 0x06: // hard disk drive and head register 0x1f6
+ // b7 Extended data field for ECC
+ // b6/b5: Used to be sector size. 00=256,01=512,10=1024,11=128
+ // Since 512 was always used, bit 6 was taken to mean LBA mode:
+ // b6 1=LBA mode, 0=CHS mode
+ // b5 1
+ // b4: DRV
+ // b3..0 HD3..HD0
+ value8 = (1 << 7) |
+ ((BX_SELECTED_CONTROLLER(channel).lba_mode>0) << 6) |
+ (1 << 5) | // 01b = 512 sector size
+ (BX_HD_THIS channels[channel].drive_select << 4) |
+ (BX_SELECTED_CONTROLLER(channel).head_no << 0);
+ goto return_value8;
+ break;
+//BX_CONTROLLER(channel,0).lba_mode
+
+ case 0x07: // Hard Disk Status 0x1f7
+ case 0x16: // Hard Disk Alternate Status 0x3f6
+ if (!BX_ANY_IS_PRESENT(channel)) {
+ // (mch) Just return zero for these registers
+ value8 = 0;
+ } else {
+ value8 = (
+ (BX_SELECTED_CONTROLLER(channel).status.busy << 7) |
+ (BX_SELECTED_CONTROLLER(channel).status.drive_ready << 6) |
+ (BX_SELECTED_CONTROLLER(channel).status.write_fault << 5) |
+ (BX_SELECTED_CONTROLLER(channel).status.seek_complete << 4) |
+ (BX_SELECTED_CONTROLLER(channel).status.drq << 3) |
+ (BX_SELECTED_CONTROLLER(channel).status.corrected_data << 2) |
+ (BX_SELECTED_CONTROLLER(channel).status.index_pulse << 1) |
+ (BX_SELECTED_CONTROLLER(channel).status.err) );
+ BX_SELECTED_CONTROLLER(channel).status.index_pulse_count++;
+ BX_SELECTED_CONTROLLER(channel).status.index_pulse = 0;
+ if (BX_SELECTED_CONTROLLER(channel).status.index_pulse_count >= INDEX_PULSE_CYCLE) {
+ BX_SELECTED_CONTROLLER(channel).status.index_pulse = 1;
+ BX_SELECTED_CONTROLLER(channel).status.index_pulse_count = 0;
+ }
+ }
+ if (port == 0x07) {
+ DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+ }
+ goto return_value8;
+ break;
+
+ case 0x17: // Hard Disk Address Register 0x3f7
+ // Obsolete and unsupported register. Not driven by hard
+ // disk controller. Report all 1's. If floppy controller
+ // is handling this address, it will call this function
+ // set/clear D7 (the only bit it handles), then return
+ // the combined value
+ value8 = 0xff;
+ goto return_value8;
+ break;
+
+ default:
+ BX_PANIC(("hard drive: io read to address %x unsupported",
+ (unsigned) address));
+ }
+
+ BX_PANIC(("hard drive: shouldnt get here!"));
+ return(0);
+
+ return_value32:
+ BX_DEBUG(("32-bit read from %04x = %08x {%s}",
+ (unsigned) address, value32, BX_SELECTED_TYPE_STRING(channel)));
+ return value32;
+
+ return_value16:
+ BX_DEBUG(("16-bit read from %04x = %04x {%s}",
+ (unsigned) address, value16, BX_SELECTED_TYPE_STRING(channel)));
+ return value16;
+
+ return_value8:
+ BX_DEBUG(("8-bit read from %04x = %02x {%s}",
+ (unsigned) address, value8, BX_SELECTED_TYPE_STRING(channel)));
+ return value8;
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_hard_drive_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_HD_SMF
+ bx_hard_drive_c *class_ptr = (bx_hard_drive_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_HD_SMF
+ off_t logical_sector;
+ off_t ret;
+ bx_bool prev_control_reset;
+
+ Bit8u channel = BX_MAX_ATA_CHANNEL;
+ Bit32u port = 0xff; // undefined
+
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr1) {
+ port = address - BX_HD_THIS channels[channel].ioaddr1;
+ break;
+ }
+ else if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr2) {
+ port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10;
+ break;
+ }
+ }
+
+ if (channel == BX_MAX_ATA_CHANNEL) {
+ if (address != 0x03f6) {
+ BX_PANIC(("write: unable to find ATA channel, ioport=0x%04x", address));
+ } else {
+ channel = 0;
+ port = address - 0x03e0;
+ }
+ }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20230c is only available for first ata channel
+if (channel == 0) {
+ BX_HD_THIS pdc20230c.prog_count = 0;
+
+ if (BX_HD_THIS pdc20230c.prog_mode != 0) {
+ switch (port) {
+ case 0x03:
+ BX_HD_THIS pdc20230c.p1f3_value = value;
+ return;
+ break;
+ case 0x04:
+ BX_HD_THIS pdc20230c.p1f4_value = value;
+ return;
+ break;
+ }
+ }
+}
+#endif
+
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) {
+ switch (io_len) {
+ case 1:
+ BX_INFO(("8-bit write to %04x = %02x {%s}",
+ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 2:
+ BX_INFO(("16-bit write to %04x = %04x {%s}",
+ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 4:
+ BX_INFO(("32-bit write to %04x = %08x {%s}",
+ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ default:
+ BX_INFO(("unknown-size write to %04x = %08x {%s}",
+ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+ }
+ }
+
+ BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value));
+
+ switch (port) {
+ case 0x00: // 0x1f0
+ switch (BX_SELECTED_CONTROLLER(channel).current_command) {
+ case 0x30: // WRITE SECTORS
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512)
+ BX_PANIC(("IO write(0x%04x): buffer_index >= 512", address));
+
+#if BX_SupportRepeatSpeedups
+ if (DEV_bulk_io_quantum_requested()) {
+ unsigned transferLen, quantumsMax;
+
+ quantumsMax =
+ (512 - BX_SELECTED_CONTROLLER(channel).buffer_index) / io_len;
+ if ( quantumsMax == 0)
+ BX_PANIC(("IO write(0x%04x): not enough space for write", address));
+ DEV_bulk_io_quantum_transferred() =
+ DEV_bulk_io_quantum_requested();
+ if (quantumsMax < DEV_bulk_io_quantum_transferred())
+ DEV_bulk_io_quantum_transferred() = quantumsMax;
+ transferLen = io_len * DEV_bulk_io_quantum_transferred();
+ memcpy(
+ &BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index],
+ (Bit8u*) DEV_bulk_io_host_addr(),
+ transferLen);
+ DEV_bulk_io_host_addr() += transferLen;
+ BX_SELECTED_CONTROLLER(channel).buffer_index += transferLen;
+ }
+ else
+#endif
+ {
+ switch(io_len){
+ case 4:
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] = (Bit8u)(value >> 24);
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] = (Bit8u)(value >> 16);
+ case 2:
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (Bit8u)(value >> 8);
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index] = (Bit8u) value;
+ }
+ BX_SELECTED_CONTROLLER(channel).buffer_index += io_len;
+ }
+
+ /* if buffer completely writtten */
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+ off_t logical_sector;
+ off_t ret;
+
+#if TEST_WRITE_BEYOND_END==1
+ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+ if (!calculate_logical_address(channel, &logical_sector)) {
+ BX_ERROR(("write reached invalid sector %lu, aborting", (unsigned long)logical_sector));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ return;
+ }
+#if TEST_WRITE_BEYOND_END==2
+ logical_sector += 100000;
+#endif
+ ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+ if (ret < 0) {
+ BX_ERROR(("could not lseek() hard drive image file at byte %lu", (unsigned long)logical_sector * 512));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ return;
+ }
+ ret = BX_SELECTED_DRIVE(channel).hard_drive->write((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+ if (ret < 512) {
+ BX_ERROR(("could not write() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+ return;
+ }
+
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+
+ /* update sector count, sector number, cylinder,
+ * drive, head, status
+ * if there are more sectors, read next one in...
+ */
+
+ increment_address(channel);
+
+ /* When the write is complete, controller clears the DRQ bit and
+ * sets the BSY bit.
+ * If at least one more sector is to be written, controller sets DRQ bit,
+ * clears BSY bit, and issues IRQ
+ */
+
+ if (BX_SELECTED_CONTROLLER(channel).sector_count!=0) {
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ }
+ else { /* no more sectors to write */
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ }
+ raise_interrupt(channel);
+ }
+ break;
+
+ case 0xa0: // PACKET
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE)
+ BX_PANIC(("IO write(0x%04x): buffer_index >= PACKET_SIZE", address));
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index] = value;
+ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (value >> 8);
+ BX_SELECTED_CONTROLLER(channel).buffer_index += 2;
+
+ /* if packet completely writtten */
+ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE) {
+ // complete command received
+ Bit8u atapi_command = BX_SELECTED_CONTROLLER(channel).buffer[0];
+
+ if (bx_dbg.cdrom)
+ BX_INFO(("cdrom: ATAPI command 0x%x started", atapi_command));
+
+ switch (atapi_command) {
+ case 0x00: // test unit ready
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ atapi_cmd_nop(channel);
+ } else {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ }
+ raise_interrupt(channel);
+ break;
+
+ case 0x03: { // request sense
+ int alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4];
+ init_send_atapi_command(channel, atapi_command, 18, alloc_length);
+
+ // sense data
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x70 | (1 << 7);
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = BX_SELECTED_DRIVE(channel).sense.sense_key;
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = BX_SELECTED_DRIVE(channel).sense.information.arr[0];
+ BX_SELECTED_CONTROLLER(channel).buffer[4] = BX_SELECTED_DRIVE(channel).sense.information.arr[1];
+ BX_SELECTED_CONTROLLER(channel).buffer[5] = BX_SELECTED_DRIVE(channel).sense.information.arr[2];
+ BX_SELECTED_CONTROLLER(channel).buffer[6] = BX_SELECTED_DRIVE(channel).sense.information.arr[3];
+ BX_SELECTED_CONTROLLER(channel).buffer[7] = 17-7;
+ BX_SELECTED_CONTROLLER(channel).buffer[8] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[0];
+ BX_SELECTED_CONTROLLER(channel).buffer[9] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[1];
+ BX_SELECTED_CONTROLLER(channel).buffer[10] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[2];
+ BX_SELECTED_CONTROLLER(channel).buffer[11] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[3];
+ BX_SELECTED_CONTROLLER(channel).buffer[12] = BX_SELECTED_DRIVE(channel).sense.asc;
+ BX_SELECTED_CONTROLLER(channel).buffer[13] = BX_SELECTED_DRIVE(channel).sense.ascq;
+ BX_SELECTED_CONTROLLER(channel).buffer[14] = BX_SELECTED_DRIVE(channel).sense.fruc;
+ BX_SELECTED_CONTROLLER(channel).buffer[15] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[0];
+ BX_SELECTED_CONTROLLER(channel).buffer[16] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[1];
+ BX_SELECTED_CONTROLLER(channel).buffer[17] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[2];
+
+ ready_to_send_atapi(channel);
+ }
+ break;
+
+ case 0x1b: { // start stop unit
+ //bx_bool Immed = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 0) & 1;
+ bx_bool LoEj = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 1) & 1;
+ bx_bool Start = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 0) & 1;
+
+ if (!LoEj && !Start) { // stop the disc
+ BX_ERROR(("FIXME: Stop disc not implemented"));
+ atapi_cmd_nop(channel);
+ raise_interrupt(channel);
+ } else if (!LoEj && Start) { // start (spin up) the disc
+#ifdef LOWLEVEL_CDROM
+ BX_SELECTED_DRIVE(channel).cdrom.cd->start_cdrom();
+#endif
+ BX_ERROR(("FIXME: ATAPI start disc not reading TOC"));
+ atapi_cmd_nop(channel);
+ raise_interrupt(channel);
+ } else if (LoEj && !Start) { // Eject the disc
+ atapi_cmd_nop(channel);
+
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+#ifdef LOWLEVEL_CDROM
+ BX_SELECTED_DRIVE(channel).cdrom.cd->eject_cdrom();
+#endif
+ BX_SELECTED_DRIVE(channel).cdrom.ready = 0;
+ bx_options.atadevice[channel][BX_SLAVE_SELECTED(channel)].Ostatus->set(BX_EJECTED);
+ bx_gui->update_drive_status_buttons();
+ }
+ raise_interrupt(channel);
+ } else { // Load the disc
+ // My guess is that this command only closes the tray, that's a no-op for us
+ atapi_cmd_nop(channel);
+ raise_interrupt(channel);
+ }
+ }
+ break;
+
+ case 0xbd: { // mechanism status
+ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 8);
+
+ if (alloc_length == 0)
+ BX_PANIC(("Zero allocation length to MECHANISM STATUS not impl."));
+
+ init_send_atapi_command(channel, atapi_command, 8, alloc_length);
+
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0; // reserved for non changers
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // reserved for non changers
+
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0; // Current LBA (TODO!)
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // Current LBA (TODO!)
+ BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // Current LBA (TODO!)
+
+ BX_SELECTED_CONTROLLER(channel).buffer[5] = 1; // one slot
+
+ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // slot table length
+ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // slot table length
+
+ ready_to_send_atapi(channel);
+ }
+ break;
+
+ case 0x5a: { // mode sense
+ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+
+ Bit8u PC = BX_SELECTED_CONTROLLER(channel).buffer[2] >> 6;
+ Bit8u PageCode = BX_SELECTED_CONTROLLER(channel).buffer[2] & 0x3f;
+
+ switch (PC) {
+ case 0x0: // current values
+ switch (PageCode) {
+ case 0x01: // error recovery
+ init_send_atapi_command(channel, atapi_command, sizeof(error_recovery_t) + 8, alloc_length);
+
+ init_mode_sense_single(channel, &BX_SELECTED_DRIVE(channel).cdrom.current.error_recovery,
+ sizeof(error_recovery_t));
+ ready_to_send_atapi(channel);
+ break;
+
+ case 0x2a: // CD-ROM capabilities & mech. status
+ init_send_atapi_command(channel, atapi_command, 28, alloc_length);
+ init_mode_sense_single(channel, &BX_SELECTED_CONTROLLER(channel).buffer[8], 28);
+ BX_SELECTED_CONTROLLER(channel).buffer[8] = 0x2a;
+ BX_SELECTED_CONTROLLER(channel).buffer[9] = 0x12;
+ BX_SELECTED_CONTROLLER(channel).buffer[10] = 0x00;
+ BX_SELECTED_CONTROLLER(channel).buffer[11] = 0x00;
+ // Multisession, Mode 2 Form 2, Mode 2 Form 1
+ BX_SELECTED_CONTROLLER(channel).buffer[12] = 0x70;
+ BX_SELECTED_CONTROLLER(channel).buffer[13] = (3 << 5);
+ BX_SELECTED_CONTROLLER(channel).buffer[14] = (unsigned char)
+(1 |
+ (BX_SELECTED_DRIVE(channel).cdrom.locked ? (1 << 1) : 0) |
+ (1 << 3) |
+ (1 << 5));
+ BX_SELECTED_CONTROLLER(channel).buffer[15] = 0x00;
+ BX_SELECTED_CONTROLLER(channel).buffer[16] = (706 >> 8) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[17] = 706 & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[18] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[19] = 2;
+ BX_SELECTED_CONTROLLER(channel).buffer[20] = (512 >> 8) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[21] = 512 & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[22] = (706 >> 8) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[23] = 706 & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[24] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[25] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[26] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[27] = 0;
+ ready_to_send_atapi(channel);
+ break;
+
+ case 0x0d: // CD-ROM
+ case 0x0e: // CD-ROM audio control
+ case 0x3f: // all
+ BX_ERROR(("cdrom: MODE SENSE (curr), code=%x"
+ " not implemented yet",
+ PageCode));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+
+ default:
+ // not implemeted by this device
+ BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+ " not implemented by device",
+ PC, PageCode));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+ }
+ break;
+
+ case 0x1: // changeable values
+ switch (PageCode) {
+ case 0x01: // error recovery
+ case 0x0d: // CD-ROM
+ case 0x0e: // CD-ROM audio control
+ case 0x2a: // CD-ROM capabilities & mech. status
+ case 0x3f: // all
+ BX_ERROR(("cdrom: MODE SENSE (chg), code=%x"
+ " not implemented yet",
+ PageCode));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+
+ default:
+ // not implemeted by this device
+ BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+ " not implemented by device",
+ PC, PageCode));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+ }
+ break;
+
+ case 0x2: // default values
+ switch (PageCode) {
+ case 0x01: // error recovery
+ case 0x0d: // CD-ROM
+ case 0x0e: // CD-ROM audio control
+ case 0x2a: // CD-ROM capabilities & mech. status
+ case 0x3f: // all
+ BX_PANIC(("cdrom: MODE SENSE (dflt), code=%x",
+ PageCode));
+ break;
+
+ default:
+ // not implemeted by this device
+ BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+ " not implemented by device",
+ PC, PageCode));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+ }
+ break;
+
+ case 0x3: // saved values not implemented
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
+ raise_interrupt(channel);
+ break;
+
+ default:
+ BX_PANIC(("Should not get here!"));
+ break;
+ }
+ }
+ break;
+
+ case 0x12: { // inquiry
+ uint8 alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4];
+
+ init_send_atapi_command(channel, atapi_command, 36, alloc_length);
+
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x05; // CD-ROM
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x80; // Removable
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x00; // ISO, ECMA, ANSI version
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0x21; // ATAPI-2, as specified
+ BX_SELECTED_CONTROLLER(channel).buffer[4] = 31; // additional length (total 36)
+ BX_SELECTED_CONTROLLER(channel).buffer[5] = 0x00; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0x00; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0x00; // reserved
+
+ // Vendor ID
+ const char* vendor_id = "VTAB ";
+ int i;
+ for (i = 0; i < 8; i++)
+ BX_SELECTED_CONTROLLER(channel).buffer[8+i] = vendor_id[i];
+
+ // Product ID
+ const char* product_id = "Turbo CD-ROM ";
+ for (i = 0; i < 16; i++)
+ BX_SELECTED_CONTROLLER(channel).buffer[16+i] = product_id[i];
+
+ // Product Revision level
+ const char* rev_level = "1.0 ";
+ for (i = 0; i < 4; i++)
+ BX_SELECTED_CONTROLLER(channel).buffer[32+i] = rev_level[i];
+
+ ready_to_send_atapi(channel);
+ }
+ break;
+
+ case 0x25: { // read cd-rom capacity
+ // no allocation length???
+ init_send_atapi_command(channel, atapi_command, 8, 8);
+
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ uint32 capacity = BX_SELECTED_DRIVE(channel).cdrom.capacity;
+ BX_INFO(("Capacity is %d sectors (%d bytes)", capacity, capacity * 2048));
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = (capacity >> 24) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = (capacity >> 16) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = (capacity >> 8) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = (capacity >> 0) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[4] = (2048 >> 24) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[5] = (2048 >> 16) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[6] = (2048 >> 8) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[7] = (2048 >> 0) & 0xff;
+ ready_to_send_atapi(channel);
+ } else {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ }
+ }
+ break;
+
+ case 0xbe: { // read cd
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ BX_ERROR(("Read CD with CD present not implemented"));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ } else {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ }
+ }
+ break;
+
+ case 0x43: { // read toc
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+#ifdef LOWLEVEL_CDROM
+ bool msf = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 1) & 1;
+ uint8 starting_track = BX_SELECTED_CONTROLLER(channel).buffer[6];
+#endif
+ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+
+ uint8 format = (BX_SELECTED_CONTROLLER(channel).buffer[9] >> 6);
+ int i;
+ switch (format) {
+ case 0:
+#ifdef LOWLEVEL_CDROM
+ int toc_length;
+ if (!(BX_SELECTED_DRIVE(channel).cdrom.cd->read_toc(BX_SELECTED_CONTROLLER(channel).buffer,
+ &toc_length, msf, starting_track))) {
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ } else {
+ init_send_atapi_command(channel, atapi_command, toc_length, alloc_length);
+ ready_to_send_atapi(channel);
+ }
+#else
+ BX_PANIC(("LOWLEVEL_CDROM not defined"));
+#endif
+ break;
+
+ case 1:
+ // multi session stuff. we ignore this and emulate a single session only
+ init_send_atapi_command(channel, atapi_command, 12, alloc_length);
+
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x0a;
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = 1;
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = 1;
+ for (i = 0; i < 8; i++)
+ BX_SELECTED_CONTROLLER(channel).buffer[4+i] = 0;
+
+ ready_to_send_atapi(channel);
+ break;
+
+ case 2:
+ default:
+ BX_PANIC(("(READ TOC) Format %d not supported", format));
+ break;
+ }
+ } else {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ }
+ }
+ break;
+
+ case 0x28: // read (10)
+ case 0xa8: // read (12)
+ {
+
+ uint32 transfer_length;
+ if (atapi_command == 0x28)
+ transfer_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+ else
+ transfer_length = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 6);
+
+ uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2);
+
+ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ break;
+ }
+
+ if (transfer_length == 0) {
+ atapi_cmd_nop(channel);
+ raise_interrupt(channel);
+ BX_INFO(("READ(%d) with transfer length 0, ok", atapi_command==0x28?10:12));
+ break;
+ }
+
+ if (lba + transfer_length > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+ raise_interrupt(channel);
+ break;
+ }
+
+ BX_DEBUG(("cdrom: READ (%d) LBA=%d LEN=%d", atapi_command==0x28?10:12, lba, transfer_length));
+
+ // handle command
+ init_send_atapi_command(channel, atapi_command, transfer_length * 2048,
+ transfer_length * 2048, true);
+ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length;
+ BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba;
+ ready_to_send_atapi(channel);
+ }
+ break;
+
+ case 0x2b: { // seek
+ uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2);
+ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ break;
+ }
+
+ if (lba > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+ raise_interrupt(channel);
+ break;
+ }
+ BX_INFO(("cdrom: SEEK (ignored)"));
+ atapi_cmd_nop(channel);
+ raise_interrupt(channel);
+ }
+ break;
+
+ case 0x1e: { // prevent/allow medium removal
+ if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ BX_SELECTED_DRIVE(channel).cdrom.locked = BX_SELECTED_CONTROLLER(channel).buffer[4] & 1;
+ atapi_cmd_nop(channel);
+ } else {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ }
+ raise_interrupt(channel);
+ }
+ break;
+
+ case 0x42: { // read sub-channel
+ bool msf = get_packet_field(channel,1, 1, 1);
+ bool sub_q = get_packet_field(channel,2, 6, 1);
+ uint8 data_format = get_packet_byte(channel,3);
+ uint8 track_number = get_packet_byte(channel,6);
+ uint16 alloc_length = get_packet_word(channel,7);
+ UNUSED(msf);
+ UNUSED(data_format);
+ UNUSED(track_number);
+
+ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+ raise_interrupt(channel);
+ } else {
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // audio not supported
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0;
+
+ int ret_len = 4; // header size
+
+ if (sub_q) { // !sub_q == header only
+ BX_ERROR(("Read sub-channel with SubQ not implemented"));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ }
+
+ init_send_atapi_command(channel, atapi_command, ret_len, alloc_length);
+ ready_to_send_atapi(channel);
+ }
+ }
+ break;
+
+ case 0x51: { // read disc info
+ // no-op to keep the Linux CD-ROM driver happy
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ }
+ break;
+
+ case 0x55: // mode select
+ case 0xa6: // load/unload cd
+ case 0x4b: // pause/resume
+ case 0x45: // play audio
+ case 0x47: // play audio msf
+ case 0xbc: // play cd
+ case 0xb9: // read cd msf
+ case 0x44: // read header
+ case 0xba: // scan
+ case 0xbb: // set cd speed
+ case 0x4e: // stop play/scan
+ case 0x46: // ???
+ case 0x4a: // ???
+ BX_ERROR(("ATAPI command 0x%x not implemented yet",
+ atapi_command));
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+ default:
+ BX_PANIC(("Unknown ATAPI command 0x%x (%d)",
+ atapi_command, atapi_command));
+ // We'd better signal the error if the user chose to continue
+ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+ raise_interrupt(channel);
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ BX_PANIC(("IO write(0x%04x): current command is %02xh", address,
+ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+ }
+ break;
+
+ case 0x01: // hard disk write precompensation 0x1f1
+ WRITE_FEATURES(channel,value);
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) {
+ if (value == 0xff)
+ BX_INFO(("no precompensation {%s}", BX_SELECTED_TYPE_STRING(channel)));
+ else
+ BX_INFO(("precompensation value %02x {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ }
+ break;
+
+ case 0x02: // hard disk sector count 0x1f2
+ WRITE_SECTOR_COUNT(channel,value);
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("sector count = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 0x03: // hard disk sector number 0x1f3
+ WRITE_SECTOR_NUMBER(channel,value);
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("sector number = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 0x04: // hard disk cylinder low 0x1f4
+ WRITE_CYLINDER_LOW(channel,value);
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("cylinder low = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 0x05: // hard disk cylinder high 0x1f5
+ WRITE_CYLINDER_HIGH(channel,value);
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("cylinder high = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+ break;
+
+ case 0x06: // hard disk drive and head register 0x1f6
+ // b7 Extended data field for ECC
+ // b6/b5: Used to be sector size. 00=256,01=512,10=1024,11=128
+ // Since 512 was always used, bit 6 was taken to mean LBA mode:
+ // b6 1=LBA mode, 0=CHS mode
+ // b5 1
+ // b4: DRV
+ // b3..0 HD3..HD0
+ {
+ if ( (value & 0xa0) != 0xa0 ) // 1x1xxxxx
+ BX_INFO(("IO write 0x%04x (%02x): not 1x1xxxxxb", address, (unsigned) value));
+ Bit32u drvsel = BX_HD_THIS channels[channel].drive_select = (value >> 4) & 0x01;
+ WRITE_HEAD_NO(channel,value & 0xf);
+ if (BX_SELECTED_CONTROLLER(channel).lba_mode == 0 && ((value >> 6) & 1) == 1)
+ BX_DEBUG(("enabling LBA mode"));
+ WRITE_LBA_MODE(channel,(value >> 6) & 1);
+ if (!BX_SELECTED_IS_PRESENT(channel)) {
+ BX_ERROR (("device set to %d which does not exist",drvsel));
+ BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // aborted
+ BX_SELECTED_CONTROLLER(channel).status.err = 1;
+ }
+ break;
+ }
+
+ case 0x07: // hard disk command 0x1f7
+ // (mch) Writes to the command register with drive_select != 0
+ // are ignored if no secondary device is present
+ if ((BX_SLAVE_SELECTED(channel)) && (!BX_SLAVE_IS_PRESENT(channel)))
+ break;
+ // Writes to the command register clear the IRQ
+ DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+
+ if (BX_SELECTED_CONTROLLER(channel).status.busy)
+ BX_PANIC(("hard disk: command sent, controller BUSY"));
+ if ( (value & 0xf0) == 0x10 )
+ value = 0x10;
+ switch (value) {
+
+ case 0x10: // CALIBRATE DRIVE
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("calibrate drive issued to non-disk"));
+ if (!BX_SELECTED_IS_PRESENT(channel)) {
+ BX_SELECTED_CONTROLLER(channel).error_register = 0x02; // Track 0 not found
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 1;
+ raise_interrupt(channel);
+ BX_INFO(("calibrate drive: disk ata%d-%d not present", channel, BX_SLAVE_SELECTED(channel)));
+ break;
+ }
+
+ /* move head to cylinder 0, issue IRQ */
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ raise_interrupt(channel);
+ break;
+
+ case 0x20: // READ MULTIPLE SECTORS, with retries
+ case 0x21: // READ MULTIPLE SECTORS, without retries
+ /* update sector_no, always points to current sector
+ * after each sector is read to buffer, DRQ bit set and issue IRQ
+ * if interrupt handler transfers all data words into main memory,
+ * and more sectors to read, then set BSY bit again, clear DRQ and
+ * read next sector into buffer
+ * sector count of 0 means 256 sectors
+ */
+
+ if (!BX_SELECTED_IS_HD(channel)) {
+ BX_ERROR(("read multiple issued to non-disk"));
+ command_aborted(channel, value);
+ break;
+ }
+
+ BX_SELECTED_CONTROLLER(channel).current_command = value;
+
+ // Lose98 accesses 0/0/0 in CHS mode
+ if (!BX_SELECTED_CONTROLLER(channel).lba_mode &&
+ !BX_SELECTED_CONTROLLER(channel).head_no &&
+ !BX_SELECTED_CONTROLLER(channel).cylinder_no &&
+ !BX_SELECTED_CONTROLLER(channel).sector_no) {
+ BX_INFO(("Read from 0/0/0, aborting command"));
+ command_aborted(channel, value);
+ break;
+ }
+
+#if TEST_READ_BEYOND_END==2
+ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+ if (!calculate_logical_address(channel, &logical_sector)) {
+ BX_ERROR(("initial read from sector %lu out of bounds, aborting", (unsigned long)logical_sector));
+ command_aborted(channel, value);
+ break;
+ }
+#if TEST_READ_BEYOND_END==3
+ logical_sector += 100000;
+#endif
+ ret=BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+ if (ret < 0) {
+ BX_ERROR (("could not lseek() hard drive image file, aborting"));
+ command_aborted(channel, value);
+ break;
+ }
+ ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+ if (ret < 512) {
+ BX_ERROR(("logical sector was %lu", (unsigned long)logical_sector));
+ BX_ERROR(("could not read() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+ command_aborted(channel, value);
+ break;
+ }
+
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ raise_interrupt(channel);
+ break;
+
+ case 0x30: /* WRITE SECTORS, with retries */
+ /* update sector_no, always points to current sector
+ * after each sector is read to buffer, DRQ bit set and issue IRQ
+ * if interrupt handler transfers all data words into main memory,
+ * and more sectors to read, then set BSY bit again, clear DRQ and
+ * read next sector into buffer
+ * sector count of 0 means 256 sectors
+ */
+
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("write multiple issued to non-disk"));
+
+ if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+ BX_PANIC(("write command: BSY bit set"));
+ }
+ BX_SELECTED_CONTROLLER(channel).current_command = value;
+
+ // implicit seek done :^)
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ // BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ break;
+
+ case 0x90: // EXECUTE DEVICE DIAGNOSTIC
+ if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+ BX_PANIC(("diagnostic command: BSY bit set"));
+ }
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("drive diagnostics issued to non-disk"));
+ BX_SELECTED_CONTROLLER(channel).error_register = 0x81; // Drive 1 failed, no error on drive 0
+ // BX_SELECTED_CONTROLLER(channel).status.busy = 0; // not needed
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ break;
+
+ case 0x91: // INITIALIZE DRIVE PARAMETERS
+ if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+ BX_PANIC(("init drive parameters command: BSY bit set"));
+ }
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("initialize drive parameters issued to non-disk"));
+ // sets logical geometry of specified drive
+ BX_DEBUG(("init drive params: sec=%u, drive sel=%u, head=%u",
+ (unsigned) BX_SELECTED_CONTROLLER(channel).sector_count,
+ (unsigned) BX_HD_THIS channels[channel].drive_select,
+ (unsigned) BX_SELECTED_CONTROLLER(channel).head_no));
+ if (!BX_SELECTED_IS_PRESENT(channel)) {
+ BX_PANIC(("init drive params: disk ata%d-%d not present", channel, BX_SLAVE_SELECTED(channel)));
+ //BX_SELECTED_CONTROLLER(channel).error_register = 0x12;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ raise_interrupt(channel);
+ break;
+ }
+ if (BX_SELECTED_CONTROLLER(channel).sector_count != BX_SELECTED_DRIVE(channel).hard_drive->sectors)
+ BX_PANIC(("init drive params: sector count doesnt match %d!=%d", BX_SELECTED_CONTROLLER(channel).sector_count, BX_SELECTED_DRIVE(channel).hard_drive->sectors));
+ if ( BX_SELECTED_CONTROLLER(channel).head_no != (BX_SELECTED_DRIVE(channel).hard_drive->heads-1) )
+ BX_PANIC(("init drive params: head number doesn't match %d != %d",BX_SELECTED_CONTROLLER(channel).head_no, BX_SELECTED_DRIVE(channel).hard_drive->heads-1));
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ raise_interrupt(channel);
+ break;
+
+ case 0xec: // IDENTIFY DEVICE
+ if (bx_options.OnewHardDriveSupport->get ()) {
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("Drive ID Command issued : 0xec "));
+
+ if (!BX_SELECTED_IS_PRESENT(channel)) {
+ BX_INFO(("disk ata%d-%d not present, aborting",channel,BX_SLAVE_SELECTED(channel)));
+ command_aborted(channel, value);
+ break;
+ }
+ if (BX_SELECTED_IS_CD(channel)) {
+ BX_SELECTED_CONTROLLER(channel).head_no = 0;
+ BX_SELECTED_CONTROLLER(channel).sector_count = 1;
+ BX_SELECTED_CONTROLLER(channel).sector_no = 1;
+ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xeb14;
+ command_aborted(channel, 0xec);
+ } else {
+ BX_SELECTED_CONTROLLER(channel).current_command = value;
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+
+ // See ATA/ATAPI-4, 8.12
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ raise_interrupt(channel);
+ identify_drive(channel);
+ }
+ }
+ else {
+ BX_INFO(("sent IDENTIFY DEVICE (0xec) to old hard drive"));
+ command_aborted(channel, value);
+ }
+ break;
+
+ case 0xef: // SET FEATURES
+ switch(BX_SELECTED_CONTROLLER(channel).features) {
+ case 0x02: // Enable and
+ case 0x82: // Disable write cache.
+ case 0xAA: // Enable and
+ case 0x55: // Disable look-ahead cache.
+ case 0xCC: // Enable and
+ case 0x66: // Disable reverting to power-on default
+ BX_INFO(("SET FEATURES subcommand 0x%02x not supported by disk.", (unsigned) BX_SELECTED_CONTROLLER(channel).features));
+ command_aborted(channel, value);
+ break;
+
+ default:
+ BX_PANIC(("SET FEATURES with unknown subcommand: 0x%02x", (unsigned) BX_SELECTED_CONTROLLER(channel).features ));
+ // We'd better signal the error if the user chose to continue
+ command_aborted(channel, value);
+ }
+ break;
+
+ case 0x40: // READ VERIFY SECTORS
+ if (bx_options.OnewHardDriveSupport->get ()) {
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("read verify issued to non-disk"));
+ BX_INFO(("Verify Command : 0x40 ! "));
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ raise_interrupt(channel);
+ }
+ else {
+ BX_INFO(("sent READ VERIFY SECTORS (0x40) to old hard drive"));
+ command_aborted(channel, value);
+ }
+ break;
+
+ case 0xc6: // SET MULTIPLE MODE (mch)
+ if (BX_SELECTED_CONTROLLER(channel).sector_count != 128 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 64 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 32 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 16 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 8 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 4 &&
+ BX_SELECTED_CONTROLLER(channel).sector_count != 2)
+ command_aborted(channel, value);
+
+ if (!BX_SELECTED_IS_HD(channel))
+ BX_PANIC(("set multiple mode issued to non-disk"));
+
+ BX_SELECTED_CONTROLLER(channel).sectors_per_block = BX_SELECTED_CONTROLLER(channel).sector_count;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ break;
+
+ // ATAPI commands
+ case 0xa1: // IDENTIFY PACKET DEVICE
+ if (BX_SELECTED_IS_CD(channel)) {
+ BX_SELECTED_CONTROLLER(channel).current_command = value;
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ raise_interrupt(channel);
+ identify_ATAPI_drive(channel);
+ } else {
+ command_aborted(channel, 0xa1);
+ }
+ break;
+
+ case 0x08: // DEVICE RESET (atapi)
+ if (BX_SELECTED_IS_CD(channel)) {
+ BX_SELECTED_CONTROLLER(channel).status.busy = 1;
+ BX_SELECTED_CONTROLLER(channel).error_register &= ~(1 << 7);
+
+ // device signature
+ BX_SELECTED_CONTROLLER(channel).head_no = 0;
+ BX_SELECTED_CONTROLLER(channel).sector_count = 1;
+ BX_SELECTED_CONTROLLER(channel).sector_no = 1;
+ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xeb14;
+
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+
+ } else {
+ BX_DEBUG(("ATAPI Device Reset on non-cd device"));
+ command_aborted(channel, 0x08);
+ }
+ break;
+
+ case 0xa0: // SEND PACKET (atapi)
+ if (BX_SELECTED_IS_CD(channel)) {
+ // PACKET
+ if (BX_SELECTED_CONTROLLER(channel).features & (1 << 0))
+ BX_PANIC(("PACKET-DMA not supported"));
+ if (BX_SELECTED_CONTROLLER(channel).features & (1 << 1))
+ BX_PANIC(("PACKET-overlapped not supported"));
+
+ // We're already ready!
+ BX_SELECTED_CONTROLLER(channel).sector_count = 1;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ // serv bit??
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ // NOTE: no interrupt here
+ BX_SELECTED_CONTROLLER(channel).current_command = value;
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ } else {
+ command_aborted (channel, 0xa0);
+ }
+ break;
+
+ case 0xa2: // SERVICE (atapi), optional
+ if (BX_SELECTED_IS_CD(channel)) {
+ BX_PANIC(("ATAPI SERVICE not implemented"));
+ } else {
+ command_aborted (channel, 0xa2);
+ }
+ break;
+
+ // power management
+ case 0xe5: // CHECK POWER MODE
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ BX_SELECTED_CONTROLLER(channel).sector_count = 0xff; // Active or Idle mode
+ raise_interrupt(channel);
+ break;
+
+ case 0x70: // SEEK (cgs)
+ if (BX_SELECTED_IS_HD(channel)) {
+ BX_DEBUG(("write cmd 0x70 (SEEK) executing"));
+ if (!calculate_logical_address(channel, &logical_sector)) {
+ BX_ERROR(("initial seek to sector %lu out of bounds, aborting", (unsigned long)logical_sector));
+ command_aborted(channel, value);
+ break;
+ }
+ BX_SELECTED_CONTROLLER(channel).error_register = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq));
+ BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq));
+ BX_DEBUG(("SEEK completed. error_register = %02x", BX_SELECTED_CONTROLLER(channel).error_register));
+ raise_interrupt(channel);
+ BX_DEBUG(("SEEK interrupt completed"));
+ } else {
+ BX_ERROR(("write cmd 0x70 (SEEK) not supported for non-disk"));
+ command_aborted(channel, 0x70);
+ }
+ break;
+
+
+
+ // List all the write operations that are defined in the ATA/ATAPI spec
+ // that we don't support. Commands that are listed here will cause a
+ // BX_ERROR, which is non-fatal, and the command will be aborted.
+ case 0x22: BX_ERROR(("write cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break;
+ case 0x23: BX_ERROR(("write cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break;
+ case 0x24: BX_ERROR(("write cmd 0x24 (READ SECTORS EXT) not supported"));command_aborted(channel, 0x24); break;
+ case 0x25: BX_ERROR(("write cmd 0x25 (READ DMA EXT) not supported"));command_aborted(channel, 0x25); break;
+ case 0x26: BX_ERROR(("write cmd 0x26 (READ DMA QUEUED EXT) not supported"));command_aborted(channel, 0x26); break;
+ case 0x27: BX_ERROR(("write cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x27); break;
+ case 0x29: BX_ERROR(("write cmd 0x29 (READ MULTIPLE EXT) not supported"));command_aborted(channel, 0x29); break;
+ case 0x2A: BX_ERROR(("write cmd 0x2A (READ STREAM DMA) not supported"));command_aborted(channel, 0x2A); break;
+ case 0x2B: BX_ERROR(("write cmd 0x2B (READ STREAM PIO) not supported"));command_aborted(channel, 0x2B); break;
+ case 0x2F: BX_ERROR(("write cmd 0x2F (READ LOG EXT) not supported"));command_aborted(channel, 0x2F); break;
+ case 0x31: BX_ERROR(("write cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break;
+ case 0x32: BX_ERROR(("write cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break;
+ case 0x33: BX_ERROR(("write cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break;
+ case 0x34: BX_ERROR(("write cmd 0x34 (WRITE SECTORS EXT) not supported"));command_aborted(channel, 0x34); break;
+ case 0x35: BX_ERROR(("write cmd 0x35 (WRITE DMA EXT) not supported"));command_aborted(channel, 0x35); break;
+ case 0x36: BX_ERROR(("write cmd 0x36 (WRITE DMA QUEUED EXT) not supported"));command_aborted(channel, 0x36); break;
+ case 0x37: BX_ERROR(("write cmd 0x37 (SET MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x37); break;
+ case 0x38: BX_ERROR(("write cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported"));command_aborted(channel, 0x38); break;
+ case 0x39: BX_ERROR(("write cmd 0x39 (WRITE MULTIPLE EXT) not supported"));command_aborted(channel, 0x39); break;
+ case 0x3A: BX_ERROR(("write cmd 0x3A (WRITE STREAM DMA) not supported"));command_aborted(channel, 0x3A); break;
+ case 0x3B: BX_ERROR(("write cmd 0x3B (WRITE STREAM PIO) not supported"));command_aborted(channel, 0x3B); break;
+ case 0x3F: BX_ERROR(("write cmd 0x3F (WRITE LOG EXT) not supported"));command_aborted(channel, 0x3F); break;
+ case 0x41: BX_ERROR(("write cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break;
+ case 0x42: BX_ERROR(("write cmd 0x42 (READ VERIFY SECTORS EXT) not supported"));command_aborted(channel, 0x42); break;
+ case 0x50: BX_ERROR(("write cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break;
+ case 0x51: BX_ERROR(("write cmd 0x51 (CONFIGURE STREAM) not supported"));command_aborted(channel, 0x51); break;
+ case 0x87: BX_ERROR(("write cmd 0x87 (CFA TRANSLATE SECTOR) not supported"));command_aborted(channel, 0x87); break;
+ case 0x92: BX_ERROR(("write cmd 0x92 (DOWNLOAD MICROCODE) not supported"));command_aborted(channel, 0x92); break;
+ case 0x94: BX_ERROR(("write cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break;
+ case 0x95: BX_ERROR(("write cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break;
+ case 0x96: BX_ERROR(("write cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break;
+ case 0x97: BX_ERROR(("write cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break;
+ case 0x98: BX_ERROR(("write cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break;
+ case 0x99: BX_ERROR(("write cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break;
+ case 0xB0: BX_ERROR(("write cmd 0xB0 (SMART commands) not supported"));command_aborted(channel, 0xB0); break;
+ case 0xB1: BX_ERROR(("write cmd 0xB1 (DEVICE CONFIGURATION commands) not supported"));command_aborted(channel, 0xB1); break;
+ case 0xC0: BX_ERROR(("write cmd 0xC0 (CFA ERASE SECTORS) not supported"));command_aborted(channel, 0xC0); break;
+ case 0xC4: BX_ERROR(("write cmd 0xC4 (READ MULTIPLE) not supported"));command_aborted(channel, 0xC4); break;
+ case 0xC5: BX_ERROR(("write cmd 0xC5 (WRITE MULTIPLE) not supported"));command_aborted(channel, 0xC5); break;
+ case 0xC7: BX_ERROR(("write cmd 0xC7 (READ DMA QUEUED) not supported"));command_aborted(channel, 0xC7); break;
+ case 0xC8: BX_ERROR(("write cmd 0xC8 (READ DMA) not supported"));command_aborted(channel, 0xC8); break;
+ case 0xC9: BX_ERROR(("write cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break;
+ case 0xCA: BX_ERROR(("write cmd 0xCA (WRITE DMA) not supported"));command_aborted(channel, 0xCA); break;
+ case 0xCC: BX_ERROR(("write cmd 0xCC (WRITE DMA QUEUED) not supported"));command_aborted(channel, 0xCC); break;
+ case 0xCD: BX_ERROR(("write cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported"));command_aborted(channel, 0xCD); break;
+ case 0xD1: BX_ERROR(("write cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported"));command_aborted(channel, 0xD1); break;
+ case 0xDA: BX_ERROR(("write cmd 0xDA (GET MEDIA STATUS) not supported"));command_aborted(channel, 0xDA); break;
+ case 0xDE: BX_ERROR(("write cmd 0xDE (MEDIA LOCK) not supported"));command_aborted(channel, 0xDE); break;
+ case 0xDF: BX_ERROR(("write cmd 0xDF (MEDIA UNLOCK) not supported"));command_aborted(channel, 0xDF); break;
+ case 0xE0: BX_ERROR(("write cmd 0xE0 (STANDBY IMMEDIATE) not supported"));command_aborted(channel, 0xE0); break;
+ case 0xE1: BX_ERROR(("write cmd 0xE1 (IDLE IMMEDIATE) not supported"));command_aborted(channel, 0xE1); break;
+ case 0xE2: BX_ERROR(("write cmd 0xE2 (STANDBY) not supported"));command_aborted(channel, 0xE2); break;
+ case 0xE3: BX_ERROR(("write cmd 0xE3 (IDLE) not supported"));command_aborted(channel, 0xE3); break;
+ case 0xE4: BX_ERROR(("write cmd 0xE4 (READ BUFFER) not supported"));command_aborted(channel, 0xE4); break;
+ case 0xE6: BX_ERROR(("write cmd 0xE6 (SLEEP) not supported"));command_aborted(channel, 0xE6); break;
+ case 0xE7: BX_ERROR(("write cmd 0xE7 (FLUSH CACHE) not supported"));command_aborted(channel, 0xE7); break;
+ case 0xE8: BX_ERROR(("write cmd 0xE8 (WRITE BUFFER) not supported"));command_aborted(channel, 0xE8); break;
+ case 0xEA: BX_ERROR(("write cmd 0xEA (FLUSH CACHE EXT) not supported"));command_aborted(channel, 0xEA); break;
+ case 0xED: BX_ERROR(("write cmd 0xED (MEDIA EJECT) not supported"));command_aborted(channel, 0xED); break;
+ case 0xF1: BX_ERROR(("write cmd 0xF1 (SECURITY SET PASSWORD) not supported"));command_aborted(channel, 0xF1); break;
+ case 0xF2: BX_ERROR(("write cmd 0xF2 (SECURITY UNLOCK) not supported"));command_aborted(channel, 0xF2); break;
+ case 0xF3: BX_ERROR(("write cmd 0xF3 (SECURITY ERASE PREPARE) not supported"));command_aborted(channel, 0xF3); break;
+ case 0xF4: BX_ERROR(("write cmd 0xF4 (SECURITY ERASE UNIT) not supported"));command_aborted(channel, 0xF4); break;
+ case 0xF5: BX_ERROR(("write cmd 0xF5 (SECURITY FREEZE LOCK) not supported"));command_aborted(channel, 0xF5); break;
+ case 0xF6: BX_ERROR(("write cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported"));command_aborted(channel, 0xF6); break;
+ case 0xF8: BX_ERROR(("write cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported"));command_aborted(channel, 0xF8); break;
+ case 0xF9: BX_ERROR(("write cmd 0xF9 (SET MAX ADDRESS) not supported"));command_aborted(channel, 0xF9); break;
+
+ default:
+ BX_PANIC(("IO write(0x%04x): command 0x%02x", address, (unsigned) value));
+ // if user foolishly decides to continue, abort the command
+ // so that the software knows the drive didn't understand it.
+ command_aborted(channel, value);
+ }
+ break;
+
+ case 0x16: // hard disk adapter control 0x3f6
+ // (mch) Even if device 1 was selected, a write to this register
+ // goes to device 0 (if device 1 is absent)
+
+ prev_control_reset = BX_SELECTED_CONTROLLER(channel).control.reset;
+ BX_HD_THIS channels[channel].drives[0].controller.control.reset = value & 0x04;
+ BX_HD_THIS channels[channel].drives[1].controller.control.reset = value & 0x04;
+ // CGS: was: BX_SELECTED_CONTROLLER(channel).control.disable_irq = value & 0x02;
+ BX_HD_THIS channels[channel].drives[0].controller.control.disable_irq = value & 0x02;
+ BX_HD_THIS channels[channel].drives[1].controller.control.disable_irq = value & 0x02;
+
+ BX_DEBUG(( "adpater control reg: reset controller = %d",
+ (unsigned) (BX_SELECTED_CONTROLLER(channel).control.reset) ? 1 : 0 ));
+ BX_DEBUG(( "adpater control reg: disable_irq(X) = %d",
+ (unsigned) (BX_SELECTED_CONTROLLER(channel).control.disable_irq) ? 1 : 0 ));
+
+ if (!prev_control_reset && BX_SELECTED_CONTROLLER(channel).control.reset) {
+ // transition from 0 to 1 causes all drives to reset
+ BX_DEBUG(("hard drive: RESET"));
+
+ // (mch) Set BSY, drive not ready
+ for (int id = 0; id < 2; id++) {
+ BX_CONTROLLER(channel,id).status.busy = 1;
+ BX_CONTROLLER(channel,id).status.drive_ready = 0;
+ BX_CONTROLLER(channel,id).reset_in_progress = 1;
+
+ BX_CONTROLLER(channel,id).status.write_fault = 0;
+ BX_CONTROLLER(channel,id).status.seek_complete = 1;
+ BX_CONTROLLER(channel,id).status.drq = 0;
+ BX_CONTROLLER(channel,id).status.corrected_data = 0;
+ BX_CONTROLLER(channel,id).status.err = 0;
+
+ BX_CONTROLLER(channel,id).error_register = 0x01; // diagnostic code: no error
+
+ BX_CONTROLLER(channel,id).current_command = 0x00;
+ BX_CONTROLLER(channel,id).buffer_index = 0;
+
+ BX_CONTROLLER(channel,id).sectors_per_block = 0x80;
+ BX_CONTROLLER(channel,id).lba_mode = 0;
+
+ BX_CONTROLLER(channel,id).control.disable_irq = 0;
+ DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+ }
+ } else if (BX_SELECTED_CONTROLLER(channel).reset_in_progress &&
+ !BX_SELECTED_CONTROLLER(channel).control.reset) {
+ // Clear BSY and DRDY
+ BX_DEBUG(("Reset complete {%s}", BX_SELECTED_TYPE_STRING(channel)));
+ for (int id = 0; id < 2; id++) {
+ BX_CONTROLLER(channel,id).status.busy = 0;
+ BX_CONTROLLER(channel,id).status.drive_ready = 1;
+ BX_CONTROLLER(channel,id).reset_in_progress = 0;
+
+ // Device signature
+ if (BX_DRIVE_IS_HD(channel,id)) {
+ BX_CONTROLLER(channel,id).head_no = 0;
+ BX_CONTROLLER(channel,id).sector_count = 1;
+ BX_CONTROLLER(channel,id).sector_no = 1;
+ BX_CONTROLLER(channel,id).cylinder_no = 0;
+ } else {
+ BX_CONTROLLER(channel,id).head_no = 0;
+ BX_CONTROLLER(channel,id).sector_count = 1;
+ BX_CONTROLLER(channel,id).sector_no = 1;
+ BX_CONTROLLER(channel,id).cylinder_no = 0xeb14;
+ }
+ }
+ }
+ BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq));
+ BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq));
+ break;
+
+ default:
+ BX_PANIC(("hard drive: io write to address %x = %02x",
+ (unsigned) address, (unsigned) value));
+ }
+}
+
+ void
+bx_hard_drive_c::close_harddrive(void)
+{
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if(BX_HD_THIS channels[channel].drives[0].hard_drive != NULL)
+ BX_HD_THIS channels[channel].drives[0].hard_drive->close();
+ if(BX_HD_THIS channels[channel].drives[1].hard_drive != NULL)
+ BX_HD_THIS channels[channel].drives[1].hard_drive->close();
+ }
+}
+
+
+ bx_bool BX_CPP_AttrRegparmN(2)
+bx_hard_drive_c::calculate_logical_address(Bit8u channel, off_t *sector)
+{
+ off_t logical_sector;
+
+ if (BX_SELECTED_CONTROLLER(channel).lba_mode) {
+ //bx_printf ("disk: calculate: %d %d %d\n", ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no), ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no), (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no);
+ logical_sector = ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no) << 24 |
+ ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no) << 8 |
+ (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no;
+ //bx_printf ("disk: result: %u\n", logical_sector);
+ } else
+ logical_sector = (BX_SELECTED_CONTROLLER(channel).cylinder_no * BX_SELECTED_DRIVE(channel).hard_drive->heads *
+ BX_SELECTED_DRIVE(channel).hard_drive->sectors) +
+ (BX_SELECTED_CONTROLLER(channel).head_no * BX_SELECTED_DRIVE(channel).hard_drive->sectors) +
+ (BX_SELECTED_CONTROLLER(channel).sector_no - 1);
+
+ Bit32u sector_count=
+ (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->cylinders *
+ (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->heads *
+ (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+ if (logical_sector >= sector_count) {
+ BX_ERROR (("calc_log_addr: out of bounds (%d/%d)", (Bit32u)logical_sector, sector_count));
+ return false;
+ }
+ *sector = logical_sector;
+ return true;
+}
+
+ void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::increment_address(Bit8u channel)
+{
+ BX_SELECTED_CONTROLLER(channel).sector_count--;
+
+ if (BX_SELECTED_CONTROLLER(channel).lba_mode) {
+ off_t current_address;
+ calculate_logical_address(channel, &current_address);
+ current_address++;
+ BX_SELECTED_CONTROLLER(channel).head_no = (Bit8u)((current_address >> 24) & 0xf);
+ BX_SELECTED_CONTROLLER(channel).cylinder_no = (Bit16u)((current_address >> 8) & 0xffff);
+ BX_SELECTED_CONTROLLER(channel).sector_no = (Bit8u)((current_address) & 0xff);
+ } else {
+ BX_SELECTED_CONTROLLER(channel).sector_no++;
+ if (BX_SELECTED_CONTROLLER(channel).sector_no > BX_SELECTED_DRIVE(channel).hard_drive->sectors) {
+ BX_SELECTED_CONTROLLER(channel).sector_no = 1;
+ BX_SELECTED_CONTROLLER(channel).head_no++;
+ if (BX_SELECTED_CONTROLLER(channel).head_no >= BX_SELECTED_DRIVE(channel).hard_drive->heads) {
+ BX_SELECTED_CONTROLLER(channel).head_no = 0;
+ BX_SELECTED_CONTROLLER(channel).cylinder_no++;
+ if (BX_SELECTED_CONTROLLER(channel).cylinder_no >= BX_SELECTED_DRIVE(channel).hard_drive->cylinders)
+ BX_SELECTED_CONTROLLER(channel).cylinder_no = BX_SELECTED_DRIVE(channel).hard_drive->cylinders - 1;
+ }
+ }
+ }
+}
+
+ void
+bx_hard_drive_c::identify_ATAPI_drive(Bit8u channel)
+{
+ unsigned i;
+
+ BX_SELECTED_DRIVE(channel).id_drive[0] = (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0); // Removable CDROM, 50us response, 12 byte packets
+
+ for (i = 1; i <= 9; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
+ for (i = 0; i < 10; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) |
+ serial_number[i*2 + 1];
+ }
+
+ for (i = 20; i <= 22; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ const char* firmware = "ALPHA1 ";
+ for (i = 0; i < strlen(firmware)/2; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) |
+ firmware[i*2 + 1];
+ }
+ BX_ASSERT((23+i) == 27);
+
+ for (i = 0; i < strlen((char *) BX_SELECTED_MODEL(channel))/2; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) |
+ BX_SELECTED_MODEL(channel)[i*2 + 1];
+ }
+ BX_ASSERT((27+i) == 47);
+
+ BX_SELECTED_DRIVE(channel).id_drive[47] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[48] = 1; // 32 bits access
+
+ BX_SELECTED_DRIVE(channel).id_drive[49] = (1 << 9); // LBA supported
+
+ BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[51] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[52] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[53] = 3; // words 64-70, 54-58 valid
+
+ for (i = 54; i <= 62; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // copied from CFA540A
+ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff)
+ BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO
+ BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4;
+ BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4;
+ BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c;
+ BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4;
+
+ BX_SELECTED_DRIVE(channel).id_drive[69] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[70] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[71] = 30; // faked
+ BX_SELECTED_DRIVE(channel).id_drive[72] = 30; // faked
+ BX_SELECTED_DRIVE(channel).id_drive[73] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[74] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[75] = 0;
+
+ for (i = 76; i <= 79; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[80] = 0x1e; // supports up to ATA/ATAPI-4
+ BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[82] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[83] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[84] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[85] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[87] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[88] = 0;
+
+ for (i = 89; i <= 126; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[127] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[128] = 0;
+
+ for (i = 129; i <= 159; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ for (i = 160; i <= 255; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // now convert the id_drive array (native 256 word format) to
+ // the controller buffer (512 bytes)
+ Bit16u temp16;
+ for (i = 0; i <= 255; i++) {
+ temp16 = BX_SELECTED_DRIVE(channel).id_drive[i];
+ BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff;
+ BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8;
+ }
+}
+
+ void
+bx_hard_drive_c::identify_drive(Bit8u channel)
+{
+ unsigned i;
+ Bit32u temp32;
+ Bit16u temp16;
+
+#if defined(CONNER_CFA540A)
+ BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0c5a;
+ BX_SELECTED_DRIVE(channel).id_drive[1] = 0x0418;
+ BX_SELECTED_DRIVE(channel).id_drive[2] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+ BX_SELECTED_DRIVE(channel).id_drive[4] = 0x9fb7;
+ BX_SELECTED_DRIVE(channel).id_drive[5] = 0x0289;
+ BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+ BX_SELECTED_DRIVE(channel).id_drive[7] = 0x0030;
+ BX_SELECTED_DRIVE(channel).id_drive[8] = 0x000a;
+ BX_SELECTED_DRIVE(channel).id_drive[9] = 0x0000;
+
+ char* serial_number = " CA00GSQ\0\0\0\0\0\0\0\0\0\0\0\0";
+ for (i = 0; i < 10; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) |
+ serial_number[i*2 + 1];
+ }
+
+ BX_SELECTED_DRIVE(channel).id_drive[20] = 3;
+ BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache
+ BX_SELECTED_DRIVE(channel).id_drive[22] = 4;
+
+ char* firmware = "8FT054 ";
+ for (i = 0; i < strlen(firmware)/2; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) |
+ firmware[i*2 + 1];
+ }
+ BX_ASSERT((23+i) == 27);
+
+ char* model = "Conner Peripherals 540MB - CFA540A ";
+ for (i = 0; i < strlen(model)/2; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (model[i*2] << 8) |
+ model[i*2 + 1];
+ }
+ BX_ASSERT((27+i) == 47);
+
+ BX_SELECTED_DRIVE(channel).id_drive[47] = 0x8080; // multiple mode identification
+ BX_SELECTED_DRIVE(channel).id_drive[48] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[49] = 0x0f01;
+
+ BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[51] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[52] = 0x0002;
+ BX_SELECTED_DRIVE(channel).id_drive[53] = 0x0003;
+ BX_SELECTED_DRIVE(channel).id_drive[54] = 0x0418;
+
+ BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+ BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+ BX_SELECTED_DRIVE(channel).id_drive[57] = 0x1e80;
+ BX_SELECTED_DRIVE(channel).id_drive[58] = 0x0010;
+ BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0100 | BX_SELECTED_CONTROLLER(channel).sectors_per_block;
+ BX_SELECTED_DRIVE(channel).id_drive[60] = 0x20e0;
+ BX_SELECTED_DRIVE(channel).id_drive[61] = 0x0010;
+
+ BX_SELECTED_DRIVE(channel).id_drive[62] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff)
+ BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO
+ BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4;
+ BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4;
+ BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c;
+ BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4;
+
+ for (i = 69; i <= 79; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[80] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[82] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[83] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[84] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[85] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[87] = 0;
+
+ for (i = 88; i <= 127; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[128] = 0x0418;
+ BX_SELECTED_DRIVE(channel).id_drive[129] = 0x103f;
+ BX_SELECTED_DRIVE(channel).id_drive[130] = 0x0418;
+ BX_SELECTED_DRIVE(channel).id_drive[131] = 0x103f;
+ BX_SELECTED_DRIVE(channel).id_drive[132] = 0x0004;
+ BX_SELECTED_DRIVE(channel).id_drive[133] = 0xffff;
+ BX_SELECTED_DRIVE(channel).id_drive[134] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[135] = 0x5050;
+
+ for (i = 136; i <= 144; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ BX_SELECTED_DRIVE(channel).id_drive[145] = 0x302e;
+ BX_SELECTED_DRIVE(channel).id_drive[146] = 0x3245;
+ BX_SELECTED_DRIVE(channel).id_drive[147] = 0x2020;
+ BX_SELECTED_DRIVE(channel).id_drive[148] = 0x2020;
+
+ for (i = 149; i <= 255; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+#else
+
+ // Identify Drive command return values definition
+ //
+ // This code is rehashed from some that was donated.
+ // I'm using ANSI X3.221-1994, AT Attachment Interface for Disk Drives
+ // and X3T10 2008D Working Draft for ATA-3
+
+
+ // Word 0: general config bit-significant info
+ // Note: bits 1-5 and 8-14 are now "Vendor specific (obsolete)"
+ // bit 15: 0=ATA device
+ // 1=ATAPI device
+ // bit 14: 1=format speed tolerance gap required
+ // bit 13: 1=track offset option available
+ // bit 12: 1=data strobe offset option available
+ // bit 11: 1=rotational speed tolerance is > 0,5% (typo?)
+ // bit 10: 1=disk transfer rate > 10Mbs
+ // bit 9: 1=disk transfer rate > 5Mbs but <= 10Mbs
+ // bit 8: 1=disk transfer rate <= 5Mbs
+ // bit 7: 1=removable cartridge drive
+ // bit 6: 1=fixed drive
+ // bit 5: 1=spindle motor control option implemented
+ // bit 4: 1=head switch time > 15 usec
+ // bit 3: 1=not MFM encoded
+ // bit 2: 1=soft sectored
+ // bit 1: 1=hard sectored
+ // bit 0: 0=reserved
+ BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0040;
+
+ // Word 1: number of user-addressable cylinders in
+ // default translation mode. If the value in words 60-61
+ // exceed 16,515,072, this word shall contain 16,383.
+ BX_SELECTED_DRIVE(channel).id_drive[1] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders;
+
+ // Word 2: reserved
+ BX_SELECTED_DRIVE(channel).id_drive[2] = 0;
+
+ // Word 3: number of user-addressable heads in default
+ // translation mode
+ BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+
+ // Word 4: # unformatted bytes per translated track in default xlate mode
+ // Word 5: # unformatted bytes per sector in default xlated mode
+ // Word 6: # user-addressable sectors per track in default xlate mode
+ // Note: words 4,5 are now "Vendor specific (obsolete)"
+ BX_SELECTED_DRIVE(channel).id_drive[4] = (512 * BX_SELECTED_DRIVE(channel).hard_drive->sectors);
+ BX_SELECTED_DRIVE(channel).id_drive[5] = 512;
+ BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+ // Word 7-9: Vendor specific
+ for (i=7; i<=9; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 10-19: Serial number (20 ASCII characters, 0000h=not specified)
+ // This field is right justified and padded with spaces (20h).
+ for (i=10; i<=19; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 20: buffer type
+ // 0000h = not specified
+ // 0001h = single ported single sector buffer which is
+ // not capable of simulataneous data xfers to/from
+ // the host and the disk.
+ // 0002h = dual ported multi-sector buffer capable of
+ // simulatenous data xfers to/from the host and disk.
+ // 0003h = dual ported mutli-sector buffer capable of
+ // simulatenous data xfers with a read caching
+ // capability.
+ // 0004h-ffffh = reserved
+ BX_SELECTED_DRIVE(channel).id_drive[20] = 3;
+
+ // Word 21: buffer size in 512 byte increments, 0000h = not specified
+ BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache
+
+ // Word 22: # of ECC bytes available on read/write long cmds
+ // 0000h = not specified
+ BX_SELECTED_DRIVE(channel).id_drive[22] = 4;
+
+ // Word 23..26: Firmware revision (8 ascii chars, 0000h=not specified)
+ // This field is left justified and padded with spaces (20h)
+ for (i=23; i<=26; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 27..46: Model number (40 ascii chars, 0000h=not specified)
+ // This field is left justified and padded with spaces (20h)
+// for (i=27; i<=46; i++)
+// BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+ for (i=0; i<20; i++) {
+ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) |
+ BX_SELECTED_MODEL(channel)[i*2 + 1];
+ }
+
+ // Word 47: 15-8 Vendor unique
+ // 7-0 00h= read/write multiple commands not implemented
+ // xxh= maximum # of sectors that can be transferred
+ // per interrupt on read and write multiple commands
+ BX_SELECTED_DRIVE(channel).id_drive[47] = max_multiple_sectors;
+
+ // Word 48: 0000h = cannot perform dword IO
+ // 0001h = can perform dword IO
+ BX_SELECTED_DRIVE(channel).id_drive[48] = 1;
+
+ // Word 49: Capabilities
+ // 15-10: 0 = reserved
+ // 9: 1 = LBA supported
+ // 8: 1 = DMA supported
+ // 7-0: Vendor unique
+ BX_SELECTED_DRIVE(channel).id_drive[49] = 1<<9;
+
+ // Word 50: Reserved
+ BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+
+ // Word 51: 15-8 PIO data transfer cycle timing mode
+ // 7-0 Vendor unique
+ BX_SELECTED_DRIVE(channel).id_drive[51] = 0x200;
+
+ // Word 52: 15-8 DMA data transfer cycle timing mode
+ // 7-0 Vendor unique
+ BX_SELECTED_DRIVE(channel).id_drive[52] = 0x200;
+
+ // Word 53: 15-1 Reserved
+ // 0 1=the fields reported in words 54-58 are valid
+ // 0=the fields reported in words 54-58 may be valid
+ BX_SELECTED_DRIVE(channel).id_drive[53] = 0;
+
+ // Word 54: # of user-addressable cylinders in curr xlate mode
+ // Word 55: # of user-addressable heads in curr xlate mode
+ // Word 56: # of user-addressable sectors/track in curr xlate mode
+ BX_SELECTED_DRIVE(channel).id_drive[54] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders;
+ BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+ BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+ // Word 57-58: Current capacity in sectors
+ // Excludes all sectors used for device specific purposes.
+ temp32 =
+ BX_SELECTED_DRIVE(channel).hard_drive->cylinders *
+ BX_SELECTED_DRIVE(channel).hard_drive->heads *
+ BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+ BX_SELECTED_DRIVE(channel).id_drive[57] = (temp32 & 0xffff); // LSW
+ BX_SELECTED_DRIVE(channel).id_drive[58] = (temp32 >> 16); // MSW
+
+ // Word 59: 15-9 Reserved
+ // 8 1=multiple sector setting is valid
+ // 7-0 current setting for number of sectors that can be
+ // transferred per interrupt on R/W multiple commands
+ BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0000 | curr_multiple_sectors;
+
+ // Word 60-61:
+ // If drive supports LBA Mode, these words reflect total # of user
+ // addressable sectors. This value does not depend on the current
+ // drive geometry. If the drive does not support LBA mode, these
+ // words shall be set to 0.
+ Bit32u num_sects = BX_SELECTED_DRIVE(channel).hard_drive->cylinders * BX_SELECTED_DRIVE(channel).hard_drive->heads * BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+ BX_SELECTED_DRIVE(channel).id_drive[60] = num_sects & 0xffff; // LSW
+ BX_SELECTED_DRIVE(channel).id_drive[61] = num_sects >> 16; // MSW
+
+ // Word 62: 15-8 single word DMA transfer mode active
+ // 7-0 single word DMA transfer modes supported
+ // The low order byte identifies by bit, all the Modes which are
+ // supported e.g., if Mode 0 is supported bit 0 is set.
+ // The high order byte contains a single bit set to indiciate
+ // which mode is active.
+ BX_SELECTED_DRIVE(channel).id_drive[62] = 0x0;
+
+ // Word 63: 15-8 multiword DMA transfer mode active
+ // 7-0 multiword DMA transfer modes supported
+ // The low order byte identifies by bit, all the Modes which are
+ // supported e.g., if Mode 0 is supported bit 0 is set.
+ // The high order byte contains a single bit set to indiciate
+ // which mode is active.
+ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0;
+
+ // Word 64-79 Reserved
+ for (i=64; i<=79; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 80: 15-5 reserved
+ // 4 supports ATA/ATAPI-4
+ // 3 supports ATA-3
+ // 2 supports ATA-2
+ // 1 supports ATA-1
+ // 0 reserved
+ BX_SELECTED_DRIVE(channel).id_drive[80] = (1 << 2) | (1 << 1);
+
+ // Word 81: Minor version number
+ BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+
+ // Word 82: 15 obsolete
+ // 14 NOP command supported
+ // 13 READ BUFFER command supported
+ // 12 WRITE BUFFER command supported
+ // 11 obsolete
+ // 10 Host protected area feature set supported
+ // 9 DEVICE RESET command supported
+ // 8 SERVICE interrupt supported
+ // 7 release interrupt supported
+ // 6 look-ahead supported
+ // 5 write cache supported
+ // 4 supports PACKET command feature set
+ // 3 supports power management feature set
+ // 2 supports removable media feature set
+ // 1 supports securite mode feature set
+ // 0 support SMART feature set
+ BX_SELECTED_DRIVE(channel).id_drive[82] = 1 << 14;
+ BX_SELECTED_DRIVE(channel).id_drive[83] = 1 << 14;
+ BX_SELECTED_DRIVE(channel).id_drive[84] = 1 << 14;
+ BX_SELECTED_DRIVE(channel).id_drive[85] = 1 << 14;
+ BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+ BX_SELECTED_DRIVE(channel).id_drive[87] = 1 << 14;
+
+ for (i=88; i<=127; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 128-159 Vendor unique
+ for (i=128; i<=159; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+ // Word 160-255 Reserved
+ for (i=160; i<=255; i++)
+ BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+#endif
+
+ BX_DEBUG(("Drive ID Info. initialized : %04d {%s}", 512, BX_SELECTED_TYPE_STRING(channel)));
+
+ // now convert the id_drive array (native 256 word format) to
+ // the controller buffer (512 bytes)
+ for (i=0; i<=255; i++) {
+ temp16 = BX_SELECTED_DRIVE(channel).id_drive[i];
+ BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff;
+ BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8;
+ }
+}
+
+ void BX_CPP_AttrRegparmN(3)
+bx_hard_drive_c::init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bool lazy)
+{
+ // BX_SELECTED_CONTROLLER(channel).byte_count is a union of BX_SELECTED_CONTROLLER(channel).cylinder_no;
+ // lazy is used to force a data read in the buffer at the next read.
+
+ if (BX_SELECTED_CONTROLLER(channel).byte_count == 0xffff)
+ BX_SELECTED_CONTROLLER(channel).byte_count = 0xfffe;
+
+ if ((BX_SELECTED_CONTROLLER(channel).byte_count & 1)
+ && !(alloc_length <= BX_SELECTED_CONTROLLER(channel).byte_count)) {
+ BX_INFO(("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x",
+ BX_SELECTED_CONTROLLER(channel).byte_count, command, BX_SELECTED_CONTROLLER(channel).byte_count - 1));
+ BX_SELECTED_CONTROLLER(channel).byte_count -= 1;
+ }
+
+ if (BX_SELECTED_CONTROLLER(channel).byte_count == 0)
+ BX_PANIC(("ATAPI command with zero byte count"));
+
+ if (alloc_length < 0)
+ BX_PANIC(("Allocation length < 0"));
+ if (alloc_length == 0)
+ alloc_length = BX_SELECTED_CONTROLLER(channel).byte_count;
+
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+ // no bytes transfered yet
+ if (lazy)
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 2048;
+ else
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ BX_SELECTED_CONTROLLER(channel).drq_index = 0;
+
+ if (BX_SELECTED_CONTROLLER(channel).byte_count > req_length)
+ BX_SELECTED_CONTROLLER(channel).byte_count = req_length;
+
+ if (BX_SELECTED_CONTROLLER(channel).byte_count > alloc_length)
+ BX_SELECTED_CONTROLLER(channel).byte_count = alloc_length;
+
+ BX_SELECTED_DRIVE(channel).atapi.command = command;
+ BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count;
+ BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining = (req_length < alloc_length) ? req_length : alloc_length;
+
+ // if (lazy) {
+ // // bias drq_bytes and total_bytes_remaining
+ // BX_SELECTED_DRIVE(channel).atapi.drq_bytes += 2048;
+ // BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining += 2048;
+ // }
+}
+
+void
+bx_hard_drive_c::atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc)
+{
+ BX_ERROR(("atapi_cmd_error channel=%02x key=%02x asc=%02x", channel, sense_key, asc));
+
+ BX_SELECTED_CONTROLLER(channel).error_register = sense_key << 4;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 1;
+
+ BX_SELECTED_DRIVE(channel).sense.sense_key = sense_key;
+ BX_SELECTED_DRIVE(channel).sense.asc = asc;
+ BX_SELECTED_DRIVE(channel).sense.ascq = 0;
+}
+
+void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::atapi_cmd_nop(Bit8u channel)
+{
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.err = 0;
+}
+
+void
+bx_hard_drive_c::init_mode_sense_single(Bit8u channel, const void* src, int size)
+{
+ // Header
+ BX_SELECTED_CONTROLLER(channel).buffer[0] = (size+6) >> 8;
+ BX_SELECTED_CONTROLLER(channel).buffer[1] = (size+6) & 0xff;
+ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x70; // no media present
+ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[5] = 0; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // reserved
+ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // reserved
+
+ // Data
+ memcpy(BX_SELECTED_CONTROLLER(channel).buffer + 8, src, size);
+}
+
+ void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::ready_to_send_atapi(Bit8u channel)
+{
+ raise_interrupt(channel);
+}
+
+void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::raise_interrupt(Bit8u channel)
+{
+ BX_DEBUG(("raise_interrupt called, disable_irq = %02x", BX_SELECTED_CONTROLLER(channel).control.disable_irq));
+ if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) { BX_DEBUG(("raising interrupt")); } else { BX_DEBUG(("Not raising interrupt")); }
+ if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) {
+ Bit32u irq = BX_HD_THIS channels[channel].irq;
+ BX_DEBUG(("Raising interrupt %d {%s}", irq, BX_SELECTED_TYPE_STRING(channel)));
+ DEV_pic_raise_irq(irq);
+ } else {
+ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+ BX_INFO(("Interrupt masked {%s}", BX_SELECTED_TYPE_STRING(channel)));
+ }
+}
+
+ void
+bx_hard_drive_c::command_aborted(Bit8u channel, unsigned value)
+{
+ BX_DEBUG(("aborting on command 0x%02x {%s}", value, BX_SELECTED_TYPE_STRING(channel)));
+ BX_SELECTED_CONTROLLER(channel).current_command = 0;
+ BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+ BX_SELECTED_CONTROLLER(channel).status.err = 1;
+ BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // command ABORTED
+ BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+ BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+ raise_interrupt(channel);
+}
+
+ Bit32u
+bx_hard_drive_c::get_device_handle(Bit8u channel, Bit8u device)
+{
+ BX_DEBUG(("get_device_handle %d %d",channel, device));
+ if ((channel < BX_MAX_ATA_CHANNEL) && (device < 2)) {
+ return ((channel*2) + device);
+ }
+
+ return BX_MAX_ATA_CHANNEL*2;
+}
+
+ Bit32u
+bx_hard_drive_c::get_first_cd_handle(void)
+{
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ if (BX_DRIVE_IS_CD(channel,0)) return (channel*2);
+ if (BX_DRIVE_IS_CD(channel,1)) return ((channel*2) + 1);
+ }
+ return BX_MAX_ATA_CHANNEL*2;
+}
+
+ unsigned
+bx_hard_drive_c::get_cd_media_status(Bit32u handle)
+{
+ if ( handle >= BX_MAX_ATA_CHANNEL*2 ) return 0;
+
+ Bit8u channel = handle / 2;
+ Bit8u device = handle % 2;
+ return( BX_HD_THIS channels[channel].drives[device].cdrom.ready );
+}
+
+ unsigned
+bx_hard_drive_c::set_cd_media_status(Bit32u handle, unsigned status)
+{
+ BX_DEBUG (("set_cd_media_status handle=%d status=%d", handle, status));
+ if ( handle >= BX_MAX_ATA_CHANNEL*2 ) return 0;
+
+ Bit8u channel = handle / 2;
+ Bit8u device = handle % 2;
+
+ // if setting to the current value, nothing to do
+ if (status == BX_HD_THIS channels[channel].drives[device].cdrom.ready)
+ return(status);
+ // return 0 if no cdromd is present
+ if (!BX_DRIVE_IS_CD(channel,device))
+ return(0);
+
+ if (status == 0) {
+ // eject cdrom if not locked by guest OS
+ if (BX_HD_THIS channels[channel].drives[device].cdrom.locked) return(1);
+ else {
+#ifdef LOWLEVEL_CDROM
+ BX_HD_THIS channels[channel].drives[device].cdrom.cd->eject_cdrom();
+#endif
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+ }
+ }
+ else {
+ // insert cdrom
+#ifdef LOWLEVEL_CDROM
+ if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom(bx_options.atadevice[channel][device].Opath->getptr())) {
+ BX_INFO(( "Media present in CD-ROM drive"));
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
+ BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
+ bx_options.atadevice[channel][device].Ostatus->set(BX_INSERTED);
+ BX_SELECTED_DRIVE(channel).sense.sense_key = SENSE_UNIT_ATTENTION;
+ BX_SELECTED_DRIVE(channel).sense.asc = 0;
+ BX_SELECTED_DRIVE(channel).sense.ascq = 0;
+ raise_interrupt(channel);
+ }
+ else {
+#endif
+ BX_INFO(( "Could not locate CD-ROM, continuing with media not present"));
+ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+#ifdef LOWLEVEL_CDROM
+ }
+#endif
+ }
+ return( BX_HD_THIS channels[channel].drives[device].cdrom.ready );
+}
+
+
+/*** default_image_t function definitions ***/
+
+int default_image_t::open (const char* pathname)
+{
+ return open(pathname, O_RDWR);
+}
+
+int default_image_t::open (const char* pathname, int flags)
+{
+ fd = ::open(pathname, flags
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+
+ if (fd < 0) {
+ return fd;
+ }
+
+ /* look at size of image file to calculate disk geometry */
+ struct stat stat_buf;
+ int ret = fstat(fd, &stat_buf);
+ if (ret) {
+ BX_PANIC(("fstat() returns error!"));
+ }
+
+ return fd;
+}
+
+void default_image_t::close ()
+{
+ if (fd > -1) {
+ ::close(fd);
+ }
+}
+
+off_t default_image_t::lseek (off_t offset, int whence)
+{
+ return ::lseek(fd, offset, whence);
+}
+
+ssize_t default_image_t::read (void* buf, size_t count)
+{
+ return ::read(fd, (char*) buf, count);
+}
+
+ssize_t default_image_t::write (const void* buf, size_t count)
+{
+ return ::write(fd, (char*) buf, count);
+}
+
+char increment_string (char *str, int diff)
+{
+ // find the last character of the string, and increment it.
+ char *p = str;
+ while (*p != 0) p++;
+ BX_ASSERT (p>str); // choke on zero length strings
+ p--; // point to last character of the string
+ (*p) += diff; // increment to next/previous ascii code.
+ BX_DEBUG(("increment string returning '%s'", str));
+ return (*p);
+}
+
+/*** concat_image_t function definitions ***/
+
+concat_image_t::concat_image_t ()
+{
+ fd = -1;
+}
+
+void concat_image_t::increment_string (char *str)
+{
+ ::increment_string(str, +1);
+}
+
+int concat_image_t::open (const char* pathname0)
+{
+ char *pathname = strdup (pathname0);
+ BX_DEBUG(("concat_image_t.open"));
+ off_t start_offset = 0;
+ for (int i=0; i<BX_CONCAT_MAX_IMAGES; i++) {
+ fd_table[i] = ::open(pathname, O_RDWR
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd_table[i] < 0) {
+ // open failed.
+ // if no FD was opened successfully, return -1 (fail).
+ if (i==0) return -1;
+ // otherwise, it only means that all images in the series have
+ // been opened. Record the number of fds opened successfully.
+ maxfd = i;
+ break;
+ }
+ BX_DEBUG(("concat_image: open image %s, fd[%d] = %d", pathname, i, fd_table[i]));
+ /* look at size of image file to calculate disk geometry */
+ struct stat stat_buf;
+ int ret = fstat(fd_table[i], &stat_buf);
+ if (ret) {
+ BX_PANIC(("fstat() returns error!"));
+ }
+#ifdef S_ISBLK
+ if (S_ISBLK(stat_buf.st_mode)) {
+ BX_PANIC(("block devices should REALLY NOT be used with --enable-split-hd. "
+ "Please reconfigure with --disable-split-hd"));
+ }
+#endif
+ if ((stat_buf.st_size % 512) != 0) {
+ BX_PANIC(("size of disk image must be multiple of 512 bytes"));
+ }
+ length_table[i] = stat_buf.st_size;
+ start_offset_table[i] = start_offset;
+ start_offset += stat_buf.st_size;
+ increment_string (pathname);
+ }
+ // start up with first image selected
+ index = 0;
+ fd = fd_table[0];
+ thismin = 0;
+ thismax = length_table[0]-1;
+ seek_was_last_op = 0;
+ return 0; // success.
+}
+
+void concat_image_t::close ()
+{
+ BX_DEBUG(("concat_image_t.close"));
+ if (fd > -1) {
+ ::close(fd);
+ }
+}
+
+off_t concat_image_t::lseek (off_t offset, int whence)
+{
+ if ((offset % 512) != 0)
+ BX_PANIC( ("lseek HD with offset not multiple of 512"));
+ BX_DEBUG(("concat_image_t.lseek(%d)", whence));
+ // is this offset in this disk image?
+ if (offset < thismin) {
+ // no, look at previous images
+ for (int i=index-1; i>=0; i--) {
+ if (offset >= start_offset_table[i]) {
+ index = i;
+ fd = fd_table[i];
+ thismin = start_offset_table[i];
+ thismax = thismin + length_table[i] - 1;
+ BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
+ break;
+ }
+ }
+ } else if (offset > thismax) {
+ // no, look at later images
+ for (int i=index+1; i<maxfd; i++) {
+ if (offset < start_offset_table[i] + length_table[i]) {
+ index = i;
+ fd = fd_table[i];
+ thismin = start_offset_table[i];
+ thismax = thismin + length_table[i] - 1;
+ BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
+ break;
+ }
+ }
+ }
+ // now offset should be within the current image.
+ offset -= start_offset_table[index];
+ if (offset < 0 || offset >= length_table[index]) {
+ BX_PANIC(("concat_image_t.lseek to byte %ld failed", (long)offset));
+ return -1;
+ }
+
+ seek_was_last_op = 1;
+ return ::lseek(fd, offset, whence);
+}
+
+ssize_t concat_image_t::read (void* buf, size_t count)
+{
+ if (bx_dbg.disk)
+ BX_DEBUG(("concat_image_t.read %ld bytes", (long)count));
+ // notice if anyone does sequential read or write without seek in between.
+ // This can be supported pretty easily, but needs additional checks for
+ // end of a partial image.
+ if (!seek_was_last_op)
+ BX_PANIC( ("no seek before read"));
+ return ::read(fd, (char*) buf, count);
+}
+
+ssize_t concat_image_t::write (const void* buf, size_t count)
+{
+ BX_DEBUG(("concat_image_t.write %ld bytes", (long)count));
+ // notice if anyone does sequential read or write without seek in between.
+ // This can be supported pretty easily, but needs additional checks for
+ // end of a partial image.
+ if (!seek_was_last_op)
+ BX_PANIC( ("no seek before write"));
+ return ::write(fd, (char*) buf, count);
+}
+
+/*** sparse_image_t function definitions ***/
+sparse_image_t::sparse_image_t ()
+{
+ fd = -1;
+ pathname = NULL;
+#ifdef _POSIX_MAPPED_FILES
+ mmap_header = NULL;
+#endif
+ pagetable = NULL;
+}
+
+
+/*
+void showpagetable(uint32 * pagetable, size_t numpages)
+{
+ printf("Non null pages: ");
+ for (int i = 0; i < numpages; i++)
+ {
+ if (pagetable[i] != 0xffffffff)
+ {
+ printf("%d ", i);
+ }
+ }
+ printf("\n");
+}
+*/
+
+
+void sparse_image_t::read_header()
+{
+ BX_ASSERT(sizeof(header) == SPARSE_HEADER_SIZE);
+
+ int ret = ::read(fd, &header, sizeof(header));
+
+ if (-1 == ret)
+ {
+ panic(strerror(errno));
+ }
+
+ if (sizeof(header) != ret)
+ {
+ panic("could not read entire header");
+ }
+
+ if (dtoh32(header.magic) != SPARSE_HEADER_MAGIC)
+ {
+ panic("failed header magic check");
+ }
+
+ if (dtoh32(header.version) != 1)
+ {
+ panic("unknown version in header");
+ }
+
+ pagesize = dtoh32(header.pagesize);
+ uint32 numpages = dtoh32(header.numpages);
+
+ total_size = pagesize;
+ total_size *= numpages;
+
+ pagesize_shift = 0;
+ while ((pagesize >> pagesize_shift) > 1) pagesize_shift++;
+
+ if ((uint32)(1 << pagesize_shift) != pagesize)
+ {
+ panic("failed block size header check");
+ }
+
+ pagesize_mask = pagesize - 1;
+
+ size_t preamble_size = (sizeof(uint32) * numpages) + sizeof(header);
+ data_start = 0;
+ while (data_start < preamble_size) data_start += pagesize;
+
+ bool did_mmap = false;
+
+#ifdef _POSIX_MAPPED_FILES
+// Try to memory map from the beginning of the file (0 is trivially a page multiple)
+ void * mmap_header = mmap(NULL, preamble_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mmap_header == MAP_FAILED)
+ {
+ BX_INFO(("failed to mmap sparse disk file - using conventional file access"));
+ mmap_header = NULL;
+ }
+ else
+ {
+ mmap_length = preamble_size;
+ did_mmap = true;
+ pagetable = ((uint32 *) (((uint8 *) mmap_header) + sizeof(header)));
+
+// system_pagesize = getpagesize();
+ system_pagesize_mask = getpagesize() - 1;
+ }
+#endif
+
+ if (!did_mmap)
+ {
+ pagetable = new uint32[numpages];
+
+ if (pagetable == NULL)
+ {
+ panic("could not allocate memory for sparse disk block table");
+ }
+
+ ret = ::read(fd, pagetable, sizeof(uint32) * numpages);
+
+ if (-1 == ret)
+ {
+ panic(strerror(errno));
+ }
+
+ if ((int)(sizeof(uint32) * numpages) != ret)
+ {
+ panic("could not read entire block table");
+ }
+ }
+}
+
+int sparse_image_t::open (const char* pathname0)
+{
+ pathname = strdup(pathname0);
+ BX_DEBUG(("sparse_image_t.open"));
+
+ fd = ::open(pathname, O_RDWR
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+
+ if (fd < 0)
+ {
+ // open failed.
+ return -1;
+ }
+ BX_DEBUG(("sparse_image: open image %s", pathname));
+
+ read_header();
+
+ struct stat stat_buf;
+ if (0 != fstat(fd, &stat_buf)) panic(("fstat() returns error!"));
+
+ underlying_filesize = stat_buf.st_size;
+
+ if ((underlying_filesize % pagesize) != 0)
+ panic("size of sparse disk image is not multiple of page size");
+
+ underlying_current_filepos = 0;
+ if (-1 == ::lseek(fd, 0, SEEK_SET))
+ panic("error while seeking to start of file");
+
+ lseek(0, SEEK_SET);
+
+ //showpagetable(pagetable, header.numpages);
+
+ char * parentpathname = strdup(pathname);
+ char lastchar = ::increment_string(parentpathname, -1);
+
+ if ((lastchar >= '0') && (lastchar <= '9'))
+ {
+ struct stat stat_buf;
+ if (0 == stat(parentpathname, &stat_buf))
+ {
+ parent_image = new sparse_image_t();
+ int ret = parent_image->open(parentpathname);
+ if (ret != 0) return ret;
+ if ( (parent_image->pagesize != pagesize)
+ || (parent_image->total_size != total_size))
+ {
+ panic("child drive image does not have same page count/page size configuration");
+ }
+ }
+ }
+
+ if (parentpathname != NULL) free(parentpathname);
+
+ return 0; // success.
+}
+
+void sparse_image_t::close ()
+{
+ BX_DEBUG(("concat_image_t.close"));
+ if (pathname != NULL)
+ {
+ free(pathname);
+ }
+#ifdef _POSIX_MAPPED_FILES
+ if (mmap_header != NULL)
+ {
+ int ret = munmap(mmap_header, mmap_length);
+ if (ret != 0)
+ BX_INFO(("failed to un-memory map sparse disk file"));
+ }
+ pagetable = NULL; // We didn't malloc it
+#endif
+ if (fd > -1) {
+ ::close(fd);
+ }
+ if (pagetable != NULL)
+ {
+ delete [] pagetable;
+ }
+ if (parent_image != NULL)
+ {
+ delete parent_image;
+ }
+}
+
+off_t sparse_image_t::lseek (off_t offset, int whence)
+{
+ //showpagetable(pagetable, header.numpages);
+
+ if ((offset % 512) != 0)
+ BX_PANIC( ("lseek HD with offset not multiple of 512"));
+ if (whence != SEEK_SET)
+ BX_PANIC( ("lseek HD with whence not SEEK_SET"));
+
+ BX_DEBUG(("sparse_image_t.lseek(%d)", whence));
+
+ if (offset > total_size)
+ {
+ BX_PANIC(("sparse_image_t.lseek to byte %ld failed", (long)offset));
+ return -1;
+ }
+
+ //printf("Seeking to position %ld\n", (long) offset);
+
+ set_virtual_page(offset >> pagesize_shift);
+ position_page_offset = offset & pagesize_mask;
+
+ return 0;
+}
+
+inline off_t sparse_image_t::get_physical_offset()
+{
+ off_t physical_offset = data_start;
+ physical_offset += (position_physical_page << pagesize_shift);
+ physical_offset += position_page_offset;
+
+ return physical_offset;
+}
+
+inline void sparse_image_t::set_virtual_page(uint32 new_virtual_page)
+{
+ position_virtual_page = new_virtual_page;
+
+ position_physical_page = dtoh32(pagetable[position_virtual_page]);
+}
+
+ssize_t sparse_image_t::read_page_fragment(uint32 read_virtual_page, uint32 read_page_offset, size_t read_size, void * buf)
+{
+ if (read_virtual_page != position_virtual_page)
+ {
+ set_virtual_page(read_virtual_page);
+ }
+
+ position_page_offset = read_page_offset;
+
+ if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
+ {
+ if (parent_image != NULL)
+ {
+ return parent_image->read_page_fragment(read_virtual_page, read_page_offset, read_size, buf);
+ }
+ else
+ {
+ memset(buf, read_size, 0);
+ }
+ }
+ else
+ {
+ off_t physical_offset = get_physical_offset();
+
+ if (physical_offset != underlying_current_filepos)
+ {
+ int ret = ::lseek(fd, physical_offset, SEEK_SET);
+ // underlying_current_filepos update deferred
+ if (ret == -1)
+ panic(strerror(errno));
+ }
+
+ //printf("Reading %s at position %ld size %d\n", pathname, (long) physical_offset, (long) read_size);
+ ssize_t readret = ::read(fd, buf, read_size);
+
+ if (readret == -1)
+ {
+ panic(strerror(errno));
+ }
+
+ if ((size_t)readret != read_size)
+ {
+ panic("could not read block contents from file");
+ }
+
+ underlying_current_filepos = physical_offset + read_size;
+ }
+
+ return read_size;
+}
+
+ssize_t sparse_image_t::read(void* buf, size_t count)
+{
+ //showpagetable(pagetable, header.numpages);
+ ssize_t total_read = 0;
+
+ if (bx_dbg.disk)
+ BX_DEBUG(("sparse_image_t.read %ld bytes", (long)count));
+
+ while (count != 0)
+ {
+ size_t can_read = pagesize - position_page_offset;
+ if (count < can_read) can_read = count;
+
+ BX_ASSERT (can_read != 0);
+
+ size_t was_read = read_page_fragment(position_virtual_page, position_page_offset, can_read, buf);
+
+ BX_ASSERT(was_read == can_read);
+
+ total_read += can_read;
+
+ position_page_offset += can_read;
+ if (position_page_offset == pagesize)
+ {
+ position_page_offset = 0;
+ set_virtual_page(position_virtual_page + 1);
+ }
+
+ BX_ASSERT(position_page_offset < pagesize);
+
+ buf = (((uint8 *) buf) + can_read);
+ count -= can_read;
+ }
+
+ return total_read;
+}
+
+void sparse_image_t::panic(const char * message)
+{
+ char buffer[1024];
+ if (message == NULL)
+ {
+ snprintf(buffer, sizeof(buffer), "error with sparse disk image %s", pathname);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "error with sparse disk image %s - %s", pathname, message);
+ }
+ BX_PANIC((buffer));
+}
+
+ssize_t sparse_image_t::write (const void* buf, size_t count)
+{
+ //showpagetable(pagetable, header.numpages);
+
+ ssize_t total_written = 0;
+
+ uint32 update_pagetable_start = position_virtual_page;
+ uint32 update_pagetable_count = 0;
+
+ if (bx_dbg.disk)
+ BX_DEBUG(("sparse_image_t.write %ld bytes", (long)count));
+
+ while (count != 0)
+ {
+ size_t can_write = pagesize - position_page_offset;
+ if (count < can_write) can_write = count;
+
+ BX_ASSERT (can_write != 0);
+
+ if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
+ {
+ // We just add on another page at the end of the file
+ // Reclamation, compaction etc should currently be done off-line
+
+ size_t data_size = underlying_filesize - data_start;
+ BX_ASSERT((data_size % pagesize) == 0);
+
+
+ uint32 data_size_pages = data_size / pagesize;
+ uint32 next_data_page = data_size_pages;
+
+ pagetable[position_virtual_page] = htod32(next_data_page);
+ position_physical_page = next_data_page;
+
+ off_t page_file_start = data_start + (position_physical_page << pagesize_shift);
+
+ if (parent_image != NULL)
+ {
+ // If we have a parent, we must merge our portion with the parent
+ void * writebuffer = NULL;
+
+ if (can_write == pagesize)
+ {
+ writebuffer = (void *) buf;
+ }
+ else
+ {
+ writebuffer = malloc(pagesize);
+ if (writebuffer == NULL)
+ panic("Cannot allocate sufficient memory for page-merge in write");
+
+ // Read entire page - could optimize, but simple for now
+ parent_image->read_page_fragment(position_virtual_page, 0, pagesize, writebuffer);
+
+ void * dest_start = ((uint8 *) writebuffer) + position_page_offset;
+ memcpy(dest_start, buf, can_write);
+ }
+
+ int ret;
+ ret = ::lseek(fd, page_file_start, SEEK_SET);
+ // underlying_current_filepos update deferred
+ if (-1 == ret) panic(strerror(errno));
+
+ ret = ::write(fd, writebuffer, pagesize);
+
+ if (-1 == ret) panic(strerror(errno));
+
+ if (pagesize != (uint32)ret) panic("failed to write entire merged page to disk");
+
+ if (can_write != pagesize)
+ {
+ free(writebuffer);
+ }
+ }
+ else
+ {
+ // We need to write a zero page because read has been returning zeroes
+ // We seek as close to the page end as possible, and then write a little
+ // This produces a sparse file which has blanks
+ // Also very quick, even when pagesize is massive
+ int ret;
+ ret = ::lseek(fd, page_file_start + pagesize - 4, SEEK_SET);
+ // underlying_current_filepos update deferred
+ if (-1 == ret) panic(strerror(errno));
+
+ uint32 zero = 0;
+ ret = ::write(fd, &zero, 4);
+
+ if (-1 == ret) panic(strerror(errno));
+
+ if (4 != ret) panic("failed to write entire blank page to disk");
+ }
+
+ update_pagetable_count = (position_virtual_page - update_pagetable_start) + 1;
+ underlying_filesize = underlying_current_filepos = page_file_start + pagesize;
+ }
+
+ BX_ASSERT(position_physical_page != SPARSE_PAGE_NOT_ALLOCATED);
+
+ off_t physical_offset = get_physical_offset();
+
+ if (physical_offset != underlying_current_filepos)
+ {
+ int ret = ::lseek(fd, physical_offset, SEEK_SET);
+ // underlying_current_filepos update deferred
+ if (ret == -1)
+ panic(strerror(errno));
+ }
+
+ //printf("Writing at position %ld size %d\n", (long) physical_offset, can_write);
+ ssize_t writeret = ::write(fd, buf, can_write);
+
+ if (writeret == -1)
+ {
+ panic(strerror(errno));
+ }
+
+ if ((size_t)writeret != can_write)
+ {
+ panic("could not write block contents to file");
+ }
+
+ underlying_current_filepos = physical_offset + can_write;
+
+ total_written += can_write;
+
+ position_page_offset += can_write;
+ if (position_page_offset == pagesize)
+ {
+ position_page_offset = 0;
+ set_virtual_page(position_virtual_page + 1);
+ }
+
+ BX_ASSERT(position_page_offset < pagesize);
+
+ buf = (((uint8 *) buf) + can_write);
+ count -= can_write;
+ }
+
+ if (update_pagetable_count != 0)
+ {
+ bool done = false;
+ off_t pagetable_write_from = sizeof(header) + (sizeof(uint32) * update_pagetable_start);
+ size_t write_bytecount = update_pagetable_count * sizeof(uint32);
+
+#ifdef _POSIX_MAPPED_FILES
+ if (mmap_header != NULL)
+ {
+ // Sync from the beginning of the page
+ size_t system_page_offset = pagetable_write_from & system_pagesize_mask;
+ void * start = ((uint8 *) mmap_header + pagetable_write_from - system_page_offset);
+
+ int ret = msync(start, system_page_offset + write_bytecount, MS_ASYNC);
+
+ if (ret != 0)
+ panic(strerror(errno));
+
+ done = true;
+ }
+#endif
+
+ if (!done)
+ {
+ int ret = ::lseek(fd, pagetable_write_from, SEEK_SET);
+ // underlying_current_filepos update deferred
+ if (ret == -1) panic(strerror(errno));
+
+ //printf("Writing header at position %ld size %ld\n", (long) pagetable_write_from, (long) write_bytecount);
+ ret = ::write(fd, &pagetable[update_pagetable_start], write_bytecount);
+ if (ret == -1) panic(strerror(errno));
+ if ((size_t)ret != write_bytecount) panic("could not write entire updated block header");
+
+ underlying_current_filepos = pagetable_write_from + write_bytecount;
+ }
+ }
+
+ return total_written;
+}
+
+#if DLL_HD_SUPPORT
+/*** dll_image_t function definitions ***/
+
+/*
+function vdisk_open(path:PChar;numclusters,clustersize:integer):integer;
+procedure vdisk_read(vunit:integer;blk:integer;var buf:TBlock);
+procedure vdisk_write(vunit:integer;blk:integer;var buf:TBlock);
+procedure vdisk_close(vunit:integer);
+*/
+
+HINSTANCE hlib_vdisk = 0;
+
+int (*vdisk_open) (const char *path,int numclusters,int clustersize);
+void (*vdisk_read) (int vunit,int blk,void *buf);
+void (*vdisk_write) (int vunit,int blk,const void *buf);
+void (*vdisk_close) (int vunit);
+
+int dll_image_t::open (const char* pathname)
+{
+ if (hlib_vdisk == 0) {
+ hlib_vdisk = LoadLibrary("vdisk.dll");
+ if (hlib_vdisk != 0) {
+ vdisk_read = (void (*)(int,int,void*)) GetProcAddress(hlib_vdisk,"vdisk_read");
+ vdisk_write = (void (*)(int,int,const void*)) GetProcAddress(hlib_vdisk,"vdisk_write");
+ vdisk_open = (int (*)(const char *,int,int)) GetProcAddress(hlib_vdisk,"vdisk_open");
+ vdisk_close = (void (*)(int)) GetProcAddress(hlib_vdisk,"vdisk_close");
+ }
+ }
+ if (hlib_vdisk != 0) {
+ vunit = vdisk_open(pathname,0x10000,64);
+ vblk = 0;
+ } else {
+ vunit = -2;
+ }
+ return vunit;
+}
+
+void dll_image_t::close ()
+{
+ if (vunit >= 0 && hlib_vdisk != 0) {
+ vdisk_close(vunit);
+ }
+}
+
+off_t dll_image_t::lseek (off_t offset, int whence)
+{
+ vblk = offset >> 9;
+ return 0;
+}
+
+ssize_t dll_image_t::read (void* buf, size_t count)
+{
+ if (vunit >= 0 && hlib_vdisk != 0) {
+ vdisk_read(vunit,vblk,buf);
+ return count;
+ } else {
+ return -1;
+ }
+}
+
+ssize_t dll_image_t::write (const void* buf, size_t count)
+{
+ if (vunit >= 0 && hlib_vdisk != 0) {
+ vdisk_write(vunit,vblk,buf);
+ return count;
+ } else {
+ return -1;
+ }
+}
+#endif // DLL_HD_SUPPORT
+
+error_recovery_t::error_recovery_t ()
+{
+ if (sizeof(error_recovery_t) != 8) {
+ BX_PANIC(("error_recovery_t has size != 8"));
+ }
+
+ data[0] = 0x01;
+ data[1] = 0x06;
+ data[2] = 0x00;
+ data[3] = 0x05; // Try to recover 5 times
+ data[4] = 0x00;
+ data[5] = 0x00;
+ data[6] = 0x00;
+ data[7] = 0x00;
+}
+
+uint16 BX_CPP_AttrRegparmN(1)
+read_16bit(const uint8* buf)
+{
+ return (buf[0] << 8) | buf[1];
+}
+
+uint32 BX_CPP_AttrRegparmN(1)
+read_32bit(const uint8* buf)
+{
+ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+// redolog implementation
+redolog_t::redolog_t ()
+{
+ fd = -1;
+ catalog = NULL;
+ bitmap = NULL;
+ extent_index = (Bit32u)0;
+ extent_offset = (Bit32u)0;
+ extent_next = (Bit32u)0;
+}
+
+void
+redolog_t::print_header()
+{
+ BX_INFO(("redolog : Standard Header : magic='%s', type='%s', subtype='%s', version = %d.%d",
+ header.standard.magic, header.standard.type, header.standard.subtype,
+ dtoh32(header.standard.version)/0x10000,
+ dtoh32(header.standard.version)%0x10000));
+ BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = %lld",
+ dtoh32(header.specific.catalog),
+ dtoh32(header.specific.bitmap),
+ dtoh32(header.specific.extent),
+ dtoh64(header.specific.disk)));
+}
+
+int
+redolog_t::make_header (const char* type, Bit64u size)
+{
+ Bit32u entries, extent_size, bitmap_size;
+ Bit64u maxsize;
+ Bit32u flip=0;
+
+ // Set standard header values
+ strcpy((char*)header.standard.magic, STANDARD_HEADER_MAGIC);
+ strcpy((char*)header.standard.type, REDOLOG_TYPE);
+ strcpy((char*)header.standard.subtype, type);
+ header.standard.version = htod32(STANDARD_HEADER_VERSION);
+ header.standard.header = htod32(STANDARD_HEADER_SIZE);
+
+ entries = 512;
+ bitmap_size = 1;
+
+ // Compute #entries and extent size values
+ do {
+ extent_size = 8 * bitmap_size * 512;
+
+ header.specific.catalog = htod32(entries);
+ header.specific.bitmap = htod32(bitmap_size);
+ header.specific.extent = htod32(extent_size);
+
+ maxsize = (Bit64u)entries * (Bit64u)extent_size;
+
+ flip++;
+
+ if(flip&0x01) bitmap_size *= 2;
+ else entries *= 2;
+ } while (maxsize < size);
+
+ header.specific.disk = htod64(size);
+
+ print_header();
+
+ catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
+ bitmap = (Bit8u*)malloc(dtoh32(header.specific.bitmap));
+
+ if ((catalog == NULL) || (bitmap==NULL))
+ BX_PANIC(("redolog : could not malloc catalog or bitmap"));
+
+ for (Bit32u i=0; i<dtoh32(header.specific.catalog); i++)
+ catalog[i] = htod32(REDOLOG_PAGE_NOT_ALLOCATED);
+
+ bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
+ extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
+
+ BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
+ BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
+
+ return 0;
+}
+
+int
+redolog_t::create (const char* filename, const char* type, Bit64u size)
+{
+ int filedes;
+
+ BX_INFO(("redolog : creating redolog %s", filename));
+
+ filedes = ::open(filename, O_RDWR | O_CREAT | O_TRUNC
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
+
+ return create(filedes, type, size);
+}
+
+int
+redolog_t::create (int filedes, const char* type, Bit64u size)
+{
+ fd = filedes;
+
+ if (fd < 0)
+ {
+ // open failed.
+ return -1;
+ }
+
+ if (make_header(type, size) < 0)
+ {
+ return -1;
+ }
+
+ // Write header
+ ::write(fd, &header, dtoh32(header.standard.header));
+
+ // Write catalog
+ // FIXME could mmap
+ ::write(fd, catalog, dtoh32(header.specific.catalog) * sizeof (Bit32u));
+
+ return 0;
+}
+
+int
+redolog_t::open (const char* filename, const char *type, Bit64u size)
+{
+ int res;
+
+ fd = ::open(filename, O_RDWR
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0)
+ {
+ BX_INFO(("redolog : could not open image %s", filename));
+ // open failed.
+ return -1;
+ }
+ BX_INFO(("redolog : open image %s", filename));
+
+ res = ::read(fd, &header, sizeof(header));
+ if (res != STANDARD_HEADER_SIZE)
+ {
+ BX_PANIC(("redolog : could not read header"));
+ return -1;
+ }
+
+ print_header();
+
+ if (strcmp((char*)header.standard.magic, STANDARD_HEADER_MAGIC) != 0)
+ {
+ BX_PANIC(("redolog : Bad header magic"));
+ return -1;
+ }
+
+ if (strcmp((char*)header.standard.type, REDOLOG_TYPE) != 0)
+ {
+ BX_PANIC(("redolog : Bad header type"));
+ return -1;
+ }
+ if (strcmp((char*)header.standard.subtype, type) != 0)
+ {
+ BX_PANIC(("redolog : Bad header subtype"));
+ return -1;
+ }
+
+ if (dtoh32(header.standard.version) != STANDARD_HEADER_VERSION)
+ {
+ BX_PANIC(("redolog : Bad header version"));
+ return -1;
+ }
+
+ catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
+
+ // FIXME could mmap
+ ::lseek(fd,dtoh32(header.standard.header),SEEK_SET);
+ res = ::read(fd, catalog, dtoh32(header.specific.catalog) * sizeof(Bit32u)) ;
+
+ if (res != (ssize_t)(dtoh32(header.specific.catalog) * sizeof(Bit32u)))
+ {
+ BX_PANIC(("redolog : could not read catalog %d=%d",res, dtoh32(header.specific.catalog)));
+ return -1;
+ }
+
+ // check last used extent
+ extent_next = 0;
+ for (Bit32u i=0; i < dtoh32(header.specific.catalog); i++)
+ {
+ if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED)
+ {
+ if (dtoh32(catalog[i]) >= extent_next)
+ extent_next = dtoh32(catalog[i]) + 1;
+ }
+ }
+ BX_INFO(("redolog : next extent will be at index %d",extent_next));
+
+ // memory used for storing bitmaps
+ bitmap = (Bit8u *)malloc(dtoh32(header.specific.bitmap));
+
+ bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
+ extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
+
+ BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
+ BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
+
+ return 0;
+}
+
+void
+redolog_t::close ()
+{
+ if (fd >= 0)
+ ::close(fd);
+
+ if (catalog != NULL)
+ free(catalog);
+
+ if (bitmap != NULL)
+ free(bitmap);
+}
+
+off_t
+redolog_t::lseek (off_t offset, int whence)
+{
+ if ((offset % 512) != 0) {
+ BX_PANIC( ("redolog : lseek HD with offset not multiple of 512"));
+ return -1;
+ }
+ if (whence != SEEK_SET) {
+ BX_PANIC( ("redolog : lseek HD with whence not SEEK_SET"));
+ return -1;
+ }
+ if (offset > (off_t)dtoh64(header.specific.disk))
+ {
+ BX_PANIC(("redolog : lseek to byte %ld failed", (long)offset));
+ return -1;
+ }
+
+ extent_index = offset / dtoh32(header.specific.extent);
+ extent_offset = (offset % dtoh32(header.specific.extent)) / 512;
+
+ BX_DEBUG(("redolog : lseeking extent index %d, offset %d",extent_index, extent_offset));
+
+ return offset;
+}
+
+ssize_t
+redolog_t::read (void* buf, size_t count)
+{
+ off_t bloc_offset, bitmap_offset;
+
+ if (count != 512)
+ BX_PANIC( ("redolog : read HD with count not 512"));
+
+ BX_DEBUG(("redolog : reading index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
+
+ if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
+ {
+ // page not allocated
+ return 0;
+ }
+
+ bitmap_offset = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+ bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
+ bloc_offset = bitmap_offset + ((off_t)512 * (bitmap_blocs + extent_offset));
+
+ BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
+ BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
+
+
+ // FIXME if same extent_index as before we can skip bitmap read
+
+ ::lseek(fd, bitmap_offset, SEEK_SET);
+
+ if (::read(fd, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
+ {
+ BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
+ return 0;
+ }
+
+ if ( ((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00 )
+ {
+ BX_DEBUG(("read not in redolog"));
+
+ // bitmap says bloc not in reloglog
+ return 0;
+ }
+
+ ::lseek(fd, bloc_offset, SEEK_SET);
+
+ return (::read(fd, buf, count));
+}
+
+ssize_t
+redolog_t::write (const void* buf, size_t count)
+{
+ Bit32u i;
+ off_t bloc_offset, bitmap_offset, catalog_offset;
+ ssize_t written;
+ bx_bool update_catalog = 0;
+
+ if (count != 512)
+ BX_PANIC( ("redolog : write HD with count not 512"));
+
+ BX_DEBUG(("redolog : writing index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
+ if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
+ {
+ if(extent_next >= dtoh32(header.specific.catalog))
+ {
+ BX_PANIC(("redolog : can't allocate new extent... catalog is full"));
+ return 0;
+ }
+
+ BX_DEBUG(("redolog : allocating new extent at %d", extent_next));
+
+ // Extent not allocated, allocate new
+ catalog[extent_index] = htod32(extent_next);
+
+ extent_next += 1;
+
+ char *zerobuffer = (char*)malloc(512);
+ memset(zerobuffer, 0, 512);
+
+ // Write bitmap
+ bitmap_offset = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+ bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
+ ::lseek(fd, bitmap_offset, SEEK_SET);
+ for(i=0; i<bitmap_blocs; i++)
+ {
+ ::write(fd, zerobuffer, 512);
+ }
+ // Write extent
+ for(i=0; i<extent_blocs; i++)
+ {
+ ::write(fd, zerobuffer, 512);
+ }
+
+ free(zerobuffer);
+
+ update_catalog = 1;
+ }
+
+ bitmap_offset = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+ bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs);
+ bloc_offset = bitmap_offset + ((off_t)512 * (bitmap_blocs + extent_offset));
+
+ BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
+ BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
+
+ // Write bloc
+ ::lseek(fd, bloc_offset, SEEK_SET);
+ written = ::write(fd, buf, count);
+
+ // Write bitmap
+ // FIXME if same extent_index as before we can skip bitmap read
+ ::lseek(fd, bitmap_offset, SEEK_SET);
+ if (::read(fd, bitmap, dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
+ {
+ BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
+ return 0;
+ }
+
+ // If bloc does not belong to extent yet
+ if ( ((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00 )
+ {
+ bitmap[extent_offset/8] |= 1 << (extent_offset%8);
+ ::lseek(fd, bitmap_offset, SEEK_SET);
+ ::write(fd, bitmap, dtoh32(header.specific.bitmap));
+ }
+
+ // Write catalog
+ if (update_catalog)
+ {
+ // FIXME if mmap
+ catalog_offset = (off_t)STANDARD_HEADER_SIZE + (extent_index * sizeof(Bit32u));
+
+ BX_DEBUG(("redolog : writing catalog at offset %x", (Bit32u)catalog_offset));
+
+ ::lseek(fd, catalog_offset, SEEK_SET);
+ ::write(fd, &catalog[extent_index], sizeof(Bit32u));
+ }
+
+ return written;
+}
+
+
+/*** growing_image_t function definitions ***/
+
+growing_image_t::growing_image_t(Bit64u _size)
+{
+ redolog = new redolog_t();
+ size = _size;
+}
+
+int growing_image_t::open (const char* pathname)
+{
+ int filedes = redolog->open(pathname,REDOLOG_SUBTYPE_GROWING,size);
+ BX_INFO(("'growing' disk opened, growing file is '%s'", pathname));
+ return filedes;
+}
+
+void growing_image_t::close ()
+{
+ redolog->close();
+}
+
+off_t growing_image_t::lseek (off_t offset, int whence)
+{
+ return redolog->lseek(offset, whence);
+}
+
+ssize_t growing_image_t::read (void* buf, size_t count)
+{
+ memset(buf, 0, count);
+ redolog->read((char*) buf, count);
+ return count;
+}
+
+ssize_t growing_image_t::write (const void* buf, size_t count)
+{
+ return redolog->write((char*) buf, count);
+}
+
+
+/*** undoable_image_t function definitions ***/
+
+undoable_image_t::undoable_image_t(Bit64u _size, const char* _redolog_name)
+{
+ redolog = new redolog_t();
+ ro_disk = new default_image_t();
+ size = _size;
+ redolog_name = NULL;
+ if (_redolog_name != NULL) {
+ if (strcmp(_redolog_name,"") != 0) {
+ redolog_name = strdup(_redolog_name);
+ }
+ }
+}
+
+int undoable_image_t::open (const char* pathname)
+{
+ char *logname=NULL;
+
+ if (ro_disk->open(pathname, O_RDONLY)<0)
+ return -1;
+
+ // if redolog name was set
+ if ( redolog_name != NULL) {
+ if ( strcmp(redolog_name, "") != 0 ) {
+ logname = (char*)malloc(strlen(redolog_name) + 1);
+ strcpy (logname, redolog_name);
+ }
+ }
+
+ // Otherwise we make up the redolog filename from the pathname
+ if ( logname == NULL) {
+ logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
+ sprintf (logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
+ }
+
+ if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE,size) < 0)
+ {
+ if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, size) < 0)
+ {
+ BX_PANIC(("Can't open or create redolog '%s'",logname));
+ return -1;
+ }
+ }
+
+ BX_INFO(("'undoable' disk opened: ro-file is '%s', redolog is '%s'", pathname, logname));
+ free(logname);
+
+ return 0;
+}
+
+void undoable_image_t::close ()
+{
+ redolog->close();
+ ro_disk->close();
+
+ if (redolog_name!=NULL)
+ free(redolog_name);
+}
+
+off_t undoable_image_t::lseek (off_t offset, int whence)
+{
+ redolog->lseek(offset, whence);
+ return ro_disk->lseek(offset, whence);
+}
+
+ssize_t undoable_image_t::read (void* buf, size_t count)
+{
+ // This should be fixed if count != 512
+ if ((size_t)redolog->read((char*) buf, count) != count)
+ return ro_disk->read((char*) buf, count);
+ else
+ return count;
+}
+
+ssize_t undoable_image_t::write (const void* buf, size_t count)
+{
+ return redolog->write((char*) buf, count);
+}
+
+
+/*** volatile_image_t function definitions ***/
+
+volatile_image_t::volatile_image_t(Bit64u _size, const char* _redolog_name)
+{
+ redolog = new redolog_t();
+ ro_disk = new default_image_t();
+ size = _size;
+ redolog_temp = NULL;
+ redolog_name = NULL;
+ if (_redolog_name != NULL) {
+ if (strcmp(_redolog_name,"") != 0) {
+ redolog_name = strdup(_redolog_name);
+ }
+ }
+}
+
+int volatile_image_t::open (const char* pathname)
+{
+ int filedes;
+ const char *logname=NULL;
+
+ if (ro_disk->open(pathname, O_RDONLY)<0)
+ return -1;
+
+ // if redolog name was set
+ if ( redolog_name != NULL) {
+ if ( strcmp(redolog_name, "") != 0 ) {
+ logname = redolog_name;
+ }
+ }
+
+ // otherwise use pathname as template
+ if (logname == NULL) {
+ logname = pathname;
+ }
+
+ redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
+ sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
+
+ filedes = mkstemp (redolog_temp);
+
+ if (filedes < 0)
+ {
+ BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+ return -1;
+ }
+ if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, size) < 0)
+ {
+ BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+ return -1;
+ }
+
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+ // on unix it is legal to delete an open file
+ unlink(redolog_temp);
+#endif
+
+ BX_INFO(("'volatile' disk opened: ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
+
+ return 0;
+}
+
+void volatile_image_t::close ()
+{
+ redolog->close();
+ ro_disk->close();
+
+#if defined(WIN32) || BX_WITH_MACOS
+ // on non-unix we have to wait till the file is closed to delete it
+ unlink(redolog_temp);
+#endif
+ if (redolog_temp!=NULL)
+ free(redolog_temp);
+
+ if (redolog_name!=NULL)
+ free(redolog_name);
+}
+
+off_t volatile_image_t::lseek (off_t offset, int whence)
+{
+ redolog->lseek(offset, whence);
+ return ro_disk->lseek(offset, whence);
+}
+
+ssize_t volatile_image_t::read (void* buf, size_t count)
+{
+ // This should be fixed if count != 512
+ if ((size_t)redolog->read((char*) buf, count) != count)
+ return ro_disk->read((char*) buf, count);
+ else
+ return count;
+}
+
+ssize_t volatile_image_t::write (const void* buf, size_t count)
+{
+ return redolog->write((char*) buf, count);
+}
+
+#if BX_COMPRESSED_HD_SUPPORT
+
+/*** z_ro_image_t function definitions ***/
+
+z_ro_image_t::z_ro_image_t()
+{
+ offset = (off_t)0;
+}
+
+int z_ro_image_t::open (const char* pathname)
+{
+ fd = ::open(pathname, O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+
+ if(fd < 0)
+ {
+ BX_PANIC(("Could not open '%s' file", pathname));
+ return fd;
+ }
+
+ gzfile = gzdopen(fd, "rb");
+}
+
+void z_ro_image_t::close ()
+{
+ if (fd > -1) {
+ gzclose(gzfile);
+ // ::close(fd);
+ }
+}
+
+off_t z_ro_image_t::lseek (off_t _offset, int whence)
+{
+ // Only SEEK_SET supported
+ if (whence != SEEK_SET)
+ {
+ BX_PANIC(("lseek on compressed images : only SEEK_SET supported"));
+ }
+
+ // Seeking is expensive on compressed files, so we do it
+ // only when necessary, at the latest moment
+ offset = _offset;
+
+ return offset;
+}
+
+ssize_t z_ro_image_t::read (void* buf, size_t count)
+{
+ gzseek(gzfile, offset, SEEK_SET);
+ return gzread(gzfile, buf, count);
+}
+
+ssize_t z_ro_image_t::write (const void* buf, size_t count)
+{
+ BX_PANIC(("z_ro_image: write not supported"));
+ return 0;
+}
+
+
+/*** z_undoable_image_t function definitions ***/
+
+z_undoable_image_t::z_undoable_image_t(Bit64u _size, const char* _redolog_name)
+{
+ redolog = new redolog_t();
+ ro_disk = new z_ro_image_t();
+ size = _size;
+
+ redolog_name = NULL;
+ if (_redolog_name != NULL) {
+ if (strcmp(_redolog_name,"") != 0) {
+ redolog_name = strdup(_redolog_name);
+ }
+ }
+}
+
+int z_undoable_image_t::open (const char* pathname)
+{
+ char *logname=NULL;
+
+ if (ro_disk->open(pathname)<0)
+ return -1;
+
+ // If redolog name was set
+ if ( redolog_name != NULL) {
+ if ( strcmp(redolog_name, "") != 0) {
+ logname = (char*)malloc(strlen(redolog_name) + 1);
+ strcpy (logname, redolog_name);
+ }
+ }
+
+ // Otherwise we make up the redolog filename from the pathname
+ if ( logname == NULL) {
+ logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
+ sprintf (logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
+ }
+
+ if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE,size) < 0)
+ {
+ if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, size) < 0)
+ {
+ BX_PANIC(("Can't open or create redolog '%s'",logname));
+ return -1;
+ }
+ }
+
+ BX_INFO(("'z-undoable' disk opened, z-ro-file is '%s', redolog is '%s'", pathname, logname));
+ free(logname);
+
+ return 0;
+}
+
+void z_undoable_image_t::close ()
+{
+ redolog->close();
+ ro_disk->close();
+
+ if (redolog_name!=NULL)
+ free(redolog_name);
+}
+
+off_t z_undoable_image_t::lseek (off_t offset, int whence)
+{
+ redolog->lseek(offset, whence);
+ return ro_disk->lseek(offset, whence);
+}
+
+ssize_t z_undoable_image_t::read (void* buf, size_t count)
+{
+ // This should be fixed if count != 512
+ if (redolog->read((char*) buf, count) != count)
+ return ro_disk->read((char*) buf, count);
+ else
+ return count;
+}
+
+ssize_t z_undoable_image_t::write (const void* buf, size_t count)
+{
+ return redolog->write((char*) buf, count);
+}
+
+
+/*** z_volatile_image_t function definitions ***/
+
+z_volatile_image_t::z_volatile_image_t(Bit64u _size, const char* _redolog_name)
+{
+ redolog = new redolog_t();
+ ro_disk = new z_ro_image_t();
+ size = _size;
+
+ redolog_temp = NULL;
+ redolog_name = NULL;
+ if (_redolog_name != NULL) {
+ if (strcmp(_redolog_name,"") != 0) {
+ redolog_name = strdup(_redolog_name);
+ }
+ }
+}
+
+int z_volatile_image_t::open (const char* pathname)
+{
+ int filedes;
+ const char *logname=NULL;
+
+ if (ro_disk->open(pathname)<0)
+ return -1;
+
+ // if redolog name was set
+ if ( redolog_name != NULL) {
+ if ( strcmp(redolog_name, "") !=0 ) {
+ logname = redolog_name;
+ }
+ }
+
+ // otherwise use pathname as template
+ if (logname == NULL) {
+ logname = pathname;
+ }
+
+ redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
+ sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
+
+ filedes = mkstemp (redolog_temp);
+
+ if (filedes < 0)
+ {
+ BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+ return -1;
+ }
+ if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, size) < 0)
+ {
+ BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+ return -1;
+ }
+
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+ // on unix it is legal to delete an open file
+ unlink(redolog_temp);
+#endif
+
+ BX_INFO(("'z-volatile' disk opened: z-ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
+
+ return 0;
+}
+
+void z_volatile_image_t::close ()
+{
+ redolog->close();
+ ro_disk->close();
+
+#if defined(WIN32) || BX_WITH_MACOS
+ // on non-unix we have to wait till the file is closed to delete it
+ unlink(redolog_temp);
+#endif
+
+ if (redolog_temp!=NULL)
+ free(redolog_temp);
+
+ if (redolog_name!=NULL)
+ free(redolog_name);
+}
+
+off_t z_volatile_image_t::lseek (off_t offset, int whence)
+{
+ redolog->lseek(offset, whence);
+ return ro_disk->lseek(offset, whence);
+}
+
+ssize_t z_volatile_image_t::read (void* buf, size_t count)
+{
+ // This should be fixed if count != 512
+ if (redolog->read((char*) buf, count) != count)
+ return ro_disk->read((char*) buf, count);
+ else
+ return count;
+}
+
+ssize_t z_volatile_image_t::write (const void* buf, size_t count)
+{
+ return redolog->write((char*) buf, count);
+}
+
+
+#endif
diff --git a/tools/ioemu/iodev/harddrv.h b/tools/ioemu/iodev/harddrv.h
new file mode 100644
index 0000000000..9320e614d5
--- /dev/null
+++ b/tools/ioemu/iodev/harddrv.h
@@ -0,0 +1,765 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: harddrv.h,v 1.22.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// SPARSE IMAGES HEADER
+#define SPARSE_HEADER_MAGIC (0x02468ace)
+#define SPARSE_HEADER_VERSION 1
+#define SPARSE_HEADER_SIZE (256) // Plenty of room for later
+#define SPARSE_PAGE_NOT_ALLOCATED (0xffffffff)
+
+ typedef struct
+ {
+ uint32 magic;
+ uint32 version;
+ uint32 pagesize;
+ uint32 numpages;
+
+ uint32 padding[60];
+ } sparse_header_t;
+
+#define STANDARD_HEADER_MAGIC "Bochs Virtual HD Image"
+#define STANDARD_HEADER_VERSION (0x00010000)
+#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
+ Bit64u disk; // disk size in bytes
+ } redolog_specific_header_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;
+
+// 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 INCLUDE_ONLY_HD_HEADERS
+
+typedef enum _sense {
+ SENSE_NONE = 0, SENSE_NOT_READY = 2, SENSE_ILLEGAL_REQUEST = 5,
+ SENSE_UNIT_ATTENTION = 6
+} sense_t;
+
+typedef enum _asc {
+ ASC_INV_FIELD_IN_CMD_PACKET = 0x24,
+ ASC_MEDIUM_NOT_PRESENT = 0x3a,
+ ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
+ ASC_LOGICAL_BLOCK_OOR = 0x21
+} asc_t;
+
+class LOWLEVEL_CDROM;
+
+class device_image_t
+{
+ public:
+ // 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 off_t lseek (off_t 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;
+
+ unsigned cylinders;
+ unsigned heads;
+ unsigned sectors;
+};
+
+// 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.
+ off_t lseek (off_t 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.
+ off_t lseek (off_t 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];
+ off_t start_offset_table[BX_CONCAT_MAX_IMAGES];
+ off_t 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
+ off_t 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.
+ off_t lseek (off_t 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
+ uint32 * 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;
+
+ uint32 pagesize;
+ int pagesize_shift;
+ uint32 pagesize_mask;
+
+ off_t data_start;
+ off_t underlying_filesize;
+
+ char * pathname;
+
+ off_t position;
+
+ uint32 position_virtual_page;
+ uint32 position_physical_page;
+ uint32 position_page_offset;
+
+ off_t underlying_current_filepos;
+
+ off_t total_size;
+
+ void panic(const char * message);
+ off_t
+#ifndef PARANOID
+ sparse_image_t::
+#endif
+ get_physical_offset();
+ void
+#ifndef PARANOID
+ sparse_image_t::
+#endif
+ set_virtual_page(uint32 new_virtual_page);
+ void read_header();
+ ssize_t read_page_fragment(uint32 read_virtual_page, uint32 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.
+ off_t lseek (off_t 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, Bit64u size);
+ void close ();
+
+ off_t lseek (off_t 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_blocs;
+ Bit32u extent_blocs;
+};
+
+// GROWING MODE
+class growing_image_t : public device_image_t
+{
+ public:
+ // Contructor
+ growing_image_t(Bit64u size);
+
+ // 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.
+ off_t lseek (off_t 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;
+ Bit64u size;
+};
+
+// UNDOABLE MODE
+class undoable_image_t : public device_image_t
+{
+ public:
+ // Contructor
+ undoable_image_t(Bit64u size, const char* redolog_name);
+
+ // 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.
+ off_t lseek (off_t 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
+ Bit64u size;
+ char *redolog_name; // Redolog name
+};
+
+
+// VOLATILE MODE
+class volatile_image_t : public device_image_t
+{
+ public:
+ // Contructor
+ volatile_image_t(Bit64u size, const char* redolog_name);
+
+ // 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.
+ off_t lseek (off_t 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
+ Bit64u size;
+ 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.
+ off_t lseek (off_t 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:
+ off_t 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);
+
+ // 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.
+ off_t lseek (off_t 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);
+
+ // 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.
+ off_t lseek (off_t 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
+
+
+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[2048];
+ Bit32u buffer_index;
+ Bit32u drq_index;
+ Bit8u current_command;
+ Bit8u sectors_per_block;
+ Bit8u lba_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;
+ } 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 ();
+};
+
+uint16 read_16bit(const uint8* buf) BX_CPP_AttrRegparmN(1);
+uint32 read_32bit(const uint8* buf) BX_CPP_AttrRegparmN(1);
+
+
+#ifdef LOWLEVEL_CDROM
+# include "cdrom.h"
+#endif
+
+
+struct cdrom_t
+{
+ bx_bool ready;
+ bx_bool locked;
+#ifdef LOWLEVEL_CDROM
+ LOWLEVEL_CDROM* cd;
+#endif
+ uint32 capacity;
+ int next_lba;
+ int remaining_blocks;
+ struct currentStruct {
+ error_recovery_t error_recovery;
+ } current;
+};
+
+struct atapi_t
+{
+ uint8 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(void);
+ virtual ~bx_hard_drive_c(void);
+ virtual void close_harddrive(void);
+ 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);
+
+ 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);
+
+private:
+
+ BX_HD_SMF bx_bool calculate_logical_address(Bit8u channel, off_t *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, bool lazy = false) BX_CPP_AttrRegparmN(3);
+ 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_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);
+
+ // 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* hard_drive;
+ 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];
+
+ controller_t controller;
+ cdrom_t cdrom;
+ sense_info_t sense;
+ atapi_t atapi;
+
+ Bit8u model_no[41];
+ } drives[2];
+ unsigned drive_select;
+
+ Bit16u ioaddr1;
+ Bit16u ioaddr2;
+ Bit8u irq;
+
+ } channels[BX_MAX_ATA_CHANNEL];
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20630c is only available for 1st ata channel
+ struct pdc20630c_t {
+ bx_bool prog_mode;
+ Bit8u prog_count;
+ Bit32u p1f3_value;
+ Bit32u p1f4_value;
+ } pdc20230c;
+#endif
+
+ };
+#endif // INCLUDE_ONLY_SPARSE_HEADER
+
diff --git a/tools/ioemu/iodev/ioapic.cc b/tools/ioemu/iodev/ioapic.cc
new file mode 100644
index 0000000000..8aaf67f848
--- /dev/null
+++ b/tools/ioemu/iodev/ioapic.cc
@@ -0,0 +1,175 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ioapic.cc,v 1.11 2002/11/19 05:47:45 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include <stdio.h>
+#include "bochs.h"
+#if BX_SUPPORT_APIC
+
+class bx_ioapic_c bx_ioapic;
+#define LOG_THIS bx_ioapic.
+
+void
+bx_io_redirect_entry_t::parse_value ()
+{
+ dest = (value >> 56) & 0xff;
+ masked = (value >> 16) & 1;
+ trig_mode = (value >> 15) & 1;
+ remote_irr = (value >> 14) & 1;
+ polarity = (value >> 13) & 1;
+ //delivery_status = (value >> 12) & 1;
+ delivery_status = 0; // always say the message has gone through
+ dest_mode = (value >> 11) & 1;
+ delivery_mode = (value >> 8) & 7;
+ vector = (value >> 0) & 0xff;
+}
+
+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", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
+}
+
+bx_ioapic_c::bx_ioapic_c ()
+ : bx_generic_apic_c ()
+{
+ put("IOAP");
+ settype(IOAPICLOG);
+}
+
+bx_ioapic_c::~bx_ioapic_c () {
+}
+
+void
+bx_ioapic_c::init ()
+{
+ bx_generic_apic_c::init ();
+ BX_DEBUG(("initializing I/O APIC"));
+ base_addr = 0xfec00000;
+ ioregsel = 0;
+ // all interrupts masked
+ for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
+ ioredtbl[i].set_even_word (0x00010000);
+ ioredtbl[i].set_odd_word (0x00000000);
+ }
+ irr = 0;
+}
+
+void
+bx_ioapic_c::reset (unsigned type)
+{
+}
+
+void
+bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
+{
+ BX_DEBUG( ("I/O APIC read_aligned addr=%08x, len=%d", address, len));
+ BX_ASSERT (len == 4);
+ address &= 0xff;
+ if (address == 0x00) {
+ // select register
+ *data = ioregsel;
+ return;
+ } else if (address != 0x10) {
+ BX_PANIC(("IOAPIC: read from unsupported address"));
+ }
+ // only reached when reading data register
+ switch (ioregsel) {
+ case 0x00: // APIC ID
+ *data = ((id & 0xf) << 24);
+ return;
+ case 0x01: // version
+ *data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16)
+ | (BX_IOAPIC_VERSION_ID & 0x0f);
+ return;
+ case 0x02:
+ BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
+ *data = 0;
+ return;
+ 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_odd_word() : entry->get_even_word ();
+ return;
+ }
+ BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
+ }
+}
+
+void
+bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
+{
+ BX_DEBUG(("IOAPIC: write addr=%08x, data=%08x, len=%d", address, *value, len));
+ 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) & 0xf;
+ 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_odd_word (*value);
+ else
+ entry->set_even_word (*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::trigger_irq (unsigned vector, unsigned from)
+{
+ BX_DEBUG(("IOAPIC: received interrupt %d", vector));
+ if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) {
+ Bit32u bit = 1<<vector;
+ if ((irr & bit) == 0) {
+ irr |= bit;
+ service_ioapic ();
+ }
+ } else BX_PANIC(("IOAPIC: vector %d out of range", vector));
+}
+
+void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from)
+{
+ BX_DEBUG(("IOAPIC: interrupt %d went away", num));
+}
+
+void bx_ioapic_c::service_ioapic ()
+{
+ // 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++) {
+ if (irr & (1<<bit)) {
+ bx_io_redirect_entry_t *entry = ioredtbl + bit;
+ if (!entry->masked) {
+ // clear irr bit and deliver
+ bx_bool done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
+ if (done) irr &= ~(1<<bit);
+ }
+ }
+ }
+}
+
+#endif /* if BX_SUPPORT_APIC */
diff --git a/tools/ioemu/iodev/ioapic.h b/tools/ioemu/iodev/ioapic.h
new file mode 100644
index 0000000000..be008f04c8
--- /dev/null
+++ b/tools/ioemu/iodev/ioapic.h
@@ -0,0 +1,54 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ioapic.h,v 1.5 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+extern class bx_ioapic_c bx_ioapic;
+
+#define BX_IOAPIC_VERSION_ID 0x00170011 // same version as 82093 IOAPIC
+#define BX_IOAPIC_NUM_PINS 0x18
+
+class bx_io_redirect_entry_t {
+ Bit64u value;
+public:
+ Bit32u get_even_word () { return value & 0xffffffff; }
+ Bit32u get_odd_word () { return (value>>32) & 0xffffffff; }
+ void set_even_word (Bit32u even) {
+ // keep high 32 bits of value, replace low 32
+ value = ((value >> 32) << 32) | (even & 0xffffffff);
+ parse_value ();
+ }
+ void set_odd_word (Bit32u odd) {
+ // keep low 32 bits of value, replace high 32
+ value = (((Bit64u)odd & 0xffffffff) << 32) | (value & 0xffffffff);
+ parse_value ();
+ }
+ void parse_value ();
+ // parse_value sets the value and all the fields below. Do not change
+ // these fields except by calling parse_value.
+ Bit8u dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector;
+ void sprintf_self (char *buf);
+};
+
+class bx_ioapic_c : public bx_generic_apic_c {
+ Bit32u ioregsel; // selects between various registers
+ // 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;
+public:
+ bx_io_redirect_entry_t ioredtbl[BX_IOAPIC_NUM_PINS]; // table of redirections
+ bx_ioapic_c ();
+ ~bx_ioapic_c ();
+ virtual void init ();
+ virtual void reset (unsigned type);
+ virtual void read_aligned(Bit32u address, Bit32u *data, unsigned len);
+ virtual void write(Bit32u address, Bit32u *value, unsigned len);
+ void trigger_irq (unsigned num, unsigned from);
+ void untrigger_irq (unsigned num, unsigned from);
+ void service_ioapic ();
+ virtual bx_bool match_logical_addr (Bit8u address) { return false; }
+ virtual bx_bool is_local_apic () { return false; }
+ virtual bx_apic_type_t get_type () { return APIC_TYPE_IOAPIC; }
+};
diff --git a/tools/ioemu/iodev/iodebug.cc b/tools/ioemu/iodev/iodebug.cc
new file mode 100644
index 0000000000..ca2314ede6
--- /dev/null
+++ b/tools/ioemu/iodev/iodebug.cc
@@ -0,0 +1,354 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodebug.cc,v 1.15 2002/11/19 05:47:45 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include "bochs.h"
+#if BX_IODEBUG_SUPPORT
+
+
+
+bx_iodebug_c bx_iodebug;
+bx_iodebug_c *bx_iodebug_ptr;
+
+ struct bx_iodebug_s_type {
+ bx_bool enabled;
+ unsigned int register_select;
+ Bit32u registers[2];
+ Bit32u monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
+ Bit32u monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
+ } bx_iodebug_s;
+
+
+
+
+// Constructor
+bx_iodebug_c::bx_iodebug_c( void )
+{
+ put("IODEBUG");
+ settype(IODEBUGLOG);
+
+}
+
+
+
+
+
+// Destructor
+bx_iodebug_c::~bx_iodebug_c( void )
+{
+}
+
+
+
+
+
+void bx_iodebug_c::init(void)
+{
+ int i;
+
+ DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 7);
+ DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 7);
+ DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 7);
+// fprintf( stderr, "IODEBUG initialized\n");
+
+ bx_iodebug_s.enabled = 0;
+ bx_iodebug_s.register_select = 0;
+ for(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;
+ }
+}
+
+void bx_iodebug_c::reset(unsigned type)
+{
+}
+
+
+Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
+{
+ 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 *class_ptr = (bx_iodebug_c *) this_ptr;
+ class_ptr->write( addr, dvalue, io_len );
+}
+
+
+
+
+
+
+void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
+{
+
+
+// fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);
+
+ if( addr == 0x8A01 && io_len == 2 )
+ {
+ bx_iodebug_s.registers[bx_iodebug_s.register_select] =
+ (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
+ (dvalue & 0x0000FFFF );
+ }
+
+ if( (addr != 0x8A00) || (io_len != 2) ) 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, Bit32u addr, unsigned len, void *data)
+{
+ Bit32u data32;
+ Bit16u data16;
+ Bit8u data8;
+
+ unsigned int area;
+ if( !bx_iodebug_s.enabled ) return;
+
+ area = bx_iodebug_c::range_test( addr, len );
+ // Device is enabled, testing address ranges
+ if( area )
+ {
+ area--;
+#if BX_DEBUGGER
+ fprintf( stdout, "%s @ eip: %08X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
+ bx_guard.interrupt_requested=1;
+#else
+ fprintf( stderr,
+ "IODEBUG write to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
+ area,
+ cpu->get_EIP(),
+ bx_iodebug_s.monitored_mem_areas_start[area],
+ bx_iodebug_s.monitored_mem_areas_end[area],
+ (unsigned int)addr);
+
+ data32 = * (Bit32u *)data;
+ data16 = (Bit16u)data32;
+ data8 = (Bit8u)data32;
+
+ switch(len)
+ {
+ case(1):
+ fprintf(stderr,"%02X\n", (unsigned int)data8);
+ break;
+
+ case(2):
+ fprintf(stderr,"%04X\n", (unsigned int)data16);
+ break;
+
+ case(4):
+ fprintf(stderr,"%08X\n", (unsigned int)data32);
+ break;
+
+ default:
+ fprintf(stderr, "unsupported write size\n");
+ }
+#endif
+ }
+}
+
+
+
+
+
+
+
+
+void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+ Bit32u data32;
+ Bit16u data16;
+ Bit8u data8;
+
+ unsigned int area;
+ if( !bx_iodebug_s.enabled ) return;
+
+ area = bx_iodebug_c::range_test( addr, len );
+ // Device is enabled, testing address ranges
+ if( area )
+ {
+ area--;
+#if BX_DEBUGGER
+ fprintf( stdout, "%s @ eip: %8X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
+ bx_guard.interrupt_requested=1;
+#else
+ fprintf( stderr,
+ "IODEBUG read to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
+ area,
+ cpu->get_EIP(),
+ bx_iodebug_s.monitored_mem_areas_start[area],
+ bx_iodebug_s.monitored_mem_areas_end[area],
+ (unsigned int)addr);
+ data32 = * (Bit32u *)data;
+ data16 = (Bit16u)data32;
+ data8 = (Bit8u)data32;
+
+ switch(len)
+ {
+ case(1):
+ fprintf(stderr,"%02X\n", (unsigned int)data8);
+ break;
+
+ case(2):
+ fprintf(stderr,"%04X\n", (unsigned int)data16);
+ break;
+
+ case(4):
+ fprintf(stderr,"%08X\n", (unsigned int)data32);
+ break;
+
+ default:
+ fprintf(stderr, "unsupported write size\n");
+ }
+#endif
+ }
+}
+
+
+
+
+
+
+
+unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
+{
+ unsigned int i;
+
+ for(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( Bit32u addr_start, Bit32u addr_end )
+{
+ unsigned int i;
+ for(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_IODEBUG_SUPPORT */
diff --git a/tools/ioemu/iodev/iodebug.h b/tools/ioemu/iodev/iodebug.h
new file mode 100644
index 0000000000..a31f7cfa92
--- /dev/null
+++ b/tools/ioemu/iodev/iodebug.h
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodebug.h,v 1.7 2002/10/26 03:53:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#ifndef _BX_IODEBUG_H
+#define _BX_IODEBUG_H
+
+#include "config.h"
+
+#define BX_IODEBUG_THIS this->
+
+#define BX_IODEBUG_MAX_AREAS 30
+
+class bx_iodebug_c : public bx_devmodel_c
+{
+public:
+ bx_iodebug_c( void );
+ ~bx_iodebug_c( void );
+ virtual void init(void);
+ virtual void reset (unsigned type);
+ static void mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+ static void mem_read( BX_CPU_C *cpu, Bit32u 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 int io_len);
+ void write(Bit32u addr, Bit32u dvalue, unsigned int io_len);
+ static unsigned int range_test(Bit32u addr, unsigned int len);
+ static void add_range( Bit32u addr_start, Bit32u addr_end);
+
+};
+
+extern bx_iodebug_c bx_iodebug;
+#endif
diff --git a/tools/ioemu/iodev/iodev.h b/tools/ioemu/iodev/iodev.h
new file mode 100644
index 0000000000..3057f6c334
--- /dev/null
+++ b/tools/ioemu/iodev/iodev.h
@@ -0,0 +1,422 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodev.h,v 1.37 2003/08/04 16:03:09 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+/* maximum number of emulated devices allowed. floppy, vga, etc...
+ you can increase this to anything below 256 since an 8-bit handle
+ is used for each device */
+#define BX_MAX_IO_DEVICES 30
+
+/* the last device in the array is the "default" I/O device */
+#define BX_DEFAULT_IO_DEVICE (BX_MAX_IO_DEVICES-1)
+
+/* 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
+#define BX_NO_IRQ -1
+
+
+class bx_pit_c;
+class bx_keyb_c;
+class bx_ioapic_c;
+class bx_g2h_c;
+#if BX_IODEBUG_SUPPORT
+class bx_iodebug_c;
+#endif
+
+
+
+typedef Bit32u (*bx_read_handler_t)(void *, Bit32u, unsigned);
+typedef void (*bx_write_handler_t)(void *, Bit32u, Bit32u, unsigned);
+
+
+#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_mem(BX_MEM_C *) {}
+ virtual void init(void) {}
+ virtual void reset(unsigned type) {}
+ virtual void device_load_state () {}
+ virtual void device_save_state () {}
+};
+
+//////////////////////////////////////////////////////////////////////
+// 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 mouse_motion(int delta_x, int delta_y, unsigned button_state) {
+ STUBFUNC(keyboard, mouse_motion);
+ }
+ virtual void gen_scancode(Bit32u key) {
+ STUBFUNC(keyboard, gen_scancode);
+ }
+ virtual void paste_bytes(Bit8u *data, Bit32s length) {
+ STUBFUNC(keyboard, paste_bytes);
+ }
+ virtual void paste_delay_changed () {
+ STUBFUNC(keyboard, paste_delay_changed);
+ }
+ virtual void mouse_enabled_changed(bool enabled) {
+ STUBFUNC(keyboard, mouse_enabled_changed);
+ }
+};
+
+class BOCHSAPI bx_hard_drive_stub_c : public bx_devmodel_c {
+ public:
+ virtual void close_harddrive(void) {
+ STUBFUNC(HD, close_harddrive);
+ }
+ 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);
+ }
+};
+
+class BOCHSAPI bx_floppy_stub_c : public bx_devmodel_c {
+ public:
+ virtual unsigned get_media_status(unsigned drive) {
+ STUBFUNC(floppy, get_media_status); return 0;
+ }
+ 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() {
+ // STUBFUNC(cmos, 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 Bit8u IAC(void) {
+ STUBFUNC(pic, IAC); return 0;
+ }
+ virtual void show_pic_state(void) {
+ STUBFUNC(pic, show_pic_state);
+ }
+};
+
+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(Bit32u addr) {
+ STUBFUNC(vga, mem_read); return 0;
+ }
+ virtual void mem_write(Bit32u 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 void set_update_interval (unsigned interval) {
+ STUBFUNC(vga, set_update_interval);
+ }
+ virtual Bit8u get_actl_palette_idx(Bit8u index) {
+ return 0;
+ }
+};
+
+class BOCHSAPI bx_pci_stub_c : public bx_devmodel_c {
+ public:
+ virtual bx_bool register_pci_handlers(void *this_ptr,
+ Bit32u (*bx_pci_read_handler)(void *, Bit8u, unsigned),
+ void(*bx_pci_write_handler)(void *, Bit8u, Bit32u, unsigned),
+ Bit8u devfunc, const char *name) {
+ STUBFUNC(pci, register_pci_handlers); return 0;
+ }
+ virtual Bit8u rd_memType (Bit32u addr) {
+ return 0;
+ }
+ virtual Bit8u wr_memType (Bit32u addr) {
+ return 0;
+ }
+ virtual void print_i440fx_state(void) {}
+};
+
+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_devices_c : public logfunctions {
+public:
+ bx_devices_c(void);
+ ~bx_devices_c(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);
+ 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 register_io_write_handler(void *this_ptr, bx_write_handler_t f, Bit32u addr, const char *name, 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);
+ void iodev_init(void);
+ Bit32u inp(Bit16u addr, unsigned io_len) BX_CPP_AttrRegparmN(2);
+ void outp(Bit16u addr, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
+
+ static void timer_handler(void *);
+ void timer(void);
+
+ bx_devmodel_c *pluginBiosDevice;
+ bx_ioapic_c *ioapic;
+ bx_pci_stub_c *pluginPciBridge;
+ bx_devmodel_c *pluginPci2IsaBridge;
+ bx_devmodel_c *pluginPciVgaAdapter;
+ bx_devmodel_c *pluginPciUSBAdapter;
+ bx_pit_c *pit;
+ bx_keyb_stub_c *pluginKeyboard;
+ bx_dma_stub_c *pluginDmaDevice;
+ bx_floppy_stub_c *pluginFloppyDevice;
+ bx_cmos_stub_c *pluginCmosDevice;
+ bx_devmodel_c *pluginSerialDevice;
+ bx_devmodel_c *pluginParallelDevice;
+ bx_devmodel_c *pluginUnmapped;
+ bx_vga_stub_c *pluginVgaDevice;
+ bx_pic_stub_c *pluginPicDevice;
+ bx_hard_drive_stub_c *pluginHardDrive;
+ bx_devmodel_c *pluginSB16Device;
+ bx_ne2k_stub_c *pluginNE2kDevice;
+ bx_g2h_c *g2h;
+ bx_devmodel_c *pluginExtFpuIrq;
+ bx_devmodel_c *pluginGameport;
+#if BX_IODEBUG_SUPPORT
+ bx_iodebug_c *iodebug;
+#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_dma_stub_c stubDma;
+ bx_pic_stub_c stubPic;
+ bx_floppy_stub_c stubFloppy;
+ bx_vga_stub_c stubVga;
+ bx_pci_stub_c stubPci;
+ bx_ne2k_stub_c stubNE2k;
+
+ // 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.
+ Bit32u bulkIOHostAddr;
+ unsigned bulkIOQuantumsRequested;
+ unsigned bulkIOQuantumsTransferred;
+
+private:
+
+ Bit8u read_handler_id[0x10000]; // 64K
+ struct {
+ bx_read_handler_t funct;
+ void *this_ptr;
+ const char *handler_name; // name of device
+ Bit8u mask; // io_len mask
+ } io_read_handler[BX_MAX_IO_DEVICES];
+ unsigned num_read_handles;
+
+ Bit8u write_handler_id[0x10000]; // 64K
+ struct {
+ bx_write_handler_t funct;
+ void *this_ptr;
+ const char *handler_name; // name of device
+ Bit8u mask; // io_len mask
+ } io_write_handler[BX_MAX_IO_DEVICES];
+ unsigned num_write_handles;
+
+ // more for informative purposes, the names of the devices which
+ // are use each of the IRQ 0..15 lines are stored here
+ const 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);
+
+ int timer_handle;
+ bx_bool is_serial_enabled ();
+ bx_bool is_usb_enabled ();
+ bx_bool is_parallel_enabled ();
+ };
+
+
+
+#if BX_PCI_SUPPORT
+#include "iodev/pci.h"
+#include "iodev/pci2isa.h"
+#if BX_PCI_VGA_SUPPORT
+#include "iodev/pcivga.h"
+#endif
+#if BX_PCI_USB_SUPPORT
+#include "iodev/pciusb.h"
+#endif
+#endif
+#include "iodev/vga.h"
+#if BX_SUPPORT_APIC
+# include "iodev/ioapic.h"
+#endif
+#include "iodev/biosdev.h"
+#include "iodev/cmos.h"
+#include "iodev/dma.h"
+#include "iodev/floppy.h"
+#include "iodev/harddrv.h"
+#if BX_IODEBUG_SUPPORT
+# include "iodev/iodebug.h"
+#endif
+#include "iodev/keyboard.h"
+#include "iodev/parallel.h"
+#include "iodev/pic.h"
+#include "iodev/pit.h"
+#include "iodev/pit_wrap.h"
+#include "iodev/virt_timer.h"
+#include "iodev/serial.h"
+#if BX_SUPPORT_SB16
+# include "iodev/sb16.h"
+#endif
+#include "iodev/unmapped.h"
+#include "iodev/eth.h"
+#include "iodev/ne2k.h"
+#include "iodev/guest2host.h"
+#include "iodev/slowdown_timer.h"
+#include "iodev/extfpuirq.h"
+#include "iodev/gameport.h"
diff --git a/tools/ioemu/iodev/keyboard.cc b/tools/ioemu/iodev/keyboard.cc
new file mode 100644
index 0000000000..693f4a4c60
--- /dev/null
+++ b/tools/ioemu/iodev/keyboard.cc
@@ -0,0 +1,1611 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keyboard.cc,v 1.82 2003/11/11 18:18:36 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Now features proper implementation of keyboard opcodes 0xF4 to 0xF6
+// Silently ignores PS/2 keyboard extensions (0xF7 to 0xFD)
+// Explicit panic on resend (0xFE)
+//
+// Emmanuel Marty <core@ggi-project.org>
+
+// NB: now the PS/2 mouse support is in, outb changes meaning
+// in conjunction with auxb
+// auxb == 0 && outb == 0 => both buffers empty (nothing to read)
+// auxb == 0 && outb == 1 => keyboard controller output buffer full
+// auxb == 1 && outb == 0 => not used
+// auxb == 1 && outb == 1 => mouse output buffer full.
+// (das)
+
+// Notes from Christophe Bothamy <cbbochs@free.fr>
+//
+// This file includes code from Ludovic Lange (http://ludovic.lange.free.fr)
+// Implementation of 3 scancodes sets mf1,mf2,mf3 with or without translation.
+// Default is mf2 with translation
+// Ability to switch between scancodes sets
+// Ability to turn translation on or off
+
+// 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 <math.h>
+#include "scancodes.h"
+
+#define LOG_THIS theKeyboard->
+#define VERBOSE_KBD_DEBUG 0
+
+
+bx_keyb_c *theKeyboard = NULL;
+
+ int
+libkeyboard_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ // Create one instance of the keyboard device object.
+ theKeyboard = new bx_keyb_c ();
+ // Before this plugin was loaded, pluginKeyboard pointed to a stub.
+ // Now make it point to the real thing.
+ bx_devices.pluginKeyboard = theKeyboard;
+ // Register this device.
+ BX_REGISTER_DEVICE_DEVMODEL (plugin, type, theKeyboard, BX_PLUGIN_KEYBOARD);
+ return(0); // Success
+}
+
+ void
+libkeyboard_LTX_plugin_fini(void)
+{
+ BX_INFO (("keyboard plugin_fini"));
+}
+
+bx_keyb_c::bx_keyb_c(void)
+{
+ // constructor
+ put("KBD");
+ settype(KBDLOG);
+}
+
+bx_keyb_c::~bx_keyb_c(void)
+{
+ // destructor
+ BX_DEBUG(("Exit."));
+}
+
+
+// flush internal buffer and reset keyboard settings to power-up condition
+ void
+bx_keyb_c::resetinternals(bx_bool powerup)
+{
+ Bit32u i;
+
+ BX_KEY_THIS s.kbd_internal_buffer.num_elements = 0;
+ for (i=0; i<BX_KBD_ELEMENTS; i++)
+ BX_KEY_THIS s.kbd_internal_buffer.buffer[i] = 0;
+ BX_KEY_THIS s.kbd_internal_buffer.head = 0;
+
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
+
+ // Default scancode set is mf2 with translation
+ BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
+ BX_KEY_THIS s.kbd_controller.current_scancodes_set = 1;
+ BX_KEY_THIS s.kbd_controller.scancodes_translate = 1;
+
+ if (powerup) {
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
+ BX_KEY_THIS s.kbd_internal_buffer.delay = 1; // 500 mS
+ BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = 0x0b; // 10.9 chars/sec
+ }
+}
+
+
+
+ void
+bx_keyb_c::init(void)
+{
+ BX_DEBUG(("Init $Id: keyboard.cc,v 1.82 2003/11/11 18:18:36 vruppert Exp $"));
+ Bit32u i;
+
+ DEV_register_irq(1, "8042 Keyboard controller");
+ DEV_register_irq(12, "8042 Keyboard controller (PS/2 mouse)");
+
+ DEV_register_ioread_handler(this, read_handler,
+ 0x0060, "8042 Keyboard controller", 1);
+ DEV_register_ioread_handler(this, read_handler,
+ 0x0064, "8042 Keyboard controller", 1);
+ DEV_register_iowrite_handler(this, write_handler,
+ 0x0060, "8042 Keyboard controller", 1);
+ DEV_register_iowrite_handler(this, write_handler,
+ 0x0064, "8042 Keyboard controller", 1);
+ BX_KEY_THIS timer_handle = bx_pc_system.register_timer( this, timer_handler,
+ bx_options.Okeyboard_serial_delay->get(), 1, 1,
+ "8042 Keyboard controller");
+
+ resetinternals(1);
+
+ BX_KEY_THIS s.kbd_internal_buffer.led_status = 0;
+ BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+
+ BX_KEY_THIS s.mouse_internal_buffer.num_elements = 0;
+ for (i=0; i<BX_MOUSE_BUFF_SIZE; i++)
+ BX_KEY_THIS s.mouse_internal_buffer.buffer[i] = 0;
+ BX_KEY_THIS s.mouse_internal_buffer.head = 0;
+
+ // BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.pare = 0;
+ BX_KEY_THIS s.kbd_controller.tim = 0;
+ BX_KEY_THIS s.kbd_controller.auxb = 0;
+ BX_KEY_THIS s.kbd_controller.keyl = 1;
+ BX_KEY_THIS s.kbd_controller.c_d = 1;
+ BX_KEY_THIS s.kbd_controller.sysf = 0;
+ BX_KEY_THIS s.kbd_controller.inpb = 0;
+ BX_KEY_THIS s.kbd_controller.outb = 0;
+
+ BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
+ BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
+ BX_KEY_THIS s.kbd_controller.allow_irq1 = 1;
+ BX_KEY_THIS s.kbd_controller.allow_irq12 = 1;
+ BX_KEY_THIS s.kbd_controller.kbd_output_buffer = 0;
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
+ BX_KEY_THIS s.kbd_controller.last_comm = 0;
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+ BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+
+//BX_DEBUG(( "# Okeyboard_serial_delay is %u usec",
+// (unsigned) bx_options.Okeyboard_serial_delay->get ()));
+ BX_KEY_THIS s.kbd_controller.timer_pending = 0;
+
+ // Mouse initialization stuff
+ BX_KEY_THIS s.mouse.sample_rate = 100; // reports per second
+ BX_KEY_THIS s.mouse.resolution_cpmm = 4; // 4 counts per millimeter
+ BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_RESET;
+ BX_KEY_THIS s.mouse.enable = 0;
+ BX_KEY_THIS s.mouse.delayed_dx = 0;
+ BX_KEY_THIS s.mouse.delayed_dy = 0;
+
+ for (i=0; i<BX_KBD_CONTROLLER_QSIZE; i++)
+ BX_KEY_THIS s.controller_Q[i] = 0;
+ BX_KEY_THIS s.controller_Qsize = 0;
+ BX_KEY_THIS s.controller_Qsource = 0;
+
+ // clear paste buffer
+ BX_KEY_THIS pastebuf = NULL;
+ BX_KEY_THIS pastebuf_len = 0;
+ BX_KEY_THIS pastebuf_ptr = 0;
+ BX_KEY_THIS paste_delay_changed ();
+ BX_KEY_THIS stop_paste = 0;
+
+ // mouse port installed on system board
+ DEV_cmos_set_reg(0x14, DEV_cmos_get_reg(0x14) | 0x04);
+
+#if BX_WITH_WX
+ static bx_bool first_time = 1;
+ if (first_time) {
+ first_time = 0;
+ // register shadow params (Experimental, not a complete list by far)
+ bx_list_c *list = new bx_list_c (BXP_KBD_PARAMETERS, "Keyboard State", "", 20);
+ list->add (new bx_shadow_bool_c (BXP_KBD_IRQ1_REQ,
+ "Keyboard IRQ1 requested: ", "",
+ &BX_KEY_THIS s.kbd_controller.irq1_requested));
+ list->add (new bx_shadow_bool_c (BXP_KBD_IRQ12_REQ,
+ "Keyboard IRQ12 requested: ", "",
+ &BX_KEY_THIS s.kbd_controller.irq12_requested));
+ list->add (new bx_shadow_num_c (BXP_KBD_TIMER_PENDING,
+ "Keyboard timer pending: ", "",
+ &BX_KEY_THIS s.kbd_controller.timer_pending));
+ list->add (new bx_shadow_bool_c (BXP_KBD_PARE,
+ "Keyboard PARE", "",
+ &BX_KEY_THIS s.kbd_controller.pare));
+ list->add (new bx_shadow_bool_c (BXP_KBD_TIM,
+ "Keyboard TIM", "",
+ &BX_KEY_THIS s.kbd_controller.tim));
+ list->add (new bx_shadow_bool_c (BXP_KBD_AUXB,
+ "Keyboard AUXB", "",
+ &BX_KEY_THIS s.kbd_controller.auxb));
+ list->add (new bx_shadow_bool_c (BXP_KBD_KEYL,
+ "Keyboard KEYL", "",
+ &BX_KEY_THIS s.kbd_controller.keyl));
+ list->add (new bx_shadow_bool_c (BXP_KBD_C_D,
+ "Keyboard C_D", "",
+ &BX_KEY_THIS s.kbd_controller.c_d));
+ list->add (new bx_shadow_bool_c (BXP_KBD_SYSF,
+ "Keyboard SYSF", "",
+ &BX_KEY_THIS s.kbd_controller.sysf));
+ list->add (new bx_shadow_bool_c (BXP_KBD_INPB,
+ "Keyboard INPB", "",
+ &BX_KEY_THIS s.kbd_controller.inpb));
+ list->add (new bx_shadow_bool_c (BXP_KBD_OUTB,
+ "Keyboard OUTB", "",
+ &BX_KEY_THIS s.kbd_controller.outb));
+ }
+#endif
+}
+
+ void
+bx_keyb_c::reset(unsigned type)
+{
+ if (BX_KEY_THIS pastebuf != NULL) {
+ BX_KEY_THIS stop_paste = 1;
+ }
+}
+
+ void
+bx_keyb_c::paste_delay_changed()
+{
+ BX_KEY_THIS pastedelay = bx_options.Okeyboard_paste_delay->get()/BX_IODEV_HANDLER_PERIOD;
+ BX_INFO(("will paste characters every %d keyboard ticks",BX_KEY_THIS pastedelay));
+}
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+// read function - the big picture:
+// if address == data port then
+// if byte for mouse then return it
+// else if byte for keyboard then return it
+// else address== status port
+// assemble the status bits and return them.
+//
+ Bit32u
+bx_keyb_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_KEY_SMF
+ bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_keyb_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_KEY_SMF
+
+//BX_DEBUG(( "read from port 0x%04x", (unsigned) address));
+
+ if (address == 0x60) { /* output buffer */
+ Bit8u val;
+ if (BX_KEY_THIS s.kbd_controller.auxb) { /* mouse byte available */
+ val = BX_KEY_THIS s.kbd_controller.aux_output_buffer;
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
+ // BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 0;
+ BX_KEY_THIS s.kbd_controller.auxb = 0;
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+
+ if (BX_KEY_THIS s.controller_Qsize) {
+ unsigned i;
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
+ // BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ BX_KEY_THIS s.kbd_controller.auxb = 1;
+ if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+ for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
+ // move Q elements towards head of queue by one
+ BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
+ }
+ BX_KEY_THIS s.controller_Qsize--;
+ }
+
+//BX_DEBUG(("mouse: ___io_read aux = 0x%02x", (unsigned) val));
+
+ DEV_pic_lower_irq(12);
+ activate_timer();
+ BX_DEBUG(("READ(%02x) (from mouse) = %02x", (unsigned) address,
+ (unsigned) val));
+ return val;
+ }
+ else if (BX_KEY_THIS s.kbd_controller.outb) { /* kbd byte available */
+ val = BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+ // BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 0;
+ BX_KEY_THIS s.kbd_controller.auxb = 0;
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+//BX_DEBUG(( "___io_read kbd"));
+
+ if (BX_KEY_THIS s.controller_Qsize) {
+ unsigned i;
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
+ // BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ BX_KEY_THIS s.kbd_controller.auxb = 1;
+ if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+ for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
+ // move Q elements towards head of queue by one
+ BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
+ }
+ BX_DEBUG(("s.controller_Qsize: %02X",BX_KEY_THIS s.controller_Qsize));
+ BX_KEY_THIS s.controller_Qsize--;
+ }
+
+ DEV_pic_lower_irq(1);
+ activate_timer();
+ BX_DEBUG(("READ(%02x) = %02x", (unsigned) address,
+ (unsigned) val));
+ return val;
+ }
+ else {
+ BX_DEBUG(("num_elements = %d", BX_KEY_THIS s.kbd_internal_buffer.num_elements));
+ BX_DEBUG(("read from port 60h with outb empty"));
+// val = BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+ return BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+ }
+ }
+
+#if BX_CPU_LEVEL >= 2
+ else if (address == 0x64) { /* status register */
+
+ return (BX_KEY_THIS s.kbd_controller.pare << 7) |
+ (BX_KEY_THIS s.kbd_controller.tim << 6) |
+ (BX_KEY_THIS s.kbd_controller.auxb << 5) |
+ (BX_KEY_THIS s.kbd_controller.keyl << 4) |
+ (BX_KEY_THIS s.kbd_controller.c_d << 3) |
+ (BX_KEY_THIS s.kbd_controller.sysf << 2) |
+ (BX_KEY_THIS s.kbd_controller.inpb << 1) |
+ BX_KEY_THIS s.kbd_controller.outb;
+ }
+
+#else /* BX_CPU_LEVEL > 0 */
+ /* XT MODE, System 8255 Mode Register */
+ else if (address == 0x64) { /* status register */
+ BX_DEBUG(("IO read from port 64h, system 8255 mode register"));
+ return BX_KEY_THIS s.kbd_controller.outb;
+ }
+#endif /* BX_CPU_LEVEL > 0 */
+
+ BX_PANIC(("unknown address in io read to keyboard port %x",
+ (unsigned) address));
+ return 0; /* keep compiler happy */
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_keyb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_KEY_SMF
+ bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_keyb_c::write( Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_KEY_SMF
+ Bit8u command_byte;
+ static int kbd_initialized=0;
+
+ BX_DEBUG(("keyboard: 8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
+
+ switch (address) {
+ case 0x60: // input buffer
+ // if expecting data byte from command last sent to port 64h
+ if (BX_KEY_THIS s.kbd_controller.expecting_port60h) {
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+ // data byte written last to 0x60
+ BX_KEY_THIS s.kbd_controller.c_d = 0;
+ if (BX_KEY_THIS s.kbd_controller.inpb) {
+ BX_PANIC(("write to port 60h, not ready for write"));
+ }
+ switch (BX_KEY_THIS s.kbd_controller.last_comm) {
+ case 0x60: // write command byte
+ {
+ bx_bool scan_convert, disable_keyboard,
+ disable_aux;
+
+ scan_convert = (value >> 6) & 0x01;
+ disable_aux = (value >> 5) & 0x01;
+ disable_keyboard = (value >> 4) & 0x01;
+ BX_KEY_THIS s.kbd_controller.sysf = (value >> 2) & 0x01;
+ BX_KEY_THIS s.kbd_controller.allow_irq1 = (value >> 0) & 0x01;
+ BX_KEY_THIS s.kbd_controller.allow_irq12 = (value >> 1) & 0x01;
+ set_kbd_clock_enable(!disable_keyboard);
+ set_aux_clock_enable(!disable_aux);
+ if (BX_KEY_THIS s.kbd_controller.allow_irq12 && BX_KEY_THIS s.kbd_controller.auxb)
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+ else if (BX_KEY_THIS s.kbd_controller.allow_irq1 && BX_KEY_THIS s.kbd_controller.outb)
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+
+ BX_DEBUG(( " allow_irq12 set to %u", (unsigned)
+ BX_KEY_THIS s.kbd_controller.allow_irq12));
+ if ( !scan_convert )
+ BX_ERROR(("keyboard: (mch) scan convert turned off"));
+
+ // (mch) NT needs this
+ BX_KEY_THIS s.kbd_controller.scancodes_translate = scan_convert;
+ }
+ break;
+ case 0xd1: // write output port
+ BX_DEBUG(("write output port with value %02xh",
+ (unsigned) value));
+ BX_SET_ENABLE_A20( (value & 0x02) != 0 );
+ if (!(value & 0x01))
+ BX_PANIC(("IO write: processor reset requested!"));
+ break;
+ case 0xd4: // Write to mouse
+ // I don't think this enables the AUX clock
+ //set_aux_clock_enable(1); // enable aux clock line
+ kbd_ctrl_to_mouse(value);
+ // ??? should I reset to previous value of aux enable?
+ break;
+
+ case 0xd3: // write mouse output buffer
+ // Queue in mouse output buffer
+ controller_enQ(value, 1);
+ break;
+
+ case 0xd2:
+ // Queue in keyboard output buffer
+ controller_enQ(value, 0);
+ break;
+
+ default:
+ BX_PANIC(("=== unsupported write to port 60h(lastcomm=%02x): %02x",
+ (unsigned) BX_KEY_THIS s.kbd_controller.last_comm, (unsigned) value));
+ }
+ }
+ else {
+ // data byte written last to 0x60
+ BX_KEY_THIS s.kbd_controller.c_d = 0;
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+ /* pass byte to keyboard */
+ /* ??? should conditionally pass to mouse device here ??? */
+ if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0) {
+ BX_ERROR(("keyboard disabled & send of byte %02x to kbd",
+ (unsigned) value));
+ }
+ kbd_ctrl_to_kbd(value);
+ }
+ break;
+
+ case 0x64: // control register
+ // command byte written last to 0x64
+ BX_KEY_THIS s.kbd_controller.c_d = 1;
+ BX_KEY_THIS s.kbd_controller.last_comm = value;
+ // most commands NOT expecting port60 write next
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+
+ switch (value) {
+ case 0x20: // get keyboard command byte
+ BX_DEBUG(("get keyboard command byte"));
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+ BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ command_byte =
+ (BX_KEY_THIS s.kbd_controller.scancodes_translate << 6) |
+ ((!BX_KEY_THIS s.kbd_controller.aux_clock_enabled) << 5) |
+ ((!BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) << 4) |
+ (0 << 3) |
+ (BX_KEY_THIS s.kbd_controller.sysf << 2) |
+ (BX_KEY_THIS s.kbd_controller.allow_irq12 << 1) |
+ (BX_KEY_THIS s.kbd_controller.allow_irq1 << 0);
+ controller_enQ(command_byte, 0);
+ break;
+ case 0x60: // write command byte
+ BX_DEBUG(("write command byte"));
+ // following byte written to port 60h is command byte
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+ break;
+
+ case 0xa0:
+ BX_DEBUG(("keyboard BIOS name not supported"));
+ break;
+
+ case 0xa1:
+ BX_DEBUG(("keyboard BIOS version not supported"));
+ break;
+
+ case 0xa7: // disable the aux device
+ set_aux_clock_enable(0);
+ BX_DEBUG(("aux device disabled"));
+ break;
+ case 0xa8: // enable the aux device
+ set_aux_clock_enable(1);
+ BX_DEBUG(("aux device enabled"));
+ break;
+ case 0xa9: // Test Mouse Port
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+ BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ controller_enQ(0x00, 0); // no errors detected
+ break;
+ case 0xaa: // motherboard controller self test
+ BX_DEBUG(("Self Test"));
+ if( kbd_initialized == 0 )
+ {
+ BX_KEY_THIS s.controller_Qsize = 0;
+ BX_KEY_THIS s.kbd_controller.outb = 0;
+ kbd_initialized++;
+ }
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+ BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ // (mch) Why is this commented out??? Enabling
+ BX_KEY_THIS s.kbd_controller.sysf = 1; // self test complete
+ controller_enQ(0x55, 0); // controller OK
+ break;
+ case 0xab: // Interface Test
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ controller_enQ(0x00, 0);
+ break;
+ case 0xad: // disable keyboard
+ set_kbd_clock_enable(0);
+ BX_DEBUG(("keyboard disabled"));
+ break;
+ case 0xae: // enable keyboard
+ set_kbd_clock_enable(1);
+ BX_DEBUG(("keyboard enabled"));
+ break;
+ case 0xc0: // read input port
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ // keyboard power normal
+ controller_enQ(0x00, 0);
+ break;
+ case 0xd0: // read output port: next byte read from port 60h
+ BX_DEBUG(("io write to port 64h, command d0h (partial)"));
+ // controller output buffer must be empty
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+ break;
+ }
+ controller_enQ(
+ (BX_KEY_THIS s.kbd_controller.auxb << 5) |
+ (BX_KEY_THIS s.kbd_controller.outb << 4) |
+ (BX_GET_ENABLE_A20() << 1) |
+ 0x01, 0);
+ break;
+
+ case 0xd1: // write output port: next byte written to port 60h
+ BX_DEBUG(("write output port"));
+ // following byte to port 60h written to output port
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+ break;
+
+ case 0xd3: // write mouse output buffer
+ //FIXME: Why was this a panic?
+ BX_DEBUG(("io write 0x64: command = 0xD3(write mouse outb)"));
+ // following byte to port 60h written to output port as mouse write.
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+ break;
+
+ case 0xd4: // write to mouse
+ BX_DEBUG(("io write 0x64: command = 0xD4 (write to mouse)"));
+ // following byte written to port 60h
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+ break;
+
+ case 0xd2: // write keyboard output buffer
+ BX_DEBUG(("io write 0x64: write keyboard output buffer"));
+ BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+ break;
+ case 0xdd: // Disable A20 Address Line
+ BX_SET_ENABLE_A20(0);
+ break;
+ case 0xdf: // Enable A20 Address Line
+ BX_SET_ENABLE_A20(1);
+ break;
+ case 0xc1: // Continuous Input Port Poll, Low
+ case 0xc2: // Continuous Input Port Poll, High
+ case 0xe0: // Read Test Inputs
+ BX_PANIC(("io write 0x64: command = %02xh", (unsigned) value));
+ break;
+
+ case 0xfe: // System Reset, transition to real mode
+ BX_INFO(("system reset"));
+ bx_pc_system.ResetSignal( PCS_SET ); /* XXX is this right? */
+ {
+ for (int i=0; i<BX_SMP_PROCESSORS; i++)
+ BX_CPU(i)->reset(BX_RESET_HARDWARE);
+ }
+ // Use bx_pc_system if necessary bx_cpu.reset_cpu();
+ // bx_pc_system.ResetSignal( PCS_SET );
+ break;
+
+ default:
+ if (value==0xff || (value>=0xf0 && value<=0xfd)) {
+ /* useless pulse output bit commands ??? */
+ BX_DEBUG(("io write to port 64h, useless command %02x",
+ (unsigned) value));
+ return;
+ }
+ BX_PANIC(("unsupported io write to keyboard port %x, value = %x",
+ (unsigned) address, (unsigned) value));
+ break;
+ }
+ break;
+
+ default: BX_PANIC(("unknown address in bx_keyb_c::write()"));
+ }
+}
+
+// service_paste_buf() transfers data from the paste buffer to the hardware
+// keyboard buffer. It tries to transfer as many chars as possible at a
+// time, but because different chars require different numbers of scancodes
+// we have to be conservative. Note that this process depends on the
+// keymap tables to know what chars correspond to what keys, and which
+// chars require a shift or other modifier.
+void
+bx_keyb_c::service_paste_buf ()
+{
+ if (!BX_KEY_THIS pastebuf) return;
+ BX_DEBUG (("service_paste_buf: ptr at %d out of %d", BX_KEY_THIS pastebuf_ptr, BX_KEY_THIS pastebuf_len));
+ int fill_threshold = BX_KBD_ELEMENTS - 8;
+ while ( (BX_KEY_THIS pastebuf_ptr < BX_KEY_THIS pastebuf_len) && ! BX_KEY_THIS stop_paste) {
+ if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= fill_threshold)
+ return;
+ // there room in the buffer for a keypress and a key release.
+ // send one keypress and a key release.
+ Bit8u byte = BX_KEY_THIS pastebuf[BX_KEY_THIS pastebuf_ptr];
+ BXKeyEntry *entry = bx_keymap.findAsciiChar (byte);
+ if (!entry) {
+ BX_ERROR (("paste character 0x%02x ignored", byte));
+ } else {
+ BX_DEBUG (("pasting character 0x%02x. baseKey is %04x", byte, entry->baseKey));
+ if (entry->modKey != BX_KEYMAP_UNKNOWN)
+ BX_KEY_THIS gen_scancode (entry->modKey);
+ BX_KEY_THIS gen_scancode (entry->baseKey);
+ BX_KEY_THIS gen_scancode (entry->baseKey | BX_KEY_RELEASED);
+ if (entry->modKey != BX_KEYMAP_UNKNOWN)
+ BX_KEY_THIS gen_scancode (entry->modKey | BX_KEY_RELEASED);
+ }
+ BX_KEY_THIS pastebuf_ptr++;
+ }
+ // reached end of pastebuf. free the memory it was using.
+ delete [] BX_KEY_THIS pastebuf;
+ BX_KEY_THIS pastebuf = NULL;
+ BX_KEY_THIS stop_paste = 0;
+}
+
+// paste_bytes schedules an arbitrary number of ASCII characters to be
+// inserted into the hardware queue as it become available. Any previous
+// paste which is still in progress will be thrown out. BYTES is a pointer
+// to a region of memory containing the chars to be pasted. When the paste
+// is complete, the keyboard code will call delete [] bytes;
+void
+bx_keyb_c::paste_bytes (Bit8u *bytes, Bit32s length)
+{
+ BX_DEBUG (("paste_bytes: %d bytes", length));
+ if (BX_KEY_THIS pastebuf) {
+ BX_ERROR (("previous paste was not completed! %d chars lost",
+ BX_KEY_THIS pastebuf_len - BX_KEY_THIS pastebuf_ptr));
+ delete [] BX_KEY_THIS pastebuf; // free the old paste buffer
+ }
+ BX_KEY_THIS pastebuf = bytes;
+ BX_KEY_THIS pastebuf_ptr = 0;
+ BX_KEY_THIS pastebuf_len = length;
+ BX_KEY_THIS service_paste_buf ();
+}
+
+ void
+bx_keyb_c::gen_scancode(Bit32u key)
+{
+ unsigned char *scancode;
+ Bit8u i;
+
+ BX_DEBUG(( "gen_scancode(): %s %s", bx_keymap.getBXKeyName(key), (key >> 31)?"released":"pressed"));
+
+ if (!BX_KEY_THIS s.kbd_controller.scancodes_translate)
+ BX_DEBUG(("keyboard: gen_scancode with scancode_translate cleared"));
+
+ // Ignore scancode if keyboard clock is driven low
+ if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0)
+ return;
+
+ // Ignore scancode if scanning is disabled
+ if (BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled==0)
+ return;
+
+ // Switch between make and break code
+ if (key & BX_KEY_RELEASED)
+ scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].brek;
+ else
+ scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].make;
+
+ if (BX_KEY_THIS s.kbd_controller.scancodes_translate) {
+ // Translate before send
+ Bit8u escaped=0x00;
+
+ for (i=0; i<strlen( (const char *)scancode ); i++) {
+ if (scancode[i] == 0xF0)
+ escaped=0x80;
+ else {
+ BX_DEBUG(("gen_scancode(): writing translated %02x",translation8042[scancode[i] ] | escaped));
+ kbd_enQ(translation8042[scancode[i] ] | escaped );
+ escaped=0x00;
+ }
+ }
+ }
+ else {
+ // Send raw data
+ for (i=0; i<strlen( (const char *)scancode ); i++) {
+ BX_DEBUG(("gen_scancode(): writing raw %02x",scancode[i]));
+ kbd_enQ( scancode[i] );
+ }
+ }
+}
+
+
+
+ void BX_CPP_AttrRegparmN(1)
+bx_keyb_c::set_kbd_clock_enable(Bit8u value)
+{
+ bx_bool prev_kbd_clock_enabled;
+
+ if (value==0) {
+ BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 0;
+ }
+ else {
+ /* is another byte waiting to be sent from the keyboard ? */
+ prev_kbd_clock_enabled = BX_KEY_THIS s.kbd_controller.kbd_clock_enabled;
+ BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
+
+ if (prev_kbd_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0) {
+ activate_timer();
+ }
+ }
+}
+
+
+
+ void
+bx_keyb_c::set_aux_clock_enable(Bit8u value)
+{
+ bx_bool prev_aux_clock_enabled;
+
+ BX_DEBUG(("set_aux_clock_enable(%u)", (unsigned) value));
+ if (value==0) {
+ BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
+ }
+ else {
+ /* is another byte waiting to be sent from the keyboard ? */
+ prev_aux_clock_enabled = BX_KEY_THIS s.kbd_controller.aux_clock_enabled;
+ BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 1;
+ if (prev_aux_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0)
+ activate_timer();
+ }
+}
+
+ Bit8u
+bx_keyb_c::get_kbd_enable(void)
+{
+ BX_DEBUG(("get_kbd_enable(): getting kbd_clock_enabled of: %02x",
+ (unsigned) BX_KEY_THIS s.kbd_controller.kbd_clock_enabled));
+
+ return(BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
+}
+
+ void
+bx_keyb_c::controller_enQ(Bit8u data, unsigned source)
+{
+ // source is 0 for keyboard, 1 for mouse
+
+ BX_DEBUG(("controller_enQ(%02x) source=%02x", (unsigned) data,source));
+
+ if (BX_KEY_THIS s.kbd_controller.outb)
+ BX_ERROR(("controller_enQ(): OUTB set!"));
+
+ // see if we need to Q this byte from the controller
+ // remember this includes mouse bytes.
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+ if (BX_KEY_THIS s.controller_Qsize >= BX_KBD_CONTROLLER_QSIZE)
+ BX_PANIC(("controller_enq(): controller_Q full!"));
+ BX_KEY_THIS s.controller_Q[BX_KEY_THIS s.controller_Qsize++] = data;
+ BX_KEY_THIS s.controller_Qsource = source;
+ return;
+ }
+
+ // the Q is empty
+ if (source == 0) { // keyboard
+ BX_KEY_THIS s.kbd_controller.kbd_output_buffer = data;
+ // BX_INFO(("kbd: %04d outb 1 auxb 0",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ BX_KEY_THIS s.kbd_controller.auxb = 0;
+ BX_KEY_THIS s.kbd_controller.inpb = 0;
+ if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+ }
+ else { // mouse
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer = data;
+ // BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ BX_KEY_THIS s.kbd_controller.auxb = 1;
+ BX_KEY_THIS s.kbd_controller.inpb = 0;
+ if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+ }
+}
+
+void
+bx_keyb_c::kbd_enQ_imm(Bit8u val)
+{
+ int tail;
+
+ if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
+ BX_PANIC(("internal keyboard buffer full (imm)"));
+ return;
+ }
+
+ /* enqueue scancode in multibyte internal keyboard buffer */
+ tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
+ BX_KBD_ELEMENTS;
+
+ BX_KEY_THIS s.kbd_controller.kbd_output_buffer = val;
+ // BX_INFO(("kbd: %04d outb 1",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+
+ if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+}
+
+
+ void
+bx_keyb_c::kbd_enQ(Bit8u scancode)
+{
+ int tail;
+
+ BX_DEBUG(("kbd_enQ(0x%02x)", (unsigned) scancode));
+
+ if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
+ BX_INFO(("internal keyboard buffer full, ignoring scancode.(%02x)",
+ (unsigned) scancode));
+ return;
+ }
+
+ /* enqueue scancode in multibyte internal keyboard buffer */
+ BX_DEBUG(("kbd_enQ: putting scancode 0x%02x in internal buffer",
+ (unsigned) scancode));
+ tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
+ BX_KBD_ELEMENTS;
+ BX_KEY_THIS s.kbd_internal_buffer.buffer[tail] = scancode;
+ BX_KEY_THIS s.kbd_internal_buffer.num_elements++;
+
+ if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) {
+ activate_timer();
+ BX_DEBUG(("activating timer..."));
+ return;
+ }
+//BX_DEBUG(( "# not activating timer...");
+//BX_DEBUG(( "# allow_irq1 = %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq1);
+//BX_DEBUG(( "# outb = %u", (unsigned) BX_KEY_THIS s.kbd_controller.outb);
+//BX_DEBUG(( "# clock_enab = %u", (unsigned) BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
+//BX_DEBUG(( "# out_buffer = %u", (unsigned) BX_KEY_THIS s.kbd_controller.kbd_output_buffer);
+}
+
+ bx_bool BX_CPP_AttrRegparmN(3)
+bx_keyb_c::mouse_enQ_packet(Bit8u b1, Bit8u b2, Bit8u b3)
+{
+ if ((BX_KEY_THIS s.mouse_internal_buffer.num_elements + 3) >= BX_MOUSE_BUFF_SIZE) {
+ return(0); /* buffer doesn't have the space */
+ }
+
+//BX_DEBUG(("mouse: enQ_packet(%02x, %02x, %02x)",
+// (unsigned) b1, (unsigned) b2, (unsigned) b3));
+
+ mouse_enQ(b1);
+ mouse_enQ(b2);
+ mouse_enQ(b3);
+ return(1);
+}
+
+
+ void
+bx_keyb_c::mouse_enQ(Bit8u mouse_data)
+{
+ int tail;
+
+ BX_DEBUG(("mouse_enQ(%02x)", (unsigned) mouse_data));
+
+ if (BX_KEY_THIS s.mouse_internal_buffer.num_elements >= BX_MOUSE_BUFF_SIZE) {
+ BX_ERROR(("mouse: internal mouse buffer full, ignoring mouse data.(%02x)",
+ (unsigned) mouse_data));
+ return;
+ }
+//BX_DEBUG(( "# mouse_enq() aux_clock_enabled = %u",
+// (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled);
+
+ /* enqueue mouse data in multibyte internal mouse buffer */
+ tail = (BX_KEY_THIS s.mouse_internal_buffer.head + BX_KEY_THIS s.mouse_internal_buffer.num_elements) %
+ BX_MOUSE_BUFF_SIZE;
+ BX_KEY_THIS s.mouse_internal_buffer.buffer[tail] = mouse_data;
+ BX_KEY_THIS s.mouse_internal_buffer.num_elements++;
+
+ if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.aux_clock_enabled) {
+ activate_timer();
+//BX_DEBUG(( "# activating timer...");
+ return;
+ }
+//BX_DEBUG(( "# not activating timer...");
+//BX_DEBUG(( "# allow_irq12= %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12);
+//BX_DEBUG(( "# outb = %u", (unsigned) BX_KEY_THIS s.kbd_controller.outb);
+//BX_DEBUG(( "# clock_enab = %u", (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled);
+//BX_DEBUG(( "# out_buffer = %u", (unsigned) BX_KEY_THIS s.kbd_controller.aux_output_buffer);
+}
+
+ void
+bx_keyb_c::kbd_ctrl_to_kbd(Bit8u value)
+{
+
+ BX_DEBUG(("controller passed byte %02xh to keyboard", value));
+
+ if (BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic) {
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
+ BX_KEY_THIS s.kbd_internal_buffer.delay = (value >> 5) & 0x03;
+ switch (BX_KEY_THIS s.kbd_internal_buffer.delay) {
+ case 0: BX_INFO(("setting delay to 250 mS (unused)")); break;
+ case 1: BX_INFO(("setting delay to 500 mS (unused)")); break;
+ case 2: BX_INFO(("setting delay to 750 mS (unused)")); break;
+ case 3: BX_INFO(("setting delay to 1000 mS (unused)")); break;
+ }
+ BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = value & 0x1f;
+ double cps = 1 /((double)(8 + (value & 0x07)) * (double)exp(log((double)2) * (double)((value >> 3) & 0x03)) * 0.00417);
+ BX_INFO(("setting repeat rate to %.1f cps (unused)", cps));
+ kbd_enQ(0xFA); // send ACK
+ return;
+ }
+
+ if (BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write) {
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
+ BX_KEY_THIS s.kbd_internal_buffer.led_status = value;
+ BX_DEBUG(("LED status set to %02x",
+ (unsigned) BX_KEY_THIS s.kbd_internal_buffer.led_status));
+ kbd_enQ(0xFA); // send ACK %%%
+ return;
+ }
+
+ if (BX_KEY_THIS s.kbd_controller.expecting_scancodes_set) {
+ BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
+ if( value != 0 ) {
+ if( value<4 ) {
+ BX_KEY_THIS s.kbd_controller.current_scancodes_set = (value-1);
+ BX_INFO(("Switched to scancode set %d\n",
+ (unsigned) BX_KEY_THIS s.kbd_controller.current_scancodes_set + 1));
+ kbd_enQ(0xFA);
+ }
+ else {
+ BX_ERROR(("Received scancodes set out of range: %d\n", value ));
+ kbd_enQ(0xFF); // send ERROR
+ }
+ }
+ else {
+ // Send current scancodes set to port 0x60
+ kbd_enQ( 1 + (BX_KEY_THIS s.kbd_controller.current_scancodes_set) );
+ }
+ return;
+ }
+
+ switch (value) {
+ case 0x00: // ??? ignore and let OS timeout with no response
+ kbd_enQ(0xFA); // send ACK %%%
+ return;
+ break;
+
+ case 0x05: // ???
+ // (mch) trying to get this to work...
+ BX_KEY_THIS s.kbd_controller.sysf = 1;
+ kbd_enQ_imm(0xfe);
+ return;
+ break;
+
+ case 0xed: // LED Write
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 1;
+ kbd_enQ_imm(0xFA); // send ACK %%%
+ return;
+ break;
+
+ case 0xee: // echo
+ kbd_enQ(0xEE); // return same byte (EEh) as echo diagnostic
+ return;
+ break;
+
+ case 0xf0: // Select alternate scan code set
+ BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 1;
+ BX_DEBUG(("Expecting scancode set info...\n"));
+ kbd_enQ(0xFA); // send ACK
+ return;
+ break;
+
+ case 0xf2: // identify keyboard
+ BX_INFO(("identify keyboard command received"));
+
+ // XT sends nothing, AT sends ACK
+ // MFII with translation sends ACK+ABh+41h
+ // MFII without translation sends ACK+ABh+83h
+ if (bx_options.Okeyboard_type->get() != BX_KBD_XT_TYPE) {
+ kbd_enQ(0xFA);
+ if (bx_options.Okeyboard_type->get() == BX_KBD_MF_TYPE) {
+ kbd_enQ(0xAB);
+
+ if(BX_KEY_THIS s.kbd_controller.scancodes_translate)
+ kbd_enQ(0x41);
+ else
+ kbd_enQ(0x83);
+ }
+ }
+ return;
+ break;
+
+ case 0xf3: // typematic info
+ BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 1;
+ BX_INFO(("setting typematic info"));
+ kbd_enQ(0xFA); // send ACK
+ return;
+ break;
+
+ case 0xf4: // enable keyboard
+ BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+ kbd_enQ(0xFA); // send ACK
+ return;
+ break;
+
+ case 0xf5: // reset keyboard to power-up settings and disable scanning
+ resetinternals(1);
+ kbd_enQ(0xFA); // send ACK
+ BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 0;
+ BX_INFO(("reset-disable command received"));
+ return;
+ break;
+
+ case 0xf6: // reset keyboard to power-up settings and enable scanning
+ resetinternals(1);
+ kbd_enQ(0xFA); // send ACK
+ BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+ BX_INFO(("reset-enable command received"));
+ return;
+ break;
+
+ case 0xf7: // PS/2 Set All Keys To Typematic
+ case 0xf8: // PS/2 Set All Keys to Make/Break
+ case 0xf9: // PS/2 PS/2 Set All Keys to Make
+ case 0xfa: // PS/2 Set All Keys to Typematic Make/Break
+ case 0xfb: // PS/2 Set Key Type to Typematic
+ case 0xfc: // PS/2 Set Key Type to Make/Break
+ case 0xfd: // PS/2 Set Key Type to Make
+ // Silently ignore and let the OS timeout, for now.
+ // If anyone has code around that makes use of that, I can
+ // provide documentation on their behavior (ask core@ggi-project.org)
+ return;
+ break;
+
+ case 0xfe: // resend. aiiee.
+ BX_PANIC( ("got 0xFE (resend)"));
+ return;
+ break;
+
+ case 0xff: // reset: internal keyboard reset and afterwards the BAT
+ BX_DEBUG(("reset command received"));
+ resetinternals(1);
+ kbd_enQ(0xFA); // send ACK
+ kbd_enQ(0xAA); // BAT test passed
+ return;
+ break;
+
+ case 0xd3:
+ kbd_enQ(0xfa);
+ return;
+
+ default:
+ /* XXX fix this properly:
+ http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/mouse/mouse.html
+ http://sourceforge.net/tracker/index.php?func=detail&aid=422457&group_id=12580&atid=112580
+ */
+ BX_ERROR(("kbd_ctrl_to_kbd(): got value of %02x",
+ (unsigned) value));
+ kbd_enQ(0xFA); /* send ACK ??? */
+ return;
+ break;
+ }
+}
+
+ void
+bx_keyb_c::timer_handler(void *this_ptr)
+{
+ bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+ unsigned retval;
+
+ // retval=class_ptr->periodic( bx_options.Okeyboard_serial_delay->get());
+ retval=class_ptr->periodic(1);
+
+ if(retval&0x01)
+ DEV_pic_raise_irq(1);
+ if(retval&0x02)
+ DEV_pic_raise_irq(12);
+}
+
+ unsigned
+bx_keyb_c::periodic( Bit32u usec_delta )
+{
+/* static int multiple=0; */
+ static unsigned count_before_paste=0;
+ Bit8u retval;
+
+ UNUSED( usec_delta );
+
+ if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled ) {
+ if(++count_before_paste>=BX_KEY_THIS pastedelay) {
+ // after the paste delay, consider adding moving more chars
+ // from the paste buffer to the keyboard buffer.
+ BX_KEY_THIS service_paste_buf ();
+ count_before_paste=0;
+ }
+ }
+
+ retval = BX_KEY_THIS s.kbd_controller.irq1_requested | (BX_KEY_THIS s.kbd_controller.irq12_requested << 1);
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+
+ if ( BX_KEY_THIS s.kbd_controller.timer_pending == 0 ) {
+ return(retval);
+ }
+
+ if ( usec_delta >= BX_KEY_THIS s.kbd_controller.timer_pending ) {
+ BX_KEY_THIS s.kbd_controller.timer_pending = 0;
+ }
+ else {
+ BX_KEY_THIS s.kbd_controller.timer_pending -= usec_delta;
+ return(retval);
+ }
+
+ if (BX_KEY_THIS s.kbd_controller.outb) {
+ return(retval);
+ }
+
+ /* nothing in outb, look for possible data xfer from keyboard or mouse */
+ if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled && BX_KEY_THIS s.kbd_internal_buffer.num_elements) {
+//BX_DEBUG(( "# servicing keyboard code");
+ BX_DEBUG(("service_keyboard: key in internal buffer waiting"));
+ BX_KEY_THIS s.kbd_controller.kbd_output_buffer =
+ BX_KEY_THIS s.kbd_internal_buffer.buffer[BX_KEY_THIS s.kbd_internal_buffer.head];
+ // BX_INFO(("kbd: %04d outb 1",__LINE__)); // das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ // commented out since this would override the current state of the
+ // mouse buffer flag - no bug seen - just seems wrong (das)
+ // BX_KEY_THIS s.kbd_controller.auxb = 0;
+//BX_DEBUG(( "# ___kbd::periodic kbd");
+ BX_KEY_THIS s.kbd_internal_buffer.head = (BX_KEY_THIS s.kbd_internal_buffer.head + 1) %
+ BX_KBD_ELEMENTS;
+ BX_KEY_THIS s.kbd_internal_buffer.num_elements--;
+ if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+ BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+ }
+ else {
+ create_mouse_packet(0);
+ if (BX_KEY_THIS s.kbd_controller.aux_clock_enabled && BX_KEY_THIS s.mouse_internal_buffer.num_elements) {
+//BX_DEBUG(( "# servicing mouse code");
+ BX_DEBUG(("service_keyboard: key(from mouse) in internal buffer waiting"));
+ BX_KEY_THIS s.kbd_controller.aux_output_buffer =
+ BX_KEY_THIS s.mouse_internal_buffer.buffer[BX_KEY_THIS s.mouse_internal_buffer.head];
+
+ // BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); //das
+ BX_KEY_THIS s.kbd_controller.outb = 1;
+ BX_KEY_THIS s.kbd_controller.auxb = 1;
+//BX_DEBUG(( "# ___kbd:periodic aux");
+ BX_KEY_THIS s.mouse_internal_buffer.head = (BX_KEY_THIS s.mouse_internal_buffer.head + 1) %
+ BX_MOUSE_BUFF_SIZE;
+ BX_KEY_THIS s.mouse_internal_buffer.num_elements--;
+//BX_DEBUG(( "# allow12 = %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12);
+ if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+ BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+ }
+ else {
+ BX_DEBUG(("service_keyboard(): no keys waiting"));
+ }
+ }
+ return(retval);
+}
+
+
+
+
+ void
+bx_keyb_c::activate_timer(void)
+{
+ if (BX_KEY_THIS s.kbd_controller.timer_pending == 0) {
+ // BX_KEY_THIS s.kbd_controller.timer_pending = bx_options.Okeyboard_serial_delay->get ();
+ BX_KEY_THIS s.kbd_controller.timer_pending = 1;
+ }
+}
+
+
+ void
+bx_keyb_c::kbd_ctrl_to_mouse(Bit8u value)
+{
+BX_DEBUG(("MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+BX_DEBUG((" enable = %u", (unsigned) BX_KEY_THIS s.mouse.enable));
+BX_DEBUG((" allow_irq12 = %u",
+ (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12));
+BX_DEBUG((" aux_clock_enabled = %u",
+ (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled));
+//BX_DEBUG(( "MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+
+ // an ACK (0xFA) is always the first response to any valid input
+ // received from the system other than Set-Wrap-Mode & Resend-Command
+
+
+ if (BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter) {
+ BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+ switch (BX_KEY_THIS s.kbd_controller.last_mouse_command) {
+ case 0xf3: // Set Mouse Sample Rate
+ BX_KEY_THIS s.mouse.sample_rate = value;
+ BX_DEBUG(("[mouse] Sampling rate set: %d Hz", value));
+ controller_enQ(0xFA, 1); // ack
+ break;
+
+ case 0xe8: // Set Mouse Resolution
+ switch (value) {
+ case 0:
+ BX_KEY_THIS s.mouse.resolution_cpmm = 1;
+ break;
+ case 1:
+ BX_KEY_THIS s.mouse.resolution_cpmm = 2;
+ break;
+ case 2:
+ BX_KEY_THIS s.mouse.resolution_cpmm = 4;
+ break;
+ case 3:
+ BX_KEY_THIS s.mouse.resolution_cpmm = 8;
+ break;
+ default:
+ BX_PANIC(("[mouse] Unknown resolution %d", value));
+ break;
+ }
+ BX_DEBUG(("[mouse] Resolution set to %d counts per mm",
+ BX_KEY_THIS s.mouse.resolution_cpmm));
+
+ controller_enQ(0xFA, 1); // ack
+ break;
+
+ default:
+ BX_PANIC(("MOUSE: unknown last command (%02xh)", (unsigned) BX_KEY_THIS s.kbd_controller.last_mouse_command));
+ }
+ } else {
+ BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+ BX_KEY_THIS s.kbd_controller.last_mouse_command = value;
+
+ // test for wrap mode first
+ if (BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
+ // if not a reset command or reset wrap mode
+ // then just echo the byte.
+ if ((value != 0xff) && (value != 0xec)) {
+ if (bx_dbg.mouse)
+ BX_INFO(("[mouse] wrap mode: Ignoring command %0X02.",value));
+ controller_enQ(value,1);
+ // bail out
+ return;
+ }
+ }
+ switch ( value ) {
+ case 0xe6: // Set Mouse Scaling to 1:1
+ controller_enQ(0xFA, 1); // ACK
+ BX_KEY_THIS s.mouse.scaling = 2;
+ BX_DEBUG(("[mouse] Scaling set to 1:1"));
+ break;
+
+ case 0xe7: // Set Mouse Scaling to 2:1
+ controller_enQ(0xFA, 1); // ACK
+ BX_KEY_THIS s.mouse.scaling = 2;
+ BX_DEBUG(("[mouse] Scaling set to 2:1"));
+ break;
+
+ case 0xe8: // Set Mouse Resolution
+ controller_enQ(0xFA, 1); // ACK
+ BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
+ break;
+
+ case 0xea: // Set Stream Mode
+ if (bx_dbg.mouse)
+ BX_INFO(("[mouse] Mouse stream mode on."));
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_STREAM;
+ controller_enQ(0xFA, 1); // ACK
+ break;
+
+ case 0xec: // Reset Wrap Mode
+ // unless we are in wrap mode ignore the command
+ if ( BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
+ if (bx_dbg.mouse)
+ BX_INFO(("[mouse] Mouse wrap mode off."));
+ // restore previous mode except disable stream mode reporting.
+ // ### TODO disabling reporting in stream mode
+ BX_KEY_THIS s.mouse.mode = BX_KEY_THIS s.mouse.saved_mode;
+ controller_enQ(0xFA, 1); // ACK
+ }
+ break;
+ case 0xee: // Set Wrap Mode
+ // ### TODO flush output queue.
+ // ### TODO disable interrupts if in stream mode.
+ if (bx_dbg.mouse)
+ BX_INFO(("[mouse] Mouse wrap mode on."));
+ BX_KEY_THIS s.mouse.saved_mode = BX_KEY_THIS s.mouse.mode;
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_WRAP;
+ controller_enQ(0xFA, 1); // ACK
+ break;
+
+ case 0xf0: // Set Remote Mode (polling mode, i.e. not stream mode.)
+ if (bx_dbg.mouse)
+ BX_INFO(("[mouse] Mouse remote mode on."));
+ // ### TODO should we flush/discard/ignore any already queued packets?
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_REMOTE;
+ controller_enQ(0xFA, 1); // ACK
+ break;
+
+
+ case 0xf2: // Read Device Type
+ controller_enQ(0xFA, 1); // ACK
+ controller_enQ(0x00, 1); // Device ID
+ BX_DEBUG(("[mouse] Read mouse ID"));
+ break;
+
+ case 0xf3: // Set Mouse Sample Rate (sample rate written to port 60h)
+ controller_enQ(0xFA, 1); // ACK
+ BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
+ break;
+
+ case 0xf4: // Enable (in stream mode)
+ BX_KEY_THIS s.mouse.enable = 1;
+ controller_enQ(0xFA, 1); // ACK
+ BX_DEBUG(("[mouse] Mouse enabled (stream mode)"));
+ break;
+
+ case 0xf5: // Disable (in stream mode)
+ BX_KEY_THIS s.mouse.enable = 0;
+ controller_enQ(0xFA, 1); // ACK
+ BX_DEBUG(("[mouse] Mouse disabled (stream mode)"));
+ break;
+
+ case 0xf6: // Set Defaults
+ BX_KEY_THIS s.mouse.sample_rate = 100; /* reports per second (default) */
+ BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
+ BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
+ BX_KEY_THIS s.mouse.enable = 0;
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_STREAM;
+ controller_enQ(0xFA, 1); // ACK
+ BX_DEBUG(("[mouse] Set Defaults"));
+ break;
+
+ case 0xff: // Reset
+ BX_KEY_THIS s.mouse.sample_rate = 100; /* reports per second (default) */
+ BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
+ BX_KEY_THIS s.mouse.scaling = 1; /* 1:1 (default) */
+ BX_KEY_THIS s.mouse.mode = MOUSE_MODE_RESET;
+ BX_KEY_THIS s.mouse.enable = 0;
+ /* (mch) NT expects an ack here */
+ controller_enQ(0xFA, 1); // ACK
+ controller_enQ(0xAA, 1); // completion code
+ controller_enQ(0x00, 1); // ID code (normal mouse, wheelmouse has id 0x3)
+ BX_DEBUG(("[mouse] Mouse reset"));
+ break;
+
+ case 0xe9: // Get mouse information
+ // should we ack here? (mch): Yes
+ controller_enQ(0xFA, 1); // ACK
+ controller_enQ(BX_KEY_THIS s.mouse.get_status_byte(), 1); // status
+ controller_enQ(BX_KEY_THIS s.mouse.get_resolution_byte(), 1); // resolution
+ controller_enQ(BX_KEY_THIS s.mouse.sample_rate, 1); // sample rate
+ BX_DEBUG(("[mouse] Get mouse information"));
+ break;
+
+ case 0xeb: // Read Data (send a packet when in Remote Mode)
+ controller_enQ(0xFA, 1); // ACK
+ // perhaps we should be adding some movement here.
+ mouse_enQ_packet( ((BX_KEY_THIS s.mouse.button_status & 0x0f) | 0x08),
+ 0x00, 0x00 ); // bit3 of first byte always set
+ //assumed we really aren't in polling mode, a rather odd assumption.
+ BX_ERROR(("[mouse] Warning: Read Data command partially supported."));
+ break;
+
+ default:
+ //FEh Resend
+ BX_PANIC(("MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+ }
+ }
+}
+
+void
+bx_keyb_c::create_mouse_packet(bool force_enq) {
+ Bit8u b1, b2, b3;
+
+ // BX_DEBUG("Calling create_mouse_packet: force_enq=%d\n",force_enq);
+
+ if(BX_KEY_THIS s.mouse_internal_buffer.num_elements && !force_enq)
+ return;
+
+ // BX_DEBUG("Got to first milestone: force_enq=%d\n",force_enq);
+
+ Bit16s delta_x = BX_KEY_THIS s.mouse.delayed_dx;
+ Bit16s delta_y = BX_KEY_THIS s.mouse.delayed_dy;
+ Bit8u button_state=BX_KEY_THIS s.mouse.button_status | 0x08;
+
+ if(!force_enq && !delta_x && !delta_y) {
+ return;
+ }
+
+ // BX_DEBUG("Got to second milestone: delta_x=%d, delta_y=%d\n",delta_x,delta_y);
+
+ if(delta_x>254) delta_x=254;
+ if(delta_x<-254) delta_x=-254;
+ if(delta_y>254) delta_y=254;
+ if(delta_y<-254) delta_y=-254;
+
+ b1 = (button_state & 0x0f) | 0x08; // bit3 always set
+
+ if ( (delta_x>=0) && (delta_x<=255) ) {
+ b2 = (Bit8u) delta_x;
+ BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
+ }
+ else if ( delta_x > 255 ) {
+ b2 = (Bit8u) 0xff;
+ BX_KEY_THIS s.mouse.delayed_dx-=255;
+ }
+ else if ( delta_x >= -256 ) {
+ b2 = (Bit8u) delta_x;
+ b1 |= 0x10;
+ BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
+ }
+ else {
+ b2 = (Bit8u) 0x00;
+ b1 |= 0x10;
+ BX_KEY_THIS s.mouse.delayed_dx+=256;
+ }
+
+ if ( (delta_y>=0) && (delta_y<=255) ) {
+ b3 = (Bit8u) delta_y;
+ BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
+ }
+ else if ( delta_y > 255 ) {
+ b3 = (Bit8u) 0xff;
+ BX_KEY_THIS s.mouse.delayed_dy-=255;
+ }
+ else if ( delta_y >= -256 ) {
+ b3 = (Bit8u) delta_y;
+ b1 |= 0x20;
+ BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
+ }
+ else {
+ b3 = (Bit8u) 0x00;
+ b1 |= 0x20;
+ BX_KEY_THIS s.mouse.delayed_dy+=256;
+ }
+ mouse_enQ_packet(b1, b2, b3);
+}
+
+
+void
+bx_keyb_c::mouse_enabled_changed(bool enabled) {
+ if(s.mouse.delayed_dx || BX_KEY_THIS s.mouse.delayed_dy) {
+ create_mouse_packet(1);
+ }
+ s.mouse.delayed_dx=0;
+ s.mouse.delayed_dy=0;
+ BX_DEBUG(("Keyboard mouse disable called."));
+}
+
+ void
+bx_keyb_c::mouse_motion(int delta_x, int delta_y, unsigned button_state)
+{
+ bool force_enq=0;
+
+ // If mouse events are disabled on the GUI headerbar, don't
+ // generate any mouse data
+ if (bx_options.Omouse_enabled->get () == 0)
+ return;
+
+
+ // don't generate interrupts if we are in remote mode.
+ if ( BX_KEY_THIS s.mouse.mode == MOUSE_MODE_REMOTE)
+ // is there any point in doing any work if we don't act on the result
+ // so go home.
+ return;
+
+
+ // Note: enable only applies in STREAM MODE.
+ if ( BX_KEY_THIS s.mouse.enable==0 )
+ return;
+
+ // scale down the motion
+ if ( (delta_x < -1) || (delta_x > 1) )
+ delta_x /= 2;
+ if ( (delta_y < -1) || (delta_y > 1) )
+ delta_y /= 2;
+
+#ifdef VERBOSE_KBD_DEBUG
+ if (delta_x != 0 || delta_y != 0)
+ BX_DEBUG(("[mouse] Dx=%d Dy=%d", delta_x, delta_y));
+#endif /* ifdef VERBOSE_KBD_DEBUG */
+
+ if( (delta_x==0) && (delta_y==0) && (BX_KEY_THIS s.mouse.button_status == (button_state & 0x3) ) ) {
+ BX_DEBUG(("Ignoring useless mouse_motion call:\n"));
+ BX_DEBUG(("This should be fixed in the gui code.\n"));
+ return;
+ }
+
+ if(BX_KEY_THIS s.mouse.button_status != (button_state & 0x3)) {
+ force_enq=1;
+ }
+
+ BX_KEY_THIS s.mouse.button_status = button_state & 0x3;
+
+ if(delta_x>255) delta_x=255;
+ if(delta_y>255) delta_y=255;
+ if(delta_x<-256) delta_x=-256;
+ if(delta_y<-256) delta_y=-256;
+
+ BX_KEY_THIS s.mouse.delayed_dx+=delta_x;
+ BX_KEY_THIS s.mouse.delayed_dy+=delta_y;
+
+ if((BX_KEY_THIS s.mouse.delayed_dx>255)||
+ (BX_KEY_THIS s.mouse.delayed_dx<-256)||
+ (BX_KEY_THIS s.mouse.delayed_dy>255)||
+ (BX_KEY_THIS s.mouse.delayed_dy<-256)) {
+ force_enq=1;
+ }
+
+ create_mouse_packet(force_enq);
+}
+
+
+ int
+bx_keyb_c::SaveState( class state_file *fd )
+{
+ fd->write_check ("keyboard start");
+ fd->write (&BX_KEY_THIS s, sizeof (BX_KEY_THIS s));
+ fd->write_check ("keyboard end");
+ return(0);
+}
+
+
+ int
+bx_keyb_c::LoadState( class state_file *fd )
+{
+ fd->read_check ("keyboard start");
+ fd->read (&BX_KEY_THIS s, sizeof (BX_KEY_THIS s));
+ fd->read_check ("keyboard end");
+ return(0);
+}
+
diff --git a/tools/ioemu/iodev/keyboard.h b/tools/ioemu/iodev/keyboard.h
new file mode 100644
index 0000000000..24d9ccfdf0
--- /dev/null
+++ b/tools/ioemu/iodev/keyboard.h
@@ -0,0 +1,234 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keyboard.h,v 1.22 2003/07/13 19:51:21 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#ifndef _PCKEY_H
+#define _PCKEY_H
+
+
+#define BX_KBD_ELEMENTS 16
+#define BX_MOUSE_BUFF_SIZE 48
+
+// 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
+#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(void);
+ ~bx_keyb_c(void);
+ // 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 mouse_motion(int delta_x, int delta_y, unsigned button_state);
+
+ // update the paste delay based on bx_options.Okeyboard_paste_delay
+ virtual void paste_delay_changed ();
+ virtual void mouse_enabled_changed(bool enabled);
+
+private:
+ BX_KEY_SMF Bit8u get_kbd_enable(void);
+ BX_KEY_SMF void service_paste_buf ();
+ BX_KEY_SMF void create_mouse_packet(bool force_enq);
+ BX_KEY_SMF void mouse_button(unsigned mouse_state);
+ BX_KEY_SMF int SaveState( class state_file *fd );
+ BX_KEY_SMF int LoadState( class state_file *fd );
+ 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;
+ } kbd_controller;
+
+ struct mouseStruct {
+ 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;
+ } 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 stop_paste; // stop the current paste operation on 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) BX_CPP_AttrRegparmN(3);
+ BX_KEY_SMF void mouse_enQ(Bit8u mouse_data);
+
+ static void timer_handler(void *);
+ void timer(void);
+ int timer_handle;
+ };
+
+
+#endif // #ifndef _PCKEY_H
diff --git a/tools/ioemu/iodev/load32bitOShack.cc b/tools/ioemu/iodev/load32bitOShack.cc
new file mode 100644
index 0000000000..6a0a4904d8
--- /dev/null
+++ b/tools/ioemu/iodev/load32bitOShack.cc
@@ -0,0 +1,322 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: load32bitOShack.cc,v 1.14 2003/08/08 00:05:53 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+#include "bochs.h"
+#define LOG_THIS genlog->
+
+
+
+static void bx_load_linux_hack(void);
+static void bx_load_null_kernel_hack(void);
+static Bit32u bx_load_kernel_image(char *path, Bit32u paddr);
+
+ void
+bx_load32bitOSimagehack(void)
+{
+ // Replay IO from log to initialize IO devices to
+ // a reasonable state needed for the OS. This is done
+ // in lieu of running the 16-bit BIOS to init things,
+ // since we want to test straight 32bit stuff for
+ // freemware.
+
+#ifndef BX_USE_VMX
+ FILE *fp;
+
+ fp = fopen(bx_options.load32bitOSImage.Oiolog->getptr (), "r");
+
+ if (fp == NULL) {
+ BX_PANIC(("could not open IO init file."));
+ }
+
+ while (1) {
+ unsigned len, op, port, val;
+ int ret;
+ ret = fscanf(fp, "%u %u %x %x\n",
+ &len, &op, &port, &val);
+ if (ret != 4) {
+ BX_PANIC(("could not open IO init file."));
+ }
+ if (op == 0) {
+ // read
+ (void) bx_devices.inp(port, len);
+ }
+ else if (op == 1) {
+ // write
+ bx_devices.outp(port, val, len);
+ }
+ else {
+ BX_PANIC(("bad IO op in init filen"));
+ }
+ if (feof(fp)) break;
+ }
+#endif
+
+ // Invoke proper hack depending on which OS image we're loading
+ switch (bx_options.load32bitOSImage.OwhichOS->get ()) {
+ case Load32bitOSLinux:
+ bx_load_linux_hack();
+ break;
+ case Load32bitOSNullKernel:
+ bx_load_null_kernel_hack();
+ break;
+ default:
+ BX_PANIC(("load32bitOSImage: OS not recognized"));
+ }
+}
+
+struct gdt_entry
+{
+ Bit32u low;
+ Bit32u high;
+};
+struct linux_setup_params
+{
+ /* 0x000 */ Bit8u orig_x;
+ /* 0x001 */ Bit8u orig_y;
+ /* 0x002 */ Bit16u memory_size_std;
+ /* 0x004 */ Bit16u orig_video_page;
+ /* 0x006 */ Bit8u orig_video_mode;
+ /* 0x007 */ Bit8u orig_video_cols;
+ /* 0x008 */ Bit16u unused1;
+ /* 0x00a */ Bit16u orig_video_ega_bx;
+ /* 0x00c */ Bit16u unused2;
+ /* 0x00e */ Bit8u orig_video_lines;
+ /* 0x00f */ Bit8u orig_video_isVGA;
+ /* 0x010 */ Bit16u orig_video_points;
+ /* 0x012 */ Bit8u pad1[0x40 - 0x12];
+ /* 0x040 */ Bit8u apm_info[0x80 - 0x40];
+ /* 0x080 */ Bit8u hd0_info[16];
+ /* 0x090 */ Bit8u hd1_info[16];
+ /* 0x0a0 */ Bit8u pad2[0x1e0 - 0xa0];
+ /* 0x1e0 */ Bit32u memory_size_ext;
+ /* 0x1e4 */ Bit8u pad3[0x1f1 - 0x1e4];
+ /* 0x1f1 */ Bit8u setup_sects;
+ /* 0x1f2 */ Bit16u mount_root_rdonly;
+ /* 0x1f4 */ Bit16u sys_size;
+ /* 0x1f6 */ Bit16u swap_dev;
+ /* 0x1f8 */ Bit16u ramdisk_flags;
+ /* 0x1fa */ Bit16u vga_mode;
+ /* 0x1fc */ Bit16u orig_root_dev;
+ /* 0x1fe */ Bit16u bootsect_magic;
+ /* 0x200 */ Bit8u pad4[0x210 - 0x200];
+ /* 0x210 */ Bit32u loader_type;
+ /* 0x214 */ Bit32u kernel_start;
+ /* 0x218 */ Bit32u initrd_start;
+ /* 0x21c */ Bit32u initrd_size;
+ /* 0x220 */ Bit8u pad5[0x400 - 0x220];
+ /* 0x400 */ struct gdt_entry gdt[128];
+ /* 0x800 */ Bit8u commandline[2048];
+};
+
+ static void
+bx_load_linux_setup_params( Bit32u initrd_start, Bit32u initrd_size )
+{
+ BX_MEM_C *mem = BX_MEM(0);
+ struct linux_setup_params *params =
+ (struct linux_setup_params *) &mem->vector[0x00090000];
+
+ memset( params, '\0', sizeof(*params) );
+
+ /* Video settings (standard VGA) */
+ params->orig_x = 0;
+ params->orig_y = 0;
+ params->orig_video_page = 0;
+ params->orig_video_mode = 3;
+ params->orig_video_cols = 80;
+ params->orig_video_lines = 25;
+ params->orig_video_points = 16;
+ params->orig_video_isVGA = 1;
+ params->orig_video_ega_bx = 3;
+
+ /* Memory size (total mem - 1MB, in KB) */
+ params->memory_size_ext = (mem->megabytes - 1) * 1024;
+
+ /* Boot parameters */
+ params->loader_type = 1;
+ params->bootsect_magic = 0xaa55;
+ params->mount_root_rdonly = 0;
+ params->orig_root_dev = 0x0100;
+ params->initrd_start = initrd_start;
+ params->initrd_size = initrd_size;
+
+ /* Initial GDT */
+ params->gdt[2].high = 0x00cf9a00;
+ params->gdt[2].low = 0x0000ffff;
+ params->gdt[3].high = 0x00cf9200;
+ params->gdt[3].low = 0x0000ffff;
+}
+
+ void
+bx_load_linux_hack(void)
+{
+#ifndef BX_USE_VMX
+ Bit32u initrd_start = 0, initrd_size = 0;
+
+ // The RESET function will have been called first.
+ // Set CPU and memory features which are assumed at this point.
+
+ // Load Linux kernel image
+ bx_load_kernel_image( bx_options.load32bitOSImage.Opath->getptr (), 0x100000 );
+
+ // Load initial ramdisk image if requested
+ if ( bx_options.load32bitOSImage.Oinitrd->getptr () )
+ {
+ initrd_start = 0x00800000; /* FIXME: load at top of memory */
+ initrd_size = bx_load_kernel_image( bx_options.load32bitOSImage.Oinitrd->getptr (), initrd_start );
+ }
+
+ // Setup Linux startup parameters buffer
+ bx_load_linux_setup_params( initrd_start, initrd_size );
+#endif
+
+ // Enable A20 line
+ BX_SET_ENABLE_A20( 1 );
+
+ // Setup PICs the way Linux likes it
+ BX_OUTP( 0x20, 0x11, 1 );
+ BX_OUTP( 0xA0, 0x11, 1 );
+ BX_OUTP( 0x21, 0x20, 1 );
+ BX_OUTP( 0xA1, 0x28, 1 );
+ BX_OUTP( 0x21, 0x04, 1 );
+ BX_OUTP( 0xA1, 0x02, 1 );
+ BX_OUTP( 0x21, 0x01, 1 );
+ BX_OUTP( 0xA1, 0x01, 1 );
+ BX_OUTP( 0x21, 0xFF, 1 );
+ BX_OUTP( 0xA1, 0xFB, 1 );
+
+#ifndef BX_USE_VMX
+ // Disable interrupts and NMIs
+ BX_CPU(0)->clear_IF ();
+#endif
+
+ BX_OUTP( 0x70, 0x80, 1 );
+
+#ifndef BX_USE_VMX
+ // Enter protected mode
+ // Fixed by george (kyriazis at nvidia.com)
+ // BX_CPU(0)->cr0.pe = 1;
+ // BX_CPU(0)->cr0.val32 |= 0x01;
+
+ BX_CPU(0)->SetCR0(BX_CPU(0)->cr0.val32 | 0x01);
+
+ // load esi with real_mode
+ BX_CPU(0)->gen_reg[BX_32BIT_REG_ESI].dword.erx = 0x90000;
+
+ // Set up initial GDT
+ BX_CPU(0)->gdtr.limit = 0x400;
+ BX_CPU(0)->gdtr.base = 0x00090400;
+
+ // Jump to protected mode entry point
+ BX_CPU(0)->jump_protected( NULL, 0x10, 0x00100000 );
+#endif
+}
+
+ void
+bx_load_null_kernel_hack(void)
+{
+#ifndef BX_USE_VMX
+ // The RESET function will have been called first.
+ // Set CPU and memory features which are assumed at this point.
+
+ bx_load_kernel_image(bx_options.load32bitOSImage.Opath->getptr (), 0x100000);
+
+ // EIP deltas
+ BX_CPU(0)->prev_eip =
+ BX_CPU(0)->dword.eip = 0x00100000;
+
+ // CS deltas
+ BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.base = 0x00000000;
+ BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFFF;
+ BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF;
+ BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // page gran
+ BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1; // 32bit
+
+ // DS deltas
+ BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.base = 0x00000000;
+ BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit = 0xFFFFF;
+ BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled = 0xFFFFFFFF;
+ BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.g = 1; // page gran
+ BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.d_b = 1; // 32bit
+
+ // CR0 deltas
+ BX_CPU(0)->cr0.pe = 1; // protected mode
+#endif // BX_USE_VMX
+}
+
+ Bit32u
+bx_load_kernel_image(char *path, Bit32u paddr)
+{
+ struct stat stat_buf;
+ int fd, ret;
+ unsigned long size, offset;
+ Bit32u page_size;
+
+ // read in ROM BIOS image file
+ fd = open(path, O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0) {
+ BX_INFO(( "load_kernel_image: couldn't open image file '%s'.", path ));
+ BX_EXIT(1);
+ }
+ ret = fstat(fd, &stat_buf);
+ if (ret) {
+ BX_INFO(( "load_kernel_image: couldn't stat image file '%s'.", path ));
+ BX_EXIT(1);
+ }
+
+ size = stat_buf.st_size;
+ page_size = ((Bit32u)size + 0xfff) & ~0xfff;
+
+ BX_MEM_C *mem = BX_MEM(0);
+ if ( (paddr + size) > mem->len ) {
+ BX_INFO(( "load_kernel_image: address range > physical memsize!" ));
+ BX_EXIT(1);
+ }
+
+ offset = 0;
+ while (size > 0) {
+ ret = read(fd, (bx_ptr_t) &mem->vector[paddr + offset], size);
+ if (ret <= 0) {
+ BX_INFO(( "load_kernel_image: read failed on image" ));
+ BX_EXIT(1);
+ }
+ size -= ret;
+ offset += ret;
+ }
+ close(fd);
+ BX_INFO(( "#(%u) load_kernel_image: '%s', size=%u read into memory at %08x",
+ BX_SIM_ID, path,
+ (unsigned) stat_buf.st_size,
+ (unsigned) paddr ));
+
+ return page_size;
+}
diff --git a/tools/ioemu/iodev/logio.cc b/tools/ioemu/iodev/logio.cc
new file mode 100644
index 0000000000..2b79719a2c
--- /dev/null
+++ b/tools/ioemu/iodev/logio.cc
@@ -0,0 +1,631 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: logio.cc,v 1.42 2003/08/24 10:30:07 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#include <assert.h>
+#include "state_file.h"
+
+#if BX_WITH_CARBON
+#include <Carbon/Carbon.h>
+#endif
+
+// Just for the iofunctions
+
+
+int Allocio=0;
+
+void
+iofunctions::flush(void) {
+ if(logfd && magic == MAGIC_LOGNUM) {
+ fflush(logfd);
+ }
+}
+
+void
+iofunctions::init(void) {
+ // iofunctions methods must not be called before this magic
+ // number is set.
+ magic=MAGIC_LOGNUM;
+
+ // sets the default logprefix
+ strcpy(logprefix,"%t%e%d");
+ n_logfn = 0;
+ init_log(stderr);
+ log = new logfunc_t(this);
+ log->put("IO");
+ log->settype(IOLOG);
+ log->ldebug ("Init(log file: '%s').",logfn);
+}
+
+void
+iofunctions::add_logfn (logfunc_t *fn)
+{
+ assert (n_logfn < MAX_LOGFNS);
+ logfn_list[n_logfn++] = fn;
+}
+
+void
+iofunctions::set_log_action (int loglevel, int action)
+{
+ for (int i=0; i<n_logfn; i++)
+ logfn_list[i]->setonoff(loglevel, action);
+}
+
+void
+iofunctions::init_log(const char *fn)
+{
+ assert (magic==MAGIC_LOGNUM);
+ // use newfd/newfn so that we can log the message to the OLD log
+ // file descriptor.
+ FILE *newfd = stderr;
+ char *newfn = "/dev/stderr";
+ if( strcmp( fn, "-" ) != 0 ) {
+ newfd = fopen(fn, "w");
+ if(newfd != NULL) {
+ newfn = strdup(fn);
+ log->ldebug ("Opened log file '%s'.", fn );
+ } else {
+ // in constructor, genlog might not exist yet, so do it the safe way.
+ log->error("Couldn't open log file: %s, using stderr instead", fn);
+ newfd = stderr;
+ }
+ }
+ logfd = newfd;
+ logfn = newfn;
+}
+
+void
+iofunctions::init_log(FILE *fs)
+{
+ assert (magic==MAGIC_LOGNUM);
+ logfd = fs;
+
+ if(fs == stderr) {
+ logfn = "/dev/stderr";
+ } else if(fs == stdout) {
+ logfn = "/dev/stdout";
+ } else {
+ logfn = "(unknown)";
+ }
+
+}
+
+void
+iofunctions::init_log(int fd)
+{
+ assert (magic==MAGIC_LOGNUM);
+ FILE *tmpfd;
+ if( (tmpfd = fdopen(fd,"w")) == NULL ) {
+ log->panic("Couldn't open fd %d as a stream for writing", fd);
+ return;
+ }
+
+ init_log(tmpfd);
+ return;
+};
+
+// all other functions may use genlog safely.
+#define LOG_THIS genlog->
+
+// This converts the option string to a printf style string with the following args:
+// 1. timer, 2. event, 3. cpu0 eip, 4. device
+void
+iofunctions::set_log_prefix(const char* prefix) {
+
+ strcpy(logprefix,prefix);
+}
+
+// iofunctions::out( class, level, prefix, fmt, ap)
+// DO NOT nest out() from ::info() and the like.
+// fmt and ap retained for direct printinf from iofunctions only!
+
+void
+iofunctions::out(int f, int l, const char *prefix, const char *fmt, va_list ap)
+{
+ char c=' ', *s;
+ assert (magic==MAGIC_LOGNUM);
+ assert (this != NULL);
+ assert (logfd != NULL);
+
+ //if( showtick )
+ // fprintf(logfd, "%011lld", bx_pc_system.time_ticks());
+
+ switch(l) {
+ case LOGLEV_INFO: c='i'; break;
+ case LOGLEV_PANIC: c='p'; break;
+ case LOGLEV_PASS: c='s'; break;
+ case LOGLEV_ERROR: c='e'; break;
+ case LOGLEV_DEBUG: c='d'; break;
+ default: break;
+ }
+ //fprintf(logfd, "-%c",c);
+
+ //if(prefix != NULL)
+ // fprintf(logfd, "%s ", prefix);
+
+ s=logprefix;
+ while(*s) {
+ switch(*s) {
+ case '%':
+ if(*(s+1))s++;
+ else break;
+ switch(*s) {
+ case 'd':
+ fprintf(logfd, "%s", prefix==NULL?"":prefix);
+ break;
+ case 't':
+ fprintf(logfd, "%011lld", bx_pc_system.time_ticks());
+ break;
+#ifndef BX_USE_VMX
+ case 'i':
+ fprintf(logfd, "%08x", BX_CPU(0)==NULL?0:BX_CPU(0)->dword.eip);
+ break;
+#endif
+ case 'e':
+ fprintf(logfd, "%c", c);
+ break;
+ case '%':
+ fprintf(logfd,"%%");
+ break;
+ default:
+ fprintf(logfd,"%%%c",*s);
+ }
+ break;
+ default :
+ fprintf(logfd,"%c",*s);
+ }
+ s++;
+ }
+
+ fprintf(logfd," ");
+
+ if(l==LOGLEV_PANIC)
+ fprintf(logfd, ">>PANIC<< ");
+ if(l==LOGLEV_PASS)
+ fprintf(logfd, ">>PASS<< ");
+
+ vfprintf(logfd, fmt, ap);
+ fprintf(logfd, "\n");
+ fflush(logfd);
+
+ return;
+}
+
+iofunctions::iofunctions(FILE *fs)
+{
+ init();
+ init_log(fs);
+}
+
+iofunctions::iofunctions(const char *fn)
+{
+ init();
+ init_log(fn);
+}
+
+iofunctions::iofunctions(int fd)
+{
+ init();
+ init_log(fd);
+}
+
+iofunctions::iofunctions(void)
+{
+ this->init();
+}
+
+iofunctions::~iofunctions(void)
+{
+ // flush before erasing magic number, or flush does nothing.
+ this->flush();
+ this->magic=0;
+}
+
+#define LOG_THIS genlog->
+
+int logfunctions::default_onoff[N_LOGLEV] = {
+ ACT_IGNORE, // ignore debug
+ ACT_REPORT, // report info
+ ACT_REPORT, // report error
+#if BX_WITH_WX
+ ACT_ASK, // on panic, ask user what to do
+#else
+ ACT_FATAL, // on panic, quit
+#endif
+ ACT_FATAL
+};
+
+logfunctions::logfunctions(void)
+{
+ prefix = NULL;
+ put(" ");
+ settype(GENLOG);
+ if (io == NULL && Allocio == 0) {
+ Allocio = 1;
+ io = new iofunc_t(stderr);
+ }
+ setio(io);
+ // BUG: unfortunately this can be called before the bochsrc is read,
+ // which means that the bochsrc has no effect on the actions.
+ for (int i=0; i<N_LOGLEV; i++)
+ onoff[i] = get_default_action(i);
+}
+
+logfunctions::logfunctions(iofunc_t *iofunc)
+{
+ prefix = NULL;
+ put(" ");
+ settype(GENLOG);
+ setio(iofunc);
+ // BUG: unfortunately this can be called before the bochsrc is read,
+ // which means that the bochsrc has no effect on the actions.
+ for (int i=0; i<N_LOGLEV; i++)
+ onoff[i] = get_default_action(i);
+}
+
+logfunctions::~logfunctions(void)
+{
+ if ( this->prefix )
+ {
+ free(this->prefix);
+ this->prefix = NULL;
+ }
+}
+
+void
+logfunctions::setio(iofunc_t *i)
+{
+ // add pointer to iofunction object to use
+ this->logio = i;
+ // give iofunction a pointer to me
+ i->add_logfn (this);
+}
+
+void
+logfunctions::put(char *p)
+{
+ char *tmpbuf;
+ tmpbuf=strdup("[ ]");// if we ever have more than 32 chars,
+ // we need to rethink this
+
+ if ( tmpbuf == NULL)
+ {
+ return ; /* allocation not successful */
+ }
+ if ( this->prefix != NULL )
+ {
+ free(this->prefix); /* free previously allocated memory */
+ this->prefix = NULL;
+ }
+ int len=strlen(p);
+ for(int i=1;i<len+1;i++) {
+ tmpbuf[i]=p[i-1];
+ }
+
+ switch(len) {
+ case 1: tmpbuf[2]=' ';
+ case 2: tmpbuf[3]=' ';
+ case 3: tmpbuf[4]=' ';
+ case 4: tmpbuf[5]=' ';
+ default: tmpbuf[6]=']'; tmpbuf[7]='\0'; break;
+ }
+
+ this->prefix=tmpbuf;
+}
+
+void
+logfunctions::settype(int t)
+{
+ type=t;
+}
+
+void
+logfunctions::info(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (this != NULL);
+ assert (this->logio != NULL);
+
+ if(!onoff[LOGLEV_INFO]) return;
+
+ va_start(ap, fmt);
+ this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap);
+ if (onoff[LOGLEV_INFO] == ACT_ASK)
+ ask (LOGLEV_INFO, this->prefix, fmt, ap);
+ if (onoff[LOGLEV_INFO] == ACT_FATAL)
+ fatal (this->prefix, fmt, ap, 1);
+ va_end(ap);
+
+}
+
+void
+logfunctions::error(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (this != NULL);
+ assert (this->logio != NULL);
+
+ if(!onoff[LOGLEV_ERROR]) return;
+
+ va_start(ap, fmt);
+ this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap);
+ if (onoff[LOGLEV_ERROR] == ACT_ASK)
+ ask (LOGLEV_ERROR, this->prefix, fmt, ap);
+ if (onoff[LOGLEV_ERROR] == ACT_FATAL)
+ fatal (this->prefix, fmt, ap, 1);
+ va_end(ap);
+}
+
+void
+logfunctions::panic(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (this != NULL);
+ assert (this->logio != NULL);
+
+ // Special case for panics since they are so important. Always print
+ // the panic to the log, no matter what the log action says.
+ //if(!onoff[LOGLEV_PANIC]) return;
+
+ va_start(ap, fmt);
+ this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap);
+
+ // This fixes a funny bug on linuxppc where va_list is no pointer but a struct
+ va_end(ap);
+ va_start(ap, fmt);
+
+ if (onoff[LOGLEV_PANIC] == ACT_ASK)
+ ask (LOGLEV_PANIC, this->prefix, fmt, ap);
+ if (onoff[LOGLEV_PANIC] == ACT_FATAL)
+ fatal (this->prefix, fmt, ap, 1);
+ va_end(ap);
+}
+
+void
+logfunctions::pass(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (this != NULL);
+ assert (this->logio != NULL);
+
+ // Special case for panics since they are so important. Always print
+ // the panic to the log, no matter what the log action says.
+ //if(!onoff[LOGLEV_PASS]) return;
+
+ va_start(ap, fmt);
+ this->logio->out(this->type,LOGLEV_PASS,this->prefix, fmt, ap);
+
+ // This fixes a funny bug on linuxppc where va_list is no pointer but a struct
+ va_end(ap);
+ va_start(ap, fmt);
+
+ if (onoff[LOGLEV_PASS] == ACT_ASK)
+ ask (LOGLEV_PASS, this->prefix, fmt, ap);
+ if (onoff[LOGLEV_PASS] == ACT_FATAL)
+ fatal (this->prefix, fmt, ap, 101);
+ va_end(ap);
+}
+
+void
+logfunctions::ldebug(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert (this != NULL);
+ assert (this->logio != NULL);
+
+ if(!onoff[LOGLEV_DEBUG]) return;
+
+ va_start(ap, fmt);
+ this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap);
+ if (onoff[LOGLEV_DEBUG] == ACT_ASK)
+ ask (LOGLEV_DEBUG, this->prefix, fmt, ap);
+ if (onoff[LOGLEV_DEBUG] == ACT_FATAL)
+ fatal (this->prefix, fmt, ap, 1);
+ va_end(ap);
+}
+
+void
+logfunctions::ask (int level, const char *prefix, const char *fmt, va_list ap)
+{
+ // Guard against reentry on ask() function. The danger is that some
+ // function that's called within ask() could trigger another
+ // BX_PANIC that could call ask() again, leading to infinite
+ // recursion and infinite asks.
+ static char in_ask_already = 0;
+ char buf1[1024];
+ if (in_ask_already) {
+ fprintf (stderr, "logfunctions::ask() should not reenter!!\n");
+ return;
+ }
+ in_ask_already = 1;
+ vsprintf (buf1, fmt, ap);
+ // FIXME: facility set to 0 because it's unknown.
+
+ // update vga screen. This is useful because sometimes useful messages
+ // are printed on the screen just before a panic. It's also potentially
+ // dangerous if this function calls ask again... That's why I added
+ // the reentry check above.
+ if (SIM->get_init_done()) DEV_vga_refresh();
+
+#if !BX_EXTERNAL_DEBUGGER
+ // ensure the text screen is showing
+ SIM->set_display_mode (DISP_MODE_CONFIG);
+ int val = SIM->log_msg (prefix, level, buf1);
+ switch (val)
+ {
+ case BX_LOG_ASK_CHOICE_CONTINUE:
+ break;
+ case BX_LOG_ASK_CHOICE_CONTINUE_ALWAYS:
+ // user said continue, and don't "ask" for this facility again.
+ setonoff (level, ACT_REPORT);
+ break;
+ case BX_LOG_ASK_CHOICE_DIE:
+ bx_user_quit = 1;
+ in_ask_already = 0; // because fatal will longjmp out
+ fatal (prefix, fmt, ap, 1);
+ // should never get here
+ BX_PANIC (("in ask(), fatal() should never return!"));
+ break;
+ case BX_LOG_ASK_CHOICE_DUMP_CORE:
+ fprintf (stderr, "User chose to dump core...\n");
+#if BX_HAVE_ABORT
+ abort ();
+#else
+ // do something highly illegal that should kill the process.
+ // Hey, this is fun!
+ {
+ char *crashptr = (char *)0; char c = *crashptr;
+ }
+ fprintf (stderr, "Sorry, I couldn't find your abort() function. Exiting.");
+ exit (0);
+#endif
+#if BX_DEBUGGER
+ case BX_LOG_ASK_CHOICE_ENTER_DEBUG:
+ // user chose debugger. To "drop into the debugger" we just set the
+ // interrupt_requested bit and continue execution. Before the next
+ // instruction, it should notice the user interrupt and return to
+ // the debugger.
+ bx_guard.interrupt_requested = 1;
+ break;
+#endif
+ default:
+ // this happens if panics happen before the callback is initialized
+ // in gui/control.cc.
+ fprintf (stderr, "WARNING: log_msg returned unexpected value %d\n", val);
+ }
+#else
+ // external debugger ask code goes here
+#endif
+ // return to simulation mode
+ SIM->set_display_mode (DISP_MODE_SIM);
+ in_ask_already = 0;
+}
+
+#if BX_WITH_CARBON
+/* Panic button to display fatal errors.
+ Completely self contained, can't rely on carbon.cc being available */
+static void carbonFatalDialog(const char *error, const char *exposition)
+{
+ DialogRef alertDialog;
+ CFStringRef cfError;
+ CFStringRef cfExposition;
+ DialogItemIndex index;
+ AlertStdCFStringAlertParamRec alertParam = {0};
+
+ // Init libraries
+ InitCursor();
+ // Assemble dialog
+ cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII);
+ if(exposition != NULL)
+ {
+ cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII);
+ }
+ else { cfExposition = NULL; }
+ alertParam.version = kStdCFStringAlertVersionOne;
+ alertParam.defaultText = CFSTR("Quit");
+ alertParam.position = kWindowDefaultPosition;
+ alertParam.defaultButton = kAlertStdAlertOKButton;
+ // Display Dialog
+ CreateStandardAlert(
+ kAlertStopAlert,
+ cfError,
+ cfExposition, /* can be NULL */
+ &alertParam, /* can be NULL */
+ &alertDialog);
+ RunStandardAlert( alertDialog, NULL, &index);
+ // Cleanup
+ CFRelease( cfError );
+ if( cfExposition != NULL ) { CFRelease( cfExposition ); }
+}
+#endif
+
+void
+logfunctions::fatal (const char *prefix, const char *fmt, va_list ap, int exit_status)
+{
+ bx_atexit();
+#if BX_WITH_CARBON
+ if(!isatty(STDIN_FILENO) && !SIM->get_init_done())
+ {
+ char buf1[1024];
+ char buf2[1024];
+ vsprintf (buf1, fmt, ap);
+ sprintf (buf2, "Bochs startup error\n%s", buf1);
+ carbonFatalDialog(buf2,
+ "For more information, try running Bochs within Terminal by clicking on \"bochs.scpt\".");
+ }
+#endif
+#if !BX_WITH_WX
+ static char *divider = "========================================================================";
+ fprintf (stderr, "%s\n", divider);
+ fprintf (stderr, "Bochs is exiting with the following message:\n");
+ fprintf (stderr, "%s ", prefix);
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n%s\n", divider);
+#endif
+#if 0 && defined(WIN32)
+#error disabled because it is not working yet!
+ // wait for a keypress before quitting. Depending on how bochs is
+ // installed, the console window can disappear before the user has
+ // a chance to read the final message.
+ fprintf (stderr, "\n\nPress Enter to exit...\n");
+ char buf[8];
+ fgets (buf, 8, stdin);
+#endif
+#if !BX_DEBUGGER
+ BX_EXIT(exit_status);
+#else
+ static bx_bool dbg_exit_called = 0;
+ if (dbg_exit_called == 0) {
+ dbg_exit_called = 1;
+ bx_dbg_exit(exit_status);
+ }
+#endif
+ // not safe to use BX_* log functions in here.
+ fprintf (stderr, "fatal() should never return, but it just did\n");
+}
+
+iofunc_t *io = NULL;
+logfunc_t *genlog = NULL;
+
+void bx_center_print (FILE *file, char *line, int maxwidth)
+{
+ int imax;
+ int len = strlen(line);
+ if (len > maxwidth)
+ BX_PANIC (("bx_center_print: line is too long: '%s'", line));
+ imax = (maxwidth - len) >> 1;
+ for (int i=0; i<imax; i++) fputc (' ', file);
+ fputs (line, file);
+}
+
+
diff --git a/tools/ioemu/iodev/main.cc b/tools/ioemu/iodev/main.cc
new file mode 100644
index 0000000000..c784adb555
--- /dev/null
+++ b/tools/ioemu/iodev/main.cc
@@ -0,0 +1,4067 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: main.cc,v 1.256.2.3 2004/02/08 14:39:50 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+// Copyright (C) 2004 Arun Sharma <arun.sharma@intel.com>
+// Copyright (C) 2004 Intel Corp
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "bochs.h"
+#include <assert.h>
+#include "state_file.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+extern "C" {
+#include <signal.h>
+}
+
+#if BX_GUI_SIGHANDLER
+bx_bool bx_gui_sighandler = 0;
+#endif
+
+// single processor simulation, so there's one of everything
+BOCHSAPI BX_CPU_C bx_cpu;
+BOCHSAPI BX_MEM_C bx_mem;
+
+int xc_handle;
+int bochsrc_include_count = 0;
+
+// some prototypes from iodev/
+// I want to stay away from including iodev/iodev.h here
+Bit32u bx_unmapped_io_read_handler(Bit32u address, unsigned io_len);
+void bx_unmapped_io_write_handler(Bit32u address, Bit32u value,
+ unsigned io_len);
+void bx_close_harddrive(void);
+
+
+void bx_init_bx_dbg (void);
+static char *divider = "========================================================================";
+static logfunctions thePluginLog;
+logfunctions *pluginlog = &thePluginLog;
+
+bx_startup_flags_t bx_startup_flags;
+bx_bool bx_user_quit;
+
+/* typedefs */
+
+#define LOG_THIS genlog->
+
+#if ( BX_PROVIDE_DEVICE_MODELS==1 )
+bx_pc_system_c bx_pc_system;
+class state_file state_stuff("state_file.out", "options");
+#endif
+
+bx_debug_t bx_dbg;
+
+bx_options_t bx_options; // initialized in bx_init_options()
+char *bochsrc_filename = NULL;
+
+static Bit32s parse_line_unformatted(char *context, char *line);
+static Bit32s parse_line_formatted(char *context, int num_params, char *params[]);
+static int parse_bochsrc(char *rcfile);
+
+static Bit64s
+bx_param_handler (bx_param_c *param, int set, Bit64s val)
+{
+ bx_id id = param->get_id ();
+ switch (id) {
+ case BXP_VGA_UPDATE_INTERVAL:
+ // if after init, notify the vga device to change its timer.
+ if (set && SIM->get_init_done ())
+ DEV_vga_set_update_interval (val);
+ break;
+ case BXP_MOUSE_ENABLED:
+ // if after init, notify the GUI
+ if (set && SIM->get_init_done ()) {
+ bx_gui->mouse_enabled_changed (val!=0);
+ DEV_mouse_enabled_changed (val!=0);
+ }
+ break;
+ case BXP_NE2K_PRESENT:
+ if (set) {
+ int enable = (val != 0);
+ SIM->get_param (BXP_NE2K_IOADDR)->set_enabled (enable);
+ SIM->get_param (BXP_NE2K_IRQ)->set_enabled (enable);
+ SIM->get_param (BXP_NE2K_MACADDR)->set_enabled (enable);
+ SIM->get_param (BXP_NE2K_ETHMOD)->set_enabled (enable);
+ SIM->get_param (BXP_NE2K_ETHDEV)->set_enabled (enable);
+ SIM->get_param (BXP_NE2K_SCRIPT)->set_enabled (enable);
+ }
+ break;
+ case BXP_LOAD32BITOS_WHICH:
+ if (set) {
+ int enable = (val != Load32bitOSNone);
+ SIM->get_param (BXP_LOAD32BITOS_PATH)->set_enabled (enable);
+ SIM->get_param (BXP_LOAD32BITOS_IOLOG)->set_enabled (enable);
+ SIM->get_param (BXP_LOAD32BITOS_INITRD)->set_enabled (enable);
+ }
+ break;
+ case BXP_ATA0_MASTER_STATUS:
+ case BXP_ATA0_SLAVE_STATUS:
+ case BXP_ATA1_MASTER_STATUS:
+ case BXP_ATA1_SLAVE_STATUS:
+ case BXP_ATA2_MASTER_STATUS:
+ case BXP_ATA2_SLAVE_STATUS:
+ case BXP_ATA3_MASTER_STATUS:
+ case BXP_ATA3_SLAVE_STATUS:
+ if ((set) && (SIM->get_init_done ())) {
+ Bit8u device = id - BXP_ATA0_MASTER_STATUS;
+ Bit32u handle = DEV_hd_get_device_handle (device/2, device%2);
+ DEV_hd_set_cd_media_status(handle, val == BX_INSERTED);
+ bx_gui->update_drive_status_buttons ();
+ }
+ break;
+ case BXP_FLOPPYA_TYPE:
+ if ((set) && (!SIM->get_init_done ())) {
+ bx_options.floppya.Odevtype->set (val);
+ }
+ break;
+ case BXP_FLOPPYA_STATUS:
+ if ((set) && (SIM->get_init_done ())) {
+ DEV_floppy_set_media_status(0, val == BX_INSERTED);
+ bx_gui->update_drive_status_buttons ();
+ }
+ break;
+ case BXP_FLOPPYB_TYPE:
+ if ((set) && (!SIM->get_init_done ())) {
+ bx_options.floppyb.Odevtype->set (val);
+ }
+ break;
+ case BXP_FLOPPYB_STATUS:
+ if ((set) && (SIM->get_init_done ())) {
+ DEV_floppy_set_media_status(1, val == BX_INSERTED);
+ bx_gui->update_drive_status_buttons ();
+ }
+ break;
+ case BXP_KBD_PASTE_DELAY:
+ if ((set) && (SIM->get_init_done ())) {
+ DEV_kbd_paste_delay_changed ();
+ }
+ break;
+
+ case BXP_ATA0_MASTER_MODE:
+ case BXP_ATA0_SLAVE_MODE:
+ case BXP_ATA1_MASTER_MODE:
+ case BXP_ATA1_SLAVE_MODE:
+ case BXP_ATA2_MASTER_MODE:
+ case BXP_ATA2_SLAVE_MODE:
+ case BXP_ATA3_MASTER_MODE:
+ case BXP_ATA3_SLAVE_MODE:
+ if (set) {
+ int device = id - BXP_ATA0_MASTER_MODE;
+ switch (val) {
+ case BX_ATA_MODE_UNDOABLE:
+ case BX_ATA_MODE_VOLATILE:
+ //case BX_ATA_MODE_Z_UNDOABLE:
+ //case BX_ATA_MODE_Z_VOLATILE:
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (1);
+ break;
+ default:
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (0);
+ }
+ }
+ break;
+
+ case BXP_ATA0_MASTER_TYPE:
+ case BXP_ATA0_SLAVE_TYPE:
+ case BXP_ATA1_MASTER_TYPE:
+ case BXP_ATA1_SLAVE_TYPE:
+ case BXP_ATA2_MASTER_TYPE:
+ case BXP_ATA2_SLAVE_TYPE:
+ case BXP_ATA3_MASTER_TYPE:
+ case BXP_ATA3_SLAVE_TYPE:
+ if (set) {
+ int device = id - BXP_ATA0_MASTER_TYPE;
+ switch (val) {
+ case BX_ATA_DEVICE_DISK:
+ SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODE + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1);
+ //SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_runtime_param (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_runtime_param (0);
+ break;
+ case BX_ATA_DEVICE_CDROM:
+ SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODE + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (0);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_runtime_param (1);
+ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_runtime_param (1);
+ break;
+ }
+ }
+ break;
+ default:
+ BX_PANIC (("bx_param_handler called with unknown id %d", id));
+ return -1;
+ }
+ return val;
+}
+
+char *bx_param_string_handler (bx_param_string_c *param, int set, char *val, int maxlen)
+{
+ bx_id id = param->get_id ();
+
+ int empty = 0;
+ if ((strlen(val) < 1) || !strcmp ("none", val)) {
+ empty = 1;
+ val = "none";
+ }
+ switch (id) {
+ case BXP_FLOPPYA_PATH:
+ if (set==1) {
+ if (SIM->get_init_done ()) {
+ if (empty) {
+ DEV_floppy_set_media_status(0, 0);
+ bx_gui->update_drive_status_buttons ();
+ } else {
+ if (!SIM->get_param_num(BXP_FLOPPYA_TYPE)->get_enabled()) {
+ BX_ERROR(("Cannot add a floppy drive at runtime"));
+ bx_options.floppya.Opath->set ("none");
+ }
+ }
+ if ((DEV_floppy_present()) &&
+ (SIM->get_param_num(BXP_FLOPPYA_STATUS)->get () == BX_INSERTED)) {
+ // tell the device model that we removed, then inserted the disk
+ DEV_floppy_set_media_status(0, 0);
+ DEV_floppy_set_media_status(0, 1);
+ }
+ } else {
+ SIM->get_param_num(BXP_FLOPPYA_DEVTYPE)->set_enabled (!empty);
+ SIM->get_param_num(BXP_FLOPPYA_TYPE)->set_enabled (!empty);
+ SIM->get_param_num(BXP_FLOPPYA_STATUS)->set_enabled (!empty);
+ }
+ }
+ break;
+ case BXP_FLOPPYB_PATH:
+ if (set==1) {
+ if (SIM->get_init_done ()) {
+ if (empty) {
+ DEV_floppy_set_media_status(1, 0);
+ bx_gui->update_drive_status_buttons ();
+ } else {
+ if (!SIM->get_param_num(BXP_FLOPPYB_TYPE)->get_enabled ()) {
+ BX_ERROR(("Cannot add a floppy drive at runtime"));
+ bx_options.floppyb.Opath->set ("none");
+ }
+ }
+ if ((DEV_floppy_present()) &&
+ (SIM->get_param_num(BXP_FLOPPYB_STATUS)->get () == BX_INSERTED)) {
+ // tell the device model that we removed, then inserted the disk
+ DEV_floppy_set_media_status(1, 0);
+ DEV_floppy_set_media_status(1, 1);
+ }
+ } else {
+ SIM->get_param_num(BXP_FLOPPYB_DEVTYPE)->set_enabled (!empty);
+ SIM->get_param_num(BXP_FLOPPYB_TYPE)->set_enabled (!empty);
+ SIM->get_param_num(BXP_FLOPPYB_STATUS)->set_enabled (!empty);
+ }
+ }
+ break;
+
+ case BXP_ATA0_MASTER_PATH:
+ case BXP_ATA0_SLAVE_PATH:
+ case BXP_ATA1_MASTER_PATH:
+ case BXP_ATA1_SLAVE_PATH:
+ case BXP_ATA2_MASTER_PATH:
+ case BXP_ATA2_SLAVE_PATH:
+ case BXP_ATA3_MASTER_PATH:
+ case BXP_ATA3_SLAVE_PATH:
+ if (set==1) {
+ if (SIM->get_init_done ()) {
+
+ Bit8u device = id - BXP_ATA0_MASTER_PATH;
+ Bit32u handle = DEV_hd_get_device_handle(device/2, device%2);
+
+ if (empty) {
+ DEV_hd_set_cd_media_status(handle, 0);
+ bx_gui->update_drive_status_buttons ();
+ } else {
+ if (!SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->get ()) {
+ BX_ERROR(("Cannot add a cdrom drive at runtime"));
+ bx_options.atadevice[device/2][device%2].Opresent->set (0);
+ }
+ if (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () != BX_ATA_DEVICE_CDROM) {
+ BX_ERROR(("Device is not a cdrom drive"));
+ bx_options.atadevice[device/2][device%2].Opresent->set (0);
+ }
+ }
+ if (DEV_hd_present() &&
+ (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_STATUS + device))->get () == BX_INSERTED) &&
+ (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () == BX_ATA_DEVICE_CDROM)) {
+ // tell the device model that we removed, then inserted the cd
+ DEV_hd_set_cd_media_status(handle, 0);
+ DEV_hd_set_cd_media_status(handle, 1);
+ }
+ }
+ }
+ break;
+
+ case BXP_SCREENMODE:
+ if (set==1) {
+ BX_INFO (("Screen mode changed to %s", val));
+ }
+ break;
+ default:
+ BX_PANIC (("bx_string_handler called with unexpected parameter %d", param->get_id()));
+ }
+ return val;
+}
+
+static int
+bx_param_enable_handler (bx_param_c *param, int val)
+{
+ bx_id id = param->get_id ();
+ switch (id) {
+ case BXP_ATA0_MASTER_STATUS:
+ case BXP_ATA0_SLAVE_STATUS:
+ case BXP_ATA1_MASTER_STATUS:
+ case BXP_ATA1_SLAVE_STATUS:
+ case BXP_ATA2_MASTER_STATUS:
+ case BXP_ATA2_SLAVE_STATUS:
+ case BXP_ATA3_MASTER_STATUS:
+ case BXP_ATA3_SLAVE_STATUS:
+ if (val != 0) {
+ Bit8u device = id - BXP_ATA0_MASTER_STATUS;
+
+ switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get()) {
+ case BX_ATA_DEVICE_CDROM:
+ return (1);
+ break;
+ }
+ }
+ return (0);
+ break;
+
+ case BXP_ATA0_MASTER_JOURNAL:
+ case BXP_ATA0_SLAVE_JOURNAL:
+ case BXP_ATA1_MASTER_JOURNAL:
+ case BXP_ATA1_SLAVE_JOURNAL:
+ case BXP_ATA2_MASTER_JOURNAL:
+ case BXP_ATA2_SLAVE_JOURNAL:
+ case BXP_ATA3_MASTER_JOURNAL:
+ case BXP_ATA3_SLAVE_JOURNAL:
+ if (val != 0) {
+ Bit8u device = id - BXP_ATA0_MASTER_JOURNAL;
+
+ switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get()) {
+ case BX_ATA_DEVICE_DISK:
+ switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_MODE + device))->get()) {
+ case BX_ATA_MODE_UNDOABLE:
+ case BX_ATA_MODE_VOLATILE:
+ //case BX_ATA_MODE_Z_UNDOABLE:
+ //case BX_ATA_MODE_Z_VOLATILE:
+ return (1);
+ break;
+ }
+ }
+ }
+ return (0);
+ break;
+
+ default:
+ BX_PANIC (("bx_param_handler called with unknown id %d", id));
+ }
+ return val;
+}
+
+
+
+void bx_init_options ()
+{
+ int i;
+ bx_list_c *menu;
+ bx_list_c *deplist;
+ char name[1024], descr[1024], label[1024];
+
+ memset (&bx_options, 0, sizeof(bx_options));
+
+ // quick start option, set by command line arg
+ new bx_param_enum_c (BXP_BOCHS_START,
+ "Bochs start types",
+ "Bochs start types",
+ bochs_start_names,
+ BX_RUN_START,
+ BX_QUICK_START);
+
+ // floppya
+ bx_options.floppya.Opath = new bx_param_filename_c (BXP_FLOPPYA_PATH,
+ "floppya:path",
+ "Pathname of first floppy image file or device. If you're booting from floppy, this should be a bootable floppy.",
+ "", BX_PATHNAME_LEN);
+ bx_options.floppya.Opath->set_ask_format ("Enter new filename, or 'none' for no disk: [%s] ");
+ bx_options.floppya.Opath->set_label ("First floppy image/device");
+ bx_options.floppya.Odevtype = new bx_param_enum_c (BXP_FLOPPYA_DEVTYPE,
+ "floppya:devtype",
+ "Type of floppy drive",
+ floppy_type_names,
+ BX_FLOPPY_NONE,
+ BX_FLOPPY_NONE);
+ bx_options.floppya.Otype = new bx_param_enum_c (BXP_FLOPPYA_TYPE,
+ "floppya:type",
+ "Type of floppy disk",
+ floppy_type_names,
+ BX_FLOPPY_NONE,
+ BX_FLOPPY_NONE);
+ bx_options.floppya.Otype->set_ask_format ("What type of floppy disk? [%s] ");
+ bx_options.floppya.Ostatus = new bx_param_enum_c (BXP_FLOPPYA_STATUS,
+ "Is floppya inserted",
+ "Inserted or ejected",
+ floppy_status_names,
+ BX_INSERTED,
+ BX_EJECTED);
+ bx_options.floppya.Ostatus->set_ask_format ("Is the floppy inserted or ejected? [%s] ");
+ bx_options.floppya.Opath->set_format ("%s");
+ bx_options.floppya.Otype->set_format ("size=%s");
+ bx_options.floppya.Ostatus->set_format ("%s");
+ bx_param_c *floppya_init_list[] = {
+ // if the order "path,type,status" changes, corresponding changes must
+ // be made in gui/wxmain.cc, MyFrame::editFloppyConfig.
+ bx_options.floppya.Opath,
+ bx_options.floppya.Otype,
+ bx_options.floppya.Ostatus,
+ NULL
+ };
+ menu = new bx_list_c (BXP_FLOPPYA, "Floppy Disk 0", "All options for first floppy disk", floppya_init_list);
+ menu->get_options ()->set (menu->SERIES_ASK);
+ bx_options.floppya.Opath->set_handler (bx_param_string_handler);
+ bx_options.floppya.Opath->set ("none");
+ bx_options.floppya.Otype->set_handler (bx_param_handler);
+ bx_options.floppya.Ostatus->set_handler (bx_param_handler);
+
+ bx_options.floppyb.Opath = new bx_param_filename_c (BXP_FLOPPYB_PATH,
+ "floppyb:path",
+ "Pathname of second floppy image file or device.",
+ "", BX_PATHNAME_LEN);
+ bx_options.floppyb.Opath->set_ask_format ("Enter new filename, or 'none' for no disk: [%s] ");
+ bx_options.floppyb.Opath->set_label ("Second floppy image/device");
+ bx_options.floppyb.Odevtype = new bx_param_enum_c (BXP_FLOPPYB_DEVTYPE,
+ "floppyb:devtype",
+ "Type of floppy drive",
+ floppy_type_names,
+ BX_FLOPPY_NONE,
+ BX_FLOPPY_NONE);
+ bx_options.floppyb.Otype = new bx_param_enum_c (BXP_FLOPPYB_TYPE,
+ "floppyb:type",
+ "Type of floppy disk",
+ floppy_type_names,
+ BX_FLOPPY_NONE,
+ BX_FLOPPY_NONE);
+ bx_options.floppyb.Otype->set_ask_format ("What type of floppy disk? [%s] ");
+ bx_options.floppyb.Ostatus = new bx_param_enum_c (BXP_FLOPPYB_STATUS,
+ "Is floppyb inserted",
+ "Inserted or ejected",
+ floppy_status_names,
+ BX_INSERTED,
+ BX_EJECTED);
+ bx_options.floppyb.Ostatus->set_ask_format ("Is the floppy inserted or ejected? [%s] ");
+ bx_options.floppyb.Opath->set_format ("%s");
+ bx_options.floppyb.Otype->set_format ("size=%s");
+ bx_options.floppyb.Ostatus->set_format ("%s");
+ bx_param_c *floppyb_init_list[] = {
+ bx_options.floppyb.Opath,
+ bx_options.floppyb.Otype,
+ bx_options.floppyb.Ostatus,
+ NULL
+ };
+ menu = new bx_list_c (BXP_FLOPPYB, "Floppy Disk 1", "All options for second floppy disk", floppyb_init_list);
+ menu->get_options ()->set (menu->SERIES_ASK);
+ bx_options.floppyb.Opath->set_handler (bx_param_string_handler);
+ bx_options.floppyb.Opath->set ("none");
+ bx_options.floppyb.Otype->set_handler (bx_param_handler);
+ bx_options.floppyb.Ostatus->set_handler (bx_param_handler);
+
+ // disk options
+
+ // FIXME use descr and name
+ char *s_atachannel[] = {
+ "ATA channel 0",
+ "ATA channel 1",
+ "ATA channel 2",
+ "ATA channel 3",
+ };
+ char *s_atadevice[4][2] = {
+ { "First HD/CD on channel 0",
+ "Second HD/CD on channel 0" },
+ { "First HD/CD on channel 1",
+ "Second HD/CD on channel 1" },
+ { "First HD/CD on channel 2",
+ "Second HD/CD on channel 2" },
+ { "First HD/CD on channel 3",
+ "Second HD/CD on channel 3" }
+ };
+ Bit16u ata_default_ioaddr1[BX_MAX_ATA_CHANNEL] = {
+ 0x1f0, 0x170, 0x1e8, 0x168
+ };
+ Bit16u ata_default_ioaddr2[BX_MAX_ATA_CHANNEL] = {
+ 0x3f0, 0x370, 0x3e0, 0x360
+ };
+ Bit8u ata_default_irq[BX_MAX_ATA_CHANNEL] = {
+ 14, 15, 11, 9
+ };
+
+ bx_list_c *ata[BX_MAX_ATA_CHANNEL];
+ bx_list_c *ata_menu[BX_MAX_ATA_CHANNEL];
+
+ Bit8u channel;
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel ++) {
+
+ ata[channel] = new bx_list_c ((bx_id)(BXP_ATAx(channel)), s_atachannel[channel], s_atachannel[channel], 8);
+ ata[channel]->get_options ()->set (bx_list_c::SERIES_ASK);
+
+ ata[channel]->add (bx_options.ata[channel].Opresent = new bx_param_bool_c ((bx_id)(BXP_ATAx_PRESENT(channel)),
+ "ata:present",
+ "Controls whether ata channel is installed or not",
+ 0));
+
+ ata[channel]->add (bx_options.ata[channel].Oioaddr1 = new bx_param_num_c ((bx_id)(BXP_ATAx_IOADDR1(channel)),
+ "ata:ioaddr1",
+ "IO adress of ata command block",
+ 0, 0xffff,
+ ata_default_ioaddr1[channel]));
+
+ ata[channel]->add (bx_options.ata[channel].Oioaddr2 = new bx_param_num_c ((bx_id)(BXP_ATAx_IOADDR2(channel)),
+ "ata:ioaddr2",
+ "IO adress of ata control block",
+ 0, 0xffff,
+ ata_default_ioaddr2[channel]));
+
+ ata[channel]->add (bx_options.ata[channel].Oirq = new bx_param_num_c ((bx_id)(BXP_ATAx_IRQ(channel)),
+ "ata:irq",
+ "IRQ used by this ata channel",
+ 0, 15,
+ ata_default_irq[channel]));
+
+ // all items in the ata[channel] menu depend on the present flag.
+ // The menu list is complete, but a few dependent_list items will
+ // be added later. Use clone() to make a copy of the dependent_list
+ // so that it can be changed without affecting the menu.
+ bx_options.ata[channel].Opresent->set_dependent_list (
+ ata[channel]->clone());
+
+ for (Bit8u slave=0; slave<2; slave++) {
+
+ menu = bx_options.atadevice[channel][slave].Omenu = new bx_list_c ((bx_id)(BXP_ATAx_DEVICE(channel,slave)),
+ s_atadevice[channel][slave],
+ s_atadevice[channel][slave],
+ BXP_PARAMS_PER_ATA_DEVICE + 1 );
+ menu->get_options ()->set (menu->SERIES_ASK);
+
+ menu->add (bx_options.atadevice[channel][slave].Opresent = new bx_param_bool_c ((bx_id)(BXP_ATAx_DEVICE_PRESENT(channel,slave)),
+ "ata-device:present",
+ "Controls whether ata device is installed or not",
+ 0));
+
+ menu->add (bx_options.atadevice[channel][slave].Otype = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_TYPE(channel,slave)),
+ "ata-device:type",
+ "Type of ATA device (disk or cdrom)",
+ atadevice_type_names,
+ BX_ATA_DEVICE_DISK,
+ BX_ATA_DEVICE_DISK));
+
+ menu->add (bx_options.atadevice[channel][slave].Opath = new bx_param_filename_c ((bx_id)(BXP_ATAx_DEVICE_PATH(channel,slave)),
+ "ata-device:path",
+ "Pathname of the image or physical device (cdrom only)",
+ "", BX_PATHNAME_LEN));
+
+ menu->add (bx_options.atadevice[channel][slave].Omode = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_MODE(channel,slave)),
+ "ata-device:mode",
+ "Mode of the ATA harddisk",
+ atadevice_mode_names,
+ BX_ATA_MODE_FLAT,
+ BX_ATA_MODE_FLAT));
+
+ menu->add (bx_options.atadevice[channel][slave].Ostatus = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_STATUS(channel,slave)),
+ "ata-device:status",
+ "CD-ROM media status (inserted / ejected)",
+ atadevice_status_names,
+ BX_INSERTED,
+ BX_EJECTED));
+
+ menu->add (bx_options.atadevice[channel][slave].Ojournal = new bx_param_filename_c ((bx_id)(BXP_ATAx_DEVICE_JOURNAL(channel,slave)),
+ "ata-device:journal",
+ "Pathname of the journal file",
+ "", BX_PATHNAME_LEN));
+
+ menu->add (bx_options.atadevice[channel][slave].Ocylinders = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_CYLINDERS(channel,slave)),
+ "ata-device:cylinders",
+ "Number of cylinders",
+ 0, 65535,
+ 0));
+ menu->add (bx_options.atadevice[channel][slave].Oheads = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_HEADS(channel,slave)),
+ "ata-device:heads",
+ "Number of heads",
+ 0, 65535,
+ 0));
+ menu->add (bx_options.atadevice[channel][slave].Ospt = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_SPT(channel,slave)),
+ "ata-device:spt",
+ "Number of sectors per track",
+ 0, 65535,
+ 0));
+
+ menu->add (bx_options.atadevice[channel][slave].Omodel = new bx_param_string_c ((bx_id)(BXP_ATAx_DEVICE_MODEL(channel,slave)),
+ "ata-device:model",
+ "String returned by the 'identify device' command",
+ "Generic 1234", 40));
+
+ menu->add (bx_options.atadevice[channel][slave].Obiosdetect = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_BIOSDETECT(channel,slave)),
+ "ata-device:biosdetect",
+ "Type of bios detection",
+ atadevice_biosdetect_names,
+ BX_ATA_BIOSDETECT_AUTO,
+ BX_ATA_BIOSDETECT_NONE));
+
+ menu->add (bx_options.atadevice[channel][slave].Otranslation = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_TRANSLATION(channel,slave)),
+ "How the ata-disk translation is done by the bios",
+ "Type of translation",
+ atadevice_translation_names,
+ BX_ATA_TRANSLATION_AUTO,
+ BX_ATA_TRANSLATION_NONE));
+
+ bx_options.atadevice[channel][slave].Opresent->set_dependent_list (
+ menu->clone ());
+ // the menu and all items on it depend on the Opresent flag
+ bx_options.atadevice[channel][slave].Opresent->get_dependent_list()->add(menu);
+ // the present flag depends on the ATA channel's present flag
+ bx_options.ata[channel].Opresent->get_dependent_list()->add (
+ bx_options.atadevice[channel][slave].Opresent);
+ }
+
+ // set up top level menu for ATA[i] controller configuration. This list
+ // controls what will appear on the ATA configure dialog. It now
+ // requests the USE_TAB_WINDOW display, which is implemented in wx.
+ char buffer[32];
+ sprintf (buffer, "Configure ATA%d", channel);
+ ata_menu[channel] = new bx_list_c ((bx_id)(BXP_ATAx_MENU(channel)), strdup(buffer), "", 4);
+ ata_menu[channel]->add (ata[channel]);
+ ata_menu[channel]->add (bx_options.atadevice[channel][0].Omenu);
+ ata_menu[channel]->add (bx_options.atadevice[channel][1].Omenu);
+ ata_menu[channel]->get_options()->set (bx_list_c::USE_TAB_WINDOW);
+ }
+
+ // Enable first ata interface by default, disable the others.
+ bx_options.ata[0].Opresent->set_initial_val(1);
+
+ // now that the dependence relationships are established, call set() on
+ // the ata device present params to set all enables correctly.
+ for (i=0; i<BX_MAX_ATA_CHANNEL; i++)
+ bx_options.ata[i].Opresent->set (i==0);
+
+ for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel ++) {
+
+ bx_options.ata[channel].Opresent->set_ask_format ("Channel is enabled: [%s] ");
+ bx_options.ata[channel].Oioaddr1->set_ask_format ("Enter new ioaddr1: [0x%x] ");
+ bx_options.ata[channel].Oioaddr2->set_ask_format ("Enter new ioaddr2: [0x%x] ");
+ bx_options.ata[channel].Oirq->set_ask_format ("Enter new IRQ: [%d] ");
+#if BX_WITH_WX
+ bx_options.ata[channel].Opresent->set_label ("Enable this channel?");
+ bx_options.ata[channel].Oioaddr1->set_label ("I/O Address 1:");
+ bx_options.ata[channel].Oioaddr2->set_label ("I/O Address 2:");
+ bx_options.ata[channel].Oirq->set_label ("IRQ:");
+ bx_options.ata[channel].Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#else
+ bx_options.ata[channel].Opresent->set_format ("enabled: %s");
+ bx_options.ata[channel].Oioaddr1->set_format ("ioaddr1: 0x%x");
+ bx_options.ata[channel].Oioaddr2->set_format ("ioaddr2: 0x%x");
+ bx_options.ata[channel].Oirq->set_format ("irq: %d");
+#endif
+ bx_options.ata[channel].Oioaddr1->set_base (16);
+ bx_options.ata[channel].Oioaddr2->set_base (16);
+
+ for (Bit8u slave=0; slave<2; slave++) {
+
+ bx_options.atadevice[channel][slave].Opresent->set_ask_format (
+ "Device is enabled: [%s] ");
+ bx_options.atadevice[channel][slave].Otype->set_ask_format (
+ "Enter type of ATA device, disk or cdrom: [%s] ");
+ bx_options.atadevice[channel][slave].Omode->set_ask_format (
+ "Enter mode of ATA device, (flat, concat, etc.): [%s] ");
+ bx_options.atadevice[channel][slave].Opath->set_ask_format (
+ "Enter new filename: [%s] ");
+ bx_options.atadevice[channel][slave].Ocylinders->set_ask_format (
+ "Enter number of cylinders: [%d] ");
+ bx_options.atadevice[channel][slave].Oheads->set_ask_format (
+ "Enter number of heads: [%d] ");
+ bx_options.atadevice[channel][slave].Ospt->set_ask_format (
+ "Enter number of sectors per track: [%d] ");
+ bx_options.atadevice[channel][slave].Ostatus->set_ask_format (
+ "Is the device inserted or ejected? [%s] ");
+ bx_options.atadevice[channel][slave].Omodel->set_ask_format (
+ "Enter new model name: [%s]");
+ bx_options.atadevice[channel][slave].Otranslation->set_ask_format (
+ "Enter translation type: [%s]");
+ bx_options.atadevice[channel][slave].Obiosdetect->set_ask_format (
+ "Enter bios detection type: [%s]");
+ bx_options.atadevice[channel][slave].Ojournal->set_ask_format (
+ "Enter path of journal file: [%s]");
+
+#if BX_WITH_WX
+ bx_options.atadevice[channel][slave].Opresent->set_label (
+ "Enable this device?");
+ bx_options.atadevice[channel][slave].Otype->set_label (
+ "Type of ATA device:");
+ bx_options.atadevice[channel][slave].Omode->set_label (
+ "Type of disk image:");
+ bx_options.atadevice[channel][slave].Opath->set_label (
+ "Path or physical device name:");
+ bx_options.atadevice[channel][slave].Ocylinders->set_label (
+ "Cylinders:");
+ bx_options.atadevice[channel][slave].Oheads->set_label (
+ "Heads:");
+ bx_options.atadevice[channel][slave].Ospt->set_label (
+ "Sectors per track:");
+ bx_options.atadevice[channel][slave].Ostatus->set_label (
+ "Inserted?");
+ bx_options.atadevice[channel][slave].Omodel->set_label (
+ "Model name:");
+ bx_options.atadevice[channel][slave].Otranslation->set_label (
+ "Translation type:");
+ bx_options.atadevice[channel][slave].Obiosdetect->set_label (
+ "BIOS Detection:");
+ bx_options.atadevice[channel][slave].Ojournal->set_label (
+ "Path of journal file:");
+#else
+ bx_options.atadevice[channel][slave].Opresent->set_format ("enabled: %s");
+ bx_options.atadevice[channel][slave].Otype->set_format ("type %s");
+ bx_options.atadevice[channel][slave].Omode->set_format ("mode %s");
+ bx_options.atadevice[channel][slave].Opath->set_format ("path '%s'");
+ bx_options.atadevice[channel][slave].Ocylinders->set_format ("%d cylinders");
+ bx_options.atadevice[channel][slave].Oheads->set_format ("%d heads");
+ bx_options.atadevice[channel][slave].Ospt->set_format ("%d sectors/track");
+ bx_options.atadevice[channel][slave].Ostatus->set_format ("%s");
+ bx_options.atadevice[channel][slave].Omodel->set_format ("model '%s'");
+ bx_options.atadevice[channel][slave].Otranslation->set_format ("translation '%s'");
+ bx_options.atadevice[channel][slave].Obiosdetect->set_format ("biosdetect '%s'");
+ bx_options.atadevice[channel][slave].Ojournal->set_format ("journal is '%s'");
+#endif
+
+ bx_options.atadevice[channel][slave].Otype->set_handler (bx_param_handler);
+ bx_options.atadevice[channel][slave].Omode->set_handler (bx_param_handler);
+ bx_options.atadevice[channel][slave].Ostatus->set_handler (bx_param_handler);
+ bx_options.atadevice[channel][slave].Opath->set_handler (bx_param_string_handler);
+
+ // Set the enable_hanlders
+ bx_options.atadevice[channel][slave].Ojournal->set_enable_handler (bx_param_enable_handler);
+ bx_options.atadevice[channel][slave].Ostatus->set_enable_handler (bx_param_enable_handler);
+
+ }
+ }
+
+ bx_options.OnewHardDriveSupport = new bx_param_bool_c (BXP_NEWHARDDRIVESUPPORT,
+ "New hard drive support",
+ "Enables new features found on newer hard drives.",
+ 1);
+
+ bx_options.Obootdrive = new bx_param_enum_c (BXP_BOOTDRIVE,
+ "bootdrive",
+ "Boot A, C or CD",
+ floppy_bootdisk_names,
+ BX_BOOT_FLOPPYA,
+ BX_BOOT_FLOPPYA);
+ bx_options.Obootdrive->set_format ("Boot from: %s drive");
+ bx_options.Obootdrive->set_ask_format ("Boot from floppy drive, hard drive or cdrom ? [%s] ");
+
+ bx_options.OfloppySigCheck = new bx_param_bool_c (BXP_FLOPPYSIGCHECK,
+ "Skip Floppy Boot Signature Check",
+ "Skips check for the 0xaa55 signature on floppy boot device.",
+ 0);
+
+ // disk menu
+ bx_param_c *disk_menu_init_list[] = {
+ SIM->get_param (BXP_FLOPPYA),
+ SIM->get_param (BXP_FLOPPYB),
+ SIM->get_param (BXP_ATA0),
+ SIM->get_param (BXP_ATA0_MASTER),
+ SIM->get_param (BXP_ATA0_SLAVE),
+#if BX_MAX_ATA_CHANNEL>1
+ SIM->get_param (BXP_ATA1),
+ SIM->get_param (BXP_ATA1_MASTER),
+ SIM->get_param (BXP_ATA1_SLAVE),
+#endif
+#if BX_MAX_ATA_CHANNEL>2
+ SIM->get_param (BXP_ATA2),
+ SIM->get_param (BXP_ATA2_MASTER),
+ SIM->get_param (BXP_ATA2_SLAVE),
+#endif
+#if BX_MAX_ATA_CHANNEL>3
+ SIM->get_param (BXP_ATA3),
+ SIM->get_param (BXP_ATA3_MASTER),
+ SIM->get_param (BXP_ATA3_SLAVE),
+#endif
+ SIM->get_param (BXP_NEWHARDDRIVESUPPORT),
+ SIM->get_param (BXP_BOOTDRIVE),
+ SIM->get_param (BXP_FLOPPYSIGCHECK),
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_DISK, "Bochs Disk Options", "diskmenu", disk_menu_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+ // memory options menu
+ bx_options.memory.Osize = new bx_param_num_c (BXP_MEM_SIZE,
+ "megs",
+ "Amount of RAM in megabytes",
+ 1, BX_MAX_BIT32U,
+ BX_DEFAULT_MEM_MEGS);
+ bx_options.memory.Osize->set_ask_format ("Enter memory size (MB): [%d] ");
+#if BX_WITH_WX
+ bx_options.memory.Osize->set_label ("Memory size (megabytes)");
+ bx_options.memory.Osize->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#else
+ bx_options.memory.Osize->set_format ("Memory size in megabytes: %d");
+#endif
+
+ // initialize serial and parallel port options
+#define PAR_SER_INIT_LIST_MAX \
+ ((BXP_PARAMS_PER_PARALLEL_PORT * BX_N_PARALLEL_PORTS) \
+ + (BXP_PARAMS_PER_SERIAL_PORT * BX_N_SERIAL_PORTS) \
+ + (BXP_PARAMS_PER_USB_HUB * BX_N_USB_HUBS))
+ bx_param_c *par_ser_init_list[1+PAR_SER_INIT_LIST_MAX];
+ bx_param_c **par_ser_ptr = &par_ser_init_list[0];
+
+ // parallel ports
+ for (i=0; i<BX_N_PARALLEL_PORTS; i++) {
+ sprintf (name, "Enable parallel port #%d", i+1);
+ sprintf (descr, "Controls whether parallel port #%d is installed or not", i+1);
+ bx_options.par[i].Oenabled = new bx_param_bool_c (
+ BXP_PARPORTx_ENABLED(i+1),
+ strdup(name),
+ strdup(descr),
+ (i==0)? 1 : 0); // only enable #1 by default
+ sprintf (name, "Parallel port #%d output file", i+1);
+ sprintf (descr, "Data written to parport#%d by the guest OS is written to this file", i+1);
+ bx_options.par[i].Ooutfile = new bx_param_filename_c (
+ BXP_PARPORTx_OUTFILE(i+1),
+ strdup(name),
+ strdup(descr),
+ "", BX_PATHNAME_LEN);
+ deplist = new bx_list_c (BXP_NULL, 1);
+ deplist->add (bx_options.par[i].Ooutfile);
+ bx_options.par[i].Oenabled->set_dependent_list (deplist);
+ // add to menu
+ *par_ser_ptr++ = bx_options.par[i].Oenabled;
+ *par_ser_ptr++ = bx_options.par[i].Ooutfile;
+ }
+
+ // serial ports
+ for (i=0; i<BX_N_SERIAL_PORTS; i++) {
+ // options for COM port
+ sprintf (name, "Enable serial port #%d (COM%d)", i+1, i+1);
+ sprintf (descr, "Controls whether COM%d is installed or not", i+1);
+ bx_options.com[i].Oenabled = new bx_param_bool_c (
+ BXP_COMx_ENABLED(i+1),
+ strdup(name),
+ strdup(descr),
+ (i==0)?1 : 0); // only enable the first by default
+ sprintf (name, "Pathname of the serial device for COM%d", i+1);
+ sprintf (descr, "The path can be a real serial device or a pty (X/Unix only)");
+ bx_options.com[i].Odev = new bx_param_filename_c (
+ BXP_COMx_PATH(i+1),
+ strdup(name),
+ strdup(descr),
+ "", BX_PATHNAME_LEN);
+ deplist = new bx_list_c (BXP_NULL, 1);
+ deplist->add (bx_options.com[i].Odev);
+ bx_options.com[i].Oenabled->set_dependent_list (deplist);
+ // add to menu
+ *par_ser_ptr++ = bx_options.com[i].Oenabled;
+ *par_ser_ptr++ = bx_options.com[i].Odev;
+ }
+
+ // usb hubs
+ for (i=0; i<BX_N_USB_HUBS; i++) {
+ // options for USB hub
+ sprintf (name, "usb%d:enabled", i+1);
+ sprintf (descr, "Controls whether USB%d is installed or not", i+1);
+ sprintf (label, "Enable usb hub #%d (USB%d)", i+1, i+1);
+ bx_options.usb[i].Oenabled = new bx_param_bool_c (
+ BXP_USBx_ENABLED(i+1),
+ strdup(name),
+ strdup(descr),
+ (i==0)?1 : 0); // only enable the first by default
+ bx_options.usb[i].Oioaddr = new bx_param_num_c (
+ BXP_USBx_IOADDR(i+1),
+ "usb:ioaddr",
+ "I/O base adress of USB hub",
+ 0, 0xffe0,
+ (i==0)?0xff80 : 0);
+ bx_options.usb[i].Oirq = new bx_param_num_c (
+ BXP_USBx_IRQ(i+1),
+ "usb:irq",
+ "IRQ used by USB hub",
+ 0, 15,
+ (i==0)?10 : 0);
+ deplist = new bx_list_c (BXP_NULL, 2);
+ deplist->add (bx_options.usb[i].Oioaddr);
+ deplist->add (bx_options.usb[i].Oirq);
+ bx_options.usb[i].Oenabled->set_dependent_list (deplist);
+ // add to menu
+ *par_ser_ptr++ = bx_options.usb[i].Oenabled;
+ *par_ser_ptr++ = bx_options.usb[i].Oioaddr;
+ *par_ser_ptr++ = bx_options.usb[i].Oirq;
+
+ bx_options.usb[i].Oioaddr->set_ask_format ("Enter new ioaddr: [0x%x] ");
+ bx_options.usb[i].Oioaddr->set_label ("I/O Address");
+ bx_options.usb[i].Oioaddr->set_base (16);
+ bx_options.usb[i].Oenabled->set_label (strdup(label));
+ bx_options.usb[i].Oirq->set_label ("USB IRQ");
+ bx_options.usb[i].Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+ }
+ // add final NULL at the end, and build the menu
+ *par_ser_ptr = NULL;
+ menu = new bx_list_c (BXP_MENU_SERIAL_PARALLEL,
+ "Serial and Parallel Port Options",
+ "serial_parallel_menu",
+ par_ser_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+ bx_options.rom.Opath = new bx_param_filename_c (BXP_ROM_PATH,
+ "romimage",
+ "Pathname of ROM image to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.rom.Opath->set_format ("Name of ROM BIOS image: %s");
+ bx_options.rom.Oaddress = new bx_param_num_c (BXP_ROM_ADDRESS,
+ "romaddr",
+ "The address at which the ROM image should be loaded",
+ 0, BX_MAX_BIT32U,
+ 0xf0000);
+ bx_options.rom.Oaddress->set_base (16);
+#if BX_WITH_WX
+ bx_options.rom.Opath->set_label ("ROM BIOS image");
+ bx_options.rom.Oaddress->set_label ("ROM BIOS address");
+#else
+ bx_options.rom.Oaddress->set_format ("ROM BIOS address: 0x%05x");
+#endif
+
+ bx_options.optrom[0].Opath = new bx_param_filename_c (BXP_OPTROM1_PATH,
+ "optional romimage #1",
+ "Pathname of optional ROM image #1 to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.optrom[0].Opath->set_format ("Name of optional ROM image #1 : %s");
+ bx_options.optrom[0].Oaddress = new bx_param_num_c (BXP_OPTROM1_ADDRESS,
+ "optional romaddr #1",
+ "The address at which the optional ROM image #1 should be loaded",
+ 0, BX_MAX_BIT32U,
+ 0);
+ bx_options.optrom[0].Oaddress->set_base (16);
+#if BX_WITH_WX
+ bx_options.optrom[0].Opath->set_label ("Optional ROM image #1");
+ bx_options.optrom[0].Oaddress->set_label ("Address");
+#else
+ bx_options.optrom[0].Oaddress->set_format ("optional ROM #1 address: 0x%05x");
+#endif
+
+ bx_options.optrom[1].Opath = new bx_param_filename_c (BXP_OPTROM2_PATH,
+ "optional romimage #2",
+ "Pathname of optional ROM image #2 to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.optrom[1].Opath->set_format ("Name of optional ROM image #2 : %s");
+ bx_options.optrom[1].Oaddress = new bx_param_num_c (BXP_OPTROM2_ADDRESS,
+ "optional romaddr #2",
+ "The address at which the optional ROM image #2 should be loaded",
+ 0, BX_MAX_BIT32U,
+ 0);
+ bx_options.optrom[1].Oaddress->set_base (16);
+#if BX_WITH_WX
+ bx_options.optrom[1].Opath->set_label ("Optional ROM image #2");
+ bx_options.optrom[1].Oaddress->set_label ("Address");
+#else
+ bx_options.optrom[1].Oaddress->set_format ("optional ROM #2 address: 0x%05x");
+#endif
+
+ bx_options.optrom[2].Opath = new bx_param_filename_c (BXP_OPTROM3_PATH,
+ "optional romimage #3",
+ "Pathname of optional ROM image #3 to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.optrom[2].Opath->set_format ("Name of optional ROM image #3 : %s");
+ bx_options.optrom[2].Oaddress = new bx_param_num_c (BXP_OPTROM3_ADDRESS,
+ "optional romaddr #3",
+ "The address at which the optional ROM image #3 should be loaded",
+ 0, BX_MAX_BIT32U,
+ 0);
+ bx_options.optrom[2].Oaddress->set_base (16);
+#if BX_WITH_WX
+ bx_options.optrom[2].Opath->set_label ("Optional ROM image #3");
+ bx_options.optrom[2].Oaddress->set_label ("Address");
+#else
+ bx_options.optrom[2].Oaddress->set_format ("optional ROM #3 address: 0x%05x");
+#endif
+
+ bx_options.optrom[3].Opath = new bx_param_filename_c (BXP_OPTROM4_PATH,
+ "optional romimage #4",
+ "Pathname of optional ROM image #4 to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.optrom[3].Opath->set_format ("Name of optional ROM image #4 : %s");
+ bx_options.optrom[3].Oaddress = new bx_param_num_c (BXP_OPTROM4_ADDRESS,
+ "optional romaddr #4",
+ "The address at which the optional ROM image #4 should be loaded",
+ 0, BX_MAX_BIT32U,
+ 0);
+ bx_options.optrom[3].Oaddress->set_base (16);
+#if BX_WITH_WX
+ bx_options.optrom[3].Opath->set_label ("Optional ROM image #4");
+ bx_options.optrom[3].Oaddress->set_label ("Address");
+#else
+ bx_options.optrom[3].Oaddress->set_format ("optional ROM #4 address: 0x%05x");
+#endif
+
+ bx_options.vgarom.Opath = new bx_param_filename_c (BXP_VGA_ROM_PATH,
+ "vgaromimage",
+ "Pathname of VGA ROM image to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.vgarom.Opath->set_format ("Name of VGA BIOS image: %s");
+#if BX_WITH_WX
+ bx_options.vgarom.Opath->set_label ("VGA BIOS image");
+#endif
+ bx_param_c *memory_init_list[] = {
+ bx_options.memory.Osize,
+ bx_options.vgarom.Opath,
+ bx_options.rom.Opath,
+ bx_options.rom.Oaddress,
+ bx_options.optrom[0].Opath,
+ bx_options.optrom[0].Oaddress,
+ bx_options.optrom[1].Opath,
+ bx_options.optrom[1].Oaddress,
+ bx_options.optrom[2].Opath,
+ bx_options.optrom[2].Oaddress,
+ bx_options.optrom[3].Opath,
+ bx_options.optrom[3].Oaddress,
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_MEMORY, "Bochs Memory Options", "memmenu", memory_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+ // interface
+ bx_options.Ovga_update_interval = new bx_param_num_c (BXP_VGA_UPDATE_INTERVAL,
+ "VGA Update Interval",
+ "Number of microseconds between VGA updates",
+ 1, BX_MAX_BIT32U,
+ 30000);
+ bx_options.Ovga_update_interval->set_handler (bx_param_handler);
+ bx_options.Ovga_update_interval->set_runtime_param (1);
+ bx_options.Ovga_update_interval->set_ask_format ("Type a new value for VGA update interval: [%d] ");
+ bx_options.Omouse_enabled = new bx_param_bool_c (BXP_MOUSE_ENABLED,
+ "Enable the mouse",
+ "Controls whether the mouse sends events to the guest. The hardware emulation is always enabled.",
+ 0);
+ bx_options.Omouse_enabled->set_handler (bx_param_handler);
+ bx_options.Omouse_enabled->set_runtime_param (1);
+ bx_options.Oips = new bx_param_num_c (BXP_IPS,
+ "Emulated instructions per second (IPS)",
+ "Emulated instructions per second, used to calibrate bochs emulated time with wall clock time.",
+ 1, BX_MAX_BIT32U,
+ 500000);
+ bx_options.Otext_snapshot_check = new bx_param_bool_c (BXP_TEXT_SNAPSHOT_CHECK,
+ "Enable panic for use in bochs testing",
+ "Enable panic when text on screen matches snapchk.txt.\nUseful for regression testing.\nIn win32, turns off CR/LF in snapshots and cuts.",
+ 0);
+ bx_options.Oprivate_colormap = new bx_param_bool_c (BXP_PRIVATE_COLORMAP,
+ "Use a private colormap",
+ "Request that the GUI create and use it's own non-shared colormap. This colormap will be used when in the bochs window. If not enabled, a shared colormap scheme may be used. Not implemented on all GUI's.",
+ 0);
+#if BX_WITH_AMIGAOS
+ bx_options.Ofullscreen = new bx_param_bool_c (BXP_FULLSCREEN,
+ "Use full screen mode",
+ "When enabled, bochs occupies the whole screen instead of just a window.",
+ 0);
+ bx_options.Oscreenmode = new bx_param_string_c (BXP_SCREENMODE,
+ "Screen mode name",
+ "Screen mode name",
+ "", BX_PATHNAME_LEN);
+ bx_options.Oscreenmode->set_handler (bx_param_string_handler);
+#endif
+ static char *config_interface_list[] = {
+ "textconfig",
+#if BX_WITH_WX
+ "wx",
+#endif
+ NULL
+ };
+ bx_options.Osel_config = new bx_param_enum_c (
+ BXP_SEL_CONFIG_INTERFACE,
+ "Configuration interface",
+ "Select configuration interface",
+ config_interface_list,
+ 0,
+ 0);
+ bx_options.Osel_config->set_by_name (BX_DEFAULT_CONFIG_INTERFACE);
+ bx_options.Osel_config->set_ask_format ("Choose which configuration interface to use: [%s] ");
+ // this is a list of gui libraries that are known to be available at
+ // compile time. The one that is listed first will be the default,
+ // which is used unless the user overrides it on the command line or
+ // in a configuration file.
+ static char *display_library_list[] = {
+#if BX_WITH_X11
+ "x",
+#endif
+#if BX_WITH_WIN32
+ "win32",
+#endif
+#if BX_WITH_CARBON
+ "carbon",
+#endif
+#if BX_WITH_BEOS
+ "beos",
+#endif
+#if BX_WITH_MACOS
+ "macos",
+#endif
+#if BX_WITH_AMIGAOS
+ "amigaos",
+#endif
+#if BX_WITH_SDL
+ "sdl",
+#endif
+#if BX_WITH_SVGA
+ "svga",
+#endif
+#if BX_WITH_TERM
+ "term",
+#endif
+#if BX_WITH_RFB
+ "rfb",
+#endif
+#if BX_WITH_WX
+ "wx",
+#endif
+#if BX_WITH_NOGUI
+ "nogui",
+#endif
+ NULL
+ };
+ bx_options.Osel_displaylib = new bx_param_enum_c (BXP_SEL_DISPLAY_LIBRARY,
+ "VGA Display Library",
+ "Select VGA Display Library",
+ display_library_list,
+ 0,
+ 0);
+ bx_options.Osel_displaylib->set_by_name (BX_DEFAULT_DISPLAY_LIBRARY);
+ bx_options.Osel_displaylib->set_ask_format ("Choose which library to use for the Bochs display: [%s] ");
+ bx_param_c *interface_init_list[] = {
+ bx_options.Osel_config,
+ bx_options.Osel_displaylib,
+ bx_options.Ovga_update_interval,
+ bx_options.Omouse_enabled,
+ bx_options.Oips,
+ bx_options.Oprivate_colormap,
+#if BX_WITH_AMIGAOS
+ bx_options.Ofullscreen,
+ bx_options.Oscreenmode,
+#endif
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_INTERFACE, "Bochs Interface Menu", "intfmenu", interface_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+ // NE2K options
+ bx_options.ne2k.Opresent = new bx_param_bool_c (BXP_NE2K_PRESENT,
+ "Enable NE2K NIC emulation",
+ "Enables the NE2K NIC emulation",
+ 0);
+ bx_options.ne2k.Oioaddr = new bx_param_num_c (BXP_NE2K_IOADDR,
+ "NE2K I/O Address",
+ "I/O base address of the emulated NE2K device",
+ 0, 0xffff,
+ 0x240);
+ bx_options.ne2k.Oioaddr->set_base (16);
+ bx_options.ne2k.Oirq = new bx_param_num_c (BXP_NE2K_IRQ,
+ "NE2K Interrupt",
+ "IRQ used by the NE2K device",
+ 0, 15,
+ 9);
+ bx_options.ne2k.Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+ bx_options.ne2k.Omacaddr = new bx_param_string_c (BXP_NE2K_MACADDR,
+ "MAC Address",
+ "MAC address of the NE2K device. Don't use an address of a machine on your net.",
+ "\xfe\xfd\xde\xad\xbe\xef", 6);
+ bx_options.ne2k.Omacaddr->get_options ()->set (bx_options.ne2k.Omacaddr->RAW_BYTES);
+ bx_options.ne2k.Omacaddr->set_separator (':');
+ static char *eth_module_list[] = {
+ "null",
+#if defined(ETH_LINUX)
+ "linux",
+#endif
+#if HAVE_ETHERTAP
+ "tap",
+#endif
+#if HAVE_TUNTAP
+ "tuntap",
+#endif
+#if defined(ETH_WIN32)
+ "win32",
+#endif
+#if defined(ETH_FBSD)
+ "fbsd",
+#endif
+#ifdef ETH_ARPBACK
+ "arpback",
+#endif
+ NULL
+ };
+ bx_options.ne2k.Oethmod = new bx_param_enum_c (BXP_NE2K_ETHMOD,
+ "Ethernet module",
+ "Module used for the connection to the real net.",
+ eth_module_list,
+ 0,
+ 0);
+ bx_options.ne2k.Oethmod->set_by_name ("null");
+ bx_options.ne2k.Oethdev = new bx_param_string_c (BXP_NE2K_ETHDEV,
+ "Ethernet device",
+ "Device used for the connection to the real net. This is only valid if an ethernet module other than 'null' is used.",
+ "xl0", BX_PATHNAME_LEN);
+ bx_options.ne2k.Oscript = new bx_param_string_c (BXP_NE2K_SCRIPT,
+ "Device configuration script",
+ "Name of the script that is executed after Bochs initializes the network interface (optional).",
+ "none", BX_PATHNAME_LEN);
+#if !BX_WITH_WX
+ bx_options.ne2k.Oscript->set_ask_format ("Enter new script name, or 'none': [%s] ");
+#endif
+ bx_param_c *ne2k_init_list[] = {
+ bx_options.ne2k.Opresent,
+ bx_options.ne2k.Oioaddr,
+ bx_options.ne2k.Oirq,
+ bx_options.ne2k.Omacaddr,
+ bx_options.ne2k.Oethmod,
+ bx_options.ne2k.Oethdev,
+ bx_options.ne2k.Oscript,
+ NULL
+ };
+ menu = new bx_list_c (BXP_NE2K, "NE2K Configuration", "", ne2k_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+ bx_param_c **ne2k_dependent_list = &ne2k_init_list[1];
+ bx_options.ne2k.Opresent->set_dependent_list (
+ new bx_list_c (BXP_NULL, "", "", ne2k_dependent_list));
+ bx_options.ne2k.Opresent->set_handler (bx_param_handler);
+ bx_options.ne2k.Opresent->set (0);
+
+ // SB16 options
+ bx_options.sb16.Opresent = new bx_param_bool_c (BXP_SB16_PRESENT,
+ "Enable SB16 emulation",
+ "Enables the SB16 emulation",
+ 0);
+ bx_options.sb16.Omidifile = new bx_param_filename_c (BXP_SB16_MIDIFILE,
+ "MIDI file",
+ "The filename is where the MIDI data is sent. This can be device or just a file.",
+ "", BX_PATHNAME_LEN);
+ bx_options.sb16.Owavefile = new bx_param_filename_c (BXP_SB16_WAVEFILE,
+ "Wave file",
+ "This is the device/file where the wave output is stored",
+ "", BX_PATHNAME_LEN);
+ bx_options.sb16.Ologfile = new bx_param_filename_c (BXP_SB16_LOGFILE,
+ "Log file",
+ "The file to write the SB16 emulator messages to.",
+ "", BX_PATHNAME_LEN);
+ bx_options.sb16.Omidimode = new bx_param_num_c (BXP_SB16_MIDIMODE,
+ "Midi mode",
+ "Controls the MIDI output format.",
+ 0, 3,
+ 0);
+ bx_options.sb16.Owavemode = new bx_param_num_c (BXP_SB16_WAVEMODE,
+ "Wave mode",
+ "Controls the wave output format.",
+ 0, 3,
+ 0);
+ bx_options.sb16.Ologlevel = new bx_param_num_c (BXP_SB16_LOGLEVEL,
+ "Log mode",
+ "Controls how verbose the SB16 emulation is (0 = no log, 5 = all errors and infos).",
+ 0, 5,
+ 0);
+ bx_options.sb16.Odmatimer = new bx_param_num_c (BXP_SB16_DMATIMER,
+ "DMA timer",
+ "Microseconds per second for a DMA cycle.",
+ 0, BX_MAX_BIT32U,
+ 0);
+
+#if BX_WITH_WX
+ bx_options.sb16.Omidimode->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+ bx_options.sb16.Owavemode->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+ bx_options.sb16.Ologlevel->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#endif
+ bx_param_c *sb16_init_list[] = {
+ bx_options.sb16.Opresent,
+ bx_options.sb16.Omidimode,
+ bx_options.sb16.Omidifile,
+ bx_options.sb16.Owavemode,
+ bx_options.sb16.Owavefile,
+ bx_options.sb16.Ologlevel,
+ bx_options.sb16.Ologfile,
+ bx_options.sb16.Odmatimer,
+ NULL
+ };
+ menu = new bx_list_c (BXP_SB16, "SB16 Configuration", "", sb16_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+ // sb16_dependent_list is a null-terminated list including all the
+ // sb16 fields except for the "present" field. These will all be enabled/
+ // disabled according to the value of the present field.
+ bx_param_c **sb16_dependent_list = &sb16_init_list[1];
+ bx_options.sb16.Opresent->set_dependent_list (
+ new bx_list_c (BXP_NULL, "", "", sb16_dependent_list));
+
+ bx_options.log.Ofilename = new bx_param_filename_c (BXP_LOG_FILENAME,
+ "Log filename",
+ "Pathname of bochs log file",
+ "-", BX_PATHNAME_LEN);
+ bx_options.log.Ofilename->set_ask_format ("Enter log filename: [%s] ");
+
+ bx_options.log.Oprefix = new bx_param_string_c (BXP_LOG_PREFIX,
+ "Log output prefix",
+ "Prefix prepended to log output",
+ "%t%e%d", BX_PATHNAME_LEN);
+ bx_options.log.Oprefix->set_ask_format ("Enter log prefix: [%s] ");
+
+ bx_options.log.Odebugger_filename = new bx_param_filename_c (BXP_DEBUGGER_LOG_FILENAME,
+ "Debugger Log filename",
+ "Pathname of debugger log file",
+ "-", BX_PATHNAME_LEN);
+ bx_options.log.Odebugger_filename->set_ask_format ("Enter debugger log filename: [%s] ");
+
+ // loader
+ bx_options.load32bitOSImage.OwhichOS = new bx_param_enum_c (BXP_LOAD32BITOS_WHICH,
+ "Which operating system?",
+ "Which OS to boot",
+ loader_os_names,
+#ifdef BX_USE_VMX
+ Load32bitOSLinux,
+#else
+ Load32bitOSNone,
+#endif
+ Load32bitOSNone);
+ bx_options.load32bitOSImage.Opath = new bx_param_filename_c (BXP_LOAD32BITOS_PATH,
+ "Pathname of OS to load",
+ "Pathname of the 32-bit OS to load",
+ "", BX_PATHNAME_LEN);
+ bx_options.load32bitOSImage.Oiolog = new bx_param_filename_c (BXP_LOAD32BITOS_IOLOG,
+ "Pathname of I/O log file",
+ "I/O logfile used for initializing the hardware",
+ "", BX_PATHNAME_LEN);
+ bx_options.load32bitOSImage.Oinitrd = new bx_param_filename_c (BXP_LOAD32BITOS_INITRD,
+ "Pathname of initrd",
+ "Pathname of the initial ramdisk",
+ "", BX_PATHNAME_LEN);
+ bx_param_c *loader_init_list[] = {
+ bx_options.load32bitOSImage.OwhichOS,
+ bx_options.load32bitOSImage.Opath,
+ bx_options.load32bitOSImage.Oiolog,
+ bx_options.load32bitOSImage.Oinitrd,
+ NULL
+ };
+ bx_options.load32bitOSImage.OwhichOS->set_format ("os=%s");
+ bx_options.load32bitOSImage.Opath->set_format ("path=%s");
+ bx_options.load32bitOSImage.Oiolog->set_format ("iolog=%s");
+ bx_options.load32bitOSImage.Oinitrd->set_format ("initrd=%s");
+ bx_options.load32bitOSImage.OwhichOS->set_ask_format ("Enter OS to load: [%s] ");
+ bx_options.load32bitOSImage.Opath->set_ask_format ("Enter pathname of OS: [%s]");
+ bx_options.load32bitOSImage.Oiolog->set_ask_format ("Enter pathname of I/O log: [%s] ");
+ bx_options.load32bitOSImage.Oinitrd->set_ask_format ("Enter pathname of initrd: [%s] ");
+ menu = new bx_list_c (BXP_LOAD32BITOS, "32-bit OS Loader", "", loader_init_list);
+ menu->get_options ()->set (menu->SERIES_ASK);
+ bx_options.load32bitOSImage.OwhichOS->set_handler (bx_param_handler);
+#ifdef BX_USE_VMX
+ bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSLinux);
+#else
+ bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSNone);
+#endif
+
+ // clock
+ bx_options.clock.Otime0 = new bx_param_num_c (BXP_CLOCK_TIME0,
+ "clock:time0",
+ "Initial time for Bochs CMOS clock, used if you really want two runs to be identical",
+ 0, BX_MAX_BIT32U,
+ BX_CLOCK_TIME0_LOCAL);
+ bx_options.clock.Osync = new bx_param_enum_c (BXP_CLOCK_SYNC,
+ "clock:sync",
+ "Host to guest time synchronization method",
+ clock_sync_names,
+ BX_CLOCK_SYNC_NONE,
+ BX_CLOCK_SYNC_NONE);
+ bx_param_c *clock_init_list[] = {
+ bx_options.clock.Osync,
+ bx_options.clock.Otime0,
+ NULL
+ };
+#if !BX_WITH_WX
+ bx_options.clock.Osync->set_format ("sync=%s");
+ bx_options.clock.Otime0->set_format ("initial time=%d");
+#endif
+ bx_options.clock.Otime0->set_ask_format ("Enter Initial CMOS time (1:localtime, 2:utc, other:time in seconds): [%d] ");
+ bx_options.clock.Osync->set_ask_format ("Enter Synchronisation method: [%s] ");
+ bx_options.clock.Otime0->set_label ("Initial CMOS time for Bochs\n(1:localtime, 2:utc, other:time in seconds)");
+ bx_options.clock.Osync->set_label ("Synchronisation method");
+ menu = new bx_list_c (BXP_CLOCK, "Clock parameters", "", clock_init_list);
+ menu->get_options ()->set (menu->SERIES_ASK);
+
+ // other
+ bx_options.Okeyboard_serial_delay = new bx_param_num_c (BXP_KBD_SERIAL_DELAY,
+ "Keyboard serial delay",
+ "Approximate time in microseconds that it takes one character to be transfered from the keyboard to controller over the serial path.",
+ 1, BX_MAX_BIT32U,
+ 20000);
+ bx_options.Okeyboard_paste_delay = new bx_param_num_c (BXP_KBD_PASTE_DELAY,
+ "Keyboard paste delay",
+ "Approximate time in microseconds between attemps to paste characters to the keyboard controller.",
+ 1000, BX_MAX_BIT32U,
+ 100000);
+ bx_options.Okeyboard_paste_delay->set_handler (bx_param_handler);
+ bx_options.Okeyboard_paste_delay->set_runtime_param (1);
+ bx_options.Ofloppy_command_delay = new bx_param_num_c (BXP_FLOPPY_CMD_DELAY,
+ "Floppy command delay",
+ "Time in microseconds to wait before completing some floppy commands such as read/write/seek/etc, which normally have a delay associated. This used to be hardwired to 50,000 before.",
+ 1, BX_MAX_BIT32U,
+ 50000);
+ bx_options.Oi440FXSupport = new bx_param_bool_c (BXP_I440FX_SUPPORT,
+ "PCI i440FX Support",
+ "Controls whether to emulate the i440FX PCI chipset",
+ 0);
+ bx_options.cmos.OcmosImage = new bx_param_bool_c (BXP_CMOS_IMAGE,
+ "Use a CMOS image",
+ "Controls the usage of a CMOS image",
+ 0);
+ bx_options.cmos.Opath = new bx_param_filename_c (BXP_CMOS_PATH,
+ "Pathname of CMOS image",
+ "Pathname of CMOS image",
+ "", BX_PATHNAME_LEN);
+ deplist = new bx_list_c (BXP_NULL, 1);
+ deplist->add (bx_options.cmos.Opath);
+ bx_options.cmos.OcmosImage->set_dependent_list (deplist);
+
+ // Keyboard mapping
+ bx_options.keyboard.OuseMapping = new bx_param_bool_c(BXP_KEYBOARD_USEMAPPING,
+ "Use keyboard mapping",
+ "Controls whether to use the keyboard mapping feature",
+ 0);
+ bx_options.keyboard.Okeymap = new bx_param_filename_c (BXP_KEYBOARD_MAP,
+ "Keymap filename",
+ "Pathname of the keymap file used",
+ "", BX_PATHNAME_LEN);
+ deplist = new bx_list_c (BXP_NULL, 1);
+ deplist->add (bx_options.keyboard.Okeymap);
+ bx_options.keyboard.OuseMapping->set_dependent_list (deplist);
+
+ // Keyboard type
+ bx_options.Okeyboard_type = new bx_param_enum_c (BXP_KBD_TYPE,
+ "Keyboard type",
+ "Keyboard type reported by the 'identify keyboard' command",
+ keyboard_type_names,
+ BX_KBD_MF_TYPE,
+ BX_KBD_XT_TYPE);
+ bx_options.Okeyboard_type->set_ask_format ("Enter keyboard type: [%s] ");
+
+ // Userbutton shortcut
+ bx_options.Ouser_shortcut = new bx_param_string_c (BXP_USER_SHORTCUT,
+ "Userbutton shortcut",
+ "Defines the keyboard shortcut to be sent when you press the 'user' button in the headerbar.",
+ "none", 16);
+
+ // GDB stub
+ bx_options.gdbstub.port = 1234;
+ bx_options.gdbstub.text_base = 0;
+ bx_options.gdbstub.data_base = 0;
+ bx_options.gdbstub.bss_base = 0;
+
+ bx_param_c *keyboard_init_list[] = {
+ bx_options.Okeyboard_serial_delay,
+ bx_options.Okeyboard_paste_delay,
+ bx_options.keyboard.OuseMapping,
+ bx_options.keyboard.Okeymap,
+ bx_options.Okeyboard_type,
+ bx_options.Ouser_shortcut,
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_KEYBOARD, "Configure Keyboard", "", keyboard_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+ bx_param_c *other_init_list[] = {
+ bx_options.Ofloppy_command_delay,
+ bx_options.Oi440FXSupport,
+ bx_options.cmos.OcmosImage,
+ bx_options.cmos.Opath,
+ SIM->get_param (BXP_CLOCK),
+ SIM->get_param (BXP_LOAD32BITOS),
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_MISC, "Configure Everything Else", "", other_init_list);
+ menu->get_options ()->set (menu->SHOW_PARENT);
+
+#if BX_WITH_WX
+ bx_param_c *other_init_list2[] = {
+// bx_options.Osel_config,
+// bx_options.Osel_displaylib,
+ bx_options.Ovga_update_interval,
+ bx_options.log.Oprefix,
+ bx_options.Omouse_enabled,
+ bx_options.OfloppySigCheck,
+ bx_options.Ofloppy_command_delay,
+ bx_options.OnewHardDriveSupport,
+ bx_options.Oprivate_colormap,
+#if BX_WITH_AMIGAOS
+ bx_options.Ofullscreen,
+ bx_options.Oscreenmode,
+#endif
+ bx_options.Oi440FXSupport,
+ bx_options.cmos.OcmosImage,
+ bx_options.cmos.Opath,
+ NULL
+ };
+ menu = new bx_list_c (BXP_MENU_MISC_2, "Other options", "", other_init_list2);
+#endif
+}
+
+void bx_reset_options ()
+{
+ // drives
+ bx_options.floppya.Opath->reset();
+ bx_options.floppya.Odevtype->reset();
+ bx_options.floppya.Otype->reset();
+ bx_options.floppya.Ostatus->reset();
+ bx_options.floppyb.Opath->reset();
+ bx_options.floppyb.Odevtype->reset();
+ bx_options.floppyb.Otype->reset();
+ bx_options.floppyb.Ostatus->reset();
+
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ bx_options.ata[channel].Opresent->reset();
+ bx_options.ata[channel].Oioaddr1->reset();
+ bx_options.ata[channel].Oioaddr2->reset();
+ bx_options.ata[channel].Oirq->reset();
+
+ for (Bit8u slave=0; slave<2; slave++) {
+ bx_options.atadevice[channel][slave].Opresent->reset();
+ bx_options.atadevice[channel][slave].Otype->reset();
+ bx_options.atadevice[channel][slave].Omode->reset();
+ bx_options.atadevice[channel][slave].Opath->reset();
+ bx_options.atadevice[channel][slave].Ocylinders->reset();
+ bx_options.atadevice[channel][slave].Oheads->reset();
+ bx_options.atadevice[channel][slave].Ospt->reset();
+ bx_options.atadevice[channel][slave].Ostatus->reset();
+ bx_options.atadevice[channel][slave].Omodel->reset();
+ bx_options.atadevice[channel][slave].Obiosdetect->reset();
+ bx_options.atadevice[channel][slave].Otranslation->reset();
+ }
+ }
+ bx_options.OnewHardDriveSupport->reset();
+
+ // boot & memory
+ bx_options.Obootdrive->reset();
+ bx_options.OfloppySigCheck->reset();
+ bx_options.memory.Osize->reset();
+
+ // standard ports
+ bx_options.com[0].Oenabled->reset();
+ bx_options.com[0].Odev->reset();
+ bx_options.par[0].Oenabled->reset();
+ bx_options.par[0].Ooutfile->reset();
+
+ // rom images
+ bx_options.rom.Opath->reset();
+ bx_options.rom.Oaddress->reset();
+ bx_options.optrom[0].Opath->reset();
+ bx_options.optrom[0].Oaddress->reset();
+ bx_options.optrom[1].Opath->reset();
+ bx_options.optrom[1].Oaddress->reset();
+ bx_options.optrom[2].Opath->reset();
+ bx_options.optrom[2].Oaddress->reset();
+ bx_options.optrom[3].Opath->reset();
+ bx_options.optrom[3].Oaddress->reset();
+ bx_options.vgarom.Opath->reset();
+
+ // interface
+ bx_options.Ovga_update_interval->reset();
+ bx_options.Omouse_enabled->reset();
+ bx_options.Oips->reset();
+ bx_options.Oprivate_colormap->reset();
+#if BX_WITH_AMIGAOS
+ bx_options.Ofullscreen->reset();
+ bx_options.Oscreenmode->reset();
+#endif
+
+ // ne2k
+ bx_options.ne2k.Opresent->reset();
+ bx_options.ne2k.Oioaddr->reset();
+ bx_options.ne2k.Oirq->reset();
+ bx_options.ne2k.Omacaddr->reset();
+ bx_options.ne2k.Oethmod->reset();
+ bx_options.ne2k.Oethdev->reset();
+ bx_options.ne2k.Oscript->reset();
+
+ // SB16
+ bx_options.sb16.Opresent->reset();
+ bx_options.sb16.Omidifile->reset();
+ bx_options.sb16.Owavefile->reset();
+ bx_options.sb16.Ologfile->reset();
+ bx_options.sb16.Omidimode->reset();
+ bx_options.sb16.Owavemode->reset();
+ bx_options.sb16.Ologlevel->reset();
+ bx_options.sb16.Odmatimer->reset();
+
+ // logfile
+ bx_options.log.Ofilename->reset();
+ bx_options.log.Oprefix->reset();
+ bx_options.log.Odebugger_filename->reset();
+
+ // loader
+ bx_options.load32bitOSImage.OwhichOS->reset();
+ bx_options.load32bitOSImage.Opath->reset();
+ bx_options.load32bitOSImage.Oiolog->reset();
+ bx_options.load32bitOSImage.Oinitrd->reset();
+
+ // keyboard
+ bx_options.Okeyboard_serial_delay->reset();
+ bx_options.Okeyboard_paste_delay->reset();
+ bx_options.keyboard.OuseMapping->reset();
+ bx_options.keyboard.Okeymap->reset();
+ bx_options.Okeyboard_type->reset();
+ bx_options.Ouser_shortcut->reset();
+
+ // Clock
+ bx_options.clock.Otime0->reset();
+ bx_options.clock.Osync->reset();
+
+ // other
+ bx_options.Ofloppy_command_delay->reset();
+ bx_options.Oi440FXSupport->reset();
+ bx_options.cmos.OcmosImage->reset();
+ bx_options.cmos.Opath->reset();
+ bx_options.Otext_snapshot_check->reset();
+}
+
+void bx_print_header ()
+{
+ fprintf (stderr, "%s\n", divider);
+ char buffer[128];
+ sprintf (buffer, "Bochs x86 Emulator %s\n", VER_STRING);
+ bx_center_print (stderr, buffer, 72);
+ if (REL_STRING[0]) {
+ sprintf (buffer, "%s\n", REL_STRING);
+ bx_center_print (stderr, buffer, 72);
+ }
+ fprintf (stderr, "%s\n", divider);
+}
+
+#if BX_WITH_CARBON
+/* Original code by Darrell Walisser - dwaliss1@purdue.edu */
+
+static void setupWorkingDirectory (char *path)
+{
+ char parentdir[MAXPATHLEN];
+ char *c;
+
+ strncpy ( parentdir, path, MAXPATHLEN );
+ c = (char*) parentdir;
+
+ while (*c != '\0') /* go to end */
+ c++;
+
+ while (*c != '/') /* back up to parent */
+ c--;
+
+ *c = '\0'; /* cut off last part (binary name) */
+
+ /* chdir to the binary app's parent */
+ int n;
+ n = chdir (parentdir);
+ if (n) BX_PANIC (("failed to change dir to parent"));
+ /* chdir to the .app's parent */
+ n = chdir ("../../../");
+ if (n) BX_PANIC (("failed to change to ../../.."));
+}
+
+/* Panic button to display fatal errors.
+ Completely self contained, can't rely on carbon.cc being available */
+static void carbonFatalDialog(const char *error, const char *exposition)
+{
+ DialogRef alertDialog;
+ CFStringRef cfError;
+ CFStringRef cfExposition;
+ DialogItemIndex index;
+ AlertStdCFStringAlertParamRec alertParam = {0};
+ fprintf(stderr, "Entering carbonFatalDialog: %s\n", error);
+
+ // Init libraries
+ InitCursor();
+ // Assemble dialog
+ cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII);
+ if(exposition != NULL)
+ {
+ cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII);
+ }
+ else { cfExposition = NULL; }
+ alertParam.version = kStdCFStringAlertVersionOne;
+ alertParam.defaultText = CFSTR("Quit");
+ alertParam.position = kWindowDefaultPosition;
+ alertParam.defaultButton = kAlertStdAlertOKButton;
+ // Display Dialog
+ CreateStandardAlert(
+ kAlertStopAlert,
+ cfError,
+ cfExposition, /* can be NULL */
+ &alertParam, /* can be NULL */
+ &alertDialog);
+ RunStandardAlert( alertDialog, NULL, &index);
+ // Cleanup
+ CFRelease( cfError );
+ if( cfExposition != NULL ) { CFRelease( cfExposition ); }
+}
+#endif
+
+int bxmain () {
+#ifdef HAVE_LOCALE_H
+ // Initialize locale (for isprint() and other functions)
+ setlocale (LC_ALL, "");
+#endif
+ bx_user_quit = 0;
+ bx_init_siminterface (); // create the SIM object
+
+ static jmp_buf context;
+ if (setjmp (context) == 0) {
+ SIM->set_quit_context (&context);
+ if (bx_init_main (bx_startup_flags.argc, bx_startup_flags.argv) < 0)
+ return 0;
+ // read a param to decide which config interface to start.
+ // If one exists, start it. If not, just begin.
+ bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+ char *ci_name = ci_param->get_choice (ci_param->get ());
+ if (!strcmp(ci_name, "textconfig")) {
+ init_text_config_interface (); // in textconfig.h
+ }
+#if BX_WITH_WX
+ else if (!strcmp(ci_name, "wx")) {
+ PLUG_load_plugin(wx, PLUGTYPE_CORE);
+ }
+#endif
+ else {
+ BX_PANIC (("unsupported configuration interface '%s'", ci_name));
+ }
+ int status = SIM->configuration_interface (ci_name, CI_START);
+ if (status == CI_ERR_NO_TEXT_CONSOLE)
+ BX_PANIC (("Bochs needed the text console, but it was not usable"));
+ // user quit the config interface, so just quit
+ } else {
+ // quit via longjmp
+ }
+}
+
+// normal main function, presently in for all cases except for
+// wxWindows under win32.
+int main (int argc, char *argv[])
+{
+ daemon(0, 0);
+ bx_startup_flags.argc = argc;
+ bx_startup_flags.argv = argv;
+#if BX_WITH_SDL && defined(WIN32)
+ // if SDL/win32, try to create a console window.
+ RedirectIOToConsole ();
+#endif
+ return bxmain ();
+}
+
+void
+print_usage ()
+{
+ fprintf(stderr,
+ "Usage: bochs [flags] [bochsrc options]\n\n"
+ " -n no configuration file\n"
+ " -f configfile specify configuration file\n"
+ " -q quick start (skip configuration interface)\n"
+ " --help display this help and exit\n\n"
+ "For information on Bochs configuration file arguments, see the\n"
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+ "bochsrc section in the user documentation or the man page of bochsrc.\n");
+#else
+ "bochsrc section in the user documentation.\n");
+#endif
+}
+
+#ifdef BX_USE_VMX
+int domid = -1;
+unsigned long megabytes = 0;
+#endif
+int
+bx_init_main (int argc, char *argv[])
+{
+ // To deal with initialization order problems inherent in C++, use the macros
+ // SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog" in all
+ // constructors or functions called by constructors. The macros test for
+ // NULL and create the object if necessary, then return it. Ensure that io
+ // and genlog get created, by making one reference to each macro right here.
+ // All other code can reference io and genlog directly. Because these
+ // objects are required for logging, and logging is so fundamental to
+ // knowing what the program is doing, they are never free()d.
+ SAFE_GET_IOFUNC(); // never freed
+ SAFE_GET_GENLOG(); // never freed
+
+ // initalization must be done early because some destructors expect
+ // the bx_options to exist by the time they are called.
+ bx_init_bx_dbg ();
+ bx_init_options ();
+
+ bx_print_header ();
+
+#ifdef BX_USE_VMX
+ xc_handle = xc_interface_open();
+ SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+#else
+ SIM->get_param_enum(BXP_BOCHS_START)->set (BX_RUN_START);
+#endif
+
+ // interpret the args that start with -, like -q, -f, etc.
+ int arg = 1, load_rcfile=1;
+ while (arg < argc) {
+ // parse next arg
+ if (!strcmp ("--help", argv[arg]) || !strncmp ("-h", argv[arg], 2)) {
+ print_usage();
+ SIM->quit_sim (0);
+ }
+ else if (!strcmp ("-n", argv[arg])) {
+ load_rcfile = 0;
+ }
+ else if (!strcmp ("-q", argv[arg])) {
+ SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+ }
+ else if (!strcmp ("-f", argv[arg])) {
+ if (++arg >= argc) BX_PANIC(("-f must be followed by a filename"));
+ else bochsrc_filename = argv[arg];
+ }
+ else if (!strcmp ("-qf", argv[arg])) {
+ SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+ if (++arg >= argc) BX_PANIC(("-qf must be followed by a filename"));
+ else bochsrc_filename = argv[arg];
+ }
+#ifdef BX_USE_VMX
+ else if (!strcmp ("-p", argv[arg])) {
+ //get the polling port
+ extern int ioreq_port;
+ if (++arg >= argc) BX_PANIC(("-p must be followed by a polling port"));
+ else sscanf(argv[arg], "%d", &ioreq_port);
+ }
+ else if (!strcmp ("-d", argv[arg])) {
+ //get the domain id
+ if (++arg >= argc) BX_PANIC(("-d must be followed by domainid"));
+ else sscanf(argv[arg], "%d", &domid);
+ }
+ else if (!strcmp ("-m", argv[arg])) {
+ //get the maxmem
+ if (++arg >= argc)
+ BX_PANIC(("-m must be followed by maxmem in megabytes"));
+ else sscanf(argv[arg], "%d", &megabytes);
+ }
+
+#endif
+ else if (argv[arg][0] == '-') {
+ print_usage();
+ BX_PANIC (("command line arg '%s' was not understood", argv[arg]));
+ }
+ else {
+ // the arg did not start with -, so stop interpreting flags
+ break;
+ }
+ arg++;
+ }
+
+ int norcfile = 1;
+
+ if (load_rcfile) {
+ /* parse configuration file and command line arguments */
+#ifdef WIN32
+ if (bochsrc_filename != NULL) {
+ lstrcpy(bx_startup_flags.initial_dir, bochsrc_filename);
+ } else {
+ bx_startup_flags.initial_dir[0] = 0;
+ }
+#endif
+ if (bochsrc_filename == NULL) bochsrc_filename = bx_find_bochsrc ();
+ if (bochsrc_filename)
+ norcfile = bx_read_configuration (bochsrc_filename);
+ }
+
+ // parse the rest of the command line. This is done after reading the
+ // configuration file so that the command line arguments can override
+ // the settings from the file.
+ if (bx_parse_cmdline (arg, argc, argv)) {
+ BX_PANIC(("There were errors while parsing the command line"));
+ return -1;
+ }
+ // initialize plugin system. This must happen before we attempt to
+ // load any modules.
+ plugin_startup();
+ return 0;
+}
+
+bx_bool load_and_init_display_lib () {
+ if (bx_gui != NULL) {
+ // bx_gui has already been filled in. This happens when you start
+ // the simulation for the second time.
+ // Also, if you load wxWindows as the configuration interface. Its
+ // plugin_init will install wxWindows as the bx_gui.
+ return true;
+ }
+ BX_ASSERT (bx_gui == NULL);
+ bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+ char *ci_name = ci_param->get_choice (ci_param->get ());
+ bx_param_enum_c *gui_param = SIM->get_param_enum(BXP_SEL_DISPLAY_LIBRARY);
+ char *gui_name = gui_param->get_choice (gui_param->get ());
+ if (!strcmp(ci_name, "wx")) {
+ BX_ERROR(("change of the config interface to wx not implemented yet"));
+ }
+ if (!strcmp (gui_name, "wx")) {
+ // they must not have used wx as the configuration interface, or bx_gui
+ // would already be initialized. Sorry, it doesn't work that way.
+ BX_ERROR (("wxWindows was not used as the configuration interface, so it cannot be used as the display library"));
+ // choose another, hopefully different!
+ gui_param->set (0);
+ gui_name = gui_param->get_choice (gui_param->get ());
+ if (!strcmp (gui_name, "wx")) {
+ BX_PANIC (("no alternative display libraries are available"));
+ return false;
+ }
+ BX_ERROR (("changing display library to '%s' instead", gui_name));
+ }
+#if BX_WITH_NOGUI
+ if (!strcmp (gui_name, "nogui"))
+ PLUG_load_plugin (nogui, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_WITH_RFB
+ if (!strcmp (gui_name, "rfb"))
+ PLUG_load_plugin (rfb, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_WITH_X11
+ if (!strcmp (gui_name, "x"))
+ PLUG_load_plugin (x, PLUGTYPE_OPTIONAL);
+#endif
+
+#if BX_GUI_SIGHANDLER
+ // set the flag for guis requiring a GUI sighandler.
+ // useful when guis are compiled as plugins
+ // only term for now
+ if (!strcmp (gui_name, "term")) {
+ bx_gui_sighandler = 1;
+ }
+#endif
+
+ BX_ASSERT (bx_gui != NULL);
+ return true;
+}
+
+int
+bx_begin_simulation (int argc, char *argv[])
+{
+ // deal with gui selection
+ if (!load_and_init_display_lib ()) {
+ BX_PANIC (("no gui module was loaded"));
+ return 0;
+ }
+#if BX_GDBSTUB
+ // If using gdbstub, it will take control and call
+ // bx_init_hardware() and cpu_loop()
+ bx_gdbstub_init (argc, argv);
+#elif BX_DEBUGGER
+ // If using the debugger, it will take control and call
+ // bx_init_hardware() and cpu_loop()
+ bx_dbg_main(argc, argv);
+#else
+
+ bx_init_hardware();
+
+ if (bx_options.load32bitOSImage.OwhichOS->get ()) {
+ void bx_load32bitOSimagehack(void);
+ bx_load32bitOSimagehack();
+ }
+
+ SIM->set_init_done (1);
+
+ // update headerbar buttons since drive status can change during init
+ bx_gui->update_drive_status_buttons ();
+
+ // The set handler for mouse_enabled does not actually update the gui
+ // until init_done is set. This forces the set handler to be called,
+ // which sets up the mouse enabled GUI-specific stuff correctly.
+ // Not a great solution but it works. BBD
+ bx_options.Omouse_enabled->set (bx_options.Omouse_enabled->get ());
+
+ if (BX_SMP_PROCESSORS == 1) {
+ // only one processor, run as fast as possible by not messing with
+ // quantums and loops.
+ BX_CPU(0)->cpu_loop(1);
+ // for one processor, the only reason for cpu_loop to return is
+ // that kill_bochs_request was set by the GUI interface.
+ } else {
+ // SMP simulation: do a few instructions on each processor, then switch
+ // to another. Increasing quantum speeds up overall performance, but
+ // reduces granularity of synchronization between processors.
+ int processor = 0;
+ int quantum = 5;
+ while (1) {
+ // do some instructions in each processor
+ BX_CPU(processor)->cpu_loop(quantum);
+ processor = (processor+1) % BX_SMP_PROCESSORS;
+ if (BX_CPU(0)->kill_bochs_request)
+ break;
+ if (processor == 0)
+ BX_TICKN(quantum);
+ }
+ }
+#endif
+ BX_INFO (("cpu loop quit, shutting down simulator"));
+ bx_atexit ();
+ return(0);
+}
+
+
+int
+bx_read_configuration (char *rcfile)
+{
+ // parse rcfile first, then parse arguments in order.
+ BX_INFO (("reading configuration from %s", rcfile));
+ if (parse_bochsrc(rcfile) < 0) {
+ BX_PANIC (("reading from %s failed", rcfile));
+ return -1;
+ }
+ // update log actions
+ for (int level=0; level<N_LOGLEV; level++) {
+ int action = SIM->get_default_log_action (level);
+ io->set_log_action (level, action);
+ }
+ return 0;
+}
+
+int bx_parse_cmdline (int arg, int argc, char *argv[])
+{
+ //if (arg < argc) BX_INFO (("parsing command line arguments"));
+
+ while (arg < argc) {
+ BX_INFO (("parsing arg %d, %s", arg, argv[arg]));
+ parse_line_unformatted("cmdline args", argv[arg]);
+ arg++;
+ }
+ // update log actions
+ for (int level=0; level<N_LOGLEV; level++) {
+ int action = SIM->get_default_log_action (level);
+ io->set_log_action (level, action);
+ }
+ return 0;
+}
+
+ int
+bx_init_hardware()
+{
+ // all configuration has been read, now initialize everything.
+
+ if (SIM->get_param_enum(BXP_BOCHS_START)->get ()==BX_QUICK_START) {
+ for (int level=0; level<N_LOGLEV; level++) {
+ int action = SIM->get_default_log_action (level);
+#if !BX_USE_CONFIG_INTERFACE
+ if (action == ACT_ASK) action = ACT_FATAL;
+#endif
+ io->set_log_action (level, action);
+ }
+ }
+
+ bx_pc_system.init_ips(bx_options.Oips->get ());
+
+ if(bx_options.log.Ofilename->getptr()[0]!='-') {
+ BX_INFO (("using log file %s", bx_options.log.Ofilename->getptr ()));
+ io->init_log(bx_options.log.Ofilename->getptr ());
+ }
+
+ io->set_log_prefix(bx_options.log.Oprefix->getptr());
+
+ // Output to the log file the cpu settings
+ // This will by handy for bug reports
+ BX_INFO(("Bochs x86 Emulator %s", VER_STRING));
+ BX_INFO((" %s", REL_STRING));
+ BX_INFO(("System configuration"));
+ BX_INFO((" processors: %d",BX_SMP_PROCESSORS));
+ BX_INFO((" A20 line support: %s",BX_SUPPORT_A20?"yes":"no"));
+ BX_INFO((" APIC support: %s",BX_SUPPORT_APIC?"yes":"no"));
+
+#ifndef BX_USE_VMX
+ BX_INFO(("CPU configuration"));
+ BX_INFO((" level: %d",BX_CPU_LEVEL));
+ BX_INFO((" fpu support: %s",BX_SUPPORT_FPU?"yes":"no"));
+ BX_INFO((" paging support: %s, tlb enabled: %s",BX_SUPPORT_PAGING?"yes":"no",BX_USE_TLB?"yes":"no"));
+ BX_INFO((" mmx support: %s",BX_SUPPORT_MMX?"yes":"no"));
+ BX_INFO((" sse support: %s",BX_SUPPORT_SSE==2?"2":BX_SUPPORT_SSE==1?"1":"no"));
+ BX_INFO((" v8086 mode support: %s",BX_SUPPORT_V8086_MODE?"yes":"no"));
+ BX_INFO((" 3dnow! support: %s",BX_SUPPORT_3DNOW?"yes":"no"));
+ BX_INFO((" PAE support: %s",BX_SupportPAE?"yes":"no"));
+ BX_INFO((" PGE support: %s",BX_SupportGlobalPages?"yes":"no"));
+ BX_INFO((" PSE support: %s",BX_SUPPORT_4MEG_PAGES?"yes":"no"));
+ BX_INFO((" x86-64 support: %s",BX_SUPPORT_X86_64?"yes":"no"));
+ BX_INFO((" SEP support: %s",BX_SUPPORT_SEP?"yes":"no"));
+ BX_INFO(("Optimization configuration"));
+ BX_INFO((" Guest2HostTLB support: %s",BX_SupportGuest2HostTLB?"yes":"no"));
+ BX_INFO((" RepeatSpeedups support: %s",BX_SupportRepeatSpeedups?"yes":"no"));
+ BX_INFO((" Icache support: %s",BX_SupportICache?"yes":"no"));
+ BX_INFO((" Host Asm support: %s",BX_SupportHostAsms?"yes":"no"));
+#endif /* BX_USE_VMX */
+
+ // set up memory and CPU objects
+#if BX_SUPPORT_APIC
+ bx_generic_apic_c::reset_all_ids ();
+#endif
+
+#ifndef BX_USE_VMX
+ // Check if there is a romimage
+ if (strcmp(bx_options.rom.Opath->getptr (),"") == 0) {
+ BX_ERROR(("No romimage to load. Is your bochsrc file loaded/valid ?"));
+ }
+
+#if BX_SMP_PROCESSORS==1
+ BX_MEM(0)->init_memory(bx_options.memory.Osize->get () * 1024*1024);
+
+ // First load the optional ROM images
+ if (strcmp(bx_options.optrom[0].Opath->getptr (),"") !=0 )
+ BX_MEM(0)->load_ROM(bx_options.optrom[0].Opath->getptr (), bx_options.optrom[0].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[1].Opath->getptr (),"") !=0 )
+ BX_MEM(0)->load_ROM(bx_options.optrom[1].Opath->getptr (), bx_options.optrom[1].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[2].Opath->getptr (),"") !=0 )
+ BX_MEM(0)->load_ROM(bx_options.optrom[2].Opath->getptr (), bx_options.optrom[2].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[3].Opath->getptr (),"") !=0 )
+ BX_MEM(0)->load_ROM(bx_options.optrom[3].Opath->getptr (), bx_options.optrom[3].Oaddress->get (), 2);
+
+ // Then Load the BIOS and VGABIOS
+ BX_MEM(0)->load_ROM(bx_options.rom.Opath->getptr (), bx_options.rom.Oaddress->get (), 0);
+ BX_MEM(0)->load_ROM(bx_options.vgarom.Opath->getptr (), 0xc0000, 1);
+
+ BX_CPU(0)->init (BX_MEM(0));
+ BX_CPU(0)->set_cpu_id(0);
+#if BX_SUPPORT_APIC
+ BX_CPU(0)->local_apic.set_id (0);
+#endif
+ BX_INSTR_INIT(0);
+ BX_CPU(0)->reset(BX_RESET_HARDWARE);
+#else
+ // SMP initialization
+ bx_mem_array[0] = new BX_MEM_C ();
+ bx_mem_array[0]->init_memory(bx_options.memory.Osize->get () * 1024*1024);
+
+ // First load the optional ROM images
+ if (strcmp(bx_options.optrom[0].Opath->getptr (),"") !=0 )
+ bx_mem_array[0]->load_ROM(bx_options.optrom[0].Opath->getptr (), bx_options.optrom[0].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[1].Opath->getptr (),"") !=0 )
+ bx_mem_array[0]->load_ROM(bx_options.optrom[1].Opath->getptr (), bx_options.optrom[1].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[2].Opath->getptr (),"") !=0 )
+ bx_mem_array[0]->load_ROM(bx_options.optrom[2].Opath->getptr (), bx_options.optrom[2].Oaddress->get (), 2);
+ if (strcmp(bx_options.optrom[3].Opath->getptr (),"") !=0 )
+ bx_mem_array[0]->load_ROM(bx_options.optrom[3].Opath->getptr (), bx_options.optrom[3].Oaddress->get (), 2);
+
+ // Then Load the BIOS and VGABIOS
+ bx_mem_array[0]->load_ROM(bx_options.rom.Opath->getptr (), bx_options.rom.Oaddress->get (), 0);
+ bx_mem_array[0]->load_ROM(bx_options.vgarom.Opath->getptr (), 0xc0000, 1);
+
+ for (int i=0; i<BX_SMP_PROCESSORS; i++) {
+ BX_CPU(i) = new BX_CPU_C;
+ BX_CPU(i)->init (bx_mem_array[0]);
+ // assign apic ID from the index of this loop
+ // if !BX_SUPPORT_APIC, this will not compile.
+ BX_CPU(i)->set_cpu_id(i);
+ BX_CPU(i)->local_apic.set_id (i);
+ BX_INSTR_INIT(i);
+ BX_CPU(i)->reset(BX_RESET_HARDWARE);
+ }
+#endif
+#else
+ // Assume UP for now for VMX
+ bx_mem.init_memory(megabytes * 1024 * 1024);
+ bx_cpu.init(&bx_mem);
+#endif // BX_USE_VMX
+
+#if BX_DEBUGGER == 0
+ DEV_init_devices();
+ DEV_reset_devices(BX_RESET_HARDWARE);
+ bx_gui->init_signal_handlers ();
+ bx_pc_system.start_timers();
+#endif
+ BX_DEBUG(("bx_init_hardware is setting signal handlers"));
+// if not using debugger, then we can take control of SIGINT.
+#if !BX_DEBUGGER
+ signal(SIGINT, bx_signal_handler);
+#endif
+
+#if BX_SHOW_IPS
+#ifndef __MINGW32__
+ signal(SIGALRM, bx_signal_handler);
+#endif
+ alarm( 1 );
+#endif
+
+ return(0);
+}
+
+
+
+ void
+bx_init_bx_dbg (void)
+{
+ bx_dbg.floppy = 0;
+ bx_dbg.keyboard = 0;
+ bx_dbg.video = 0;
+ bx_dbg.disk = 0;
+ bx_dbg.pit = 0;
+ bx_dbg.pic = 0;
+ bx_dbg.bios = 0;
+ bx_dbg.cmos = 0;
+ bx_dbg.a20 = 0;
+ bx_dbg.interrupts = 0;
+ bx_dbg.exceptions = 0;
+ bx_dbg.unsupported = 0;
+ bx_dbg.temp = 0;
+ bx_dbg.reset = 0;
+ bx_dbg.mouse = 0;
+ bx_dbg.io = 0;
+ bx_dbg.debugger = 0;
+ bx_dbg.xms = 0;
+ bx_dbg.v8086 = 0;
+ bx_dbg.paging = 0;
+ bx_dbg.creg = 0;
+ bx_dbg.dreg = 0;
+ bx_dbg.dma = 0;
+ bx_dbg.unsupported_io = 0;
+ bx_dbg.record_io = 0;
+ bx_dbg.serial = 0;
+ bx_dbg.cdrom = 0;
+#ifdef MAGIC_BREAKPOINT
+ bx_dbg.magic_break_enabled = 0;
+#endif
+
+}
+
+
+int
+bx_atexit(void)
+{
+ static bx_bool been_here = 0;
+ if (been_here) return 1; // protect from reentry
+ been_here = 1;
+
+ // in case we ended up in simulation mode, change back to config mode
+ // so that the user can see any messages left behind on the console.
+ SIM->set_display_mode (DISP_MODE_CONFIG);
+
+#if BX_PROVIDE_DEVICE_MODELS==1
+ bx_pc_system.exit();
+#endif
+
+#if BX_DEBUGGER == 0
+ if (SIM && SIM->get_init_done ()) {
+ for (int cpu=0; cpu<BX_SMP_PROCESSORS; cpu++)
+ if (BX_CPU(cpu)) BX_CPU(cpu)->atexit();
+ }
+#endif
+
+#if BX_PCI_SUPPORT
+ if (bx_options.Oi440FXSupport->get ()) {
+ bx_devices.pluginPciBridge->print_i440fx_state();
+ }
+#endif
+
+ // restore signal handling to defaults
+#if !BX_DEBUGGER
+ BX_INFO (("restoring default signal behavior"));
+ signal(SIGINT, SIG_DFL);
+#endif
+
+#if BX_SHOW_IPS
+#ifndef __MINGW32__
+ signal(SIGALRM, SIG_DFL);
+#endif
+#endif
+ return 0;
+}
+
+#if BX_PROVIDE_MAIN
+
+char *
+bx_find_bochsrc ()
+{
+ FILE *fd = NULL;
+ char rcfile[512];
+ Bit32u retry = 0, found = 0;
+ // try several possibilities for the bochsrc before giving up
+ while (!found) {
+ rcfile[0] = 0;
+ switch (retry++) {
+ case 0: strcpy (rcfile, ".bochsrc"); break;
+ case 1: strcpy (rcfile, "bochsrc"); break;
+ case 2: strcpy (rcfile, "bochsrc.txt"); break;
+#ifdef WIN32
+ case 3: strcpy (rcfile, "bochsrc.bxrc"); break;
+#elif !BX_WITH_MACOS
+ // only try this on unix
+ case 3:
+ {
+ char *ptr = getenv("HOME");
+ if (ptr) snprintf (rcfile, sizeof(rcfile), "%s/.bochsrc", ptr);
+ }
+ break;
+ case 4: strcpy (rcfile, "/etc/bochsrc"); break;
+#endif
+ default:
+ return NULL;
+ }
+ if (rcfile[0]) {
+ BX_DEBUG (("looking for configuration in %s", rcfile));
+ fd = fopen(rcfile, "r");
+ if (fd) found = 1;
+ }
+ }
+ assert (fd != NULL && rcfile[0] != 0);
+ fclose (fd);
+ return strdup (rcfile);
+}
+
+ static int
+parse_bochsrc(char *rcfile)
+{
+ FILE *fd = NULL;
+ char *ret;
+ char line[512];
+
+ // try several possibilities for the bochsrc before giving up
+
+ bochsrc_include_count++;
+
+ fd = fopen (rcfile, "r");
+ if (fd == NULL) return -1;
+
+ int retval = 0;
+ do {
+ ret = fgets(line, sizeof(line)-1, fd);
+ line[sizeof(line) - 1] = '\0';
+ int len = strlen(line);
+ if (len>0)
+ line[len-1] = '\0';
+ if ((ret != NULL) && strlen(line)) {
+ if (parse_line_unformatted(rcfile, line) < 0) {
+ retval = -1;
+ break; // quit parsing after first error
+ }
+ }
+ } while (!feof(fd));
+ fclose(fd);
+ bochsrc_include_count--;
+ return retval;
+}
+
+ static Bit32s
+parse_line_unformatted(char *context, char *line)
+{
+#define MAX_PARAMS_LEN 40
+ char *ptr;
+ unsigned i, string_i;
+ char string[512];
+ char *params[MAX_PARAMS_LEN];
+ int num_params;
+ bx_bool inquotes = 0;
+ bx_bool comment = 0;
+
+ memset(params, 0, sizeof(params));
+ if (line == NULL) return 0;
+
+ // if passed nothing but whitespace, just return
+ for (i=0; i<strlen(line); i++) {
+ if (!isspace(line[i])) break;
+ }
+ if (i>=strlen(line))
+ return 0;
+
+ num_params = 0;
+
+ if (!strncmp(line, "#include", 8))
+ ptr = strtok(line, " ");
+ else
+ ptr = strtok(line, ":");
+ while ((ptr) && (!comment)) {
+ string_i = 0;
+ for (i=0; i<strlen(ptr); i++) {
+ if (ptr[i] == '"')
+ inquotes = !inquotes;
+ else if ((ptr[i] == '#') && (strncmp(line+i, "#include", 8)) && !inquotes) {
+ comment = 1;
+ break;
+ } else {
+#if BX_HAVE_GETENV
+ // substitute environment variables.
+ if (ptr[i] == '$') {
+ char varname[512];
+ char *pv = varname;
+ char *value;
+ *pv = 0;
+ i++;
+ while (isalpha(ptr[i]) || ptr[i]=='_') {
+ *pv = ptr[i]; pv++; i++;
+ }
+ *pv = 0;
+ if (strlen(varname)<1 || !(value = getenv(varname))) {
+ BX_PANIC (("could not look up environment variable '%s'", varname));
+ } else {
+ // append value to the string
+ for (pv=value; *pv; pv++)
+ string[string_i++] = *pv;
+ }
+ }
+#endif
+ if (!isspace(ptr[i]) || inquotes) {
+ string[string_i++] = ptr[i];
+ }
+ }
+ }
+ string[string_i] = '\0';
+ if (string_i == 0) break;
+ if ( params[num_params] != NULL )
+ {
+ free(params[num_params]);
+ params[num_params] = NULL;
+ }
+ if ( num_params < MAX_PARAMS_LEN )
+ {
+ params[num_params++] = strdup (string);
+ ptr = strtok(NULL, ",");
+ }
+ else
+ {
+ BX_PANIC (("too many parameters, max is %d\n", MAX_PARAMS_LEN));
+ }
+ }
+ Bit32s retval = parse_line_formatted(context, num_params, &params[0]);
+ for (i=0; i < MAX_PARAMS_LEN; i++)
+ {
+ if ( params[i] != NULL )
+ {
+ free(params[i]);
+ params[i] = NULL;
+ }
+ }
+ return retval;
+}
+
+// These macros are called for all parse errors, so that we can easily
+// change the behavior of all occurrences.
+#define PARSE_ERR(x) \
+ do { BX_PANIC(x); return -1; } while (0)
+#define PARSE_WARN(x) \
+ BX_ERROR(x)
+
+ static Bit32s
+parse_line_formatted(char *context, int num_params, char *params[])
+{
+ int i;
+
+ if (num_params < 1) return 0;
+ if (num_params < 2) {
+ PARSE_ERR(("%s: a bochsrc option needs at least one parameter", context));
+ }
+
+ if (!strcmp(params[0], "#include")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: ignoring malformed #include directive.", context));
+ }
+ if (!strcmp(params[1], context)) {
+ PARSE_ERR(("%s: cannot include this file again.", context));
+ }
+ if (bochsrc_include_count == 2) {
+ PARSE_ERR(("%s: include directive in an included file not supported yet.", context));
+ }
+ bx_read_configuration(params[1]);
+ }
+ else if (!strcmp(params[0], "floppya")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "2_88=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_2_88);
+ }
+ else if (!strncmp(params[i], "1_44=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_1_44);
+ }
+ else if (!strncmp(params[i], "1_2=", 4)) {
+ bx_options.floppya.Opath->set (&params[i][4]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_1_2);
+ }
+ else if (!strncmp(params[i], "720k=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_720K);
+ }
+ else if (!strncmp(params[i], "360k=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_360K);
+ }
+ // use CMOS reserved types?
+ else if (!strncmp(params[i], "160k=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_160K);
+ }
+ else if (!strncmp(params[i], "180k=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_180K);
+ }
+ else if (!strncmp(params[i], "320k=", 5)) {
+ bx_options.floppya.Opath->set (&params[i][5]);
+ bx_options.floppya.Otype->set (BX_FLOPPY_320K);
+ }
+ else if (!strncmp(params[i], "status=ejected", 14)) {
+ bx_options.floppya.Ostatus->set (BX_EJECTED);
+ }
+ else if (!strncmp(params[i], "status=inserted", 15)) {
+ bx_options.floppya.Ostatus->set (BX_INSERTED);
+ }
+ else {
+ PARSE_ERR(("%s: floppya attribute '%s' not understood.", context,
+ params[i]));
+ }
+ }
+ }
+ else if (!strcmp(params[0], "gdbstub_port"))
+ {
+ if (num_params != 2)
+ {
+ fprintf(stderr, ".bochsrc: gdbstub_port directive: wrong # args.\n");
+ exit(1);
+ }
+ bx_options.gdbstub.port = atoi(params[1]);
+ }
+ else if (!strcmp(params[0], "gdbstub_text_base"))
+ {
+ if (num_params != 2)
+ {
+ fprintf(stderr, ".bochsrc: gdbstub_text_base directive: wrong # args.\n");
+ exit(1);
+ }
+ bx_options.gdbstub.text_base = atoi(params[1]);
+ }
+ else if (!strcmp(params[0], "gdbstub_data_base"))
+ {
+ if (num_params != 2)
+ {
+ fprintf(stderr, ".bochsrc: gdbstub_data_base directive: wrong # args.\n");
+ exit(1);
+ }
+ bx_options.gdbstub.data_base = atoi(params[1]);
+ }
+ else if (!strcmp(params[0], "gdbstub_bss_base"))
+ {
+ if (num_params != 2)
+ {
+ fprintf(stderr, ".bochsrc: gdbstub_bss_base directive: wrong # args.\n");
+ exit(1);
+ }
+ bx_options.gdbstub.bss_base = atoi(params[1]);
+ }
+
+ else if (!strcmp(params[0], "floppyb")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "2_88=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_2_88);
+ }
+ else if (!strncmp(params[i], "1_44=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_1_44);
+ }
+ else if (!strncmp(params[i], "1_2=", 4)) {
+ bx_options.floppyb.Opath->set (&params[i][4]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_1_2);
+ }
+ else if (!strncmp(params[i], "720k=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_720K);
+ }
+ else if (!strncmp(params[i], "360k=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_360K);
+ }
+ // use CMOS reserved types?
+ else if (!strncmp(params[i], "160k=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_160K);
+ }
+ else if (!strncmp(params[i], "180k=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_180K);
+ }
+ else if (!strncmp(params[i], "320k=", 5)) {
+ bx_options.floppyb.Opath->set (&params[i][5]);
+ bx_options.floppyb.Otype->set (BX_FLOPPY_320K);
+ }
+ else if (!strncmp(params[i], "status=ejected", 14)) {
+ bx_options.floppyb.Ostatus->set (BX_EJECTED);
+ }
+ else if (!strncmp(params[i], "status=inserted", 15)) {
+ bx_options.floppyb.Ostatus->set (BX_INSERTED);
+ }
+ else {
+ PARSE_ERR(("%s: floppyb attribute '%s' not understood.", context,
+ params[i]));
+ }
+ }
+ }
+
+ else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) == 4)) {
+ Bit8u channel = params[0][3];
+
+ if ((channel < '0') || (channel > '9')) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+ channel-='0';
+ if (channel >= BX_MAX_ATA_CHANNEL) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+
+ if ((num_params < 2) || (num_params > 5)) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+ else {
+ bx_options.ata[channel].Opresent->set (atol(&params[1][8]));
+ }
+
+ if (num_params > 2) {
+ if (strncmp(params[2], "ioaddr1=", 8)) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+ else {
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.ata[channel].Oioaddr1->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.ata[channel].Oioaddr1->set (strtoul (&params[2][8], NULL, 10));
+ }
+ }
+
+ if (num_params > 3) {
+ if (strncmp(params[3], "ioaddr2=", 8)) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+ else {
+ if ( (params[3][8] == '0') && (params[3][9] == 'x') )
+ bx_options.ata[channel].Oioaddr2->set (strtoul (&params[3][8], NULL, 16));
+ else
+ bx_options.ata[channel].Oioaddr2->set (strtoul (&params[3][8], NULL, 10));
+ }
+ }
+
+ if (num_params > 4) {
+ if (strncmp(params[4], "irq=", 4)) {
+ PARSE_ERR(("%s: ataX directive malformed.", context));
+ }
+ else {
+ bx_options.ata[channel].Oirq->set (atol(&params[4][4]));
+ }
+ }
+ }
+
+ // ataX-master, ataX-slave
+ else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) > 4)) {
+ Bit8u channel = params[0][3], slave = 0;
+
+ if ((channel < '0') || (channel > '9')) {
+ PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+ }
+ channel-='0';
+ if (channel >= BX_MAX_ATA_CHANNEL) {
+ PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+ }
+
+ if ((strcmp(&params[0][4], "-slave")) &&
+ (strcmp(&params[0][4], "-master"))) {
+ PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+ }
+
+ if (!strcmp(&params[0][4], "-slave")) {
+ slave = 1;
+ }
+
+ // This was originally meant to warn users about both diskc
+ // and ata0-master defined, but it also prevent users to
+ // override settings on the command line
+ // (see [ 661010 ] cannot override ata-settings from cmdline)
+ // if (bx_options.atadevice[channel][slave].Opresent->get()) {
+ // BX_INFO(("%s: %s device of ata channel %d already defined.", context, slave?"slave":"master",channel));
+ // }
+
+ for (i=1; i<num_params; i++) {
+ if (!strcmp(params[i], "type=disk")) {
+ bx_options.atadevice[channel][slave].Otype->set (BX_ATA_DEVICE_DISK);
+ }
+ else if (!strcmp(params[i], "type=cdrom")) {
+ bx_options.atadevice[channel][slave].Otype->set (BX_ATA_DEVICE_CDROM);
+ }
+ else if (!strcmp(params[i], "mode=flat")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_FLAT);
+ }
+ else if (!strcmp(params[i], "mode=concat")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_CONCAT);
+ }
+ else if (!strcmp(params[i], "mode=external")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_EXTDISKSIM);
+ }
+ else if (!strcmp(params[i], "mode=dll")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_DLL_HD);
+ }
+ else if (!strcmp(params[i], "mode=sparse")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_SPARSE);
+ }
+ else if (!strcmp(params[i], "mode=vmware3")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_VMWARE3);
+ }
+// else if (!strcmp(params[i], "mode=split")) {
+// bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_SPLIT);
+// }
+ else if (!strcmp(params[i], "mode=undoable")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_UNDOABLE);
+ }
+ else if (!strcmp(params[i], "mode=growing")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_GROWING);
+ }
+ else if (!strcmp(params[i], "mode=volatile")) {
+ bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_VOLATILE);
+ }
+// else if (!strcmp(params[i], "mode=z-undoable")) {
+// bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_Z_UNDOABLE);
+// }
+// else if (!strcmp(params[i], "mode=z-volatile")) {
+// bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_Z_VOLATILE);
+// }
+ else if (!strncmp(params[i], "path=", 5)) {
+ bx_options.atadevice[channel][slave].Opath->set (&params[i][5]);
+ }
+ else if (!strncmp(params[i], "cylinders=", 10)) {
+ bx_options.atadevice[channel][slave].Ocylinders->set (atol(&params[i][10]));
+ }
+ else if (!strncmp(params[i], "heads=", 6)) {
+ bx_options.atadevice[channel][slave].Oheads->set (atol(&params[i][6]));
+ }
+ else if (!strncmp(params[i], "spt=", 4)) {
+ bx_options.atadevice[channel][slave].Ospt->set (atol(&params[i][4]));
+ }
+ else if (!strncmp(params[i], "model=", 6)) {
+ bx_options.atadevice[channel][slave].Omodel->set(&params[i][6]);
+ }
+ else if (!strcmp(params[i], "biosdetect=none")) {
+ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_NONE);
+ }
+ else if (!strcmp(params[i], "biosdetect=cmos")) {
+ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_CMOS);
+ }
+ else if (!strcmp(params[i], "biosdetect=auto")) {
+ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_AUTO);
+ }
+ else if (!strcmp(params[i], "translation=none")) {
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_NONE);
+ }
+ else if (!strcmp(params[i], "translation=lba")) {
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LBA);
+ }
+ else if (!strcmp(params[i], "translation=large")) {
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LARGE);
+ }
+ else if (!strcmp(params[i], "translation=echs")) { // synonym of large
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LARGE);
+ }
+ else if (!strcmp(params[i], "translation=rechs")) {
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_RECHS);
+ }
+ else if (!strcmp(params[i], "translation=auto")) {
+ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_AUTO);
+ }
+ else if (!strcmp(params[i], "status=ejected")) {
+ bx_options.atadevice[channel][slave].Ostatus->set(BX_EJECTED);
+ }
+ else if (!strcmp(params[i], "status=inserted")) {
+ bx_options.atadevice[channel][slave].Ostatus->set(BX_INSERTED);
+ }
+ else if (!strncmp(params[i], "journal=", 8)) {
+ bx_options.atadevice[channel][slave].Ojournal->set(&params[i][8]);
+ }
+ else {
+ PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+ }
+ }
+
+ // Enables the ata device
+ bx_options.atadevice[channel][slave].Opresent->set(1);
+
+ // if enabled, check if device ok
+ if (bx_options.atadevice[channel][slave].Opresent->get() == 1) {
+ if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_DISK) {
+ if (strlen(bx_options.atadevice[channel][slave].Opath->getptr()) ==0)
+ PARSE_WARN(("%s: ataX-master/slave has empty path", context));
+ if ((bx_options.atadevice[channel][slave].Ocylinders->get() == 0) ||
+ (bx_options.atadevice[channel][slave].Oheads->get() ==0 ) ||
+ (bx_options.atadevice[channel][slave].Ospt->get() == 0)) {
+ PARSE_WARN(("%s: ataX-master/slave cannot have zero cylinders, heads, or sectors/track", context));
+ }
+ }
+ else if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_CDROM) {
+ if (strlen(bx_options.atadevice[channel][slave].Opath->getptr()) == 0) {
+ PARSE_WARN(("%s: ataX-master/slave has empty path", context));
+ }
+ }
+ else {
+ PARSE_WARN(("%s: ataX-master/slave: type should be specified", context));
+ }
+ }
+ }
+
+ // Legacy disk options emulation
+ else if (!strcmp(params[0], "diskc")) { // DEPRECATED
+ BX_INFO(("WARNING: diskc directive is deprecated, use ata0-master: instead"));
+ if (bx_options.atadevice[0][0].Opresent->get()) {
+ PARSE_ERR(("%s: master device of ata channel 0 already defined.", context));
+ }
+ if (num_params != 5) {
+ PARSE_ERR(("%s: diskc directive malformed.", context));
+ }
+ if (strncmp(params[1], "file=", 5) ||
+ strncmp(params[2], "cyl=", 4) ||
+ strncmp(params[3], "heads=", 6) ||
+ strncmp(params[4], "spt=", 4)) {
+ PARSE_ERR(("%s: diskc directive malformed.", context));
+ }
+ bx_options.ata[0].Opresent->set(1);
+ bx_options.atadevice[0][0].Otype->set (BX_ATA_DEVICE_DISK);
+ bx_options.atadevice[0][0].Opath->set (&params[1][5]);
+ bx_options.atadevice[0][0].Ocylinders->set (atol(&params[2][4]));
+ bx_options.atadevice[0][0].Oheads->set (atol(&params[3][6]));
+ bx_options.atadevice[0][0].Ospt->set (atol(&params[4][4]));
+ bx_options.atadevice[0][0].Opresent->set (1);
+ }
+ else if (!strcmp(params[0], "diskd")) { // DEPRECATED
+ BX_INFO(("WARNING: diskd directive is deprecated, use ata0-slave: instead"));
+ if (bx_options.atadevice[0][1].Opresent->get()) {
+ PARSE_ERR(("%s: slave device of ata channel 0 already defined.", context));
+ }
+ if (num_params != 5) {
+ PARSE_ERR(("%s: diskd directive malformed.", context));
+ }
+ if (strncmp(params[1], "file=", 5) ||
+ strncmp(params[2], "cyl=", 4) ||
+ strncmp(params[3], "heads=", 6) ||
+ strncmp(params[4], "spt=", 4)) {
+ PARSE_ERR(("%s: diskd directive malformed.", context));
+ }
+ bx_options.ata[0].Opresent->set(1);
+ bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_DISK);
+ bx_options.atadevice[0][1].Opath->set (&params[1][5]);
+ bx_options.atadevice[0][1].Ocylinders->set (atol( &params[2][4]));
+ bx_options.atadevice[0][1].Oheads->set (atol( &params[3][6]));
+ bx_options.atadevice[0][1].Ospt->set (atol( &params[4][4]));
+ bx_options.atadevice[0][1].Opresent->set (1);
+ }
+ else if (!strcmp(params[0], "cdromd")) { // DEPRECATED
+ BX_INFO(("WARNING: cdromd directive is deprecated, use ata0-slave: instead"));
+ if (bx_options.atadevice[0][1].Opresent->get()) {
+ PARSE_ERR(("%s: slave device of ata channel 0 already defined.", context));
+ }
+ if (num_params != 3) {
+ PARSE_ERR(("%s: cdromd directive malformed.", context));
+ }
+ if (strncmp(params[1], "dev=", 4) || strncmp(params[2], "status=", 7)) {
+ PARSE_ERR(("%s: cdromd directive malformed.", context));
+ }
+ bx_options.ata[0].Opresent->set(1);
+ bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_CDROM);
+ bx_options.atadevice[0][1].Opath->set (&params[1][4]);
+ if (!strcmp(params[2], "status=inserted"))
+ bx_options.atadevice[0][1].Ostatus->set (BX_INSERTED);
+ else if (!strcmp(params[2], "status=ejected"))
+ bx_options.atadevice[0][1].Ostatus->set (BX_EJECTED);
+ else {
+ PARSE_ERR(("%s: cdromd directive malformed.", context));
+ }
+ bx_options.atadevice[0][1].Opresent->set (1);
+ }
+
+ else if (!strcmp(params[0], "boot")) {
+ if (!strcmp(params[1], "a")) {
+ bx_options.Obootdrive->set (BX_BOOT_FLOPPYA);
+ } else if (!strcmp(params[1], "floppy")) {
+ bx_options.Obootdrive->set (BX_BOOT_FLOPPYA);
+ } else if (!strcmp(params[1], "c")) {
+ bx_options.Obootdrive->set (BX_BOOT_DISKC);
+ } else if (!strcmp(params[1], "disk")) {
+ bx_options.Obootdrive->set (BX_BOOT_DISKC);
+ } else if (!strcmp(params[1], "cdrom")) {
+ bx_options.Obootdrive->set (BX_BOOT_CDROM);
+ } else {
+ PARSE_ERR(("%s: boot directive with unknown boot device '%s'. use 'floppy', 'disk' or 'cdrom'.", context, params[1]));
+ }
+ }
+
+ else if (!strcmp(params[0], "com1")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.com[0].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "dev=", 4)) {
+ bx_options.com[0].Odev->set (&params[i][4]);
+ bx_options.com[0].Oenabled->set (1);
+ }
+ else {
+ PARSE_ERR(("%s: unknown parameter for com1 ignored.", context));
+ }
+ }
+ }
+#if 0
+ else if (!strcmp(params[0], "com2")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.com[1].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "dev=", 4)) {
+ bx_options.com[1].Odev->set (&params[i][4]);
+ bx_options.com[1].Oenabled->set (1);
+ }
+ else {
+ PARSE_ERR(("%s: unknown parameter for com2 ignored.", context));
+ }
+ }
+ }
+ else if (!strcmp(params[0], "com3")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.com[2].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "dev=", 4)) {
+ bx_options.com[2].Odev->set (&params[i][4]);
+ bx_options.com[2].Oenabled->set (1);
+ }
+ else {
+ PARSE_ERR(("%s: unknown parameter for com3 ignored.", context));
+ }
+ }
+ }
+ else if (!strcmp(params[0], "com4")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.com[3].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "dev=", 4)) {
+ bx_options.com[3].Odev->set (&params[i][4]);
+ bx_options.com[3].Oenabled->set (1);
+ }
+ else {
+ PARSE_ERR(("%s: unknown parameter for com4 ignored.", context));
+ }
+ }
+ }
+#endif
+ else if (!strcmp(params[0], "usb1")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.usb[0].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "ioaddr=", 7)) {
+ if ( (params[i][7] == '0') && (params[i][8] == 'x') )
+ bx_options.usb[0].Oioaddr->set (strtoul (&params[i][7], NULL, 16));
+ else
+ bx_options.usb[0].Oioaddr->set (strtoul (&params[i][7], NULL, 10));
+ bx_options.usb[0].Oenabled->set (1);
+ }
+ else if (!strncmp(params[i], "irq=", 4)) {
+ bx_options.usb[0].Oirq->set (atol(&params[i][4]));
+ }
+ else {
+ PARSE_ERR(("%s: unknown parameter for usb1 ignored.", context));
+ }
+ }
+ }
+ else if (!strcmp(params[0], "floppy_bootsig_check")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+ }
+ if (strncmp(params[1], "disabled=", 9)) {
+ PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+ }
+ if (params[1][9] == '0')
+ bx_options.OfloppySigCheck->set (0);
+ else if (params[1][9] == '1')
+ bx_options.OfloppySigCheck->set (1);
+ else {
+ PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "log")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: log directive has wrong # args.", context));
+ }
+ bx_options.log.Ofilename->set (params[1]);
+ }
+ else if (!strcmp(params[0], "logprefix")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: logprefix directive has wrong # args.", context));
+ }
+ bx_options.log.Oprefix->set (params[1]);
+ }
+ else if (!strcmp(params[0], "debugger_log")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: debugger_log directive has wrong # args.", context));
+ }
+ bx_options.log.Odebugger_filename->set (params[1]);
+ }
+ else if (!strcmp(params[0], "panic")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: panic directive malformed.", context));
+ }
+ if (strncmp(params[1], "action=", 7)) {
+ PARSE_ERR(("%s: panic directive malformed.", context));
+ }
+ char *action = 7 + params[1];
+ if (!strcmp(action, "fatal"))
+ SIM->set_default_log_action (LOGLEV_PANIC, ACT_FATAL);
+ else if (!strcmp (action, "report"))
+ SIM->set_default_log_action (LOGLEV_PANIC, ACT_REPORT);
+ else if (!strcmp (action, "ignore"))
+ SIM->set_default_log_action (LOGLEV_PANIC, ACT_IGNORE);
+ else if (!strcmp (action, "ask"))
+ SIM->set_default_log_action (LOGLEV_PANIC, ACT_ASK);
+ else {
+ PARSE_ERR(("%s: panic directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "pass")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: pass directive malformed.", context));
+ }
+ if (strncmp(params[1], "action=", 7)) {
+ PARSE_ERR(("%s: pass directive malformed.", context));
+ }
+ char *action = 7 + params[1];
+ if (!strcmp(action, "fatal"))
+ SIM->set_default_log_action (LOGLEV_PASS, ACT_FATAL);
+ else if (!strcmp (action, "report"))
+ SIM->set_default_log_action (LOGLEV_PASS, ACT_REPORT);
+ else if (!strcmp (action, "ignore"))
+ SIM->set_default_log_action (LOGLEV_PASS, ACT_IGNORE);
+ else if (!strcmp (action, "ask"))
+ SIM->set_default_log_action (LOGLEV_PASS, ACT_ASK);
+ else {
+ PARSE_ERR(("%s: pass directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "error")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: error directive malformed.", context));
+ }
+ if (strncmp(params[1], "action=", 7)) {
+ PARSE_ERR(("%s: error directive malformed.", context));
+ }
+ char *action = 7 + params[1];
+ if (!strcmp(action, "fatal"))
+ SIM->set_default_log_action (LOGLEV_ERROR, ACT_FATAL);
+ else if (!strcmp (action, "report"))
+ SIM->set_default_log_action (LOGLEV_ERROR, ACT_REPORT);
+ else if (!strcmp (action, "ignore"))
+ SIM->set_default_log_action (LOGLEV_ERROR, ACT_IGNORE);
+ else if (!strcmp (action, "ask"))
+ SIM->set_default_log_action (LOGLEV_ERROR, ACT_ASK);
+ else {
+ PARSE_ERR(("%s: error directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "info")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: info directive malformed.", context));
+ }
+ if (strncmp(params[1], "action=", 7)) {
+ PARSE_ERR(("%s: info directive malformed.", context));
+ }
+ char *action = 7 + params[1];
+ if (!strcmp(action, "fatal"))
+ SIM->set_default_log_action (LOGLEV_INFO, ACT_FATAL);
+ else if (!strcmp (action, "report"))
+ SIM->set_default_log_action (LOGLEV_INFO, ACT_REPORT);
+ else if (!strcmp (action, "ignore"))
+ SIM->set_default_log_action (LOGLEV_INFO, ACT_IGNORE);
+ else if (!strcmp (action, "ask"))
+ SIM->set_default_log_action (LOGLEV_INFO, ACT_ASK);
+ else {
+ PARSE_ERR(("%s: info directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "debug")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: debug directive malformed.", context));
+ }
+ if (strncmp(params[1], "action=", 7)) {
+ PARSE_ERR(("%s: debug directive malformed.", context));
+ }
+ char *action = 7 + params[1];
+ if (!strcmp(action, "fatal"))
+ SIM->set_default_log_action (LOGLEV_DEBUG, ACT_FATAL);
+ else if (!strcmp (action, "report"))
+ SIM->set_default_log_action (LOGLEV_DEBUG, ACT_REPORT);
+ else if (!strcmp (action, "ignore"))
+ SIM->set_default_log_action (LOGLEV_DEBUG, ACT_IGNORE);
+ else if (!strcmp (action, "ask"))
+ SIM->set_default_log_action (LOGLEV_DEBUG, ACT_ASK);
+ else {
+ PARSE_ERR(("%s: debug directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "romimage")) {
+ if (num_params != 3) {
+ PARSE_ERR(("%s: romimage directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "file=", 5)) {
+ PARSE_ERR(("%s: romimage directive malformed.", context));
+ }
+ if (strncmp(params[2], "address=", 8)) {
+ PARSE_ERR(("%s: romimage directive malformed.", context));
+ }
+ bx_options.rom.Opath->set (&params[1][5]);
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.rom.Oaddress->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.rom.Oaddress->set (strtoul (&params[2][8], NULL, 10));
+ }
+ else if (!strcmp(params[0], "optromimage1")) {
+ if (num_params != 3) {
+ PARSE_ERR(("%s: optromimage1 directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "file=", 5)) {
+ PARSE_ERR(("%s: optromimage1 directive malformed.", context));
+ }
+ if (strncmp(params[2], "address=", 8)) {
+ PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+ }
+ bx_options.optrom[0].Opath->set (&params[1][5]);
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.optrom[0].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.optrom[0].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+ }
+ else if (!strcmp(params[0], "optromimage2")) {
+ if (num_params != 3) {
+ PARSE_ERR(("%s: optromimage2 directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "file=", 5)) {
+ PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+ }
+ if (strncmp(params[2], "address=", 8)) {
+ PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+ }
+ bx_options.optrom[1].Opath->set (&params[1][5]);
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.optrom[1].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.optrom[1].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+ }
+ else if (!strcmp(params[0], "optromimage3")) {
+ if (num_params != 3) {
+ PARSE_ERR(("%s: optromimage3 directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "file=", 5)) {
+ PARSE_ERR(("%s: optromimage3 directive malformed.", context));
+ }
+ if (strncmp(params[2], "address=", 8)) {
+ PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+ }
+ bx_options.optrom[2].Opath->set (&params[1][5]);
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.optrom[2].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.optrom[2].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+ }
+ else if (!strcmp(params[0], "optromimage4")) {
+ if (num_params != 3) {
+ PARSE_ERR(("%s: optromimage4 directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "file=", 5)) {
+ PARSE_ERR(("%s: optromimage4 directive malformed.", context));
+ }
+ if (strncmp(params[2], "address=", 8)) {
+ PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+ }
+ bx_options.optrom[3].Opath->set (&params[1][5]);
+ if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+ bx_options.optrom[3].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+ else
+ bx_options.optrom[3].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+ }
+ else if (!strcmp(params[0], "vgaromimage")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: vgaromimage directive: wrong # args.", context));
+ }
+ bx_options.vgarom.Opath->set (params[1]);
+ }
+ else if (!strcmp(params[0], "vga_update_interval")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: vga_update_interval directive: wrong # args.", context));
+ }
+ bx_options.Ovga_update_interval->set (atol(params[1]));
+ if (bx_options.Ovga_update_interval->get () < 50000) {
+ BX_INFO(("%s: vga_update_interval seems awfully small!", context));
+ }
+ }
+ else if (!strcmp(params[0], "keyboard_serial_delay")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: keyboard_serial_delay directive: wrong # args.", context));
+ }
+ bx_options.Okeyboard_serial_delay->set (atol(params[1]));
+ if (bx_options.Okeyboard_serial_delay->get () < 5) {
+ PARSE_ERR (("%s: keyboard_serial_delay not big enough!", context));
+ }
+ }
+ else if (!strcmp(params[0], "keyboard_paste_delay")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: keyboard_paste_delay directive: wrong # args.", context));
+ }
+ bx_options.Okeyboard_paste_delay->set (atol(params[1]));
+ if (bx_options.Okeyboard_paste_delay->get () < 1000) {
+ PARSE_ERR (("%s: keyboard_paste_delay not big enough!", context));
+ }
+ }
+ else if (!strcmp(params[0], "megs")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: megs directive: wrong # args.", context));
+ }
+ bx_options.memory.Osize->set (atol(params[1]));
+ }
+ else if (!strcmp(params[0], "floppy_command_delay")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: floppy_command_delay directive: wrong # args.", context));
+ }
+ bx_options.Ofloppy_command_delay->set (atol(params[1]));
+ if (bx_options.Ofloppy_command_delay->get () < 100) {
+ PARSE_ERR(("%s: floppy_command_delay not big enough!", context));
+ }
+ }
+ else if (!strcmp(params[0], "ips")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: ips directive: wrong # args.", context));
+ }
+ bx_options.Oips->set (atol(params[1]));
+ if (bx_options.Oips->get () < BX_MIN_IPS) {
+ BX_ERROR(("%s: WARNING: ips is AWFULLY low!", context));
+ }
+ }
+ else if (!strcmp(params[0], "pit")) { // Deprecated
+ if (num_params != 2) {
+ PARSE_ERR(("%s: pit directive: wrong # args.", context));
+ }
+ BX_INFO(("WARNING: pit directive is deprecated, use clock: instead"));
+ if (!strncmp(params[1], "realtime=", 9)) {
+ switch (params[1][9]) {
+ case '0':
+ BX_INFO(("WARNING: not disabling realtime pit"));
+ break;
+ case '1': bx_options.clock.Osync->set (BX_CLOCK_SYNC_REALTIME); break;
+ default: PARSE_ERR(("%s: pit expected realtime=[0|1] arg", context));
+ }
+ }
+ else PARSE_ERR(("%s: pit expected realtime=[0|1] arg", context));
+ }
+ else if (!strcmp(params[0], "max_ips")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: max_ips directive: wrong # args.", context));
+ }
+ BX_INFO(("WARNING: max_ips not implemented"));
+ }
+ else if (!strcmp(params[0], "text_snapshot_check")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: text_snapshot_check directive: wrong # args.", context));
+ }
+ if (!strncmp(params[1], "enable", 6)) {
+ bx_options.Otext_snapshot_check->set (1);
+ }
+ else if (!strncmp(params[1], "disable", 7)) {
+ bx_options.Otext_snapshot_check->set (0);
+ }
+ else bx_options.Otext_snapshot_check->set (!!(atol(params[1])));
+ }
+ else if (!strcmp(params[0], "mouse")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: mouse directive malformed.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: mouse directive malformed.", context));
+ }
+ if (params[1][8] == '0' || params[1][8] == '1')
+ bx_options.Omouse_enabled->set (params[1][8] - '0');
+ else
+ PARSE_ERR(("%s: mouse directive malformed.", context));
+ }
+ else if (!strcmp(params[0], "private_colormap")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: private_colormap directive malformed.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: private_colormap directive malformed.", context));
+ }
+ if (params[1][8] == '0' || params[1][8] == '1')
+ bx_options.Oprivate_colormap->set (params[1][8] - '0');
+ else {
+ PARSE_ERR(("%s: private_colormap directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "fullscreen")) {
+#if BX_WITH_AMIGAOS
+ if (num_params != 2) {
+ PARSE_ERR(("%s: fullscreen directive malformed.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: fullscreen directive malformed.", context));
+ }
+ if (params[1][8] == '0' || params[1][8] == '1') {
+ bx_options.Ofullscreen->set (params[1][8] - '0');
+ } else {
+ PARSE_ERR(("%s: fullscreen directive malformed.", context));
+ }
+#endif
+ }
+ else if (!strcmp(params[0], "screenmode")) {
+#if BX_WITH_AMIGAOS
+ if (num_params != 2) {
+ PARSE_ERR(("%s: screenmode directive malformed.", context));
+ }
+ if (strncmp(params[1], "name=", 5)) {
+ PARSE_ERR(("%s: screenmode directive malformed.", context));
+ }
+ bx_options.Oscreenmode->set (strdup(&params[1][5]));
+#endif
+ }
+
+ else if (!strcmp(params[0], "sb16")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "midi=", 5)) {
+ bx_options.sb16.Omidifile->set (strdup(&params[i][5]));
+ }
+ else if (!strncmp(params[i], "midimode=", 9)) {
+ bx_options.sb16.Omidimode->set (atol(&params[i][9]));
+ }
+ else if (!strncmp(params[i], "wave=", 5)) {
+ bx_options.sb16.Owavefile->set (strdup(&params[i][5]));
+ }
+ else if (!strncmp(params[i], "wavemode=", 9)) {
+ bx_options.sb16.Owavemode->set (atol(&params[i][9]));
+ }
+ else if (!strncmp(params[i], "log=", 4)) {
+ bx_options.sb16.Ologfile->set (strdup(&params[i][4]));
+ }
+ else if (!strncmp(params[i], "loglevel=", 9)) {
+ bx_options.sb16.Ologlevel->set (atol(&params[i][9]));
+ }
+ else if (!strncmp(params[i], "dmatimer=", 9)) {
+ bx_options.sb16.Odmatimer->set (atol(&params[i][9]));
+ }
+ }
+ if (bx_options.sb16.Odmatimer->get () > 0)
+ bx_options.sb16.Opresent->set (1);
+ }
+
+ else if (!strcmp(params[0], "parport1")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.par[0].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "file=", 5)) {
+ bx_options.par[0].Ooutfile->set (strdup(&params[i][5]));
+ bx_options.par[0].Oenabled->set (1);
+ }
+ else {
+ BX_ERROR(("%s: unknown parameter for parport1 ignored.", context));
+ }
+ }
+ }
+
+#if 0
+ else if (!strcmp(params[0], "parport2")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.par[1].Oenabled->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "file=", 5)) {
+ bx_options.par[1].Ooutfile->set (strdup(&params[i][5]));
+ bx_options.par[1].Oenabled->set (1);
+ }
+ else {
+ BX_ERROR(("%s: unknown parameter for parport2 ignored.", context));
+ }
+ }
+ }
+#endif
+
+ else if (!strcmp(params[0], "i440fxsupport")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+ }
+ if (params[1][8] == '0')
+ bx_options.Oi440FXSupport->set (0);
+ else if (params[1][8] == '1')
+ bx_options.Oi440FXSupport->set (1);
+ else {
+ PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "newharddrivesupport")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+ }
+ if (params[1][8] == '0')
+ bx_options.OnewHardDriveSupport->set (0);
+ else if (params[1][8] == '1')
+ bx_options.OnewHardDriveSupport->set (1);
+ else {
+ PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+ }
+ }
+ else if (!strcmp(params[0], "cmosimage")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: cmosimage directive: wrong # args.", context));
+ }
+ bx_options.cmos.Opath->set (strdup(params[1]));
+ bx_options.cmos.OcmosImage->set (1); // CMOS Image is true
+ }
+ else if (!strcmp(params[0], "time0")) { // Deprectated
+ BX_INFO(("WARNING: time0 directive is deprecated, use clock: instead"));
+ if (num_params != 2) {
+ PARSE_ERR(("%s: time0 directive: wrong # args.", context));
+ }
+ bx_options.clock.Otime0->set (atoi(params[1]));
+ }
+ else if (!strcmp(params[0], "clock")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "sync=", 5)) {
+ bx_options.clock.Osync->set_by_name (&params[i][5]);
+ }
+ else if (!strcmp(params[i], "time0=local")) {
+ bx_options.clock.Otime0->set (BX_CLOCK_TIME0_LOCAL);
+ }
+ else if (!strcmp(params[i], "time0=utc")) {
+ bx_options.clock.Otime0->set (BX_CLOCK_TIME0_UTC);
+ }
+ else if (!strncmp(params[i], "time0=", 6)) {
+ bx_options.clock.Otime0->set (atoi(&params[i][6]));
+ }
+ else {
+ BX_ERROR(("%s: unknown parameter for clock ignored.", context));
+ }
+ }
+ }
+#ifdef MAGIC_BREAKPOINT
+ else if (!strcmp(params[0], "magic_break")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: magic_break directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "enabled=", 8)) {
+ PARSE_ERR(("%s: magic_break directive malformed.", context));
+ }
+ if (params[1][8] == '0') {
+ BX_INFO(("Ignoring magic break points"));
+ bx_dbg.magic_break_enabled = 0;
+ }
+ else if (params[1][8] == '1') {
+ BX_INFO(("Stopping on magic break points"));
+ bx_dbg.magic_break_enabled = 1;
+ }
+ else {
+ PARSE_ERR(("%s: magic_break directive malformed.", context));
+ }
+ }
+#endif
+ else if (!strcmp(params[0], "ne2k")) {
+ int tmp[6];
+ char tmpchar[6];
+ int valid = 0;
+ int n;
+ if (!bx_options.ne2k.Opresent->get ()) {
+ bx_options.ne2k.Oethmod->set_by_name ("null");
+ }
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "ioaddr=", 7)) {
+ bx_options.ne2k.Oioaddr->set (strtoul(&params[i][7], NULL, 16));
+ valid |= 0x01;
+ }
+ else if (!strncmp(params[i], "irq=", 4)) {
+ bx_options.ne2k.Oirq->set (atol(&params[i][4]));
+ valid |= 0x02;
+ }
+ else if (!strncmp(params[i], "mac=", 4)) {
+ n = sscanf(&params[i][4], "%x:%x:%x:%x:%x:%x",
+ &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5]);
+ if (n != 6) {
+ PARSE_ERR(("%s: ne2k mac address malformed.", context));
+ }
+ for (n=0;n<6;n++)
+ tmpchar[n] = (unsigned char)tmp[n];
+ bx_options.ne2k.Omacaddr->set (tmpchar);
+ valid |= 0x04;
+ }
+ else if (!strncmp(params[i], "ethmod=", 7)) {
+ if (!bx_options.ne2k.Oethmod->set_by_name (strdup(&params[i][7])))
+ PARSE_ERR(("%s: ethernet module '%s' not available", context, strdup(&params[i][7])));
+ }
+ else if (!strncmp(params[i], "ethdev=", 7)) {
+ bx_options.ne2k.Oethdev->set (strdup(&params[i][7]));
+ }
+ else if (!strncmp(params[i], "script=", 7)) {
+ bx_options.ne2k.Oscript->set (strdup(&params[i][7]));
+ }
+ else {
+ PARSE_ERR(("%s: ne2k directive malformed.", context));
+ }
+ }
+ if (!bx_options.ne2k.Opresent->get ()) {
+ if (valid == 0x07) {
+ bx_options.ne2k.Opresent->set (1);
+ }
+ else {
+ PARSE_ERR(("%s: ne2k directive incomplete (ioaddr, irq and mac are required)", context));
+ }
+ }
+ }
+
+ else if (!strcmp(params[0], "load32bitOSImage")) {
+ if ( (num_params!=4) && (num_params!=5) ) {
+ PARSE_ERR(("%s: load32bitOSImage directive: wrong # args.", context));
+ }
+ if (strncmp(params[1], "os=", 3)) {
+ PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+ }
+ if (!strcmp(&params[1][3], "nullkernel")) {
+ bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSNullKernel);
+ }
+ else if (!strcmp(&params[1][3], "linux")) {
+ bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSLinux);
+ }
+ else {
+ PARSE_ERR(("%s: load32bitOSImage: unsupported OS.", context));
+ }
+ if (strncmp(params[2], "path=", 5)) {
+ PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+ }
+ if (strncmp(params[3], "iolog=", 6)) {
+ PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+ }
+ bx_options.load32bitOSImage.Opath->set (strdup(&params[2][5]));
+ bx_options.load32bitOSImage.Oiolog->set (strdup(&params[3][6]));
+ if (num_params == 5) {
+ if (strncmp(params[4], "initrd=", 7)) {
+ PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+ }
+ bx_options.load32bitOSImage.Oinitrd->set (strdup(&params[4][7]));
+ }
+ }
+ else if (!strcmp(params[0], "keyboard_type")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: keyboard_type directive: wrong # args.", context));
+ }
+ if(strcmp(params[1],"xt")==0){
+ bx_options.Okeyboard_type->set (BX_KBD_XT_TYPE);
+ }
+ else if(strcmp(params[1],"at")==0){
+ bx_options.Okeyboard_type->set (BX_KBD_AT_TYPE);
+ }
+ else if(strcmp(params[1],"mf")==0){
+ bx_options.Okeyboard_type->set (BX_KBD_MF_TYPE);
+ }
+ else{
+ PARSE_ERR(("%s: keyboard_type directive: wrong arg %s.", context,params[1]));
+ }
+ }
+
+ else if (!strcmp(params[0], "keyboard_mapping")
+ ||!strcmp(params[0], "keyboardmapping")) {
+ for (i=1; i<num_params; i++) {
+ if (!strncmp(params[i], "enabled=", 8)) {
+ bx_options.keyboard.OuseMapping->set (atol(&params[i][8]));
+ }
+ else if (!strncmp(params[i], "map=", 4)) {
+ bx_options.keyboard.Okeymap->set (strdup(&params[i][4]));
+ }
+ }
+ }
+ else if (!strcmp(params[0], "user_shortcut")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: user_shortcut directive: wrong # args.", context));
+ }
+ if(!strncmp(params[1], "keys=", 4)) {
+ bx_options.Ouser_shortcut->set (strdup(&params[1][5]));
+ }
+ }
+ else if (!strcmp(params[0], "config_interface")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: config_interface directive: wrong # args.", context));
+ }
+ if (!bx_options.Osel_config->set_by_name (params[1]))
+ PARSE_ERR(("%s: config_interface '%s' not available", context, params[1]));
+ }
+ else if (!strcmp(params[0], "display_library")) {
+ if (num_params != 2) {
+ PARSE_ERR(("%s: display_library directive: wrong # args.", context));
+ }
+ if (!bx_options.Osel_displaylib->set_by_name (params[1]))
+ PARSE_ERR(("%s: display library '%s' not available", context, params[1]));
+ }
+ else {
+ PARSE_ERR(( "%s: directive '%s' not understood", context, params[0]));
+ }
+ return 0;
+}
+
+static char *fdtypes[] = {
+ "none", "1_2", "1_44", "2_88", "720k", "360k", "160k", "180k", "320k"
+};
+
+
+int
+bx_write_floppy_options (FILE *fp, int drive, bx_floppy_options *opt)
+{
+ BX_ASSERT (drive==0 || drive==1);
+ if (opt->Otype->get () == BX_FLOPPY_NONE) {
+ fprintf (fp, "# no floppy%c\n", (char)'a'+drive);
+ return 0;
+ }
+ BX_ASSERT (opt->Otype->get () > BX_FLOPPY_NONE && opt->Otype->get () <= BX_FLOPPY_LAST);
+ fprintf (fp, "floppy%c: %s=\"%s\", status=%s\n",
+ (char)'a'+drive,
+ fdtypes[opt->Otype->get () - BX_FLOPPY_NONE],
+ opt->Opath->getptr (),
+ opt->Ostatus->get ()==BX_EJECTED ? "ejected" : "inserted");
+ return 0;
+}
+
+int
+bx_write_ata_options (FILE *fp, Bit8u channel, bx_ata_options *opt)
+{
+ fprintf (fp, "ata%d: enabled=%d", channel, opt->Opresent->get());
+
+ if (opt->Opresent->get()) {
+ fprintf (fp, ", ioaddr1=0x%x, ioaddr2=0x%x, irq=%d", opt->Oioaddr1->get(),
+ opt->Oioaddr2->get(), opt->Oirq->get());
+ }
+
+ fprintf (fp, "\n");
+ return 0;
+}
+
+int
+bx_write_atadevice_options (FILE *fp, Bit8u channel, Bit8u drive, bx_atadevice_options *opt)
+{
+ if (opt->Opresent->get()) {
+ fprintf (fp, "ata%d-%s: ", channel, drive==0?"master":"slave");
+
+ if (opt->Otype->get() == BX_ATA_DEVICE_DISK) {
+ fprintf (fp, "type=disk");
+
+ switch(opt->Omode->get()) {
+ case BX_ATA_MODE_FLAT:
+ fprintf (fp, ", mode=flat");
+ break;
+ case BX_ATA_MODE_CONCAT:
+ fprintf (fp, ", mode=concat");
+ break;
+ case BX_ATA_MODE_EXTDISKSIM:
+ fprintf (fp, ", mode=external");
+ break;
+ case BX_ATA_MODE_DLL_HD:
+ fprintf (fp, ", mode=dll");
+ break;
+ case BX_ATA_MODE_SPARSE:
+ fprintf (fp, ", mode=sparse");
+ break;
+ case BX_ATA_MODE_VMWARE3:
+ fprintf (fp, ", mode=vmware3");
+ break;
+// case BX_ATA_MODE_SPLIT:
+// fprintf (fp, ", mode=split");
+// break;
+ case BX_ATA_MODE_UNDOABLE:
+ fprintf (fp, ", mode=undoable");
+ break;
+ case BX_ATA_MODE_GROWING:
+ fprintf (fp, ", mode=growing");
+ break;
+ case BX_ATA_MODE_VOLATILE:
+ fprintf (fp, ", mode=volatile");
+ break;
+// case BX_ATA_MODE_Z_UNDOABLE:
+// fprintf (fp, ", mode=z-undoable");
+// break;
+// case BX_ATA_MODE_Z_VOLATILE:
+// fprintf (fp, ", mode=z-volatile");
+// break;
+ }
+
+ switch(opt->Otranslation->get()) {
+ case BX_ATA_TRANSLATION_NONE:
+ fprintf (fp, ", translation=none");
+ break;
+ case BX_ATA_TRANSLATION_LBA:
+ fprintf (fp, ", translation=lba");
+ break;
+ case BX_ATA_TRANSLATION_LARGE:
+ fprintf (fp, ", translation=large");
+ break;
+ case BX_ATA_TRANSLATION_RECHS:
+ fprintf (fp, ", translation=rechs");
+ break;
+ case BX_ATA_TRANSLATION_AUTO:
+ fprintf (fp, ", translation=auto");
+ break;
+ }
+
+ fprintf (fp, ", path=\"%s\", cylinders=%d, heads=%d, spt=%d",
+ opt->Opath->getptr(),
+ opt->Ocylinders->get(), opt->Oheads->get(), opt->Ospt->get());
+
+ if (opt->Ojournal->getptr() != NULL)
+ if ( strcmp(opt->Ojournal->getptr(), "") != 0)
+ fprintf (fp, ", journal=\"%s\"", opt->Ojournal->getptr());
+
+ }
+ else if (opt->Otype->get() == BX_ATA_DEVICE_CDROM) {
+ fprintf (fp, "type=cdrom, path=\"%s\", status=%s",
+ opt->Opath->getptr(),
+ opt->Ostatus->get ()==BX_EJECTED ? "ejected" : "inserted");
+ }
+
+ switch(opt->Obiosdetect->get()) {
+ case BX_ATA_BIOSDETECT_NONE:
+ fprintf (fp, ", biosdetect=none");
+ break;
+ case BX_ATA_BIOSDETECT_CMOS:
+ fprintf (fp, ", biosdetect=cmos");
+ break;
+ case BX_ATA_BIOSDETECT_AUTO:
+ fprintf (fp, ", biosdetect=auto");
+ break;
+ }
+ if (strlen(opt->Omodel->getptr())>0) {
+ fprintf (fp, ", model=\"%s\"", opt->Omodel->getptr());
+ }
+
+ fprintf (fp, "\n");
+ }
+ return 0;
+}
+
+int
+bx_write_parport_options (FILE *fp, bx_parport_options *opt, int n)
+{
+ fprintf (fp, "parport%d: enabled=%d", n, opt->Oenabled->get ());
+ if (opt->Oenabled->get ()) {
+ fprintf (fp, ", file=\"%s\"", opt->Ooutfile->getptr ());
+ }
+ fprintf (fp, "\n");
+ return 0;
+}
+
+int
+bx_write_serial_options (FILE *fp, bx_serial_options *opt, int n)
+{
+ fprintf (fp, "com%d: enabled=%d", n, opt->Oenabled->get ());
+ if (opt->Oenabled->get ()) {
+ fprintf (fp, ", dev=\"%s\"", opt->Odev->getptr ());
+ }
+ fprintf (fp, "\n");
+ return 0;
+}
+
+int
+bx_write_usb_options (FILE *fp, bx_usb_options *opt, int n)
+{
+ fprintf (fp, "usb%d: enabled=%d", n, opt->Oenabled->get ());
+ if (opt->Oenabled->get ()) {
+ fprintf (fp, ", ioaddr=0x%04x, irq=%d", opt->Oioaddr->get (),
+ opt->Oirq->get ());
+ }
+ fprintf (fp, "\n");
+ return 0;
+}
+
+int
+bx_write_sb16_options (FILE *fp, bx_sb16_options *opt)
+{
+ if (!opt->Opresent->get ()) {
+ fprintf (fp, "# no sb16\n");
+ return 0;
+ }
+ fprintf (fp, "sb16: midimode=%d, midi=%s, wavemode=%d, wave=%s, loglevel=%d, log=%s, dmatimer=%d\n", opt->Omidimode->get (), opt->Omidifile->getptr (), opt->Owavemode->get (), opt->Owavefile->getptr (), opt->Ologlevel->get (), opt->Ologfile->getptr (), opt->Odmatimer->get ());
+ return 0;
+}
+
+int
+bx_write_ne2k_options (FILE *fp, bx_ne2k_options *opt)
+{
+ if (!opt->Opresent->get ()) {
+ fprintf (fp, "# no ne2k\n");
+ return 0;
+ }
+ char *ptr = opt->Omacaddr->getptr ();
+ fprintf (fp, "ne2k: ioaddr=0x%x, irq=%d, mac=%02x:%02x:%02x:%02x:%02x:%02x, ethmod=%s, ethdev=%s, script=%s\n",
+ opt->Oioaddr->get (),
+ opt->Oirq->get (),
+ (unsigned int)(0xff & ptr[0]),
+ (unsigned int)(0xff & ptr[1]),
+ (unsigned int)(0xff & ptr[2]),
+ (unsigned int)(0xff & ptr[3]),
+ (unsigned int)(0xff & ptr[4]),
+ (unsigned int)(0xff & ptr[5]),
+ opt->Oethmod->get_choice(opt->Oethmod->get()),
+ opt->Oethdev->getptr (),
+ opt->Oscript->getptr ());
+ return 0;
+}
+
+int
+bx_write_loader_options (FILE *fp, bx_load32bitOSImage_t *opt)
+{
+ if (opt->OwhichOS->get () == 0) {
+ fprintf (fp, "# no loader\n");
+ return 0;
+ }
+ BX_ASSERT(opt->OwhichOS->get () == Load32bitOSLinux || opt->OwhichOS->get () == Load32bitOSNullKernel);
+ fprintf (fp, "load32bitOSImage: os=%s, path=%s, iolog=%s, initrd=%s\n",
+ (opt->OwhichOS->get () == Load32bitOSLinux) ? "linux" : "nullkernel",
+ opt->Opath->getptr (),
+ opt->Oiolog->getptr (),
+ opt->Oinitrd->getptr ());
+ return 0;
+}
+
+int
+bx_write_clock_options (FILE *fp, bx_clock_options *opt)
+{
+ fprintf (fp, "clock: ");
+
+ switch (opt->Osync->get()) {
+ case BX_CLOCK_SYNC_NONE:
+ fprintf (fp, "sync=none");
+ break;
+ case BX_CLOCK_SYNC_REALTIME:
+ fprintf (fp, "sync=realtime");
+ break;
+ case BX_CLOCK_SYNC_SLOWDOWN:
+ fprintf (fp, "sync=slowdown");
+ break;
+ case BX_CLOCK_SYNC_BOTH:
+ fprintf (fp, "sync=both");
+ break;
+ default:
+ BX_PANIC(("Unknown value for sync method"));
+ }
+
+ switch (opt->Otime0->get()) {
+ case 0: break;
+ case BX_CLOCK_TIME0_LOCAL:
+ fprintf (fp, ", time0=local");
+ break;
+ case BX_CLOCK_TIME0_UTC:
+ fprintf (fp, ", time0=utc");
+ break;
+ default:
+ fprintf (fp, ", time0=%u", opt->Otime0->get());
+ }
+
+ fprintf (fp, "\n");
+ return 0;
+}
+
+int
+bx_write_log_options (FILE *fp, bx_log_options *opt)
+{
+ fprintf (fp, "log: %s\n", opt->Ofilename->getptr ());
+ fprintf (fp, "logprefix: %s\n", opt->Oprefix->getptr ());
+ fprintf (fp, "debugger_log: %s\n", opt->Odebugger_filename->getptr ());
+ fprintf (fp, "panic: action=%s\n",
+ io->getaction(logfunctions::get_default_action (LOGLEV_PANIC)));
+ fprintf (fp, "error: action=%s\n",
+ io->getaction(logfunctions::get_default_action (LOGLEV_ERROR)));
+ fprintf (fp, "info: action=%s\n",
+ io->getaction(logfunctions::get_default_action (LOGLEV_INFO)));
+ fprintf (fp, "debug: action=%s\n",
+ io->getaction(logfunctions::get_default_action (LOGLEV_DEBUG)));
+ fprintf (fp, "pass: action=%s\n",
+ io->getaction(logfunctions::get_default_action (LOGLEV_PASS)));
+ return 0;
+}
+
+int
+bx_write_keyboard_options (FILE *fp, bx_keyboard_options *opt)
+{
+ fprintf (fp, "keyboard_mapping: enabled=%d, map=%s\n", opt->OuseMapping->get(), opt->Okeymap->getptr());
+ return 0;
+}
+
+// return values:
+// 0: written ok
+// -1: failed
+// -2: already exists, and overwrite was off
+int
+bx_write_configuration (char *rc, int overwrite)
+{
+ BX_INFO (("write configuration to %s\n", rc));
+ // check if it exists. If so, only proceed if overwrite is set.
+ FILE *fp = fopen (rc, "r");
+ if (fp != NULL) {
+ fclose (fp);
+ if (!overwrite) return -2;
+ }
+ fp = fopen (rc, "w");
+ if (fp == NULL) return -1;
+ // finally it's open and we can start writing.
+ fprintf (fp, "# configuration file generated by Bochs\n");
+ fprintf (fp, "config_interface: %s\n", bx_options.Osel_config->get_choice(bx_options.Osel_config->get()));
+ fprintf (fp, "display_library: %s\n", bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()));
+ fprintf (fp, "megs: %d\n", bx_options.memory.Osize->get ());
+ if (strlen (bx_options.rom.Opath->getptr ()) > 0)
+ fprintf (fp, "romimage: file=%s, address=0x%05x\n", bx_options.rom.Opath->getptr(), (unsigned int)bx_options.rom.Oaddress->get ());
+ else
+ fprintf (fp, "# no romimage\n");
+ if (strlen (bx_options.vgarom.Opath->getptr ()) > 0)
+ fprintf (fp, "vgaromimage: %s\n", bx_options.vgarom.Opath->getptr ());
+ else
+ fprintf (fp, "# no vgaromimage\n");
+ int bootdrive = bx_options.Obootdrive->get ();
+ fprintf (fp, "boot: %s\n", (bootdrive==BX_BOOT_FLOPPYA) ? "floppy" : (bootdrive==BX_BOOT_DISKC) ? "disk" : "cdrom");
+ // it would be nice to put this type of function as methods on
+ // the structs like bx_floppy_options::print or something.
+ bx_write_floppy_options (fp, 0, &bx_options.floppya);
+ bx_write_floppy_options (fp, 1, &bx_options.floppyb);
+ for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+ bx_write_ata_options (fp, channel, &bx_options.ata[channel]);
+ bx_write_atadevice_options (fp, channel, 0, &bx_options.atadevice[channel][0]);
+ bx_write_atadevice_options (fp, channel, 1, &bx_options.atadevice[channel][1]);
+ }
+ if (strlen (bx_options.optrom[0].Opath->getptr ()) > 0)
+ fprintf (fp, "optromimage1: file=%s, address=0x%05x\n", bx_options.optrom[0].Opath->getptr(), (unsigned int)bx_options.optrom[0].Oaddress->get ());
+ if (strlen (bx_options.optrom[1].Opath->getptr ()) > 0)
+ fprintf (fp, "optromimage2: file=%s, address=0x%05x\n", bx_options.optrom[1].Opath->getptr(), (unsigned int)bx_options.optrom[1].Oaddress->get ());
+ if (strlen (bx_options.optrom[2].Opath->getptr ()) > 0)
+ fprintf (fp, "optromimage3: file=%s, address=0x%05x\n", bx_options.optrom[2].Opath->getptr(), (unsigned int)bx_options.optrom[2].Oaddress->get ());
+ if (strlen (bx_options.optrom[3].Opath->getptr ()) > 0)
+ fprintf (fp, "optromimage4: file=%s, address=0x%05x\n", bx_options.optrom[3].Opath->getptr(), (unsigned int)bx_options.optrom[3].Oaddress->get ());
+ bx_write_parport_options (fp, &bx_options.par[0], 1);
+ //bx_write_parport_options (fp, &bx_options.par[1], 2);
+ bx_write_serial_options (fp, &bx_options.com[0], 1);
+ //bx_write_serial_options (fp, &bx_options.com[1], 2);
+ //bx_write_serial_options (fp, &bx_options.com[2], 3);
+ //bx_write_serial_options (fp, &bx_options.com[3], 4);
+ bx_write_usb_options (fp, &bx_options.usb[0], 1);
+ bx_write_sb16_options (fp, &bx_options.sb16);
+ fprintf (fp, "floppy_bootsig_check: disabled=%d\n", bx_options.OfloppySigCheck->get ());
+ fprintf (fp, "vga_update_interval: %u\n", bx_options.Ovga_update_interval->get ());
+ fprintf (fp, "keyboard_serial_delay: %u\n", bx_options.Okeyboard_serial_delay->get ());
+ fprintf (fp, "keyboard_paste_delay: %u\n", bx_options.Okeyboard_paste_delay->get ());
+ fprintf (fp, "floppy_command_delay: %u\n", bx_options.Ofloppy_command_delay->get ());
+ fprintf (fp, "ips: %u\n", bx_options.Oips->get ());
+ fprintf (fp, "text_snapshot_check: %d\n", bx_options.Otext_snapshot_check->get ());
+ fprintf (fp, "mouse: enabled=%d\n", bx_options.Omouse_enabled->get ());
+ fprintf (fp, "private_colormap: enabled=%d\n", bx_options.Oprivate_colormap->get ());
+#if BX_WITH_AMIGAOS
+ fprintf (fp, "fullscreen: enabled=%d\n", bx_options.Ofullscreen->get ());
+ fprintf (fp, "screenmode: name=\"%s\"\n", bx_options.Oscreenmode->getptr ());
+#endif
+ fprintf (fp, "i440fxsupport: enabled=%d\n", bx_options.Oi440FXSupport->get ());
+ bx_write_clock_options (fp, &bx_options.clock);
+ bx_write_ne2k_options (fp, &bx_options.ne2k);
+ fprintf (fp, "newharddrivesupport: enabled=%d\n", bx_options.OnewHardDriveSupport->get ());
+ bx_write_loader_options (fp, &bx_options.load32bitOSImage);
+ bx_write_log_options (fp, &bx_options.log);
+ bx_write_keyboard_options (fp, &bx_options.keyboard);
+ fprintf (fp, "keyboard_type: %s\n", bx_options.Okeyboard_type->get ()==BX_KBD_XT_TYPE?"xt":
+ bx_options.Okeyboard_type->get ()==BX_KBD_AT_TYPE?"at":"mf");
+ fprintf (fp, "user_shortcut: keys=%s\n", bx_options.Ouser_shortcut->getptr ());
+ if (strlen (bx_options.cmos.Opath->getptr ()) > 0)
+ fprintf (fp, "cmosimage: %s\n", bx_options.cmos.Opath->getptr());
+ else
+ fprintf (fp, "# no cmosimage\n");
+ fclose (fp);
+ return 0;
+}
+#endif // #if BX_PROVIDE_MAIN
+
+ void
+bx_signal_handler( int signum)
+{
+ // in a multithreaded environment, a signal such as SIGINT can be sent to all
+ // threads. This function is only intended to handle signals in the
+ // simulator thread. It will simply return if called from any other thread.
+ // Otherwise the BX_PANIC() below can be called in multiple threads at
+ // once, leading to multiple threads trying to display a dialog box,
+ // leading to GUI deadlock.
+ if (!SIM->is_sim_thread ()) {
+ BX_INFO (("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum));
+ return;
+ }
+#if BX_GUI_SIGHANDLER
+ if (bx_gui_sighandler) {
+ // GUI signal handler gets first priority, if the mask says it's wanted
+ if ((1<<signum) & bx_gui->get_sighandler_mask ()) {
+ bx_gui->sighandler (signum);
+ return;
+ }
+ }
+#endif
+
+#if BX_SHOW_IPS
+ extern unsigned long ips_count;
+
+ if (signum == SIGALRM ) {
+ BX_INFO(("ips = %lu", ips_count));
+ ips_count = 0;
+#ifndef __MINGW32__
+ signal(SIGALRM, bx_signal_handler);
+ alarm( 1 );
+#endif
+ return;
+ }
+#endif
+
+#if BX_GUI_SIGHANDLER
+ if (bx_gui_sighandler) {
+ if ((1<<signum) & bx_gui->get_sighandler_mask ()) {
+ bx_gui->sighandler (signum);
+ return;
+ }
+ }
+#endif
+ BX_PANIC(("SIGNAL %u caught", signum));
+}
+
diff --git a/tools/ioemu/iodev/ne2k.cc b/tools/ioemu/iodev/ne2k.cc
new file mode 100644
index 0000000000..d6e0ac4966
--- /dev/null
+++ b/tools/ioemu/iodev/ne2k.cc
@@ -0,0 +1,1608 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if BX_NE2K_SUPPORT
+
+//Never completely fill the ne2k ring so that we never
+// hit the unclear completely full buffer condition.
+#define BX_NE2K_NEVER_FULL_RING (1)
+
+#define LOG_THIS theNE2kDevice->
+
+bx_ne2k_c *theNE2kDevice = NULL;
+
+ int
+libne2k_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theNE2kDevice = new bx_ne2k_c ();
+ bx_devices.pluginNE2kDevice = theNE2kDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theNE2kDevice, BX_PLUGIN_NE2K);
+ return(0); // Success
+}
+
+ void
+libne2k_LTX_plugin_fini(void)
+{
+}
+
+bx_ne2k_c::bx_ne2k_c(void)
+{
+ put("NE2K");
+ settype(NE2KLOG);
+ s.tx_timer_index = BX_NULL_TIMER_HANDLE;
+}
+
+
+bx_ne2k_c::~bx_ne2k_c(void)
+{
+ // nothing for now
+}
+
+//
+// reset - restore state to power-up, cancelling all i/o
+//
+void
+bx_ne2k_c::reset(unsigned type)
+{
+ BX_DEBUG (("reset"));
+ // Zero out registers and memory
+ memset( & BX_NE2K_THIS s.CR, 0, sizeof(BX_NE2K_THIS s.CR) );
+ memset( & BX_NE2K_THIS s.ISR, 0, sizeof(BX_NE2K_THIS s.ISR));
+ memset( & BX_NE2K_THIS s.IMR, 0, sizeof(BX_NE2K_THIS s.IMR));
+ memset( & BX_NE2K_THIS s.DCR, 0, sizeof(BX_NE2K_THIS s.DCR));
+ memset( & BX_NE2K_THIS s.TCR, 0, sizeof(BX_NE2K_THIS s.TCR));
+ memset( & BX_NE2K_THIS s.TSR, 0, sizeof(BX_NE2K_THIS s.TSR));
+ memset( & BX_NE2K_THIS s.RCR, 0, sizeof(BX_NE2K_THIS s.RCR));
+ memset( & BX_NE2K_THIS s.RSR, 0, sizeof(BX_NE2K_THIS s.RSR));
+ BX_NE2K_THIS s.local_dma = 0;
+ BX_NE2K_THIS s.page_start = 0;
+ BX_NE2K_THIS s.page_stop = 0;
+ BX_NE2K_THIS s.bound_ptr = 0;
+ BX_NE2K_THIS s.tx_page_start = 0;
+ BX_NE2K_THIS s.num_coll = 0;
+ BX_NE2K_THIS s.tx_bytes = 0;
+ BX_NE2K_THIS s.fifo = 0;
+ BX_NE2K_THIS s.remote_dma = 0;
+ BX_NE2K_THIS s.remote_start = 0;
+ BX_NE2K_THIS s.remote_bytes = 0;
+ BX_NE2K_THIS s.tallycnt_0 = 0;
+ BX_NE2K_THIS s.tallycnt_1 = 0;
+ BX_NE2K_THIS s.tallycnt_2 = 0;
+
+ memset( & BX_NE2K_THIS s.physaddr, 0, sizeof(BX_NE2K_THIS s.physaddr));
+ memset( & BX_NE2K_THIS s.mchash, 0, sizeof(BX_NE2K_THIS s.mchash));
+ BX_NE2K_THIS s.curr_page = 0;
+
+ BX_NE2K_THIS s.rempkt_ptr = 0;
+ BX_NE2K_THIS s.localpkt_ptr = 0;
+ BX_NE2K_THIS s.address_cnt = 0;
+
+ memset( & BX_NE2K_THIS s.mem, 0, sizeof(BX_NE2K_THIS s.mem));
+
+ // Set power-up conditions
+ BX_NE2K_THIS s.CR.stop = 1;
+ BX_NE2K_THIS s.CR.rdma_cmd = 4;
+ BX_NE2K_THIS s.ISR.reset = 1;
+ BX_NE2K_THIS s.DCR.longaddr = 1;
+ DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
+}
+
+//
+// read_cr/write_cr - utility routines for handling reads/writes to
+// the Command Register
+//
+Bit32u
+bx_ne2k_c::read_cr(void)
+{
+ Bit32u val =
+ (((BX_NE2K_THIS s.CR.pgsel & 0x03) << 6) |
+ ((BX_NE2K_THIS s.CR.rdma_cmd & 0x07) << 3) |
+ (BX_NE2K_THIS s.CR.tx_packet << 2) |
+ (BX_NE2K_THIS s.CR.start << 1) |
+ (BX_NE2K_THIS s.CR.stop));
+ BX_DEBUG(("read CR returns 0x%08x", val));
+ return val;
+}
+
+void
+bx_ne2k_c::write_cr(Bit32u value)
+{
+ BX_DEBUG(("wrote 0x%02x to CR", value));
+
+ // Validate remote-DMA
+ if ((value & 0x38) == 0x00) {
+ BX_DEBUG(("CR write - invalid rDMA value 0"));
+ value |= 0x20; /* dma_cmd == 4 is a safe default */
+ }
+
+ // Check for s/w reset
+ if (value & 0x01) {
+ BX_NE2K_THIS s.ISR.reset = 1;
+ BX_NE2K_THIS s.CR.stop = 1;
+ } else {
+ BX_NE2K_THIS s.CR.stop = 0;
+ }
+
+ BX_NE2K_THIS s.CR.rdma_cmd = (value & 0x38) >> 3;
+
+ // If start command issued, the RST bit in the ISR
+ // must be cleared
+ if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) {
+ BX_NE2K_THIS s.ISR.reset = 0;
+ }
+
+ BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
+ BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6;
+
+ // Check for send-packet command
+ if (BX_NE2K_THIS s.CR.rdma_cmd == 3) {
+ // Set up DMA read from receive ring
+ BX_NE2K_THIS s.remote_start = BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.bound_ptr * 256;
+ BX_NE2K_THIS s.remote_bytes = *((Bit16u*) & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]);
+ BX_INFO(("Sending buffer #x%x length %d",
+ BX_NE2K_THIS s.remote_start,
+ BX_NE2K_THIS s.remote_bytes));
+ }
+
+ // Check for start-tx
+ if ((value & 0x04) && BX_NE2K_THIS s.TCR.loop_cntl) {
+ if (BX_NE2K_THIS s.TCR.loop_cntl != 1) {
+ BX_INFO(("Loop mode %d not supported.", BX_NE2K_THIS s.TCR.loop_cntl));
+ } else {
+ rx_frame (& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART],
+ BX_NE2K_THIS s.tx_bytes);
+ }
+ } else if (value & 0x04) {
+ if (BX_NE2K_THIS s.CR.stop || !BX_NE2K_THIS s.CR.start)
+ BX_PANIC(("CR write - tx start, dev in reset"));
+
+ if (BX_NE2K_THIS s.tx_bytes == 0)
+ BX_PANIC(("CR write - tx start, tx bytes == 0"));
+
+#ifdef notdef
+ // XXX debug stuff
+ printf("packet tx (%d bytes):\t", BX_NE2K_THIS s.tx_bytes);
+ for (int i = 0; i < BX_NE2K_THIS s.tx_bytes; i++) {
+ printf("%02x ", BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 -
+ BX_NE2K_MEMSTART + i]);
+ if (i && (((i+1) % 16) == 0))
+ printf("\t");
+ }
+ printf("");
+#endif
+
+ // Send the packet to the system driver
+ BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes);
+
+ // some more debug
+ if (BX_NE2K_THIS s.tx_timer_active)
+ BX_PANIC(("CR write, tx timer still active"));
+
+ // Schedule a timer to trigger a tx-complete interrupt
+ // The number of microseconds is the bit-time / 10.
+ // The bit-time is the preamble+sfd (64 bits), the
+ // inter-frame gap (96 bits), the CRC (4 bytes), and the
+ // the number of bits in the frame (s.tx_bytes * 8).
+ //
+ bx_pc_system.activate_timer(BX_NE2K_THIS s.tx_timer_index,
+ (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10,
+ 0); // not continuous
+ }
+
+ // Linux probes for an interrupt by setting up a remote-DMA read
+ // of 0 bytes with remote-DMA completion interrupts enabled.
+ // Detect this here
+ if (BX_NE2K_THIS s.CR.rdma_cmd == 0x01 &&
+ BX_NE2K_THIS s.CR.start &&
+ BX_NE2K_THIS s.remote_bytes == 0) {
+ BX_NE2K_THIS s.ISR.rdma_done = 1;
+ if (BX_NE2K_THIS s.IMR.rdma_inte) {
+ DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+ }
+ }
+}
+
+//
+// chipmem_read/chipmem_write - access the 64K private RAM.
+// The ne2000 memory is accessed through the data port of
+// the asic (offset 0) after setting up a remote-DMA transfer.
+// Both byte and word accesses are allowed.
+// The first 16 bytes contains the MAC address at even locations,
+// and there is 16K of buffer memory starting at 16K
+//
+Bit32u BX_CPP_AttrRegparmN(2)
+bx_ne2k_c::chipmem_read(Bit32u address, unsigned int io_len)
+{
+ Bit32u retval = 0;
+
+ if ((io_len == 2) && (address & 0x1))
+ BX_PANIC(("unaligned chipmem word read"));
+
+ // ROM'd MAC address
+ if ((address >=0) && (address <= 31)) {
+ retval = BX_NE2K_THIS s.macaddr[address];
+ if (io_len == 2) {
+ retval |= (BX_NE2K_THIS s.macaddr[address + 1] << 8);
+ }
+ return (retval);
+ }
+
+ if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
+ retval = BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART];
+ if (io_len == 2) {
+ retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] << 8);
+ }
+ return (retval);
+ }
+
+ BX_DEBUG(("out-of-bounds chipmem read, %04X", address));
+
+ return (0xff);
+}
+
+void BX_CPP_AttrRegparmN(3)
+bx_ne2k_c::chipmem_write(Bit32u address, Bit32u value, unsigned io_len)
+{
+ if ((io_len == 2) && (address & 0x1))
+ BX_PANIC(("unaligned chipmem word write"));
+
+ if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
+ BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART] = value & 0xff;
+ if (io_len == 2)
+ BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] = value >> 8;
+ } else
+ BX_DEBUG(("out-of-bounds chipmem write, %04X", address));
+}
+
+//
+// asic_read/asic_write - This is the high 16 bytes of i/o space
+// (the lower 16 bytes is for the DS8390). Only two locations
+// are used: offset 0, which is used for data transfer, and
+// offset 0xf, which is used to reset the device.
+// The data transfer port is used to as 'external' DMA to the
+// DS8390. The chip has to have the DMA registers set up, and
+// after that, insw/outsw instructions can be used to move
+// the appropriate number of bytes to/from the device.
+//
+Bit32u BX_CPP_AttrRegparmN(2)
+bx_ne2k_c::asic_read(Bit32u offset, unsigned int io_len)
+{
+ Bit32u retval = 0;
+
+ switch (offset) {
+ case 0x0: // Data register
+ //
+ // A read remote-DMA command must have been issued,
+ // and the source-address and length registers must
+ // have been initialised.
+ //
+ if (io_len > BX_NE2K_THIS s.remote_bytes)
+ {
+ BX_ERROR(("ne2K: dma read underrun iolen=%d remote_bytes=%d",io_len,BX_NE2K_THIS s.remote_bytes));
+ //return 0;
+ }
+
+ //BX_INFO(("ne2k read DMA: addr=%4x remote_bytes=%d",BX_NE2K_THIS s.remote_dma,BX_NE2K_THIS s.remote_bytes));
+ retval = chipmem_read(BX_NE2K_THIS s.remote_dma, io_len);
+ //
+ // The 8390 bumps the address and decreases the byte count
+ // by the selected word size after every access, not by
+ // the amount of data requested by the host (io_len).
+ //
+ BX_NE2K_THIS s.remote_dma += (BX_NE2K_THIS s.DCR.wdsize + 1);
+ if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
+ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
+ }
+ // keep s.remote_bytes from underflowing
+ if (BX_NE2K_THIS s.remote_bytes > 1)
+ BX_NE2K_THIS s.remote_bytes -= (BX_NE2K_THIS s.DCR.wdsize + 1);
+ else
+ BX_NE2K_THIS s.remote_bytes = 0;
+
+ // If all bytes have been written, signal remote-DMA complete
+ if (BX_NE2K_THIS s.remote_bytes == 0) {
+ BX_NE2K_THIS s.ISR.rdma_done = 1;
+ if (BX_NE2K_THIS s.IMR.rdma_inte) {
+ DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+ }
+ }
+ break;
+
+ case 0xf: // Reset register
+ theNE2kDevice->reset(BX_RESET_SOFTWARE);
+ break;
+
+ default:
+ BX_INFO(("asic read invalid address %04x", (unsigned) offset));
+ break;
+ }
+
+ return (retval);
+}
+
+void
+bx_ne2k_c::asic_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+ BX_DEBUG(("asic write addr=0x%02x, value=0x%04x", (unsigned) offset, (unsigned) value));
+ switch (offset) {
+ case 0x0: // Data register - see asic_read for a description
+
+ if ((io_len == 2) && (BX_NE2K_THIS s.DCR.wdsize == 0)) {
+ BX_PANIC(("dma write length 2 on byte mode operation"));
+ break;
+ }
+
+ if (BX_NE2K_THIS s.remote_bytes == 0)
+ BX_PANIC(("ne2K: dma write, byte count 0"));
+
+ chipmem_write(BX_NE2K_THIS s.remote_dma, value, io_len);
+ // is this right ??? asic_read uses DCR.wordsize
+ BX_NE2K_THIS s.remote_dma += io_len;
+ if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
+ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
+ }
+
+ BX_NE2K_THIS s.remote_bytes -= io_len;
+ if (BX_NE2K_THIS s.remote_bytes > BX_NE2K_MEMSIZ)
+ BX_NE2K_THIS s.remote_bytes = 0;
+
+ // If all bytes have been written, signal remote-DMA complete
+ if (BX_NE2K_THIS s.remote_bytes == 0) {
+ BX_NE2K_THIS s.ISR.rdma_done = 1;
+ if (BX_NE2K_THIS s.IMR.rdma_inte) {
+ DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+ }
+ }
+ break;
+
+ case 0xf: // Reset register
+ theNE2kDevice->reset(BX_RESET_SOFTWARE);
+ break;
+
+ default: // this is invalid, but happens under win95 device detection
+ BX_INFO(("asic write invalid address %04x, ignoring", (unsigned) offset));
+ break ;
+ }
+}
+
+//
+// page0_read/page0_write - These routines handle reads/writes to
+// the 'zeroth' page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page0_read(Bit32u offset, unsigned int io_len)
+{
+ BX_DEBUG(("page 0 read from port %04x, len=%u", (unsigned) offset,
+ (unsigned) io_len));
+ if (io_len > 1) {
+ BX_ERROR(("bad length! page 0 read from port %04x, len=%u", (unsigned) offset,
+ (unsigned) io_len)); /* encountered with win98 hardware probe */
+ return 0;
+ }
+
+
+ switch (offset) {
+ case 0x0: // CR
+ return (read_cr());
+ break;
+
+ case 0x1: // CLDA0
+ return (BX_NE2K_THIS s.local_dma & 0xff);
+ break;
+
+ case 0x2: // CLDA1
+ return (BX_NE2K_THIS s.local_dma >> 8);
+ break;
+
+ case 0x3: // BNRY
+ return (BX_NE2K_THIS s.bound_ptr);
+ break;
+
+ case 0x4: // TSR
+ return ((BX_NE2K_THIS s.TSR.ow_coll << 7) |
+ (BX_NE2K_THIS s.TSR.cd_hbeat << 6) |
+ (BX_NE2K_THIS s.TSR.fifo_ur << 5) |
+ (BX_NE2K_THIS s.TSR.no_carrier << 4) |
+ (BX_NE2K_THIS s.TSR.aborted << 3) |
+ (BX_NE2K_THIS s.TSR.collided << 2) |
+ (BX_NE2K_THIS s.TSR.tx_ok));
+ break;
+
+ case 0x5: // NCR
+ return (BX_NE2K_THIS s.num_coll);
+ break;
+
+ case 0x6: // FIFO
+ // reading FIFO is only valid in loopback mode
+ BX_ERROR(("reading FIFO not supported yet"));
+ return (BX_NE2K_THIS s.fifo);
+ break;
+
+ case 0x7: // ISR
+ return ((BX_NE2K_THIS s.ISR.reset << 7) |
+ (BX_NE2K_THIS s.ISR.rdma_done << 6) |
+ (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
+ (BX_NE2K_THIS s.ISR.overwrite << 4) |
+ (BX_NE2K_THIS s.ISR.tx_err << 3) |
+ (BX_NE2K_THIS s.ISR.rx_err << 2) |
+ (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
+ (BX_NE2K_THIS s.ISR.pkt_rx));
+ break;
+
+ case 0x8: // CRDA0
+ return (BX_NE2K_THIS s.remote_dma & 0xff);
+ break;
+
+ case 0x9: // CRDA1
+ return (BX_NE2K_THIS s.remote_dma >> 8);
+ break;
+
+ case 0xa: // reserved
+ BX_INFO(("reserved read - page 0, 0xa"));
+ return (0xff);
+ break;
+
+ case 0xb: // reserved
+ BX_INFO(("reserved read - page 0, 0xb"));
+ return (0xff);
+ break;
+
+ case 0xc: // RSR
+ return ((BX_NE2K_THIS s.RSR.deferred << 7) |
+ (BX_NE2K_THIS s.RSR.rx_disabled << 6) |
+ (BX_NE2K_THIS s.RSR.rx_mbit << 5) |
+ (BX_NE2K_THIS s.RSR.rx_missed << 4) |
+ (BX_NE2K_THIS s.RSR.fifo_or << 3) |
+ (BX_NE2K_THIS s.RSR.bad_falign << 2) |
+ (BX_NE2K_THIS s.RSR.bad_crc << 1) |
+ (BX_NE2K_THIS s.RSR.rx_ok));
+ break;
+
+ case 0xd: // CNTR0
+ return (BX_NE2K_THIS s.tallycnt_0);
+ break;
+
+ case 0xe: // CNTR1
+ return (BX_NE2K_THIS s.tallycnt_1);
+ break;
+
+ case 0xf: // CNTR2
+ return (BX_NE2K_THIS s.tallycnt_2);
+ break;
+
+ default:
+ BX_PANIC(("page 0 offset %04x out of range", (unsigned) offset));
+ }
+
+ return(0);
+}
+
+void
+bx_ne2k_c::page0_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+ BX_DEBUG(("page 0 write to port %04x, len=%u", (unsigned) offset,
+ (unsigned) io_len));
+
+ // It appears to be a common practice to use outw on page0 regs...
+
+ // break up outw into two outb's
+ if (io_len == 2) {
+ page0_write(offset, (value & 0xff), 1);
+ page0_write(offset + 1, ((value >> 8) & 0xff), 1);
+ return;
+ }
+
+ switch (offset) {
+ case 0x0: // CR
+ write_cr(value);
+ break;
+
+ case 0x1: // PSTART
+ BX_NE2K_THIS s.page_start = value;
+ break;
+
+ case 0x2: // PSTOP
+ // BX_INFO(("Writing to PSTOP: %02x", value));
+ BX_NE2K_THIS s.page_stop = value;
+ break;
+
+ case 0x3: // BNRY
+ BX_NE2K_THIS s.bound_ptr = value;
+ break;
+
+ case 0x4: // TPSR
+ BX_NE2K_THIS s.tx_page_start = value;
+ break;
+
+ case 0x5: // TBCR0
+ // Clear out low byte and re-insert
+ BX_NE2K_THIS s.tx_bytes &= 0xff00;
+ BX_NE2K_THIS s.tx_bytes |= (value & 0xff);
+ break;
+
+ case 0x6: // TBCR1
+ // Clear out high byte and re-insert
+ BX_NE2K_THIS s.tx_bytes &= 0x00ff;
+ BX_NE2K_THIS s.tx_bytes |= ((value & 0xff) << 8);
+ break;
+
+ case 0x7: // ISR
+ value &= 0x7f; // clear RST bit - status-only bit
+ // All other values are cleared iff the ISR bit is 1
+ BX_NE2K_THIS s.ISR.pkt_rx &= ~((bx_bool)((value & 0x01) == 0x01));
+ BX_NE2K_THIS s.ISR.pkt_tx &= ~((bx_bool)((value & 0x02) == 0x02));
+ BX_NE2K_THIS s.ISR.rx_err &= ~((bx_bool)((value & 0x04) == 0x04));
+ BX_NE2K_THIS s.ISR.tx_err &= ~((bx_bool)((value & 0x08) == 0x08));
+ BX_NE2K_THIS s.ISR.overwrite &= ~((bx_bool)((value & 0x10) == 0x10));
+ BX_NE2K_THIS s.ISR.cnt_oflow &= ~((bx_bool)((value & 0x20) == 0x20));
+ BX_NE2K_THIS s.ISR.rdma_done &= ~((bx_bool)((value & 0x40) == 0x40));
+ value = ((BX_NE2K_THIS s.ISR.rdma_done << 6) |
+ (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
+ (BX_NE2K_THIS s.ISR.overwrite << 4) |
+ (BX_NE2K_THIS s.ISR.tx_err << 3) |
+ (BX_NE2K_THIS s.ISR.rx_err << 2) |
+ (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
+ (BX_NE2K_THIS s.ISR.pkt_rx));
+ value &= ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
+ (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
+ (BX_NE2K_THIS s.IMR.overw_inte << 4) |
+ (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
+ (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
+ (BX_NE2K_THIS s.IMR.tx_inte << 1) |
+ (BX_NE2K_THIS s.IMR.rx_inte));
+ if (value == 0)
+ DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
+ break;
+
+ case 0x8: // RSAR0
+ // Clear out low byte and re-insert
+ BX_NE2K_THIS s.remote_start &= 0xff00;
+ BX_NE2K_THIS s.remote_start |= (value & 0xff);
+ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
+ break;
+
+ case 0x9: // RSAR1
+ // Clear out high byte and re-insert
+ BX_NE2K_THIS s.remote_start &= 0x00ff;
+ BX_NE2K_THIS s.remote_start |= ((value & 0xff) << 8);
+ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
+ break;
+
+ case 0xa: // RBCR0
+ // Clear out low byte and re-insert
+ BX_NE2K_THIS s.remote_bytes &= 0xff00;
+ BX_NE2K_THIS s.remote_bytes |= (value & 0xff);
+ break;
+
+ case 0xb: // RBCR1
+ // Clear out high byte and re-insert
+ BX_NE2K_THIS s.remote_bytes &= 0x00ff;
+ BX_NE2K_THIS s.remote_bytes |= ((value & 0xff) << 8);
+ break;
+
+ case 0xc: // RCR
+ // Check if the reserved bits are set
+ if (value & 0xc0)
+ BX_INFO(("RCR write, reserved bits set"));
+
+ // Set all other bit-fields
+ BX_NE2K_THIS s.RCR.errors_ok = ((value & 0x01) == 0x01);
+ BX_NE2K_THIS s.RCR.runts_ok = ((value & 0x02) == 0x02);
+ BX_NE2K_THIS s.RCR.broadcast = ((value & 0x04) == 0x04);
+ BX_NE2K_THIS s.RCR.multicast = ((value & 0x08) == 0x08);
+ BX_NE2K_THIS s.RCR.promisc = ((value & 0x10) == 0x10);
+ BX_NE2K_THIS s.RCR.monitor = ((value & 0x20) == 0x20);
+
+ // Monitor bit is a little suspicious...
+ if (value & 0x20)
+ BX_INFO(("RCR write, monitor bit set!"));
+ break;
+
+ case 0xd: // TCR
+ // Check reserved bits
+ if (value & 0xe0)
+ BX_ERROR(("TCR write, reserved bits set"));
+
+ // Test loop mode (not supported)
+ if (value & 0x06) {
+ BX_NE2K_THIS s.TCR.loop_cntl = (value & 0x6) >> 1;
+ BX_INFO(("TCR write, loop mode %d not supported", BX_NE2K_THIS s.TCR.loop_cntl));
+ } else {
+ BX_NE2K_THIS s.TCR.loop_cntl = 0;
+ }
+
+ // Inhibit-CRC not supported.
+ if (value & 0x01)
+ BX_PANIC(("TCR write, inhibit-CRC not supported"));
+
+ // Auto-transmit disable very suspicious
+ if (value & 0x08)
+ BX_PANIC(("TCR write, auto transmit disable not supported"));
+
+ // Allow collision-offset to be set, although not used
+ BX_NE2K_THIS s.TCR.coll_prio = ((value & 0x08) == 0x08);
+ break;
+
+ case 0xe: // DCR
+ // the loopback mode is not suppported yet
+ if (!(value & 0x08)) {
+ BX_ERROR(("DCR write, loopback mode selected"));
+ }
+ // It is questionable to set longaddr and auto_rx, since they
+ // aren't supported on the ne2000. Print a warning and continue
+ if (value & 0x04)
+ BX_INFO(("DCR write - LAS set ???"));
+ if (value & 0x10)
+ BX_INFO(("DCR write - AR set ???"));
+
+ // Set other values.
+ BX_NE2K_THIS s.DCR.wdsize = ((value & 0x01) == 0x01);
+ BX_NE2K_THIS s.DCR.endian = ((value & 0x02) == 0x02);
+ BX_NE2K_THIS s.DCR.longaddr = ((value & 0x04) == 0x04); // illegal ?
+ BX_NE2K_THIS s.DCR.loop = ((value & 0x08) == 0x08);
+ BX_NE2K_THIS s.DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ?
+ BX_NE2K_THIS s.DCR.fifo_size = (value & 0x50) >> 5;
+ break;
+
+ case 0xf: // IMR
+ // Check for reserved bit
+ if (value & 0x80)
+ BX_PANIC(("IMR write, reserved bit set"));
+
+ // Set other values
+ BX_NE2K_THIS s.IMR.rx_inte = ((value & 0x01) == 0x01);
+ BX_NE2K_THIS s.IMR.tx_inte = ((value & 0x02) == 0x02);
+ BX_NE2K_THIS s.IMR.rxerr_inte = ((value & 0x04) == 0x04);
+ BX_NE2K_THIS s.IMR.txerr_inte = ((value & 0x08) == 0x08);
+ BX_NE2K_THIS s.IMR.overw_inte = ((value & 0x10) == 0x10);
+ BX_NE2K_THIS s.IMR.cofl_inte = ((value & 0x20) == 0x20);
+ BX_NE2K_THIS s.IMR.rdma_inte = ((value & 0x40) == 0x40);
+ break;
+
+ default:
+ BX_PANIC(("page 0 write, bad offset %0x", offset));
+ }
+}
+
+
+//
+// page1_read/page1_write - These routines handle reads/writes to
+// the first page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page1_read(Bit32u offset, unsigned int io_len)
+{
+ BX_DEBUG(("page 1 read from port %04x, len=%u", (unsigned) offset,
+ (unsigned) io_len));
+ if (io_len > 1)
+ BX_PANIC(("bad length! page 1 read from port %04x, len=%u", (unsigned) offset,
+ (unsigned) io_len));
+
+ switch (offset) {
+ case 0x0: // CR
+ return (read_cr());
+ break;
+
+ case 0x1: // PAR0-5
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ return (BX_NE2K_THIS s.physaddr[offset - 1]);
+ break;
+
+ case 0x7: // CURR
+ BX_DEBUG(("returning current page: %02x", (BX_NE2K_THIS s.curr_page)));
+ return (BX_NE2K_THIS s.curr_page);
+
+ case 0x8: // MAR0-7
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ return (BX_NE2K_THIS s.mchash[offset - 8]);
+ break;
+
+ default:
+ BX_PANIC(("page 1 r offset %04x out of range", (unsigned) offset));
+ }
+
+ return (0);
+}
+
+void
+bx_ne2k_c::page1_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+ BX_DEBUG(("page 1 w offset %04x", (unsigned) offset));
+ switch (offset) {
+ case 0x0: // CR
+ write_cr(value);
+ break;
+
+ case 0x1: // PAR0-5
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ BX_NE2K_THIS s.physaddr[offset - 1] = value;
+ break;
+
+ case 0x7: // CURR
+ BX_NE2K_THIS s.curr_page = value;
+ break;
+
+ case 0x8: // MAR0-7
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ BX_NE2K_THIS s.mchash[offset - 8] = value;
+ break;
+
+ default:
+ BX_PANIC(("page 1 w offset %04x out of range", (unsigned) offset));
+ }
+}
+
+
+//
+// page2_read/page2_write - These routines handle reads/writes to
+// the second page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page2_read(Bit32u offset, unsigned int io_len)
+{
+ BX_DEBUG(("page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len));
+
+ if (io_len > 1)
+ BX_PANIC(("bad length! page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len));
+
+ switch (offset) {
+ case 0x0: // CR
+ return (read_cr());
+ break;
+
+ case 0x1: // PSTART
+ return (BX_NE2K_THIS s.page_start);
+ break;
+
+ case 0x2: // PSTOP
+ return (BX_NE2K_THIS s.page_stop);
+ break;
+
+ case 0x3: // Remote Next-packet pointer
+ return (BX_NE2K_THIS s.rempkt_ptr);
+ break;
+
+ case 0x4: // TPSR
+ return (BX_NE2K_THIS s.tx_page_start);
+ break;
+
+ case 0x5: // Local Next-packet pointer
+ return (BX_NE2K_THIS s.localpkt_ptr);
+ break;
+
+ case 0x6: // Address counter (upper)
+ return (BX_NE2K_THIS s.address_cnt >> 8);
+ break;
+
+ case 0x7: // Address counter (lower)
+ return (BX_NE2K_THIS s.address_cnt & 0xff);
+ break;
+
+ case 0x8: // Reserved
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ BX_ERROR(("reserved read - page 2, 0x%02x", (unsigned) offset));
+ return (0xff);
+ break;
+
+ case 0xc: // RCR
+ return ((BX_NE2K_THIS s.RCR.monitor << 5) |
+ (BX_NE2K_THIS s.RCR.promisc << 4) |
+ (BX_NE2K_THIS s.RCR.multicast << 3) |
+ (BX_NE2K_THIS s.RCR.broadcast << 2) |
+ (BX_NE2K_THIS s.RCR.runts_ok << 1) |
+ (BX_NE2K_THIS s.RCR.errors_ok));
+ break;
+
+ case 0xd: // TCR
+ return ((BX_NE2K_THIS s.TCR.coll_prio << 4) |
+ (BX_NE2K_THIS s.TCR.ext_stoptx << 3) |
+ ((BX_NE2K_THIS s.TCR.loop_cntl & 0x3) << 1) |
+ (BX_NE2K_THIS s.TCR.crc_disable));
+ break;
+
+ case 0xe: // DCR
+ return (((BX_NE2K_THIS s.DCR.fifo_size & 0x3) << 5) |
+ (BX_NE2K_THIS s.DCR.auto_rx << 4) |
+ (BX_NE2K_THIS s.DCR.loop << 3) |
+ (BX_NE2K_THIS s.DCR.longaddr << 2) |
+ (BX_NE2K_THIS s.DCR.endian << 1) |
+ (BX_NE2K_THIS s.DCR.wdsize));
+ break;
+
+ case 0xf: // IMR
+ return ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
+ (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
+ (BX_NE2K_THIS s.IMR.overw_inte << 4) |
+ (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
+ (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
+ (BX_NE2K_THIS s.IMR.tx_inte << 1) |
+ (BX_NE2K_THIS s.IMR.rx_inte));
+ break;
+
+ default:
+ BX_PANIC(("page 2 offset %04x out of range", (unsigned) offset));
+ }
+
+ return (0);
+};
+
+void
+bx_ne2k_c::page2_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+ // Maybe all writes here should be BX_PANIC()'d, since they
+ // affect internal operation, but let them through for now
+ // and print a warning.
+ if (offset != 0)
+ BX_ERROR(("page 2 write ?"));
+
+ switch (offset) {
+ case 0x0: // CR
+ write_cr(value);
+ break;
+
+ case 0x1: // CLDA0
+ // Clear out low byte and re-insert
+ BX_NE2K_THIS s.local_dma &= 0xff00;
+ BX_NE2K_THIS s.local_dma |= (value & 0xff);
+ break;
+
+ case 0x2: // CLDA1
+ // Clear out high byte and re-insert
+ BX_NE2K_THIS s.local_dma &= 0x00ff;
+ BX_NE2K_THIS s.local_dma |= ((value & 0xff) << 8);
+ break;
+
+ case 0x3: // Remote Next-pkt pointer
+ BX_NE2K_THIS s.rempkt_ptr = value;
+ break;
+
+ case 0x4:
+ BX_PANIC(("page 2 write to reserved offset 4"));
+ break;
+
+ case 0x5: // Local Next-packet pointer
+ BX_NE2K_THIS s.localpkt_ptr = value;
+ break;
+
+ case 0x6: // Address counter (upper)
+ // Clear out high byte and re-insert
+ BX_NE2K_THIS s.address_cnt &= 0x00ff;
+ BX_NE2K_THIS s.address_cnt |= ((value & 0xff) << 8);
+ break;
+
+ case 0x7: // Address counter (lower)
+ // Clear out low byte and re-insert
+ BX_NE2K_THIS s.address_cnt &= 0xff00;
+ BX_NE2K_THIS s.address_cnt |= (value & 0xff);
+ break;
+
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ BX_PANIC(("page 2 write to reserved offset %0x", offset));
+ break;
+
+ default:
+ BX_PANIC(("page 2 write, illegal offset %0x", offset));
+ break;
+ }
+}
+
+//
+// page3_read/page3_write - writes to this page are illegal
+//
+Bit32u
+bx_ne2k_c::page3_read(Bit32u offset, unsigned int io_len)
+{
+ BX_PANIC(("page 3 read attempted"));
+ return (0);
+}
+
+void
+bx_ne2k_c::page3_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+ BX_PANIC(("page 3 write attempted"));
+}
+
+//
+// tx_timer_handler/tx_timer
+//
+void
+bx_ne2k_c::tx_timer_handler(void *this_ptr)
+{
+ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+
+ class_ptr->tx_timer();
+}
+
+void
+bx_ne2k_c::tx_timer(void)
+{
+ BX_DEBUG(("tx_timer"));
+ BX_NE2K_THIS s.TSR.tx_ok = 1;
+ // Generate an interrupt if not masked and not one in progress
+ if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
+ BX_NE2K_THIS s.ISR.pkt_tx = 1;
+ DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+ }
+ BX_NE2K_THIS s.tx_timer_active = 0;
+}
+
+
+//
+// read_handler/read - i/o 'catcher' function called from BOCHS
+// mainline when the CPU attempts a read in the i/o space registered
+// by this ne2000 instance
+//
+Bit32u
+bx_ne2k_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_NE2K_SMF
+ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+Bit32u
+bx_ne2k_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_NE2K_SMF
+ BX_DEBUG(("read addr %x, len %d", address, io_len));
+ Bit32u retval = 0;
+ int offset = address - BX_NE2K_THIS s.base_address;
+
+ if (offset >= 0x10) {
+ retval = asic_read(offset - 0x10, io_len);
+ } else {
+ switch (BX_NE2K_THIS s.CR.pgsel) {
+ case 0x00:
+ retval = page0_read(offset, io_len);
+ break;
+
+ case 0x01:
+ retval = page1_read(offset, io_len);
+ break;
+
+ case 0x02:
+ retval = page2_read(offset, io_len);
+ break;
+
+ case 0x03:
+ retval = page3_read(offset, io_len);
+ break;
+
+ default:
+ BX_PANIC(("ne2K: unknown value of pgsel in read - %d",
+ BX_NE2K_THIS s.CR.pgsel));
+ }
+ }
+
+ return (retval);
+}
+
+//
+// write_handler/write - i/o 'catcher' function called from BOCHS
+// mainline when the CPU attempts a write in the i/o space registered
+// by this ne2000 instance
+//
+void
+bx_ne2k_c::write_handler(void *this_ptr, Bit32u address, Bit32u value,
+ unsigned io_len)
+{
+#if !BX_USE_NE2K_SMF
+ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+void
+bx_ne2k_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_NE2K_SMF
+ BX_DEBUG(("write with length %d", io_len));
+ int offset = address - BX_NE2K_THIS s.base_address;
+
+ //
+ // The high 16 bytes of i/o space are for the ne2000 asic -
+ // the low 16 bytes are for the DS8390, with the current
+ // page being selected by the PS0,PS1 registers in the
+ // command register
+ //
+ if (offset >= 0x10) {
+ asic_write(offset - 0x10, value, io_len);
+ } else {
+ switch (BX_NE2K_THIS s.CR.pgsel) {
+ case 0x00:
+ page0_write(offset, value, io_len);
+ break;
+
+ case 0x01:
+ page1_write(offset, value, io_len);
+ break;
+
+ case 0x02:
+ page2_write(offset, value, io_len);
+ break;
+
+ case 0x03:
+ page3_write(offset, value, io_len);
+ break;
+
+ default:
+ BX_PANIC(("ne2K: unknown value of pgsel in write - %d",
+ BX_NE2K_THIS s.CR.pgsel));
+ }
+ }
+}
+
+
+/*
+ * mcast_index() - return the 6-bit index into the multicast
+ * table. Stolen unashamedly from FreeBSD's if_ed.c
+ */
+unsigned
+bx_ne2k_c::mcast_index(const void *dst)
+{
+#define POLYNOMIAL 0x04c11db6
+ unsigned long crc = 0xffffffffL;
+ int carry, i, j;
+ unsigned char b;
+ unsigned char *ep = (unsigned char *) dst;
+
+ for (i = 6; --i >= 0;) {
+ b = *ep++;
+ for (j = 8; --j >= 0;) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry)
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ return (crc >> 26);
+#undef POLYNOMIAL
+}
+
+/*
+ * Callback from the eth system driver when a frame has arrived
+ */
+void
+bx_ne2k_c::rx_handler(void *arg, const void *buf, unsigned len)
+{
+ // BX_DEBUG(("rx_handler with length %d", len));
+ bx_ne2k_c *class_ptr = (bx_ne2k_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_ne2k_c::rx_frame(const void *buf, unsigned io_len)
+{
+ unsigned pages;
+ unsigned avail;
+ unsigned idx;
+ int wrapped;
+ int nextpage;
+ unsigned char pkthdr[4];
+ unsigned char *pktbuf = (unsigned char *) buf;
+ unsigned char *startptr;
+ static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+ BX_DEBUG(("rx_frame with length %d", io_len));
+
+
+ if ((BX_NE2K_THIS s.CR.stop != 0) ||
+ (BX_NE2K_THIS s.page_start == 0) ||
+ ((BX_NE2K_THIS s.DCR.loop == 0) &&
+ (BX_NE2K_THIS s.TCR.loop_cntl != 0))) {
+
+ return;
+ }
+
+ // Add the pkt header + CRC to the length, and work
+ // out how many 256-byte pages the frame would occupy
+ pages = (io_len + 4 + 4 + 255)/256;
+
+ if (BX_NE2K_THIS s.curr_page < BX_NE2K_THIS s.bound_ptr) {
+ avail = BX_NE2K_THIS s.bound_ptr - BX_NE2K_THIS s.curr_page;
+ } else {
+ avail = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start) -
+ (BX_NE2K_THIS s.curr_page - BX_NE2K_THIS s.bound_ptr);
+ wrapped = 1;
+ }
+
+ // Avoid getting into a buffer overflow condition by not attempting
+ // to do partial receives. The emulation to handle this condition
+ // seems particularly painful.
+ if ((avail < pages)
+#if BX_NE2K_NEVER_FULL_RING
+ || (avail == pages)
+#endif
+ ) {
+ return;
+ }
+
+ if ((io_len < 60) && !BX_NE2K_THIS s.RCR.runts_ok) {
+ BX_DEBUG(("rejected small packet, length %d", io_len));
+ return;
+ }
+
+ // Do address filtering if not in promiscuous mode
+ if (! BX_NE2K_THIS s.RCR.promisc) {
+ if (!memcmp(buf, bcast_addr, 6)) {
+ if (!BX_NE2K_THIS s.RCR.broadcast) {
+ return;
+ }
+ } else if (pktbuf[0] & 0x01) {
+ if (! BX_NE2K_THIS s.RCR.multicast) {
+ return;
+ }
+ idx = mcast_index(buf);
+ if (!(BX_NE2K_THIS s.mchash[idx >> 3] & (1 << (idx & 0x7)))) {
+ return;
+ }
+ } else if (0 != memcmp(buf, BX_NE2K_THIS s.physaddr, 6)) {
+ return;
+ }
+ } else {
+ BX_DEBUG(("rx_frame promiscuous receive"));
+ }
+
+// BX_INFO(("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x",
+// io_len,
+// pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5],
+// pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]));
+
+ nextpage = BX_NE2K_THIS s.curr_page + pages;
+ if (nextpage >= BX_NE2K_THIS s.page_stop) {
+ nextpage -= BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start;
+ }
+
+ // Setup packet header
+ pkthdr[0] = 0; // rx status - old behavior
+ pkthdr[0] = 1; // Probably better to set it all the time
+ // rather than set it to 0, which is clearly wrong.
+ if (pktbuf[0] & 0x01) {
+ pkthdr[0] |= 0x20; // rx status += multicast packet
+ }
+ pkthdr[1] = nextpage; // ptr to next packet
+ pkthdr[2] = (io_len + 4) & 0xff; // length-low
+ pkthdr[3] = (io_len + 4) >> 8; // length-hi
+
+ // copy into buffer, update curpage, and signal interrupt if config'd
+ startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.curr_page * 256 -
+ BX_NE2K_MEMSTART];
+ if ((nextpage > BX_NE2K_THIS s.curr_page) ||
+ ((BX_NE2K_THIS s.curr_page + pages) == BX_NE2K_THIS s.page_stop)) {
+ memcpy(startptr, pkthdr, 4);
+ memcpy(startptr + 4, buf, io_len);
+ BX_NE2K_THIS s.curr_page = nextpage;
+ } else {
+ int endbytes = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.curr_page)
+ * 256;
+ memcpy(startptr, pkthdr, 4);
+ memcpy(startptr + 4, buf, endbytes - 4);
+ startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.page_start * 256 -
+ BX_NE2K_MEMSTART];
+ memcpy(startptr, (void *)(pktbuf + endbytes - 4),
+ io_len - endbytes + 8);
+ BX_NE2K_THIS s.curr_page = nextpage;
+ }
+
+ BX_NE2K_THIS s.RSR.rx_ok = 1;
+ if (pktbuf[0] & 0x80) {
+ BX_NE2K_THIS s.RSR.rx_mbit = 1;
+ }
+
+ BX_NE2K_THIS s.ISR.pkt_rx = 1;
+
+ if (BX_NE2K_THIS s.IMR.rx_inte) {
+ DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+ }
+
+}
+
+void
+bx_ne2k_c::init(void)
+{
+ BX_DEBUG(("Init $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $"));
+
+ // Read in values from config file
+ BX_NE2K_THIS s.base_address = bx_options.ne2k.Oioaddr->get ();
+ BX_NE2K_THIS s.base_irq = bx_options.ne2k.Oirq->get ();
+ memcpy(BX_NE2K_THIS s.physaddr, bx_options.ne2k.Omacaddr->getptr (), 6);
+
+ if (BX_NE2K_THIS s.tx_timer_index == BX_NULL_TIMER_HANDLE) {
+ BX_NE2K_THIS s.tx_timer_index =
+ bx_pc_system.register_timer(this, tx_timer_handler, 0,
+ 0,0, "ne2k"); // one-shot, inactive
+ }
+ // Register the IRQ and i/o port addresses
+ DEV_register_irq(BX_NE2K_THIS s.base_irq, "NE2000 ethernet NIC");
+
+ for (unsigned addr = BX_NE2K_THIS s.base_address;
+ addr <= BX_NE2K_THIS s.base_address + 0x20;
+ addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "ne2000 NIC", 3);
+ DEV_register_iowrite_handler(this, write_handler, addr, "ne2000 NIC", 3);
+ }
+ BX_INFO(("port 0x%x/32 irq %d mac %02x:%02x:%02x:%02x:%02x:%02x",
+ BX_NE2K_THIS s.base_address,
+ BX_NE2K_THIS s.base_irq,
+ BX_NE2K_THIS s.physaddr[0],
+ BX_NE2K_THIS s.physaddr[1],
+ BX_NE2K_THIS s.physaddr[2],
+ BX_NE2K_THIS s.physaddr[3],
+ BX_NE2K_THIS s.physaddr[4],
+ BX_NE2K_THIS s.physaddr[5]));
+
+ // Initialise the mac address area by doubling the physical address
+ BX_NE2K_THIS s.macaddr[0] = BX_NE2K_THIS s.physaddr[0];
+ BX_NE2K_THIS s.macaddr[1] = BX_NE2K_THIS s.physaddr[0];
+ BX_NE2K_THIS s.macaddr[2] = BX_NE2K_THIS s.physaddr[1];
+ BX_NE2K_THIS s.macaddr[3] = BX_NE2K_THIS s.physaddr[1];
+ BX_NE2K_THIS s.macaddr[4] = BX_NE2K_THIS s.physaddr[2];
+ BX_NE2K_THIS s.macaddr[5] = BX_NE2K_THIS s.physaddr[2];
+ BX_NE2K_THIS s.macaddr[6] = BX_NE2K_THIS s.physaddr[3];
+ BX_NE2K_THIS s.macaddr[7] = BX_NE2K_THIS s.physaddr[3];
+ BX_NE2K_THIS s.macaddr[8] = BX_NE2K_THIS s.physaddr[4];
+ BX_NE2K_THIS s.macaddr[9] = BX_NE2K_THIS s.physaddr[4];
+ BX_NE2K_THIS s.macaddr[10] = BX_NE2K_THIS s.physaddr[5];
+ BX_NE2K_THIS s.macaddr[11] = BX_NE2K_THIS s.physaddr[5];
+
+ // ne2k signature
+ for (int i = 12; i < 32; i++)
+ BX_NE2K_THIS s.macaddr[i] = 0x57;
+
+ // Attach to the simulated ethernet dev
+ char *ethmod = bx_options.ne2k.Oethmod->get_choice(bx_options.ne2k.Oethmod->get());
+ BX_NE2K_THIS ethdev = eth_locator_c::create(ethmod,
+ bx_options.ne2k.Oethdev->getptr (),
+ (const char *) bx_options.ne2k.Omacaddr->getptr (),
+ rx_handler,
+ this);
+
+ if (BX_NE2K_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_NE2K_THIS ethdev = eth_locator_c::create("null", NULL,
+ (const char *) bx_options.ne2k.Omacaddr->getptr (),
+ rx_handler,
+ this);
+ if (BX_NE2K_THIS ethdev == NULL)
+ BX_PANIC(("could not locate null module"));
+ }
+
+ // Bring the register state into power-up state
+ theNE2kDevice->reset(BX_RESET_HARDWARE);
+}
+
+#if BX_DEBUGGER
+
+/*
+ * this implements the info ne2k commands in the debugger.
+ * info ne2k - shows all registers
+ * info ne2k page N - shows all registers in a page
+ * info ne2k page N reg M - shows just one register
+ */
+
+#define SHOW_FIELD(reg,field) do { \
+ if (n>0 && !(n%5)) dbg_printf ("\n "); \
+ dbg_printf ("%s=%d ", #field, BX_NE2K_THIS s.reg.field); \
+ n++; \
+} while (0);
+#define BX_HIGH_BYTE(x) ((0xff00 & (x)) >> 8)
+#define BX_LOW_BYTE(x) (0x00ff & (x))
+#define BX_DUPLICATE(n) if (brief && num!=n) break;
+
+void
+bx_ne2k_c::print_info (FILE *fp, int page, int reg, int brief)
+{
+ int i;
+ int n = 0;
+ if (page < 0) {
+ for (page=0; page<=2; page++)
+ theNE2kDevice->print_info (fp, page, reg, 1);
+ // tell them how to use this command
+ dbg_printf ("\nHow to use the info ne2k command:\n");
+ dbg_printf ("info ne2k - show all registers\n");
+ dbg_printf ("info ne2k page N - show registers in page N\n");
+ dbg_printf ("info ne2k page N reg M - show just one register\n");
+ return;
+ }
+ if (page > 2) {
+ dbg_printf ("NE2K has only pages 0, 1, and 2. Page %d is out of range.\n", page);
+ return;
+ }
+ if (reg < 0) {
+ dbg_printf ("NE2K registers, page %d\n", page);
+ dbg_printf ("----------------------\n");
+ for (reg=0; reg<=15; reg++)
+ theNE2kDevice->print_info (fp, page, reg, 1);
+ dbg_printf ("----------------------\n");
+ return;
+ }
+ if (reg > 15) {
+ dbg_printf ("NE2K has only registers 0-15 (0x0-0xf). Register %d is out of range.\n", reg);
+ return;
+ }
+ if (!brief) {
+ dbg_printf ("NE2K Info - page %d, register 0x%02x\n", page, reg);
+ dbg_printf ("----------------------------------\n");
+ }
+ int num = page*0x100 + reg;
+ switch (num) {
+ case 0x0000:
+ case 0x0100:
+ case 0x0200:
+ dbg_printf ("CR (Command register):\n ");
+ SHOW_FIELD (CR, stop);
+ SHOW_FIELD (CR, start);
+ SHOW_FIELD (CR, tx_packet);
+ SHOW_FIELD (CR, rdma_cmd);
+ SHOW_FIELD (CR, pgsel);
+ dbg_printf ("\n");
+ break;
+ case 0x0003:
+ dbg_printf ("BNRY = Boundary Pointer = 0x%02x\n", BX_NE2K_THIS s.bound_ptr);
+ break;
+ case 0x0004:
+ dbg_printf ("TSR (Transmit Status Register), read-only:\n ");
+ SHOW_FIELD (TSR, tx_ok);
+ SHOW_FIELD (TSR, reserved);
+ SHOW_FIELD (TSR, collided);
+ SHOW_FIELD (TSR, aborted);
+ SHOW_FIELD (TSR, no_carrier);
+ SHOW_FIELD (TSR, fifo_ur);
+ SHOW_FIELD (TSR, cd_hbeat);
+ SHOW_FIELD (TSR, ow_coll);
+ dbg_printf ("\n");
+ // fall through into TPSR, no break line.
+ case 0x0204:
+ dbg_printf ("TPSR = Transmit Page Start = 0x%02x\n", BX_NE2K_THIS s.tx_page_start);
+ break;
+ case 0x0005:
+ case 0x0006: BX_DUPLICATE(0x0005);
+ dbg_printf ("NCR = Number of Collisions Register (read-only) = 0x%02x\n", BX_NE2K_THIS s.num_coll);
+ dbg_printf ("TBCR1,TBCR0 = Transmit Byte Count = %02x %02x\n",
+ BX_HIGH_BYTE (BX_NE2K_THIS s.tx_bytes),
+ BX_LOW_BYTE (BX_NE2K_THIS s.tx_bytes));
+ dbg_printf ("FIFO = %02x\n", BX_NE2K_THIS s.fifo);
+ break;
+ case 0x0007:
+ dbg_printf ("ISR (Interrupt Status Register):\n ");
+ SHOW_FIELD (ISR, pkt_rx);
+ SHOW_FIELD (ISR, pkt_tx);
+ SHOW_FIELD (ISR, rx_err);
+ SHOW_FIELD (ISR, tx_err);
+ SHOW_FIELD (ISR, overwrite);
+ SHOW_FIELD (ISR, cnt_oflow);
+ SHOW_FIELD (ISR, rdma_done);
+ SHOW_FIELD (ISR, reset);
+ dbg_printf ("\n");
+ break;
+ case 0x0008:
+ case 0x0009: BX_DUPLICATE(0x0008);
+ dbg_printf ("CRDA1,0 = Current remote DMA address = %02x %02x\n",
+ BX_HIGH_BYTE (BX_NE2K_THIS s.remote_dma),
+ BX_LOW_BYTE (BX_NE2K_THIS s.remote_dma));
+ dbg_printf ("RSAR1,0 = Remote start address = %02x %02x\n",
+ BX_HIGH_BYTE(s.remote_start),
+ BX_LOW_BYTE(s.remote_start));
+ break;
+ case 0x000a:
+ case 0x000b: BX_DUPLICATE(0x000a);
+ dbg_printf ("RCBR1,0 = Remote byte count = %02x\n", BX_NE2K_THIS s.remote_bytes);
+ break;
+ case 0x000c:
+ dbg_printf ("RSR (Receive Status Register), read-only:\n ");
+ SHOW_FIELD (RSR, rx_ok);
+ SHOW_FIELD (RSR, bad_crc);
+ SHOW_FIELD (RSR, bad_falign);
+ SHOW_FIELD (RSR, fifo_or);
+ SHOW_FIELD (RSR, rx_missed);
+ SHOW_FIELD (RSR, rx_mbit);
+ SHOW_FIELD (RSR, rx_disabled);
+ SHOW_FIELD (RSR, deferred);
+ dbg_printf ("\n");
+ // fall through into RCR
+ case 0x020c:
+ dbg_printf ("RCR (Receive Configuration Register):\n ");
+ SHOW_FIELD (RCR, errors_ok);
+ SHOW_FIELD (RCR, runts_ok);
+ SHOW_FIELD (RCR, broadcast);
+ SHOW_FIELD (RCR, multicast);
+ SHOW_FIELD (RCR, promisc);
+ SHOW_FIELD (RCR, monitor);
+ SHOW_FIELD (RCR, reserved);
+ dbg_printf ("\n");
+ break;
+ case 0x000d:
+ dbg_printf ("CNTR0 = Tally Counter 0 (Frame alignment errors) = %02x\n",
+ BX_NE2K_THIS s.tallycnt_0);
+ // fall through into TCR
+ case 0x020d:
+ dbg_printf ("TCR (Transmit Configuration Register):\n ");
+ SHOW_FIELD (TCR, crc_disable);
+ SHOW_FIELD (TCR, loop_cntl);
+ SHOW_FIELD (TCR, ext_stoptx);
+ SHOW_FIELD (TCR, coll_prio);
+ SHOW_FIELD (TCR, reserved);
+ dbg_printf ("\n");
+ break;
+ case 0x000e:
+ dbg_printf ("CNTR1 = Tally Counter 1 (CRC Errors) = %02x\n",
+ BX_NE2K_THIS s.tallycnt_1);
+ // fall through into DCR
+ case 0x020e:
+ dbg_printf ("DCR (Data Configuration Register):\n ");
+ SHOW_FIELD (DCR, wdsize);
+ SHOW_FIELD (DCR, endian);
+ SHOW_FIELD (DCR, longaddr);
+ SHOW_FIELD (DCR, loop);
+ SHOW_FIELD (DCR, auto_rx);
+ SHOW_FIELD (DCR, fifo_size);
+ dbg_printf ("\n");
+ break;
+ case 0x000f:
+ dbg_printf ("CNTR2 = Tally Counter 2 (Missed Packet Errors) = %02x\n",
+ BX_NE2K_THIS s.tallycnt_2);
+ // fall through into IMR
+ case 0x020f:
+ dbg_printf ("IMR (Interrupt Mask Register)\n ");
+ SHOW_FIELD (IMR, rx_inte);
+ SHOW_FIELD (IMR, tx_inte);
+ SHOW_FIELD (IMR, rxerr_inte);
+ SHOW_FIELD (IMR, txerr_inte);
+ SHOW_FIELD (IMR, overw_inte);
+ SHOW_FIELD (IMR, cofl_inte);
+ SHOW_FIELD (IMR, rdma_inte);
+ SHOW_FIELD (IMR, reserved);
+ dbg_printf ("\n");
+ break;
+ case 0x0101:
+ case 0x0102: BX_DUPLICATE(0x0101);
+ case 0x0103: BX_DUPLICATE(0x0101);
+ case 0x0104: BX_DUPLICATE(0x0101);
+ case 0x0105: BX_DUPLICATE(0x0101);
+ case 0x0106: BX_DUPLICATE(0x0101);
+ dbg_printf ("MAC address registers are located at page 1, registers 1-6.\n");
+ dbg_printf ("The MAC address is ");
+ for (i=0; i<=5; i++)
+ dbg_printf ("%02x%c", BX_NE2K_THIS s.physaddr[i], i<5?':' : '\n');
+ break;
+ case 0x0107:
+ dbg_printf ("Current page is 0x%02x\n", BX_NE2K_THIS s.curr_page);
+ break;
+ case 0x0108:
+ case 0x0109: BX_DUPLICATE(0x0108);
+ case 0x010A: BX_DUPLICATE(0x0108);
+ case 0x010B: BX_DUPLICATE(0x0108);
+ case 0x010C: BX_DUPLICATE(0x0108);
+ case 0x010D: BX_DUPLICATE(0x0108);
+ case 0x010E: BX_DUPLICATE(0x0108);
+ case 0x010F: BX_DUPLICATE(0x0108);
+ dbg_printf ("MAR0-7 (Multicast address registers 0-7) are set to:\n");
+ for (i=0; i<8; i++) dbg_printf ("%02x ", BX_NE2K_THIS s.mchash[i]);
+ dbg_printf ("\nMAR0 is listed first.\n");
+ break;
+ case 0x0001:
+ case 0x0002: BX_DUPLICATE(0x0001);
+ case 0x0201: BX_DUPLICATE(0x0001);
+ case 0x0202: BX_DUPLICATE(0x0001);
+ dbg_printf ("PSTART = Page start register = %02x\n", BX_NE2K_THIS s.page_start);
+ dbg_printf ("PSTOP = Page stop register = %02x\n", BX_NE2K_THIS s.page_stop);
+ dbg_printf ("Local DMA address = %02x %02x\n",
+ BX_HIGH_BYTE(BX_NE2K_THIS s.local_dma),
+ BX_LOW_BYTE(BX_NE2K_THIS s.local_dma));
+ break;
+ case 0x0203:
+ dbg_printf ("Remote Next Packet Pointer = %02x\n", BX_NE2K_THIS s.rempkt_ptr);
+ break;
+ case 0x0205:
+ dbg_printf ("Local Next Packet Pointer = %02x\n", BX_NE2K_THIS s.localpkt_ptr);
+ break;
+ case 0x0206:
+ case 0x0207: BX_DUPLICATE(0x0206);
+ dbg_printf ("Address Counter= %02x %02x\n",
+ BX_HIGH_BYTE(BX_NE2K_THIS s.address_cnt),
+ BX_LOW_BYTE(BX_NE2K_THIS s.address_cnt));
+ break;
+ case 0x0208:
+ case 0x0209: BX_DUPLICATE(0x0208);
+ case 0x020A: BX_DUPLICATE(0x0208);
+ case 0x020B: BX_DUPLICATE(0x0208);
+ if (!brief) dbg_printf ("Reserved\n");
+ case 0xffff:
+ dbg_printf ("IMR (Interrupt Mask Register):\n ");
+ dbg_printf ("\n");
+ break;
+ default:
+ dbg_printf ("NE2K info: sorry, page %d register %d cannot be displayed.\n", page, reg);
+ }
+ if (!brief)
+ dbg_printf ("\n");
+}
+
+#else
+
+void
+bx_ne2k_c::print_info (FILE *fp, int page, int reg, int brief)
+{
+}
+
+#endif
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/ne2k.h b/tools/ioemu/iodev/ne2k.h
new file mode 100644
index 0000000000..37cc712106
--- /dev/null
+++ b/tools/ioemu/iodev/ne2k.h
@@ -0,0 +1,239 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ne2k.h,v 1.11 2003/03/02 23:59:11 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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.
+//
+
+
+#if BX_USE_NE2K_SMF
+# define BX_NE2K_SMF static
+# define BX_NE2K_THIS theNE2kDevice->
+#else
+# define BX_NE2K_SMF
+# define BX_NE2K_THIS this->
+#endif
+
+#define BX_NE2K_MEMSIZ (32*1024)
+#define BX_NE2K_MEMSTART (16*1024)
+#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
+
+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;
+ int tx_timer_active;
+
+} bx_ne2k_t;
+
+
+
+class bx_ne2k_c : public bx_ne2k_stub_c {
+public:
+ bx_ne2k_c(void);
+ ~bx_ne2k_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+ virtual void print_info (FILE *file, int page, int reg, int nodups);
+
+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 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
+};
diff --git a/tools/ioemu/iodev/osdep.cc b/tools/ioemu/iodev/osdep.cc
new file mode 100644
index 0000000000..c010306c82
--- /dev/null
+++ b/tools/ioemu/iodev/osdep.cc
@@ -0,0 +1,340 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: osdep.cc,v 1.14.2.1 2004/02/06 22:14:34 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// osdep.cc
+//
+// Provide definition of library functions that are missing on various
+// systems. The only reason this is a .cc file rather than a .c file
+// is so that it can include bochs.h. Bochs.h includes all the required
+// system headers, with appropriate #ifdefs for different compilers and
+// platforms.
+//
+
+#include "bochs.h"
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions. These should work on any platform
+// that needs them.
+//////////////////////////////////////////////////////////////////////
+
+#if !BX_HAVE_SNPRINTF
+/* XXX use real snprintf */
+/* if they don't have snprintf, just use sprintf */
+int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
+{
+ va_list arg;
+ int done;
+
+ va_start (arg, format);
+ done = vsprintf (s, format, arg);
+ va_end (arg);
+
+ return done;
+}
+#endif /* !BX_HAVE_SNPRINTF */
+
+
+#if (!BX_HAVE_STRTOULL && !BX_HAVE_STRTOUQ)
+/* taken from glibc-2.2.2: strtod.c, and stripped down a lot. There are
+ still a few leftover references to decimal points and exponents,
+ but it works for bases 10 and 16 */
+
+#define RETURN(val,end) \
+ do { if (endptr != NULL) *endptr = (char *) (end); \
+ return val; } while (0)
+
+Bit64u
+bx_strtoull (const char *nptr, char **endptr, int baseignore)
+{
+ int negative; /* The sign of the number. */
+ int exponent; /* Exponent of the number. */
+
+ /* Numbers starting `0X' or `0x' have to be processed with base 16. */
+ int base = 10;
+
+ /* Number of bits currently in result value. */
+ int bits;
+
+ /* Running pointer after the last character processed in the string. */
+ const char *cp, *tp;
+ /* Start of significant part of the number. */
+ const char *startp, *start_of_digits;
+ /* Total number of digit and number of digits in integer part. */
+ int dig_no;
+ /* Contains the last character read. */
+ char c;
+
+ Bit64s n = 0;
+ char const *p;
+
+ /* Prepare number representation. */
+ exponent = 0;
+ negative = 0;
+ bits = 0;
+
+ /* Parse string to get maximal legal prefix. We need the number of
+ characters of the integer part, the fractional part and the exponent. */
+ cp = nptr - 1;
+ /* Ignore leading white space. */
+ do
+ c = *++cp;
+ while (isspace (c));
+
+ /* Get sign of the result. */
+ if (c == '-')
+ {
+ negative = 1;
+ c = *++cp;
+ }
+ else if (c == '+')
+ c = *++cp;
+
+ if (c < '0' || c > '9')
+ {
+ /* It is really a text we do not recognize. */
+ RETURN (0, nptr);
+ }
+
+ /* First look whether we are faced with a hexadecimal number. */
+ if (c == '0' && tolower (cp[1]) == 'x')
+ {
+ /* Okay, it is a hexa-decimal number. Remember this and skip
+ the characters. BTW: hexadecimal numbers must not be
+ grouped. */
+ base = 16;
+ cp += 2;
+ c = *cp;
+ }
+
+ /* Record the start of the digits, in case we will check their grouping. */
+ start_of_digits = startp = cp;
+
+ /* Ignore leading zeroes. This helps us to avoid useless computations. */
+ while (c == '0')
+ c = *++cp;
+
+ /* If no other digit but a '0' is found the result is 0.0.
+ Return current read pointer. */
+ if ((c < '0' || c > '9')
+ && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
+ && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
+ && (base != 16 && tolower (c) != 'e'))
+ {
+ tp = start_of_digits;
+ /* If TP is at the start of the digits, there was no correctly
+ grouped prefix of the string; so no number found. */
+ RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
+ }
+
+ /* Remember first significant digit and read following characters until the
+ decimal point, exponent character or any non-FP number character. */
+ startp = cp;
+ dig_no = 0;
+ while (1)
+ {
+ if ((c >= '0' && c <= '9')
+ || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
+ ++dig_no;
+ else
+ break;
+ c = *++cp;
+ }
+
+ /* The whole string is parsed. Store the address of the next character. */
+ if (endptr)
+ *endptr = (char *) cp;
+
+ if (dig_no == 0)
+ return 0;
+
+ for (p=start_of_digits; p!=cp; p++) {
+ n = n * (Bit64s)base;
+ c = tolower (*p);
+ c = (c >= 'a') ? (10+c-'a') : c-'0';
+ n = n + (Bit64s)c;
+ //printf ("after shifting in digit %c, n is %lld\n", *p, n);
+ }
+ return negative? -n : n;
+}
+#endif /* !BX_HAVE_STRTOULL */
+
+#if BX_TEST_STRTOULL_MAIN
+/* test driver for strtoull. Do not compile by default. */
+int main (int argc, char **argv)
+{
+ char buf[256], *endbuf;
+ long l;
+ Bit64s ll;
+ while (1) {
+ printf ("Enter a long int: ");
+ gets (buf);
+ l = strtoul (buf, &endbuf, 10);
+ printf ("As a long, %ld\n", l);
+ printf ("Endbuf is at buf[%d]\n", endbuf-buf);
+ ll = bx_strtoull (buf, &endbuf, 10);
+ printf ("As a long long, %lld\n", ll);
+ printf ("Endbuf is at buf[%d]\n", endbuf-buf);
+ }
+ return 0;
+}
+#endif /* BX_TEST_STRTOULL_MAIN */
+
+#if !BX_HAVE_STRDUP
+/* XXX use real strdup */
+char *bx_strdup(const char *str)
+{
+ char *temp;
+
+ temp = (char*)malloc(strlen(str)+1);
+ sprintf(temp, "%s", str);
+ return temp;
+
+ // Well, I'm sure this isn't how strdup is REALLY implemented,
+ // but it works...
+}
+#endif /* !BX_HAVE_STRDUP */
+
+#if !BX_HAVE_STRREV
+char *bx_strrev(char *str)
+{
+ char *p1, *p2;
+
+ if (! str || ! *str)
+ return str;
+
+ for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
+ *p1 ^= *p2;
+ *p2 ^= *p1;
+ *p1 ^= *p2;
+ }
+ return str;
+}
+#endif /* !BX_HAVE_STRREV */
+
+#if BX_WITH_MACOS
+namespace std{extern "C" {char *mktemp(char *tpl);}}
+#endif
+#if !BX_HAVE_MKSTEMP
+int bx_mkstemp(char *tpl)
+{
+ mktemp(tpl);
+ return ::open(tpl, O_RDWR | O_CREAT | O_TRUNC
+# ifdef O_BINARY
+ | O_BINARY
+# endif
+ , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
+}
+#endif // !BX_HAVE_MKSTEMP
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions, implemented for MacOS only
+//////////////////////////////////////////////////////////////////////
+
+#if BX_WITH_MACOS
+// these functions are part of MacBochs. They are not intended to be
+// portable!
+#include <Devices.h>
+#include <Files.h>
+#include <Disks.h>
+
+int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
+{
+ OSErr err;
+ IOParam param;
+
+ param.ioRefNum=-5; // Refnum of the floppy disk driver
+ param.ioVRefNum=1;
+ param.ioPosMode=fsFromStart;
+ param.ioPosOffset=offset;
+ param.ioBuffer=buffer;
+ param.ioReqCount=bytes;
+ err = PBReadSync((union ParamBlockRec *)(&param));
+ return param.ioActCount;
+}
+
+int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
+{
+ OSErr err;
+ IOParam param;
+
+ param.ioRefNum=-5; // Refnum of the floppy disk driver
+ param.ioVRefNum=1;
+ param.ioPosMode=fsFromStart;
+ param.ioPosOffset=offset;
+ param.ioBuffer=buffer;
+ param.ioReqCount=bytes;
+ err = PBWriteSync((union ParamBlockRec *)(&param));
+ return param.ioActCount;
+}
+
+int fd_stat(struct stat *buf)
+{
+ OSErr err;
+ DrvSts status;
+ int result;
+
+ result = 0;
+ err = DriveStatus(1, &status);
+ if (status.diskInPlace <1 || status.diskInPlace > 2)
+ result = -1;
+ buf->st_mode = S_IFCHR;
+ return result;
+}
+#endif /* BX_WITH_MACOS */
+
+
+
+//////////////////////////////////////////////////////////////////////
+// New functions to replace library functions
+// with OS-independent versions
+//////////////////////////////////////////////////////////////////////
+
+#if BX_HAVE_REALTIME_USEC
+# if BX_HAVE_GETTIMEOFDAY
+Bit64u bx_get_realtime64_usec (void) {
+ timeval thetime;
+ gettimeofday(&thetime,0);
+ Bit64u mytime;
+ mytime=(Bit64u)thetime.tv_sec*(Bit64u)1000000+(Bit64u)thetime.tv_usec;
+ return mytime;
+}
+# elif defined(WIN32)
+Bit64u last_realtime64_top = 0;
+Bit64u last_realtime64_bottom = 0;
+Bit64u bx_get_realtime64_usec (void) {
+ Bit64u new_bottom = ((Bit64u) GetTickCount()) & BX_CONST64(0x0FFFFFFFF);
+ if(new_bottom < last_realtime64_bottom) {
+ last_realtime64_top += BX_CONST64(0x0000000100000000);
+ }
+ last_realtime64_bottom = new_bottom;
+ Bit64u interim_realtime64 =
+ (last_realtime64_top & BX_CONST64(0xFFFFFFFF00000000)) |
+ (new_bottom & BX_CONST64(0x00000000FFFFFFFF));
+ return interim_realtime64*(BX_CONST64(1000));
+}
+# endif
+#endif
diff --git a/tools/ioemu/iodev/parallel.cc b/tools/ioemu/iodev/parallel.cc
new file mode 100644
index 0000000000..8b0d4b3245
--- /dev/null
+++ b/tools/ioemu/iodev/parallel.cc
@@ -0,0 +1,300 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: parallel.cc,v 1.24 2003/10/29 17:29:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////
+// 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 "bochs.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_devices.pluginParallelDevice = theParallelDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theParallelDevice, BX_PLUGIN_PARALLEL);
+ return(0); // Success
+}
+
+ void
+libparallel_LTX_plugin_fini(void)
+{
+}
+
+bx_parallel_c::bx_parallel_c(void)
+{
+ put("PAR");
+ settype(PARLOG);
+ s.output = NULL;
+}
+
+bx_parallel_c::~bx_parallel_c(void)
+{
+ if (s.output != NULL)
+ fclose(s.output);
+}
+
+ void
+bx_parallel_c::init(void)
+{
+ BX_DEBUG(("Init $Id: parallel.cc,v 1.24 2003/10/29 17:29:26 vruppert Exp $"));
+
+ if (bx_options.par[0].Oenabled->get ()) {
+
+ /* PARALLEL PORT 1 */
+
+ DEV_register_irq(7, "Parallel Port 1");
+ BX_INFO (("parallel port 1 at 0x378 irq 7"));
+ for (unsigned addr=0x0378; addr<=0x037A; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "Parallel Port 1", 1);
+ }
+ DEV_register_iowrite_handler(this, write_handler, 0x0378, "Parallel Port 1", 1);
+ DEV_register_iowrite_handler(this, write_handler, 0x037A, "Parallel Port 1", 1);
+
+ BX_PAR_THIS s.STATUS.error = 1;
+ BX_PAR_THIS s.STATUS.slct = 1;
+ BX_PAR_THIS s.STATUS.pe = 0;
+ BX_PAR_THIS s.STATUS.ack = 1;
+ BX_PAR_THIS s.STATUS.busy = 1;
+
+ BX_PAR_THIS s.CONTROL.strobe = 0;
+ BX_PAR_THIS s.CONTROL.autofeed = 0;
+ BX_PAR_THIS s.CONTROL.init = 1;
+ BX_PAR_THIS s.CONTROL.slct_in = 1;
+ BX_PAR_THIS s.CONTROL.irq = 0;
+ BX_PAR_THIS s.CONTROL.input = 0;
+
+ BX_PAR_THIS s.initmode = 0;
+
+ if (strlen(bx_options.par[0].Ooutfile->getptr ()) > 0) {
+ s.output = fopen(bx_options.par[0].Ooutfile->getptr (), "wb");
+ if (!s.output)
+ BX_PANIC (("Could not open '%s' to write parport1 output",
+ bx_options.par[0].Ooutfile->getptr ()));
+ }
+ }
+}
+
+ void
+bx_parallel_c::reset(unsigned type)
+{
+}
+
+ void
+bx_parallel_c::virtual_printer(void)
+{
+ if (BX_PAR_THIS s.STATUS.slct) {
+ if (BX_PAR_THIS s.output != NULL) {
+ fputc(BX_PAR_THIS s.data, BX_PAR_THIS s.output);
+ fflush (BX_PAR_THIS s.output);
+ }
+ if (BX_PAR_THIS s.CONTROL.irq == 1) {
+ DEV_pic_raise_irq(7);
+ }
+ BX_PAR_THIS s.STATUS.ack = 0;
+ BX_PAR_THIS s.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
+
+ Bit32u retval;
+
+ switch (address) {
+ /* PARALLEL PORT 1 */
+ case 0x0378:
+ if (!BX_PAR_THIS s.CONTROL.input) {
+ return (Bit32u)BX_PAR_THIS s.data;
+ } else {
+ BX_ERROR(("read: input mode not supported"));
+ return (0xFF);
+ }
+ break;
+ case 0x0379:
+ {
+ retval = ((BX_PAR_THIS s.STATUS.busy << 7) |
+ (BX_PAR_THIS s.STATUS.ack << 6) |
+ (BX_PAR_THIS s.STATUS.pe << 5) |
+ (BX_PAR_THIS s.STATUS.slct << 4) |
+ (BX_PAR_THIS s.STATUS.error << 3));
+ if (BX_PAR_THIS s.STATUS.ack == 0) {
+ BX_PAR_THIS s.STATUS.ack = 1;
+ if (BX_PAR_THIS s.CONTROL.irq == 1) {
+ DEV_pic_lower_irq(7);
+ }
+ }
+ if (BX_PAR_THIS s.initmode == 1) {
+ BX_PAR_THIS s.STATUS.busy = 1;
+ BX_PAR_THIS s.STATUS.slct = 1;
+ BX_PAR_THIS s.STATUS.ack = 0;
+ if (BX_PAR_THIS s.CONTROL.irq == 1) {
+ DEV_pic_raise_irq(7);
+ }
+ BX_PAR_THIS s.initmode = 0;
+ }
+ BX_DEBUG(("read: status register returns 0x%02x", retval));
+ return retval;
+ }
+ break;
+ case 0x037A:
+ {
+ retval = ((BX_PAR_THIS s.CONTROL.input << 5) |
+ (BX_PAR_THIS s.CONTROL.irq << 4) |
+ (BX_PAR_THIS s.CONTROL.slct_in << 3) |
+ (BX_PAR_THIS s.CONTROL.init << 2) |
+ (BX_PAR_THIS s.CONTROL.autofeed << 1) |
+ (BX_PAR_THIS s.CONTROL.strobe));
+ BX_DEBUG(("read: control register returns 0x%02x", 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
+
+ switch (address) {
+ /* PARALLEL PORT 1 */
+ case 0x0378:
+ BX_PAR_THIS s.data = (Bit8u)value;
+ BX_DEBUG(("write: data output register = 0x%02x", (Bit8u)value));
+ break;
+ case 0x037A:
+ {
+ if ((value & 0x01) == 0x01) {
+ if (BX_PAR_THIS s.CONTROL.strobe == 0) {
+ BX_PAR_THIS s.CONTROL.strobe = 1;
+ virtual_printer(); // data is valid now
+ }
+ } else {
+ if (BX_PAR_THIS s.CONTROL.strobe == 1) {
+ BX_PAR_THIS s.CONTROL.strobe = 0;
+ }
+ }
+ BX_PAR_THIS s.CONTROL.autofeed = ((value & 0x02) == 0x02);
+ if ((value & 0x04) == 0x04) {
+ if (BX_PAR_THIS s.CONTROL.init == 0) {
+ BX_PAR_THIS s.CONTROL.init = 1;
+ BX_PAR_THIS s.STATUS.busy = 0;
+ BX_PAR_THIS s.STATUS.slct = 0;
+ BX_PAR_THIS s.initmode = 1;
+ BX_DEBUG(("printer init requested"));
+ }
+ } else {
+ if (BX_PAR_THIS s.CONTROL.init == 1) {
+ BX_PAR_THIS s.CONTROL.init = 0;
+ }
+ }
+ if ((value & 0x08) == 0x08) {
+ if (BX_PAR_THIS s.CONTROL.slct_in == 0) {
+ BX_PAR_THIS s.CONTROL.slct_in = 1;
+ BX_DEBUG(("printer now online"));
+ }
+ } else {
+ if (BX_PAR_THIS s.CONTROL.slct_in == 1) {
+ BX_PAR_THIS s.CONTROL.slct_in = 0;
+ BX_DEBUG(("printer now offline"));
+ }
+ }
+ BX_PAR_THIS s.STATUS.slct = BX_PAR_THIS s.CONTROL.slct_in;
+ if ((value & 0x10) == 0x10) {
+ if (BX_PAR_THIS s.CONTROL.irq == 0) {
+ BX_PAR_THIS s.CONTROL.irq = 1;
+ BX_DEBUG(("irq mode selected"));
+ }
+ } else {
+ if (BX_PAR_THIS s.CONTROL.irq == 1) {
+ BX_PAR_THIS s.CONTROL.irq = 0;
+ BX_DEBUG(("polling mode selected"));
+ }
+ }
+ if ((value & 0x20) == 0x20) {
+ if (BX_PAR_THIS s.CONTROL.input == 0) {
+ BX_PAR_THIS s.CONTROL.input = 1;
+ BX_DEBUG(("data input mode selected"));
+ }
+ } else {
+ if (BX_PAR_THIS s.CONTROL.input == 1) {
+ BX_PAR_THIS s.CONTROL.input = 0;
+ BX_DEBUG(("data output mode selected"));
+ }
+ }
+ if ((value & 0xC0) > 0) {
+ BX_ERROR(("write: unsupported control bit ignored"));
+ }
+ }
+ break;
+ }
+}
diff --git a/tools/ioemu/iodev/parallel.h b/tools/ioemu/iodev/parallel.h
new file mode 100644
index 0000000000..b4a256a616
--- /dev/null
+++ b/tools/ioemu/iodev/parallel.h
@@ -0,0 +1,78 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: parallel.h,v 1.11 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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
+
+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;
+ FILE *output;
+ bx_bool initmode;
+} bx_par_t;
+
+
+
+class bx_parallel_c : public bx_devmodel_c {
+public:
+
+ bx_parallel_c(void);
+ ~bx_parallel_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+
+private:
+ bx_par_t s;
+
+ static void virtual_printer();
+
+ 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
+ };
diff --git a/tools/ioemu/iodev/pc_system.cc b/tools/ioemu/iodev/pc_system.cc
new file mode 100644
index 0000000000..de34d9914b
--- /dev/null
+++ b/tools/ioemu/iodev/pc_system.cc
@@ -0,0 +1,570 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pc_system.cc,v 1.34 2003/06/07 19:16:51 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+#define LOG_THIS bx_pc_system.
+
+#ifdef WIN32
+#ifndef __MINGW32__
+// #include <winsock2.h> // +++
+#include <winsock.h>
+#endif
+#endif
+
+#if BX_SHOW_IPS
+unsigned long ips_count=0;
+#endif
+
+#if defined(PROVIDE_M_IPS)
+double m_ips; // Millions of Instructions Per Second
+#endif
+
+#ifdef BX_USE_VMX
+unsigned int tsc_per_bx_tick;
+#endif
+
+// Option for turning off BX_TIMER_DEBUG?
+// Check out m_ips and ips
+
+#define SpewPeriodicTimerInfo 0
+#define MinAllowableTimerPeriod 1
+
+
+#if SpewPeriodicTimerInfo
+// If debugging, set the heartbeat to 5M cycles. Each heartbeat
+// spews the active timer info.
+const Bit64u bx_pc_system_c::NullTimerInterval = 5000000;
+#else
+// This must be the maximum 32-bit unsigned int value, NOT (Bit64u) -1.
+const Bit64u bx_pc_system_c::NullTimerInterval = 0xffffffff;
+#endif
+
+ // constructor
+bx_pc_system_c::bx_pc_system_c(void)
+{
+ this->put("SYS");
+
+ // Timer[0] is the null timer. It is initialized as a special
+ // case here. It should never be turned off or modified, and its
+ // duration should always remain the same.
+ ticksTotal = 0; // Reset ticks since emulator started.
+ timer[0].period = NullTimerInterval;
+ timer[0].timeToFire = ticksTotal + NullTimerInterval;
+ timer[0].active = 1;
+ timer[0].continuous = 1;
+ timer[0].funct = nullTimer;
+ timer[0].this_ptr = this;
+ currCountdown = NullTimerInterval;
+ currCountdownPeriod = NullTimerInterval;
+ numTimers = 1; // So far, only the nullTimer.
+ lastTimeUsec = 0;
+ usecSinceLast = 0;
+}
+
+ void
+bx_pc_system_c::init_ips(Bit32u ips)
+{
+ HRQ = 0;
+
+ enable_a20 = 1;
+ //set_INTR (0);
+
+#if BX_CPU_LEVEL < 2
+ a20_mask = 0xfffff;
+#elif BX_CPU_LEVEL == 2
+ a20_mask = 0xffffff;
+#else /* 386+ */
+ a20_mask = 0xffffffff;
+#endif
+
+#ifdef BX_USE_VMX
+ Bit64u phy_cpu_freq = cpu_calibrate_ticks();
+
+ if (ips == 500000) { //default ips: we use fixed scaling factor to calulate ips
+ tsc_per_bx_tick = 2000;
+ ips = phy_cpu_freq / tsc_per_bx_tick;
+ } else //use uesr defined ips to calulate factor
+ tsc_per_bx_tick = ((phy_cpu_freq + (ips>>1)) / ips);
+#endif
+
+ // parameter 'ips' is the processor speed in Instructions-Per-Second
+ m_ips = double(ips) / 1000000.0L;
+
+ BX_DEBUG(("ips = %u", (unsigned) ips));
+}
+
+ void
+bx_pc_system_c::set_HRQ(bx_bool val)
+{
+ HRQ = val;
+ if (val)
+ BX_CPU(0)->async_event = 1;
+}
+
+
+#if (BX_NUM_SIMULATORS < 2)
+ void
+bx_pc_system_c::set_INTR(bx_bool value)
+{
+ if (bx_dbg.interrupts)
+ BX_INFO(("pc_system: Setting INTR=%d on bootstrap processor %d", (int)value, BX_BOOTSTRAP_PROCESSOR));
+ //INTR = value;
+ BX_CPU(BX_BOOTSTRAP_PROCESSOR)->set_INTR(value);
+}
+#endif
+
+//
+// Read from the IO memory address space
+//
+
+ Bit32u BX_CPP_AttrRegparmN(2)
+bx_pc_system_c::inp(Bit16u addr, unsigned io_len)
+{
+ Bit32u ret;
+
+ ret = bx_devices.inp(addr, io_len);
+
+ return( ret );
+}
+
+
+//
+// Write to the IO memory address space.
+//
+
+ void BX_CPP_AttrRegparmN(3)
+bx_pc_system_c::outp(Bit16u addr, Bit32u value, unsigned io_len)
+{
+ bx_devices.outp(addr, value, io_len);
+}
+
+ void BX_CPP_AttrRegparmN(1)
+bx_pc_system_c::set_enable_a20(Bit8u value)
+{
+#if BX_CPU_LEVEL < 2
+ BX_PANIC(("set_enable_a20() called: 8086 emulation"));
+#else
+
+#if BX_SUPPORT_A20
+ unsigned old_enable_a20 = enable_a20;
+
+ if (value) {
+ enable_a20 = 1;
+#if BX_CPU_LEVEL == 2
+ a20_mask = 0xffffff; /* 286: enable all 24 address lines */
+#else /* 386+ */
+ a20_mask = 0xffffffff; /* 386: enable all 32 address lines */
+#endif
+ }
+ else {
+ enable_a20 = 0;
+ a20_mask = 0xffefffff; /* mask off A20 address line */
+ }
+
+ BX_DBG_A20_REPORT(value);
+
+ BX_DEBUG(("A20: set() = %u", (unsigned) enable_a20));
+
+ // If there has been a transition, we need to notify the CPUs so
+ // they can potentially invalidate certain cache info based on
+ // A20-line-applied physical addresses.
+ if (old_enable_a20 != enable_a20) {
+ for (unsigned i=0; i<BX_SMP_PROCESSORS; i++)
+ BX_CPU(i)->pagingA20Changed();
+ }
+#else
+ BX_DEBUG(("set_enable_a20: ignoring: SUPPORT_A20 = 0"));
+#endif // #if BX_SUPPORT_A20
+
+#endif
+}
+
+ bx_bool
+bx_pc_system_c::get_enable_a20(void)
+{
+#if BX_SUPPORT_A20
+ if (bx_dbg.a20)
+ BX_INFO(("A20: get() = %u", (unsigned) enable_a20));
+
+ if (enable_a20) return(1);
+ else return(0);
+#else
+ BX_INFO(("get_enable_a20: ignoring: SUPPORT_A20 = 0"));
+ return(1);
+#endif // #if BX_SUPPORT_A20
+}
+
+ int
+bx_pc_system_c::ResetSignal( PCS_OP operation )
+{
+ UNUSED( operation );
+ // Reset the processor.
+
+ BX_ERROR(( "# bx_pc_system_c::ResetSignal() called" ));
+ for (int i=0; i<BX_SMP_PROCESSORS; i++)
+ BX_CPU(i)->reset(BX_RESET_SOFTWARE);
+ DEV_reset_devices(BX_RESET_SOFTWARE);
+ return(0);
+}
+
+
+ Bit8u
+bx_pc_system_c::IAC(void)
+{
+ return( DEV_pic_iac() );
+}
+
+ void
+bx_pc_system_c::exit(void)
+{
+ if (DEV_hd_present())
+ DEV_hd_close_harddrive();
+
+ BX_INFO(("Last time is %u", (unsigned) DEV_cmos_get_timeval()));
+
+ if (bx_gui) bx_gui->exit();
+}
+
+
+// ================================================
+// Bochs internal timer delivery framework features
+// ================================================
+
+ int
+bx_pc_system_c::register_timer( void *this_ptr, void (*funct)(void *),
+ Bit32u useconds, bx_bool continuous, bx_bool active, const char *id)
+{
+ Bit64u ticks;
+
+ // Convert useconds to number of ticks.
+ ticks = (Bit64u) (double(useconds) * m_ips);
+
+ return register_timer_ticks(this_ptr, funct, ticks, continuous, active, id);
+}
+
+ int
+bx_pc_system_c::register_timer_ticks(void* this_ptr, bx_timer_handler_t funct,
+ Bit64u ticks, bx_bool continuous, bx_bool active, const char *id)
+{
+ unsigned i;
+
+#if BX_TIMER_DEBUG
+ if (numTimers >= BX_MAX_TIMERS) {
+ BX_PANIC(("register_timer: too many registered timers."));
+ }
+ if (this_ptr == NULL)
+ BX_PANIC(("register_timer_ticks: this_ptr is NULL"));
+ if (funct == NULL)
+ BX_PANIC(("register_timer_ticks: funct is NULL"));
+#endif
+
+ // If the timer frequency is rediculously low, make it more sane.
+ // This happens when 'ips' is too low.
+ if (ticks < MinAllowableTimerPeriod) {
+ //BX_INFO(("register_timer_ticks: adjusting ticks of %llu to min of %u",
+ // ticks, MinAllowableTimerPeriod));
+ ticks = MinAllowableTimerPeriod;
+ }
+
+ for (i=0; i < numTimers; i++) {
+ if (timer[i].inUse == 0)
+ break;
+ }
+
+ timer[i].inUse = 1;
+ timer[i].period = ticks;
+ timer[i].timeToFire = (ticksTotal + Bit64u(currCountdownPeriod-currCountdown)) +
+ ticks;
+ timer[i].active = active;
+ timer[i].continuous = continuous;
+ timer[i].funct = funct;
+ timer[i].this_ptr = this_ptr;
+ strncpy(timer[i].id, id, BxMaxTimerIDLen);
+ timer[i].id[BxMaxTimerIDLen-1] = 0; // Null terminate if not already.
+
+ if (active) {
+ if (ticks < Bit64u(currCountdown)) {
+ // This new timer needs to fire before the current countdown.
+ // Skew the current countdown and countdown period to be smaller
+ // by the delta.
+ currCountdownPeriod -= (currCountdown - Bit32u(ticks));
+ currCountdown = Bit32u(ticks);
+ }
+ }
+
+ // If we didn't find a free slot, increment the bound, numTimers.
+ if (i==numTimers)
+ numTimers++; // One new timer installed.
+
+ // Return timer id.
+ return(i);
+}
+
+
+ void
+bx_pc_system_c::countdownEvent(void)
+{
+ unsigned i;
+ Bit64u minTimeToFire;
+ bx_bool triggered[BX_MAX_TIMERS];
+
+ // The countdown decremented to 0. We need to service all the active
+ // timers, and invoke callbacks from those timers which have fired.
+#if BX_TIMER_DEBUG
+ if (currCountdown != 0)
+ BX_PANIC(("countdownEvent: ticks!=0"));
+#endif
+
+ // Increment global ticks counter by number of ticks which have
+ // elapsed since the last update.
+ ticksTotal += Bit64u(currCountdownPeriod);
+ minTimeToFire = (Bit64u) -1;
+
+ for (i=0; i < numTimers; i++) {
+ triggered[i] = 0; // Reset triggered flag.
+ if (timer[i].active) {
+#if BX_TIMER_DEBUG
+ if (ticksTotal > timer[i].timeToFire)
+ BX_PANIC(("countdownEvent: ticksTotal > timeToFire[%u], D " FMT_LL "u", i,
+ timer[i].timeToFire-ticksTotal));
+#endif
+ if (ticksTotal == timer[i].timeToFire) {
+ // This timer is ready to fire.
+ triggered[i] = 1;
+
+ if (timer[i].continuous==0) {
+ // If triggered timer is one-shot, deactive.
+ timer[i].active = 0;
+ }
+ else {
+ // Continuous timer, increment time-to-fire by period.
+ timer[i].timeToFire += timer[i].period;
+ if (timer[i].timeToFire < minTimeToFire)
+ minTimeToFire = timer[i].timeToFire;
+ }
+ }
+ else {
+ // This timer is not ready to fire yet.
+ if (timer[i].timeToFire < minTimeToFire)
+ minTimeToFire = timer[i].timeToFire;
+ }
+ }
+ }
+
+ // Calculate next countdown period. We need to do this before calling
+ // any of the callbacks, as they may call timer features, which need
+ // to be advanced to the next countdown cycle.
+ currCountdown = currCountdownPeriod =
+ Bit32u(minTimeToFire - ticksTotal);
+
+ for (i=0; i < numTimers; i++) {
+ // Call requested timer function. It may request a different
+ // timer period or deactivate etc.
+ if (triggered[i]) {
+ timer[i].funct(timer[i].this_ptr);
+ }
+ }
+}
+
+ void
+bx_pc_system_c::nullTimer(void* this_ptr)
+{
+ // This function is always inserted in timer[0]. It is sort of
+ // a heartbeat timer. It ensures that at least one timer is
+ // always active to make the timer logic more simple, and has
+ // a duration of less than the maximum 32-bit integer, so that
+ // a 32-bit size can be used for the hot countdown timer. The
+ // rest of the timer info can be 64-bits. This is also a good
+ // place for some logic to report actual emulated
+ // instructions-per-second (IPS) data when measured relative to
+ // the host computer's wall clock.
+
+ UNUSED(this_ptr);
+
+#if SpewPeriodicTimerInfo
+ BX_INFO(("==================================="));
+ for (unsigned i=0; i < bx_pc_system.numTimers; i++) {
+ if (bx_pc_system.timer[i].active) {
+ BX_INFO(("BxTimer(%s): period=" FMT_LL "u, continuous=%u",
+ bx_pc_system.timer[i].id, bx_pc_system.timer[i].period,
+ bx_pc_system.timer[i].continuous));
+ }
+ }
+#endif
+}
+
+#if BX_DEBUGGER
+ void
+bx_pc_system_c::timebp_handler(void* this_ptr)
+{
+ BX_CPU(0)->break_point = BREAK_POINT_TIME;
+ BX_DEBUG(( "Time breakpoint triggered" ));
+
+ if (timebp_queue_size > 1) {
+ Bit64s new_diff = timebp_queue[1] - bx_pc_system.time_ticks();
+ bx_pc_system.activate_timer_ticks(timebp_timer, new_diff, 1);
+ }
+ timebp_queue_size--;
+ for (int i = 0; i < timebp_queue_size; i++)
+ timebp_queue[i] = timebp_queue[i+1];
+}
+#endif // BX_DEBUGGER
+
+ Bit64u
+bx_pc_system_c::time_usec_sequential() {
+ Bit64u this_time_usec = time_usec();
+ if(this_time_usec != lastTimeUsec) {
+ Bit64u diff_usec = this_time_usec-lastTimeUsec;
+ lastTimeUsec = this_time_usec;
+ if(diff_usec >= usecSinceLast) {
+ usecSinceLast = 0;
+ } else {
+ usecSinceLast -= diff_usec;
+ }
+ }
+ usecSinceLast++;
+ return (this_time_usec+usecSinceLast);
+}
+ Bit64u
+bx_pc_system_c::time_usec() {
+ return (Bit64u) (((double)(Bit64s)time_ticks()) / m_ips );
+}
+
+ void
+bx_pc_system_c::start_timers(void)
+{
+}
+
+ void
+bx_pc_system_c::activate_timer_ticks(unsigned i, Bit64u ticks, bx_bool continuous)
+{
+#if BX_TIMER_DEBUG
+ if (i >= numTimers)
+ BX_PANIC(("activate_timer_ticks: timer %u OOB", i));
+ if (timer[i].period < MinAllowableTimerPeriod)
+ BX_PANIC(("activate_timer_ticks: timer[%u].period of " FMT_LL "u < min of %u",
+ i, timer[i].period, MinAllowableTimerPeriod));
+#endif
+
+ // If the timer frequency is rediculously low, make it more sane.
+ // This happens when 'ips' is too low.
+ if (ticks < MinAllowableTimerPeriod) {
+ //BX_INFO(("activate_timer_ticks: adjusting ticks of %llu to min of %u",
+ // ticks, MinAllowableTimerPeriod));
+ ticks = MinAllowableTimerPeriod;
+ }
+
+ timer[i].period = ticks;
+ timer[i].timeToFire = (ticksTotal + Bit64u(currCountdownPeriod-currCountdown)) +
+ ticks;
+ timer[i].active = 1;
+ timer[i].continuous = continuous;
+
+ if (ticks < Bit64u(currCountdown)) {
+ // This new timer needs to fire before the current countdown.
+ // Skew the current countdown and countdown period to be smaller
+ // by the delta.
+ currCountdownPeriod -= (currCountdown - Bit32u(ticks));
+ currCountdown = Bit32u(ticks);
+ }
+}
+
+ void
+bx_pc_system_c::activate_timer(unsigned i, Bit32u useconds, bx_bool continuous)
+{
+ Bit64u ticks;
+
+#if BX_TIMER_DEBUG
+ if (i >= numTimers)
+ BX_PANIC(("activate_timer: timer %u OOB", i));
+#endif
+
+ // if useconds = 0, use default stored in period field
+ // else set new period from useconds
+ if (useconds==0) {
+ ticks = timer[i].period;
+ }
+ else {
+ // convert useconds to number of ticks
+ ticks = (Bit64u) (double(useconds) * m_ips);
+
+ // If the timer frequency is rediculously low, make it more sane.
+ // This happens when 'ips' is too low.
+ if (ticks < MinAllowableTimerPeriod) {
+ //BX_INFO(("activate_timer: adjusting ticks of %llu to min of %u",
+ // ticks, MinAllowableTimerPeriod));
+ ticks = MinAllowableTimerPeriod;
+ }
+
+ timer[i].period = ticks;
+ }
+
+ activate_timer_ticks(i, ticks, continuous);
+}
+
+ void
+bx_pc_system_c::deactivate_timer( unsigned i )
+{
+#if BX_TIMER_DEBUG
+ if (i >= numTimers)
+ BX_PANIC(("deactivate_timer: timer %u OOB", i));
+#endif
+
+ timer[i].active = 0;
+}
+
+ unsigned
+bx_pc_system_c::unregisterTimer(int timerIndex)
+{
+ unsigned i = (unsigned) timerIndex;
+
+#if BX_TIMER_DEBUG
+ if (i >= numTimers)
+ BX_PANIC(("unregisterTimer: timer %u OOB", i));
+ if (i == 0)
+ BX_PANIC(("unregisterTimer: timer 0 is the nullTimer!"));
+ if (timer[i].inUse == 0)
+ BX_PANIC(("unregisterTimer: timer %u is not in-use!", i));
+#endif
+
+ if (timer[i].active) {
+ BX_PANIC(("unregisterTimer: timer '%s' is still active!", timer[i].id));
+ return(0); // Fail.
+ }
+
+ // Reset timer fields for good measure.
+ timer[i].inUse = 0; // No longer registered.
+ timer[i].period = BX_MAX_BIT64S; // Max value (invalid)
+ timer[i].timeToFire = BX_MAX_BIT64S; // Max value (invalid)
+ timer[i].continuous = 0;
+ timer[i].funct = NULL;
+ timer[i].this_ptr = NULL;
+ memset(timer[i].id, 0, BxMaxTimerIDLen);
+
+ return(1); // OK
+}
diff --git a/tools/ioemu/iodev/pci.cc b/tools/ioemu/iodev/pci.cc
new file mode 100644
index 0000000000..6dfe5dbbad
--- /dev/null
+++ b/tools/ioemu/iodev/pci.cc
@@ -0,0 +1,467 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci.cc,v 1.29 2003/07/31 19:51:42 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// 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 "bochs.h"
+#if BX_PCI_SUPPORT
+
+#define LOG_THIS thePciBridge->
+
+bx_pci_c *thePciBridge = NULL;
+
+ int
+libpci_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ thePciBridge = new bx_pci_c ();
+ bx_devices.pluginPciBridge = thePciBridge;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciBridge, BX_PLUGIN_PCI);
+ return(0); // Success
+}
+
+ void
+libpci_LTX_plugin_fini(void)
+{
+}
+
+bx_pci_c::bx_pci_c(void)
+{
+ put("PCI");
+ settype(PCILOG);
+}
+
+bx_pci_c::~bx_pci_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_pci_c::init(void)
+{
+ // called once when bochs initializes
+ unsigned i;
+ BX_PCI_THIS num_pci_handles = 0;
+
+ /* set unused elements to appropriate values */
+ for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
+ BX_PCI_THIS pci_handler[i].read = NULL;
+ BX_PCI_THIS pci_handler[i].write = NULL;
+ }
+
+ for (i=0; i < 0x100; i++) {
+ BX_PCI_THIS pci_handler_id[i] = BX_MAX_PCI_DEVICES; // not assigned
+ }
+
+ // 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);
+ }
+
+ DEV_register_pci_handlers(this, pci_read_handler, pci_write_handler,
+ BX_PCI_DEVICE(0,0), "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_c::reset(unsigned type)
+{
+ 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 (unsigned i=0x59; i<0x60; i++)
+ BX_PCI_THIS s.i440fx.pci_conf[i] = 0x00;
+}
+
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pci_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+ bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pci_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;
+ }
+ break;
+ 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].read)
+ (BX_PCI_THIS pci_handler[handle].this_ptr, 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_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+ bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_pci_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:
+ {
+ Bit32u handle;
+ 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)) {
+ if (((regnum>=4) && (regnum<=7)) || (regnum==12) || (regnum==13) || (regnum>14)) {
+ (* BX_PCI_THIS pci_handler[handle].write)
+ (BX_PCI_THIS pci_handler[handle].this_ptr, 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));
+ }
+}
+
+
+ // static pci configuration space read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pci_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+ bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+ return( class_ptr->pci_read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pci_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+ Bit32u val440fx = 0;
+
+ if (io_len <= 4) {
+ for (unsigned i=0; i<io_len; i++) {
+ val440fx |= (BX_PCI_THIS s.i440fx.pci_conf[address+i] << (i*8));
+ }
+ BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x", address, val440fx));
+ return val440fx;
+ }
+ else
+ return(0xffffffff);
+}
+
+
+ // static pci configuration space write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pci_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+ bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+ class_ptr->pci_write(address, value, io_len);
+}
+
+ void
+bx_pci_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+ Bit8u value8;
+
+ if (io_len <= 4) {
+ for (unsigned i=0; i<io_len; i++) {
+ value8 = (value >> (i*8)) & 0xFF;
+ switch (address+i) {
+ case 0x06:
+ case 0x0c:
+ break;
+ default:
+ BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
+ BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x", address,
+ value8));
+ }
+ }
+ }
+}
+
+
+ Bit8u
+bx_pci_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 !"));
+ return(0); // keep compiler happy
+ break;
+ }
+
+}
+
+ Bit8u
+bx_pci_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 !"));
+ return(0); // keep compiler happy
+ break;
+ }
+}
+
+ void
+bx_pci_c::print_i440fx_state()
+{
+ 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_c::register_pci_handlers( void *this_ptr, bx_pci_read_handler_t f1,
+ bx_pci_write_handler_t f2, Bit8u devfunc,
+ const char *name)
+{
+ unsigned handle;
+
+ /* first check if device/function is available */
+ if (BX_PCI_THIS pci_handler_id[devfunc] == BX_MAX_PCI_DEVICES) {
+ if (BX_PCI_THIS num_pci_handles >= 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_handles++;
+ BX_PCI_THIS pci_handler[handle].read = f1;
+ BX_PCI_THIS pci_handler[handle].write = f2;
+ BX_PCI_THIS pci_handler[handle].this_ptr = this_ptr;
+ BX_PCI_THIS pci_handler_id[devfunc] = handle;
+ BX_INFO(("%s present at device %d, function %d", name, devfunc >> 3,
+ devfunc & 0x07));
+ return true; // device/function mapped successfully
+ }
+ else {
+ return false; // device/function not available, return false.
+ }
+}
+#endif /* BX_PCI_SUPPORT */
diff --git a/tools/ioemu/iodev/pci.h b/tools/ioemu/iodev/pci.h
new file mode 100644
index 0000000000..92e7beef4f
--- /dev/null
+++ b/tools/ioemu/iodev/pci.h
@@ -0,0 +1,90 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci.h,v 1.14 2003/01/23 19:31:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#define BX_MAX_PCI_DEVICES 20
+
+#define BX_PCI_DEVICE(device, function) ((device)<<3 | (function))
+
+typedef Bit32u (*bx_pci_read_handler_t)(void *, Bit8u, unsigned);
+typedef void (*bx_pci_write_handler_t)(void *, Bit8u, Bit32u, unsigned);
+
+#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
+
+
+typedef struct {
+ Bit32u confAddr;
+ Bit32u confData;
+ Bit8u pci_conf[256];
+ } bx_def440fx_t;
+
+
+
+class bx_pci_c : public bx_pci_stub_c {
+
+public:
+ bx_pci_c(void);
+ ~bx_pci_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+ virtual bx_bool register_pci_handlers(void *this_ptr,
+ bx_pci_read_handler_t f1,
+ bx_pci_write_handler_t f2,
+ Bit8u devfunc, const char *name);
+ virtual void print_i440fx_state(void);
+ virtual Bit8u rd_memType (Bit32u addr);
+ virtual Bit8u wr_memType (Bit32u addr);
+
+private:
+ Bit8u pci_handler_id[0x100]; // 256 devices/functions
+ struct {
+ bx_pci_read_handler_t read;
+ bx_pci_write_handler_t write;
+ void *this_ptr;
+ } pci_handler[BX_MAX_PCI_DEVICES];
+ unsigned num_pci_handles;
+
+ struct {
+ bx_def440fx_t i440fx;
+ } 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);
+ static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+ static void pci_write_handler(void *this_ptr, Bit8u 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);
+ Bit32u pci_read(Bit8u address, unsigned io_len);
+ void pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+ };
diff --git a/tools/ioemu/iodev/pci2isa.cc b/tools/ioemu/iodev/pci2isa.cc
new file mode 100644
index 0000000000..54c3bc441a
--- /dev/null
+++ b/tools/ioemu/iodev/pci2isa.cc
@@ -0,0 +1,294 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci2isa.cc,v 1.10 2003/07/31 19:51:42 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// 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 "bochs.h"
+#if BX_PCI_SUPPORT
+
+#define LOG_THIS thePci2IsaBridge->
+
+bx_pci2isa_c *thePci2IsaBridge = NULL;
+
+ int
+libpci2isa_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ thePci2IsaBridge = new bx_pci2isa_c ();
+ bx_devices.pluginPci2IsaBridge = thePci2IsaBridge;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePci2IsaBridge, BX_PLUGIN_PCI2ISA);
+ return(0); // Success
+}
+
+ void
+libpci2isa_LTX_plugin_fini(void)
+{
+}
+
+bx_pci2isa_c::bx_pci2isa_c(void)
+{
+ put("P2I");
+ settype(PCI2ISALOG);
+}
+
+bx_pci2isa_c::~bx_pci2isa_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_pci2isa_c::init(void)
+{
+ // called once when bochs initializes
+
+ DEV_register_pci_handlers(this, pci_read_handler, pci_write_handler,
+ BX_PCI_DEVICE(1,0), "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 (unsigned i=0; i<256; i++)
+ BX_P2I_THIS s.pci_conf[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[0x0a] = 0x01;
+ BX_P2I_THIS s.pci_conf[0x0b] = 0x06;
+ BX_P2I_THIS s.pci_conf[0x0e] = 0x80;
+}
+
+ void
+bx_pci2isa_c::reset(unsigned type)
+{
+ BX_P2I_THIS s.pci_conf[0x04] = 0x07;
+ 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[0x60] = 0x80;
+ 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[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;
+
+ BX_P2I_THIS s.elcr1 = 0x00;
+ BX_P2I_THIS s.elcr2 = 0x00;
+}
+
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pci2isa_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+ bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pci2isa_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+ switch (address) {
+ case 0x00b2:
+ BX_ERROR(("read: APM command register not supported yet"));
+ break;
+ case 0x00b3:
+ BX_ERROR(("read: APM status register not supported yet"));
+ break;
+ case 0x04d0:
+ return(BX_P2I_THIS s.elcr1);
+ break;
+ case 0x04d1:
+ return(BX_P2I_THIS s.elcr2);
+ break;
+ case 0x0cf9:
+ BX_ERROR(("read: CPU reset register not supported yet"));
+ break;
+ }
+
+ return(0xffffffff);
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pci2isa_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+ bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_pci2isa_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+ switch (address) {
+ case 0x00b2:
+ BX_ERROR(("write: APM command register not supported yet"));
+ break;
+ case 0x00b3:
+ BX_ERROR(("write: APM status register not supported yet"));
+ break;
+ case 0x04d0:
+ BX_P2I_THIS s.elcr1 = (value & 0xf8);
+ BX_ERROR(("write: ELCR1 changes have no effect yet"));
+ break;
+ case 0x04d1:
+ BX_P2I_THIS s.elcr2 = (value & 0xde);
+ BX_ERROR(("write: ELCR2 changes have no effect yet"));
+ break;
+ case 0x0cf9:
+ BX_ERROR(("write: CPU reset register not supported yet"));
+ break;
+ }
+}
+
+
+ // static pci configuration space read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pci2isa_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+ bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+ return( class_ptr->pci_read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pci2isa_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+ Bit32u value = 0;
+
+ if (io_len <= 4) {
+ 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;
+ }
+ else
+ return(0xffffffff);
+}
+
+
+ // static pci configuration space write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pci2isa_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+ bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+ class_ptr->pci_write(address, value, io_len);
+}
+
+ void
+bx_pci2isa_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+ Bit8u value8;
+
+ if (io_len <= 4) {
+ for (unsigned i=0; i<io_len; i++) {
+ value8 = (value >> (i*8)) & 0xFF;
+ switch (address+i) {
+ case 0x06:
+ 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,
+ value8));
+ }
+ }
+ }
+}
+
+#endif /* BX_PCI_SUPPORT */
diff --git a/tools/ioemu/iodev/pci2isa.h b/tools/ioemu/iodev/pci2isa.h
new file mode 100644
index 0000000000..1517052d92
--- /dev/null
+++ b/tools/ioemu/iodev/pci2isa.h
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci2isa.h,v 1.4 2002/11/09 20:51:40 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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_pci2isa_c : public bx_devmodel_c {
+
+public:
+ bx_pci2isa_c(void);
+ ~bx_pci2isa_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+
+private:
+
+ struct {
+ Bit8u pci_conf[256];
+ Bit8u elcr1;
+ Bit8u elcr2;
+ } 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);
+ static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+ static void pci_write_handler(void *this_ptr, Bit8u 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);
+ Bit32u pci_read(Bit8u address, unsigned io_len);
+ void pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+ };
diff --git a/tools/ioemu/iodev/pciusb.cc b/tools/ioemu/iodev/pciusb.cc
new file mode 100644
index 0000000000..e2d4248369
--- /dev/null
+++ b/tools/ioemu/iodev/pciusb.cc
@@ -0,0 +1,668 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pciusb.cc,v 1.3 2003/02/06 19:09:24 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+//
+// Experimental PCI USB adapter
+// Benjamin D Lunt (fys@cybertrails.com) coded most of this usb emulation.
+// I hope to add to this code to make it more functionable.
+//
+
+// 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"
+#if BX_PCI_SUPPORT && BX_PCI_USB_SUPPORT
+
+#define LOG_THIS theUSBDevice->
+
+bx_pciusb_c* theUSBDevice = NULL;
+
+ int
+libpciusb_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theUSBDevice = new bx_pciusb_c ();
+ bx_devices.pluginPciUSBAdapter = theUSBDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUSBDevice, BX_PLUGIN_PCIUSB);
+ return 0; // Success
+}
+
+ void
+libpciusb_LTX_plugin_fini(void)
+{
+}
+
+
+bx_pciusb_c::bx_pciusb_c(void)
+{
+ put("USB");
+ settype(PCIUSBLOG);
+}
+
+bx_pciusb_c::~bx_pciusb_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_pciusb_c::init(void)
+{
+ // called once when bochs initializes
+
+ if (!bx_options.usb[0].Oenabled->get()) return;
+
+ Bit16u base_ioaddr = bx_options.usb[0].Oioaddr->get();
+ Bit8u irq = bx_options.usb[0].Oirq->get();
+
+ DEV_register_irq(irq, "USB Hub #1");
+ BX_USB_THIS hub[0].irq = irq;
+
+ // Call our timer routine every 1mS (1,000uS)
+ // Continuous and active
+ BX_USB_THIS hub[0].timer_index =
+ bx_pc_system.register_timer(this, usb_timer_handler, 1000, 1,1, "usb.timer");
+
+ for (unsigned addr=base_ioaddr; addr<(unsigned)(base_ioaddr+0x14); addr++) {
+ BX_DEBUG(("register read/write: 0x%04x", addr));
+ DEV_register_ioread_handler(this, read_handler, addr, "USB Hub #1", 7);
+ DEV_register_iowrite_handler(this, write_handler, addr, "USB Hub #1", 7);
+ }
+ BX_USB_THIS hub[0].base_ioaddr = base_ioaddr;
+
+ DEV_register_pci_handlers(this,
+ pci_read_handler,
+ pci_write_handler,
+ BX_PCI_DEVICE(1,2),
+ "Experimental PCI USB");
+
+ for (unsigned i=0; i<256; i++) {
+ BX_USB_THIS hub[0].pci_conf[i] = 0x0;
+ }
+
+ BX_INFO(("usb1 at 0x%04x-0x%04x irq %d", base_ioaddr, base_ioaddr+0x13, irq));
+}
+
+ void
+bx_pciusb_c::reset(unsigned type)
+{
+ unsigned i;
+
+ static const struct reset_vals_t {
+ unsigned addr;
+ unsigned char val;
+ } reset_vals[] = {
+ { 0x00, 0x86 }, { 0x01, 0x80 }, // 0x8086 = vendor
+ { 0x02, 0x20 }, { 0x03, 0x70 }, // 0x7020 = device
+ { 0x04, 0x05 }, { 0x05, 0x00 }, // command_io
+ { 0x06, 0x80 }, { 0x07, 0x02 }, // status
+ { 0x08, 0x01 }, // revision number
+ { 0x09, 0x00 }, // interface
+ { 0x0a, 0x03 }, // class_sub USB Host Controller
+ { 0x0b, 0x0c }, // class_base Serial Bus Controller
+ { 0x0D, 0x20 }, // bus latency
+ { 0x0e, 0x00 }, // header_type_generic
+ // address space 0x20 - 0x23
+ { 0x20, ((bx_options.usb[0].Oioaddr->get() & 0xE0) | 0x01) },
+ { 0x21, (bx_options.usb[0].Oioaddr->get() >> 8) },
+ { 0x22, 0x00 }, { 0x23, 0x00 },
+ { 0x3c, bx_options.usb[0].Oirq->get() }, // IRQ
+ { 0x3d, 0x04 }, // INT
+ { 0x6a, 0x01 }, // USB clock
+ { 0xc1, 0x20 } // PIRQ enable
+
+ };
+ for (i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
+ BX_USB_THIS hub[0].pci_conf[reset_vals[i].addr] = reset_vals[i].val;
+ }
+
+ // reset locals
+ BX_USB_THIS global_reset = 0;
+
+ // Put the USB registers into their RESET state
+ for (i=0; i<BX_USB_CONFDEV; i++) {
+ BX_USB_THIS hub[i].usb_command.max_packet_size = 0;
+ BX_USB_THIS hub[i].usb_command.configured = 0;
+ BX_USB_THIS hub[i].usb_command.debug = 0;
+ BX_USB_THIS hub[i].usb_command.resume = 0;
+ BX_USB_THIS hub[i].usb_command.suspend = 1;
+ BX_USB_THIS hub[i].usb_command.host_reset = 0;
+ BX_USB_THIS hub[i].usb_command.reset = 0;
+ BX_USB_THIS hub[i].usb_command.schedule = 0;
+ BX_USB_THIS hub[i].usb_status.error_interrupt = 0;
+ BX_USB_THIS hub[i].usb_status.host_error = 0;
+ BX_USB_THIS hub[i].usb_status.host_halted = 0;
+ BX_USB_THIS hub[i].usb_status.interrupt = 0;
+ BX_USB_THIS hub[i].usb_status.pci_error = 0;
+ BX_USB_THIS hub[i].usb_status.resume = 0;
+ BX_USB_THIS hub[i].usb_enable.short_packet = 0;
+ BX_USB_THIS hub[i].usb_enable.on_complete = 0;
+ BX_USB_THIS hub[i].usb_enable.resume = 0;
+ BX_USB_THIS hub[i].usb_enable.timeout_crc = 0;
+ BX_USB_THIS hub[i].usb_frame_num.frame_num = 0x0000;
+ BX_USB_THIS hub[i].usb_frame_base.frame_base = 0x00000000;
+ BX_USB_THIS hub[i].usb_sof.sof_timing = 0x40;
+ for (unsigned j=0; j<USB_NUM_PORTS; j++) {
+ BX_USB_THIS hub[i].usb_port[j].connect_changed = 0;
+ BX_USB_THIS hub[i].usb_port[j].line_dminus = 0;
+ BX_USB_THIS hub[i].usb_port[j].line_dplus = 0;
+ BX_USB_THIS hub[i].usb_port[j].low_speed = 0;
+ BX_USB_THIS hub[i].usb_port[j].reset = 0;
+ BX_USB_THIS hub[i].usb_port[j].resume = 0;
+ BX_USB_THIS hub[i].usb_port[j].suspend = 0;
+ BX_USB_THIS hub[i].usb_port[j].enabled = 0;
+ BX_USB_THIS hub[i].usb_port[j].able_changed = 0;
+ BX_USB_THIS hub[i].usb_port[j].status = 0;
+ }
+ }
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pciusb_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+ bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_pciusb_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+ Bit32u val = 0x0;
+ Bit8u offset,port;
+
+ BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
+
+ offset = address - BX_USB_THIS hub[0].base_ioaddr;
+
+ switch (offset) {
+ case 0x0C: // Start of Frame Modify
+ case 0x11: // port0 (high byte read)
+ case 0x13: // port1 (high byte read)
+ if (io_len != 1)
+ BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ case 0x10: // port0
+ case 0x12: // port1
+ if ((io_len < 1) || (io_len > 2))
+ BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ case 0x00: // command register (16-bit)
+ case 0x02: // status register (16-bit)
+ case 0x04: // interrupt enable register (1-bit)
+ case 0x06: // frame number register (16-bit)
+ if (io_len != 2)
+ BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ case 0x08: // frame base register (32-bit)
+ if (io_len != 4)
+ BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ }
+
+ switch (offset) {
+ case 0x00: // command register (16-bit)
+ val = BX_USB_THIS hub[0].usb_command.max_packet_size << 7
+ | BX_USB_THIS hub[0].usb_command.configured << 6
+ | BX_USB_THIS hub[0].usb_command.debug << 5
+ | BX_USB_THIS hub[0].usb_command.resume << 4
+ | BX_USB_THIS hub[0].usb_command.suspend << 3
+ | BX_USB_THIS hub[0].usb_command.reset << 2
+ | BX_USB_THIS hub[0].usb_command.host_reset << 1
+ | BX_USB_THIS hub[0].usb_command.schedule;
+ break;
+
+ case 0x02: // status register (16-bit)
+ val = BX_USB_THIS hub[0].usb_status.host_halted << 5
+ | BX_USB_THIS hub[0].usb_status.host_error << 4
+ | BX_USB_THIS hub[0].usb_status.pci_error << 3
+ | BX_USB_THIS hub[0].usb_status.resume << 2
+ | BX_USB_THIS hub[0].usb_status.error_interrupt << 1
+ | BX_USB_THIS hub[0].usb_status.interrupt;
+ break;
+
+ case 0x04: // interrupt enable register (16-bit)
+ val = BX_USB_THIS hub[0].usb_enable.short_packet << 3
+ | BX_USB_THIS hub[0].usb_enable.on_complete << 2
+ | BX_USB_THIS hub[0].usb_enable.resume << 1
+ | BX_USB_THIS hub[0].usb_enable.timeout_crc;
+ break;
+
+ case 0x06: // frame number register (16-bit)
+ val = BX_USB_THIS hub[0].usb_frame_num.frame_num;
+ break;
+
+ case 0x08: // frame base register (32-bit)
+ val = BX_USB_THIS hub[0].usb_frame_base.frame_base;
+ break;
+
+ case 0x0C: // start of Frame Modify register (8-bit)
+ val = BX_USB_THIS hub[0].usb_sof.sof_timing;
+ break;
+
+ case 0x10: // port0
+ case 0x12: // port1
+ port = (offset & 0x0F) >> 1;
+ if (port < USB_NUM_PORTS) {
+ val = BX_USB_THIS hub[0].usb_port[port].suspend << 12
+ | BX_USB_THIS hub[0].usb_port[port].reset << 9
+ | BX_USB_THIS hub[0].usb_port[port].low_speed << 8
+ | 1 << 7
+ | BX_USB_THIS hub[0].usb_port[port].resume << 6
+ | BX_USB_THIS hub[0].usb_port[port].line_dplus << 5
+ | BX_USB_THIS hub[0].usb_port[port].line_dminus << 4
+ | BX_USB_THIS hub[0].usb_port[port].able_changed << 3
+ | BX_USB_THIS hub[0].usb_port[port].enabled << 2
+ | BX_USB_THIS hub[0].usb_port[port].connect_changed << 1
+ | BX_USB_THIS hub[0].usb_port[port].status;
+ break;
+ } // else fall through to default
+
+ default:
+ val = 0; // keep compiler happy
+ BX_PANIC(("unsupported io read from address=0x%04x!", (unsigned) address));
+ break;
+ }
+
+ BX_DEBUG(("val = 0x%08x", (Bit32u) val));
+
+ return(val);
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pciusb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+ bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_pciusb_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+ Bit8u offset,port;
+
+ BX_DEBUG(("register write to address 0x%04x - ", (unsigned) address));
+
+ offset = address - BX_USB_THIS hub[0].base_ioaddr;
+
+ switch (offset) {
+ case 0x0C: // Start of Frame Modify
+ if (io_len != 1)
+ BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ case 0x00: // command register (16-bit)
+ case 0x02: // status register (16-bit)
+ case 0x04: // interrupt enable register (1-bit)
+ case 0x06: // frame number register (16-bit)
+ case 0x10: // port0
+ case 0x12: // port1
+ if (io_len != 2)
+ BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ case 0x08: // frame base register (32-bit)
+ if (io_len != 4)
+ BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+ break;
+ }
+
+ switch (offset) {
+ case 0x00: // command register (16-bit) (R/W)
+ if (value & 0xFF00)
+ BX_ERROR(("write to command register with bits 15:8 not zero: 0x%04x", value));
+
+ BX_USB_THIS hub[0].usb_command.max_packet_size = (value & 0x80) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.configured = (value & 0x40) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.debug = (value & 0x20) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.resume = (value & 0x10) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.suspend = (value & 0x08) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.reset = (value & 0x04) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.host_reset = (value & 0x02) ? 1: 0;
+ BX_USB_THIS hub[0].usb_command.schedule = (value & 0x01) ? 1: 0;
+
+ // If software set the reset bit, we need to set reset bit of each port for 10ms.
+ if (BX_USB_THIS hub[0].usb_command.reset)
+ BX_USB_THIS global_reset = 10;
+
+ // If host_reset then reset all registers, etc.
+ if (BX_USB_THIS hub[0].usb_command.host_reset)
+ BX_USB_THIS reset(0);
+
+ // If Run/Stop, identify in log and ignore
+ if (BX_USB_THIS hub[0].usb_command.schedule)
+ BX_INFO(("Software set Schedule bit in Command register"));
+
+ // If Debug mode set, panic. Not implemented
+ if (BX_USB_THIS hub[0].usb_command.debug)
+ BX_PANIC(("Software set DEBUG bit in Command register. Not implemented"));
+
+ break;
+
+ case 0x02: // status register (16-bit) (R/WC)
+ if (value & 0xFFC0)
+ BX_ERROR(("write to status register with bits 15:6 not zero: 0x%04x", value));
+
+ BX_USB_THIS hub[0].usb_status.host_halted = (value & 0x20) ? 0: BX_USB_THIS hub[0].usb_status.host_halted;
+ BX_USB_THIS hub[0].usb_status.host_error = (value & 0x10) ? 0: BX_USB_THIS hub[0].usb_status.host_error;
+ BX_USB_THIS hub[0].usb_status.pci_error = (value & 0x08) ? 0: BX_USB_THIS hub[0].usb_status.pci_error;
+ BX_USB_THIS hub[0].usb_status.resume = (value & 0x04) ? 0: BX_USB_THIS hub[0].usb_status.resume;
+ BX_USB_THIS hub[0].usb_status.error_interrupt = (value & 0x02) ? 0: BX_USB_THIS hub[0].usb_status.error_interrupt;
+ BX_USB_THIS hub[0].usb_status.interrupt = (value & 0x01) ? 0: BX_USB_THIS hub[0].usb_status.interrupt;
+ break;
+
+ case 0x04: // interrupt enable register (16-bit)
+ if (value & 0xFFF0)
+ BX_ERROR(("write to interrupt enable register with bits 15:4 not zero: 0x%04x", value));
+
+ BX_USB_THIS hub[0].usb_enable.short_packet = (value & 0x08) ? 1: 0;
+ BX_USB_THIS hub[0].usb_enable.on_complete = (value & 0x04) ? 1: 0;
+ BX_USB_THIS hub[0].usb_enable.resume = (value & 0x02) ? 1: 0;
+ BX_USB_THIS hub[0].usb_enable.timeout_crc = (value & 0x01) ? 1: 0;
+
+ // For now, we will just ignore these being set since we never raise the IRQ
+
+ break;
+
+ case 0x06: // frame number register (16-bit)
+ if (value & 0xF800)
+ BX_ERROR(("write to frame number register with bits 15:11 not zero: 0x%04x", value));
+
+ if (BX_USB_THIS hub[0].usb_status.host_halted)
+ BX_USB_THIS hub[0].usb_frame_num.frame_num = value;
+ else
+ // ignored by the hardward, but lets report it anyway
+ BX_ERROR(("write to frame number register with STATUS.HALTED == 0"));
+
+ break;
+
+ case 0x08: // frame base register (32-bit)
+ if (value & 0xFFF)
+ BX_PANIC(("write to frame base register with bits 11:0 not zero: 0x%08x", value));
+
+ BX_USB_THIS hub[0].usb_frame_base.frame_base = value;
+ break;
+
+ case 0x0C: // start of Frame Modify register (8-bit)
+ if (value & 0x80)
+ BX_ERROR(("write to SOF Modify register with bit 7 not zero: 0x%04x", value));
+
+ BX_USB_THIS hub[0].usb_sof.sof_timing = value;
+ break;
+
+ case 0x10: // port0
+ case 0x12: // port1
+ port = (offset & 0x0F) >> 1;
+ if (port < USB_NUM_PORTS) {
+ if (value & ((1<<5) | (1<<4) | (1<<0)))
+ BX_PANIC(("write to one or more read-only bits in port%d register: 0x%04x", port, value));
+ if (!(value & (1<<7)))
+ BX_ERROR(("write to port%d register bit 7 = 0", port));
+ if (value & (1<<8))
+ BX_INFO(("write to bit 8 in port%d register ignored", port));
+ if (value & (1<<2))
+ BX_INFO(("port%d enabled ignored. Not implemented", port));
+ if ((value & (1<<12)) && BX_USB_THIS hub[0].usb_command.suspend)
+ BX_ERROR(("write to port%d register bit 12 when in Global-Suspend", port));
+
+ BX_USB_THIS hub[0].usb_port[port].suspend = (value & (1<<12)) ? 1 : 0;
+ BX_USB_THIS hub[0].usb_port[port].reset = (value & (1<<9)) ? 1 : 0;
+ BX_USB_THIS hub[0].usb_port[port].resume = (value & (1<<6)) ? 1 : 0;
+ BX_USB_THIS hub[0].usb_port[port].able_changed = (value & (1<<3)) ? 0 : BX_USB_THIS hub[0].usb_port[0].able_changed;
+ BX_USB_THIS hub[0].usb_port[port].enabled = (value & (1<<2)) ? 1 : 0;
+ BX_USB_THIS hub[0].usb_port[port].connect_changed = (value & (1<<1)) ? 0 : BX_USB_THIS hub[0].usb_port[0].connect_changed;
+ break;
+ }
+ // else fall through to default
+
+ default:
+ BX_PANIC(("unsupported io write to address=0x%04x!", (unsigned) address));
+ break;
+ }
+}
+
+void bx_pciusb_c::usb_timer_handler(void *this_ptr)
+{
+ bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+ class_ptr->usb_timer();
+}
+
+// Called once every 1ms
+void bx_pciusb_c::usb_timer(void)
+{
+ int i;
+
+ // The Frame Number Register is incremented every 1ms ?????????
+ // Needs more work and investigation on this.
+ BX_USB_THIS hub[0].usb_frame_num.frame_num++;
+ BX_USB_THIS hub[0].usb_frame_num.frame_num &= (1024-1);
+
+ // If the "global reset" bit was set by software, we need
+ // to set the reset bit in each "active" port for 10ms
+ if (BX_USB_THIS global_reset) {
+ for (i=0; i<USB_NUM_PORTS; i++) {
+ BX_USB_THIS hub[0].usb_port[i].able_changed = 0;
+ BX_USB_THIS hub[0].usb_port[i].connect_changed = 0;
+ BX_USB_THIS hub[0].usb_port[i].enabled = 0;
+ BX_USB_THIS hub[0].usb_port[i].line_dminus = 0;
+ BX_USB_THIS hub[0].usb_port[i].line_dplus = 0;
+ BX_USB_THIS hub[0].usb_port[i].low_speed = 0;
+ BX_USB_THIS hub[0].usb_port[i].reset = 1;
+ BX_USB_THIS hub[0].usb_port[i].resume = 0;
+ BX_USB_THIS hub[0].usb_port[i].status = 0;
+ BX_USB_THIS hub[0].usb_port[i].suspend = 0;
+ }
+ BX_USB_THIS global_reset--;
+ } else {
+ for (i=0; i<USB_NUM_PORTS; i++)
+ BX_USB_THIS hub[0].usb_port[i].reset = 0;
+ }
+
+ // If command.schedule = 0, then we need to set Status.Halted
+ if (!BX_USB_THIS hub[0].usb_command.schedule)
+ BX_USB_THIS hub[0].usb_status.host_halted = 1;
+
+
+ // TODO:
+ // If ins Global_Suspend mode and any of usb_port[i] bits 6,3, or 1 are set,
+ // we need to issue a Global_Resume (set the global resume bit).
+ // However, since we don't do anything, let's not.
+
+}
+
+ // static pci configuration space read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pciusb_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+ bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+ return class_ptr->pci_read(address, io_len);
+}
+
+
+ Bit32u
+bx_pciusb_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+
+ Bit32u value = 0;
+
+ if (io_len > 4 || io_len == 0) {
+ BX_ERROR(("Experimental USB PCI read register 0x%02x, len=%u !",
+ (unsigned) address, (unsigned) io_len));
+ return 0xffffffff;
+ }
+
+ const char* pszName = " ";
+ switch (address) {
+ case 0x00: if (io_len == 2) {
+ pszName = "(vendor id) ";
+ } else if (io_len == 4) {
+ pszName = "(vendor + device) ";
+ }
+ break;
+ case 0x04: if (io_len == 2) {
+ pszName = "(command) ";
+ } else if (io_len == 4) {
+ pszName = "(command+status) ";
+ }
+ break;
+ case 0x08: if (io_len == 1) {
+ pszName = "(revision id) ";
+ } else if (io_len == 4) {
+ pszName = "(rev.+class code) ";
+ }
+ break;
+ case 0x0c: pszName = "(cache line size) "; break;
+ case 0x20: pszName = "(base address) "; break;
+ case 0x28: pszName = "(cardbus cis) "; break;
+ case 0x2c: pszName = "(subsys. vendor+) "; break;
+ case 0x30: pszName = "(rom base) "; break;
+ case 0x3c: pszName = "(interrupt line+) "; break;
+ case 0x3d: pszName = "(interrupt pin) "; break;
+ }
+
+ // This odd code is to display only what bytes actually were read.
+ char szTmp[9];
+ char szTmp2[3];
+ szTmp[0] = '\0';
+ szTmp2[0] = '\0';
+ for (unsigned i=0; i<io_len; i++) {
+ value |= (BX_USB_THIS hub[0].pci_conf[address+i] << (i*8));
+ sprintf(szTmp2, "%02x", (BX_USB_THIS hub[0].pci_conf[address+i]));
+ strrev(szTmp2);
+ strcat(szTmp, szTmp2);
+ }
+ strrev(szTmp);
+ BX_DEBUG(("Experimental USB PCI read register 0x%02x %svalue 0x%s",
+ address, pszName, szTmp));
+ return value;
+}
+
+
+ // static pci configuration space write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pciusb_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+ bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+ class_ptr->pci_write(address, value, io_len);
+}
+
+ void
+bx_pciusb_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+
+ if (io_len > 4 || io_len == 0) {
+ BX_ERROR(("Experimental USB PCI write register 0x%02x, len=%u !",
+ (unsigned) address, (unsigned) io_len));
+ return;
+ }
+
+ // This odd code is to display only what bytes actually were written.
+ char szTmp[9];
+ char szTmp2[3];
+ szTmp[0] = '\0';
+ szTmp2[0] = '\0';
+ for (unsigned i=0; i<io_len; i++) {
+ const Bit8u value8 = (value >> (i*8)) & 0xFF;
+ switch (address+i) {
+ case 0x20: // Base address
+ BX_USB_THIS hub[0].pci_conf[address+i] = (value8 & 0xe0) | 0x01;
+ sprintf(szTmp2, "%02x", (value8 & 0xe0) | 0x01);
+ break;
+ case 0x10: // Reserved
+ case 0x11: //
+ case 0x12: //
+ case 0x13: //
+ case 0x14: //
+ case 0x15: //
+ case 0x16: //
+ case 0x17: //
+ case 0x18: //
+ case 0x19: //
+ case 0x1a: //
+ case 0x1b: //
+ case 0x1c: //
+ case 0x1d: //
+ case 0x1e: //
+ case 0x1f: //
+ case 0x22: // Always 0
+ case 0x23: //
+ case 0x24: // Reserved
+ case 0x25: //
+ case 0x26: //
+ case 0x27: //
+ case 0x30: // Oh, no, you're not writing to rom_base!
+ case 0x31: //
+ case 0x32: //
+ case 0x33: //
+ case 0x3d: //
+ case 0x05: // disallowing write to command hi-byte
+ case 0x06: // disallowing write to status lo-byte (is that expected?)
+ strcpy(szTmp2, "..");
+ break;
+ default:
+ BX_USB_THIS hub[0].pci_conf[address+i] = value8;
+ sprintf(szTmp2, "%02x", value8);
+ }
+ strrev(szTmp2);
+ strcat(szTmp, szTmp2);
+ }
+ strrev(szTmp);
+ BX_DEBUG(("Experimental USB PCI write register 0x%02x value 0x%s", address, szTmp));
+}
+
+#endif // BX_PCI_SUPPORT && BX_PCI_USB_SUPPORT
diff --git a/tools/ioemu/iodev/pciusb.h b/tools/ioemu/iodev/pciusb.h
new file mode 100644
index 0000000000..be2532c86f
--- /dev/null
+++ b/tools/ioemu/iodev/pciusb.h
@@ -0,0 +1,195 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pciusb.h,v 1.1 2003/01/28 16:58:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// Benjamin D Lunt (fys@cybertrails.com) coded most of this usb emulation.
+// I hope to add to this code to make it more functionable.
+//
+
+#if BX_USE_PCIUSB_SMF
+# define BX_USB_THIS theUSBDevice->
+#else
+# define BX_USB_THIS this->
+#endif
+
+#define BX_USB_MAXDEV 1
+#define BX_USB_CONFDEV 1 /* only 1 USB hub currently */
+
+#define USB_NUM_PORTS 2 /* UHCI supports 2 ports per root hub */
+
+typedef struct {
+
+ Bit16u base_ioaddr;
+ Bit8u irq;
+ int timer_index;
+
+ // Registers
+ // Base + 0x00 Command register
+ // Base + 0x02 Status register
+ // Base + 0x04 Interrupt Enable register
+ // Base + 0x06 Frame Number register
+ // Base + 0x08 Frame Base Register (32-bit)
+ // Base + 0x0C Start of Frame Modify register
+ // Base + 0x0D
+ // Base + 0x0E
+ // Base + 0x0F
+ // Base + 0x10 Eight(?) 16-bit ports (one for each port on hub)
+
+ // Bit reps of registers above
+ // Command Register
+ // Bits 15-8 are reserved
+ // Bit 7 = Maximum packet size
+ // Bit 6 = Host Controller has been configured (set by software)
+ // Bit 5 = software debug mode
+ // Bit 4 = force global resume
+ // Bit 3 = enter global suspend mode
+ // Bit 2 = global reset
+ // Bit 1 = host controller reset
+ // Bit 0 = run/stop schedule
+ struct {
+ bx_bool max_packet_size; //(bit 7) 0 = 32 bytes, 1 = 64 bytes
+ bx_bool configured; //(bit 6)
+ bx_bool debug; //(bit 5)
+ bx_bool resume; //(bit 4)
+ bx_bool suspend; //(bit 3)
+ bx_bool reset; //(bit 2)
+ bx_bool host_reset; //(bit 1)
+ bx_bool schedule; //(bit 0) 0 = Stop, 1 = Run
+ } usb_command;
+
+ // Status Register
+ // Bits 15-6 are reserved
+ // Bit 5 = Host controller halted
+ // Bit 4 = Host controller process error
+ // Bit 3 = PCI Bus error
+ // Bit 2 = resume received
+ // Bit 1 = USB error interrupt
+ // Bit 0 = USB interrupt
+ struct {
+ bx_bool host_halted; //(bit 5)
+ bx_bool host_error; //(bit 4)
+ bx_bool pci_error; //(bit 3)
+ bx_bool resume; //(bit 2)
+ bx_bool error_interrupt; //(bit 1)
+ bx_bool interrupt; //(bit 0)
+ } usb_status;
+
+ // Interrupt Enable Register
+ // Bits 15-4 are reserved
+ // Bit 3 = enable short packet interrupts
+ // Bit 2 = enable interrupt On Complete
+ // Bit 1 = enable resume
+ // Bit 0 = enable timeout/crc
+ struct {
+ bx_bool short_packet; //(bit 3)
+ bx_bool on_complete; //(bit 2)
+ bx_bool resume; //(bit 1)
+ bx_bool timeout_crc; //(bit 0)
+ } usb_enable;
+
+ // Frame Number Register
+ // Bits 15-11 are reserved
+ // Bits 10-0 Frame List Current Index/Frame Number
+ struct {
+ Bit16u frame_num;
+ } usb_frame_num;
+
+ // Frame List Base Address Register
+ // Bits 31-12 Base
+ // Bits 11-0 *must* be zeros when written to
+ struct {
+ Bit32u frame_base;
+ } usb_frame_base;
+
+ // Start of Frame Modify Register
+ // Bit 7 reserved
+ // Bits 6-0 SOF timing value (default 64)
+ // SOF cycle time equals 11936+timing value
+ struct {
+ Bit8u sof_timing;
+ } usb_sof;
+
+ // Port Register (0-1)
+ // Bits 15-13 are reserved
+ // Bit 12 suspend port
+ // Bit 11-10 are reserved
+ // Bit 9 port in reset state
+ // Bit 8 low-speed device is attached (read-only)
+ // Bit 7 reserved
+ // Bit 6 resume detected (read-only)
+ // Bit 5 line-status D+ (read-only)
+ // Bit 4 line-status D- (read-only)
+ // Bit 3 port enabled/disable status has changed
+ // (write 1 to this bit to clear it)
+ // Bit 2 port is enabled
+ // Bit 1 connect status has changed
+ // (write 1 to this bit to clear it)
+ // Bit 0 current connect status (read-only)
+ // Can only write in WORD sizes (Read in byte sizes???)
+ struct {
+ bx_bool suspend;
+ bx_bool reset;
+ bx_bool low_speed;
+ bx_bool resume;
+ bx_bool line_dplus;
+ bx_bool line_dminus;
+ bx_bool able_changed;
+ bx_bool enabled;
+ bx_bool connect_changed;
+ bx_bool status;
+ } usb_port[USB_NUM_PORTS];
+
+ Bit8u pci_conf[256];
+
+} bx_usb_t;
+
+
+class bx_pciusb_c : public bx_devmodel_c
+{
+public:
+ bx_pciusb_c(void);
+ ~bx_pciusb_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+
+private:
+
+ bx_usb_t hub[BX_USB_MAXDEV];
+ Bit8u global_reset;
+
+ static void usb_timer_handler(void *);
+ void usb_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);
+ static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+ static void pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PCIUSB_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+ Bit32u pci_read(Bit8u address, unsigned io_len);
+ void pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+};
diff --git a/tools/ioemu/iodev/pcivga.cc b/tools/ioemu/iodev/pcivga.cc
new file mode 100644
index 0000000000..4d999be74d
--- /dev/null
+++ b/tools/ioemu/iodev/pcivga.cc
@@ -0,0 +1,248 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pcivga.cc,v 1.2 2003/01/23 19:31:28 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "bochs.h"
+#if BX_PCI_SUPPORT && BX_PCI_VGA_SUPPORT
+
+#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_devices.pluginPciVgaAdapter = thePciVgaAdapter;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciVgaAdapter, BX_PLUGIN_PCIVGA);
+ return 0; // Success
+}
+
+ void
+libpcivga_LTX_plugin_fini(void)
+{
+}
+
+
+bx_pcivga_c::bx_pcivga_c(void)
+{
+ put("PCIVGA");
+ settype(PCIVGALOG);
+}
+
+bx_pcivga_c::~bx_pcivga_c(void)
+{
+ // nothing for now
+ BX_DEBUG(("Exit."));
+}
+
+
+ void
+bx_pcivga_c::init(void)
+{
+ // called once when bochs initializes
+
+ DEV_register_pci_handlers(this,
+ pci_read_handler,
+ pci_write_handler,
+ BX_PCI_DEVICE(2,0),
+ "Experimental PCI VGA");
+
+ for (unsigned 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 (unsigned i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
+ BX_PCIVGA_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
+ }
+}
+
+ void
+bx_pcivga_c::reset(unsigned type)
+{
+ static const struct reset_vals_t {
+ unsigned addr;
+ unsigned char val;
+ } reset_vals[] = {
+ { 0x04, 0x01 }, { 0x05, 0x00 }, // command_io
+ { 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;
+ }
+}
+
+
+ // static pci configuration space read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_pcivga_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCIVGA_SMF
+ bx_pcivga_c *class_ptr = (bx_pcivga_c *) this_ptr;
+
+ return class_ptr->pci_read(address, io_len);
+}
+
+
+ Bit32u
+bx_pcivga_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIVGA_SMF
+
+ Bit32u value = 0;
+
+ if (io_len > 4 || io_len == 0) {
+ BX_DEBUG(("Experimental PCIVGA read register 0x%02x, len=%u !",
+ (unsigned) address, (unsigned) io_len));
+ return 0xffffffff;
+ }
+
+ const char* pszName = " ";
+ switch (address) {
+ case 0x00: if (io_len == 2) {
+ pszName = "(vendor id) ";
+ } else if (io_len == 4) {
+ pszName = "(vendor + device) ";
+ }
+ break;
+ case 0x04: if (io_len == 2) {
+ pszName = "(command) ";
+ } else if (io_len == 4) {
+ pszName = "(command+status) ";
+ }
+ break;
+ case 0x08: if (io_len == 1) {
+ pszName = "(revision id) ";
+ } else if (io_len == 4) {
+ pszName = "(rev.+class code) ";
+ }
+ break;
+ case 0x0c: pszName = "(cache line size) "; break;
+ case 0x28: pszName = "(cardbus cis) "; break;
+ case 0x2c: pszName = "(subsys. vendor+) "; break;
+ case 0x30: pszName = "(rom base) "; break;
+ case 0x3c: pszName = "(interrupt line+) "; break;
+ case 0x3d: pszName = "(interrupt pin) "; break;
+ }
+
+ // This odd code is to display only what bytes actually were read.
+ char szTmp[9];
+ char szTmp2[3];
+ szTmp[0] = '\0';
+ szTmp2[0] = '\0';
+ for (unsigned i=0; i<io_len; i++) {
+ value |= (BX_PCIVGA_THIS s.pci_conf[address+i] << (i*8));
+
+ sprintf(szTmp2, "%02x", (BX_PCIVGA_THIS s.pci_conf[address+i]));
+ strrev(szTmp2);
+ strcat(szTmp, szTmp2);
+ }
+ strrev(szTmp);
+ BX_DEBUG(("Experimental PCIVGA read register 0x%02x %svalue 0x%s",
+ address, pszName, szTmp));
+ return value;
+}
+
+
+ // static pci configuration space write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_pcivga_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIVGA_SMF
+ bx_pcivga_c *class_ptr = (bx_pcivga_c *) this_ptr;
+
+ class_ptr->pci_write(address, value, io_len);
+}
+
+ void
+bx_pcivga_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PCIVGA_SMF
+
+ if (io_len > 4 || io_len == 0) {
+ BX_DEBUG(("Experimental PCIVGA write register 0x%02x, len=%u !",
+ (unsigned) address, (unsigned) io_len));
+ return;
+ }
+
+ // This odd code is to display only what bytes actually were written.
+ char szTmp[9];
+ char szTmp2[3];
+ szTmp[0] = '\0';
+ szTmp2[0] = '\0';
+ for (unsigned i=0; i<io_len; i++) {
+ const Bit8u value8 = (value >> (i*8)) & 0xFF;
+ switch (address+i) {
+ case 0x30: // Oh, no, you're not writing to rom_base!
+ case 0x31: //
+ case 0x32: //
+ case 0x33: //
+ case 0x04: // disallowing write to command
+ case 0x06: // disallowing write to status lo-byte (is that expected?)
+ strcpy(szTmp2, "..");
+ break;
+ default:
+ BX_PCIVGA_THIS s.pci_conf[address+i] = value8;
+ sprintf(szTmp2, "%02x", value8);
+ }
+ strrev(szTmp2);
+ strcat(szTmp, szTmp2);
+ }
+ strrev(szTmp);
+ BX_DEBUG(("Experimental PCIVGA write register 0x%02x value 0x%s", address, szTmp));
+}
+
+#endif // BX_PCI_SUPPORT && BX_PCI_VGA_SUPPORT
diff --git a/tools/ioemu/iodev/pcivga.h b/tools/ioemu/iodev/pcivga.h
new file mode 100644
index 0000000000..15bd986a09
--- /dev/null
+++ b/tools/ioemu/iodev/pcivga.h
@@ -0,0 +1,48 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pcivga.h,v 1.3 2003/01/27 21:11:55 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#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_pcivga_c(void);
+ ~bx_pcivga_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+
+private:
+
+ struct {
+ Bit8u pci_conf[256];
+ } s;
+
+ static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+ static void pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PCIVGA_SMF
+ Bit32u pci_read(Bit8u address, unsigned io_len);
+ void pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+};
diff --git a/tools/ioemu/iodev/pic.cc b/tools/ioemu/iodev/pic.cc
new file mode 100644
index 0000000000..f4455508b6
--- /dev/null
+++ b/tools/ioemu/iodev/pic.cc
@@ -0,0 +1,887 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pic.cc,v 1.33 2003/08/05 09:19:36 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// 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"
+
+#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)
+{
+}
+
+
+bx_pic_c::bx_pic_c(void)
+{
+ put("PIC");
+ settype(PICLOG);
+}
+
+bx_pic_c::~bx_pic_c(void)
+{
+ // nothing for now
+}
+
+
+ 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 = 0; /* no meaning, buffered_mode=0 */
+ 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.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; /* no meaning, buffered_mode=0 */
+ 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;
+
+ for (unsigned i=0; i<8; i++) { /* all IRQ lines low */
+ BX_PIC_THIS s.master_pic.IRQ_line[i] = 0;
+ BX_PIC_THIS s.slave_pic.IRQ_line[i] = 0;
+ }
+}
+
+ void
+bx_pic_c::reset(unsigned type)
+{
+}
+
+ // 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);
+ break;
+ 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);
+ break;
+ }
+
+ 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;
+
+ 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;
+ break;
+ 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;
+ break;
+
+ 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.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;
+
+ 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;
+ break;
+ 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;
+ break;
+ 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;
+ break;
+ 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;
+ break;
+ } /* switch (address) */
+
+ return;
+}
+
+// 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())
+ bx_devices.ioapic->untrigger_irq (irq_no, -1);
+#endif
+
+ if ((irq_no <= 7) && (BX_PIC_THIS s.master_pic.IRQ_line[irq_no])) {
+ BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
+ BX_PIC_THIS s.master_pic.IRQ_line[irq_no] = 0;
+ BX_PIC_THIS s.master_pic.irr &= ~(1 << irq_no);
+ if ((BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr) == 0) {
+ BX_SET_INTR(0);
+ BX_PIC_THIS s.master_pic.INT = 0;
+ }
+ } else if ((irq_no > 7) && (irq_no <= 15) &&
+ (BX_PIC_THIS s.slave_pic.IRQ_line[irq_no-8])) {
+ BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
+ BX_PIC_THIS s.slave_pic.IRQ_line[irq_no - 8] = 0;
+ BX_PIC_THIS s.slave_pic.irr &= ~(1 << (irq_no - 8));
+ if ((BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr) == 0) {
+ BX_PIC_THIS s.slave_pic.INT = 0;
+ lower_irq(2);
+ }
+ }
+}
+
+ void
+bx_pic_c::raise_irq(unsigned irq_no)
+{
+#if BX_SUPPORT_APIC
+ // forward this function call to the ioapic too
+ bx_devices.ioapic->trigger_irq (irq_no, -1);
+#endif
+
+ if ((irq_no <= 7) && (!BX_PIC_THIS s.master_pic.IRQ_line[irq_no])) {
+ BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
+ BX_PIC_THIS s.master_pic.IRQ_line[irq_no] = 1;
+ BX_PIC_THIS s.master_pic.irr |= (1 << irq_no);
+ service_master_pic();
+ } else if ((irq_no > 7) && (irq_no <= 15) &&
+ (!BX_PIC_THIS s.slave_pic.IRQ_line[irq_no-8])) {
+ BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
+ BX_PIC_THIS s.slave_pic.IRQ_line[irq_no - 8] = 1;
+ BX_PIC_THIS s.slave_pic.irr |= (1 << (irq_no - 8));
+ service_slave_pic();
+ }
+}
+
+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_SET_INTR(1);
+ BX_PIC_THIS s.master_pic.irq = irq;
+ 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;
+ 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_line[2] = 0;
+ irq = BX_PIC_THIS s.slave_pic.irq;
+ vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+ 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);
+}
+
+ Bit8u
+bx_pic_c::irq_to_vec(Bit8u irq)
+{
+ Bit8u vector = 0;
+
+ if (irq >= 8 && irq <= 15)
+ vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+ else if (irq != 2 && irq <= 7)
+ vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
+ else
+ BX_ERROR(("invalid irq!\n"));
+
+ return vector;
+}
+
+ void
+bx_pic_c::show_pic_state(void)
+{
+#if defined(BX_DEBUGGER) && (BX_DEBUGGER == 1)
+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
+}
diff --git a/tools/ioemu/iodev/pic.h b/tools/ioemu/iodev/pic.h
new file mode 100644
index 0000000000..378809d67d
--- /dev/null
+++ b/tools/ioemu/iodev/pic.h
@@ -0,0 +1,97 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pic.h,v 1.11 2003/08/04 16:03:09 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#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 */
+ bx_bool IRQ_line[8]; /* IRQ pins of PIC */
+ struct {
+ bx_bool in_init;
+ bx_bool requires_4;
+ int 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. */
+ } bx_pic_t;
+
+
+class bx_pic_c : public bx_pic_stub_c {
+public:
+ bx_pic_c(void);
+ ~bx_pic_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+ virtual void lower_irq(unsigned irq_no);
+ virtual void raise_irq(unsigned irq_no);
+ virtual Bit8u IAC(void);
+ virtual void show_pic_state(void);
+ Bit8u irq_to_vec(Bit8u);
+
+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);
+ };
diff --git a/tools/ioemu/iodev/pit.cc b/tools/ioemu/iodev/pit.cc
new file mode 100644
index 0000000000..cf4777a759
--- /dev/null
+++ b/tools/ioemu/iodev/pit.cc
@@ -0,0 +1,856 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit.cc,v 1.15 2003/07/31 12:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#include "bochs.h"
+
+#if (BX_USE_NEW_PIT==0)
+
+#define LOG_THIS bx_pit.
+
+
+// NOTES ON THE 8253/8254 PIT MODES
+
+// MODE 0: Interrupt on Terminal Count
+// ===================================
+// Writing new count action:
+// loaded upon next CLK pulse. counting doesn't start until GATE=1
+// GATE 0..1 transition:
+// ???
+// GATE 1..0 transition:
+// counter expiration action:
+// wraps to FFFF
+// * OUT rises until new count val or new control word for mode 0 written
+
+// MODE 1: Programmable Monoflop
+// =============================
+// Writing new count action:
+// not effective for current process
+// GATE 0..1 transition:
+// loads counter
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+// OUT rises until new count val or new control word for mode 0 written
+
+// MODE 2: Rate Generator
+// ======================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// loads initial count val and starts counting
+// counter expiration action:
+// reloads after count expires
+// NOTES:
+// * after control word & initial count val N loaded, PIT starts
+// counting upon next CLK pulse.
+// * when counter reaches 1, OUT drops to a low level, for one
+// CLK cycle. (short peak pulse generated)
+// * afterwards, the initial count val is automatically reloaded
+// and the PIT restarts the same counting operation again.
+// * distance of two OUT pulses is N CLK cycles long.
+// * GATE=1 enables, GATE=0 disables counter.
+// * if GATE drops to low level during counting operation and rises
+// to high level later, PIT loads initial count value at the
+// rise and starts counting.
+// * PIT starts counting after last data byte written if GATE=1
+// * if the output is low when the gate goes low, the output is
+// immediately set high.
+
+// MODE 3: Square Wave Generator
+// =============================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// reloads after count expires
+// NOTES:
+// * initially OUT at a high level
+// * drop of GATE to a low level while OUT low, raises OUT to a high level
+// * a rise from a low to a high level at GATE (trigger pulse),
+// loads the counter with the initial count value and starts
+// counting operation
+// * a new count value supplied during the course of an active
+// counting operation doesn't affect the current process.
+// At the end of the current half cycle, the PIT loads the new value
+// * if the GATE line goes low, count is temporarily halted until GATE
+// returns high
+// * if the OUT line is high when GATE goes low, OUT is forced low.
+// ??? different for odd/even counts
+
+// MODE 4: Software Triggered Pulse
+// ================================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+
+// MODE 5: Hardware Triggered Pulse
+// ================================
+// Writing new count action:
+// ???
+// GATE 0..1 transition:
+// ???
+// counter expiration action:
+// wraps to FFFF
+// NOTES:
+
+
+
+#define BX_PIT_LATCH_MODE_LSB 10
+#define BX_PIT_LATCH_MODE_MSB 11
+#define BX_PIT_LATCH_MODE_16BIT 12
+
+
+bx_pit_c bx_pit;
+#if BX_USE_PIT_SMF
+#define this (&bx_pit)
+#endif
+
+#ifdef OUT
+# undef OUT
+#endif
+
+
+bx_pit_c::bx_pit_c( void )
+{
+ put("PIT");
+ settype(PITLOG);
+ memset(&s, 0, sizeof(s));
+
+ /* 8254 PIT (Programmable Interval Timer) */
+
+ BX_PIT_THIS s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
+ BX_PIT_THIS s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
+}
+
+bx_pit_c::~bx_pit_c( void )
+{
+}
+
+
+ int
+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_PIT_THIS s.speaker_data_on = 0;
+ BX_PIT_THIS s.refresh_clock_div2 = 0;
+
+ BX_PIT_THIS s.timer[0].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[0].input_latch_value = 0;
+ BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].output_latch_value = 0;
+ BX_PIT_THIS s.timer[0].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].output_latch_full = 0;
+ BX_PIT_THIS s.timer[0].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[0].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[0].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[0].GATE = 1; /* GATE tied to + logic */
+ BX_PIT_THIS s.timer[0].OUT = 1;
+ BX_PIT_THIS s.timer[0].active = 0;
+
+ BX_PIT_THIS s.timer[1].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[1].input_latch_value = 0;
+ BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].output_latch_value = 0;
+ BX_PIT_THIS s.timer[1].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].output_latch_full = 0;
+ BX_PIT_THIS s.timer[1].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[1].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[1].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[1].GATE = 1; /* GATE tied to + logic */
+ BX_PIT_THIS s.timer[1].OUT = 1;
+ BX_PIT_THIS s.timer[1].active = 0;
+
+ BX_PIT_THIS s.timer[2].mode = 3; /* periodic rate generator */
+ BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[2].input_latch_value = 0;
+ BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].output_latch_value = 0;
+ BX_PIT_THIS s.timer[2].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].output_latch_full = 0;
+ BX_PIT_THIS s.timer[2].counter_max = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[2].counter = 0; /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+ BX_PIT_THIS s.timer[2].bcd_mode = 0; /* binary counting mode */
+ BX_PIT_THIS s.timer[2].GATE = 0; /* timer2 gate controlled by port 61h bit 0 */
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].active = 0;
+
+ return(1);
+}
+
+void bx_pit_c::reset(unsigned type) {
+}
+
+ // 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 int io_len )
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIT_SMF
+ if (bx_dbg.pit)
+ BX_INFO(("pit: io read from port %04x", (unsigned) address));
+
+ switch (address) {
+ case 0x40: /* timer 0 - system ticks */
+ return( read_counter(0) );
+ break;
+
+ case 0x42: /* timer 2 read */
+ return( read_counter(2) );
+ break;
+
+ case 0x61:
+ /* AT, port 61h */
+ BX_PIT_THIS s.refresh_clock_div2 = !BX_PIT_THIS s.refresh_clock_div2;
+ return( (BX_PIT_THIS s.timer[2].OUT<<5) |
+ (BX_PIT_THIS s.refresh_clock_div2<<4) |
+ (BX_PIT_THIS s.speaker_data_on<<1) |
+ (BX_PIT_THIS s.timer[2].GATE) );
+ break;
+
+ default:
+ BX_PANIC(("pit: unsupported io read from port %04x", address));
+ }
+ return(0); /* keep compiler happy */
+}
+
+
+ // 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 int io_len )
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIT_SMF
+ Bit8u command, mode, bcd_mode;
+ Bit8u value;
+
+ value = (Bit8u ) dvalue;
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: write to port %04x = %02x",
+ (unsigned) address, (unsigned) value));
+
+ switch (address) {
+ case 0x40: /* timer 0: write count register */
+ write_count_reg( value, 0 );
+ break;
+
+ case 0x41: /* timer 1: write count register */
+ write_count_reg( value, 1 );
+ break;
+
+ case 0x42: /* timer 2: write count register */
+ write_count_reg( value, 2 );
+ break;
+
+ case 0x43: /* timer 0-2 mode control */
+ /* |7 6 5 4|3 2 1|0|
+ * |-------|-----|-|
+ * |command|mode |bcd/binary|
+ */
+ command = value >> 4;
+ mode = (value >> 1) & 0x07;
+ bcd_mode = value & 0x01;
+#if 0
+BX_INFO(("timer 0-2 mode control: comm:%02x mode:%02x bcd_mode:%u",
+ (unsigned) command, (unsigned) mode, (unsigned) bcd_mode));
+#endif
+
+ if ( (mode > 5) || (command > 0x0e) )
+ BX_PANIC(("pit: outp(43h)=%02xh out of range", (unsigned) value));
+ if (bcd_mode)
+ BX_PANIC(("pit: outp(43h)=%02xh: bcd mode unhandled",
+ (unsigned) bcd_mode));
+
+ switch (command) {
+ case 0x0: /* timer 0: counter latch */
+ latch( 0 );
+ break;
+
+ case 0x1: /* timer 0: LSB mode */
+ case 0x2: /* timer 0: MSB mode */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+ (unsigned) command));
+ break;
+ case 0x3: /* timer 0: 16-bit mode */
+ BX_PIT_THIS s.timer[0].mode = mode;
+ BX_PIT_THIS s.timer[0].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[0].input_latch_value = 0;
+ BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[0].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm 3, mode %02x, bcd %02x unhandled",
+ (unsigned) mode, bcd_mode));
+ break;
+ case 0x4: /* timer 1: counter latch */
+ latch( 1 );
+ break;
+
+ case 0x5: /* timer 1: LSB mode */
+ case 0x6: /* timer 1: MSB mode */
+ BX_INFO(("pit: outp(43h): command %02xh unhandled (ignored)",
+ (unsigned) command));
+ break;
+ case 0x7: /* timer 1: 16-bit mode */
+ BX_PIT_THIS s.timer[1].mode = mode;
+ BX_PIT_THIS s.timer[1].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[1].input_latch_value = 0;
+ BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[1].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm 7, mode %02x, bcd %02x unhandled",
+ (unsigned) mode, bcd_mode));
+ break;
+ case 0x8: /* timer 2: counter latch */
+ latch( 2 );
+ break;
+
+ case 0x9: /* timer 2: LSB mode */
+ case 0xa: /* timer 2: MSB mode */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+ (unsigned) command));
+ break;
+ case 0xb: /* timer 2: 16-bit mode */
+ BX_PIT_THIS s.timer[2].mode = mode;
+ BX_PIT_THIS s.timer[2].latch_mode = BX_PIT_LATCH_MODE_16BIT;
+ BX_PIT_THIS s.timer[2].input_latch_value = 0;
+ BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+ BX_PIT_THIS s.timer[2].bcd_mode = bcd_mode;
+ if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+ BX_PANIC(("pit: outp(43h): comm Bh, mode %02x, bcd %02x unhandled",
+ (unsigned) mode, bcd_mode));
+ break;
+#if 0
+ case 0xd: /* general counter latch */
+ if (value & 0x08) /* select counter 2 */
+ latch( 2 );
+ if (value & 0x04) /* select counter 1 */
+ latch( 1 );
+ if (value & 0x02) /* select counter 0 */
+ latch( 0 );
+ break;
+
+ case 0xe: /* latch status of timers */
+ BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+ (unsigned) command);
+ break;
+#endif
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ BX_INFO(("pit: ignoring 8254 command %u", (unsigned) command));
+ break;
+
+ default: /* 0xc & 0xf */
+ BX_PANIC(("pit: outp(43h) command %1xh unhandled",
+ (unsigned) command));
+ break;
+ }
+ break;
+
+ case 0x61:
+ BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
+/*??? only on AT+ */
+ set_GATE(2, value & 0x01);
+#if BX_CPU_LEVEL < 2
+ /* ??? XT: */
+ bx_kbd_port61h_write(value);
+#endif
+ break;
+
+ default:
+ BX_PANIC(("pit: unsupported io write to port %04x = %02x",
+ (unsigned) address, (unsigned) value));
+ }
+}
+
+
+
+
+ void
+bx_pit_c::write_count_reg( Bit8u value, unsigned timerid )
+{
+ bx_bool xfer_complete;
+
+ switch ( BX_PIT_THIS s.timer[timerid].latch_mode ) {
+ case BX_PIT_LATCH_MODE_16BIT: /* write1=LSB, write2=MSB */
+ if (BX_PIT_THIS s.timer[timerid].input_latch_toggle==0) {
+ BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+ BX_PIT_THIS s.timer[timerid].input_latch_toggle = 1;
+ xfer_complete = 0;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
+ }
+ else {
+ BX_PIT_THIS s.timer[timerid].input_latch_value |= (value << 8);
+ BX_PIT_THIS s.timer[timerid].input_latch_toggle = 0;
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
+ }
+ break;
+
+ case BX_PIT_LATCH_MODE_MSB: /* write1=MSB, LSB=0 */
+ BX_PIT_THIS s.timer[timerid].input_latch_value = (value << 8);
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
+ break;
+
+ case BX_PIT_LATCH_MODE_LSB: /* write1=LSB, MSB=0 */
+ BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+ xfer_complete = 1;
+ if (bx_dbg.pit)
+ BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
+ break;
+
+ default:
+ BX_PANIC(("write_count_reg: latch_mode unknown"));
+ xfer_complete = 0;
+ }
+
+ if (xfer_complete) {
+ BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].input_latch_value;
+
+ // reprogramming counter clears latch
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+
+ // counter bounds
+ // mode minimum maximum
+ // 0 1 0
+ // 1 1 0
+ // 2 2 0
+ // 3 2 0
+ // 4 1 0
+ // 5 1 0
+ switch (BX_PIT_THIS s.timer[timerid].mode) {
+ case 0:
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ if (BX_PIT_THIS s.timer[timerid].GATE) {
+ BX_PIT_THIS s.timer[timerid].OUT = 0; // OUT pin starts low
+ start( timerid );
+ }
+ break;
+ case 1:
+ BX_PANIC(("pit:write_count_reg(%u): mode1 unsupported",
+ timerid));
+ break;
+ case 2:
+ if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+ BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
+ timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+ // software triggered
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
+ start( timerid );
+ }
+ break;
+ case 3:
+ if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+ BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
+ timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].counter_max & 0xfffe;
+ if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+ // software triggered
+ BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+ BX_PIT_THIS s.timer[timerid].active = 1;
+ BX_PIT_THIS s.timer[timerid].OUT = 1; // initially set high
+ start( timerid );
+ }
+ break;
+ case 4:
+ BX_PANIC(("pit:write_count_reg(%u): mode4 unsupported",
+ timerid));
+ break;
+ case 5:
+ BX_PANIC(("pit:write_count_reg(%u): mode5 unsupported",
+ timerid));
+ break;
+ }
+ }
+}
+
+
+ Bit8u
+bx_pit_c::read_counter( unsigned timerid )
+{
+ Bit16u counter_value;
+ Bit8u retval;
+
+ if (BX_PIT_THIS s.timer[timerid].output_latch_full) { /* latched read */
+ counter_value = BX_PIT_THIS s.timer[timerid].output_latch_value;
+ }
+ else { /* direct unlatched read */
+ counter_value = BX_PIT_THIS s.timer[timerid].counter;
+BX_INFO(("CV=%04x", (unsigned) BX_PIT_THIS s.timer[timerid].counter));
+ }
+
+ switch (BX_PIT_THIS s.timer[timerid].latch_mode) {
+ case BX_PIT_LATCH_MODE_LSB:
+ retval = (Bit8u ) counter_value;
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ case BX_PIT_LATCH_MODE_MSB:
+ retval = (Bit8u ) ( counter_value >> 8 );
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ case BX_PIT_LATCH_MODE_16BIT:
+ if (BX_PIT_THIS s.timer[timerid].output_latch_toggle==0) { /* LSB 1st */
+ retval = (Bit8u ) counter_value;
+ }
+ else { /* MSB 2nd */
+ retval = (Bit8u ) ( counter_value >> 8 );
+ }
+ BX_PIT_THIS s.timer[timerid].output_latch_toggle = !BX_PIT_THIS s.timer[timerid].output_latch_toggle;
+ if (BX_PIT_THIS s.timer[timerid].output_latch_toggle == 0)
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+ break;
+ default:
+ BX_PANIC(("pit: io read from port 40h: unknown latch mode"));
+ retval = 0; /* keep compiler happy */
+ }
+ return( retval );
+}
+
+
+ void
+bx_pit_c::latch( unsigned timerid )
+{
+ /* subsequent counter latch commands are ignored until value read out */
+ if (BX_PIT_THIS s.timer[timerid].output_latch_full) {
+ BX_INFO(("pit: pit(%u) latch: output latch full, ignoring",
+ timerid));
+ return;
+ }
+
+ BX_PIT_THIS s.timer[timerid].output_latch_value = BX_PIT_THIS s.timer[timerid].counter;
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: latch_value = %u", (unsigned) BX_PIT_THIS s.timer[timerid].output_latch_value));
+ BX_PIT_THIS s.timer[timerid].output_latch_toggle = 0;
+ BX_PIT_THIS s.timer[timerid].output_latch_full = 1;
+}
+
+ void
+bx_pit_c::set_GATE(unsigned pit_id, unsigned value)
+{
+ // GATE's for Timer 0 & Timer 1 are tied high.
+ if (pit_id != 2)
+ BX_PANIC(("pit:set_GATE: pit_id != 2"));
+
+ value = (value > 0);
+
+ /* if no transition of GATE input line, then nothing to do */
+ if (value == BX_PIT_THIS s.timer[2].GATE)
+ return;
+
+ if (value) { /* PIT2: GATE transition from 0 to 1 */
+ BX_PIT_THIS s.timer[2].GATE = 1;
+ switch ( BX_PIT_THIS s.timer[2].mode ) {
+ case 0:
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ if (BX_PIT_THIS s.timer[2].active) {
+ BX_PIT_THIS s.timer[2].OUT = 0;
+ }
+ start( 2 );
+ break;
+ case 2:
+ // begin counting, reload counter
+ BX_PIT_THIS s.timer[2].active = 1;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ start( 2 );
+ break;
+ case 3:
+ // begin counting, reload counter
+ BX_PIT_THIS s.timer[2].active = 1;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+ start( 2 );
+ break;
+ case 1:
+ case 4:
+ case 5:
+ default:
+ BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
+ (unsigned) BX_PIT_THIS s.timer[2].mode));
+ }
+ }
+ else { // PIT2: GATE transition from 1 to 0, deactivate
+ BX_PIT_THIS s.timer[2].GATE = 0;
+ switch ( BX_PIT_THIS s.timer[2].mode ) {
+ case 0:
+ break;
+ case 2:
+ // 1) stops count, 2) OUT goes immediately high
+ BX_PIT_THIS s.timer[2].active = 0;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ break;
+ case 3:
+ // 1) stops count, 2) OUT goes immediately high
+ BX_PIT_THIS s.timer[2].active = 0;
+ BX_PIT_THIS s.timer[2].OUT = 1;
+ break;
+ case 1:
+ case 4:
+ case 5:
+ default:
+ BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
+ (unsigned) BX_PIT_THIS s.timer[2].mode));
+ }
+ }
+}
+
+
+ void
+bx_pit_c::start(unsigned timerid)
+{
+ unsigned long period_hz;
+
+ if (BX_PIT_THIS s.timer[timerid].counter_max == 0x0000) {
+ period_hz = 1193182 / 65536;
+ }
+ else {
+ period_hz = 1193182 / BX_PIT_THIS s.timer[timerid].counter_max;
+ }
+ BX_INFO(("timer%u period set to %lu hz", timerid, period_hz));
+
+
+ switch (BX_PIT_THIS s.timer[timerid].mode) {
+ case 0: /* single timeout */
+ break;
+ case 1: /* retriggerable one-shot */
+ BX_PANIC(("start: mode %u unhandled",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ case 2: /* rate generator */
+ break;
+ case 3: /* square wave mode */
+ break;
+ case 4: /* software triggered strobe */
+ BX_PANIC(("start: mode %u unhandled",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ case 5: /* hardware retriggerable strobe */
+ BX_PANIC(("start: mode %u unhandled",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ break;
+ default:
+ BX_PANIC(("start: timer%u has bad mode",
+ (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+ }
+}
+
+
+
+
+ int
+bx_pit_c::SaveState( class state_file *fd )
+{
+ fd->write_check ("8254 start");
+ fd->write (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->write_check ("8254 end");
+ return(0);
+}
+
+
+ int
+bx_pit_c::LoadState( class state_file *fd )
+{
+ fd->read_check ("8254 start");
+ fd->read (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->read_check ("8254 end");
+ return(0);
+}
+
+
+#if 0
+ void
+bx_kbd_port61h_write(Bit8u value)
+{
+// PcError("KBD_PORT61H_WRITE(): not implemented yet");
+ UNUSED( value );
+}
+#endif
+
+
+ bx_bool
+bx_pit_c::periodic( Bit32u usec_delta )
+{
+ bx_bool prev_timer0_out;
+
+ prev_timer0_out = BX_PIT_THIS s.timer[0].OUT;
+
+ for (unsigned i = 0; i < 3; i++) {
+ // is timer enabled and active?
+ if ( BX_PIT_THIS s.timer[i].GATE && BX_PIT_THIS s.timer[i].active ) {
+ switch ( BX_PIT_THIS s.timer[i].mode ) {
+ case 0: // Mode 0: Single Timeout
+ // wraps after count expires
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // counter previously expired, wrap counter
+ BX_PIT_THIS s.timer[i].counter = 0xffff;
+ }
+ else if ( usec_delta >= BX_PIT_THIS s.timer[i].counter ) {
+ // counter expired
+ BX_PIT_THIS s.timer[i].counter = 0;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+ }
+ break;
+
+ case 1: // Mode 1: Retriggerable One-Shot
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+
+ case 2: // Mode 2: Rate Generator
+ // reloads after count expires
+ // OUT is low when counter=1, high otherwise
+ // min count=2, max count=0
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // max counter val, just wrap
+ BX_PIT_THIS s.timer[i].counter = 0xffff;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else if ( BX_PIT_THIS s.timer[i].counter == 1 ) {
+ // counter previously expired, reload
+ BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+ BX_PIT_THIS s.timer[i].OUT = 1;
+ }
+ else if ( (BX_PIT_THIS s.timer[i].counter == 2) ||
+ (usec_delta >= (Bit32u(BX_PIT_THIS s.timer[i].counter) - 1)) ) {
+ // in either case, counter will reach 1
+ BX_PIT_THIS s.timer[i].counter = 1;
+ BX_PIT_THIS s.timer[i].OUT = 0;
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+ }
+ break;
+
+ case 3: // Mode 3: Square Wave Mode
+ // reloads after count expires
+ // min count=2, max count=0
+ if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+ // max count, dec by 2
+ BX_PIT_THIS s.timer[i].counter = 0xfffe;
+ }
+ else if ( (BX_PIT_THIS s.timer[i].counter <= 2) ||
+ ( (usec_delta*2) >= BX_PIT_THIS s.timer[i].counter ) ) {
+ // counter expired, reload
+ BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+ BX_PIT_THIS s.timer[i].OUT = !BX_PIT_THIS s.timer[i].OUT;
+ //BX_INFO(("CV: reload t%u to %04x", (unsigned) i, (unsigned)
+ // BX_PIT_THIS s.timer[i].counter));
+ }
+ else {
+ // decrement counter by elapsed useconds
+ BX_PIT_THIS s.timer[i].counter -= (Bit16u ) ( 2*usec_delta );
+ //BX_INFO(("CV: dec count to %04x",
+ // (unsigned) BX_PIT_THIS s.timer[i].counter));
+ }
+ break;
+
+ case 4: // Mode 4: Software Triggered Strobe
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+
+ case 5: // Mode 5: Hardware Retriggerable Strobe
+ // wraps after count expires
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+ default:
+ BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+ i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+ break;
+ } // switch ( BX_PIT_THIS s.tim...
+ } // if ( BX_PIT_THIS s.timer[i]...
+ } // for (unsigned i...
+
+ // see if there's a rising edge on timer0's output to trigger an IRQ0.
+ if ( (prev_timer0_out==0) && (BX_PIT_THIS s.timer[0].OUT==1) )
+ return(1); // request IRQ 0
+ else
+ return(0);
+}
+
+#endif // #if (BX_USE_NEW_PIT==0)
diff --git a/tools/ioemu/iodev/pit.h b/tools/ioemu/iodev/pit.h
new file mode 100644
index 0000000000..49b663bf9d
--- /dev/null
+++ b/tools/ioemu/iodev/pit.h
@@ -0,0 +1,103 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit.h,v 1.10 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#ifndef _BX_PIT_H
+#define _BX_PIT_H
+
+#include "config.h"
+
+#if (BX_USE_NEW_PIT==0)
+
+#if BX_USE_PIT_SMF
+# define BX_PIT_SMF static
+# define BX_PIT_THIS bx_pit.
+#else
+# define BX_PIT_SMF
+# define BX_PIT_THIS this->
+#endif
+
+#ifdef OUT
+# undef OUT
+#endif
+
+
+typedef struct {
+ Bit8u mode;
+ Bit8u latch_mode;
+ Bit16u input_latch_value;
+ bx_bool input_latch_toggle;
+ Bit16u output_latch_value;
+ bx_bool output_latch_toggle;
+ bx_bool output_latch_full;
+ Bit16u counter_max;
+ Bit16u counter;
+ bx_bool bcd_mode;
+ bx_bool active;
+ bx_bool GATE; // GATE input pin
+ bx_bool OUT; // OUT output pin
+ } bx_pit_t;
+
+
+
+
+class bx_pit_c : public logfunctions {
+public:
+ bx_pit_c( void );
+ ~bx_pit_c( void );
+ BX_PIT_SMF int init(void);
+ BX_PIT_SMF void reset( unsigned type);
+ BX_PIT_SMF bx_bool periodic( Bit32u usec_delta );
+
+ BX_PIT_SMF int SaveState( class state_file *fd );
+ BX_PIT_SMF int LoadState( class state_file *fd );
+
+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 int len );
+ void write( Bit32u addr, Bit32u Value, unsigned int len );
+#endif
+
+ struct s_type {
+ bx_pit_t timer[3];
+ Bit8u speaker_data_on;
+ bx_bool refresh_clock_div2;
+ int timer_handle[3];
+ } s;
+
+ BX_PIT_SMF void write_count_reg( Bit8u value, unsigned timerid );
+ BX_PIT_SMF Bit8u read_counter( unsigned timerid );
+ BX_PIT_SMF void latch( unsigned timerid );
+ BX_PIT_SMF void set_GATE(unsigned pit_id, unsigned value);
+ BX_PIT_SMF void start(unsigned timerid);
+ };
+
+extern bx_pit_c bx_pit;
+
+#endif // #if (BX_USE_NEW_PIT==0)
+#endif // #ifndef _BX_PIT_H
diff --git a/tools/ioemu/iodev/pit82c54.cc b/tools/ioemu/iodev/pit82c54.cc
new file mode 100644
index 0000000000..493faf6ee1
--- /dev/null
+++ b/tools/ioemu/iodev/pit82c54.cc
@@ -0,0 +1,930 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit82c54.cc,v 1.23 2003/06/29 17:24:52 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ * 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?
+ */
+
+#include "bochs.h"
+#include "pit82c54.h"
+#define LOG_THIS this->
+
+
+void pit_82C54::print_counter(counter_type & thisctr) {
+#if 1
+ 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"));
+#endif
+}
+
+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, bool data) {
+ //This will probably have a callback, so I put it here.
+ thisctr.OUTpin=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) {
+ Bit8u i;
+
+ put("PIT81");
+ settype(PIT81LOG);
+
+ for(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;
+ }
+ seen_problems=0;
+ }
+
+ pit_82C54::pit_82C54 (void) {
+ init();
+ }
+
+ void pit_82C54::reset (unsigned type) {
+ }
+
+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;
+ }
+
+#ifdef BX_VMX_PIT
+//extra operations when use vmx pit device model
+ void pit_82C54::write_initcount_vmx(Bit8u cnum) {
+ if(cnum>MAX_COUNTER) {
+ BX_ERROR(("Counter number incorrect\n"));
+ }
+
+ ioreq_t *req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+ extern bx_pic_c *thePic;
+ counter_type & thisctr = counter[cnum];
+ if(req->pdata_valid) {
+ BX_ERROR(("VMX_PIT:err!pit is port io!\n"));
+ }
+
+ if (thisctr.mode == 2) {//periodic mode, need HV to help send interrupt
+ req->state = STATE_IORESP_HOOK;
+
+// req->u.data = thisctr.inlatch * 1000 / PIT_FREQ;//init count:16 bit
+ req->u.data = thisctr.inlatch; //init count:16 bit
+ //get the pit irq(0)'s vector from pic DM
+ req->u.data |= ((thePic->irq_to_vec(0)) << 16 ); //timer vec:8 bit
+ req->u.data |= (cnum << 24); //PIT channel(0~2):2 bit
+ req->u.data |= ((thisctr.rw_mode) << 26); //rw mode:2 bit
+
+ BX_INFO(("VMX_PIT:whole pit hook packet = 0x%llx \n", (req->u.data ) ));
+ BX_INFO(("VMX_PIT:init counter = %d ms\n", (req->u.data & 0xFFFF) ));
+ }
+
+ }
+#endif
+
+ 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=(thisctr.inlatch & (0xFF<<8)) | data;
+ thisctr.write_state=MSByte_multiple;
+ break;
+ case LSByte:
+ thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
+ thisctr.null_count=1;
+ thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+ write_initcount_vmx(address);
+#endif
+ break;
+ case MSByte_multiple:
+ thisctr.write_state=LSByte_multiple;
+ case MSByte: //shared between MSB_multiple and MSByte
+ thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
+ thisctr.null_count=1;
+ thisctr.count_written=1;
+#ifdef BX_VMX_PIT
+ write_initcount_vmx(address);
+#endif
+ break;
+ default:
+ BX_ERROR(("write counter in invalid write state."));
+ break;
+ }
+ 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, 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;
+ }
+ }
+ }
+ }
+
+ bool pit_82C54::read_OUT(Bit8u cnum) {
+ if(cnum>MAX_COUNTER) {
+ BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
+ return 0;
+ } else {
+ return counter[cnum].OUTpin;
+ }
+ }
+
+ bool pit_82C54::read_GATE(Bit8u cnum) {
+ if(cnum>MAX_COUNTER) {
+ BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
+ return 0;
+ } else {
+ 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;
+ } else {
+ return counter[cnum].next_change_time;
+ }
+}
+
+Bit32u pit_82C54::get_next_event_time(void) {
+ Bit32u out;
+ Bit32u time0=get_clock_event_time(0);
+ Bit32u time1=get_clock_event_time(1);
+ Bit32u time2=get_clock_event_time(2);
+
+ out=time0;
+ if(time1 && (time1<out))
+ out=time1;
+ if(time2 && (time2<out))
+ out=time2;
+ return out;
+}
diff --git a/tools/ioemu/iodev/pit82c54.h b/tools/ioemu/iodev/pit82c54.h
new file mode 100644
index 0000000000..95d36b3973
--- /dev/null
+++ b/tools/ioemu/iodev/pit82c54.h
@@ -0,0 +1,143 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit82c54.h,v 1.12 2003/03/02 23:59:11 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ * Emulator of an Intel 8254/82C54 Programmable Interval Timer.
+ * Greg Alexander <yakovlev@usa.com>
+ *
+ * This code is not yet linked into Bochs, but has been included so
+ * that you can experiment with it. (bbd)
+ */
+
+#ifndef _PIT_82C54_H_
+#define _PIT_82C54_H_ 1
+
+#include "bochs.h"
+
+#ifdef BX_USE_VMX
+#define BX_VMX_PIT 1
+#define PIT_FREQ 1193181
+#endif
+
+
+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;
+ bool GATE; //GATE Input value at end of cycle
+ 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.
+ bool bcd_mode; //1-bit BCD vs. Binary setting.
+ bool null_count; //Null count bit of status register.
+
+ //Latch status data;
+ bool count_LSB_latched;
+ bool count_MSB_latched;
+ bool status_latched;
+
+ //Miscelaneous State;
+ Bit32u count_binary; //Value of the count in binary.
+ 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
+ bool count_written; //Whether a count written since programmed
+ bool first_pass; //Whether or not this is the first loaded count.
+ bool state_bit_1; //Miscelaneous state bits.
+ bool state_bit_2;
+ Bit32u next_change_time; //Next time something besides count changes.
+ //0 means never.
+ };
+
+ counter_type counter[3];
+
+ Bit8u controlword;
+
+ int seen_problems;
+
+ void latch_counter(counter_type & thisctr);
+
+ void set_OUT (counter_type & thisctr, 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);
+
+#ifdef BX_USE_VMX
+ void write_initcount_vmx(Bit8u cnum);
+#endif
+
+public:
+ void init (void);
+ void reset (unsigned type);
+ pit_82C54 (void);
+
+ 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, bool data);
+ bool read_GATE(Bit8u cnum);
+
+ bool read_OUT(Bit8u cnum);
+
+ Bit32u get_clock_event_time(Bit8u cnum);
+ Bit32u get_next_event_time(void);
+
+ void print_cnum(Bit8u cnum);
+
+};
+
+#endif
diff --git a/tools/ioemu/iodev/pit_wrap.cc b/tools/ioemu/iodev/pit_wrap.cc
new file mode 100644
index 0000000000..5fd1721073
--- /dev/null
+++ b/tools/ioemu/iodev/pit_wrap.cc
@@ -0,0 +1,444 @@
+////////////////////////////////////////////////////////////////////////
+// $Id: pit_wrap.cc,v 1.52 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+#include "bochs.h"
+
+#if BX_USE_NEW_PIT
+
+#include "pit_wrap.h"
+
+
+//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))
+
+//DEBUG configuration:
+
+//Set up Logging.
+#define LOG_THIS bx_pit.
+
+//A single instance.
+bx_pit_c bx_pit;
+#if BX_USE_PIT_SMF
+#define this (&bx_pit)
+#endif
+
+//Workaround for environments where OUT is defined.
+#ifdef OUT
+# undef OUT
+#endif
+
+
+//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( void )
+{
+ put("PIT");
+ settype(PITLOG);
+ s.speaker_data_on=0;
+
+ /* 8254 PIT (Programmable Interval Timer) */
+
+ BX_PIT_THIS s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
+ BX_PIT_THIS s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
+ BX_PIT_THIS s.timer_handle[0] = BX_NULL_TIMER_HANDLE;
+}
+
+bx_pit_c::~bx_pit_c( void )
+{
+}
+
+ int
+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(("pit: starting init"));
+
+ BX_PIT_THIS s.speaker_data_on = 0;
+ BX_PIT_THIS s.refresh_clock_div2 = 0;
+
+ BX_PIT_THIS s.timer.init();
+
+ 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(("pit: 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(("pit: 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));
+
+ return(1);
+}
+
+ void
+bx_pit_c::reset(unsigned type)
+{
+}
+
+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(("pit: 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(("pit: 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 int io_len )
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_PIT_SMF
+ BX_DEBUG(("pit: entering read handler"));
+
+ handle_timer();
+
+ Bit64u my_time_usec = bx_virt_timer.time_usec();
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: io read from port %04x", (unsigned) address));
+
+ switch (address) {
+
+ case 0x40: /* timer 0 - system ticks */
+ return(BX_PIT_THIS s.timer.read(0));
+ break;
+ case 0x41: /* timer 1 read */
+ return(BX_PIT_THIS s.timer.read(1));
+ break;
+ case 0x42: /* timer 2 read */
+ return(BX_PIT_THIS s.timer.read(2));
+ break;
+ case 0x43: /* timer 1 read */
+ return(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);
+ return( (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(("pit: unsupported io read from port %04x", address));
+ }
+ return(0); /* keep compiler happy */
+}
+
+
+ // 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 int 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;
+
+ BX_DEBUG(("pit: entering write handler"));
+
+ if(time_passed32) {
+ periodic(time_passed32);
+ }
+ BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
+
+ value = (Bit8u ) dvalue;
+
+ if (bx_dbg.pit)
+ BX_INFO(("pit: write to port %04x = %02x",
+ (unsigned) address, (unsigned) 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;
+/*??? only on AT+ */
+ BX_PIT_THIS s.timer.set_GATE(2, value & 0x01);
+#if BX_CPU_LEVEL < 2
+ /* ??? XT: */
+ bx_kbd_port61h_write(value);
+#endif
+ break;
+
+ default:
+ BX_PANIC(("pit: unsupported io write to port %04x = %02x",
+ (unsigned) address, (unsigned) value));
+ }
+
+#ifndef BX_VMX_PIT
+ if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+ DEV_pic_raise_irq(0);
+ } else {
+ DEV_pic_lower_irq(0);
+ }
+#endif
+
+ if(time_passed ||
+ (BX_PIT_THIS s.last_next_event_time
+ != BX_PIT_THIS s.timer.get_next_event_time())
+ ) {
+ BX_DEBUG(("pit: 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));
+
+}
+
+
+
+
+ int
+bx_pit_c::SaveState( class state_file *fd )
+{
+ fd->write_check ("8254 start");
+ fd->write (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->write_check ("8254 end");
+ return(0);
+}
+
+
+ int
+bx_pit_c::LoadState( class state_file *fd )
+{
+ fd->read_check ("8254 start");
+ fd->read (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+ fd->read_check ("8254 end");
+ return(0);
+}
+
+
+#if 0
+ void
+bx_kbd_port61h_write(Bit8u value)
+{
+// PcError("KBD_PORT61H_WRITE(): not implemented yet");
+ UNUSED( value );
+}
+#endif
+
+
+ bx_bool
+bx_pit_c::periodic( Bit32u usec_delta )
+{
+ bx_bool prev_timer0_out = BX_PIT_THIS s.timer.read_OUT(0);
+ bx_bool want_interrupt = 0;
+ Bit32u ticks_delta = 0;
+
+#ifdef BX_SCHEDULED_DIE_TIME
+ if (bx_pc_system.time_ticks() > BX_SCHEDULED_DIE_TIME) {
+ BX_ERROR (("ticks exceeded scheduled die time, quitting"));
+ BX_EXIT (2);
+ }
+#endif
+
+ 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);
+ if ( (prev_timer0_out==0) ) {
+ if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+#ifndef BX_VMX_PIT
+ DEV_pic_raise_irq(0);
+#endif
+ prev_timer0_out=1;
+ }
+ } else {
+ if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
+#ifndef BX_VMX_PIT
+ DEV_pic_lower_irq(0);
+#endif
+ prev_timer0_out=0;
+ }
+ }
+ prev_timer0_out=BX_PIT_THIS s.timer.read_OUT(0);
+ ticks_delta-=timedelta;
+ }
+
+ return(want_interrupt);
+}
+
+#endif // #if BX_USE_NEW_PIT
diff --git a/tools/ioemu/iodev/pit_wrap.h b/tools/ioemu/iodev/pit_wrap.h
new file mode 100644
index 0000000000..e45e1e6b57
--- /dev/null
+++ b/tools/ioemu/iodev/pit_wrap.h
@@ -0,0 +1,104 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit_wrap.h,v 1.17 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#ifndef _BX_PIT_WRAP_H
+#define _BX_PIT_WRAP_H
+
+#include "bochs.h"
+
+#if BX_USE_NEW_PIT
+
+#include "pit82c54.h"
+
+#if BX_USE_PIT_SMF
+# define BX_PIT_SMF static
+# define BX_PIT_THIS bx_pit.
+#else
+# define BX_PIT_SMF
+# define BX_PIT_THIS this->
+#endif
+
+#ifdef OUT
+# undef OUT
+#endif
+
+class bx_pit_c : public logfunctions {
+public:
+ bx_pit_c( void );
+ ~bx_pit_c( void );
+ BX_PIT_SMF int init( void );
+ BX_PIT_SMF void reset( unsigned type);
+ BX_PIT_SMF bx_bool periodic( Bit32u usec_delta );
+
+ BX_PIT_SMF int SaveState( class state_file *fd );
+ BX_PIT_SMF int LoadState( class state_file *fd );
+
+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 int len );
+ void write( Bit32u addr, Bit32u Value, unsigned int len );
+#endif
+
+ struct s_type {
+ pit_82C54 timer;
+ Bit8u speaker_data_on;
+ bx_bool refresh_clock_div2;
+ int timer_handle[3];
+ Bit64u last_usec;
+ Bit32u last_next_event_time;
+ Bit64u total_ticks;
+ Bit64u usec_per_second;
+ Bit64u ticks_per_second;
+ Bit64u total_sec;
+ Bit64u last_time;
+ Bit64u last_sec_usec;
+ Bit64u max_ticks;
+ Bit64u stored_delta;
+ Bit64u total_usec;
+ Bit64u em_last_realtime;
+ Bit64u last_realtime_delta;
+ Bit64u last_realtime_ticks;
+ } s;
+
+ static void timer_handler(void *this_ptr);
+ BX_PIT_SMF void handle_timer();
+
+ BX_PIT_SMF void write_count_reg( Bit8u value, unsigned timerid );
+ BX_PIT_SMF Bit8u read_counter( unsigned timerid );
+ BX_PIT_SMF void latch( unsigned timerid );
+ BX_PIT_SMF void set_GATE(unsigned pit_id, unsigned value);
+ BX_PIT_SMF void start(unsigned timerid);
+
+ BX_PIT_SMF void second_update_data(void);
+};
+
+extern bx_pit_c bx_pit;
+
+#endif // #if BX_USE_NEW_PIT
+#endif // #ifndef _BX_PIT_WRAP_H
diff --git a/tools/ioemu/iodev/plugin.cc b/tools/ioemu/iodev/plugin.cc
new file mode 100644
index 0000000000..136065d9d8
--- /dev/null
+++ b/tools/ioemu/iodev/plugin.cc
@@ -0,0 +1,554 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: plugin.cc,v 1.8 2003/07/31 12:04:47 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file defines the plugin and plugin-device registration functions and
+// the device registration functions. It handles dynamic loading of modules,
+// using the LTDL library for cross-platform support.
+//
+// This file is based on the plugin.c file from plex86, but with significant
+// changes to make it work in Bochs.
+// Plex86 is Copyright (C) 1999-2000 The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#include "bochs.h"
+#include "plugin.h"
+
+#define LOG_THIS genlog->
+
+#define PLUGIN_INIT_FMT_STRING "lib%s_LTX_plugin_init"
+#define PLUGIN_FINI_FMT_STRING "lib%s_LTX_plugin_fini"
+#define PLUGIN_PATH ""
+
+#ifndef WIN32
+#define PLUGIN_FILENAME_FORMAT "libbx_%s.la"
+#else
+#define PLUGIN_FILENAME_FORMAT "bx_%s.dll"
+#endif
+
+
+
+void (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0;
+void (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 0;
+
+void (* pluginResetSignal)(unsigned sig) = 0;
+
+void (*pluginSetHRQ)(unsigned val) = 0;
+void (*pluginSetHRQHackCallback)( void (*callback)(void) ) = 0;
+
+int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+ unsigned base, const char *name, Bit8u mask) = 0;
+int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ unsigned base, const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+ const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ const char *name, Bit8u mask) = 0;
+int (*pluginRegisterTimer)(void *this_ptr, void (*funct)(void *),
+ Bit32u useconds, bx_bool continuous,
+ bx_bool active, const char* name) = 0;
+void (*pluginActivateTimer)(unsigned id, Bit32u usec, bx_bool continuous) = 0;
+
+void (*pluginHRQHackCallback)(void);
+unsigned pluginHRQ = 0;
+
+plugin_t *plugins = NULL; /* Head of the linked list of plugins */
+#if BX_PLUGINS
+static void plugin_init_one(plugin_t *plugin);
+#endif
+
+device_t *devices = NULL; /* Head of the linked list of registered devices */
+
+plugin_t *current_plugin_context = NULL;
+
+/************************************************************************/
+/* Builtins declarations */
+/************************************************************************/
+
+ static void
+builtinRegisterIRQ(unsigned irq, const char* name)
+{
+#if 0
+ pluginlog->panic("builtinRegisterIRQ called, no pic plugin loaded?");
+#else
+ bx_devices.register_irq(irq, name);
+#endif
+}
+
+ static void
+builtinUnregisterIRQ(unsigned irq, const char* name)
+{
+#if 0
+ pluginlog->panic("builtinUnregisterIRQ called, no pic plugin loaded?");
+#else
+ bx_devices.unregister_irq(irq, name);
+#endif
+}
+
+ static void
+builtinSetHRQ(unsigned val)
+{
+#if 0
+ pluginlog->panic("builtinSetHRQ called, no plugin loaded?");
+#else
+ pluginHRQ = val;
+#endif
+}
+
+ static void
+builtinSetHRQHackCallback( void (*callback)(void) )
+{
+#if 0
+ pluginlog->panic("builtinSetHRQHackCallback called, no plugin loaded?");
+#else
+ pluginHRQHackCallback = callback;
+#endif
+}
+
+ static void
+builtinResetSignal( unsigned )
+{
+ pluginlog->panic("builtinResetSignal called, no plugin loaded?");
+}
+
+ static int
+builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback,
+ unsigned base, const char *name, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_io_read_handler (thisPtr, callback, base, name, mask);
+ pluginlog->ldebug("plugin %s registered I/O read address at %04x", name, base);
+ return 0;
+}
+
+ static int
+builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
+ unsigned base, const char *name, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_io_write_handler (thisPtr, callback, base, name, mask);
+ pluginlog->ldebug("plugin %s registered I/O write address at %04x", name, base);
+ return 0;
+}
+
+ static int
+builtinRegisterDefaultIOReadHandler(void *thisPtr, ioReadHandler_t callback,
+ const char *name, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_default_io_read_handler (thisPtr, callback, name, mask);
+ pluginlog->ldebug("plugin %s registered default I/O read ", name);
+ return 0;
+}
+
+ static int
+builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
+ const char *name, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_default_io_write_handler (thisPtr, callback, name, mask);
+ pluginlog->ldebug("plugin %s registered default I/O write ", name);
+ return 0;
+}
+
+ static int
+builtinRegisterTimer(void *this_ptr, void (*funct)(void *),
+ Bit32u useconds, bx_bool continuous,
+ bx_bool active, const char* name)
+{
+ int id = bx_pc_system.register_timer (this_ptr, funct, useconds, continuous, active, name);
+ pluginlog->ldebug("plugin %s registered timer %d", name, id);
+ return id;
+}
+
+ static void
+builtinActivateTimer(unsigned id, Bit32u usec, bx_bool continuous)
+{
+ bx_pc_system.activate_timer (id, usec, continuous);
+ pluginlog->ldebug("plugin activated timer %d", id);
+}
+
+#if BX_PLUGINS
+/************************************************************************/
+/* Plugin initialization / deinitialization */
+/************************************************************************/
+
+ void
+plugin_init_all (void)
+{
+ plugin_t *plugin;
+
+ pluginlog->info("Initializing plugins");
+
+ for (plugin = plugins; plugin; plugin = plugin->next)
+ {
+ char *arg_ptr = plugin->args;
+
+ /* process the command line */
+ plugin->argc = 0;
+ while (plugin->argc < MAX_ARGC)
+ {
+ while (*arg_ptr && isspace (*arg_ptr))
+ arg_ptr++;
+
+ if (!*arg_ptr)
+ break;
+ plugin->argv[plugin->argc++] = arg_ptr;
+
+ while (*arg_ptr && !isspace (*arg_ptr))
+ arg_ptr++;
+
+ if (!*arg_ptr)
+ break;
+ *arg_ptr++ = '\0';
+ }
+
+ /* initialize the plugin */
+ if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
+ {
+ pluginlog->panic("Plugin initialization failed for %s", plugin->name);
+ plugin_abort();
+ }
+
+ plugin->initialized = 1;
+ }
+
+ return;
+}
+
+void
+plugin_init_one(plugin_t *plugin)
+{
+ char *arg_ptr = plugin->args;
+
+ /* process the command line */
+ plugin->argc = 0;
+ while (plugin->argc < MAX_ARGC)
+ {
+ while (*arg_ptr && isspace (*arg_ptr))
+ arg_ptr++;
+
+ if (!*arg_ptr)
+ break;
+ plugin->argv[plugin->argc++] = arg_ptr;
+
+ while (*arg_ptr && !isspace (*arg_ptr))
+ arg_ptr++;
+
+ if (!*arg_ptr)
+ break;
+ *arg_ptr++ = '\0';
+ }
+
+ /* initialize the plugin */
+ if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
+ {
+ pluginlog->info("Plugin initialization failed for %s", plugin->name);
+ plugin_abort();
+ }
+
+ plugin->initialized = 1;
+}
+
+
+ plugin_t *
+plugin_unload(plugin_t *plugin)
+{
+ plugin_t *dead_plug;
+
+ if (plugin->initialized)
+ plugin->plugin_fini ();
+
+ lt_dlclose (plugin->handle);
+ free (plugin->name);
+ free (plugin->args);
+
+ dead_plug = plugin;
+ plugin = plugin->next;
+ free (dead_plug);
+
+ return plugin;
+}
+
+
+void
+plugin_fini_all (void)
+{
+ plugin_t *plugin;
+
+ for (plugin = plugins; plugin; plugin = plugin_unload (plugin));
+
+ return;
+}
+
+ void
+plugin_load (char *name, char *args, plugintype_t type)
+{
+ plugin_t *plugin;
+
+ plugin = (plugin_t *)malloc (sizeof (plugin_t));
+ if (!plugin)
+ {
+ BX_PANIC (("malloc plugin_t failed"));
+ }
+
+ plugin->type = type;
+ plugin->name = name;
+ plugin->args = args;
+ plugin->initialized = 0;
+
+ char plugin_filename[BX_PATHNAME_LEN], buf[BX_PATHNAME_LEN];
+ sprintf (buf, PLUGIN_FILENAME_FORMAT, name);
+ sprintf(plugin_filename, "%s%s", PLUGIN_PATH, buf);
+
+ // Set context so that any devices that the plugin registers will
+ // be able to see which plugin created them. The registration will
+ // be called from either dlopen (global constructors) or plugin_init.
+ BX_ASSERT (current_plugin_context == NULL);
+ current_plugin_context = plugin;
+ plugin->handle = lt_dlopen (plugin_filename);
+ BX_INFO (("lt_dlhandle is %p", plugin->handle));
+ if (!plugin->handle)
+ {
+ current_plugin_context = NULL;
+ BX_PANIC (("dlopen failed for module '%s': %s", name, lt_dlerror ()));
+ free (plugin);
+ return;
+ }
+
+ sprintf (buf, PLUGIN_INIT_FMT_STRING, name);
+ plugin->plugin_init =
+ (int (*)(struct _plugin_t *, enum plugintype_t, int, char *[])) /* monster typecast */
+ lt_dlsym (plugin->handle, buf);
+ if (plugin->plugin_init == NULL) {
+ pluginlog->panic("could not find plugin_init: %s", lt_dlerror ());
+ plugin_abort ();
+ }
+
+ sprintf (buf, PLUGIN_FINI_FMT_STRING, name);
+ plugin->plugin_fini = (void (*)(void)) lt_dlsym (plugin->handle, buf);
+ if (plugin->plugin_init == NULL) {
+ pluginlog->panic("could not find plugin_fini: %s", lt_dlerror ());
+ plugin_abort ();
+ }
+ pluginlog->info("loaded plugin %s",plugin_filename);
+
+
+ /* Insert plugin at the _end_ of the plugin linked list. */
+ plugin->next = NULL;
+
+ if (!plugins)
+ {
+ /* Empty list, this become the first entry. */
+ plugins = plugin;
+ }
+ else
+ {
+ /* Non-empty list. Add to end. */
+ plugin_t *temp = plugins;
+
+ while (temp->next)
+ temp = temp->next;
+
+ temp->next = plugin;
+ }
+
+ plugin_init_one(plugin);
+
+ // check that context didn't change. This should only happen if we
+ // need a reentrant plugin_load.
+ BX_ASSERT (current_plugin_context == plugin);
+ current_plugin_context = NULL;
+
+ return;
+}
+
+void
+plugin_abort (void)
+{
+ pluginlog->panic("plugin load aborted");
+}
+
+#endif /* end of #if BX_PLUGINS */
+
+/************************************************************************/
+/* Plugin system: initialisation of plugins entry points */
+/************************************************************************/
+
+ void
+plugin_startup(void)
+{
+ pluginRegisterIRQ = builtinRegisterIRQ;
+ pluginUnregisterIRQ = builtinUnregisterIRQ;
+
+ pluginResetSignal = builtinResetSignal;
+
+ pluginSetHRQHackCallback = builtinSetHRQHackCallback;
+ pluginSetHRQ = builtinSetHRQ;
+
+ pluginRegisterIOReadHandler = builtinRegisterIOReadHandler;
+ pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler;
+
+ pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler;
+ pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler;
+
+ pluginRegisterTimer = builtinRegisterTimer;
+ pluginActivateTimer = builtinActivateTimer;
+
+#if BX_PLUGINS
+ pluginlog = new logfunctions();
+ pluginlog->put("PLGIN");
+ pluginlog->settype(PLUGINLOG);
+ int status = lt_dlinit ();
+ if (status != 0) {
+ BX_ERROR (("initialization error in ltdl library (for loading plugins)"));
+ BX_PANIC (("error message was: %s", lt_dlerror ()));
+ }
+#endif
+}
+
+
+/************************************************************************/
+/* Plugin system: Device registration */
+/************************************************************************/
+
+void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *devmodel, char *name)
+{
+ device_t *device;
+
+ device = (device_t *)malloc (sizeof (device_t));
+ if (!device)
+ {
+ pluginlog->panic("can't allocate device_t");
+ }
+
+ device->name = name;
+ BX_ASSERT (devmodel != NULL);
+ device->devmodel = devmodel;
+ device->plugin = plugin; // this can be NULL
+ device->use_devmodel_interface = 1;
+ device->device_init_mem = NULL; // maybe should use 1 to detect any use?
+ device->device_init_dev = NULL;
+ device->device_reset = NULL;
+ device->device_load_state = NULL;
+ device->device_save_state = NULL;
+ device->next = NULL;
+
+ // Don't add every kind of device to the list.
+ switch (type) {
+ case PLUGTYPE_CORE:
+ // Core devices are present whether or not we are using plugins, so
+ // they are managed by the same code in iodev/devices.cc whether
+ // plugins are on or off.
+ return; // Do not add core devices to the devices list.
+ case PLUGTYPE_OPTIONAL:
+ case PLUGTYPE_USER:
+ default:
+ // The plugin system will manage optional and user devices only.
+ break;
+ }
+
+ if (!devices)
+ {
+ /* Empty list, this become the first entry. */
+ devices = device;
+ }
+ else
+ {
+ /* Non-empty list. Add to end. */
+ device_t *temp = devices;
+
+ while (temp->next)
+ temp = temp->next;
+
+ temp->next = device;
+ }
+}
+
+/************************************************************************/
+/* Plugin system: Check if a plugin is loaded */
+/************************************************************************/
+
+bx_bool pluginDevicePresent(char *name)
+{
+ device_t *device;
+
+ for (device = devices; device; device = device->next)
+ {
+ if (strcmp(device->name,name)==0) return true;
+ }
+
+ return false;
+}
+
+#if BX_PLUGINS
+/************************************************************************/
+/* Plugin system: Load one plugin */
+/************************************************************************/
+
+int bx_load_plugin (const char *name, plugintype_t type)
+{
+ char *namecopy = new char[1+strlen(name)];
+ strcpy (namecopy, name);
+ plugin_load (namecopy, "", type);
+ return 0;
+}
+#endif /* end of #if BX_PLUGINS */
+
+/*************************************************************************/
+/* Plugin system: Execute init function of all registered plugin-devices */
+/*************************************************************************/
+
+void bx_init_plugins()
+{
+ device_t *device;
+
+ // two loops
+ for (device = devices; device; device = device->next)
+ {
+ if (!device->use_devmodel_interface) {
+ if (device->device_init_mem != NULL) {
+ pluginlog->info("init_mem of '%s' plugin device by function pointer",device->name);
+ device->device_init_mem(BX_MEM(0));
+ }
+ } else {
+ pluginlog->info("init_mem of '%s' plugin device by virtual method",device->name);
+ device->devmodel->init_mem (BX_MEM(0));
+ }
+ }
+
+ for (device = devices; device; device = device->next)
+ {
+ if (!device->use_devmodel_interface) {
+ if (device->device_init_dev != NULL) {
+ pluginlog->info("init_dev of '%s' plugin device by function pointer",device->name);
+ device->device_init_dev();
+ }
+ } else {
+ pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
+ device->devmodel->init ();
+ }
+ }
+}
+
+/**************************************************************************/
+/* Plugin system: Execute reset function of all registered plugin-devices */
+/**************************************************************************/
+
+void bx_reset_plugins(unsigned signal)
+{
+ device_t *device;
+ for (device = devices; device; device = device->next)
+ {
+ if (!device->use_devmodel_interface) {
+ if (device->device_reset != NULL) {
+ pluginlog->info("reset of '%s' plugin device by function pointer",device->name);
+ device->device_reset(signal);
+ }
+ } else {
+ pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
+ device->devmodel->reset (signal);
+ }
+ }
+}
diff --git a/tools/ioemu/iodev/scancodes.cc b/tools/ioemu/iodev/scancodes.cc
new file mode 100644
index 0000000000..63efed45f6
--- /dev/null
+++ b/tools/ioemu/iodev/scancodes.cc
@@ -0,0 +1,770 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scancodes.cc,v 1.5 2002/10/24 21:07:51 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// 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" , "\xF0x58" },
+ },
+
+ { // 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\x37" , "\xE0\xB7" },
+ { "\xE0\x7C" , "\xE0\xF0\x7C" },
+ { "\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" },
+ { "" , "" },
+ },
+
+};
diff --git a/tools/ioemu/iodev/scancodes.h b/tools/ioemu/iodev/scancodes.h
new file mode 100644
index 0000000000..f26491b56e
--- /dev/null
+++ b/tools/ioemu/iodev/scancodes.h
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scancodes.h,v 1.4 2002/10/24 21:07:51 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// 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];
diff --git a/tools/ioemu/iodev/scsi_commands.h b/tools/ioemu/iodev/scsi_commands.h
new file mode 100644
index 0000000000..c516fde31c
--- /dev/null
+++ b/tools/ioemu/iodev/scsi_commands.h
@@ -0,0 +1,418 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsi_commands.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* 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
+
diff --git a/tools/ioemu/iodev/scsidefs.h b/tools/ioemu/iodev/scsidefs.h
new file mode 100644
index 0000000000..86239e8a7d
--- /dev/null
+++ b/tools/ioemu/iodev/scsidefs.h
@@ -0,0 +1,286 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsidefs.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// iodev/scsidefs.h
+// $Id: scsidefs.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+//
+// 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)
diff --git a/tools/ioemu/iodev/scsipt.h b/tools/ioemu/iodev/scsipt.h
new file mode 100644
index 0000000000..b3c8508abf
--- /dev/null
+++ b/tools/ioemu/iodev/scsipt.h
@@ -0,0 +1,144 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsipt.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// iodev/scsipt.h
+// $Id: scsipt.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+//
+// 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
diff --git a/tools/ioemu/iodev/serial.cc b/tools/ioemu/iodev/serial.cc
new file mode 100644
index 0000000000..02deec3014
--- /dev/null
+++ b/tools/ioemu/iodev/serial.cc
@@ -0,0 +1,1001 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial.cc,v 1.41 2003/11/09 00:14:43 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Peter Grehan (grehan@iprg.nokia.com) coded the original version of this
+// serial emulation. He implemented a single 8250, and allow terminal
+// input/output to stdout on FreeBSD.
+// The current version emulates a single 16550A with FIFO. Terminal
+// input/output now works on some more platforms.
+
+
+// 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"
+
+#define LOG_THIS theSerialDevice->
+
+#if USE_RAW_SERIAL
+#include <signal.h>
+#endif
+
+#ifdef WIN32
+#ifndef __MINGW32__
+// +++
+//#include <winsock2.h>
+#include <winsock.h>
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__GNU__) || defined(__APPLE__)
+#define SERIAL_ENABLE
+#endif
+
+#ifdef SERIAL_ENABLE
+extern "C" {
+#include <termios.h>
+};
+#endif
+
+#ifdef SERIAL_ENABLE
+static struct termios term_orig, term_new;
+#endif
+
+static int tty_id;
+
+bx_serial_c *theSerialDevice = NULL;
+
+ int
+libserial_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theSerialDevice = new bx_serial_c ();
+ bx_devices.pluginSerialDevice = theSerialDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSerialDevice, BX_PLUGIN_SERIAL);
+ return(0); // Success
+}
+
+ void
+libserial_LTX_plugin_fini(void)
+{
+}
+
+bx_serial_c::bx_serial_c(void)
+{
+ put("SER");
+ settype(SERLOG);
+ tty_id = -1;
+ for (int i=0; i<BX_SERIAL_MAXDEV; i++) {
+ s[i].tx_timer_index = BX_NULL_TIMER_HANDLE;
+ s[i].rx_timer_index = BX_NULL_TIMER_HANDLE;
+ s[i].fifo_timer_index = BX_NULL_TIMER_HANDLE;
+ }
+}
+
+bx_serial_c::~bx_serial_c(void)
+{
+#ifdef SERIAL_ENABLE
+ if ((bx_options.com[0].Oenabled->get ()) && (tty_id >= 0))
+ tcsetattr(tty_id, TCSAFLUSH, &term_orig);
+#endif
+ // nothing for now
+}
+
+
+ void
+bx_serial_c::init(void)
+{
+ Bit16u ports[BX_SERIAL_MAXDEV] = {0x03f8, 0x02f8, 0x03e8, 0x02e8};
+ char name[16];
+
+ if (!bx_options.com[0].Oenabled->get ())
+ return;
+
+#ifdef SERIAL_ENABLE
+ if (strlen(bx_options.com[0].Odev->getptr ()) > 0) {
+ tty_id = open(bx_options.com[0].Odev->getptr (), O_RDWR|O_NONBLOCK,600);
+ if (tty_id < 0)
+ BX_PANIC(("open of %s (%s) failed\n",
+ "com1", bx_options.com[0].Odev->getptr ()));
+ BX_DEBUG(("tty_id: %d",tty_id));
+ tcgetattr(tty_id, &term_orig);
+ bcopy((caddr_t) &term_orig, (caddr_t) &term_new, sizeof(struct termios));
+ cfmakeraw(&term_new);
+ term_new.c_oflag |= OPOST | ONLCR; // Enable NL to CR-NL translation
+#ifndef TRUE_CTLC
+ // ctl-C will exit Bochs, or trap to the debugger
+ term_new.c_iflag &= ~IGNBRK;
+ term_new.c_iflag |= BRKINT;
+ term_new.c_lflag |= ISIG;
+#else
+ // ctl-C will be delivered to the serial port
+ term_new.c_iflag |= IGNBRK;
+ term_new.c_iflag &= ~BRKINT;
+#endif /* !def TRUE_CTLC */
+ term_new.c_iflag = 0;
+ term_new.c_oflag = 0;
+ term_new.c_cflag = CS8|CREAD|CLOCAL;
+ term_new.c_lflag = 0;
+ term_new.c_cc[VMIN] = 1;
+ term_new.c_cc[VTIME] = 0;
+ //term_new.c_iflag |= IXOFF;
+ tcsetattr(tty_id, TCSAFLUSH, &term_new);
+ }
+#endif /* def SERIAL_ENABLE */
+ // nothing for now
+#if USE_RAW_SERIAL
+ this->raw = new serial_raw("/dev/cua0", SIGUSR1);
+#endif // USE_RAW_SERIAL
+
+ /*
+ * Put the UART registers into their RESET state
+ */
+ for (unsigned i=0; i<BX_N_SERIAL_PORTS; i++) {
+ if (bx_options.com[i].Oenabled->get ()) {
+ sprintf(name, "Serial Port %d", i + 1);
+ /* serial interrupt */
+ BX_SER_THIS s[i].IRQ = 4 - (i & 1);
+ if (i < 2) {
+ DEV_register_irq(BX_SER_THIS s[i].IRQ, name);
+ }
+ /* internal state */
+ BX_SER_THIS s[i].ls_ipending = 0;
+ BX_SER_THIS s[i].ms_ipending = 0;
+ BX_SER_THIS s[i].rx_ipending = 0;
+ BX_SER_THIS s[i].fifo_ipending = 0;
+ BX_SER_THIS s[i].ls_interrupt = 0;
+ BX_SER_THIS s[i].ms_interrupt = 0;
+ BX_SER_THIS s[i].rx_interrupt = 0;
+ BX_SER_THIS s[i].tx_interrupt = 0;
+ BX_SER_THIS s[i].fifo_interrupt = 0;
+
+ if (BX_SER_THIS s[i].tx_timer_index == BX_NULL_TIMER_HANDLE) {
+ BX_SER_THIS s[i].tx_timer_index =
+ bx_pc_system.register_timer(this, tx_timer_handler, 0,
+ 0,0, "serial.tx"); // one-shot, inactive
+ }
+
+ if (BX_SER_THIS s[i].rx_timer_index == BX_NULL_TIMER_HANDLE) {
+ BX_SER_THIS s[i].rx_timer_index =
+ bx_pc_system.register_timer(this, rx_timer_handler, 0,
+ 0,0, "serial.rx"); // one-shot, inactive
+ }
+ if (BX_SER_THIS s[i].fifo_timer_index == BX_NULL_TIMER_HANDLE) {
+ BX_SER_THIS s[i].fifo_timer_index =
+ bx_pc_system.register_timer(this, fifo_timer_handler, 0,
+ 0,0, "serial.fifo"); // one-shot, inactive
+ }
+ BX_SER_THIS s[i].rx_pollstate = BX_SER_RXIDLE;
+
+ /* int enable: b0000 0000 */
+ BX_SER_THIS s[i].int_enable.rxdata_enable = 0;
+ BX_SER_THIS s[i].int_enable.txhold_enable = 0;
+ BX_SER_THIS s[i].int_enable.rxlstat_enable = 0;
+ BX_SER_THIS s[i].int_enable.modstat_enable = 0;
+
+ /* int ID: b0000 0001 */
+ BX_SER_THIS s[i].int_ident.ipending = 1;
+ BX_SER_THIS s[i].int_ident.int_ID = 0;
+
+ /* FIFO control: b0000 0000 */
+ BX_SER_THIS s[i].fifo_cntl.enable = 0;
+ BX_SER_THIS s[i].fifo_cntl.rxtrigger = 0;
+ BX_SER_THIS s[i].rx_fifo_end = 0;
+ BX_SER_THIS s[i].tx_fifo_end = 0;
+
+ /* Line Control reg: b0000 0000 */
+ BX_SER_THIS s[i].line_cntl.wordlen_sel = 0;
+ BX_SER_THIS s[i].line_cntl.stopbits = 0;
+ BX_SER_THIS s[i].line_cntl.parity_enable = 0;
+ BX_SER_THIS s[i].line_cntl.evenparity_sel = 0;
+ BX_SER_THIS s[i].line_cntl.stick_parity = 0;
+ BX_SER_THIS s[i].line_cntl.break_cntl = 0;
+ BX_SER_THIS s[i].line_cntl.dlab = 0;
+
+ /* Modem Control reg: b0000 0000 */
+ BX_SER_THIS s[i].modem_cntl.dtr = 0;
+ BX_SER_THIS s[i].modem_cntl.rts = 0;
+ BX_SER_THIS s[i].modem_cntl.out1 = 0;
+ BX_SER_THIS s[i].modem_cntl.out2 = 0;
+ BX_SER_THIS s[i].modem_cntl.local_loopback = 0;
+
+ /* Line Status register: b0110 0000 */
+ BX_SER_THIS s[i].line_status.rxdata_ready = 0;
+ BX_SER_THIS s[i].line_status.overrun_error = 0;
+ BX_SER_THIS s[i].line_status.parity_error = 0;
+ BX_SER_THIS s[i].line_status.framing_error = 0;
+ BX_SER_THIS s[i].line_status.break_int = 0;
+ BX_SER_THIS s[i].line_status.thr_empty = 1;
+ BX_SER_THIS s[i].line_status.tsr_empty = 1;
+ BX_SER_THIS s[i].line_status.fifo_error = 0;
+
+ /* Modem Status register: bXXXX 0000 */
+ BX_SER_THIS s[i].modem_status.delta_cts = 0;
+ BX_SER_THIS s[i].modem_status.delta_dsr = 0;
+ BX_SER_THIS s[i].modem_status.ri_trailedge = 0;
+ BX_SER_THIS s[i].modem_status.delta_dcd = 0;
+ BX_SER_THIS s[i].modem_status.cts = 0;
+ BX_SER_THIS s[i].modem_status.dsr = 0;
+ BX_SER_THIS s[i].modem_status.ri = 0;
+ BX_SER_THIS s[i].modem_status.dcd = 0;
+
+ BX_SER_THIS s[i].scratch = 0; /* scratch register */
+ BX_SER_THIS s[i].divisor_lsb = 1; /* divisor-lsb register */
+ BX_SER_THIS s[i].divisor_msb = 0; /* divisor-msb register */
+
+ BX_SER_THIS s[i].baudrate = 115200;
+
+ for (unsigned addr=ports[i]; addr<(unsigned)(ports[i]+8); addr++) {
+ BX_DEBUG(("register read/write: 0x%04x",addr));
+ DEV_register_ioread_handler(this, read_handler, addr, name, 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, name, 1);
+ }
+ BX_INFO(("com%d at 0x%04x irq %d", i+1, ports[i], BX_SER_THIS s[i].IRQ));
+ }
+ }
+}
+
+ void
+bx_serial_c::reset(unsigned type)
+{
+}
+
+ void
+bx_serial_c::lower_interrupt(Bit8u port)
+{
+ /* If there are no more ints pending, clear the irq */
+ if ((BX_SER_THIS s[port].rx_interrupt == 0) &&
+ (BX_SER_THIS s[port].tx_interrupt == 0) &&
+ (BX_SER_THIS s[port].ls_interrupt == 0) &&
+ (BX_SER_THIS s[port].ms_interrupt == 0) &&
+ (BX_SER_THIS s[port].fifo_interrupt == 0)) {
+ DEV_pic_lower_irq(BX_SER_THIS s[port].IRQ);
+ }
+}
+
+ void
+bx_serial_c::raise_interrupt(Bit8u port, int type)
+{
+ bx_bool gen_int = 0;
+
+ switch (type) {
+ case BX_SER_INT_IER: /* IER has changed */
+ gen_int = 1;
+ break;
+ case BX_SER_INT_RXDATA:
+ if (BX_SER_THIS s[port].int_enable.rxdata_enable) {
+ BX_SER_THIS s[port].rx_interrupt = 1;
+ gen_int = 1;
+ } else {
+ BX_SER_THIS s[port].rx_ipending = 1;
+ }
+ break;
+ case BX_SER_INT_TXHOLD:
+ if (BX_SER_THIS s[port].int_enable.txhold_enable) {
+ BX_SER_THIS s[port].tx_interrupt = 1;
+ gen_int = 1;
+ }
+ break;
+ case BX_SER_INT_RXLSTAT:
+ if (BX_SER_THIS s[port].int_enable.rxlstat_enable) {
+ BX_SER_THIS s[port].ls_interrupt = 1;
+ gen_int = 1;
+ } else {
+ BX_SER_THIS s[port].ls_ipending = 1;
+ }
+ break;
+ case BX_SER_INT_MODSTAT:
+ if ((BX_SER_THIS s[port].ms_ipending == 1) &&
+ (BX_SER_THIS s[port].int_enable.modstat_enable == 1)) {
+ BX_SER_THIS s[port].ms_interrupt = 1;
+ BX_SER_THIS s[port].ms_ipending = 0;
+ gen_int = 1;
+ }
+ break;
+ case BX_SER_INT_FIFO:
+ if (BX_SER_THIS s[port].int_enable.rxdata_enable) {
+ BX_SER_THIS s[port].fifo_interrupt = 1;
+ gen_int = 1;
+ } else {
+ BX_SER_THIS s[port].fifo_ipending = 1;
+ }
+ break;
+ }
+ if (gen_int && BX_SER_THIS s[port].modem_cntl.out2) {
+ DEV_pic_raise_irq(BX_SER_THIS s[port].IRQ);
+ }
+}
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_serial_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_SER_SMF
+ bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_serial_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_SER_SMF
+ //UNUSED(address);
+ Bit8u val;
+
+ /* SERIAL PORT 1 */
+
+ BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
+
+ switch (address) {
+ case 0x03F8: /* receive buffer, or divisor latch LSB if DLAB set */
+ if (BX_SER_THIS s[0].line_cntl.dlab) {
+ val = BX_SER_THIS s[0].divisor_lsb;
+ } else {
+ if (BX_SER_THIS s[0].fifo_cntl.enable) {
+ val = BX_SER_THIS s[0].rx_fifo[0];
+ if (BX_SER_THIS s[0].rx_fifo_end > 0) {
+ memcpy(&BX_SER_THIS s[0].rx_fifo[0], &BX_SER_THIS s[0].rx_fifo[1], 15);
+ BX_SER_THIS s[0].rx_fifo_end--;
+ }
+ if (BX_SER_THIS s[0].rx_fifo_end == 0) {
+ BX_SER_THIS s[0].line_status.rxdata_ready = 0;
+ BX_SER_THIS s[0].rx_interrupt = 0;
+ BX_SER_THIS s[0].rx_ipending = 0;
+ BX_SER_THIS s[0].fifo_interrupt = 0;
+ BX_SER_THIS s[0].fifo_ipending = 0;
+ lower_interrupt(0);
+ }
+ } else {
+ val = BX_SER_THIS s[0].rxbuffer;
+ BX_SER_THIS s[0].line_status.rxdata_ready = 0;
+ BX_SER_THIS s[0].rx_interrupt = 0;
+ BX_SER_THIS s[0].rx_ipending = 0;
+ lower_interrupt(0);
+ }
+ }
+ break;
+
+ case 0x03F9: /* interrupt enable register, or div. latch MSB */
+ if (BX_SER_THIS s[0].line_cntl.dlab) {
+ val = BX_SER_THIS s[0].divisor_msb;
+ } else {
+ val = BX_SER_THIS s[0].int_enable.rxdata_enable |
+ (BX_SER_THIS s[0].int_enable.txhold_enable << 1) |
+ (BX_SER_THIS s[0].int_enable.rxlstat_enable << 2) |
+ (BX_SER_THIS s[0].int_enable.modstat_enable << 3);
+ }
+ break;
+
+ case 0x03FA: /* interrupt ID register */
+ /*
+ * Set the interrupt ID based on interrupt source
+ */
+ if (BX_SER_THIS s[0].ls_interrupt) {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x3;
+ BX_SER_THIS s[0].int_ident.ipending = 0;
+ } else if (BX_SER_THIS s[0].fifo_interrupt) {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x6;
+ BX_SER_THIS s[0].int_ident.ipending = 0;
+ } else if (BX_SER_THIS s[0].rx_interrupt) {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x2;
+ BX_SER_THIS s[0].int_ident.ipending = 0;
+ } else if (BX_SER_THIS s[0].tx_interrupt) {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x1;
+ BX_SER_THIS s[0].int_ident.ipending = 0;
+ } else if (BX_SER_THIS s[0].ms_interrupt) {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x0;
+ BX_SER_THIS s[0].int_ident.ipending = 0;
+ } else {
+ BX_SER_THIS s[0].int_ident.int_ID = 0x0;
+ BX_SER_THIS s[0].int_ident.ipending = 1;
+ }
+ BX_SER_THIS s[0].tx_interrupt = 0;
+ lower_interrupt(0);
+
+ val = BX_SER_THIS s[0].int_ident.ipending |
+ (BX_SER_THIS s[0].int_ident.int_ID << 1) |
+ (BX_SER_THIS s[0].fifo_cntl.enable ? 0xc0 : 0x00);
+ break;
+
+ case 0x03FB: /* Line control register */
+ val = BX_SER_THIS s[0].line_cntl.wordlen_sel |
+ (BX_SER_THIS s[0].line_cntl.stopbits << 2) |
+ (BX_SER_THIS s[0].line_cntl.parity_enable << 3) |
+ (BX_SER_THIS s[0].line_cntl.evenparity_sel << 4) |
+ (BX_SER_THIS s[0].line_cntl.stick_parity << 5) |
+ (BX_SER_THIS s[0].line_cntl.break_cntl << 6) |
+ (BX_SER_THIS s[0].line_cntl.dlab << 7);
+ break;
+
+ case 0x03FC: /* MODEM control register */
+ val = BX_SER_THIS s[0].modem_cntl.dtr |
+ (BX_SER_THIS s[0].modem_cntl.rts << 1) |
+ (BX_SER_THIS s[0].modem_cntl.out1 << 2) |
+ (BX_SER_THIS s[0].modem_cntl.out2 << 3) |
+ (BX_SER_THIS s[0].modem_cntl.local_loopback << 4);
+ break;
+
+ case 0x03FD: /* Line status register */
+ val = BX_SER_THIS s[0].line_status.rxdata_ready |
+ (BX_SER_THIS s[0].line_status.overrun_error << 1) |
+ (BX_SER_THIS s[0].line_status.parity_error << 2) |
+ (BX_SER_THIS s[0].line_status.framing_error << 3) |
+ (BX_SER_THIS s[0].line_status.break_int << 4) |
+ (BX_SER_THIS s[0].line_status.thr_empty << 5) |
+ (BX_SER_THIS s[0].line_status.tsr_empty << 6) |
+ (BX_SER_THIS s[0].line_status.fifo_error << 7);
+ BX_SER_THIS s[0].line_status.overrun_error = 0;
+ BX_SER_THIS s[0].line_status.break_int = 0;
+ BX_SER_THIS s[0].ls_interrupt = 0;
+ BX_SER_THIS s[0].ls_ipending = 0;
+ lower_interrupt(0);
+ break;
+
+ case 0x03FE: /* MODEM status register */
+ val = BX_SER_THIS s[0].modem_status.delta_cts |
+ (BX_SER_THIS s[0].modem_status.delta_dsr << 1) |
+ (BX_SER_THIS s[0].modem_status.ri_trailedge << 2) |
+ (BX_SER_THIS s[0].modem_status.delta_dcd << 3) |
+ (BX_SER_THIS s[0].modem_status.cts << 4) |
+ (BX_SER_THIS s[0].modem_status.dsr << 5) |
+ (BX_SER_THIS s[0].modem_status.ri << 6) |
+ (BX_SER_THIS s[0].modem_status.dcd << 7);
+ BX_SER_THIS s[0].modem_status.delta_cts = 0;
+ BX_SER_THIS s[0].modem_status.delta_dsr = 0;
+ BX_SER_THIS s[0].modem_status.ri_trailedge = 0;
+ BX_SER_THIS s[0].modem_status.delta_dcd = 0;
+ BX_SER_THIS s[0].ms_interrupt = 0;
+ BX_SER_THIS s[0].ms_ipending = 0;
+ lower_interrupt(0);
+ break;
+
+ case 0x03FF: /* scratch register */
+ val = BX_SER_THIS s[0].scratch;
+ break;
+
+ default:
+ val = 0; // keep compiler happy
+ BX_PANIC(("unsupported io read from address=0x%04x!",
+ (unsigned) address));
+ break;
+ }
+
+ BX_DEBUG(("val = 0x%02x", (unsigned) val));
+
+ return(val);
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+void
+bx_serial_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_SER_SMF
+ bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+void
+bx_serial_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_SER_SMF
+ bx_bool prev_cts, prev_dsr, prev_ri, prev_dcd;
+ bx_bool new_rx_ien, new_tx_ien, new_ls_ien, new_ms_ien;
+ bx_bool gen_int = 0;
+
+ /* SERIAL PORT 1 */
+
+ BX_DEBUG(("write to address: 0x%04x = 0x%02x",
+ (unsigned) address, (unsigned) value));
+
+ switch (address) {
+ case 0x03F8: /* transmit buffer, or divisor latch LSB if DLAB set */
+ if (BX_SER_THIS s[0].line_cntl.dlab) {
+ BX_SER_THIS s[0].divisor_lsb = value;
+
+ if ((value != 0) || (BX_SER_THIS s[0].divisor_msb != 0)) {
+ BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL /
+ (16 * ((BX_SER_THIS s[0].divisor_msb << 8) |
+ BX_SER_THIS s[0].divisor_lsb)));
+#if USE_RAW_SERIAL
+ BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate);
+#endif // USE_RAW_SERIAL
+ }
+ } else {
+ Bit8u bitmask = 0xff >> (3 - BX_SER_THIS s[0].line_cntl.wordlen_sel);
+ if (BX_SER_THIS s[0].line_status.thr_empty) {
+ if (BX_SER_THIS s[0].fifo_cntl.enable) {
+ BX_SER_THIS s[0].tx_fifo[BX_SER_THIS s[0].tx_fifo_end++] = value & bitmask;
+ } else {
+ BX_SER_THIS s[0].thrbuffer = value & bitmask;
+ }
+ BX_SER_THIS s[0].line_status.thr_empty = 0;
+ if (BX_SER_THIS s[0].line_status.tsr_empty) {
+ if (BX_SER_THIS s[0].fifo_cntl.enable) {
+ BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].tx_fifo[0];
+ memcpy(&BX_SER_THIS s[0].tx_fifo[0], &BX_SER_THIS s[0].tx_fifo[1], 15);
+ BX_SER_THIS s[0].line_status.thr_empty = (--BX_SER_THIS s[0].tx_fifo_end == 0);
+ } else {
+ BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].thrbuffer;
+ BX_SER_THIS s[0].line_status.thr_empty = 1;
+ }
+ BX_SER_THIS s[0].line_status.tsr_empty = 0;
+ raise_interrupt(0, BX_SER_INT_TXHOLD);
+ bx_pc_system.activate_timer(BX_SER_THIS s[0].tx_timer_index,
+ (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+ (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+ 0); /* not continuous */
+ } else {
+ BX_SER_THIS s[0].tx_interrupt = 0;
+ lower_interrupt(0);
+ }
+ } else {
+ if (BX_SER_THIS s[0].fifo_cntl.enable) {
+ if (BX_SER_THIS s[0].tx_fifo_end < 16) {
+ BX_SER_THIS s[0].tx_fifo[BX_SER_THIS s[0].tx_fifo_end++] = value & bitmask;
+ } else {
+ BX_ERROR(("com1: transmit FIFO overflow"));
+ }
+ } else {
+ BX_ERROR(("write to tx hold register when not empty"));
+ }
+ }
+ }
+ break;
+
+ case 0x03F9: /* interrupt enable register, or div. latch MSB */
+ if (BX_SER_THIS s[0].line_cntl.dlab) {
+ BX_SER_THIS s[0].divisor_msb = value;
+
+ if ((value != 0) || (BX_SER_THIS s[0].divisor_lsb != 0)) {
+ BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL /
+ (16 * ((BX_SER_THIS s[0].divisor_msb << 8) |
+ BX_SER_THIS s[0].divisor_lsb)));
+#if USE_RAW_SERIAL
+ BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate);
+#endif // USE_RAW_SERIAL
+ }
+ } else {
+ new_rx_ien = value & 0x01;
+ new_tx_ien = (value & 0x02) >> 1;
+ new_ls_ien = (value & 0x04) >> 2;
+ new_ms_ien = (value & 0x08) >> 3;
+ if (new_ms_ien != BX_SER_THIS s[0].int_enable.modstat_enable) {
+ BX_SER_THIS s[0].int_enable.modstat_enable = new_ms_ien;
+ if (BX_SER_THIS s[0].int_enable.modstat_enable == 1) {
+ if (BX_SER_THIS s[0].ms_ipending == 1) {
+ BX_SER_THIS s[0].ms_interrupt = 1;
+ BX_SER_THIS s[0].ms_ipending = 0;
+ gen_int = 1;
+ }
+ } else {
+ if (BX_SER_THIS s[0].ms_interrupt == 1) {
+ BX_SER_THIS s[0].ms_interrupt = 0;
+ BX_SER_THIS s[0].ms_ipending = 1;
+ lower_interrupt(0);
+ }
+ }
+ }
+ if (new_tx_ien != BX_SER_THIS s[0].int_enable.txhold_enable) {
+ BX_SER_THIS s[0].int_enable.txhold_enable = new_tx_ien;
+ if (BX_SER_THIS s[0].int_enable.txhold_enable == 1) {
+ BX_SER_THIS s[0].tx_interrupt = BX_SER_THIS s[0].line_status.thr_empty;
+ if (BX_SER_THIS s[0].tx_interrupt) gen_int = 1;
+ } else {
+ BX_SER_THIS s[0].tx_interrupt = 0;
+ lower_interrupt(0);
+ }
+ }
+ if (new_rx_ien != BX_SER_THIS s[0].int_enable.rxdata_enable) {
+ BX_SER_THIS s[0].int_enable.rxdata_enable = new_rx_ien;
+ if (BX_SER_THIS s[0].int_enable.rxdata_enable == 1) {
+ if (BX_SER_THIS s[0].fifo_ipending == 1) {
+ BX_SER_THIS s[0].fifo_interrupt = 1;
+ BX_SER_THIS s[0].fifo_ipending = 0;
+ gen_int = 1;
+ }
+ if (BX_SER_THIS s[0].rx_ipending == 1) {
+ BX_SER_THIS s[0].rx_interrupt = 1;
+ BX_SER_THIS s[0].rx_ipending = 0;
+ gen_int = 1;
+ }
+ } else {
+ if (BX_SER_THIS s[0].rx_interrupt == 1) {
+ BX_SER_THIS s[0].rx_interrupt = 0;
+ BX_SER_THIS s[0].rx_ipending = 1;
+ lower_interrupt(0);
+ }
+ if (BX_SER_THIS s[0].fifo_interrupt == 1) {
+ BX_SER_THIS s[0].fifo_interrupt = 0;
+ BX_SER_THIS s[0].fifo_ipending = 1;
+ lower_interrupt(0);
+ }
+ }
+ }
+ if (new_ls_ien != BX_SER_THIS s[0].int_enable.rxlstat_enable) {
+ BX_SER_THIS s[0].int_enable.rxlstat_enable = new_ls_ien;
+ if (BX_SER_THIS s[0].int_enable.rxlstat_enable == 1) {
+ if (BX_SER_THIS s[0].ls_ipending == 1) {
+ BX_SER_THIS s[0].ls_interrupt = 1;
+ BX_SER_THIS s[0].ls_ipending = 0;
+ gen_int = 1;
+ }
+ } else {
+ if (BX_SER_THIS s[0].ls_interrupt == 1) {
+ BX_SER_THIS s[0].ls_interrupt = 0;
+ BX_SER_THIS s[0].ls_ipending = 1;
+ lower_interrupt(0);
+ }
+ }
+ }
+ if (gen_int) raise_interrupt(0, BX_SER_INT_IER);
+ }
+ break;
+
+ case 0x03FA: /* FIFO control register */
+ if (!BX_SER_THIS s[0].fifo_cntl.enable && (value & 0x01)) {
+ BX_INFO(("FIFO enabled"));
+ BX_SER_THIS s[0].rx_fifo_end = 0;
+ BX_SER_THIS s[0].tx_fifo_end = 0;
+ }
+ BX_SER_THIS s[0].fifo_cntl.enable = value & 0x01;
+ if (value & 0x02) {
+ BX_SER_THIS s[0].rx_fifo_end = 0;
+ }
+ if (value & 0x04) {
+ BX_SER_THIS s[0].tx_fifo_end = 0;
+ }
+ BX_SER_THIS s[0].fifo_cntl.rxtrigger = (value & 0xc0) >> 6;
+ break;
+
+ case 0x03FB: /* Line control register */
+#if !USE_RAW_SERIAL
+ if ((value & 0x3) != 0x3) {
+ /* ignore this: this is set by FreeBSD when the console
+ code wants to set DLAB */
+ }
+#endif // !USE_RAW_SERIAL
+#if USE_RAW_SERIAL
+ if (BX_SER_THIS s[0].line_cntl.wordlen_sel != (value & 0x3)) {
+ BX_SER_THIS raw->set_data_bits((value & 0x3) + 5);
+ }
+ if (BX_SER_THIS s[0].line_cntl.stopbits != (value & 0x4) >> 2) {
+ BX_SER_THIS raw->set_stop_bits((value & 0x4 >> 2) ? 2 : 1);
+ }
+ if (BX_SER_THIS s[0].line_cntl.parity_enable != (value & 0x8) >> 3 ||
+ BX_SER_THIS s[0].line_cntl.evenparity_sel != (value & 0x10) >> 4 ||
+ BX_SER_THIS s[0].line_cntl.stick_parity != (value & 0x20) >> 5) {
+ if (((value & 0x20) >> 5) &&
+ ((value & 0x8) >> 3))
+ BX_PANIC(("sticky parity set and parity enabled"));
+ BX_SER_THIS raw->set_parity_mode(((value & 0x8) >> 3),
+ ((value & 0x10) >> 4) ? P_EVEN : P_ODD);
+ }
+ if (BX_SER_THIS s[0].line_cntl.break_cntl && !((value & 0x40) >> 6)) {
+ BX_SER_THIS raw->transmit(C_BREAK);
+ }
+#endif // USE_RAW_SERIAL
+
+ BX_SER_THIS s[0].line_cntl.wordlen_sel = value & 0x3;
+ /* These are ignored, but set them up so they can be read back */
+ BX_SER_THIS s[0].line_cntl.stopbits = (value & 0x4) >> 2;
+ BX_SER_THIS s[0].line_cntl.parity_enable = (value & 0x8) >> 3;
+ BX_SER_THIS s[0].line_cntl.evenparity_sel = (value & 0x10) >> 4;
+ BX_SER_THIS s[0].line_cntl.stick_parity = (value & 0x20) >> 5;
+ BX_SER_THIS s[0].line_cntl.break_cntl = (value & 0x40) >> 6;
+ /* used when doing future writes */
+ if (BX_SER_THIS s[0].line_cntl.dlab &&
+ !((value & 0x80) >> 7)) {
+ // Start the receive polling process if not already started
+ // and there is a valid baudrate.
+ if (BX_SER_THIS s[0].rx_pollstate == BX_SER_RXIDLE &&
+ BX_SER_THIS s[0].baudrate != 0) {
+ BX_SER_THIS s[0].rx_pollstate = BX_SER_RXPOLL;
+ bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index,
+ (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+ (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+ 0); /* not continuous */
+ }
+ BX_DEBUG(("baud rate set - %d", BX_SER_THIS s[0].baudrate));
+ }
+ BX_SER_THIS s[0].line_cntl.dlab = (value & 0x80) >> 7;
+ break;
+
+ case 0x03FC: /* MODEM control register */
+ if ((value & 0x01) == 0) {
+#if USE_RAW_SERIAL
+ BX_SER_THIS raw->send_hangup();
+#endif
+ }
+
+ BX_SER_THIS s[0].modem_cntl.dtr = value & 0x01;
+ BX_SER_THIS s[0].modem_cntl.rts = (value & 0x02) >> 1;
+ BX_SER_THIS s[0].modem_cntl.out1 = (value & 0x04) >> 2;
+ BX_SER_THIS s[0].modem_cntl.out2 = (value & 0x08) >> 3;
+ BX_SER_THIS s[0].modem_cntl.local_loopback = (value & 0x10) >> 4;
+
+ if (BX_SER_THIS s[0].modem_cntl.local_loopback) {
+ prev_cts = BX_SER_THIS s[0].modem_status.cts;
+ prev_dsr = BX_SER_THIS s[0].modem_status.dsr;
+ prev_ri = BX_SER_THIS s[0].modem_status.ri;
+ prev_dcd = BX_SER_THIS s[0].modem_status.dcd;
+ BX_SER_THIS s[0].modem_status.cts = BX_SER_THIS s[0].modem_cntl.rts;
+ BX_SER_THIS s[0].modem_status.dsr = BX_SER_THIS s[0].modem_cntl.dtr;
+ BX_SER_THIS s[0].modem_status.ri = BX_SER_THIS s[0].modem_cntl.out1;
+ BX_SER_THIS s[0].modem_status.dcd = BX_SER_THIS s[0].modem_cntl.out2;
+ if (BX_SER_THIS s[0].modem_status.cts != prev_cts) {
+ BX_SER_THIS s[0].modem_status.delta_cts = 1;
+ BX_SER_THIS s[0].ms_ipending = 1;
+ }
+ if (BX_SER_THIS s[0].modem_status.dsr != prev_dsr) {
+ BX_SER_THIS s[0].modem_status.delta_dsr = 1;
+ BX_SER_THIS s[0].ms_ipending = 1;
+ }
+ if (BX_SER_THIS s[0].modem_status.ri != prev_ri)
+ BX_SER_THIS s[0].ms_ipending = 1;
+ if ((BX_SER_THIS s[0].modem_status.ri == 0) && (prev_ri == 1))
+ BX_SER_THIS s[0].modem_status.ri_trailedge = 1;
+ if (BX_SER_THIS s[0].modem_status.dcd != prev_dcd) {
+ BX_SER_THIS s[0].modem_status.delta_dcd = 1;
+ BX_SER_THIS s[0].ms_ipending = 1;
+ }
+ raise_interrupt(0, BX_SER_INT_MODSTAT);
+ } else {
+ /* set these to 0 for the time being */
+ BX_SER_THIS s[0].modem_status.cts = 0;
+ BX_SER_THIS s[0].modem_status.dsr = 0;
+ BX_SER_THIS s[0].modem_status.ri = 0;
+ BX_SER_THIS s[0].modem_status.dcd = 0;
+ }
+ break;
+
+ case 0x03FD: /* Line status register */
+ BX_ERROR(("write to line status register ignored"));
+ break;
+
+ case 0x03FE: /* MODEM status register */
+ BX_ERROR(("write to MODEM status register ignored"));
+ break;
+
+ case 0x03FF: /* scratch register */
+ BX_SER_THIS s[0].scratch = value;
+ break;
+
+ default:
+ BX_PANIC(("unsupported io write to address=0x%04x, value = 0x%02x!",
+ (unsigned) address, (unsigned) value));
+ break;
+ }
+}
+
+
+void
+bx_serial_c::rx_fifo_enq(Bit8u port, Bit8u data)
+{
+ bx_bool gen_int = 0;
+
+ if (BX_SER_THIS s[port].fifo_cntl.enable) {
+ if (BX_SER_THIS s[port].rx_fifo_end == 16) {
+ BX_ERROR(("com%d: receive FIFO overflow", port + 1));
+ BX_SER_THIS s[port].line_status.overrun_error = 1;
+ raise_interrupt(port, BX_SER_INT_RXLSTAT);
+ } else {
+ BX_SER_THIS s[port].rx_fifo[BX_SER_THIS s[0].rx_fifo_end++] = data;
+ switch (BX_SER_THIS s[port].fifo_cntl.rxtrigger) {
+ case 1:
+ if (BX_SER_THIS s[0].rx_fifo_end == 4) gen_int = 1;
+ break;
+ case 2:
+ if (BX_SER_THIS s[0].rx_fifo_end == 8) gen_int = 1;
+ break;
+ case 3:
+ if (BX_SER_THIS s[0].rx_fifo_end == 14) gen_int = 1;
+ break;
+ default:
+ gen_int = 1;
+ }
+ if (gen_int) {
+ bx_pc_system.deactivate_timer(BX_SER_THIS s[0].fifo_timer_index);
+ BX_SER_THIS s[port].line_status.rxdata_ready = 1;
+ raise_interrupt(port, BX_SER_INT_RXDATA);
+ } else {
+ bx_pc_system.activate_timer(BX_SER_THIS s[0].fifo_timer_index,
+ (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+ (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5) * 16),
+ 0); /* not continuous */
+ }
+ }
+ } else {
+ if (BX_SER_THIS s[port].line_status.rxdata_ready == 1) {
+ BX_ERROR(("com%d: overrun error", port + 1));
+ BX_SER_THIS s[port].line_status.overrun_error = 1;
+ raise_interrupt(port, BX_SER_INT_RXLSTAT);
+ }
+ BX_SER_THIS s[port].rxbuffer = data;
+ BX_SER_THIS s[port].line_status.rxdata_ready = 1;
+ raise_interrupt(port, BX_SER_INT_RXDATA);
+ }
+}
+
+
+void
+bx_serial_c::tx_timer_handler(void *this_ptr)
+{
+ bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+ class_ptr->tx_timer();
+}
+
+
+void
+bx_serial_c::tx_timer(void)
+{
+ bx_bool gen_int = 0;
+
+ if (BX_SER_THIS s[0].modem_cntl.local_loopback) {
+ rx_fifo_enq(0, BX_SER_THIS s[0].tsrbuffer);
+ } else {
+#if USE_RAW_SERIAL
+ if (!BX_SER_THIS raw->ready_transmit())
+ BX_PANIC(("Not ready to transmit"));
+ BX_SER_THIS raw->transmit(BX_SER_THIS s[0].tsrbuffer);
+#endif
+#if defined(SERIAL_ENABLE)
+ BX_DEBUG(("write: '%c'", BX_SER_THIS s[0].tsrbuffer));
+ if (tty_id >= 0) write(tty_id, (bx_ptr_t) & BX_SER_THIS s[0].tsrbuffer, 1);
+#endif
+ }
+
+ BX_SER_THIS s[0].line_status.tsr_empty = 1;
+ if (BX_SER_THIS s[0].fifo_cntl.enable && (BX_SER_THIS s[0].tx_fifo_end > 0)) {
+ BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].tx_fifo[0];
+ BX_SER_THIS s[0].line_status.tsr_empty = 0;
+ memcpy(&BX_SER_THIS s[0].tx_fifo[0], &BX_SER_THIS s[0].tx_fifo[1], 15);
+ gen_int = (--BX_SER_THIS s[0].tx_fifo_end == 0);
+ } else if (!BX_SER_THIS s[0].line_status.thr_empty) {
+ BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].thrbuffer;
+ BX_SER_THIS s[0].line_status.tsr_empty = 0;
+ gen_int = 1;
+ }
+ if (!BX_SER_THIS s[0].line_status.tsr_empty) {
+ if (gen_int) {
+ BX_SER_THIS s[0].line_status.thr_empty = 1;
+ raise_interrupt(0, BX_SER_INT_TXHOLD);
+ }
+ bx_pc_system.activate_timer(BX_SER_THIS s[0].tx_timer_index,
+ (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+ (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+ 0); /* not continuous */
+ }
+}
+
+
+void
+bx_serial_c::rx_timer_handler(void *this_ptr)
+{
+ bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+ class_ptr->rx_timer();
+}
+
+
+void
+bx_serial_c::rx_timer(void)
+{
+#if BX_HAVE_SELECT
+#ifndef __BEOS__
+ struct timeval tval;
+ fd_set fds;
+#endif
+#endif
+ int bdrate = BX_SER_THIS s[0].baudrate / (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5);
+ unsigned char chbuf = 0;
+
+#if BX_HAVE_SELECT
+#ifndef __BEOS__
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+
+// MacOS: I'm not sure what to do with this, since I don't know
+// what an fd_set is or what FD_SET() or select() do. They aren't
+// declared in the CodeWarrior standard library headers. I'm just
+// leaving it commented out for the moment.
+
+ FD_ZERO(&fds);
+ if (tty_id >= 0) FD_SET(tty_id, &fds);
+
+ if ((BX_SER_THIS s[0].line_status.rxdata_ready == 0) ||
+ (BX_SER_THIS s[0].fifo_cntl.enable)) {
+#if USE_RAW_SERIAL
+ bx_bool rdy;
+ uint16 data;
+ if ((rdy = BX_SER_THIS raw->ready_receive())) {
+ data = BX_SER_THIS raw->receive();
+ if (data == C_BREAK) {
+ BX_DEBUG(("got BREAK"));
+ BX_SER_THIS s[0].line_status.break_int = 1;
+ rdy = 0;
+ }
+ }
+ if (rdy) {
+ chbuf = data;
+#elif defined(SERIAL_ENABLE)
+ if ((tty_id >= 0) && (select(tty_id + 1, &fds, NULL, NULL, &tval) == 1)) {
+ (void) read(tty_id, &chbuf, 1);
+ BX_DEBUG(("read: '%c'",chbuf));
+#else
+ if (0) {
+#endif
+ if (!BX_SER_THIS s[0].modem_cntl.local_loopback) {
+ rx_fifo_enq(0, chbuf);
+ }
+ } else {
+ if (!BX_SER_THIS s[0].fifo_cntl.enable) {
+ bdrate = (int) (1000000.0 / 100000); // Poll frequency is 100ms
+ }
+ }
+ } else {
+ // Poll at 4x baud rate to see if the next-char can
+ // be read
+ bdrate *= 4;
+ }
+#endif
+#endif
+
+ bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index,
+ (int) (1000000.0 / bdrate),
+ 0); /* not continuous */
+}
+
+
+void
+bx_serial_c::fifo_timer_handler(void *this_ptr)
+{
+ bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+ class_ptr->fifo_timer();
+}
+
+
+void
+bx_serial_c::fifo_timer(void)
+{
+ BX_SER_THIS s[0].line_status.rxdata_ready = 1;
+ raise_interrupt(0, BX_SER_INT_FIFO);
+}
diff --git a/tools/ioemu/iodev/serial.h b/tools/ioemu/iodev/serial.h
new file mode 100644
index 0000000000..00f01c976e
--- /dev/null
+++ b/tools/ioemu/iodev/serial.h
@@ -0,0 +1,193 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial.h,v 1.15 2003/11/16 08:21:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// Peter Grehan (grehan@iprg.nokia.com) coded most of this
+// serial emulation.
+
+#if USE_RAW_SERIAL
+#include "serial_raw.h"
+#endif // USE_RAW_SERIAL
+
+#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
+
+#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
+
+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
+};
+
+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;
+
+ /*
+ * 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(void);
+ ~bx_serial_c(void);
+ virtual void init(void);
+ virtual void reset(unsigned type);
+#if USE_RAW_SERIAL
+ serial_raw* raw;
+#endif // USE_RAW_SERIAL
+
+private:
+ bx_serial_t s[BX_SERIAL_MAXDEV];
+
+ 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 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
+ };
+
diff --git a/tools/ioemu/iodev/serial_raw.h b/tools/ioemu/iodev/serial_raw.h
new file mode 100644
index 0000000000..978c28d29b
--- /dev/null
+++ b/tools/ioemu/iodev/serial_raw.h
@@ -0,0 +1,23 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial_raw.h,v 1.2 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include <linux/serial.h>
+
+#define P_EVEN 0
+#define P_ODD 1
+#define C_BREAK 201
+
+class serial_raw : public logfunctions {
+ public:
+ serial_raw (char *ttypath, int signal);
+ void set_baudrate (int rate);
+ void set_data_bits (int );
+ void set_stop_bits (int);
+ void set_parity_mode (int, int);
+ void transmit (int byte);
+ void send_hangup ();
+ int ready_transmit ();
+ int ready_receive ();
+ int receive ();
+};
diff --git a/tools/ioemu/iodev/slowdown_timer.cc b/tools/ioemu/iodev/slowdown_timer.cc
new file mode 100644
index 0000000000..76d8613ec8
--- /dev/null
+++ b/tools/ioemu/iodev/slowdown_timer.cc
@@ -0,0 +1,182 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: slowdown_timer.cc,v 1.17.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#include "bochs.h"
+#include <errno.h>
+
+//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)
+
+#if BX_HAVE_USLEEP
+# define Qval 1000
+#else
+# define Qval SECINUSEC
+#endif
+
+#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("STIMER");
+ settype(STIMERLOG);
+
+
+ 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 ( (bx_options.clock.Osync->get () != BX_CLOCK_SYNC_SLOWDOWN)
+ && (bx_options.clock.Osync->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::reset(unsigned type)
+{
+}
+
+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,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(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
+}
+
diff --git a/tools/ioemu/iodev/slowdown_timer.h b/tools/ioemu/iodev/slowdown_timer.h
new file mode 100644
index 0000000000..3b6b153a71
--- /dev/null
+++ b/tools/ioemu/iodev/slowdown_timer.h
@@ -0,0 +1,33 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: slowdown_timer.h,v 1.8 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+
+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; // (Q (in seconds))
+ } s;
+
+public:
+ bx_slowdown_timer_c();
+
+ void init(void);
+ void reset(unsigned type);
+
+ static void timer_handler(void * this_ptr);
+
+ void handle_timer();
+
+};
+
+extern bx_slowdown_timer_c bx_slowdown_timer;
+
diff --git a/tools/ioemu/iodev/soundlnx.cc b/tools/ioemu/iodev/soundlnx.cc
new file mode 100644
index 0000000000..773addc311
--- /dev/null
+++ b/tools/ioemu/iodev/soundlnx.cc
@@ -0,0 +1,227 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundlnx.cc,v 1.6 2002/12/24 10:12:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// This file (SOUNDLNX.CC) written and donated by Josef Drexler
+
+
+#include "bochs.h"
+#if (defined(linux) || defined(__FreeBSD__)) && BX_SUPPORT_SB16
+#define LOG_THIS bx_sb16.
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+bx_sound_linux_c::bx_sound_linux_c(bx_sb16_c *sb16)
+ :bx_sound_output_c(sb16)
+{
+ this->sb16 = sb16;
+ midi = NULL;
+ wavedevice = NULL;
+ wave = -1;
+}
+
+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;
+}
+
+int bx_sound_linux_c::openmidioutput(char *device)
+{
+ if ( (device == NULL) || (strlen(device) < 1) )
+ return BX_SOUND_OUTPUT_ERR;
+
+ midi = fopen(device,"w");
+
+ if (midi == NULL)
+ {
+ WRITELOG( MIDILOG(2), "Couldn't open midi output device %s: %s.",
+ device, strerror(errno));
+ return BX_SOUND_OUTPUT_ERR;
+ }
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+
+int bx_sound_linux_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
+{
+ UNUSED(delta);
+ // BX_PANIC(("Sendmidicommand!!");
+
+ 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()
+{
+ fclose(midi);
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+
+int bx_sound_linux_c::openwaveoutput(char *device)
+{
+ int length = strlen(device) + 1;
+
+ if (wavedevice != NULL)
+ delete(wavedevice);
+
+ wavedevice = new char[length];
+
+ if (wavedevice == NULL)
+ return BX_SOUND_OUTPUT_ERR;
+
+ strncpy(wavedevice, device, length);
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::startwaveplayback(int frequency, int bits, int stereo, int format)
+{
+ int fmt, ret;
+ int signeddata = format & 1;
+
+ if ( (wavedevice == NULL) || (strlen(wavedevice) < 1) )
+ return BX_SOUND_OUTPUT_ERR;
+
+ if (wave == -1)
+ wave = open(wavedevice, O_WRONLY);
+ 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 (wave == -1)
+ return BX_SOUND_OUTPUT_ERR;
+
+ 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)
+ WRITELOG( WAVELOG(4), "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
+ {
+ WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_SETFMT, %d): %s",
+ fmt, strerror(errno));
+ return BX_SOUND_OUTPUT_ERR;
+ }
+
+ ret = ioctl(wave, SNDCTL_DSP_STEREO, &stereo);
+ if (ret != 0)
+ WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_STEREO, %d): %s",
+ stereo, strerror(errno));
+
+ ret = ioctl(wave, SNDCTL_DSP_SPEED, &frequency);
+ if (ret != 0)
+ WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_SPEED, %d): %s",
+ frequency, strerror(errno));
+
+ // ioctl(wave, SNDCTL_DSP_GETBLKSIZE, &fragment);
+ // WRITELOG( WAVELOG(4), "current output block size is %d", fragment);
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::sendwavepacket(int length, Bit8u data[])
+{
+ int ret;
+
+ ret = write(wave, data, length);
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::stopwaveplayback()
+{
+ // ioctl(wave, SNDCTL_DSP_SYNC);
+ // close(wave);
+ // wave = -1;
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::closewaveoutput()
+{
+ if (wavedevice != NULL)
+ delete(wavedevice);
+
+ if (wave != -1)
+ {
+ close(wave);
+ wave = -1;
+ }
+
+ wavedevice = NULL;
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+#endif // defined(linux)
diff --git a/tools/ioemu/iodev/soundlnx.h b/tools/ioemu/iodev/soundlnx.h
new file mode 100644
index 0000000000..8f718b5acd
--- /dev/null
+++ b/tools/ioemu/iodev/soundlnx.h
@@ -0,0 +1,69 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundlnx.h,v 1.5 2002/12/24 10:12:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// This file (SOUNDLNX.H) written and donated by Josef Drexler
+
+
+#if (defined(linux) || defined(__FreeBSD__))
+
+#include "bochs.h"
+
+#define BX_SOUND_LINUX_BUFSIZE BX_SOUND_OUTPUT_WAVEPACKETSIZE
+
+class bx_sound_linux_c : public bx_sound_output_c {
+public:
+ bx_sound_linux_c(bx_sb16_c *sb16);
+ BX_SOUND_VIRTUAL ~bx_sound_linux_c();
+
+ // if virtual functions are used, we have to override them
+ // and define our own. Otherwise this file will just implement
+ // the original functions
+#ifdef BX_USE_SOUND_VIRTUAL
+ BX_SOUND_VIRTUAL int waveready();
+ BX_SOUND_VIRTUAL int midiready();
+
+ BX_SOUND_VIRTUAL int openmidioutput(char *device);
+ BX_SOUND_VIRTUAL int sendmidicommand(int delta, int command, int length, Bit8u data[]);
+ BX_SOUND_VIRTUAL int closemidioutput();
+
+ BX_SOUND_VIRTUAL int openwaveoutput(char *device);
+ BX_SOUND_VIRTUAL int startwaveplayback(int frequency, int bits, int stereo, int format);
+ BX_SOUND_VIRTUAL int sendwavepacket(int length, Bit8u data[]);
+ BX_SOUND_VIRTUAL int stopwaveplayback();
+ BX_SOUND_VIRTUAL int closewaveoutput();
+#endif
+
+private:
+ bx_sb16_c *sb16;
+ FILE *midi;
+ char *wavedevice;
+ int wave;
+ int bufferpos;
+ Bit8u audio_buffer[BX_SOUND_LINUX_BUFSIZE];
+ int oldfreq,oldbits,oldstereo,oldformat;
+};
+
+#endif // defined(linux)
diff --git a/tools/ioemu/iodev/soundwin.cc b/tools/ioemu/iodev/soundwin.cc
new file mode 100644
index 0000000000..b8b386cae4
--- /dev/null
+++ b/tools/ioemu/iodev/soundwin.cc
@@ -0,0 +1,521 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundwin.cc,v 1.13 2003/04/05 08:26:49 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// 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 "bochs.h"
+#if defined(WIN32) && BX_SUPPORT_SB16
+
+#define LOG_THIS bx_devices.pluginSB16Device->
+
+bx_sound_windows_c::bx_sound_windows_c(bx_sb16_c *sb16)
+ :bx_sound_output_c(sb16)
+{
+ this->sb16 = sb16;
+
+ 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)
+
+ int 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);
+ }
+
+ if (offset > size)
+ BX_PANIC(("Allocated memory was too small!"));
+
+#undef size
+#undef ALIGN
+#undef NEWBUFFER
+}
+
+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(char *device)
+{
+ // could make the output device selectable,
+ // but currently only the midi mapper is supported
+ UNUSED(device);
+
+ UINT deviceid = (UINT) MIDIMAPPER;
+
+ MidiOpen = 0;
+
+ UINT ret = midiOutOpen( &MidiOut, deviceid, 0, 0, CALLBACK_NULL);
+ if (ret == 0)
+ MidiOpen = 1;
+
+ WRITELOG( MIDILOG(4), "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) )
+ {
+ WRITELOG( WAVELOG(5), "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)
+ WRITELOG( MIDILOG(2), "midiOutPrepareHeader() = %d", ret);
+ ret = midiOutLongMsg(MidiOut, MidiHeader, sizeof(*MidiHeader));
+ if (ret != 0)
+ WRITELOG( MIDILOG(2), "midiOutLongMsg() = %d", ret);
+ }
+ else
+ {
+ DWORD msg = command;
+
+ for (int i = 0; i<length; i++)
+ msg |= (data[i] << (8 * (i + 1) ) );
+
+ ret = midiOutShortMsg(MidiOut, msg);
+ WRITELOG( MIDILOG(4), "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);
+ WRITELOG( MIDILOG(4), "midiOutClose() = %d", ret);
+ MidiOpen = 0;
+
+ return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
+}
+
+int bx_sound_windows_c::openwaveoutput(char *device)
+{
+ // could make the output device selectable,
+ // but currently only the midi mapper is supported
+ UNUSED(device);
+
+ WRITELOG( WAVELOG(4), "openwaveoutput(%s)", device);
+
+#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);
+ WRITELOG( WAVELOG(5), "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;
+
+ WRITELOG( WAVELOG(4), "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;
+
+ WRITELOG( WAVELOG(4), "Couldn't open wave device again (error %d), trying 11KHz, mono, 8bit", ret);
+
+ break;
+ case 2: // nope, doesn't work
+
+ WRITELOG( WAVELOG(2), "Couldn't open wave device (error %d)!", ret);
+
+ return BX_SOUND_OUTPUT_ERR;
+ }
+ WRITELOG( WAVELOG(5), "The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,",
+ waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec);
+ WRITELOG( WAVELOG(5), " 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)
+ {
+ WRITELOG( WAVELOG(5), "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)
+ {
+ WRITELOG( WAVELOG(2), "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);
+ WRITELOG( WAVELOG(5), "waveOutWrite: %s", errormsg);
+ }
+ }
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::startwaveplayback(int frequency, int bits, int stereo, int format)
+{
+ // UINT ret;
+
+ WRITELOG( WAVELOG(4), "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;
+
+ 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[])
+{
+// UINT ret;
+ int bufnum;
+
+ WRITELOG( WAVELOG(4), "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!
+ WRITELOG( WAVELOG(2), "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 )
+ {
+ WRITELOG( WAVELOG(5), "Buffer status: Head %d, TailFull %d, TailPlay %d. Stall.",
+ head, tailfull, tailplay);
+ iswaveready = 0;
+ }
+
+ playnextbuffer();
+
+#endif
+
+#ifdef usesndPlaySnd
+ LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData;
+
+ header->length = length + 36;
+ header->chnk2len = length;
+
+ memcpy( &(header->data), data, length);
+
+ FILE *test = fopen("test", "a");
+ fwrite(WaveData, 1, length + 44, test);
+ fclose(test);
+
+ ret = sndPlaySoundA( (LPCSTR) header, SND_SYNC | SND_MEMORY );
+ if (ret != 0)
+ {
+ WRITELOG( WAVELOG(3), "sndPlaySoundA: %d", ret);
+ }
+#endif
+
+ return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::stopwaveplayback()
+{
+ WRITELOG( WAVELOG(4), "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()
+{
+// int bufnum;
+
+ WRITELOG( WAVELOG(4), "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 & WHDR_DONE) != 0)
+ {
+ WRITELOG( MIDILOG(5), "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)
+ {
+ WRITELOG( WAVELOG(5), "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 )
+ {
+ WRITELOG( WAVELOG(5), "Buffer status: Head %d, TailFull %d, TailPlay %d. Ready.",
+ head, tailfull, tailplay);
+ iswaveready = 1;
+ }
+}
+
+#endif // defined(WIN32)
diff --git a/tools/ioemu/iodev/soundwin.h b/tools/ioemu/iodev/soundwin.h
new file mode 100644
index 0000000000..122fa554e9
--- /dev/null
+++ b/tools/ioemu/iodev/soundwin.h
@@ -0,0 +1,229 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundwin.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+// This file (SOUNDWIN.H) written and donated by Josef Drexler
+
+
+#if defined(WIN32)
+
+#include "bochs.h"
+#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 4 // 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);
+}
+
+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(0)
+
+#endif // MMSYSERR_NOERROR defined
+
+class bx_sound_windows_c : public bx_sound_output_c {
+public:
+ bx_sound_windows_c(bx_sb16_c *sb16);
+ BX_SOUND_VIRTUAL ~bx_sound_windows_c();
+
+ // if virtual functions are used, we have to override them
+ // and define our own. Otherwise this file will just implement
+ // the original functions
+#ifdef BX_USE_SOUND_VIRTUAL
+ BX_SOUND_VIRTUAL int waveready();
+ BX_SOUND_VIRTUAL int midiready();
+
+ BX_SOUND_VIRTUAL int openmidioutput(char *device);
+ BX_SOUND_VIRTUAL int sendmidicommand(int delta, int command, int length, Bit8u data[]);
+ BX_SOUND_VIRTUAL int closemidioutput();
+
+ BX_SOUND_VIRTUAL int openwaveoutput(char *device);
+ BX_SOUND_VIRTUAL int startwaveplayback(int frequency, int bits, int stereo, int format);
+ BX_SOUND_VIRTUAL int sendwavepacket(int length, Bit8u data[]);
+ BX_SOUND_VIRTUAL int stopwaveplayback();
+ BX_SOUND_VIRTUAL int closewaveoutput();
+#endif
+
+private:
+ bx_sb16_c *sb16;
+
+ 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)
diff --git a/tools/ioemu/iodev/state_file.cc b/tools/ioemu/iodev/state_file.cc
new file mode 100644
index 0000000000..f7d0d0feef
--- /dev/null
+++ b/tools/ioemu/iodev/state_file.cc
@@ -0,0 +1,136 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: state_file.cc,v 1.9 2001/12/21 19:33:18 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// Classes for helping to make checkpoints of the emulator state.
+
+
+
+#include "bochs.h"
+#define LOG_THIS log->
+
+
+
+FILE *state_file::get_handle()
+{
+ BX_INFO(("state_file::get_handle()"));
+ return NULL;
+}
+
+void state_file::write(Bit8u)
+{
+ BX_PANIC(("state_file::write(Bit8u)"));
+}
+
+void state_file::write(Bit16u)
+{
+ BX_PANIC(("state_file::write(Bit16u)"));
+}
+
+void state_file::write(Bit32u)
+{
+ BX_PANIC(("state_file::write(Bit32u)"));
+}
+
+void state_file::write(Bit64u)
+{
+ BX_PANIC(("state_file::write(Bit64u)"));
+}
+
+void state_file::write(const void *, size_t)
+{
+ BX_PANIC(("state_file::write(const void *, size_t)"));
+}
+
+void state_file::read(Bit8u &)
+{
+ BX_PANIC(("state_file::read(uint8 &)"));
+}
+
+void state_file::read(Bit16u &)
+{
+ BX_PANIC(("state_file::read(uint16 &)"));
+}
+
+void state_file::read(Bit32u &)
+{
+ BX_PANIC(("state_file::read(uint32 &)"));
+}
+
+void state_file::read(Bit64u &)
+{
+ BX_PANIC(("state_file::read(uint64 &)"));
+}
+
+void state_file::read(void *, size_t)
+{
+ BX_PANIC(("state_file::read(void *, size_t)"));
+}
+
+void state_file::write_check(const char *)
+{
+ BX_PANIC(("state_file::write_check()"));
+}
+
+void state_file::read_check (const char *)
+{
+ BX_PANIC(("state_file::read_check()"));
+}
+
+void
+state_file::init(void)
+{
+ log = new class logfunctions();
+ log->put("STAT");
+ log->settype(GENLOG);
+}
+
+
+state_file::state_file (const char *name, const char *options)
+{
+ UNUSED(name);
+ UNUSED(options);
+ init();
+ BX_DEBUG(( "Init(const char *, const char *)." ));
+}
+
+state_file::state_file (FILE *f)
+{
+ UNUSED(f);
+ init();
+ BX_INFO(("Init(FILE *)."));
+}
+
+state_file::~state_file()
+{
+ BX_DEBUG(("Exit."));
+ if ( log != NULL )
+ {
+ delete log;
+ log = NULL;
+ }
+}
diff --git a/tools/ioemu/iodev/unmapped.cc b/tools/ioemu/iodev/unmapped.cc
new file mode 100644
index 0000000000..5c7aafedb1
--- /dev/null
+++ b/tools/ioemu/iodev/unmapped.cc
@@ -0,0 +1,305 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: unmapped.cc,v 1.22 2003/08/10 17:19:49 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+// 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"
+
+#define LOG_THIS theUnmappedDevice->
+
+
+bx_unmapped_c *theUnmappedDevice = NULL;
+
+ int
+libunmapped_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theUnmappedDevice = new bx_unmapped_c ();
+ bx_devices.pluginUnmapped = theUnmappedDevice;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUnmappedDevice, BX_PLUGIN_UNMAPPED);
+ return(0); // Success
+}
+
+ void
+libunmapped_LTX_plugin_fini(void)
+{
+}
+
+bx_unmapped_c::bx_unmapped_c(void)
+{
+ put("UNMP");
+ settype(UNMAPLOG);
+ s.port80 = 0x00;
+ s.port8e = 0x00;
+ s.shutdown = 0;
+}
+
+bx_unmapped_c::~bx_unmapped_c(void)
+{
+ // Nothing yet
+}
+
+ void
+bx_unmapped_c::init(void)
+{
+ DEV_register_default_ioread_handler(this, read_handler, "Unmapped", 7);
+ DEV_register_default_iowrite_handler(this, write_handler, "Unmapped", 7);
+}
+
+ void
+bx_unmapped_c::reset(unsigned type)
+{
+}
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_unmapped_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+ bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+ Bit32u
+bx_unmapped_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_UM_SMF
+ UNUSED(io_len);
+
+ Bit32u retval;
+
+ // This function gets called for access to any IO ports which
+ // are not mapped to any device handler. Reads return 0
+
+ if (address >= 0x02e0 && address <= 0x02ef) {
+ retval = 0;
+ goto return_from_read;
+ }
+
+ switch (address) {
+ case 0x80:
+ retval = BX_UM_THIS s.port80;
+ break;
+ case 0x8e:
+ retval = BX_UM_THIS s.port8e;
+ break;
+#if BX_PORT_E9_HACK
+ // Unused port on ISA - this can be used by the emulated code
+ // to detect it is running inside Bochs and that the debugging
+ // features are available (write 0xFF or something on unused
+ // port 0x80, then read from 0xe9, if value is 0xe9, debug
+ // output is available) (see write() for that) -- Andreas and Emmanuel
+ case 0xe9:
+ retval = 0xe9;
+ break;
+#endif
+ case 0x03df:
+ retval = 0xffffffff;
+ BX_DEBUG(("unsupported IO read from port %04x (CGA)", address));
+ break;
+ case 0x023a:
+ case 0x02f8: /* UART */
+ case 0x02f9: /* UART */
+ case 0x02fb: /* UART */
+ case 0x02fc: /* UART */
+ case 0x02fd: /* UART */
+ case 0x02ea:
+ case 0x02eb:
+ case 0x03e8:
+ case 0x03e9:
+ case 0x03ea:
+ case 0x03eb:
+ case 0x03ec:
+ case 0x03ed:
+ case 0x03f8: /* UART */
+ case 0x03f9: /* UART */
+ case 0x03fb: /* UART */
+ case 0x03fc: /* UART */
+ case 0x03fd: /* UART */
+ case 0x17c6:
+ retval = 0xffffffff;
+ BX_DEBUG(("unsupported IO read from port %04x", address));
+ break;
+ default:
+ retval = 0xffffffff;
+ }
+
+ return_from_read:
+ if (bx_dbg.unsupported_io)
+ switch (io_len) {
+ case 1:
+ retval = (Bit8u)retval;
+ BX_DEBUG(("unmapped: 8-bit read from %04x = %02x", address, retval));
+ break;
+ case 2:
+ retval = (Bit16u)retval;
+ BX_DEBUG(("unmapped: 16-bit read from %04x = %04x", address, retval));
+ break;
+ case 4:
+ BX_DEBUG(("unmapped: 32-bit read from %04x = %08x", address, retval));
+ break;
+ default:
+ BX_DEBUG(("unmapped: %d-bit read from %04x = %x", io_len * 8, address, retval));
+ }
+ return retval;
+}
+
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_unmapped_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+ bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len);
+}
+
+ void
+bx_unmapped_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_UM_SMF
+ UNUSED(io_len);
+
+
+ // This function gets called for access to any IO ports which
+ // are not mapped to any device handler. Writes to an unmapped
+ // IO port are ignored.
+
+// ???
+
+ if (address >= 0x02e0 && address <= 0x02ef)
+ goto return_from_write;
+
+ switch (address) {
+ case 0x80: // diagnostic test port to display progress of POST
+ //BX_DEBUG(("Diagnostic port 80h: write = %02xh", (unsigned) value));
+ BX_UM_THIS s.port80 = value;
+ break;
+
+ case 0x8e: // ???
+ BX_UM_THIS s.port8e = value;
+ break;
+
+#if BX_PORT_E9_HACK
+ // This port doesn't exist on normal ISA architecture. However,
+ // we define a convention here, to display on the console of the
+ // system running Bochs, anything that is written to it. The
+ // idea is to provide debug output very early when writing
+ // BIOS or OS code for example, without having to bother with
+ // properly setting up a serial port or anything.
+ //
+ // Idea by Andreas Beck (andreas.beck@ggi-project.org)
+
+ case 0xe9:
+ putchar(value);
+ fflush(stdout);
+ break;
+#endif
+
+ case 0xed: // Dummy port used as I/O delay
+ break;
+ case 0xee: // ???
+ break;
+
+ case 0x2f2:
+ case 0x2f3:
+ case 0x2f4:
+ case 0x2f5:
+ case 0x2f6:
+ case 0x2f7:
+ case 0x3e8:
+ case 0x3e9:
+ case 0x3eb:
+ case 0x3ec:
+ case 0x3ed:
+ // BX_DEBUG(("unsupported IO write to port %04x of %02x",
+ // address, value));
+ break;
+
+ case 0x8900: // Shutdown port, could be moved in a PM device
+ // or a host <-> guest communication device
+ switch (value) {
+ case 'S': if (BX_UM_THIS s.shutdown == 0) BX_UM_THIS s.shutdown = 1; break;
+ case 'h': if (BX_UM_THIS s.shutdown == 1) BX_UM_THIS s.shutdown = 2; break;
+ case 'u': if (BX_UM_THIS s.shutdown == 2) BX_UM_THIS s.shutdown = 3; break;
+ case 't': if (BX_UM_THIS s.shutdown == 3) BX_UM_THIS s.shutdown = 4; break;
+ case 'd': if (BX_UM_THIS s.shutdown == 4) BX_UM_THIS s.shutdown = 5; break;
+ case 'o': if (BX_UM_THIS s.shutdown == 5) BX_UM_THIS s.shutdown = 6; break;
+ case 'w': if (BX_UM_THIS s.shutdown == 6) BX_UM_THIS s.shutdown = 7; break;
+ case 'n': if (BX_UM_THIS s.shutdown == 7) BX_UM_THIS s.shutdown = 8; break;
+#if BX_DEBUGGER
+ // Very handy for debugging:
+ // output 'D' to port 8900, and bochs quits to debugger
+ case 'D': bx_debug_break (); break;
+#endif
+ default : BX_UM_THIS s.shutdown = 0; break;
+ }
+ if (BX_UM_THIS s.shutdown == 8) {
+ bx_user_quit = 1;
+ LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+ BX_PANIC(("Shutdown port: shutdown requested"));
+ }
+ break;
+
+ case 0xfedc:
+ bx_dbg.debugger = (value > 0);
+ BX_DEBUG(( "DEBUGGER = %u", (unsigned) bx_dbg.debugger));
+ break;
+
+ default:
+ break;
+ }
+ return_from_write:
+ if (bx_dbg.unsupported_io)
+ switch (io_len) {
+ case 1:
+ BX_INFO(("unmapped: 8-bit write to %04x = %02x", address, value));
+ break;
+ case 2:
+ BX_INFO(("unmapped: 16-bit write to %04x = %04x", address, value));
+ break;
+ case 4:
+ BX_INFO(("unmapped: 32-bit write to %04x = %08x", address, value));
+ break;
+ default:
+ BX_INFO(("unmapped: %d-bit write to %04x = %x", io_len * 8, address, value));
+ break;
+ }
+}
diff --git a/tools/ioemu/iodev/unmapped.h b/tools/ioemu/iodev/unmapped.h
new file mode 100644
index 0000000000..c9ef1dc068
--- /dev/null
+++ b/tools/ioemu/iodev/unmapped.h
@@ -0,0 +1,64 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: unmapped.h,v 1.10 2002/10/24 21:07:52 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+#if BX_USE_UM_SMF
+# define BX_UM_SMF static
+# define BX_UM_THIS theUnmappedDevice->
+#else
+# define BX_UM_SMF
+# define BX_UM_THIS this->
+#endif
+
+
+
+class bx_unmapped_c : public bx_devmodel_c {
+public:
+ bx_unmapped_c(void);
+ ~bx_unmapped_c(void);
+
+ virtual void init(void);
+ virtual void reset (unsigned type);
+
+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_UM_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+
+ struct {
+ Bit8u port80;
+ Bit8u port8e;
+ Bit8u shutdown;
+ } s; // state information
+
+ };
diff --git a/tools/ioemu/iodev/vga.cc b/tools/ioemu/iodev/vga.cc
new file mode 100644
index 0000000000..894f80bbb6
--- /dev/null
+++ b/tools/ioemu/iodev/vga.cc
@@ -0,0 +1,3116 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.cc,v 1.94.2.1 2004/02/02 22:37:48 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+// 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"
+
+#define LOG_THIS theVga->
+
+/* NOTES:
+ * I take it data rotate is a true rotate with carry of bit 0 to bit 7.
+ * support map mask (3c5 reg 02)
+ */
+
+/* Notes from cb
+ *
+ * It seems that the vga card should support multi bytes IO reads and write
+ * From my tests, inw(port) return port+1 * 256 + port, except for port 0x3c9
+ * (PEL data register, data cycling). More reverse engineering is needed.
+ * This would fix the gentoo bug.
+ */
+
+// (mch)
+#define VGA_TRACE_FEATURE
+
+// Only reference the array if the tile numbers are within the bounds
+// of the array. If out of bounds, do nothing.
+#define SET_TILE_UPDATED(xtile,ytile,value) \
+ do { \
+ if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES)) \
+ BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] = value; \
+ } while (0)
+
+// Only reference the array if the tile numbers are within the bounds
+// of the array. If out of bounds, return 0.
+#define GET_TILE_UPDATED(xtile,ytile) \
+ ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))? \
+ BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] \
+ : 0)
+
+static const Bit8u ccdat[16][4] = {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0xff, 0x00, 0x00, 0x00 },
+ { 0x00, 0xff, 0x00, 0x00 },
+ { 0xff, 0xff, 0x00, 0x00 },
+ { 0x00, 0x00, 0xff, 0x00 },
+ { 0xff, 0x00, 0xff, 0x00 },
+ { 0x00, 0xff, 0xff, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 },
+ { 0x00, 0x00, 0x00, 0xff },
+ { 0xff, 0x00, 0x00, 0xff },
+ { 0x00, 0xff, 0x00, 0xff },
+ { 0xff, 0xff, 0x00, 0xff },
+ { 0x00, 0x00, 0xff, 0xff },
+ { 0xff, 0x00, 0xff, 0xff },
+ { 0x00, 0xff, 0xff, 0xff },
+ { 0xff, 0xff, 0xff, 0xff },
+};
+
+bx_vga_c *theVga = NULL;
+
+unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0, old_BPP = 0;
+
+ int
+libvga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+ theVga = new bx_vga_c ();
+ bx_devices.pluginVgaDevice = theVga;
+ BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
+ return(0); // Success
+}
+
+ void
+libvga_LTX_plugin_fini(void)
+{
+}
+
+bx_vga_c::bx_vga_c(void)
+{
+ put("VGA");
+ s.vga_mem_updated = 0;
+ s.x_tilesize = X_TILESIZE;
+ s.y_tilesize = Y_TILESIZE;
+ timer_id = BX_NULL_TIMER_HANDLE;
+}
+
+
+bx_vga_c::~bx_vga_c(void)
+{
+ // nothing for now
+}
+
+
+ void
+bx_vga_c::init(void)
+{
+ unsigned i;
+ unsigned x,y;
+
+ unsigned addr;
+ for (addr=0x03B4; addr<=0x03B5; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+ }
+
+ for (addr=0x03BA; addr<=0x03BA; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+ }
+
+ for (addr=0x03C0; addr<=0x03CF; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+ }
+
+ for (addr=0x03D4; addr<=0x03D5; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+ }
+
+ for (addr=0x03DA; addr<=0x03DA; addr++) {
+ DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+ DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+ }
+
+
+ BX_VGA_THIS s.misc_output.color_emulation = 1;
+ BX_VGA_THIS s.misc_output.enable_ram = 1;
+ BX_VGA_THIS s.misc_output.clock_select = 0;
+ BX_VGA_THIS s.misc_output.select_high_bank = 0;
+ BX_VGA_THIS s.misc_output.horiz_sync_pol = 1;
+ BX_VGA_THIS s.misc_output.vert_sync_pol = 1;
+
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
+
+ BX_VGA_THIS s.line_offset=80;
+ BX_VGA_THIS s.line_compare=1023;
+ BX_VGA_THIS s.vertical_display_end=399;
+
+ for (i=0; i<=0x18; i++)
+ BX_VGA_THIS s.CRTC.reg[i] = 0;
+ BX_VGA_THIS s.CRTC.address = 0;
+
+ BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
+ BX_VGA_THIS s.attribute_ctrl.address = 0;
+ BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
+ for (i=0; i<16; i++)
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[i] = 0;
+ BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
+ BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 0x0f;
+ BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 0;
+ BX_VGA_THIS s.attribute_ctrl.color_select = 0;
+
+ for (i=0; i<256; i++) {
+ BX_VGA_THIS s.pel.data[i].red = 0;
+ BX_VGA_THIS s.pel.data[i].green = 0;
+ BX_VGA_THIS s.pel.data[i].blue = 0;
+ }
+ BX_VGA_THIS s.pel.write_data_register = 0;
+ BX_VGA_THIS s.pel.write_data_cycle = 0;
+ BX_VGA_THIS s.pel.read_data_register = 0;
+ BX_VGA_THIS s.pel.read_data_cycle = 0;
+ BX_VGA_THIS s.pel.dac_state = 0x01;
+ BX_VGA_THIS s.pel.mask = 0xff;
+
+ BX_VGA_THIS s.graphics_ctrl.index = 0;
+ BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
+ BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
+ BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
+ BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
+ BX_VGA_THIS s.graphics_ctrl.raster_op = 0;
+ BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
+ BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
+ BX_VGA_THIS s.graphics_ctrl.read_mode = 0;
+ BX_VGA_THIS s.graphics_ctrl.odd_even = 0;
+ BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 0;
+ BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
+ BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
+ BX_VGA_THIS s.graphics_ctrl.memory_mapping = 2; // monochrome text mode
+ BX_VGA_THIS s.graphics_ctrl.color_dont_care = 0;
+ BX_VGA_THIS s.graphics_ctrl.bitmask = 0;
+ for (i=0; i<4; i++) {
+ BX_VGA_THIS s.graphics_ctrl.latch[i] = 0;
+ }
+
+ BX_VGA_THIS s.sequencer.index = 0;
+ BX_VGA_THIS s.sequencer.map_mask = 0;
+ for (i=0; i<4; i++) {
+ BX_VGA_THIS s.sequencer.map_mask_bit[i] = 0;
+ }
+ BX_VGA_THIS s.sequencer.reset1 = 1;
+ BX_VGA_THIS s.sequencer.reset2 = 1;
+ BX_VGA_THIS s.sequencer.reg1 = 0;
+ BX_VGA_THIS s.sequencer.char_map_select = 0;
+ BX_VGA_THIS s.sequencer.extended_mem = 1; // display mem greater than 64K
+ BX_VGA_THIS s.sequencer.odd_even = 1; // use sequential addressing mode
+ BX_VGA_THIS s.sequencer.chain_four = 0; // use map mask & read map select
+
+ memset(BX_VGA_THIS s.vga_memory, 0, sizeof(BX_VGA_THIS s.vga_memory));
+
+ BX_VGA_THIS s.vga_mem_updated = 0;
+ for (y=0; y<480/Y_TILESIZE; y++)
+ for (x=0; x<640/X_TILESIZE; x++)
+ SET_TILE_UPDATED (x, y, 0);
+
+ {
+ /* ??? should redo this to pass X args */
+ char *argv[1] = { "bochs" };
+ bx_gui->init(1, &argv[0], BX_VGA_THIS s.x_tilesize, BX_VGA_THIS s.y_tilesize);
+ }
+
+ BX_INFO(("interval=%u", bx_options.Ovga_update_interval->get ()));
+ if (BX_VGA_THIS timer_id == BX_NULL_TIMER_HANDLE) {
+ BX_VGA_THIS timer_id = bx_pc_system.register_timer(this, timer_handler,
+ bx_options.Ovga_update_interval->get (), 1, 1, "vga");
+ }
+
+ /* video card with BIOS ROM */
+ DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0xcf) | 0x00);
+
+ BX_VGA_THIS s.charmap_address = 0;
+ BX_VGA_THIS s.x_dotclockdiv2 = 0;
+ BX_VGA_THIS s.y_doublescan = 0;
+
+#if BX_SUPPORT_VBE
+ // The following is for the vbe display extension
+
+ for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
+ DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
+ DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
+ }
+#if !BX_PCI_USB_SUPPORT
+ for (addr=VBE_DISPI_IOPORT_INDEX_OLD; addr<=VBE_DISPI_IOPORT_DATA_OLD; addr++) {
+ DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
+ DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
+ }
+#endif
+ BX_VGA_THIS s.vbe_cur_dispi=VBE_DISPI_ID0;
+ BX_VGA_THIS s.vbe_xres=640;
+ BX_VGA_THIS s.vbe_yres=480;
+ BX_VGA_THIS s.vbe_bpp=8;
+ BX_VGA_THIS s.vbe_bank=0;
+ BX_VGA_THIS s.vbe_enabled=0;
+ BX_VGA_THIS s.vbe_curindex=0;
+ BX_VGA_THIS s.vbe_offset_x=0;
+ BX_VGA_THIS s.vbe_offset_y=0;
+ BX_VGA_THIS s.vbe_virtual_xres=640;
+ BX_VGA_THIS s.vbe_virtual_yres=480;
+ BX_VGA_THIS s.vbe_bpp_multiplier=1;
+ BX_VGA_THIS s.vbe_virtual_start=0;
+ BX_VGA_THIS s.vbe_line_byte_width=640;
+ BX_VGA_THIS s.vbe_lfb_enabled=0;
+
+
+ BX_INFO(("VBE Bochs Display Extension Enabled"));
+#endif
+ bios_init();
+}
+
+ void
+bx_vga_c::bios_init()
+{
+ int i;
+
+ BX_VGA_THIS s.misc_output.color_emulation = 1;
+ BX_VGA_THIS s.misc_output.enable_ram = 1;
+ BX_VGA_THIS s.misc_output.clock_select = 1;
+ BX_VGA_THIS s.misc_output.select_high_bank = 1;
+ BX_VGA_THIS s.misc_output.horiz_sync_pol = 1;
+ BX_VGA_THIS s.misc_output.vert_sync_pol = 0;
+ BX_VGA_THIS s.CRTC.address = 15;
+ BX_VGA_THIS s.CRTC.reg[0] = 95;
+ BX_VGA_THIS s.CRTC.reg[1] = 79;
+ BX_VGA_THIS s.CRTC.reg[2] = 80;
+ BX_VGA_THIS s.CRTC.reg[3] = 130;
+ BX_VGA_THIS s.CRTC.reg[4] = 85;
+ BX_VGA_THIS s.CRTC.reg[5] = 129;
+ BX_VGA_THIS s.CRTC.reg[6] = 191;
+ BX_VGA_THIS s.CRTC.reg[7] = 31;
+ BX_VGA_THIS s.CRTC.reg[8] = 0;
+ BX_VGA_THIS s.CRTC.reg[9] = 79;
+ BX_VGA_THIS s.CRTC.reg[10] = 14;
+ BX_VGA_THIS s.CRTC.reg[11] = 15;
+ BX_VGA_THIS s.CRTC.reg[12] = 0;
+ BX_VGA_THIS s.CRTC.reg[13] = 0;
+ BX_VGA_THIS s.CRTC.reg[14] = 5;
+ BX_VGA_THIS s.CRTC.reg[15] = 160;
+ BX_VGA_THIS s.CRTC.reg[16] = 156;
+ BX_VGA_THIS s.CRTC.reg[17] = 142;
+ BX_VGA_THIS s.CRTC.reg[18] = 143;
+ BX_VGA_THIS s.CRTC.reg[19] = 40;
+ BX_VGA_THIS s.CRTC.reg[20] = 31;
+ BX_VGA_THIS s.CRTC.reg[21] = 150;
+ BX_VGA_THIS s.CRTC.reg[22] = 185;
+ BX_VGA_THIS s.CRTC.reg[23] = 163;
+ BX_VGA_THIS s.CRTC.reg[24] = 255;
+ BX_VGA_THIS s.attribute_ctrl.flip_flop = 1;
+ BX_VGA_THIS s.attribute_ctrl.address = 0;
+ BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[0] = 0;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[1] = 1;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[2] = 2;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[3] = 3;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[4] = 4;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[5] = 5;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[6] = 6;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[7] = 7;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[8] = 8;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[9] = 9;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[10] = 10;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[11] = 11;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[12] = 12;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[13] = 13;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[14] = 14;
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[15] = 15;
+ BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
+ BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 15;
+ BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 8;
+ BX_VGA_THIS s.attribute_ctrl.color_select = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 1;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
+ BX_VGA_THIS s.pel.write_data_register = 16;
+ BX_VGA_THIS s.pel.write_data_cycle = 0;
+ BX_VGA_THIS s.pel.read_data_register = 0;
+ BX_VGA_THIS s.pel.read_data_cycle = 0;
+ BX_VGA_THIS s.pel.dac_state = 0;
+ memset((BX_VGA_THIS s.pel.data), 0, 256);
+ BX_VGA_THIS s.pel.data[0].red = 0;
+ BX_VGA_THIS s.pel.data[0].green = 0;
+ BX_VGA_THIS s.pel.data[0].blue = 0;
+ BX_VGA_THIS s.pel.mask = 255;
+ BX_VGA_THIS s.graphics_ctrl.index = 6;
+ BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
+ BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
+ BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
+ BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
+ BX_VGA_THIS s.graphics_ctrl.raster_op = 0;
+ BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
+ BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
+ BX_VGA_THIS s.graphics_ctrl.read_mode = 0;
+ BX_VGA_THIS s.graphics_ctrl.odd_even = 1;
+ BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 1;
+ BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
+ BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
+ BX_VGA_THIS s.graphics_ctrl.memory_mapping = 3;
+ BX_VGA_THIS s.graphics_ctrl.color_dont_care = 15;
+ BX_VGA_THIS s.graphics_ctrl.bitmask = 255;
+ BX_VGA_THIS s.graphics_ctrl.latch[0] = 0;
+ BX_VGA_THIS s.graphics_ctrl.latch[1] = 0;
+ BX_VGA_THIS s.graphics_ctrl.latch[2] = 0;
+ BX_VGA_THIS s.graphics_ctrl.latch[3] = 0;
+ BX_VGA_THIS s.sequencer.index = 3;
+ BX_VGA_THIS s.sequencer.map_mask = 3;
+ BX_VGA_THIS s.sequencer.map_mask_bit[0] = 1;
+ BX_VGA_THIS s.sequencer.map_mask_bit[1] = 1;
+ BX_VGA_THIS s.sequencer.map_mask_bit[2] = 0;
+ BX_VGA_THIS s.sequencer.map_mask_bit[3] = 0;
+ BX_VGA_THIS s.sequencer.reset1 = 1;
+ BX_VGA_THIS s.sequencer.reset2 = 1;
+ BX_VGA_THIS s.sequencer.reg1 = 0;
+ BX_VGA_THIS s.sequencer.char_map_select = 0;
+ BX_VGA_THIS s.sequencer.extended_mem = 1;
+ BX_VGA_THIS s.sequencer.odd_even = 0;
+ BX_VGA_THIS s.sequencer.chain_four = 0;
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ BX_VGA_THIS s.x_tilesize = 16;
+ BX_VGA_THIS s.y_tilesize = 24;
+ BX_VGA_THIS s.line_offset = 160;
+ BX_VGA_THIS s.line_compare = 1023;
+ BX_VGA_THIS s.vertical_display_end = 399;
+ memset((BX_VGA_THIS s.vga_tile_updated), 0, BX_NUM_X_TILES * BX_NUM_Y_TILES);
+
+ memset((BX_VGA_THIS s.vga_memory), ' ', 256 * 1024);
+ for(i = 0; i < 256 * 1024;i+=2) {
+ BX_VGA_THIS s.vga_memory[i] = ' ';
+ BX_VGA_THIS s.vga_memory[i+1] = 0x07;
+
+ }
+ memset((BX_VGA_THIS s.text_snapshot), 0, 32 * 1024);
+ memset((BX_VGA_THIS s.rgb), 0, 3 * 256);
+ memset((BX_VGA_THIS s.tile), 0, X_TILESIZE * Y_TILESIZE * 4);
+ BX_VGA_THIS s.charmap_address = 0;
+ BX_VGA_THIS s.x_dotclockdiv2 = 0;
+ BX_VGA_THIS s.y_doublescan = 1;
+}
+
+ void
+bx_vga_c::reset(unsigned type)
+{
+}
+
+
+ void
+bx_vga_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth)
+{
+ int ai[0x20];
+ int i,h,v;
+ for ( i = 0 ; i < 0x20 ; i++ )
+ ai[i] = BX_VGA_THIS s.CRTC.reg[i];
+
+ h = (ai[1] + 1) * 8;
+ v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;
+
+ if ( BX_VGA_THIS s.graphics_ctrl.shift_reg == 0 )
+ {
+ *piWidth = 640;
+ *piHeight = 480;
+
+ if ( BX_VGA_THIS s.CRTC.reg[6] == 0xBF )
+ {
+ if (BX_VGA_THIS s.CRTC.reg[23] == 0xA3 &&
+ BX_VGA_THIS s.CRTC.reg[20] == 0x40 &&
+ BX_VGA_THIS s.CRTC.reg[9] == 0x41)
+ {
+ *piWidth = 320;
+ *piHeight = 240;
+ }
+ else {
+ if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
+ *piWidth = h;
+ *piHeight = v;
+ }
+ }
+ else if ((h >= 640) && (v >= 480)) {
+ *piWidth = h;
+ *piHeight = v;
+ }
+ }
+ else if ( BX_VGA_THIS s.graphics_ctrl.shift_reg == 2 )
+ {
+
+ if ( BX_VGA_THIS s.sequencer.chain_four )
+ {
+ *piWidth = h;
+ *piHeight = v;
+ }
+ else
+ {
+ *piWidth = h;
+ *piHeight = v;
+ }
+ }
+ else
+ {
+ if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
+ *piWidth = h;
+ *piHeight = v;
+ }
+}
+
+
+ // static IO port read callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ Bit32u
+bx_vga_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ return( class_ptr->read(address, io_len) );
+}
+
+
+ Bit32u
+bx_vga_c::read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_VGA_SMF
+ bx_bool horiz_retrace = 0, vert_retrace = 0;
+ Bit64u usec;
+ Bit16u vertres;
+ Bit8u retval;
+
+#if defined(VGA_TRACE_FEATURE)
+ Bit32u ret = 0;
+#define RETURN(x) do { ret = (x); goto read_return; } while (0)
+#else
+#define RETURN return
+#endif
+
+#ifdef __OS2__
+ if ( bx_options.videomode == BX_VIDEO_DIRECT )
+ {
+ return _inp(address);
+ }
+#endif
+
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io read from 0x%04x", (unsigned) address));
+#endif
+
+ if ( (address >= 0x03b0) && (address <= 0x03bf) &&
+ (BX_VGA_THIS s.misc_output.color_emulation) ) {
+ RETURN(0xff);
+ }
+ if ( (address >= 0x03d0) && (address <= 0x03df) &&
+ (BX_VGA_THIS s.misc_output.color_emulation==0) ) {
+ RETURN(0xff);
+ }
+
+ switch (address) {
+ case 0x03ba: /* Input Status 1 (monochrome emulation modes) */
+ case 0x03ca: /* Feature Control ??? */
+ case 0x03da: /* Input Status 1 (color emulation modes) */
+ // bit3: Vertical Retrace
+ // 0 = display is in the display mode
+ // 1 = display is in the vertical retrace mode
+ // bit0: Display Enable
+ // 0 = display is in the display mode
+ // 1 = display is not in the display mode; either the
+ // horizontal or vertical retrace period is active
+
+ // using 72 Hz vertical frequency
+ usec = bx_pc_system.time_usec();
+ switch ( ( BX_VGA_THIS s.misc_output.vert_sync_pol << 1) | BX_VGA_THIS s.misc_output.horiz_sync_pol )
+ {
+ case 0: vertres = 200; break;
+ case 1: vertres = 400; break;
+ case 2: vertres = 350; break;
+ default: vertres = 480; break;
+ }
+ if ((usec % 13888) < 70) {
+ vert_retrace = 1;
+ }
+ if ((usec % (13888 / vertres)) == 0) {
+ horiz_retrace = 1;
+ }
+
+ retval = 0;
+ if (horiz_retrace || vert_retrace)
+ retval = 0x01;
+ if (vert_retrace)
+ retval |= 0x08;
+
+ /* reading this port resets the flip-flop to address mode */
+ BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
+ RETURN(retval);
+ break;
+
+
+ case 0x03c0: /* */
+ if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) {
+ //BX_INFO(("io read: 0x3c0: flip_flop = 0"));
+ retval =
+ (BX_VGA_THIS s.attribute_ctrl.video_enabled << 5) |
+ BX_VGA_THIS s.attribute_ctrl.address;
+ RETURN(retval);
+ }
+ else {
+ BX_ERROR(("io read: 0x3c0: flip_flop != 0"));
+ return(0);
+ }
+ break;
+
+ case 0x03c1: /* */
+ switch (BX_VGA_THIS s.attribute_ctrl.address) {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ retval = BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address];
+ RETURN(retval);
+ break;
+ case 0x10: /* mode control register */
+ retval =
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type << 1) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity << 3) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |
+ (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size << 7);
+ RETURN(retval);
+ break;
+ case 0x11: /* overscan color register */
+ RETURN(BX_VGA_THIS s.attribute_ctrl.overscan_color);
+ break;
+ case 0x12: /* color plane enable */
+ RETURN(BX_VGA_THIS s.attribute_ctrl.color_plane_enable);
+ break;
+ case 0x13: /* horizontal PEL panning register */
+ RETURN(BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning);
+ break;
+ case 0x14: /* color select register */
+ RETURN(BX_VGA_THIS s.attribute_ctrl.color_select);
+ break;
+ default:
+ BX_INFO(("io read: 0x3c1: unknown register 0x%02x",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
+ RETURN(0);
+ }
+ break;
+
+ case 0x03c2: /* Input Status 0 */
+ BX_DEBUG(("io read 0x3c2: input status #0: ignoring"));
+ RETURN(0);
+ break;
+
+ case 0x03c3: /* VGA Enable Register */
+ RETURN(1);
+ break;
+
+ case 0x03c4: /* Sequencer Index Register */
+ RETURN(BX_VGA_THIS s.sequencer.index);
+ break;
+
+ case 0x03c5: /* Sequencer Registers 00..04 */
+ switch (BX_VGA_THIS s.sequencer.index) {
+ case 0: /* sequencer: reset */
+ BX_DEBUG(("io read 0x3c5: sequencer reset"));
+ RETURN(BX_VGA_THIS s.sequencer.reset1 | (BX_VGA_THIS s.sequencer.reset2<<1));
+ break;
+ case 1: /* sequencer: clocking mode */
+ BX_DEBUG(("io read 0x3c5: sequencer clocking mode"));
+ RETURN(BX_VGA_THIS s.sequencer.reg1);
+ break;
+ case 2: /* sequencer: map mask register */
+ RETURN(BX_VGA_THIS s.sequencer.map_mask);
+ break;
+ case 3: /* sequencer: character map select register */
+ RETURN(BX_VGA_THIS s.sequencer.char_map_select);
+ break;
+ case 4: /* sequencer: memory mode register */
+ retval =
+ (BX_VGA_THIS s.sequencer.extended_mem << 1) |
+ (BX_VGA_THIS s.sequencer.odd_even << 2) |
+ (BX_VGA_THIS s.sequencer.chain_four << 3);
+ RETURN(retval);
+ break;
+
+ default:
+ BX_DEBUG(("io read 0x3c5: index %u unhandled",
+ (unsigned) BX_VGA_THIS s.sequencer.index));
+ RETURN(0);
+ }
+ break;
+
+ case 0x03c6: /* PEL mask ??? */
+ RETURN(BX_VGA_THIS s.pel.mask);
+ break;
+
+ case 0x03c7: /* DAC state, read = 11b, write = 00b */
+ RETURN(BX_VGA_THIS s.pel.dac_state);
+ break;
+
+ case 0x03c8: /* PEL address write mode */
+ RETURN(BX_VGA_THIS s.pel.write_data_register);
+ break;
+
+ case 0x03c9: /* PEL Data Register, colors 00..FF */
+ if (BX_VGA_THIS s.pel.dac_state == 0x03) {
+ switch (BX_VGA_THIS s.pel.read_data_cycle) {
+ case 0:
+ retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].red;
+ break;
+ case 1:
+ retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].green;
+ break;
+ case 2:
+ retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].blue;
+ break;
+ default:
+ retval = 0; // keep compiler happy
+ }
+ BX_VGA_THIS s.pel.read_data_cycle++;
+ if (BX_VGA_THIS s.pel.read_data_cycle >= 3) {
+ BX_VGA_THIS s.pel.read_data_cycle = 0;
+ BX_VGA_THIS s.pel.read_data_register++;
+ }
+ }
+ else {
+ retval = 0x3f;
+ }
+ RETURN(retval);
+ break;
+
+ case 0x03cc: /* Miscellaneous Output / Graphics 1 Position ??? */
+ retval =
+ ((BX_VGA_THIS s.misc_output.color_emulation & 0x01) << 0) |
+ ((BX_VGA_THIS s.misc_output.enable_ram & 0x01) << 1) |
+ ((BX_VGA_THIS s.misc_output.clock_select & 0x03) << 2) |
+ ((BX_VGA_THIS s.misc_output.select_high_bank & 0x01) << 5) |
+ ((BX_VGA_THIS s.misc_output.horiz_sync_pol & 0x01) << 6) |
+ ((BX_VGA_THIS s.misc_output.vert_sync_pol & 0x01) << 7);
+ RETURN(retval);
+ break;
+
+ case 0x03ce: /* Graphics Controller Index Register */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.index);
+ break;
+
+ case 0x03cd: /* ??? */
+ BX_DEBUG(("io read from 03cd"));
+ RETURN(0x00);
+ break;
+
+ case 0x03cf: /* Graphics Controller Registers 00..08 */
+ switch (BX_VGA_THIS s.graphics_ctrl.index) {
+ case 0: /* Set/Reset */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.set_reset);
+ break;
+ case 1: /* Enable Set/Reset */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
+ break;
+ case 2: /* Color Compare */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.color_compare);
+ break;
+ case 3: /* Data Rotate */
+ retval =
+ ((BX_VGA_THIS s.graphics_ctrl.raster_op & 0x03) << 3) |
+ ((BX_VGA_THIS s.graphics_ctrl.data_rotate & 0x07) << 0);
+ RETURN(retval);
+ break;
+ case 4: /* Read Map Select */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.read_map_select);
+ break;
+ case 5: /* Mode */
+ retval =
+ ((BX_VGA_THIS s.graphics_ctrl.shift_reg & 0x03) << 5) |
+ ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01 ) << 4) |
+ ((BX_VGA_THIS s.graphics_ctrl.read_mode & 0x01) << 3) |
+ ((BX_VGA_THIS s.graphics_ctrl.write_mode & 0x03) << 0);
+
+ if (BX_VGA_THIS s.graphics_ctrl.odd_even ||
+ BX_VGA_THIS s.graphics_ctrl.shift_reg)
+ BX_DEBUG(("io read 0x3cf: reg 05 = 0x%02x", (unsigned) retval));
+ RETURN(retval);
+ break;
+ case 6: /* Miscellaneous */
+ retval =
+ ((BX_VGA_THIS s.graphics_ctrl.memory_mapping & 0x03 ) << 2) |
+ ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 1) |
+ ((BX_VGA_THIS s.graphics_ctrl.graphics_alpha & 0x01) << 0);
+ RETURN(retval);
+ break;
+ case 7: /* Color Don't Care */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.color_dont_care);
+ break;
+ case 8: /* Bit Mask */
+ RETURN(BX_VGA_THIS s.graphics_ctrl.bitmask);
+ break;
+ default:
+ /* ??? */
+ BX_DEBUG(("io read: 0x3cf: index %u unhandled",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
+ RETURN(0);
+ }
+ break;
+
+ case 0x03d4: /* CRTC Index Register (color emulation modes) */
+ RETURN(BX_VGA_THIS s.CRTC.address);
+ break;
+
+ case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
+ case 0x03d5: /* CRTC Registers (color emulation modes) */
+ if (BX_VGA_THIS s.CRTC.address > 0x18) {
+ BX_DEBUG(("io read: invalid CRTC register 0x%02x",
+ (unsigned) BX_VGA_THIS s.CRTC.address));
+ RETURN(0);
+ }
+ RETURN(BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]);
+ break;
+
+ case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
+ case 0x03cb: /* not sure but OpenBSD reads it a lot */
+ default:
+ BX_INFO(("io read from vga port 0x%02x", (unsigned) address));
+ RETURN(0); /* keep compiler happy */
+ }
+
+#if defined(VGA_TRACE_FEATURE)
+ read_return:
+ BX_DEBUG(("8-bit read from %04x = %02x", (unsigned) address, ret));
+ return ret;
+#endif
+}
+#if defined(VGA_TRACE_FEATURE)
+#undef RETURN
+#endif
+
+ // static IO port write callback handler
+ // redirects to non-static class handler to avoid virtual functions
+
+ void
+bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len, 0);
+#else
+ UNUSED(this_ptr);
+ theVga->write(address, value, io_len, 0);
+#endif
+}
+
+ void
+bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ class_ptr->write(address, value, io_len, 1);
+#else
+ UNUSED(this_ptr);
+ theVga->write(address, value, io_len, 1);
+#endif
+}
+
+ void
+bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log)
+{
+ unsigned i;
+ Bit8u charmap1, charmap2, prev_memory_mapping;
+ bx_bool prev_video_enabled, prev_line_graphics, prev_int_pal_size;
+ bx_bool prev_graphics_alpha, prev_chain_odd_even;
+ bx_bool needs_update = 0;
+
+#if defined(VGA_TRACE_FEATURE)
+ if (!no_log)
+ switch (io_len) {
+ case 1:
+ BX_DEBUG(("8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
+ break;
+ case 2:
+ BX_DEBUG(("16-bit write to %04x = %04x", (unsigned)address, (unsigned)value));
+ break;
+ default:
+ BX_PANIC(("Weird VGA write size"));
+ }
+#else
+ if (io_len == 1) {
+ BX_DEBUG(("io write to 0x%04x = 0x%02x", (unsigned) address,
+ (unsigned) value));
+ }
+#endif
+
+ if (io_len == 2) {
+#if BX_USE_VGA_SMF
+ bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
+ bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
+#else
+ bx_vga_c::write(address, value & 0xff, 1, 1);
+ bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
+#endif
+ return;
+ }
+
+#ifdef __OS2__
+ if ( bx_options.videomode == BX_VIDEO_DIRECT )
+ {
+ _outp(address,value);
+ return;
+ }
+#endif
+
+ if ( (address >= 0x03b0) && (address <= 0x03bf) &&
+ (BX_VGA_THIS s.misc_output.color_emulation) )
+ return;
+ if ( (address >= 0x03d0) && (address <= 0x03df) &&
+ (BX_VGA_THIS s.misc_output.color_emulation==0) )
+ return;
+
+ switch (address) {
+ case 0x03ba: /* Feature Control (monochrome emulation modes) */
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3ba: feature control: ignoring"));
+#endif
+ break;
+
+ case 0x03c0: /* Attribute Controller */
+ if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) { /* address mode */
+ prev_video_enabled = BX_VGA_THIS s.attribute_ctrl.video_enabled;
+ BX_VGA_THIS s.attribute_ctrl.video_enabled = (value >> 5) & 0x01;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: video_enabled = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
+#endif
+ if (BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
+ bx_gui->clear_screen();
+ else if (!prev_video_enabled) {
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("found enable transition"));
+#endif
+ needs_update = 1;
+ }
+ value &= 0x1f; /* address = bits 0..4 */
+ BX_VGA_THIS s.attribute_ctrl.address = value;
+ switch (value) {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ break;
+
+ default:
+ BX_DEBUG(("io write 3c0: address mode reg=%u",
+ (unsigned) value));
+ }
+ }
+ else { /* data-write mode */
+ switch (BX_VGA_THIS s.attribute_ctrl.address) {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0a: case 0x0b:
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ if (value != BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address]) {
+ BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address] =
+ value;
+ needs_update = 1;
+ }
+ break;
+ case 0x10: // mode control register
+ prev_line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
+ prev_int_pal_size = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha =
+ (value >> 0) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type =
+ (value >> 1) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics =
+ (value >> 2) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity =
+ (value >> 3) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat =
+ (value >> 5) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select =
+ (value >> 6) & 0x01;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size =
+ (value >> 7) & 0x01;
+ if (((value >> 2) & 0x01) != prev_line_graphics) {
+ bx_gui->set_text_charmap(
+ & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ }
+ if (((value >> 7) & 0x01) != prev_int_pal_size) {
+ needs_update = 1;
+ }
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: mode control: %02x h",
+ (unsigned) value));
+#endif
+ break;
+ case 0x11: // Overscan Color Register
+ BX_VGA_THIS s.attribute_ctrl.overscan_color = (value & 0x3f);
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: overscan color = %02x",
+ (unsigned) value));
+#endif
+ break;
+ case 0x12: // Color Plane Enable Register
+ BX_VGA_THIS s.attribute_ctrl.color_plane_enable = (value & 0x0f);
+ needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: color plane enable = %02x",
+ (unsigned) value));
+#endif
+ break;
+ case 0x13: // Horizontal Pixel Panning Register
+ BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = (value & 0x0f);
+ needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: horiz pel panning = %02x",
+ (unsigned) value));
+#endif
+ break;
+ case 0x14: // Color Select Register
+ BX_VGA_THIS s.attribute_ctrl.color_select = (value & 0x0f);
+ needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c0: color select = %02x",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.color_select));
+#endif
+ break;
+ default:
+ BX_DEBUG(("io write 3c0: data-write mode %02x h",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
+ }
+ }
+ BX_VGA_THIS s.attribute_ctrl.flip_flop = !BX_VGA_THIS s.attribute_ctrl.flip_flop;
+ break;
+
+ case 0x03c2: // Miscellaneous Output Register
+ BX_VGA_THIS s.misc_output.color_emulation = (value >> 0) & 0x01;
+ BX_VGA_THIS s.misc_output.enable_ram = (value >> 1) & 0x01;
+ BX_VGA_THIS s.misc_output.clock_select = (value >> 2) & 0x03;
+ BX_VGA_THIS s.misc_output.select_high_bank = (value >> 5) & 0x01;
+ BX_VGA_THIS s.misc_output.horiz_sync_pol = (value >> 6) & 0x01;
+ BX_VGA_THIS s.misc_output.vert_sync_pol = (value >> 7) & 0x01;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c2:"));
+ BX_DEBUG((" color_emulation (attempted) = %u",
+ (value >> 0) & 0x01));
+ BX_DEBUG((" enable_ram = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.enable_ram));
+ BX_DEBUG((" clock_select = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.clock_select));
+ BX_DEBUG((" select_high_bank = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
+ BX_DEBUG((" horiz_sync_pol = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
+ BX_DEBUG((" vert_sync_pol = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
+#endif
+ break;
+
+ case 0x03c3: // VGA enable
+ // bit0: enables VGA display if set
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c3: (ignoring) VGA enable = %u",
+ (unsigned) (value & 0x01) ));
+#endif
+ break;
+
+ case 0x03c4: /* Sequencer Index Register */
+ if (value > 4) {
+ BX_DEBUG(("io write 3c4: value > 4"));
+ }
+ BX_VGA_THIS s.sequencer.index = value;
+ break;
+
+ case 0x03c5: /* Sequencer Registers 00..04 */
+ switch (BX_VGA_THIS s.sequencer.index) {
+ case 0: /* sequencer: reset */
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("write 0x3c5: sequencer reset: value=0x%02x",
+ (unsigned) value));
+#endif
+ if (BX_VGA_THIS s.sequencer.reset1 && ((value & 0x01) == 0)) {
+ BX_VGA_THIS s.sequencer.char_map_select = 0;
+ BX_VGA_THIS s.charmap_address = 0;
+ bx_gui->set_text_charmap(
+ & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ }
+ BX_VGA_THIS s.sequencer.reset1 = (value >> 0) & 0x01;
+ BX_VGA_THIS s.sequencer.reset2 = (value >> 1) & 0x01;
+ break;
+ case 1: /* sequencer: clocking mode */
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c5=%02x: clocking mode reg: ignoring",
+ (unsigned) value));
+#endif
+ BX_VGA_THIS s.sequencer.reg1 = value & 0x3f;
+ BX_VGA_THIS s.x_dotclockdiv2 = ((value & 0x08) > 0);
+ break;
+ case 2: /* sequencer: map mask register */
+ BX_VGA_THIS s.sequencer.map_mask = (value & 0x0f);
+ for (i=0; i<4; i++)
+ BX_VGA_THIS s.sequencer.map_mask_bit[i] = (value >> i) & 0x01;
+ break;
+ case 3: /* sequencer: character map select register */
+ BX_VGA_THIS s.sequencer.char_map_select = value;
+ charmap1 = value & 0x13;
+ if (charmap1 > 3) charmap1 = (charmap1 & 3) + 4;
+ charmap2 = (value & 0x2C) >> 2;
+ if (charmap2 > 3) charmap2 = (charmap2 & 3) + 4;
+ if (BX_VGA_THIS s.CRTC.reg[0x09] > 0) {
+ BX_VGA_THIS s.charmap_address = (charmap1 << 13);
+ bx_gui->set_text_charmap(
+ & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ }
+ if (charmap2 != charmap1)
+ BX_INFO(("char map select: #2=%d (unused)", charmap2));
+ break;
+ case 4: /* sequencer: memory mode register */
+ BX_VGA_THIS s.sequencer.extended_mem = (value >> 1) & 0x01;
+ BX_VGA_THIS s.sequencer.odd_even = (value >> 2) & 0x01;
+ BX_VGA_THIS s.sequencer.chain_four = (value >> 3) & 0x01;
+
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write 3c5: index 4:"));
+ BX_DEBUG((" extended_mem %u",
+ (unsigned) BX_VGA_THIS s.sequencer.extended_mem));
+ BX_DEBUG((" odd_even %u",
+ (unsigned) BX_VGA_THIS s.sequencer.odd_even));
+ BX_DEBUG((" chain_four %u",
+ (unsigned) BX_VGA_THIS s.sequencer.chain_four));
+#endif
+ break;
+ default:
+ BX_DEBUG(("io write 3c5: index %u unhandled",
+ (unsigned) BX_VGA_THIS s.sequencer.index));
+ }
+ break;
+
+ case 0x03c6: /* PEL mask */
+ BX_VGA_THIS s.pel.mask = value;
+ if (BX_VGA_THIS s.pel.mask != 0xff)
+ BX_DEBUG(("io write 3c6: PEL mask=0x%02x != 0xFF", value));
+ // BX_VGA_THIS s.pel.mask should be and'd with final value before
+ // indexing into color register BX_VGA_THIS s.pel.data[]
+ break;
+
+ case 0x03c7: // PEL address, read mode
+ BX_VGA_THIS s.pel.read_data_register = value;
+ BX_VGA_THIS s.pel.read_data_cycle = 0;
+ BX_VGA_THIS s.pel.dac_state = 0x03;
+ break;
+
+ case 0x03c8: /* PEL address write mode */
+ BX_VGA_THIS s.pel.write_data_register = value;
+ BX_VGA_THIS s.pel.write_data_cycle = 0;
+ BX_VGA_THIS s.pel.dac_state = 0x00;
+ break;
+
+ case 0x03c9: /* PEL Data Register, colors 00..FF */
+ switch (BX_VGA_THIS s.pel.write_data_cycle) {
+ case 0:
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red = value;
+ break;
+ case 1:
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green = value;
+ break;
+ case 2:
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue = value;
+
+ needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red<<2,
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green<<2,
+ BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue<<2);
+ break;
+ }
+
+ BX_VGA_THIS s.pel.write_data_cycle++;
+ if (BX_VGA_THIS s.pel.write_data_cycle >= 3) {
+ //BX_INFO(("BX_VGA_THIS s.pel.data[%u] {r=%u, g=%u, b=%u}",
+ // (unsigned) BX_VGA_THIS s.pel.write_data_register,
+ // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
+ // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
+ // (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
+ BX_VGA_THIS s.pel.write_data_cycle = 0;
+ BX_VGA_THIS s.pel.write_data_register++;
+ }
+ break;
+
+ case 0x03ca: /* Graphics 2 Position (EGA) */
+ // ignore, EGA only???
+ break;
+
+ case 0x03cc: /* Graphics 1 Position (EGA) */
+ // ignore, EGA only???
+ break;
+
+ case 0x03ce: /* Graphics Controller Index Register */
+ if (value > 0x08) /* ??? */
+ BX_DEBUG(("io write: 3ce: value > 8"));
+ BX_VGA_THIS s.graphics_ctrl.index = value;
+ break;
+
+ case 0x03cd: /* ??? */
+ BX_DEBUG(("io write to 03cd = %02x", (unsigned) value));
+ break;
+
+ case 0x03cf: /* Graphics Controller Registers 00..08 */
+ switch (BX_VGA_THIS s.graphics_ctrl.index) {
+ case 0: /* Set/Reset */
+ BX_VGA_THIS s.graphics_ctrl.set_reset = value & 0x0f;
+ break;
+ case 1: /* Enable Set/Reset */
+ BX_VGA_THIS s.graphics_ctrl.enable_set_reset = value & 0x0f;
+ break;
+ case 2: /* Color Compare */
+ BX_VGA_THIS s.graphics_ctrl.color_compare = value & 0x0f;
+ break;
+ case 3: /* Data Rotate */
+ BX_VGA_THIS s.graphics_ctrl.data_rotate = value & 0x07;
+ /* ??? is this bits 3..4 or 4..5 */
+ BX_VGA_THIS s.graphics_ctrl.raster_op = (value >> 3) & 0x03; /* ??? */
+ break;
+ case 4: /* Read Map Select */
+ BX_VGA_THIS s.graphics_ctrl.read_map_select = value & 0x03;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("io write to 03cf = %02x (RMS)", (unsigned) value));
+#endif
+ break;
+ case 5: /* Mode */
+ BX_VGA_THIS s.graphics_ctrl.write_mode = value & 0x03;
+ BX_VGA_THIS s.graphics_ctrl.read_mode = (value >> 3) & 0x01;
+ BX_VGA_THIS s.graphics_ctrl.odd_even = (value >> 4) & 0x01;
+ BX_VGA_THIS s.graphics_ctrl.shift_reg = (value >> 5) & 0x03;
+
+ if (BX_VGA_THIS s.graphics_ctrl.odd_even)
+ BX_DEBUG(("io write: 3cf: reg 05: value = %02xh",
+ (unsigned) value));
+ if (BX_VGA_THIS s.graphics_ctrl.shift_reg)
+ BX_DEBUG(("io write: 3cf: reg 05: value = %02xh",
+ (unsigned) value));
+ break;
+ case 6: /* Miscellaneous */
+ prev_graphics_alpha = BX_VGA_THIS s.graphics_ctrl.graphics_alpha;
+ prev_chain_odd_even = BX_VGA_THIS s.graphics_ctrl.chain_odd_even;
+ prev_memory_mapping = BX_VGA_THIS s.graphics_ctrl.memory_mapping;
+
+ BX_VGA_THIS s.graphics_ctrl.graphics_alpha = value & 0x01;
+ BX_VGA_THIS s.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;
+ BX_VGA_THIS s.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;
+#if !defined(VGA_TRACE_FEATURE)
+ BX_DEBUG(("memory_mapping set to %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+ BX_DEBUG(("graphics mode set to %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
+ BX_DEBUG(("odd_even mode set to %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
+ BX_DEBUG(("io write: 3cf: reg 06: value = %02xh",
+ (unsigned) value));
+#endif
+ if (prev_memory_mapping != BX_VGA_THIS s.graphics_ctrl.memory_mapping)
+ needs_update = 1;
+ if (prev_graphics_alpha != BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+ needs_update = 1;
+ old_iHeight = 0;
+ }
+ break;
+ case 7: /* Color Don't Care */
+ BX_VGA_THIS s.graphics_ctrl.color_dont_care = value & 0x0f;
+ break;
+ case 8: /* Bit Mask */
+ BX_VGA_THIS s.graphics_ctrl.bitmask = value;
+ break;
+ default:
+ /* ??? */
+ BX_DEBUG(("io write: 3cf: index %u unhandled",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
+ }
+ break;
+
+ case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
+ case 0x03d4: /* CRTC Index Register (color emulation modes) */
+ BX_VGA_THIS s.CRTC.address = value & 0x7f;
+ if (BX_VGA_THIS s.CRTC.address > 0x18)
+ BX_DEBUG(("write: invalid CRTC register 0x%02x selected",
+ (unsigned) BX_VGA_THIS s.CRTC.address));
+ break;
+
+ case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
+ case 0x03d5: /* CRTC Registers (color emulation modes) */
+ if (BX_VGA_THIS s.CRTC.address > 0x18) {
+ BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
+ (unsigned) BX_VGA_THIS s.CRTC.address));
+ return;
+ }
+ if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
+ BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
+ switch (BX_VGA_THIS s.CRTC.address) {
+ case 0x07:
+ BX_VGA_THIS s.vertical_display_end &= 0xff;
+ if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x02) BX_VGA_THIS s.vertical_display_end |= 0x100;
+ if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x40) BX_VGA_THIS s.vertical_display_end |= 0x200;
+ BX_VGA_THIS s.line_compare &= 0x2ff;
+ if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
+ needs_update = 1;
+ break;
+ case 0x08:
+ // Vertical pel panning change
+ needs_update = 1;
+ break;
+ case 0x09:
+ BX_VGA_THIS s.y_doublescan = ((value & 0x9f) > 0);
+ BX_VGA_THIS s.line_compare &= 0x1ff;
+ if (BX_VGA_THIS s.CRTC.reg[0x09] & 0x40) BX_VGA_THIS s.line_compare |= 0x200;
+ needs_update = 1;
+ break;
+ case 0x0A:
+ case 0x0B:
+ case 0x0E:
+ case 0x0F:
+ // Cursor size / location change
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ break;
+ case 0x0C:
+ case 0x0D:
+ // Start address change
+ if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+ needs_update = 1;
+ } else {
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ }
+ break;
+ case 0x12:
+ BX_VGA_THIS s.vertical_display_end &= 0x300;
+ BX_VGA_THIS s.vertical_display_end |= BX_VGA_THIS s.CRTC.reg[0x12];
+ break;
+ case 0x13:
+ case 0x14:
+ case 0x17:
+ // Line offset change
+ BX_VGA_THIS s.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 1;
+ if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) BX_VGA_THIS s.line_offset <<= 2;
+ else if ((BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) == 0) BX_VGA_THIS s.line_offset <<= 1;
+ needs_update = 1;
+ break;
+ case 0x18:
+ BX_VGA_THIS s.line_compare &= 0x300;
+ BX_VGA_THIS s.line_compare |= BX_VGA_THIS s.CRTC.reg[0x18];
+ needs_update = 1;
+ break;
+ }
+
+ }
+ break;
+
+ case 0x03da: /* Feature Control (color emulation modes) */
+ BX_DEBUG(("io write: 3da: ignoring: feature ctrl & vert sync"));
+ break;
+
+ case 0x03c1: /* */
+ default:
+ BX_ERROR(("unsupported io write to port 0x%04x, val=0x%02x",
+ (unsigned) address, (unsigned) value));
+ }
+ if (needs_update) {
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ // Mark all video as updated so the changes will go through
+ if ((BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
+#if BX_SUPPORT_VBE
+ || (BX_VGA_THIS s.vbe_enabled)
+#endif
+ ) {
+ for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+ for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+ SET_TILE_UPDATED (xti, yti, 1);
+ }
+ }
+ } else {
+ memset(BX_VGA_THIS s.text_snapshot, 0,
+ sizeof(BX_VGA_THIS s.text_snapshot));
+ }
+ }
+}
+
+void
+bx_vga_c::set_update_interval (unsigned interval)
+{
+ BX_INFO (("Changing timer interval to %d\n", interval));
+ BX_VGA_THIS timer_handler (theVga);
+ bx_pc_system.activate_timer (BX_VGA_THIS timer_id, interval, 1);
+}
+
+ void
+bx_vga_c::trigger_timer(void *this_ptr)
+{
+ timer_handler(this_ptr);
+}
+
+ void
+bx_vga_c::timer_handler(void *this_ptr)
+{
+#if !BX_USE_VGA_SMF
+
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ class_ptr->timer();
+}
+
+ void
+bx_vga_c::timer(void)
+{
+#else
+ UNUSED(this_ptr);
+#endif
+
+ update();
+ bx_gui->flush();
+
+}
+
+
+ void
+bx_vga_c::update(void)
+{
+ unsigned iHeight, iWidth;
+
+ /* no screen update necessary */
+ if (BX_VGA_THIS s.vga_mem_updated==0)
+ return;
+
+ /* skip screen update when the sequencer is in reset mode or video is disabled */
+ if (!BX_VGA_THIS s.sequencer.reset1 || !BX_VGA_THIS s.sequencer.reset2
+ || !BX_VGA_THIS s.attribute_ctrl.video_enabled)
+ return;
+
+ /* skip screen update if the vertical retrace is in progress
+ (using 72 Hz vertical frequency) */
+ if ((bx_pc_system.time_usec() % 13888) < 70)
+ return;
+
+#if BX_SUPPORT_VBE
+ if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+ {
+ // specific VBE code display update code
+ // this is partly copied/modified from the 320x200x8 update more below
+ unsigned xc, yc, xti, yti;
+ unsigned r;
+ unsigned long pixely, bmp_ofs_y, tile_ofs_y;
+
+ if (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_32)
+ {
+ Bit32u *vidmem = (Bit32u *)(&BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start]);
+ Bit32u *tile = (Bit32u *)(BX_VGA_THIS s.tile);
+ Bit16u width = BX_VGA_THIS s.vbe_virtual_xres;
+
+ Bit32u *vidptr, *tileptr;
+
+ iWidth=BX_VGA_THIS s.vbe_xres;
+ iHeight=BX_VGA_THIS s.vbe_yres;
+
+ for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+ {
+ for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+ {
+ if (GET_TILE_UPDATED (xti, yti))
+ {
+ for (r=0; r<Y_TILESIZE; r++)
+ {
+ pixely = yc + r;
+ // calc offsets into video and tile memory
+ bmp_ofs_y = pixely*width;
+ tile_ofs_y = r*X_TILESIZE;
+ // get offsets so that we do less calc in the inner loop
+ vidptr = &vidmem[bmp_ofs_y+xc];
+ tileptr = &tile[tile_ofs_y];
+ memmove(tileptr, vidptr, X_TILESIZE<<2);
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+ else if (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_24)
+ {
+ Bit8u *vidmem = &BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start];
+ Bit8u *tile = BX_VGA_THIS s.tile;
+ Bit16u width = BX_VGA_THIS s.vbe_virtual_xres*3;
+
+ Bit8u *vidptr, *tileptr;
+
+ iWidth=BX_VGA_THIS s.vbe_xres;
+ iHeight=BX_VGA_THIS s.vbe_yres;
+
+ for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+ {
+ for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+ {
+ if (GET_TILE_UPDATED (xti, yti))
+ {
+ for (r=0; r<Y_TILESIZE; r++)
+ {
+ pixely = yc + r;
+ // calc offsets into video and tile memory
+ bmp_ofs_y = pixely*width;
+ tile_ofs_y = r*X_TILESIZE*3;
+ // get offsets so that we do less calc in the inner loop
+ vidptr = &vidmem[bmp_ofs_y+xc*3];
+ tileptr = &tile[tile_ofs_y];
+ memmove(tileptr, vidptr, X_TILESIZE*3);
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+ else if ((BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_15) ||
+ (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_16))
+ {
+ Bit16u *vidmem = (Bit16u *)(&BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start]);
+ Bit16u *tile = (Bit16u *)(BX_VGA_THIS s.tile);
+ Bit16u width = BX_VGA_THIS s.vbe_virtual_xres;
+
+ Bit16u *vidptr, *tileptr;
+
+ iWidth=BX_VGA_THIS s.vbe_xres;
+ iHeight=BX_VGA_THIS s.vbe_yres;
+
+ for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+ {
+ for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+ {
+ if (GET_TILE_UPDATED (xti, yti))
+ {
+ for (r=0; r<Y_TILESIZE; r++)
+ {
+ pixely = yc + r;
+ // calc offsets into video and tile memory
+ bmp_ofs_y = pixely*width;
+ tile_ofs_y = r*X_TILESIZE;
+ // get offsets so that we do less calc in the inner loop
+ vidptr = &vidmem[bmp_ofs_y+xc];
+ tileptr = &tile[tile_ofs_y];
+ memmove(tileptr, vidptr, X_TILESIZE<<1);
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+ else /* Update 8bpp mode */
+ {
+ Bit8u *vidmem = &BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start];
+ Bit8u *tile = BX_VGA_THIS s.tile;
+ Bit16u width = BX_VGA_THIS s.vbe_virtual_xres;
+
+ Bit8u *vidptr, *tileptr;
+
+ iWidth=BX_VGA_THIS s.vbe_xres;
+ iHeight=BX_VGA_THIS s.vbe_yres;
+
+ for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+ {
+ for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+ {
+ // If the tile has not been updated, copy it into the tile buffer for update
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ // actual video y coord is tile_y + y
+ pixely = yc + r;
+ // calc offsets into video and tile memory
+ bmp_ofs_y = pixely*width;
+ tile_ofs_y = r*X_TILESIZE;
+ // get offsets so that we do less calc in the inner loop
+ vidptr = &vidmem[bmp_ofs_y+xc];
+ tileptr = &tile[tile_ofs_y];
+ memmove(tileptr, vidptr, X_TILESIZE);
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+
+ old_iWidth = iWidth;
+ old_iHeight = iHeight;
+ BX_VGA_THIS s.vga_mem_updated = 0;
+ // after a vbe display update, don't try to do any 'normal vga' updates anymore
+ return;
+ }
+#endif
+ // fields that effect the way video memory is serialized into screen output:
+ // GRAPHICS CONTROLLER:
+ // BX_VGA_THIS s.graphics_ctrl.shift_reg:
+ // 0: output data in standard VGA format or CGA-compatible 640x200 2 color
+ // graphics mode (mode 6)
+ // 1: output data in CGA-compatible 320x200 4 color graphics mode
+ // (modes 4 & 5)
+ // 2: output data 8 bits at a time from the 4 bit planes
+ // (mode 13 and variants like modeX)
+
+ // if (BX_VGA_THIS s.vga_mem_updated==0 || BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
+
+ if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+ Bit8u color;
+ unsigned bit_no, r, c, x, y;
+ unsigned long byte_offset, start_addr;
+ unsigned xc, yc, xti, yti;
+
+ start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
+
+//BX_DEBUG(("update: shiftreg=%u, chain4=%u, mapping=%u",
+// (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg,
+// (unsigned) BX_VGA_THIS s.sequencer.chain_four,
+// (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
+
+ determine_screen_dimensions(&iHeight, &iWidth);
+ if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (old_BPP > 8) ) {
+ bx_gui->dimension_update(iWidth, iHeight);
+ old_iWidth = iWidth;
+ old_iHeight = iHeight;
+ old_BPP = 8;
+ }
+
+ switch ( BX_VGA_THIS s.graphics_ctrl.shift_reg ) {
+
+ case 0:
+ Bit8u attribute, palette_reg_val, DAC_regno;
+ unsigned long line_compare;
+
+ if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // CGA 640x200x2
+
+ for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+ for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ y = yc + r;
+ if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+ for (c=0; c<X_TILESIZE; c++) {
+
+ x = xc + c;
+ /* 0 or 0x2000 */
+ byte_offset = start_addr + ((y & 1) << 13);
+ /* to the start of the line */
+ byte_offset += (320 / 4) * (y / 2);
+ /* to the byte start */
+ byte_offset += (x / 8);
+
+ bit_no = 7 - (x % 8);
+ palette_reg_val = (((BX_VGA_THIS s.vga_memory[byte_offset]) >> bit_no) & 1);
+ DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
+ BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+ }
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ } else { // output data in serial fashion with each display plane
+ // output on its associated serial output. Standard EGA/VGA format
+
+ line_compare = BX_VGA_THIS s.line_compare;
+ if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1;
+
+ for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+ for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ y = yc + r;
+ if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+ for (c=0; c<X_TILESIZE; c++) {
+ x = xc + c;
+ if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
+ bit_no = 7 - (x % 8);
+ if (y > line_compare) {
+ byte_offset = x / 8 +
+ ((y - line_compare - 1) * BX_VGA_THIS s.line_offset);
+ } else {
+ byte_offset = start_addr + x / 8 +
+ (y * BX_VGA_THIS s.line_offset);
+ }
+ attribute =
+ (((BX_VGA_THIS s.vga_memory[0*65536 + byte_offset] >> bit_no) & 0x01) << 0) |
+ (((BX_VGA_THIS s.vga_memory[1*65536 + byte_offset] >> bit_no) & 0x01) << 1) |
+ (((BX_VGA_THIS s.vga_memory[2*65536 + byte_offset] >> bit_no) & 0x01) << 2) |
+ (((BX_VGA_THIS s.vga_memory[3*65536 + byte_offset] >> bit_no) & 0x01) << 3);
+
+ attribute &= BX_VGA_THIS s.attribute_ctrl.color_plane_enable;
+ // undocumented feature ???: colors 0..7 high intensity, colors 8..15 blinking
+ // using low/high intensity. Blinking is not implemented yet.
+ if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) attribute ^= 0x08;
+ palette_reg_val = BX_VGA_THIS s.attribute_ctrl.palette_reg[attribute];
+ if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size) {
+ // use 4 lower bits from palette register
+ // use 4 higher bits from color select register
+ // 16 banks of 16-color registers
+ DAC_regno = (palette_reg_val & 0x0f) |
+ (BX_VGA_THIS s.attribute_ctrl.color_select << 4);
+ }
+ else {
+ // use 6 lower bits from palette register
+ // use 2 higher bits from color select register
+ // 4 banks of 64-color registers
+ DAC_regno = (palette_reg_val & 0x3f) |
+ ((BX_VGA_THIS s.attribute_ctrl.color_select & 0x0c) << 4);
+ }
+ // DAC_regno &= video DAC mask register ???
+
+ BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+ }
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+ break; // case 0
+
+ case 1: // output the data in a CGA-compatible 320x200 4 color graphics
+ // mode. (modes 4 & 5)
+
+ /* CGA 320x200x4 start */
+
+ for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+ for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ y = yc + r;
+ if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+ for (c=0; c<X_TILESIZE; c++) {
+
+ x = xc + c;
+ if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
+ /* 0 or 0x2000 */
+ byte_offset = start_addr + ((y & 1) << 13);
+ /* to the start of the line */
+ byte_offset += (320 / 4) * (y / 2);
+ /* to the byte start */
+ byte_offset += (x / 4);
+
+ attribute = 6 - 2*(x % 4);
+ palette_reg_val = (BX_VGA_THIS s.vga_memory[byte_offset]) >> attribute;
+ palette_reg_val &= 3;
+ DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
+ BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+ }
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ /* CGA 320x200x4 end */
+
+ break; // case 1
+
+ case 2: // output the data eight bits at a time from the 4 bit plane
+ // (format for VGA mode 13 hex)
+
+ if ( BX_VGA_THIS s.sequencer.chain_four ) {
+ unsigned long pixely, pixelx, plane;
+ // bx_vga_dump_status();
+
+ if (BX_VGA_THIS s.misc_output.select_high_bank != 1)
+ BX_PANIC(("update: select_high_bank != 1"));
+
+ for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+ for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ pixely = yc + r;
+ if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
+ for (c=0; c<X_TILESIZE; c++) {
+ pixelx = (xc + c) >> 1;
+ plane = (pixelx % 4);
+ byte_offset = start_addr + (plane * 65536) +
+ (pixely * BX_VGA_THIS s.line_offset) + (pixelx & ~0x03);
+ color = BX_VGA_THIS s.vga_memory[byte_offset];
+ BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
+ }
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+
+ else { // chain_four == 0, modeX
+ unsigned long pixely, pixelx, plane;
+
+ for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+ for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+ if (GET_TILE_UPDATED (xti, yti)) {
+ for (r=0; r<Y_TILESIZE; r++) {
+ pixely = yc + r;
+ if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
+ for (c=0; c<X_TILESIZE; c++) {
+ pixelx = (xc + c) >> 1;
+ plane = (pixelx % 4);
+ byte_offset = (plane * 65536) +
+ (pixely * BX_VGA_THIS s.line_offset)
+ + (pixelx >> 2);
+ color = BX_VGA_THIS s.vga_memory[start_addr + byte_offset];
+ BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
+ }
+ }
+ SET_TILE_UPDATED (xti, yti, 0);
+ bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+ }
+ }
+ }
+ }
+ break; // case 2
+
+ default:
+ BX_PANIC(("update: shift_reg == %u", (unsigned)
+ BX_VGA_THIS s.graphics_ctrl.shift_reg ));
+ }
+
+ BX_VGA_THIS s.vga_mem_updated = 0;
+ return;
+ }
+
+ else { // text mode
+ unsigned long start_address;
+ unsigned long cursor_address, cursor_x, cursor_y;
+ bx_vga_tminfo_t tm_info;
+
+
+ tm_info.cs_start = BX_VGA_THIS s.CRTC.reg[0x0a] & 0x3f;
+ tm_info.cs_end = BX_VGA_THIS s.CRTC.reg[0x0b] & 0x1f;
+ tm_info.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 2;
+ tm_info.line_compare = BX_VGA_THIS s.line_compare;
+ tm_info.h_panning = BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning & 0x0f;
+ tm_info.v_panning = BX_VGA_THIS s.CRTC.reg[0x08] & 0x1f;
+ tm_info.line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
+ if ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 0) {
+ if (tm_info.h_panning == 8)
+ tm_info.h_panning = 0;
+ else
+ tm_info.h_panning++;
+ }
+
+ switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+ case 0: // 128K @ A0000
+ case 1: // 64K @ A0000
+ iWidth = 8*80; // TODO: should use font size
+ iHeight = 16*25;
+ if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (old_BPP > 8) )
+ {
+ bx_gui->dimension_update(iWidth, iHeight, 16, 8);
+ old_iWidth = iWidth;
+ old_iHeight = iHeight;
+ old_BPP = 8;
+ }
+ /* pass old text snapshot & new VGA memory contents */
+ start_address = 0x0;
+ cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) |
+ BX_VGA_THIS s.CRTC.reg[0x0f]);
+ if (cursor_address < start_address) {
+ cursor_x = 0xffff;
+ cursor_y = 0xffff;
+ }
+ else {
+ cursor_x = ((cursor_address - start_address)/2) % 80;
+ cursor_y = ((cursor_address - start_address)/2) / 80;
+ }
+ bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
+ &BX_VGA_THIS s.vga_memory[start_address],
+ cursor_x, cursor_y, tm_info, 25);
+ // screen updated, copy new VGA memory contents into text snapshot
+ memcpy(BX_VGA_THIS s.text_snapshot,
+ &BX_VGA_THIS s.vga_memory[start_address],
+ 2*80*25);
+ BX_VGA_THIS s.vga_mem_updated = 0;
+ break;
+
+ case 2: // B0000 .. B7FFF
+ case 3: // B8000 .. BFFFF
+ unsigned VDE, MSL, rows, cWidth;
+
+ // Verticle Display End: find out how many lines are displayed
+ VDE = BX_VGA_THIS s.vertical_display_end;
+ // Maximum Scan Line: height of character cell
+ MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
+ if (MSL == 0) {
+ //BX_ERROR(("character height = 1, skipping text update"));
+ return;
+ }
+ if ((MSL == 1) && (BX_VGA_THIS s.CRTC.reg[0x06] == 100)) {
+ // emulated CGA graphics mode 160x100x16 colors
+ MSL = 3;
+ rows = 100;
+ cWidth = 8;
+ iWidth = cWidth * BX_VGA_THIS s.CRTC.reg[1];
+ iHeight = 400;
+ } else {
+ rows = (VDE+1)/(MSL+1);
+ if (rows > BX_MAX_TEXT_LINES)
+ BX_PANIC(("text rows>%d: %d",BX_MAX_TEXT_LINES,rows));
+ cWidth = ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 1) ? 8 : 9;
+ iWidth = cWidth * (BX_VGA_THIS s.CRTC.reg[1] + 1);
+ iHeight = VDE+1;
+ }
+ if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (MSL != old_MSL) || (old_BPP > 8) )
+ {
+ bx_gui->dimension_update(iWidth, iHeight, MSL+1, cWidth);
+ old_iWidth = iWidth;
+ old_iHeight = iHeight;
+ old_MSL = MSL;
+ old_BPP = 8;
+ }
+ // pass old text snapshot & new VGA memory contents
+ start_address = 2*((BX_VGA_THIS s.CRTC.reg[12] << 8) + BX_VGA_THIS s.CRTC.reg[13]);
+ cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) |
+ BX_VGA_THIS s.CRTC.reg[0x0f]);
+ if (cursor_address < start_address) {
+ cursor_x = 0xffff;
+ cursor_y = 0xffff;
+ }
+ else {
+ cursor_x = ((cursor_address - start_address)/2) % (iWidth/cWidth);
+ cursor_y = ((cursor_address - start_address)/2) / (iWidth/cWidth);
+ }
+ bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
+ &BX_VGA_THIS s.vga_memory[start_address],
+ cursor_x, cursor_y, tm_info, rows);
+ // screen updated, copy new VGA memory contents into text snapshot
+ memcpy(BX_VGA_THIS s.text_snapshot,
+ &BX_VGA_THIS s.vga_memory[start_address],
+ 2*80*rows);
+ BX_VGA_THIS s.vga_mem_updated = 0;
+ break;
+ default:
+ BX_DEBUG(("update(): color text mode: mem map is %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+ }
+ }
+}
+
+
+ Bit8u
+bx_vga_c::mem_read(Bit32u addr)
+{
+ Bit32u offset;
+
+#if BX_SUPPORT_VBE
+ // if in a vbe enabled mode, read from the vbe_memory
+ if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+ {
+ return vbe_mem_read(addr);
+ }
+#endif
+
+#if defined(VGA_TRACE_FEATURE)
+// BX_DEBUG(("8-bit memory read from %08x", addr));
+#endif
+
+#ifdef __OS2__
+
+#if BX_PLUGINS
+#error Fix the code for plugins
+#endif
+
+ if ( bx_options.videomode == BX_VIDEO_DIRECT )
+ {
+ char value;
+
+ value = devices->mem->video[addr-0xA0000];
+
+ return value;
+ }
+#endif
+
+ switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+ case 1: // 0xA0000 .. 0xAFFFF
+ if (addr > 0xAFFFF) return 0xff;
+ offset = addr - 0xA0000;
+ break;
+ case 2: // 0xB0000 .. 0xB7FFF
+ if ((addr < 0xB0000) || (addr > 0xB7FFF)) return 0xff;
+ return BX_VGA_THIS s.vga_memory[addr - 0xB0000];
+ break;
+ case 3: // 0xB8000 .. 0xBFFFF
+ if (addr < 0xB8000) return 0xff;
+ return BX_VGA_THIS s.vga_memory[addr - 0xB8000];
+ break;
+ default: // 0xA0000 .. 0xBFFFF
+ return BX_VGA_THIS s.vga_memory[addr - 0xA0000];
+ }
+
+ // addr between 0xA0000 and 0xAFFFF
+ if ( BX_VGA_THIS s.sequencer.chain_four ) {
+
+ // Mode 13h: 320 x 200 256 color mode: chained pixel representation
+ return BX_VGA_THIS s.vga_memory[(offset & ~0x03) + (offset % 4)*65536];
+ }
+
+ /* addr between 0xA0000 and 0xAFFFF */
+ switch (BX_VGA_THIS s.graphics_ctrl.read_mode) {
+ case 0: /* read mode 0 */
+ BX_VGA_THIS s.graphics_ctrl.latch[0] = BX_VGA_THIS s.vga_memory[ offset];
+ BX_VGA_THIS s.graphics_ctrl.latch[1] = BX_VGA_THIS s.vga_memory[1*65536 + offset];
+ BX_VGA_THIS s.graphics_ctrl.latch[2] = BX_VGA_THIS s.vga_memory[2*65536 + offset];
+ BX_VGA_THIS s.graphics_ctrl.latch[3] = BX_VGA_THIS s.vga_memory[3*65536 + offset];
+ return(BX_VGA_THIS s.graphics_ctrl.latch[BX_VGA_THIS s.graphics_ctrl.read_map_select]);
+ break;
+
+ case 1: /* read mode 1 */
+ {
+ Bit8u color_compare, color_dont_care;
+ Bit8u latch0, latch1, latch2, latch3, retval;
+
+ color_compare = BX_VGA_THIS s.graphics_ctrl.color_compare & 0x0f;
+ color_dont_care = BX_VGA_THIS s.graphics_ctrl.color_dont_care & 0x0f;
+ latch0 = BX_VGA_THIS s.graphics_ctrl.latch[0] = BX_VGA_THIS s.vga_memory[ offset];
+ latch1 = BX_VGA_THIS s.graphics_ctrl.latch[1] = BX_VGA_THIS s.vga_memory[1*65536 + offset];
+ latch2 = BX_VGA_THIS s.graphics_ctrl.latch[2] = BX_VGA_THIS s.vga_memory[2*65536 + offset];
+ latch3 = BX_VGA_THIS s.graphics_ctrl.latch[3] = BX_VGA_THIS s.vga_memory[3*65536 + offset];
+
+ latch0 ^= ccdat[color_compare][0];
+ latch1 ^= ccdat[color_compare][1];
+ latch2 ^= ccdat[color_compare][2];
+ latch3 ^= ccdat[color_compare][3];
+
+ latch0 &= ccdat[color_dont_care][0];
+ latch1 &= ccdat[color_dont_care][1];
+ latch2 &= ccdat[color_dont_care][2];
+ latch3 &= ccdat[color_dont_care][3];
+
+ retval = ~(latch0 | latch1 | latch2 | latch3);
+
+ return retval;
+ }
+ break;
+ default:
+ return 0;
+ }
+}
+
+ void
+bx_vga_c::mem_write(Bit32u addr, Bit8u value)
+{
+ Bit32u offset;
+ Bit8u new_val[4];
+ unsigned start_addr;
+
+#if BX_SUPPORT_VBE
+ // if in a vbe enabled mode, write to the vbe_memory
+ if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+ {
+ vbe_mem_write(addr,value);
+ return;
+ }
+#endif
+
+#if defined(VGA_TRACE_FEATURE)
+// BX_DEBUG(("8-bit memory write to %08x = %02x", addr, value));
+#endif
+
+#ifdef __OS2__
+
+#if BX_PLUGINS
+#error Fix the code for plugins
+#endif
+
+ if ( bx_options.videomode == BX_VIDEO_DIRECT )
+ {
+ devices->mem->video[addr-0xA0000] = value;
+
+ return;
+ }
+#endif
+
+ switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+ case 1: // 0xA0000 .. 0xAFFFF
+ if (addr > 0xAFFFF) return;
+ offset = addr - 0xA0000;
+ break;
+ case 2: // 0xB0000 .. 0xB7FFF
+ if ((addr < 0xB0000) || (addr > 0xB7FFF)) return;
+ offset = addr - 0xB0000;
+ break;
+ case 3: // 0xB8000 .. 0xBFFFF
+ if (addr < 0xB8000) return;
+ offset = addr - 0xB8000;
+ break;
+ default: // 0xA0000 .. 0xBFFFF
+ offset = addr - 0xA0000;
+ }
+
+ start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
+
+ if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+ if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // 0xB8000 .. 0xBFFFF
+ unsigned x_tileno, x_tileno2, y_tileno;
+
+ /* CGA 320x200x4 / 640x200x2 start */
+ BX_VGA_THIS s.vga_memory[offset] = value;
+ offset -= start_addr;
+ if (offset>=0x2000) {
+ y_tileno = offset - 0x2000;
+ y_tileno /= (320/4);
+ y_tileno <<= 1; //2 * y_tileno;
+ y_tileno++;
+ x_tileno = (offset - 0x2000) % (320/4);
+ x_tileno <<= 2; //*= 4;
+ } else {
+ y_tileno = offset / (320/4);
+ y_tileno <<= 1; //2 * y_tileno;
+ x_tileno = offset % (320/4);
+ x_tileno <<= 2; //*=4;
+ }
+ x_tileno2=x_tileno;
+ if (BX_VGA_THIS s.graphics_ctrl.shift_reg==0) {
+ x_tileno*=2;
+ x_tileno2+=7;
+ } else {
+ x_tileno2+=3;
+ }
+ if (BX_VGA_THIS s.x_dotclockdiv2) {
+ x_tileno/=(X_TILESIZE/2);
+ x_tileno2/=(X_TILESIZE/2);
+ } else {
+ x_tileno/=X_TILESIZE;
+ x_tileno2/=X_TILESIZE;
+ }
+ if (BX_VGA_THIS s.y_doublescan) {
+ y_tileno/=(Y_TILESIZE/2);
+ } else {
+ y_tileno/=Y_TILESIZE;
+ }
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ if (x_tileno2!=x_tileno) {
+ SET_TILE_UPDATED (x_tileno2, y_tileno, 1);
+ }
+ return;
+ /* CGA 320x200x4 / 640x200x2 end */
+ }
+ else if (BX_VGA_THIS s.graphics_ctrl.memory_mapping != 1) {
+
+ BX_PANIC(("mem_write: graphics: mapping = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+ return;
+ }
+
+ if ( BX_VGA_THIS s.sequencer.chain_four ) {
+ unsigned x_tileno, y_tileno;
+
+ // 320 x 200 256 color mode: chained pixel representation
+ BX_VGA_THIS s.vga_memory[(offset & ~0x03) + (offset % 4)*65536] = value;
+ offset -= start_addr;
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE/2);
+ if (BX_VGA_THIS s.y_doublescan) {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE/2);
+ } else {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+ }
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ return;
+ }
+
+ }
+
+ /* addr between 0xA0000 and 0xAFFFF */
+ switch (BX_VGA_THIS s.graphics_ctrl.write_mode) {
+ unsigned i;
+
+ case 0: /* write mode 0 */
+ {
+ const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
+ const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
+ const Bit8u enable_set_reset = BX_VGA_THIS s.graphics_ctrl.enable_set_reset;
+ /* perform rotate on CPU data in case its needed */
+ if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
+ value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
+ (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
+ }
+ new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+ new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+ new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+ new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+ switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+ case 0: // replace
+ new_val[0] |= ((enable_set_reset & 1)
+ ? ((set_reset & 1) ? bitmask : 0)
+ : (value & bitmask));
+ new_val[1] |= ((enable_set_reset & 2)
+ ? ((set_reset & 2) ? bitmask : 0)
+ : (value & bitmask));
+ new_val[2] |= ((enable_set_reset & 4)
+ ? ((set_reset & 4) ? bitmask : 0)
+ : (value & bitmask));
+ new_val[3] |= ((enable_set_reset & 8)
+ ? ((set_reset & 8) ? bitmask : 0)
+ : (value & bitmask));
+ break;
+ case 1: // AND
+ new_val[0] |= ((enable_set_reset & 1)
+ ? ((set_reset & 1)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+ : 0)
+ : (value & BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
+ new_val[1] |= ((enable_set_reset & 2)
+ ? ((set_reset & 2)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+ : 0)
+ : (value & BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
+ new_val[2] |= ((enable_set_reset & 4)
+ ? ((set_reset & 4)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+ : 0)
+ : (value & BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
+ new_val[3] |= ((enable_set_reset & 8)
+ ? ((set_reset & 8)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+ : 0)
+ : (value & BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
+ break;
+ case 2: // OR
+ new_val[0]
+ |= ((enable_set_reset & 1)
+ ? ((set_reset & 1)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
+ : ((value | BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask));
+ new_val[1]
+ |= ((enable_set_reset & 2)
+ ? ((set_reset & 2)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
+ : ((value | BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask));
+ new_val[2]
+ |= ((enable_set_reset & 4)
+ ? ((set_reset & 4)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
+ : ((value | BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask));
+ new_val[3]
+ |= ((enable_set_reset & 8)
+ ? ((set_reset & 8)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
+ : ((value | BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask));
+ break;
+ case 3: // XOR
+ new_val[0]
+ |= ((enable_set_reset & 1)
+ ? ((set_reset & 1)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
+ : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
+ new_val[1]
+ |= ((enable_set_reset & 2)
+ ? ((set_reset & 2)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
+ : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
+ new_val[2]
+ |= ((enable_set_reset & 4)
+ ? ((set_reset & 4)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
+ : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
+ new_val[3]
+ |= ((enable_set_reset & 8)
+ ? ((set_reset & 8)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
+ : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
+ break;
+ default:
+ BX_PANIC(("vga_mem_write: write mode 0: op = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.raster_op));
+ }
+ }
+ break;
+
+ case 1: /* write mode 1 */
+ for (i=0; i<4; i++ ) {
+ new_val[i] = BX_VGA_THIS s.graphics_ctrl.latch[i];
+ }
+ break;
+
+ case 2: /* write mode 2 */
+ {
+ const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
+
+ new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+ new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+ new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+ new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+ switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+ case 0: // write
+ new_val[0] |= (value & 1) ? bitmask : 0;
+ new_val[1] |= (value & 2) ? bitmask : 0;
+ new_val[2] |= (value & 4) ? bitmask : 0;
+ new_val[3] |= (value & 8) ? bitmask : 0;
+ break;
+ case 1: // AND
+ new_val[0] |= (value & 1)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+ : 0;
+ new_val[1] |= (value & 2)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+ : 0;
+ new_val[2] |= (value & 4)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+ : 0;
+ new_val[3] |= (value & 8)
+ ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+ : 0;
+ break;
+ case 2: // OR
+ new_val[0] |= (value & 1)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
+ new_val[1] |= (value & 2)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
+ new_val[2] |= (value & 4)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
+ new_val[3] |= (value & 8)
+ ? bitmask
+ : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
+ break;
+ case 3: // XOR
+ new_val[0] |= (value & 1)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
+ new_val[1] |= (value & 2)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
+ new_val[2] |= (value & 4)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
+ new_val[3] |= (value & 8)
+ ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+ : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
+ break;
+ }
+ }
+ break;
+
+ case 3: /* write mode 3 */
+ {
+ const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask & value;
+ const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
+
+ /* perform rotate on CPU data */
+ if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
+ value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
+ (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
+ }
+ new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+ new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+ new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+ new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+
+ value &= bitmask;
+
+ switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+ case 0: // write
+ new_val[0] |= (set_reset & 1) ? value : 0;
+ new_val[1] |= (set_reset & 2) ? value : 0;
+ new_val[2] |= (set_reset & 4) ? value : 0;
+ new_val[3] |= (set_reset & 8) ? value : 0;
+ break;
+ case 1: // AND
+ new_val[0] |= ((set_reset & 1) ? value : 0)
+ & BX_VGA_THIS s.graphics_ctrl.latch[0];
+ new_val[1] |= ((set_reset & 2) ? value : 0)
+ & BX_VGA_THIS s.graphics_ctrl.latch[1];
+ new_val[2] |= ((set_reset & 4) ? value : 0)
+ & BX_VGA_THIS s.graphics_ctrl.latch[2];
+ new_val[3] |= ((set_reset & 8) ? value : 0)
+ & BX_VGA_THIS s.graphics_ctrl.latch[3];
+ break;
+ case 2: // OR
+ new_val[0] |= ((set_reset & 1) ? value : 0)
+ | BX_VGA_THIS s.graphics_ctrl.latch[0];
+ new_val[1] |= ((set_reset & 2) ? value : 0)
+ | BX_VGA_THIS s.graphics_ctrl.latch[1];
+ new_val[2] |= ((set_reset & 4) ? value : 0)
+ | BX_VGA_THIS s.graphics_ctrl.latch[2];
+ new_val[3] |= ((set_reset & 8) ? value : 0)
+ | BX_VGA_THIS s.graphics_ctrl.latch[3];
+ break;
+ case 3: // XOR
+ new_val[0] |= ((set_reset & 1) ? value : 0)
+ ^ BX_VGA_THIS s.graphics_ctrl.latch[0];
+ new_val[1] |= ((set_reset & 2) ? value : 0)
+ ^ BX_VGA_THIS s.graphics_ctrl.latch[1];
+ new_val[2] |= ((set_reset & 4) ? value : 0)
+ ^ BX_VGA_THIS s.graphics_ctrl.latch[2];
+ new_val[3] |= ((set_reset & 8) ? value : 0)
+ ^ BX_VGA_THIS s.graphics_ctrl.latch[3];
+ break;
+ }
+ }
+ break;
+
+ default:
+ BX_PANIC(("vga_mem_write: write mode %u ?",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.write_mode));
+ }
+
+ if (BX_VGA_THIS s.sequencer.map_mask & 0x0f) {
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ if (BX_VGA_THIS s.sequencer.map_mask_bit[0])
+ BX_VGA_THIS s.vga_memory[0*65536 + offset] = new_val[0];
+ if (BX_VGA_THIS s.sequencer.map_mask_bit[1])
+ BX_VGA_THIS s.vga_memory[1*65536 + offset] = new_val[1];
+ if (BX_VGA_THIS s.sequencer.map_mask_bit[2]) {
+ if ((!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) &&
+ ((offset & 0xe000) == BX_VGA_THIS s.charmap_address)) {
+ bx_gui->set_text_charbyte((offset & 0x1fff), new_val[2]);
+ }
+ BX_VGA_THIS s.vga_memory[2*65536 + offset] = new_val[2];
+ }
+ if (BX_VGA_THIS s.sequencer.map_mask_bit[3])
+ BX_VGA_THIS s.vga_memory[3*65536 + offset] = new_val[3];
+
+ unsigned x_tileno, y_tileno;
+
+ if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
+ offset -= start_addr;
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) * 4 / (X_TILESIZE / 2);
+ if (BX_VGA_THIS s.y_doublescan) {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
+ } else {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+ }
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ } else {
+ if (BX_VGA_THIS s.line_compare < BX_VGA_THIS s.vertical_display_end) {
+ if (BX_VGA_THIS s.x_dotclockdiv2) {
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
+ } else {
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
+ }
+ if (BX_VGA_THIS s.y_doublescan) {
+ y_tileno = ((offset / BX_VGA_THIS s.line_offset) * 2 + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
+ } else {
+ y_tileno = ((offset / BX_VGA_THIS s.line_offset) + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
+ }
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ }
+ if (offset >= start_addr) {
+ offset -= start_addr;
+ if (BX_VGA_THIS s.x_dotclockdiv2) {
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
+ } else {
+ x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
+ }
+ if (BX_VGA_THIS s.y_doublescan) {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
+ } else {
+ y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+ }
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ }
+ }
+ }
+}
+
+ void
+bx_vga_c::get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
+ unsigned *txWidth)
+{
+ unsigned VDE, MSL;
+
+ if (!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+ *text_snapshot = &BX_VGA_THIS s.text_snapshot[0];
+ VDE = BX_VGA_THIS s.vertical_display_end;
+ MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
+ *txHeight = (VDE+1)/(MSL+1);
+ *txWidth = BX_VGA_THIS s.CRTC.reg[1] + 1;
+ } else {
+ *txHeight = 0;
+ *txWidth = 0;
+ }
+}
+
+ Bit8u
+bx_vga_c::get_actl_palette_idx(Bit8u index)
+{
+ return BX_VGA_THIS s.attribute_ctrl.palette_reg[index];
+}
+
+ void
+bx_vga_c::dump_status(void)
+{
+ BX_INFO(("s.misc_output.color_emulation = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.color_emulation));
+ BX_INFO(("s.misc_output.enable_ram = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.enable_ram));
+ BX_INFO(("s.misc_output.clock_select = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.clock_select));
+ if (BX_VGA_THIS s.misc_output.clock_select == 0)
+ BX_INFO((" 25Mhz 640 horiz pixel clock"));
+ else
+ BX_INFO((" 28Mhz 720 horiz pixel clock"));
+ BX_INFO(("s.misc_output.select_high_bank = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
+ BX_INFO(("s.misc_output.horiz_sync_pol = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
+ BX_INFO(("s.misc_output.vert_sync_pol = %u",
+ (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
+ switch ( (BX_VGA_THIS s.misc_output.vert_sync_pol << 1) |
+ BX_VGA_THIS s.misc_output.horiz_sync_pol ) {
+ case 0: BX_INFO((" (reserved")); break;
+ case 1: BX_INFO((" 400 lines")); break;
+ case 2: BX_INFO((" 350 lines")); break;
+ case 3: BX_INFO((" 480 lines")); break;
+ default: BX_INFO((" ???"));
+ }
+
+ BX_INFO(("s.graphics_ctrl.odd_even = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
+ BX_INFO(("s.graphics_ctrl.chain_odd_even = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.chain_odd_even));
+ BX_INFO(("s.graphics_ctrl.shift_reg = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg));
+ BX_INFO(("s.graphics_ctrl.graphics_alpha = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
+ BX_INFO(("s.graphics_ctrl.memory_mapping = %u",
+ (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+ switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+ case 0: BX_INFO((" A0000-BFFFF")); break;
+ case 1: BX_INFO((" A0000-AFFFF")); break;
+ case 2: BX_INFO((" B0000-B7FFF")); break;
+ case 3: BX_INFO((" B8000-BFFFF")); break;
+ default: BX_INFO((" ???"));
+ }
+
+ BX_INFO(("s.sequencer.extended_mem = %u",
+ (unsigned) BX_VGA_THIS s.sequencer.extended_mem));
+ BX_INFO(("s.sequencer.odd_even = %u (inverted)",
+ (unsigned) BX_VGA_THIS s.sequencer.odd_even));
+ BX_INFO(("s.sequencer.chain_four = %u",
+ (unsigned) BX_VGA_THIS s.sequencer.chain_four));
+
+ BX_INFO(("s.attribute_ctrl.video_enabled = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
+ BX_INFO(("s.attribute_ctrl.mode_ctrl.graphics_alpha = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha));
+ BX_INFO(("s.attribute_ctrl.mode_ctrl.display_type = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type));
+ BX_INFO(("s.attribute_ctrl.mode_ctrl.internal_palette_size = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size));
+ BX_INFO(("s.attribute_ctrl.mode_ctrl.pixel_clock_select = %u",
+ (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select));
+}
+
+
+ void
+bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
+ unsigned height)
+{
+ unsigned xi, yi, x1, y1, xmax, ymax;
+
+ BX_VGA_THIS s.vga_mem_updated = 1;
+
+#if BX_SUPPORT_VBE
+ if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha || BX_VGA_THIS s.vbe_enabled) {
+#else
+ if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+#endif
+ // graphics mode
+ x1 = x0 + width - 1;
+ y1 = y0 + height - 1;
+
+ xmax = old_iWidth;
+ ymax = old_iHeight;
+#if BX_SUPPORT_VBE
+ if (BX_VGA_THIS s.vbe_enabled) {
+ xmax = BX_VGA_THIS s.vbe_xres;
+ ymax = BX_VGA_THIS s.vbe_yres;
+ }
+#endif
+ for (yi=0; yi<ymax; yi+=Y_TILESIZE) {
+ for (xi=0; xi<xmax; xi+=X_TILESIZE) {
+ // is redraw rectangle outside x boundaries of this tile?
+ if (x1 < xi) continue;
+ if (x0 > (xi+X_TILESIZE-1)) continue;
+
+ // is redraw rectangle outside y boundaries of this tile?
+ if (y1 < yi) continue;
+ if (y0 > (yi+Y_TILESIZE-1)) continue;
+ unsigned xti = xi/X_TILESIZE;
+ unsigned yti = yi/Y_TILESIZE;
+ SET_TILE_UPDATED (xti, yti, 1);
+ }
+ }
+ }
+ else {
+ // text mode
+ memset(BX_VGA_THIS s.text_snapshot, 0,
+ sizeof(BX_VGA_THIS s.text_snapshot));
+ }
+}
+
+
+#if BX_SUPPORT_VBE
+ Bit8u BX_CPP_AttrRegparmN(1)
+bx_vga_c::vbe_mem_read(Bit32u addr)
+{
+ Bit32u offset;
+
+ if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+ {
+ // LFB read
+ offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+ }
+ else
+ {
+ // banked mode read
+ offset = BX_VGA_THIS s.vbe_bank*65536 + addr - 0xA0000;
+ }
+
+ // check for out of memory read
+ if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
+ return 0;
+
+ return (BX_VGA_THIS s.vbe_memory[offset]);
+}
+
+ void BX_CPP_AttrRegparmN(2)
+bx_vga_c::vbe_mem_write(Bit32u addr, Bit8u value)
+{
+ Bit32u offset;
+ unsigned x_tileno, y_tileno;
+
+ if (BX_VGA_THIS s.vbe_lfb_enabled)
+ {
+ if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+ {
+ // LFB write
+ offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+ }
+ else
+ {
+ // banked mode write while in LFB mode -> ignore
+ return;
+ }
+ }
+ else
+ {
+ if (addr < VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+ {
+ // banked mode write
+ offset = (BX_VGA_THIS s.vbe_bank*65536) + (addr - 0xA0000);
+ }
+ else
+ {
+ // LFB write while in banked mode -> ignore
+ return;
+ }
+ }
+
+ // check for out of memory write
+ if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
+ {
+ BX_VGA_THIS s.vbe_memory[offset]=value;
+ }
+ else
+ {
+ // make sure we don't flood the logfile
+ static int count=0;
+ if (count<100)
+ {
+ count ++;
+ BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
+ }
+ }
+
+ offset-=BX_VGA_THIS s.vbe_virtual_start;
+
+ // only update the UI when writing 'onscreen'
+ if (offset < BX_VGA_THIS s.vbe_visable_screen_size)
+ {
+ y_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) / BX_VGA_THIS s.vbe_virtual_xres) / Y_TILESIZE;
+ x_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) % BX_VGA_THIS s.vbe_virtual_xres) / X_TILESIZE;
+
+ if ((y_tileno < BX_NUM_Y_TILES) && (x_tileno < BX_NUM_X_TILES))
+ {
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+ }
+ }
+}
+
+ Bit32u
+bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ return( class_ptr->vbe_read(address, io_len) );
+}
+
+
+ Bit32u
+bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif // !BX_USE_VGA_SMF
+
+// BX_INFO(("VBE_read %x (len %x)", address, io_len));
+
+ if ((address==VBE_DISPI_IOPORT_INDEX) ||
+ (address==VBE_DISPI_IOPORT_INDEX_OLD))
+ {
+ // index register
+ return (Bit32u) BX_VGA_THIS s.vbe_curindex;
+ }
+ else
+ {
+ // data register read
+
+ switch (BX_VGA_THIS s.vbe_curindex)
+ {
+ case VBE_DISPI_INDEX_ID: // Display Interface ID check
+ {
+ return BX_VGA_THIS s.vbe_cur_dispi;
+ } break;
+
+ case VBE_DISPI_INDEX_XRES: // x resolution
+ {
+ return BX_VGA_THIS s.vbe_xres;
+ } break;
+
+ case VBE_DISPI_INDEX_YRES: // y resolution
+ {
+ return BX_VGA_THIS s.vbe_yres;
+ } break;
+
+ case VBE_DISPI_INDEX_BPP: // bpp
+ {
+ return BX_VGA_THIS s.vbe_bpp;
+ } break;
+
+ case VBE_DISPI_INDEX_ENABLE: // vbe enabled
+ {
+ return BX_VGA_THIS s.vbe_enabled;
+ } break;
+
+ case VBE_DISPI_INDEX_BANK: // current bank
+ {
+ return BX_VGA_THIS s.vbe_bank;
+ } break;
+
+ case VBE_DISPI_INDEX_X_OFFSET:
+ {
+ return BX_VGA_THIS s.vbe_offset_x;
+ } break;
+
+ case VBE_DISPI_INDEX_Y_OFFSET:
+ {
+ return BX_VGA_THIS s.vbe_offset_y;
+ } break;
+
+ case VBE_DISPI_INDEX_VIRT_WIDTH:
+ {
+ return BX_VGA_THIS s.vbe_virtual_xres;
+
+ } break;
+
+ case VBE_DISPI_INDEX_VIRT_HEIGHT:
+ {
+ return BX_VGA_THIS s.vbe_virtual_yres;
+ } break;
+
+
+ default:
+ {
+ BX_PANIC(("VBE unknown data read index 0x%x",BX_VGA_THIS s.vbe_curindex));
+ } break;
+ }
+ }
+ BX_PANIC(("VBE_read shouldn't reach this"));
+ return 0; /* keep compiler happy */
+}
+
+ void
+bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+ bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+ class_ptr->vbe_write(address, value, io_len);
+}
+
+ Bit32u
+bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+ UNUSED(this_ptr);
+#endif
+
+// BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
+
+ switch(address)
+ {
+ // index register
+ case VBE_DISPI_IOPORT_INDEX:
+ // legacy index register
+ case VBE_DISPI_IOPORT_INDEX_OLD:
+
+ BX_VGA_THIS s.vbe_curindex = (Bit16u) value;
+ break;
+
+ // data register
+ // FIXME: maybe do some 'sanity' checks on received data?
+ case VBE_DISPI_IOPORT_DATA:
+ // legacy data register
+ case VBE_DISPI_IOPORT_DATA_OLD:
+ switch (BX_VGA_THIS s.vbe_curindex)
+ {
+ case VBE_DISPI_INDEX_ID: // Display Interface ID check
+ {
+ if ( (value == VBE_DISPI_ID0) ||
+ (value == VBE_DISPI_ID1) ||
+ (value == VBE_DISPI_ID2) )
+ {
+ // allow backwards compatible with previous dispi bioses
+ BX_VGA_THIS s.vbe_cur_dispi=value;
+ }
+ else
+ {
+ BX_PANIC(("VBE unknown Display Interface %x",value));
+ }
+
+ // make sure we don't flood the logfile
+ static int count=0;
+ if (count < 100)
+ {
+ count++;
+ BX_INFO(("VBE known Display Interface %x",value));
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_XRES: // set xres
+ {
+ // check that we don't set xres during vbe enabled
+ if (!BX_VGA_THIS s.vbe_enabled)
+ {
+ // check for within max xres range
+ if (value <= VBE_DISPI_MAX_XRES)
+ {
+ BX_VGA_THIS s.vbe_xres=(Bit16u) value;
+ BX_INFO(("VBE set xres (%d)",value));
+ }
+ else
+ {
+ BX_INFO(("VBE set xres more then max xres (%d)",value));
+ }
+ }
+ else
+ {
+ BX_INFO(("VBE set xres during vbe enabled!"));
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_YRES: // set yres
+ {
+ // check that we don't set yres during vbe enabled
+ if (!BX_VGA_THIS s.vbe_enabled)
+ {
+ // check for within max yres range
+ if (value <= VBE_DISPI_MAX_YRES)
+ {
+ BX_VGA_THIS s.vbe_yres=(Bit16u) value;
+ BX_INFO(("VBE set yres (%d)",value));
+ }
+ else
+ {
+ BX_INFO(("VBE set yres more then max yres (%d)",value));
+ }
+ }
+ else
+ {
+ BX_INFO(("VBE set yres during vbe enabled!"));
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_BPP: // set bpp
+ {
+ // check that we don't set bpp during vbe enabled
+ if (!BX_VGA_THIS s.vbe_enabled)
+ {
+ // for backward compatiblity
+ if (value == 0) value = VBE_DISPI_BPP_8;
+ // check for correct bpp range
+ if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
+ (value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
+ {
+ BX_VGA_THIS s.vbe_bpp=(Bit16u) value;
+ BX_INFO(("VBE set bpp (%d)",value));
+ }
+ else
+ {
+ BX_INFO(("VBE set bpp with unknown bpp (%d)",value));
+ }
+ }
+ else
+ {
+ BX_INFO(("VBE set bpp during vbe enabled!"));
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_BANK: // set bank
+ {
+ value=value & 0xff ; // FIXME lobyte = vbe bank A?
+
+ // check for max bank nr
+ if (value < (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB /64))
+ {
+ if (!BX_VGA_THIS s.vbe_lfb_enabled)
+ {
+ BX_DEBUG(("VBE set bank to %d", value));
+ BX_VGA_THIS s.vbe_bank=value;
+ }
+ else
+ {
+ BX_ERROR(("VBE set bank in LFB mode ignored"));
+ }
+ }
+ else
+ {
+ BX_INFO(("VBE set invalid bank (%d)",value));
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_ENABLE: // enable video
+ {
+ if (value & VBE_DISPI_ENABLED)
+ {
+ unsigned depth=0;
+
+ // setup virtual resolution to be the same as current reso
+ BX_VGA_THIS s.vbe_virtual_yres=BX_VGA_THIS s.vbe_yres;
+ BX_VGA_THIS s.vbe_virtual_xres=BX_VGA_THIS s.vbe_xres;
+
+ // reset offset
+ BX_VGA_THIS s.vbe_offset_x=0;
+ BX_VGA_THIS s.vbe_offset_y=0;
+ BX_VGA_THIS s.vbe_virtual_start=0;
+
+ switch((BX_VGA_THIS s.vbe_bpp))
+ {
+ // Default pixel sizes
+ case VBE_DISPI_BPP_8:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 1;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres));
+ depth=8;
+ break;
+
+ case VBE_DISPI_BPP_4:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 1;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres));
+ depth=4;
+ break;
+
+ case VBE_DISPI_BPP_15:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 2;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 2;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 2;
+ depth=15;
+ break;
+
+ case VBE_DISPI_BPP_16:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 2;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 2;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 2;
+ depth=16;
+ break;
+
+ case VBE_DISPI_BPP_24:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 3;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 3;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 3;
+ depth=24;
+ break;
+
+ case VBE_DISPI_BPP_32:
+ BX_VGA_THIS s.vbe_bpp_multiplier = 4;
+ BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres << 2;
+ BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) << 2;
+ depth=32;
+ break;
+ }
+
+ BX_INFO(("VBE enabling x %d, y %d, bpp %d, %u bytes visible", BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, BX_VGA_THIS s.vbe_bpp, BX_VGA_THIS s.vbe_visable_screen_size));
+
+ if (depth > 4)
+ {
+ BX_VGA_THIS s.vbe_lfb_enabled=(bx_bool)(value & VBE_DISPI_LFB_ENABLED);
+ if ((value & VBE_DISPI_NOCLEARMEM) == 0)
+ {
+ memset(BX_VGA_THIS s.vbe_memory, 0, BX_VGA_THIS s.vbe_visable_screen_size);
+ }
+ bx_gui->dimension_update(BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, 0, 0, depth);
+ old_BPP = depth;
+ // some test applications expect these standard VGA settings
+ BX_VGA_THIS s.CRTC.reg[9] = 0x00;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 1;
+ BX_VGA_THIS s.graphics_ctrl.memory_mapping = 1;
+ BX_VGA_THIS s.CRTC.reg[1] = (BX_VGA_THIS s.vbe_xres / 8) - 1;
+ BX_VGA_THIS s.CRTC.reg[19] = BX_VGA_THIS s.vbe_xres >> 2;
+ BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 1;
+ BX_VGA_THIS s.CRTC.reg[18] = (BX_VGA_THIS s.vbe_yres - 1) & 0xff;
+ BX_VGA_THIS s.CRTC.reg[7] &= ~0x42;
+ if ((BX_VGA_THIS s.vbe_yres - 1) & 0x0100) {
+ BX_VGA_THIS s.CRTC.reg[7] |= 0x02;
+ }
+ if ((BX_VGA_THIS s.vbe_yres - 1) & 0x0200) {
+ BX_VGA_THIS s.CRTC.reg[7] |= 0x40;
+ }
+ }
+ }
+ else
+ {
+ if (BX_VGA_THIS s.vbe_enabled) BX_INFO(("VBE disabling"));
+ BX_VGA_THIS s.vbe_lfb_enabled=0;
+ }
+ BX_VGA_THIS s.vbe_enabled=(bx_bool)(value & VBE_DISPI_ENABLED);
+ } break;
+
+ case VBE_DISPI_INDEX_X_OFFSET:
+ {
+ // BX_INFO(("VBE offset x %x",value));
+ BX_VGA_THIS s.vbe_offset_x=(Bit16u)value;
+
+ BX_VGA_THIS s.vbe_virtual_start = ((BX_VGA_THIS s.vbe_offset_y) * (BX_VGA_THIS s.vbe_line_byte_width)) +
+ ((BX_VGA_THIS s.vbe_offset_x) * (BX_VGA_THIS s.vbe_bpp_multiplier));
+
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+ for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+ SET_TILE_UPDATED (xti, yti, 1);
+ }
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_Y_OFFSET:
+ {
+ // BX_INFO(("VBE offset y %x",value));
+ BX_VGA_THIS s.vbe_offset_y=(Bit16u)value;
+ BX_VGA_THIS s.vbe_virtual_start = ((BX_VGA_THIS s.vbe_offset_y) * (BX_VGA_THIS s.vbe_line_byte_width)) +
+ ((BX_VGA_THIS s.vbe_offset_x) * (BX_VGA_THIS s.vbe_bpp_multiplier));
+
+ BX_VGA_THIS s.vga_mem_updated = 1;
+ for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+ for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+ SET_TILE_UPDATED (xti, yti, 1);
+ }
+ }
+ } break;
+
+ case VBE_DISPI_INDEX_VIRT_WIDTH:
+ {
+ BX_INFO(("VBE requested virtual width %d",value));
+
+ // calculate virtual width & height dimensions
+ // req:
+ // virt_width > xres
+ // virt_height >=yres
+ // virt_width*virt_height < MAX_VIDEO_MEMORY
+
+ // basicly 2 situations
+
+ // situation 1:
+ // MAX_VIDEO_MEMORY / virt_width >= yres
+ // adjust result height
+ // else
+ // adjust result width based upon virt_height=yres
+ Bit16u new_width=value;
+ Bit16u new_height=(sizeof(BX_VGA_THIS s.vbe_memory) / BX_VGA_THIS s.vbe_bpp_multiplier) / new_width;
+ if (new_height >=BX_VGA_THIS s.vbe_yres)
+ {
+ // we have a decent virtual width & new_height
+ BX_INFO(("VBE decent virtual height %d",new_height));
+ }
+ else
+ {
+ // no decent virtual height: adjust width & height
+ new_height=BX_VGA_THIS s.vbe_yres;
+ new_width=(sizeof(BX_VGA_THIS s.vbe_memory) / BX_VGA_THIS s.vbe_bpp_multiplier) / new_height;
+
+ BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
+ }
+
+ BX_VGA_THIS s.vbe_virtual_xres=new_width;
+ BX_VGA_THIS s.vbe_virtual_yres=new_height;
+ BX_VGA_THIS s.vbe_visable_screen_size = (new_width * (BX_VGA_THIS s.vbe_yres)) * BX_VGA_THIS s.vbe_bpp_multiplier;
+
+ } break;
+ /*
+ case VBE_DISPI_INDEX_VIRT_HEIGHT:
+ {
+ BX_INFO(("VBE virtual height %x",value));
+
+ } break;
+ */
+ default:
+ {
+ BX_PANIC(("VBE unknown data write index 0x%x",BX_VGA_THIS s.vbe_curindex));
+ } break;
+ }
+ break;
+
+ } // end switch address
+}
+
+#endif
diff --git a/tools/ioemu/iodev/vga.h b/tools/ioemu/iodev/vga.h
new file mode 100644
index 0000000000..cafb60cd6b
--- /dev/null
+++ b/tools/ioemu/iodev/vga.h
@@ -0,0 +1,300 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.h,v 1.36 2003/12/31 10:33:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#if BX_SUPPORT_VBE
+ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
+
+ #define VBE_DISPI_BANK_ADDRESS 0xA0000
+ #define VBE_DISPI_BANK_SIZE_KB 64
+
+ #define VBE_DISPI_MAX_XRES 1024
+ #define VBE_DISPI_MAX_YRES 768
+
+ #define VBE_DISPI_IOPORT_INDEX 0x01CE
+ #define VBE_DISPI_IOPORT_DATA 0x01CF
+
+ #define VBE_DISPI_IOPORT_INDEX_OLD 0xFF80
+ #define VBE_DISPI_IOPORT_DATA_OLD 0xFF81
+
+ #define VBE_DISPI_INDEX_ID 0x0
+ #define VBE_DISPI_INDEX_XRES 0x1
+ #define VBE_DISPI_INDEX_YRES 0x2
+ #define VBE_DISPI_INDEX_BPP 0x3
+ #define VBE_DISPI_INDEX_ENABLE 0x4
+ #define VBE_DISPI_INDEX_BANK 0x5
+ #define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+ #define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+ #define VBE_DISPI_INDEX_X_OFFSET 0x8
+ #define VBE_DISPI_INDEX_Y_OFFSET 0x9
+
+ #define VBE_DISPI_ID0 0xB0C0
+ #define VBE_DISPI_ID1 0xB0C1
+ #define VBE_DISPI_ID2 0xB0C2
+
+ #define VBE_DISPI_BPP_4 0x04
+ #define VBE_DISPI_BPP_8 0x08
+ #define VBE_DISPI_BPP_15 0x0F
+ #define VBE_DISPI_BPP_16 0x10
+ #define VBE_DISPI_BPP_24 0x18
+ #define VBE_DISPI_BPP_32 0x20
+
+ #define VBE_DISPI_DISABLED 0x00
+ #define VBE_DISPI_ENABLED 0x01
+ #define VBE_DISPI_NOCLEARMEM 0x80
+ #define VBE_DISPI_LFB_ENABLED 0x40
+
+ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_KB (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB * 1024)
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB * 1024)
+
+#define BX_MAX_XRES VBE_DISPI_MAX_XRES
+#define BX_MAX_YRES VBE_DISPI_MAX_YRES
+
+#else
+
+#define BX_MAX_XRES 800
+#define BX_MAX_YRES 600
+
+#endif //BX_SUPPORT_VBE
+
+#define X_TILESIZE 16
+#define Y_TILESIZE 24
+#define BX_NUM_X_TILES (BX_MAX_XRES /X_TILESIZE)
+#define BX_NUM_Y_TILES (BX_MAX_YRES /Y_TILESIZE)
+
+// Support varying number of rows of text. This used to
+// be limited to only 25 lines.
+#define BX_MAX_TEXT_LINES 100
+
+#if BX_USE_VGA_SMF
+# define BX_VGA_SMF static
+# define BX_VGA_THIS theVga->
+#else
+# define BX_VGA_SMF
+# define BX_VGA_THIS this->
+#endif
+
+
+class bx_vga_c : public bx_vga_stub_c {
+public:
+
+ bx_vga_c(void);
+ ~bx_vga_c(void);
+ virtual void init(void);
+ virtual void bios_init(void);
+ virtual void reset(unsigned type);
+ virtual Bit8u mem_read(Bit32u addr);
+ // Note: either leave value of type Bit8u, or mask it when
+ // used to 8 bits, in memory.cc
+ virtual void mem_write(Bit32u addr, Bit8u value);
+ virtual void trigger_timer(void *this_ptr);
+
+#if BX_SUPPORT_VBE
+ BX_VGA_SMF Bit8u vbe_mem_read(Bit32u addr) BX_CPP_AttrRegparmN(1);
+ BX_VGA_SMF void vbe_mem_write(Bit32u addr, Bit8u value) BX_CPP_AttrRegparmN(2);
+#endif
+
+ virtual void redraw_area(unsigned x0, unsigned y0,
+ unsigned width, unsigned height);
+
+ virtual void set_update_interval (unsigned interval);
+ virtual void get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
+ unsigned *txWidth);
+ virtual Bit8u get_actl_palette_idx(Bit8u index);
+
+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);
+ static void write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+
+#if BX_SUPPORT_VBE
+ static Bit32u vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+ static void vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+ struct {
+ struct {
+ bx_bool color_emulation; // 1=color emulation, base address = 3Dx
+ // 0=mono emulation, base address = 3Bx
+ bx_bool enable_ram; // enable CPU access to video memory if set
+ Bit8u clock_select; // 0=25Mhz 1=28Mhz
+ bx_bool select_high_bank; // when in odd/even modes, select
+ // high 64k bank if set
+ bx_bool horiz_sync_pol; // bit6: negative if set
+ bx_bool vert_sync_pol; // bit7: negative if set
+ // bit7,bit6 represent number of lines on display:
+ // 0 = reserved
+ // 1 = 400 lines
+ // 2 = 350 lines
+ // 3 - 480 lines
+ } misc_output;
+
+ struct {
+ Bit8u address;
+ Bit8u reg[0x19];
+ } CRTC;
+
+ struct {
+ bx_bool flip_flop; /* 0 = address, 1 = data-write */
+ unsigned address; /* register number */
+ bx_bool video_enabled;
+ Bit8u palette_reg[16];
+ Bit8u overscan_color;
+ Bit8u color_plane_enable;
+ Bit8u horiz_pel_panning;
+ Bit8u color_select;
+ struct {
+ bx_bool graphics_alpha;
+ bx_bool display_type;
+ bx_bool enable_line_graphics;
+ bx_bool blink_intensity;
+ bx_bool pixel_panning_compat;
+ bx_bool pixel_clock_select;
+ bx_bool internal_palette_size;
+ } mode_ctrl;
+ } attribute_ctrl;
+
+ struct {
+ Bit8u write_data_register;
+ Bit8u write_data_cycle; /* 0, 1, 2 */
+ Bit8u read_data_register;
+ Bit8u read_data_cycle; /* 0, 1, 2 */
+ Bit8u dac_state;
+ struct {
+ Bit8u red;
+ Bit8u green;
+ Bit8u blue;
+ } data[256];
+ Bit8u mask;
+ } pel;
+
+
+ struct {
+ Bit8u index;
+ Bit8u set_reset;
+ Bit8u enable_set_reset;
+ Bit8u color_compare;
+ Bit8u data_rotate;
+ Bit8u raster_op;
+ Bit8u read_map_select;
+ Bit8u write_mode;
+ bx_bool read_mode;
+ bx_bool odd_even;
+ bx_bool chain_odd_even;
+ Bit8u shift_reg;
+ bx_bool graphics_alpha;
+ Bit8u memory_mapping; /* 0 = use A0000-BFFFF
+ * 1 = use A0000-AFFFF EGA/VGA graphics modes
+ * 2 = use B0000-B7FFF Monochrome modes
+ * 3 = use B8000-BFFFF CGA modes
+ */
+ Bit8u color_dont_care;
+ Bit8u bitmask;
+ Bit8u latch[4];
+ } graphics_ctrl;
+
+ struct {
+ Bit8u index;
+ Bit8u map_mask;
+ bx_bool map_mask_bit[4];
+ bx_bool reset1;
+ bx_bool reset2;
+ Bit8u reg1;
+ Bit8u char_map_select;
+ bx_bool extended_mem;
+ bx_bool odd_even;
+ bx_bool chain_four;
+ } sequencer;
+
+ bx_bool vga_mem_updated;
+ unsigned x_tilesize;
+ unsigned y_tilesize;
+ unsigned line_offset;
+ unsigned line_compare;
+ unsigned vertical_display_end;
+ bx_bool vga_tile_updated[BX_NUM_X_TILES][BX_NUM_Y_TILES];
+ Bit8u vga_memory[256 * 1024];
+ Bit8u text_snapshot[32 * 1024]; // current text snapshot
+ Bit8u rgb[3 * 256];
+ Bit8u tile[X_TILESIZE * Y_TILESIZE * 4]; /**< Currently allocates the tile as large as needed. */
+ Bit16u charmap_address;
+ bx_bool x_dotclockdiv2;
+ bx_bool y_doublescan;
+
+#if BX_SUPPORT_VBE
+ Bit8u vbe_memory[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
+ Bit16u vbe_cur_dispi;
+ Bit16u vbe_xres;
+ Bit16u vbe_yres;
+ Bit16u vbe_bpp;
+ Bit16u vbe_bank;
+ bx_bool vbe_enabled;
+ Bit16u vbe_curindex;
+ Bit32u vbe_visable_screen_size; /**< in bytes */
+ Bit16u vbe_offset_x; /**< Virtual screen x start (in pixels) */
+ Bit16u vbe_offset_y; /**< Virtual screen y start (in pixels) */
+ Bit16u vbe_virtual_xres;
+ Bit16u vbe_virtual_yres;
+ Bit16u vbe_line_byte_width; /**< For dealing with bpp>8, this is they width of a line in bytes. */
+ Bit32u vbe_virtual_start; /**< For dealing with bpp>8, this is where the virtual screen starts. */
+ Bit8u vbe_bpp_multiplier; /**< We have to save this b/c sometimes we need to recalculate stuff with it. */
+ bx_bool vbe_lfb_enabled;
+#endif
+ } s; // state information
+
+
+#if !BX_USE_VGA_SMF
+ Bit32u read(Bit32u address, unsigned io_len);
+ void write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#else
+ void write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#endif
+
+#if BX_SUPPORT_VBE
+
+#if !BX_USE_VGA_SMF
+ Bit32u vbe_read(Bit32u address, unsigned io_len);
+ void vbe_write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#else
+ void vbe_write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#endif
+#endif
+
+ int timer_id;
+
+ public:
+ static void timer_handler(void *);
+ BX_VGA_SMF void timer(void);
+
+ private:
+ BX_VGA_SMF void update(void);
+ BX_VGA_SMF void dump_status(void);
+ BX_VGA_SMF void determine_screen_dimensions(unsigned *piHeight,
+ unsigned *piWidth);
+ };
diff --git a/tools/ioemu/iodev/virt_timer.cc b/tools/ioemu/iodev/virt_timer.cc
new file mode 100644
index 0000000000..eb108a025b
--- /dev/null
+++ b/tools/ioemu/iodev/virt_timer.cc
@@ -0,0 +1,552 @@
+////////////////////////////////////////////////////////////////////////
+// $Id: virt_timer.cc,v 1.19.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+//Realtime Algorithm (with gettimeofday)
+// HAVE:
+// Real number of usec.
+// Emulated number of usec.
+// WANT:
+// Number of ticks to use.
+// Number of emulated usec to wait until next try.
+//
+// ticks=number of ticks needed to match total real usec.
+// if(desired ticks > max ticks for elapsed real time)
+// ticks = max ticks for elapsed real time.
+// if(desired ticks > max ticks for elapsed emulated usec)
+// ticks = max ticks for emulated usec.
+// next wait ticks = number of ticks until next event.
+// next wait real usec = (current ticks + next wait ticks) * usec per ticks
+// next wait emulated usec = next wait real usec * emulated usec / real usec
+// if(next wait emulated usec < minimum emulated usec for next wait ticks)
+// next wait emulated usec = minimum emulated usec for next wait ticks.
+// if(next wait emulated usec > max emulated usec wait)
+// next wait emulated usec = max emulated usec wait.
+//
+// How to calculate elapsed real time:
+// store an unused time value whenever no ticks are used in a given time.
+// add this to the current elapsed time.
+// How to calculate elapsed emulated time:
+// same as above.
+// Above can be done by not updating last_usec and last_sec.
+//
+// How to calculate emulated usec/real usec:
+// Each time there are actual ticks:
+// Alpha_product(old emulated usec, emulated usec);
+// Alpha_product(old real usec, real usec);
+// Divide resulting values.
+//
+/////////////////////////////////////////////////////////////////////////
+
+#include "bochs.h"
+
+#define BX_USE_VIRTUAL_TIMERS 1
+#define BX_VIRTUAL_TIMERS_REALTIME 1
+
+//Important constant #defines:
+#define USEC_PER_SECOND (1000000)
+
+
+// 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))
+
+//CONFIGURATION #defines:
+
+
+//MAINLINE Configuration (For realtime PIT):
+
+//How much faster than real time we can go:
+#define MAX_MULT (1.25)
+
+//Minimum number of emulated useconds per second.
+// Now calculated using BX_MIN_IPS, the minimum number of
+// instructions per second.
+#define MIN_USEC_PER_SECOND (((((Bit64u)USEC_PER_SECOND)*((Bit64u)BX_MIN_IPS))/((Bit64u)(bx_options.Oips->get())))+(Bit64u)1)
+
+
+//DEBUG configuration:
+
+//Debug with printf options.
+#define DEBUG_REALTIME_WITH_PRINTF 0
+
+//Use to test execution at multiples of real time.
+#define TIME_DIVIDER (1)
+#define TIME_MULTIPLIER (1)
+#define TIME_HEADSTART (0)
+
+
+#define GET_VIRT_REALTIME64_USEC() (((bx_get_realtime64_usec()*(Bit64u)TIME_MULTIPLIER/(Bit64u)TIME_DIVIDER)))
+//Set up Logging.
+#define LOG_THIS bx_virt_timer.
+
+//A single instance.
+bx_virt_timer_c bx_virt_timer;
+
+
+//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))))))
+
+
+//Conversion between emulated useconds and optionally realtime ticks.
+#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_virt_timer_c::bx_virt_timer_c( void )
+{
+ put("VTIMER");
+ settype(VTIMERLOG);
+
+ numTimers = 0;
+ current_timers_time = 0;
+ timers_next_event_time = BX_MAX_VIRTUAL_TIME;
+ last_sequential_time = 0;
+ in_timer_handler = 0;
+ virtual_next_event_time = BX_MAX_VIRTUAL_TIME;
+ current_virtual_time = 0;
+
+ use_virtual_timers = BX_USE_VIRTUAL_TIMERS;
+ init_done = 0;
+}
+
+bx_virt_timer_c::~bx_virt_timer_c( void )
+{
+}
+
+
+
+const Bit64u bx_virt_timer_c::NullTimerInterval = BX_MAX_VIRTUAL_TIME;
+
+void
+bx_virt_timer_c::nullTimer(void* this_ptr) {
+ UNUSED(this_ptr);
+}
+
+void
+bx_virt_timer_c::periodic(Bit64u time_passed) {
+ //Assert that we haven't skipped any events.
+ BX_ASSERT (time_passed <= timers_next_event_time);
+ BX_ASSERT(!in_timer_handler);
+
+ //Update time variables.
+ timers_next_event_time -= time_passed;
+ current_timers_time += time_passed;
+
+ //If no events are occurring, just pass the time and we're done.
+ if( time_passed < timers_next_event_time ) {
+ return;
+ }
+ //Starting timer handler calls.
+ in_timer_handler = 1;
+ //Otherwise, cause any events to occur that should.
+ unsigned i;
+ for(i=0;i<numTimers;i++) {
+ if( timer[i].inUse && timer[i].active ) {
+ //Assert that we haven't skipped any timers.
+ BX_ASSERT(current_timers_time <= timer[i].timeToFire);
+ if(timer[i].timeToFire == current_timers_time) {
+ if(timer[i].continuous) {
+ timer[i].timeToFire+=timer[i].period;
+ } else {
+ timer[i].active = 0;
+ }
+ //This function MUST return, or the timer mechanism
+ // will be broken.
+ timer[i].funct(timer[i].this_ptr);
+ }
+ }
+ }
+ //Finished timer handler calls.
+ in_timer_handler = 0;
+ //Use a second FOR loop so that a timer function call can
+ // change the behavior of another timer.
+ //timers_next_event_time normally contains a cycle count, not a cycle time.
+ // here we use it as a temporary variable that IS a cycle time,
+ // but then convert it back to a cycle count afterwards.
+ timers_next_event_time = current_timers_time + BX_MAX_VIRTUAL_TIME;
+ for(i=0;i<numTimers;i++) {
+ if( timer[i].inUse && timer[i].active && ((timer[i].timeToFire)<timers_next_event_time) ) {
+ timers_next_event_time = timer[i].timeToFire;
+ }
+ }
+ timers_next_event_time-=current_timers_time;
+ next_event_time_update();
+ //FIXME
+}
+
+
+//Get the current virtual time.
+// This may return the same value on subsequent calls.
+Bit64u
+bx_virt_timer_c::time_usec(void) {
+ if(!use_virtual_timers) {
+ return bx_pc_system.time_usec();
+ }
+
+ //Update the time here only if we're not in a timer handler.
+ //If we're in a timer handler we're up-to-date, and otherwise
+ // this prevents call stack loops.
+ if(!in_timer_handler) {
+ timer_handler();
+ }
+
+ return current_timers_time;
+}
+
+//Get the current virtual time.
+// This will return a monotonically increasing value.
+// MUST NOT be called from within a timer interrupt.
+Bit64u
+bx_virt_timer_c::time_usec_sequential(void) {
+ if(!use_virtual_timers) {
+ return bx_pc_system.time_usec_sequential();
+ }
+
+ //Can't prevent call stack loops here, so this
+ // MUST NOT be called from within a timer handler.
+ BX_ASSERT(timers_next_event_time>0);
+ BX_ASSERT(!in_timer_handler);
+
+ if(last_sequential_time >= current_timers_time) {
+ periodic(1);
+ last_sequential_time = current_timers_time;
+ }
+ return current_timers_time;
+}
+
+
+
+//Register a timer handler to go off after a given interval.
+//Register a timer handler to go off with a periodic interval.
+int
+bx_virt_timer_c::register_timer( void *this_ptr, bx_timer_handler_t handler,
+ Bit32u useconds,
+ bx_bool continuous, bx_bool active,
+ const char *id) {
+ if(!use_virtual_timers) {
+ return bx_pc_system.register_timer(this_ptr, handler, useconds,
+ continuous, active, id);
+ }
+
+ //We don't like starting with a zero period timer.
+ BX_ASSERT((!active) || (useconds>0));
+
+ //Search for an unused timer.
+ unsigned int i;
+ for (i=0; i < numTimers; i++) {
+ if (timer[i].inUse == 0 || i==numTimers)
+ break;
+ }
+ // If we didn't find a free slot, increment the bound, numTimers.
+ if (i==numTimers)
+ numTimers++; // One new timer installed.
+ BX_ASSERT(numTimers<BX_MAX_VIRTUAL_TIMERS);
+
+ timer[i].inUse = 1;
+ timer[i].period = useconds;
+ timer[i].timeToFire = current_timers_time + (Bit64u)useconds;
+ timer[i].active = active;
+ timer[i].continuous = continuous;
+ timer[i].funct = handler;
+ timer[i].this_ptr = this_ptr;
+ strncpy(timer[i].id, id, BxMaxTimerIDLen);
+ timer[i].id[BxMaxTimerIDLen-1]=0; //I like null terminated strings.
+
+ if(useconds < timers_next_event_time) {
+ timers_next_event_time = useconds;
+ next_event_time_update();
+ //FIXME
+ }
+ return i;
+}
+
+//unregister a previously registered timer.
+unsigned
+bx_virt_timer_c::unregisterTimer(int timerID) {
+ if(!use_virtual_timers) {
+ return bx_pc_system.unregisterTimer(timerID);
+ }
+
+ BX_ASSERT(timerID >= 0);
+ BX_ASSERT(timerID < BX_MAX_VIRTUAL_TIMERS);
+
+ if (timer[timerID].active) {
+ BX_PANIC(("unregisterTimer: timer '%s' is still active!", timer[timerID].id));
+ return(0); // Fail.
+ }
+
+
+ //No need to prevent doing this to unused timers.
+ timer[timerID].inUse = 0;
+ return(1);
+}
+
+void
+bx_virt_timer_c::start_timers(void) {
+ if(!use_virtual_timers) {
+ bx_pc_system.start_timers();
+ return;
+ }
+ //FIXME
+}
+
+//activate a deactivated but registered timer.
+void
+bx_virt_timer_c::activate_timer( unsigned timer_index, Bit32u useconds,
+ bx_bool continuous ) {
+ if(!use_virtual_timers) {
+ bx_pc_system.activate_timer(timer_index, useconds, continuous);
+ return;
+ }
+
+ BX_ASSERT(timer_index >= 0);
+ BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
+
+ BX_ASSERT(timer[timer_index].inUse);
+ BX_ASSERT(useconds>0);
+
+ timer[timer_index].period=useconds;
+ timer[timer_index].timeToFire = current_timers_time + (Bit64u)useconds;
+ timer[timer_index].active=1;
+ timer[timer_index].continuous=continuous;
+
+ if(useconds < timers_next_event_time) {
+ timers_next_event_time = useconds;
+ next_event_time_update();
+ //FIXME
+ }
+}
+
+//deactivate (but don't unregister) a currently registered timer.
+void
+bx_virt_timer_c::deactivate_timer( unsigned timer_index ) {
+ if(!use_virtual_timers) {
+ bx_pc_system.deactivate_timer(timer_index);
+ return;
+ }
+
+ BX_ASSERT(timer_index >= 0);
+ BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
+
+ //No need to prevent doing this to unused/inactive timers.
+ timer[timer_index].active = 0;
+}
+
+void
+bx_virt_timer_c::advance_virtual_time(Bit64u time_passed) {
+ BX_ASSERT(time_passed <= virtual_next_event_time);
+
+ current_virtual_time += time_passed;
+ virtual_next_event_time -= time_passed;
+
+ if(current_virtual_time > current_timers_time) {
+ periodic(current_virtual_time - current_timers_time);
+ }
+}
+
+//Called when next_event_time changes.
+void
+bx_virt_timer_c::next_event_time_update(void) {
+ virtual_next_event_time = timers_next_event_time + current_timers_time - current_virtual_time;
+ if(init_done) {
+ bx_pc_system.deactivate_timer(system_timer_id);
+ BX_ASSERT(virtual_next_event_time);
+ bx_pc_system.activate_timer(system_timer_id,
+ (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))),
+ 0);
+ }
+}
+
+void
+bx_virt_timer_c::init(void) {
+
+ if ( (bx_options.clock.Osync->get ()!=BX_CLOCK_SYNC_REALTIME)
+ && (bx_options.clock.Osync->get ()!=BX_CLOCK_SYNC_BOTH) )
+ virtual_timers_realtime = 0;
+ else
+ virtual_timers_realtime = 1;
+
+ if (virtual_timers_realtime) {
+ BX_INFO(("using 'realtime pit' synchronization method"));
+ }
+
+ register_timer(this, nullTimer, (Bit32u)NullTimerInterval, 1, 1, "Null Timer");
+
+ system_timer_id = bx_pc_system.register_timer(this, pc_system_timer_handler,virtual_next_event_time , 0, 1, "Virtual Timer");
+
+ //Real time variables:
+#if BX_HAVE_REALTIME_USEC
+ last_real_time=GET_VIRT_REALTIME64_USEC()+(Bit64u)TIME_HEADSTART*(Bit64u)USEC_PER_SECOND;
+#endif
+ total_real_usec=0;
+ last_realtime_delta=0;
+ //System time variables:
+ last_usec = 0
+;
+ usec_per_second = USEC_PER_SECOND;
+ stored_delta=0;
+ last_system_usec=0;
+ em_last_realtime=0;
+ //Virtual timer variables:
+ total_ticks=0;
+ last_realtime_ticks=0;
+ ticks_per_second = USEC_PER_SECOND;
+
+ init_done = 1;
+}
+
+void
+bx_virt_timer_c::timer_handler(void) {
+ if(!virtual_timers_realtime) {
+ Bit64u temp_final_time = bx_pc_system.time_usec();
+ temp_final_time-=current_virtual_time;
+ while(temp_final_time) {
+ if((temp_final_time)>(virtual_next_event_time)) {
+ temp_final_time-=virtual_next_event_time;
+ advance_virtual_time(virtual_next_event_time);
+ } else {
+ advance_virtual_time(temp_final_time);
+ temp_final_time-=temp_final_time;
+ }
+ }
+ bx_pc_system.activate_timer(system_timer_id,
+ (Bit32u)BX_MIN(0x7FFFFFFF,(virtual_next_event_time>2)?(virtual_next_event_time-2):1),
+ 0);
+ return;
+ }
+
+ Bit64u usec_delta = bx_pc_system.time_usec()-last_usec;
+
+ if (usec_delta) {
+#if BX_HAVE_REALTIME_USEC
+ Bit64u ticks_delta = 0;
+ Bit64u real_time_delta = GET_VIRT_REALTIME64_USEC() - last_real_time;
+ Bit64u real_time_total = real_time_delta + total_real_usec;
+ Bit64u system_time_delta = (Bit64u)usec_delta + (Bit64u)stored_delta;
+ if(real_time_delta) {
+ last_realtime_delta = real_time_delta;
+ last_realtime_ticks = total_ticks;
+ }
+ ticks_per_second = USEC_PER_SECOND;
+
+ //Start out with the number of ticks we would like
+ // to have to line up with real time.
+ ticks_delta = real_time_total - total_ticks;
+ if(real_time_total < total_ticks) {
+ //This slows us down if we're already ahead.
+ // probably only an issue on startup, but it solves some problems.
+ ticks_delta = 0;
+ }
+ if(ticks_delta + total_ticks - last_realtime_ticks > (F2I(MAX_MULT * I2F(last_realtime_delta)))) {
+ //This keeps us from going too fast in relation to real time.
+#if 0
+ ticks_delta = (F2I(MAX_MULT * I2F(last_realtime_delta))) + last_realtime_ticks - total_ticks;
+#endif
+ ticks_per_second = F2I(MAX_MULT * I2F(USEC_PER_SECOND));
+ }
+ if(ticks_delta > system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND) {
+ //This keeps us from having too few instructions between ticks.
+ ticks_delta = system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND;
+ }
+ if(ticks_delta > virtual_next_event_time) {
+ //This keeps us from missing ticks.
+ ticks_delta = virtual_next_event_time;
+ }
+
+ if(ticks_delta) {
+
+# if DEBUG_REALTIME_WITH_PRINTF
+ //Every second print some info.
+ if(((last_real_time + real_time_delta) / USEC_PER_SECOND) > (last_real_time / USEC_PER_SECOND)) {
+ Bit64u temp1, temp2, temp3, temp4;
+ temp1 = (Bit64u) total_real_usec;
+ temp2 = (total_real_usec);
+ temp3 = (Bit64u)total_ticks;
+ temp4 = (Bit64u)((total_real_usec) - total_ticks);
+ printf("useconds: %llu, ",temp1);
+ printf("expect ticks: %llu, ",temp2);
+ printf("ticks: %llu, ",temp3);
+ printf("diff: %llu\n",temp4);
+ }
+# endif
+
+ last_real_time += real_time_delta;
+ total_real_usec += real_time_delta;
+ last_system_usec += system_time_delta;
+ stored_delta = 0;
+ total_ticks += ticks_delta;
+ } else {
+ stored_delta = system_time_delta;
+ }
+
+
+ Bit64u a,b;
+ a=(usec_per_second);
+ if(real_time_delta) {
+ //FIXME
+ Bit64u em_realtime_delta = last_system_usec + stored_delta - em_last_realtime;
+ b=((Bit64u)USEC_PER_SECOND * em_realtime_delta / real_time_delta);
+ em_last_realtime = last_system_usec + stored_delta;
+ } else {
+ b=a;
+ }
+ usec_per_second = ALPHA_LOWER(a,b);
+#else
+ BX_ASSERT(0);
+#endif
+#if BX_HAVE_REALTIME_USEC
+ advance_virtual_time(ticks_delta);
+#endif
+ }
+
+ last_usec=last_usec + usec_delta;
+ bx_pc_system.deactivate_timer(system_timer_id);
+ BX_ASSERT(virtual_next_event_time);
+ bx_pc_system.activate_timer(system_timer_id,
+ (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))),
+ 0);
+
+}
+
+void
+bx_virt_timer_c::pc_system_timer_handler(void* this_ptr) {
+ ((bx_virt_timer_c *)this_ptr)->timer_handler();
+}
+
diff --git a/tools/ioemu/iodev/virt_timer.h b/tools/ioemu/iodev/virt_timer.h
new file mode 100644
index 0000000000..a10b16cd0e
--- /dev/null
+++ b/tools/ioemu/iodev/virt_timer.h
@@ -0,0 +1,131 @@
+
+#ifndef _BX_VIRT_TIMER_H
+#define _BX_VIRT_TIMER_H
+
+
+#define BX_MAX_VIRTUAL_TIMERS (15+BX_SMP_PROCESSORS)
+#define BX_NULL_VIRTUAL_TIMER_HANDLE 10000
+
+#define BX_MAX_VIRTUAL_TIME (0x7fffffff)
+
+class bx_virt_timer_c : public logfunctions {
+ private:
+
+ struct {
+ bx_bool inUse; // Timer slot is in-use (currently registered).
+ Bit64u period; // Timer periodocity in virtual useconds.
+ Bit64u timeToFire; // Time to fire next (in virtual useconds).
+ bx_bool active; // 0=inactive, 1=active.
+ bx_bool continuous; // 0=one-shot timer, 1=continuous periodicity.
+ bx_timer_handler_t funct; // A callback function for when the
+ // timer fires.
+ // This function MUST return.
+ void *this_ptr; // The this-> pointer for C++ callbacks
+ // has to be stored as well.
+ char id[BxMaxTimerIDLen]; // String ID of timer.
+ } timer[BX_MAX_VIRTUAL_TIMERS];
+
+ unsigned numTimers; // Number of currently allocated timers.
+
+ //Variables for the timer subsystem:
+ Bit64u current_timers_time;
+ Bit64u timers_next_event_time;
+
+ Bit64u last_sequential_time;
+ bx_bool in_timer_handler;
+
+ //Variables for the time sync subsystem:
+ Bit64u virtual_next_event_time;
+ Bit64u current_virtual_time;
+
+ //Real time variables:
+ Bit64u last_real_time;
+ Bit64u total_real_usec;
+ Bit64u last_realtime_delta;
+ //System time variables:
+ Bit64u last_usec;
+ Bit64u usec_per_second;
+ Bit64u stored_delta;
+ Bit64u last_system_usec;
+ Bit64u em_last_realtime;
+ //Virtual timer variables:
+ Bit64u total_ticks;
+ Bit64u last_realtime_ticks;
+ Bit64u ticks_per_second;
+
+ bx_bool init_done;
+
+ int system_timer_id;
+
+ //Whether or not to use virtual timers.
+ bx_bool use_virtual_timers;
+ bx_bool virtual_timers_realtime;
+
+ // A special null timer is always inserted in the timer[0] slot. This
+ // make sure that at least one timer is always active, and that the
+ // duration is always less than a maximum 32-bit integer, so a 32-bit
+ // counter can be used for the current countdown.
+ static const Bit64u NullTimerInterval;
+ static void nullTimer(void* this_ptr);
+
+
+ //Step the given number of cycles, optionally calling any timer handlers.
+ void periodic(Bit64u time_passed);
+
+
+ //Called when next_event_time changes.
+ void next_event_time_update(void);
+
+ //Called to advance the virtual time.
+ // calls periodic as needed.
+ void advance_virtual_time(Bit64u time_passed);
+
+ public:
+
+
+ //Get the current virtual time.
+ // This may return the same value on subsequent calls.
+ Bit64u time_usec(void);
+
+ //Get the current virtual time.
+ // This will return a monotonically increasing value.
+ // MUST NOT be called from within a timer handler.
+ Bit64u time_usec_sequential(void);
+
+ //Register a timer handler to go off after a given interval.
+ //Register a timer handler to go off with a periodic interval.
+ int register_timer( void *this_ptr, bx_timer_handler_t handler,
+ Bit32u useconds,
+ bx_bool continuous, bx_bool active, const char *id);
+
+ //unregister a previously registered timer.
+ unsigned unregisterTimer(int timerID);
+
+ void start_timers(void);
+
+ //activate a deactivated but registered timer.
+ void activate_timer( unsigned timer_index, Bit32u useconds,
+ bx_bool continuous );
+
+ //deactivate (but don't unregister) a currently registered timer.
+ void deactivate_timer( unsigned timer_index );
+
+
+ //Timer handler passed to pc_system
+ static void pc_system_timer_handler(void* this_ptr);
+
+ //The real timer handler.
+ void timer_handler();
+
+ //Initialization
+ void init(void);
+ bx_virt_timer_c(void);
+ ~bx_virt_timer_c(void);
+
+};
+
+
+
+extern bx_virt_timer_c bx_virt_timer;
+
+#endif // _BX_VIRT_TIMER_H
diff --git a/tools/ioemu/memory/Makefile b/tools/ioemu/memory/Makefile
new file mode 100644
index 0000000000..eb9be7da4b
--- /dev/null
+++ b/tools/ioemu/memory/Makefile
@@ -0,0 +1,12 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS= memory.o misc_mem.o
+
+all: libmemory.a
+
+libmemory.a: $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(TOPDIR)/mk/helix.mk
+
+install:: all
diff --git a/tools/ioemu/memory/memory.cc b/tools/ioemu/memory/memory.cc
new file mode 100644
index 0000000000..7ee55f360f
--- /dev/null
+++ b/tools/ioemu/memory/memory.cc
@@ -0,0 +1,450 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: memory.cc,v 1.27 2003/03/02 23:59:12 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+
+
+
+#include "bochs.h"
+#define LOG_THIS BX_MEM_THIS
+
+#if BX_PROVIDE_CPU_MEMORY
+
+ void BX_CPP_AttrRegparmN(3)
+BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+ Bit8u *data_ptr;
+ Bit32u a20addr;
+
+ // Note: accesses should always be contained within a single page now.
+
+#if BX_IODEBUG_SUPPORT
+ bx_iodebug_c::mem_write(cpu, addr, len, data);
+#endif
+ if (addr+len > this->dma_limit)
+ BX_PANIC(("address too large: %lx > %lx", addr+len, this->dma_limit));
+
+ a20addr = A20ADDR(addr);
+ BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);
+
+#if BX_DEBUGGER
+ // (mch) Check for physical write break points, TODO
+ // (bbd) Each breakpoint should have an associated CPU#, TODO
+ for (int i = 0; i < num_write_watchpoints; i++)
+ if (write_watchpoint[i] == a20addr) {
+ BX_CPU(0)->watchpoint = a20addr;
+ BX_CPU(0)->break_point = BREAK_POINT_WRITE;
+ break;
+ }
+#endif
+
+#if BX_SupportICache
+ if (a20addr < BX_MEM_THIS len)
+ cpu->iCache.decWriteStamp(cpu, a20addr);
+#endif
+
+ if ( a20addr <= BX_MEM_THIS len ) {
+ // all of data is within limits of physical memory
+ if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+ if (len == 4) {
+ WriteHostDWordToLittleEndian(&vector[a20addr], *(Bit32u*)data);
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ return;
+ }
+ if (len == 2) {
+ WriteHostWordToLittleEndian(&vector[a20addr], *(Bit16u*)data);
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ return;
+ }
+ if (len == 1) {
+ * ((Bit8u *) (&vector[a20addr])) = * (Bit8u *) data;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ return;
+ }
+ // len == other, just fall thru to special cases handling
+ }
+
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+ data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+write_one:
+ if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+ // addr *not* in range 00080000 .. 000FFFFF
+ vector[a20addr] = *data_ptr;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+inc_one:
+ if (len == 1) return;
+ len--;
+ a20addr++;
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ goto write_one;
+ }
+
+ // addr in range 00080000 .. 000FFFFF
+
+ if (a20addr <= 0x0009ffff) {
+ // regular memory 80000 .. 9FFFF
+ vector[a20addr] = *data_ptr;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ goto inc_one;
+ }
+ if (a20addr <= 0x000bffff) {
+ // VGA memory A0000 .. BFFFF
+ DEV_vga_mem_write(a20addr, *data_ptr);
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ BX_DBG_UCMEM_REPORT(a20addr, 1, BX_WRITE, *data_ptr); // obsolete
+ goto inc_one;
+ }
+ // adapter ROM C0000 .. DFFFF
+ // ROM BIOS memory E0000 .. FFFFF
+ // (ignore write)
+ //BX_INFO(("ROM lock %08x: len=%u",
+ // (unsigned) a20addr, (unsigned) len));
+#if BX_PCI_SUPPORT == 0
+#if BX_SHADOW_RAM
+ // Write it since its in shadow RAM
+ vector[a20addr] = *data_ptr;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+#else
+ // ignore write to ROM
+#endif
+#else
+ // Write Based on 440fx Programming
+ if (bx_options.Oi440FXSupport->get () &&
+ ((a20addr >= 0xC0000) && (a20addr <= 0xFFFFF))) {
+ switch (DEV_pci_wr_memtype(a20addr & 0xFC000)) {
+ case 0x1: // Writes to ShadowRAM
+// BX_INFO(("Writing to ShadowRAM %08x, len %u ! ", (unsigned) a20addr, (unsigned) len));
+ shadow[a20addr - 0xc0000] = *data_ptr;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ goto inc_one;
+
+ case 0x0: // Writes to ROM, Inhibit
+ BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
+ goto inc_one;
+ default:
+ BX_PANIC(("writePhysicalPage: default case"));
+ goto inc_one;
+ }
+ }
+#endif
+ goto inc_one;
+ }
+
+ else {
+ // some or all of data is outside limits of physical memory
+ unsigned i;
+
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+ data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+
+#if BX_SUPPORT_VBE
+ // Check VBE LFB support
+
+ if ((a20addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS) &&
+ (a20addr < (VBE_DISPI_LFB_PHYSICAL_ADDRESS + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)))
+ {
+ for (i = 0; i < len; i++) {
+
+ //if (a20addr < BX_MEM_THIS len) {
+ //vector[a20addr] = *data_ptr;
+ //BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ DEV_vga_mem_write(a20addr, *data_ptr);
+ // }
+
+ // otherwise ignore byte, since it overruns memory
+ addr++;
+ a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ }
+ return;
+ }
+
+#endif
+
+
+#if BX_SUPPORT_APIC
+ bx_generic_apic_c *local_apic = &cpu->local_apic;
+ bx_generic_apic_c *ioapic = bx_devices.ioapic;
+ if (local_apic->is_selected (a20addr, len)) {
+ local_apic->write (a20addr, (Bit32u *)data, len);
+ return;
+ } else if (ioapic->is_selected (a20addr, len)) {
+ ioapic->write (a20addr, (Bit32u *)data, len);
+ return;
+ }
+ else
+#endif
+ for (i = 0; i < len; i++) {
+ if (a20addr < BX_MEM_THIS len) {
+ vector[a20addr] = *data_ptr;
+ BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ }
+ // otherwise ignore byte, since it overruns memory
+ addr++;
+ a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ }
+ return;
+ }
+}
+
+
+ void BX_CPP_AttrRegparmN(3)
+BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+ Bit8u *data_ptr;
+ Bit32u a20addr;
+
+#if BX_IODEBUG_SUPPORT
+ bx_iodebug_c::mem_read(cpu, addr, len, data);
+#endif
+
+ if (addr+len > this->dma_limit)
+ BX_PANIC(("address too large: %lx > %lx", addr+len, this->dma_limit));
+
+ a20addr = A20ADDR(addr);
+ BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);
+
+#if BX_DEBUGGER
+ // (mch) Check for physical read break points, TODO
+ // (bbd) Each breakpoint should have an associated CPU#, TODO
+ for (int i = 0; i < num_read_watchpoints; i++)
+ if (read_watchpoint[i] == a20addr) {
+ BX_CPU(0)->watchpoint = a20addr;
+ BX_CPU(0)->break_point = BREAK_POINT_READ;
+ break;
+ }
+#endif
+
+ if ( (a20addr + len) <= BX_MEM_THIS len ) {
+ // all of data is within limits of physical memory
+ if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+ if (len == 4) {
+ ReadHostDWordFromLittleEndian(&vector[a20addr], * (Bit32u*) data);
+ return;
+ }
+ if (len == 2) {
+ ReadHostWordFromLittleEndian(&vector[a20addr], * (Bit16u*) data);
+ return;
+ }
+ if (len == 1) {
+ * (Bit8u *) data = * ((Bit8u *) (&vector[a20addr]));
+ return;
+ }
+ // len == 3 case can just fall thru to special cases handling
+ }
+
+
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+ data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+
+
+read_one:
+ if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+ // addr *not* in range 00080000 .. 000FFFFF
+ *data_ptr = vector[a20addr];
+inc_one:
+ if (len == 1) return;
+ len--;
+ a20addr++;
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ goto read_one;
+ }
+
+ // addr in range 00080000 .. 000FFFFF
+#if BX_PCI_SUPPORT == 0
+ if ((a20addr <= 0x0009ffff) || (a20addr >= 0x000c0000) ) {
+ // regular memory 80000 .. 9FFFF, C0000 .. F0000
+ *data_ptr = vector[a20addr];
+ goto inc_one;
+ }
+ // VGA memory A0000 .. BFFFF
+ *data_ptr = DEV_vga_mem_read(a20addr);
+ BX_DBG_UCMEM_REPORT(a20addr, 1, BX_READ, *data_ptr); // obsolete
+ goto inc_one;
+#else // #if BX_PCI_SUPPORT == 0
+ if (a20addr <= 0x0009ffff) {
+ *data_ptr = vector[a20addr];
+ goto inc_one;
+ }
+ if (a20addr <= 0x000BFFFF) {
+ // VGA memory A0000 .. BFFFF
+ *data_ptr = DEV_vga_mem_read(a20addr);
+ BX_DBG_UCMEM_REPORT(a20addr, 1, BX_READ, *data_ptr);
+ goto inc_one;
+ }
+
+ // a20addr in C0000 .. FFFFF
+ if (!bx_options.Oi440FXSupport->get ()) {
+ *data_ptr = vector[a20addr];
+ goto inc_one;
+ }
+ else {
+ switch (DEV_pci_rd_memtype(a20addr & 0xFC000)) {
+ case 0x1: // Read from ShadowRAM
+ *data_ptr = shadow[a20addr - 0xc0000];
+ BX_INFO(("Reading from ShadowRAM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+ goto inc_one;
+
+ case 0x0: // Read from ROM
+ *data_ptr = vector[a20addr];
+ //BX_INFO(("Reading from ROM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+ goto inc_one;
+ default:
+ BX_PANIC(("::readPhysicalPage: default case"));
+ }
+ }
+ goto inc_one;
+#endif // #if BX_PCI_SUPPORT == 0
+ }
+ else {
+ // some or all of data is outside limits of physical memory
+ unsigned i;
+
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+ data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+#if BX_SUPPORT_VBE
+ // Check VBE LFB support
+
+ if ((a20addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS) &&
+ (a20addr < (VBE_DISPI_LFB_PHYSICAL_ADDRESS + VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)))
+ {
+ for (i = 0; i < len; i++) {
+
+ //if (a20addr < BX_MEM_THIS len) {
+ //vector[a20addr] = *data_ptr;
+ //BX_DBG_DIRTY_PAGE(a20addr >> 12);
+ *data_ptr = DEV_vga_mem_read(a20addr);
+ // }
+
+ // otherwise ignore byte, since it overruns memory
+ addr++;
+ a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ }
+ return;
+ }
+
+#endif
+
+
+#if BX_SUPPORT_APIC
+ bx_generic_apic_c *local_apic = &cpu->local_apic;
+ bx_generic_apic_c *ioapic = bx_devices.ioapic;
+ if (local_apic->is_selected (addr, len)) {
+ local_apic->read (addr, data, len);
+ return;
+ } else if (ioapic->is_selected (addr, len)) {
+ ioapic->read (addr, data, len);
+ return;
+ }
+#endif
+ for (i = 0; i < len; i++) {
+#if BX_PCI_SUPPORT == 0
+ if (a20addr < BX_MEM_THIS len)
+ *data_ptr = vector[a20addr];
+ else
+ *data_ptr = 0xff;
+#else // BX_PCI_SUPPORT == 0
+ if (a20addr < BX_MEM_THIS len) {
+ if ((a20addr >= 0x000C0000) && (a20addr <= 0x000FFFFF)) {
+ if (!bx_options.Oi440FXSupport->get ())
+ *data_ptr = vector[a20addr];
+ else {
+ switch (DEV_pci_rd_memtype(a20addr & 0xFC000)) {
+ case 0x0: // Read from ROM
+ *data_ptr = vector[a20addr];
+ //BX_INFO(("Reading from ROM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+ break;
+
+ case 0x1: // Read from Shadow RAM
+ *data_ptr = shadow[a20addr - 0xc0000];
+ BX_INFO(("Reading from ShadowRAM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+ break;
+ default:
+ BX_PANIC(("readPhysicalPage: default case"));
+ } // Switch
+ }
+ }
+ else {
+ *data_ptr = vector[a20addr];
+ BX_INFO(("Reading from Norm %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+ }
+ }
+ else
+ *data_ptr = 0xff;
+#endif // BX_PCI_SUPPORT == 0
+ addr++;
+ a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+ data_ptr++;
+#else // BX_BIG_ENDIAN
+ data_ptr--;
+#endif
+ }
+ return;
+ }
+}
+
+#endif // #if BX_PROVIDE_CPU_MEMORY
diff --git a/tools/ioemu/memory/memory.h b/tools/ioemu/memory/memory.h
new file mode 100644
index 0000000000..2af787b3c3
--- /dev/null
+++ b/tools/ioemu/memory/memory.h
@@ -0,0 +1,98 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: memory.h,v 1.16 2003/08/05 13:19:35 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2001 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+#define BX_USE_MEM_SMF 0
+
+#if BX_USE_MEM_SMF
+// if static member functions on, then there is only one memory
+# define BX_MEM_SMF static
+# define BX_MEM_THIS BX_MEM(0)->
+#else
+# define BX_MEM_SMF
+# define BX_MEM_THIS this->
+#endif
+
+// alignment of memory vector, must be a power of 2
+#define BX_MEM_VECTOR_ALIGN 4096
+
+class BOCHSAPI BX_MEM_C : public logfunctions {
+
+public:
+ Bit8u *actual_vector;
+ Bit8u *vector; // aligned correctly
+ size_t len;
+ size_t dma_limit;
+ size_t megabytes; // (len in Megabytes)
+#if BX_PCI_SUPPORT
+ Bit8u shadow[4*16*4096]; // 256k of memory
+#endif
+#if BX_DEBUGGER
+ unsigned char dbg_dirty_pages[(BX_MAX_DIRTY_PAGE_TABLE_MEGS * 1024 * 1024) / 4096];
+ Bit32u dbg_count_dirty_pages () {
+ return (BX_MAX_DIRTY_PAGE_TABLE_MEGS * 1024 * 1024) / 4096;
+ }
+#endif
+ unsigned long *page_array; /* for get_pfn_list() */
+
+ BX_MEM_C(void);
+ //BX_MEM_C(size_t memsize);
+ ~BX_MEM_C(void);
+ BX_MEM_SMF void alloc_vector_aligned (size_t bytes, size_t alignment) BX_CPP_AttrRegparmN(2);
+ BX_MEM_SMF void init_memory(int memsize);
+ BX_MEM_SMF void readPhysicalPage(BX_CPU_C *cpu, Bit32u addr,
+ unsigned len, void *data) BX_CPP_AttrRegparmN(3);
+ BX_MEM_SMF void writePhysicalPage(BX_CPU_C *cpu, Bit32u addr,
+ unsigned len, void *data) BX_CPP_AttrRegparmN(3);
+ BX_MEM_SMF void load_ROM(const char *path, Bit32u romaddress, Bit8u type);
+ BX_MEM_SMF Bit32u get_memory_in_k(void);
+#if BX_PCI_SUPPORT
+ BX_MEM_SMF Bit8u* pci_fetch_ptr(Bit32u addr) BX_CPP_AttrRegparmN(1);
+#endif
+ BX_MEM_SMF bx_bool dbg_fetch_mem(Bit32u addr, unsigned len, Bit8u *buf);
+ BX_MEM_SMF bx_bool dbg_set_mem(Bit32u addr, unsigned len, Bit8u *buf);
+ BX_MEM_SMF bx_bool dbg_crc32(
+ unsigned long (*f)(unsigned char *buf, int len),
+ Bit32u addr1, Bit32u addr2, Bit32u *crc);
+ BX_MEM_SMF Bit8u * getHostMemAddr(BX_CPU_C *cpu, Bit32u a20Addr, unsigned op) BX_CPP_AttrRegparmN(3);
+ };
+
+#if BX_PROVIDE_CPU_MEMORY==1
+
+#if BX_SMP_PROCESSORS==1
+BOCHSAPI extern BX_MEM_C bx_mem;
+#else
+BOCHSAPI extern BX_MEM_C *bx_mem_array[BX_ADDRESS_SPACES];
+#endif /* BX_SMP_PROCESSORS */
+
+#endif /* BX_PROVIDE_CPU_MEMORY==1 */
+
+#if BX_DEBUGGER
+# define BX_DBG_DIRTY_PAGE(page) BX_MEM(0)->dbg_dirty_pages[page] = 1;
+#else
+# define BX_DBG_DIRTY_PAGE(page)
+#endif
diff --git a/tools/ioemu/memory/misc_mem.cc b/tools/ioemu/memory/misc_mem.cc
new file mode 100644
index 0000000000..5d2b678531
--- /dev/null
+++ b/tools/ioemu/memory/misc_mem.cc
@@ -0,0 +1,440 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: misc_mem.cc,v 1.41 2003/09/10 16:34:56 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// MandrakeSoft S.A.
+// 43, rue d'Aboukir
+// 75002 Paris - France
+// http://www.linux-mandrake.com/
+// http://www.mandrakesoft.com/
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+
+
+
+#include "bochs.h"
+#ifdef BX_USE_VMX
+extern "C" {
+#include <sys/mman.h>
+}
+#endif
+
+#define LOG_THIS BX_MEM(0)->
+
+#if BX_PROVIDE_CPU_MEMORY
+ Bit32u
+BX_MEM_C::get_memory_in_k(void)
+{
+ return(BX_MEM_THIS megabytes * 1024);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+ // BX_MEM_C constructor
+BX_MEM_C::BX_MEM_C(void)
+{
+ char mem[6];
+ snprintf(mem, 6, "MEM%d", BX_SIM_ID);
+ put(mem);
+ settype(MEMLOG);
+
+ vector = NULL;
+ actual_vector = NULL;
+ len = 0;
+ megabytes = 0;
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+
+#if BX_PROVIDE_CPU_MEMORY
+void BX_CPP_AttrRegparmN(2)
+BX_MEM_C::alloc_vector_aligned (size_t bytes, size_t alignment)
+{
+ if (actual_vector != NULL) {
+ BX_INFO (("freeing existing memory vector"));
+ delete [] actual_vector;
+ actual_vector = NULL;
+ vector = NULL;
+ }
+ Bit64u test_mask = alignment - 1;
+ actual_vector = new Bit8u [bytes+test_mask];
+ // round address forward to nearest multiple of alignment. Alignment
+ // MUST BE a power of two for this to work.
+ unsigned long masked = ((unsigned long)(actual_vector + test_mask)) & ~test_mask;
+ vector = (Bit8u *)masked;
+ // sanity check: no lost bits during pointer conversion
+ BX_ASSERT (sizeof(masked) >= sizeof(vector));
+ // sanity check: after realignment, everything fits in allocated space
+ BX_ASSERT (vector+bytes <= actual_vector+bytes+test_mask);
+ BX_INFO (("allocated memory at %p. after alignment, vector=%p",
+ actual_vector, vector));
+}
+#endif
+
+// We can't use this because alloc_vector_aligned uses BX_INFO, but the object does not yet exists
+/*
+#if BX_PROVIDE_CPU_MEMORY
+ // BX_MEM_C constructor
+
+BX_MEM_C::BX_MEM_C(size_t memsize)
+{
+ char mem[6];
+ snprintf(mem, 6, "MEM%d", BX_SIM_ID);
+ put(mem);
+ settype(MEMLOG);
+
+ vector = NULL;
+ actual_vector = NULL;
+ alloc_vector_aligned (memsize, BX_MEM_VECTOR_ALIGN);
+ len = memsize;
+ megabytes = len / (1024*1024);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+*/
+
+
+#if BX_PROVIDE_CPU_MEMORY
+// BX_MEM_C destructor
+BX_MEM_C::~BX_MEM_C(void)
+{
+ if (this-> vector != NULL) {
+ delete [] actual_vector;
+ actual_vector = NULL;
+ vector = NULL;
+ }
+ else {
+ BX_DEBUG(("(%u) memory not freed as it wasn't allocated!", BX_SIM_ID));
+ }
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+ void
+BX_MEM_C::init_memory(int memsize)
+{
+ BX_DEBUG(("Init $Id: misc_mem.cc,v 1.41 2003/09/10 16:34:56 vruppert Exp $"));
+ // you can pass 0 if memory has been allocated already through
+ // the constructor, or the desired size of memory if it hasn't
+ // BX_INFO(("%.2fMB", (float)(BX_MEM_THIS megabytes) ));
+
+#ifndef BX_USE_VMX
+ if (BX_MEM_THIS vector == NULL) {
+ // memory not already allocated, do now...
+ alloc_vector_aligned (memsize, BX_MEM_VECTOR_ALIGN);
+#endif
+ BX_MEM_THIS len = memsize;
+ BX_MEM_THIS megabytes = memsize / (1024*1024);
+ BX_INFO(("%.2fMB", (float)(BX_MEM_THIS megabytes) ));
+#ifndef BX_USE_VMX
+ }
+#endif
+
+#if BX_DEBUGGER
+ if (megabytes > BX_MAX_DIRTY_PAGE_TABLE_MEGS) {
+ BX_INFO(("Error: memory larger than dirty page table can handle"));
+ BX_PANIC(("Error: increase BX_MAX_DIRTY_PAGE_TABLE_MEGS"));
+ }
+#endif
+
+ unsigned long nr_pages = megabytes * (1024 * 1024/getpagesize());
+
+ if ( (page_array = (unsigned long *)
+ malloc(nr_pages * sizeof(unsigned long))) == NULL)
+ {
+ BX_ERROR(("Could not allocate memory"));
+ return;
+ }
+
+ if ( xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages )
+ {
+ BX_ERROR(("Could not get the page frame list"));
+ return;
+ }
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+
+ if ((vector = (Bit8u *) xc_map_foreign_batch(xc_handle, domid,
+ PROT_READ|PROT_WRITE,
+ page_array,
+ nr_pages - 1)) == 0) {
+ BX_ERROR(("Could not map guest physical"));
+ return;
+ }
+
+ BX_MEM_THIS dma_limit = (nr_pages - 1) << PAGE_SHIFT;
+ BX_INFO(("DMA limit: %lx", BX_MEM_THIS dma_limit));
+
+ shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ page_array[nr_pages - 1]);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+ void
+ // Values for type :
+ // 0 : System Bios
+ // 1 : VGA Bios
+ // 2 : Optional ROM Bios
+BX_MEM_C::load_ROM(const char *path, Bit32u romaddress, Bit8u type)
+{
+ struct stat stat_buf;
+ int fd, ret;
+ unsigned long size, offset;
+
+ if (*path == '\0') {
+ if (type == 2) {
+ BX_PANIC(( "ROM: Optional BIOS image undefined."));
+ }
+ else if (type == 1) {
+ BX_PANIC(( "ROM: VGA BIOS image undefined."));
+ }
+ else {
+ BX_PANIC(( "ROM: System BIOS image undefined."));
+ }
+ return;
+ }
+ // read in ROM BIOS image file
+ fd = open(path, O_RDONLY
+#ifdef O_BINARY
+ | O_BINARY
+#endif
+ );
+ if (fd < 0) {
+ if (type < 2) {
+ BX_PANIC(( "ROM: couldn't open ROM image file '%s'.", path));
+ }
+ else {
+ BX_ERROR(( "ROM: couldn't open ROM image file '%s'.", path));
+ }
+ return;
+ }
+ ret = fstat(fd, &stat_buf);
+ if (ret) {
+ if (type < 2) {
+ BX_PANIC(( "ROM: couldn't stat ROM image file '%s'.", path));
+ }
+ else {
+ BX_ERROR(( "ROM: couldn't stat ROM image file '%s'.", path));
+ }
+ return;
+ }
+
+ size = stat_buf.st_size;
+
+ if ( (romaddress + size) > BX_MEM_THIS len ) {
+ BX_PANIC(( "ROM: ROM address range > physical memsize!"));
+ return;
+ }
+
+ offset = 0;
+ while (size > 0) {
+ ret = read(fd, (bx_ptr_t) &BX_MEM_THIS vector[romaddress + offset], size);
+ if (ret <= 0) {
+ BX_PANIC(( "ROM: read failed on BIOS image: '%s'",path));
+ }
+ size -= ret;
+ offset += ret;
+ }
+ close(fd);
+ BX_INFO(("rom at 0x%05x/%u ('%s')",
+ (unsigned) romaddress,
+ (unsigned) stat_buf.st_size,
+ path
+ ));
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+#if BX_PCI_SUPPORT
+ Bit8u* BX_CPP_AttrRegparmN(1)
+BX_MEM_C::pci_fetch_ptr(Bit32u addr)
+{
+ if (bx_options.Oi440FXSupport->get ()) {
+ switch (DEV_pci_rd_memtype (addr)) {
+ case 0x1: // Read from ShadowRAM
+ return (&BX_MEM_THIS shadow[addr - 0xc0000]);
+
+ case 0x0: // Read from ROM
+ return (&BX_MEM_THIS vector[addr]);
+ default:
+ BX_PANIC(("pci_fetch_ptr(): default case"));
+ return(0);
+ }
+ }
+ else
+ return (&BX_MEM_THIS vector[addr]);
+}
+#endif
+
+
+#if ( BX_DEBUGGER || BX_DISASM || BX_GDBSTUB)
+ bx_bool
+BX_MEM_C::dbg_fetch_mem(Bit32u addr, unsigned len, Bit8u *buf)
+{
+ if ( (addr + len) > this->len ) {
+ BX_INFO(("dbg_fetch_mem out of range. 0x%x > 0x%x",
+ addr+len, this->len));
+ return(0); // error, beyond limits of memory
+ }
+ for (; len>0; len--) {
+ if ( (addr & 0xfffe0000) == 0x000a0000 ) {
+ *buf = DEV_vga_mem_read(addr);
+ }
+ else {
+#if BX_PCI_SUPPORT == 0
+ *buf = vector[addr];
+#else
+ if ( bx_options.Oi440FXSupport->get () &&
+ ((addr >= 0x000C0000) && (addr <= 0x000FFFFF)) ) {
+ switch (DEV_pci_rd_memtype (addr)) {
+ case 0x1: // Fetch from ShadowRAM
+ *buf = shadow[addr - 0xc0000];
+// BX_INFO(("Fetching from ShadowRAM %06x, len %u !", (unsigned)addr, (unsigned)len));
+ break;
+
+ case 0x0: // Fetch from ROM
+ *buf = vector[addr];
+// BX_INFO(("Fetching from ROM %06x, Data %02x ", (unsigned)addr, *buf));
+ break;
+ default:
+ BX_PANIC(("dbg_fetch_mem: default case"));
+ }
+ }
+ else
+ *buf = vector[addr];
+#endif // #if BX_PCI_SUPPORT == 0
+ }
+ buf++;
+ addr++;
+ }
+ return(1);
+}
+#endif
+
+#if BX_DEBUGGER || BX_GDBSTUB
+ bx_bool
+BX_MEM_C::dbg_set_mem(Bit32u addr, unsigned len, Bit8u *buf)
+{
+ if ( (addr + len) > this->len ) {
+ return(0); // error, beyond limits of memory
+ }
+ for (; len>0; len--) {
+ if ( (addr & 0xfffe0000) == 0x000a0000 ) {
+ DEV_vga_mem_write(addr, *buf);
+ }
+ else
+ vector[addr] = *buf;
+ buf++;
+ addr++;
+ }
+ return(1);
+}
+#endif
+
+ bx_bool
+BX_MEM_C::dbg_crc32(unsigned long (*f)(unsigned char *buf, int len),
+ Bit32u addr1, Bit32u addr2, Bit32u *crc)
+{
+ unsigned len;
+
+ *crc = 0;
+ if (addr1 > addr2)
+ return(0);
+
+ if (addr2 >= this->len) {
+ return(0); // error, specified address past last phy mem addr
+ }
+
+ len = 1 + addr2 - addr1;
+ *crc = f(vector + addr1, len);
+
+ return(1);
+}
+
+
+ Bit8u * BX_CPP_AttrRegparmN(3)
+BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, Bit32u a20Addr, unsigned op)
+ // Return a host address corresponding to the guest physical memory
+ // address (with A20 already applied), given that the calling
+ // code will perform an 'op' operation. This address will be
+ // used for direct access to guest memory as an acceleration by
+ // a few instructions, like REP {MOV, INS, OUTS, etc}.
+ // Values of 'op' are { BX_READ, BX_WRITE, BX_RW }.
+
+ // The other assumption is that the calling code _only_ accesses memory
+ // directly within the page that encompasses the address requested.
+{
+ if ( a20Addr >= BX_MEM_THIS len )
+ return(NULL); // Error, requested addr is out of bounds.
+ if (op == BX_READ) {
+ if ( (a20Addr > 0x9ffff) && (a20Addr < 0xc0000) )
+ return(NULL); // Vetoed! Mem mapped IO (VGA)
+#if !BX_PCI_SUPPORT
+ return( (Bit8u *) & vector[a20Addr] );
+#else
+ else if ( (a20Addr < 0xa0000) || (a20Addr > 0xfffff)
+ || (!bx_options.Oi440FXSupport->get ()) )
+ return( (Bit8u *) & vector[a20Addr] );
+ else {
+ switch (DEV_pci_rd_memtype (a20Addr)) {
+ case 0x0: // Read from ROM
+ return ( (Bit8u *) & vector[a20Addr]);
+ case 0x1: // Read from ShadowRAM
+ return( (Bit8u *) & shadow[a20Addr - 0xc0000]);
+ default:
+ BX_PANIC(("getHostMemAddr(): default case"));
+ return(0);
+ }
+ }
+#endif
+ }
+ else { // op == {BX_WRITE, BX_RW}
+ Bit8u *retAddr;
+
+ if ( (a20Addr < 0xa0000) || (a20Addr > 0xfffff) ) {
+ retAddr = (Bit8u *) & vector[a20Addr];
+ }
+#if !BX_PCI_SUPPORT
+ else
+ return(NULL); // Vetoed! Mem mapped IO (VGA) and ROMs
+#else
+ else if ( (a20Addr < 0xc0000) || (!bx_options.Oi440FXSupport->get ()) )
+ return(NULL); // Vetoed! Mem mapped IO (VGA) and ROMs
+ else if (DEV_pci_wr_memtype (a20Addr) == 1) {
+ // Write to ShadowRAM
+ retAddr = (Bit8u *) & shadow[a20Addr - 0xc0000];
+ }
+ else
+ return(NULL); // Vetoed! ROMs
+#endif
+
+#if BX_SupportICache
+ cpu->iCache.decWriteStamp(cpu, a20Addr);
+#endif
+
+ return(retAddr);
+ }
+}
diff --git a/tools/ioemu/mk/helix.mk b/tools/ioemu/mk/helix.mk
new file mode 100644
index 0000000000..e18eb340d2
--- /dev/null
+++ b/tools/ioemu/mk/helix.mk
@@ -0,0 +1,6 @@
+CXXFLAGS += -O2 -I../../../tools/libxc -I../../../xen/include/public
+clean:
+ $(RM) -f *.o *~ lib*.a device-model
+
+install::
+